-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Use annotated parameters as type context #20635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Diagnostic diff on typing conformance testsChanges were detected when running ty on typing conformance tests--- old-output.txt 2025-10-03 20:48:40.319496259 +0000
+++ new-output.txt 2025-10-03 20:48:43.574517278 +0000
@@ -1,6 +1,6 @@
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/29ab321/src/function/execute.rs:217:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_type_statement.py`: `PEP695TypeAliasType < 'db >::value_type_(Id(cc17)): execute: too many cycle iterations`
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/29ab321/src/function/execute.rs:217:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(15c32)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/29ab321/src/function/execute.rs:217:25 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(16432)): execute: too many cycle iterations`
_directives_deprecated_library.py:15:31: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `int`
_directives_deprecated_library.py:30:26: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `str`
_directives_deprecated_library.py:36:41: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@__add__` |
|
a90814a to
49661f2
Compare
|
It looks like a lot of these errors are duplicated diagnostics now that we infer argument expressions multiple times for callable unions/overloads, e.g., if flag:
def f(_: int): ...
else:
def f(_: int): ...
if flag:
x = 0
# warning[possibly-unresolved-reference] Name `x` used when possibly not defined
# warning[possibly-unresolved-reference] Name `x` used when possibly not defined
f(x)(In this example, multi-inference is not strictly necessary because the signatures are identical, but that's a separate performance concern). I'm not sure there's a great way around this other than adding checks around all diagnostics that aren't type-context specific? |
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
missing-typed-dict-key |
162 | 0 | 0 |
unresolved-attribute |
2 | 109 | 0 |
type-assertion-failure |
30 | 3 | 0 |
invalid-argument-type |
4 | 0 | 9 |
invalid-context-manager |
0 | 13 | 0 |
non-subscriptable |
9 | 0 | 0 |
unsupported-operator |
2 | 2 | 2 |
possibly-missing-attribute |
3 | 0 | 1 |
redundant-cast |
3 | 1 | 0 |
invalid-assignment |
3 | 0 | 0 |
invalid-return-type |
2 | 0 | 0 |
possibly-missing-implicit-call |
1 | 0 | 0 |
unused-ignore-comment |
0 | 1 | 0 |
| Total | 221 | 129 | 12 |
Instead of adding checks for every non-type-context-specific context, can we use state on |
b68d4ca to
f9a4ae1
Compare
CodSpeed Instrumentation Performance ReportMerging #20635 will degrade performances by 17.12%Comparing Summary
Benchmarks breakdown
|
d8b1f25 to
f5e0cb1
Compare
CodSpeed WallTime Performance ReportMerging #20635 will degrade performances by 21.13%Comparing Summary
Benchmarks breakdown
|
|
|
I've decided to remove the idea of "lints that may be affected by bidirectional type context", as this seemed quite. Instead, the new implementation does the following for each argument:
This does mean we get worse diagnostics for I also went through the ecosystem report, and most diagnostic changes seem to be correct, or the result of an unrelated known limitation (namely |
e8b8f6d to
ecd6491
Compare
| match call_expression_tcx { | ||
| // A type variable is not a useful type-context for expression inference, and applying it | ||
| // to the return type can lead to confusing unions in nested generic calls. | ||
| Type::TypeVar(_) => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mostly for better diagnostics. Without it, reveal_type(identity(1)) is revealed as T@reveal_type | int. It also doesn't quite work for parameters annotated as T | None — we still might union the inferred type with T@f in that case.
ecd6491 to
af00ebe
Compare
|
|
||
| fn get_argument_node( | ||
| node: ast::AnyNodeRef<'_>, | ||
| argument_index: Option<usize>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think you can update this helper to take in argument_index: usize, and use argument_index? up above when you call the helper. Then you only need to match on node below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also use get_argument_node in the diagnostic code with an Option<usize>, so I'm not sure the change is worth it.
| let val_ty = | ||
| BoundTypeVarInstance::synthetic(db, "T", TypeVarVariance::Invariant); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were there tests that were failing with the old signature? I can see that the new signature means that there's now a return value, which will have the same type as the value being checked, but I don't see any tests that rely on that behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue that showed up in the ecosystem report was that the f(1) in assert_type(f(1), int) was inferred as int | Any, because the signature of assert_type was (Any, ..) -> ... I added a test.
af00ebe to
6227fca
Compare
|
Deduplicating the parameter types helps the performance regression somewhat, but outside of that I think it's unavoidable. |
Summary
Use the type annotation of function parameters as bidirectional type context when inferring the argument expression. For example, the following example now type-checks:
Part of astral-sh/ty#168.