-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Infer type for implicit self parameters in method bodies
#20922
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-23 07:17:38.427123571 +0000
+++ new-output.txt 2025-10-23 07:17:41.924130267 +0000
@@ -1,5 +1,5 @@
fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_type_statement.py`: `PEP695TypeAliasType < 'db >::value_type_(Id(d817)): execute: too many cycle iterations`
-fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(17c43)): execute: too many cycle iterations`
+fatal[panic] Panicked at /home/runner/.cargo/git/checkouts/salsa-e6f3bb7c2a062968/ef9f932/src/function/execute.rs:402:17 when checking `/home/runner/work/ruff/ruff/typing/conformance/tests/aliases_typealiastype.py`: `infer_definition_types(Id(18043)): 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__`
@@ -352,6 +352,7 @@
enums_member_names.py:30:5: error[type-assertion-failure] Argument does not have asserted type `Literal["RED", "BLUE", "GREEN"]`
enums_member_values.py:30:5: error[type-assertion-failure] Argument does not have asserted type `Literal[1, 2, 3]`
enums_member_values.py:54:1: error[type-assertion-failure] Argument does not have asserted type `Literal[1]`
+enums_member_values.py:85:9: error[invalid-assignment] Object of type `int` is not assignable to attribute `_value_` of type `str`
enums_member_values.py:96:1: error[type-assertion-failure] Argument does not have asserted type `int`
enums_members.py:128:21: info[revealed-type] Revealed type: `Unknown | Literal[2]`
enums_members.py:129:9: error[type-assertion-failure] Argument does not have asserted type `Unknown`
@@ -445,7 +446,6 @@
generics_self_advanced.py:18:1: error[type-assertion-failure] Argument does not have asserted type `ParentA`
generics_self_advanced.py:19:1: error[type-assertion-failure] Argument does not have asserted type `ChildA`
generics_self_advanced.py:28:25: error[invalid-return-type] Function always implicitly returns `None`, which is not assignable to return type `Self@method1`
-generics_self_advanced.py:35:9: error[type-assertion-failure] Argument does not have asserted type `Self@method2`
generics_self_advanced.py:36:9: error[type-assertion-failure] Argument does not have asserted type `list[Self@method2]`
generics_self_advanced.py:37:9: error[type-assertion-failure] Argument does not have asserted type `Self@method2`
generics_self_advanced.py:38:9: error[type-assertion-failure] Argument does not have asserted type `Self@method2`
@@ -455,7 +455,6 @@
generics_self_attributes.py:26:33: error[invalid-argument-type] Argument is incorrect: Expected `typing.Self | None`, found `LinkedList[int]`
generics_self_attributes.py:29:5: error[invalid-assignment] Object of type `OrdinalLinkedList` is not assignable to attribute `next` of type `typing.Self | None`
generics_self_attributes.py:32:5: error[invalid-assignment] Object of type `LinkedList[int]` is not assignable to attribute `next` of type `typing.Self | None`
-generics_self_basic.py:14:9: error[type-assertion-failure] Argument does not have asserted type `Self@set_scale`
generics_self_basic.py:20:16: error[invalid-return-type] Return type does not match returned value: expected `Self@method2`, found `Shape`
generics_self_basic.py:33:16: error[invalid-return-type] Return type does not match returned value: expected `Self@cls_method2`, found `Shape`
generics_self_basic.py:54:1: error[type-assertion-failure] Argument does not have asserted type `Shape`
@@ -499,6 +498,7 @@
generics_syntax_infer_variance.py:46:1: error[invalid-assignment] Object of type `ShouldBeCovariant3[int | float]` is not assignable to `ShouldBeCovariant3[int]`
generics_syntax_infer_variance.py:74:1: error[invalid-assignment] Object of type `ShouldBeCovariant5[int]` is not assignable to `ShouldBeCovariant5[int | float]`
generics_syntax_infer_variance.py:75:1: error[invalid-assignment] Object of type `ShouldBeCovariant5[int | float]` is not assignable to `ShouldBeCovariant5[int]`
+generics_syntax_infer_variance.py:82:9: error[invalid-assignment] Cannot assign to final attribute `x` on type `Self@__init__`
generics_syntax_infer_variance.py:85:1: error[invalid-assignment] Object of type `ShouldBeCovariant6[int]` is not assignable to `ShouldBeCovariant6[int | float]`
generics_syntax_infer_variance.py:86:1: error[invalid-assignment] Object of type `ShouldBeCovariant6[int | float]` is not assignable to `ShouldBeCovariant6[int]`
generics_syntax_infer_variance.py:102:1: error[invalid-assignment] Object of type `ShouldBeInvariant1[int]` is not assignable to `ShouldBeInvariant1[int | float]`
@@ -764,6 +764,8 @@
protocols_definition.py:287:1: error[invalid-assignment] Object of type `Concrete5_Bad3` is not assignable to `Template5`
protocols_definition.py:288:1: error[invalid-assignment] Object of type `Concrete5_Bad4` is not assignable to `Template5`
protocols_definition.py:289:1: error[invalid-assignment] Object of type `Concrete5_Bad5` is not assignable to `Template5`
+protocols_explicit.py:56:9: error[invalid-assignment] Object of type `tuple[int, int, str]` is not assignable to attribute `rgb` of type `tuple[int, int, int]`
+protocols_explicit.py:85:9: error[invalid-attribute-access] Cannot assign to ClassVar `cm1` from an instance of type `Self@__init__`
protocols_generic.py:40:1: error[invalid-assignment] Object of type `Concrete1` is not assignable to `Proto1[int, str]`
protocols_generic.py:56:5: error[invalid-assignment] Object of type `Box[int | float]` is not assignable to `Box[int]`
protocols_generic.py:66:5: error[invalid-assignment] Object of type `Sender[int]` is not assignable to `Sender[int | float]`
@@ -808,6 +810,11 @@
qualifiers_annotated.py:64:8: error[invalid-type-form] Special form `typing.Annotated` expected at least 2 arguments (one type and at least one metadata element)
qualifiers_annotated.py:91:1: error[call-non-callable] Object of type `typing.Annotated` is not callable
qualifiers_final_annotation.py:18:7: error[invalid-type-form] Type qualifier `typing.Final` expected exactly 1 argument, got 2
+qualifiers_final_annotation.py:52:9: error[invalid-assignment] Cannot assign to final attribute `ID4` on type `Self@__init__`
+qualifiers_final_annotation.py:54:9: error[invalid-assignment] Cannot assign to final attribute `ID5` on type `Self@__init__`
+qualifiers_final_annotation.py:57:13: error[invalid-assignment] Cannot assign to final attribute `ID6` on type `Self@__init__`
+qualifiers_final_annotation.py:59:13: error[invalid-assignment] Cannot assign to final attribute `ID6` on type `Self@__init__`
+qualifiers_final_annotation.py:65:9: error[invalid-assignment] Cannot assign to final attribute `ID7` on type `Self@method1`
qualifiers_final_annotation.py:71:1: error[invalid-assignment] Reassignment of `Final` symbol `RATE` is not allowed: Symbol later reassigned here
qualifiers_final_annotation.py:81:1: error[invalid-assignment] Cannot assign to final attribute `DEFAULT_ID` on type `<class 'ClassB'>`
qualifiers_final_annotation.py:118:9: error[invalid-type-form] Type qualifier `typing.Final` is not allowed in type expressions (only in annotation expressions)
@@ -915,5 +922,5 @@
typeddicts_usage.py:28:17: error[missing-typed-dict-key] Missing required key 'name' in TypedDict `Movie` constructor
typeddicts_usage.py:28:18: error[invalid-key] Invalid key access on TypedDict `Movie`: Unknown key "title"
typeddicts_usage.py:40:24: error[invalid-type-form] The special form `typing.TypedDict` is not allowed in type expressions. Did you mean to use a concrete TypedDict or `collections.abc.Mapping[str, object]` instead?
-Found 917 diagnostics
+Found 924 diagnostics
WARN A fatal error occurred while checking some files. Not all project files were analyzed. See the diagnostics list above for details. |
|
|
||
| class ThisFails: | ||
| def __init__(self): | ||
| # error: [invalid-assignment] "Implicit shadowing of function `__getattribute__`" |
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.
Probably something we should look at or create an issue for.
|
| Lint rule | Added | Removed | Changed |
|---|---|---|---|
unresolved-attribute |
5,931 | 0 | 0 |
possibly-missing-attribute |
3,292 | 8 | 21 |
invalid-argument-type |
1,989 | 6 | 117 |
unused-ignore-comment |
0 | 1,115 | 0 |
unsupported-operator |
939 | 2 | 5 |
invalid-assignment |
496 | 8 | 15 |
invalid-return-type |
386 | 74 | 14 |
non-subscriptable |
413 | 0 | 0 |
call-non-callable |
220 | 0 | 0 |
too-many-positional-arguments |
174 | 0 | 0 |
not-iterable |
130 | 0 | 0 |
no-matching-overload |
120 | 0 | 0 |
missing-argument |
114 | 0 | 0 |
possibly-missing-implicit-call |
92 | 4 | 10 |
unknown-argument |
66 | 0 | 0 |
deprecated |
28 | 0 | 0 |
parameter-already-assigned |
17 | 4 | 0 |
possibly-unresolved-reference |
0 | 19 | 0 |
redundant-cast |
18 | 0 | 0 |
division-by-zero |
6 | 4 | 0 |
index-out-of-bounds |
6 | 0 | 0 |
invalid-await |
4 | 0 | 1 |
invalid-context-manager |
3 | 0 | 0 |
type-assertion-failure |
0 | 3 | 0 |
invalid-attribute-access |
2 | 0 | 0 |
invalid-key |
2 | 0 | 0 |
missing-typed-dict-key |
2 | 0 | 0 |
unsupported-base |
2 | 0 | 0 |
invalid-parameter-default |
1 | 0 | 0 |
invalid-super-argument |
1 | 0 | 0 |
invalid-type-form |
1 | 0 | 0 |
| Total | 14,455 | 1,247 | 183 |
This comment was marked as resolved.
This comment was marked as resolved.
CodSpeed Performance ReportMerging #20922 will degrade performances by 16.56%Comparing Summary
Benchmarks breakdown
|
c6cfaf7 to
195669f
Compare
|
4bc8be9 to
9c4278d
Compare
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.
Congrats!
| .node(&module) | ||
| .parameters | ||
| .index(parameter.name()) | ||
| .is_some_and(|index| index != 0) |
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.
Should we also return here if the function has no parameter named parameter.name (which should never happen?)
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.
Or alternatively, can we pass the parameter index into infer_parameter_definition, and only call this method for the first parameter? Then we don't have to look up by name, and we don't have to verify that what we found was parameter 0.
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.
can we pass the parameter index into infer_parameter_definition
I see no way of doing that, unfortunately. The AST doesn't store the index of the parameter.
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.
It looks like element_offset is stabilizing soon — so in some number of months we'll be able to get the parameter index from the function's parameter slice without threading it through explicitly!
| .node(&module) | ||
| .parameters | ||
| .index(parameter.name()) | ||
| .is_some_and(|index| index != 0) |
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.
Or alternatively, can we pass the parameter index into infer_parameter_definition, and only call this method for the first parameter? Then we don't have to look up by name, and we don't have to verify that what we found was parameter 0.
Part of astral-sh/ty#159 Add support for adding a synthetic `typing.Self` type for `self` arguments in methods. `typing.Self` is assigned as the type if there are no annotations. - Updated md tests. --------- Co-authored-by: David Peter <mail@david-peter.de>
9c4278d to
c35cb85
Compare
c35cb85 to
0c3d16a
Compare
Summary
Infer a type of
Selffor unannotatedselfparameters in methods of classes.part of astral-sh/ty#159
closes astral-sh/ty#1081
Conformance tests changes
+enums_member_values.py:85:9: error[invalid-assignment] Object of type `int` is not assignable to attribute `_value_` of type `str`A true positive ✔️
Two false positives going away ✔️
+generics_syntax_infer_variance.py:82:9: error[invalid-assignment] Cannot assign to final attribute `x` on type `Self@__init__`This looks like a true positive to me, even if it's not marked with
# E✔️+protocols_explicit.py:56:9: error[invalid-assignment] Object of type `tuple[int, int, str]` is not assignable to attribute `rgb` of type `tuple[int, int, int]`True positive ✔️
This looks like a true positive to me, even if it's not marked with
# E. But this is consistent with our understanding ofClassVar, I think. ✔️New true positives ✔️
This is a new false positive, but that's a pre-existing issue on main (if you annotate with
Self): https://play.ty.dev/3ee1c56d-7e13-43bb-811a-7a81e236e6ab ❌ => reported as astral-sh/ty#1409Ecosystem
unresolved-attributeand 3292 newpossibly-missing-attributeattribute errors, way too many to look at all of them. I randomly sampled 15 of these errors and found:setattrdynamicness going on. I would consider all of them to be true positives.objin__new__, which we don't support yet__slots__Finalinstance attributes being set in__init__. I don't think this should block this PR.Test Plan
New Markdown tests.