Skip to content

Conversation

@cormacrelf
Copy link
Contributor

@cormacrelf cormacrelf commented Nov 12, 2025

From #1132

@cormacrelf (me):
... lowest-hanging fruit to make the LSP type checking better...

There is some barrier to type-checking provider code like ctx.attrs.dep[ProviderName].blah, the .blah is not checked probably because the .[] is too generic. ... That will get you much more coverage in real .bzl code. I quickly looked into this and it will require #[starlark(ty_custom_function = ...)] to be supported on methods.

This PR fixes that. We get type checking for dep[ProviderName] and dep.get(ProviderName), where the return type is computed from the argument type. It does not check that the argument is actually a provider callable, but that's ok, we do that at runtime.

This required quite a few private types from starlark to be made available. I'm open to making this work with more wrappers such that less has to be made public.

  • #[starlark(ty_custom_function = ...)] now works on methods.
  • TyCustomFunctionImpl made public, and also types that appear in its methods
    • can we reduce the validate_call at all to expose less stuff?
  • New type TyCustomIndex / TyCustomIndexImpl to do the same for dep[xxx] via a TyUser wrapper. This is pretty good and self-contained. Is it awkward that you need TyUser only for this when TyStarlarkValue can handle the ty_custom_function annotations? You then need a LazyLock to cache the TyUser...
  • An awkward method Ty::as_callable_return, should this be on the typing oracle ctx instead?
  • A number of type checker improvements, like TyUser forwarding bin_op to the base, TyUser's callable being used.

Together with the LSP improvements in #1132 :

Screenshot 2025-11-13 at 12 23 12 am

Altogether, we can now typecheck all of these scenarios:

Prov = provider(
    fields = dict(
        hello = provider_field(str),
    )
)
x = Prov(hello = "hi")
x.ello                    # type error, also eval error

def abc() -> int:
    x = Prov(hello="hi")
    return x.ello         # type error

def def() -> int:
    return x.ello         # type error

def hij(dep: Dependency):
    prov = dep.get(Prov)
    xyz: str = prov.ello  # type error

def klm(dep: Dependency):
    prov = dep[Prov]
    xyz: str = prov.ello  # type error

def nop(p: Prov):
    p.ello                # type error

Remaining work

  • How to get type(x) to be the name of the provider? I tried for a while and got nowhere, no dice for records either. The TYPE property / #[starlark_value(type = xxx)] is authoritative, so you just get "Provider". TyUser needs to be able to take this over.
  • There are no typings for ctx.attrs.dep because AnalysisContext.attrs is just an unknown struct that has any fields during typechecking. This limits the application of provider/dependency type checking, you would need to be using helper functions that annotate types well. ideas welcome. Possibly needs something like
MyAttributes = rule_attributes({
    "label": attrs.label(),
    "dep": attrs.dep(),
})

def _my_rule_impl(ctx: AnalysisContext[MyAttributes]) -> list[Provider]:
    # ctx.attrs is now of type MyAttributes
    # and this gets typechecked
    input: Artifact = ctx.attrs.dep[DefaultInfo].default_outputs[0]
    return [DefaultInfo(output)]

my_rule = rule(
    impl = _my_rule_impl,
    attrs = MyAttributes,
)

This had some 'TODO: do not unwrap' at the callsites. Done!
It was easier to add this functionality than it would have been to
make the error messages describing how it was not supported.
@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Nov 12, 2025
@meta-codesync
Copy link
Contributor

meta-codesync bot commented Nov 12, 2025

@facebook-github-bot has imported this pull request. If you are a Meta employee, you can view this in D86862894. (Because this pull request was imported automatically, there will not be any future comments.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant