[ty] Fix implementation of Top[Callable[..., object]]#22145
[ty] Fix implementation of Top[Callable[..., object]]#22145charliermarsh merged 12 commits intomainfrom
Top[Callable[..., object]]#22145Conversation
Diagnostic diff on typing conformance testsNo changes detected when running ty on typing conformance tests ✅ |
|
|
|
|
It's the same as the difference between |
|
We implement ruff/crates/ty_python_semantic/src/types/generics.rs Lines 734 to 741 in 4a93754 CallableType and/or Parameters.
|
|
🫡 |
b8dccb9 to
b655839
Compare
...) for parameters in Callable bottom type...) for parameters in Callable bottom type
...) for parameters in Callable bottom type...) for parameters in Callable top materialization
|
Nice, this looks like it's on the right track now!
Diagnostics like this indicate that some of the subtyping rules aren't quite right yet. All Similarly, |
|
The primer report is starting to look a lot better! There's another change that we need to make... which might make the ecosystem blow up, but I do think it's the "correct" thing to do: def f(x: object):
if callable(x):
x() # this should be an error...
# we know that `x` is callable, but we do not know
# *how* it is callable (is it okay to call it with *zero arguments*?).
# `Top[Callable[..., object]]` is much stricter than `Callable[..., object]`
# for things like this
This is similar to the way we apply much stricter rules to from ty_extensions import Top
from typing import Any
def f(x: list[Any], y: Top[list[Any]]):
x.append("foo") # fine
y.append("foo") # error: expected `Never`, found `Literal["foo"] |
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
invalid-argument-type |
2 | 36 | 14 |
unresolved-attribute |
6 | 3 | 19 |
invalid-assignment |
0 | 6 | 21 |
invalid-return-type |
0 | 4 | 13 |
possibly-missing-attribute |
0 | 7 | 8 |
unsupported-operator |
0 | 7 | 0 |
call-top-callable |
5 | 0 | 0 |
missing-argument |
5 | 0 | 0 |
not-iterable |
0 | 3 | 1 |
unused-ignore-comment |
3 | 1 | 0 |
call-non-callable |
1 | 1 | 0 |
too-many-positional-arguments |
0 | 2 | 0 |
type-assertion-failure |
2 | 0 | 0 |
invalid-parameter-default |
0 | 0 | 1 |
invalid-type-form |
0 | 0 | 1 |
no-matching-overload |
0 | 1 | 0 |
| Total | 24 | 71 | 78 |
|
I wouldn't worry about the spack panic in ecosystem-analyzer — we've seen it on some other PRs; it's one of our nondeterminism issues right now |
c873d89 to
2c73f4f
Compare
|
Lots of false positives going away in the ecosystem report! 🎉 I see a few new diagnostics with message "Object of type Other type checkers unsoundly use |
|
(I think that diagnostic is what Alex asked for here: #22145 (comment). No issue from me with using a custom diagnostic for it!) |
carljm
left a comment
There was a problem hiding this comment.
Awesome!
I think it'd be good to have some tests showing the behavior of the bottom callable, too? It's always callable with any arguments.
The ways it could be created in real code are a bit complex. You'd need a gradual-form callable type in contravariant position of some type -- e.g. as an argument to another Callable -- and then you'd need to do something that would top-materialize the outer type, like return it wrapped in TypeIs. I'm not sure we need to represent this in a test; I'd just use ty_extensions.Bottom to create the type "manually".
| /// The callable type is a top materialization (e.g., `Top[Callable[..., object]]`), which | ||
| /// represents an unknown callable signature. While such types *are* callable (they pass | ||
| /// `callable()`), any specific call should fail because we don't know the actual signature. | ||
| UnknownCallableSignature(Type<'db>), |
There was a problem hiding this comment.
Although the term "unknown" is correct here, it's confusing given our frequent usage of Unknown as a dynamic type. This isn't user-facing, it's in code: maybe CalledTopCallable?
2c73f4f to
9216960
Compare
...) for parameters in Callable top materializationTop[Callable[..., object]]
|
The ecosystem report's looking good again! |
AlexWaygood
left a comment
There was a problem hiding this comment.
This looks great -- thank you!! 😃
crates/ty_python_semantic/resources/mdtest/type_properties/materialization.md
Outdated
Show resolved
Hide resolved
2a71cef to
e1bd5ad
Compare
e1bd5ad to
5201bc3
Compare
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
|
Thank you @AlexWaygood! |
…ute on a `Callable` type (#22182) ## Summary Other type checkers allow you to access all `FunctionType` attributes on any object with a `Callable` type. ty does not, because this is demonstrably unsound, but this is often a source of confusion for users. And there were lots of diagnostics in the ecosystem report for #22145 that were complaining that "Object of type `(...) -> Unknown` has no attribute `__name__`", for example. The discrepancy between what ty does here and what other type checkers do is discussed a bit in astral-sh/ty#1495. You can see that there have been lots of issues closed as duplicates of that issue; we should probably also add an FAQ entry for it. Anyway, this PR adds a subdiagnostic to help users out when they hit this diagnostic. Unfortunately something I did meant that rustfmt increased the indentation of the whole of this huge closure, so this PR is best reviewed with the "No whitespace" option selected for viewing the diff. ## Test Plan Snapshot added
Summary
Add a proper representation for the
Callabletop type, and use it to getcallable()narrowing right.Closes astral-sh/ty#1426.