Skip to content
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
a760300
[ty] Introduce "assignment target" and integrate the symbol table and…
mtshiba May 10, 2025
c28be0d
support narrowing by attribute/subscript assignment
mtshiba May 12, 2025
792d1eb
refactor
mtshiba May 12, 2025
fee1c1c
unify handling of adding definition
mtshiba May 15, 2025
848bb5b
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 15, 2025
3ba4a27
update docs
mtshiba May 15, 2025
5873c1f
unify target load inferring
mtshiba May 15, 2025
70c4da7
(partially) fix comprehension definition bug
mtshiba May 16, 2025
78c8155
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 16, 2025
40f07dc
(partially) fix comprehension definition bug (2)
mtshiba May 16, 2025
f2db5d6
Update nested.md
mtshiba May 16, 2025
30d7074
refactor: `Target` -> `Place`
mtshiba May 16, 2025
1c4c7ab
add explanation about "place"
mtshiba May 16, 2025
cce43f0
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 16, 2025
4f3c9fc
refactor: `symbol` -> `place`
mtshiba May 18, 2025
2a4c4e4
`infer_expression_types` called during narrowing may cause a cycle
mtshiba May 18, 2025
691e813
move packages that fail with mypy_primer to bad.txt
mtshiba May 18, 2025
9c8ed04
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 18, 2025
bde827f
remove unnecessary code
mtshiba May 18, 2025
1885ea9
Revert "remove unnecessary code"
mtshiba May 18, 2025
7892bd3
modify & add document comments
mtshiba May 18, 2025
255d756
remove `explicit_global_place`, `global_place`
mtshiba May 19, 2025
ae8769b
Don't narrow the result type of a customized subscript by assignment
mtshiba May 19, 2025
83fd836
replac `place` with a more appropriate implementation and add `fallba…
mtshiba May 19, 2025
94acd47
move packages that fail with mypy_primer to bad.txt
mtshiba May 19, 2025
757e5da
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 20, 2025
8d78b41
Update assignment.md
mtshiba May 20, 2025
eb87936
Don't narrow the type of invalid place expressions
mtshiba May 21, 2025
e67c5a2
Update assignment.md
mtshiba May 21, 2025
0b74511
Update attributes.md
mtshiba May 23, 2025
34b1f34
Move a package that pass the check by mypy_primer to good.txt
mtshiba May 23, 2025
d3329c4
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 23, 2025
f26e9cf
refactor: `symbol` -> `place`
mtshiba May 23, 2025
694ee4b
Update attributes.md
mtshiba May 23, 2025
ed31a14
Update crates/ty_python_semantic/src/semantic_index/place.rs
mtshiba May 23, 2025
8e68d3f
Update crates/ty_python_semantic/resources/mdtest/narrow/assignment.md
mtshiba May 23, 2025
99dcf14
Apply suggestions from code review
mtshiba May 23, 2025
0b97b1f
Update crates/ty_python_semantic/src/semantic_index/definition.rs
mtshiba May 24, 2025
ec51668
remove workaround & add a regression test
mtshiba May 24, 2025
cde9217
Don't perform assignment-based subscript narrowing on subclasses of s…
mtshiba May 24, 2025
f6c4182
do type checking for annotated assignments of non-name targets
mtshiba May 25, 2025
6dcafb4
Revert "do type checking for annotated assignments of non-name targets"
mtshiba May 25, 2025
d62f7ca
minor fix & add comments, test cases
mtshiba May 25, 2025
dabe595
(WIP) disable place narrowing by overwriting root attributes
mtshiba May 26, 2025
eee9821
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 26, 2025
d40efec
record only the unbound name binding in `unbound_narrowing_constraint`
mtshiba May 26, 2025
1bf58b7
fix performance regression in `associated_place_ids`, `root_place_exprs`
mtshiba May 27, 2025
6b5b365
improve data descriptor checking
mtshiba May 31, 2025
9e6e50d
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 31, 2025
3666afa
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba May 31, 2025
69e7180
revert declared-only instance-attribute special case for now
carljm May 31, 2025
80b5dea
alphabetize good.txt
carljm May 31, 2025
5a2f7b0
Update crates/ty_python_semantic/src/semantic_index/place.rs
mtshiba May 31, 2025
5a0798a
delete `fallback_place` and infer the `node` type
mtshiba May 31, 2025
e928898
style fix & add docs
mtshiba May 31, 2025
a22e754
Merge remote-tracking branch 'upstream/main' into narrow_by_assignment
mtshiba Jun 3, 2025
d417c65
add docs for `DefinitionState::Undefined`
mtshiba Jun 3, 2025
ba6d9c1
Move `schemathesis` to bad.txt and `static-frame`, `sympy` to good.txt
mtshiba Jun 3, 2025
ac84635
add cycle handling for class_member_with_policy
carljm Jun 4, 2025
fcc7ee0
move schemathesis back to good.txt
carljm Jun 4, 2025
8160cbb
a few tweaks from review
carljm Jun 4, 2025
4007c36
Merge branch 'main' into narrow_by_assignment
carljm Jun 4, 2025
820f75a
use SmallVec for place-expr segments
carljm Jun 4, 2025
17a9e9b
no boolean flag argument on is_data_descriptor
carljm Jun 4, 2025
af373dd
Merge branch 'main' into narrow_by_assignment
carljm Jun 4, 2025
63119d3
Merge branch 'main' into narrow_by_assignment
carljm Jun 4, 2025
78b6dce
extract TypeInferenceBuilder::infer_maybe_standalone_expression
carljm Jun 4, 2025
da118e8
minor adjustments
carljm Jun 4, 2025
77122d3
simplify check for descriptor
carljm Jun 4, 2025
2a4cc40
reformat a comment
carljm Jun 4, 2025
bc72edb
remove comprehension scope-traveling
carljm Jun 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This is a regression test for `infer_expression_types`.
# ref: https://github.com/astral-sh/ruff/pull/18041#discussion_r2094573989

class C:
def f(self, other: "C"):
if self.a > other.b or self.b:
return False
if self:
return True

C().a
53 changes: 29 additions & 24 deletions crates/ty_python_semantic/resources/mdtest/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ reveal_type(c_instance.inferred_from_other_attribute) # revealed: Unknown
# See https://github.com/astral-sh/ruff/issues/15960 for a related discussion.
reveal_type(c_instance.inferred_from_param) # revealed: Unknown | int | None

reveal_type(c_instance.declared_only) # revealed: bytes
# TODO: Should be `bytes` with no error, like mypy and pyright?
# error: [unresolved-attribute]
reveal_type(c_instance.declared_only) # revealed: Unknown

reveal_type(c_instance.declared_and_bound) # revealed: bool

Expand All @@ -64,12 +66,10 @@ C.inferred_from_value = "overwritten on class"
# This assignment is fine:
c_instance.declared_and_bound = False

# TODO: After this assignment to the attribute within this scope, we may eventually want to narrow
# the `bool` type (see above) for this instance variable to `Literal[False]` here. This is unsound
# in general (we don't know what else happened to `c_instance` between the assignment and the use
# here), but mypy and pyright support this. In conclusion, this could be `bool` but should probably
# be `Literal[False]`.
reveal_type(c_instance.declared_and_bound) # revealed: bool
# Strictly speaking, inferring this as `Literal[False]` rather than `bool` is unsound in general
# (we don't know what else happened to `c_instance` between the assignment and the use here),
# but mypy and pyright support this.
reveal_type(c_instance.declared_and_bound) # revealed: Literal[False]
```

#### Variable declared in class body and possibly bound in `__init__`
Expand Down Expand Up @@ -149,14 +149,16 @@ class C:
c_instance = C(True)

reveal_type(c_instance.only_declared_in_body) # revealed: str | None
reveal_type(c_instance.only_declared_in_init) # revealed: str | None
# TODO: should be `str | None` without error
# error: [unresolved-attribute]
reveal_type(c_instance.only_declared_in_init) # revealed: Unknown
reveal_type(c_instance.declared_in_body_and_init) # revealed: str | None

reveal_type(c_instance.declared_in_body_defined_in_init) # revealed: str | None

# TODO: This should be `str | None`. Fixing this requires an overhaul of the `Symbol` API,
# which is planned in https://github.com/astral-sh/ruff/issues/14297
reveal_type(c_instance.bound_in_body_declared_in_init) # revealed: Unknown | str | None
reveal_type(c_instance.bound_in_body_declared_in_init) # revealed: Unknown | Literal["a"]

reveal_type(c_instance.bound_in_body_and_init) # revealed: Unknown | None | Literal["a"]
```
Expand Down Expand Up @@ -187,7 +189,9 @@ reveal_type(c_instance.inferred_from_other_attribute) # revealed: Unknown

reveal_type(c_instance.inferred_from_param) # revealed: Unknown | int | None

reveal_type(c_instance.declared_only) # revealed: bytes
# TODO: should be `bytes` with no error, like mypy and pyright?
# error: [unresolved-attribute]
reveal_type(c_instance.declared_only) # revealed: Unknown

reveal_type(c_instance.declared_and_bound) # revealed: bool

Expand Down Expand Up @@ -260,8 +264,8 @@ class C:
self.w += None

# TODO: Mypy and pyright do not support this, but it would be great if we could
# infer `Unknown | str` or at least `Unknown | Weird | str` here.
reveal_type(C().w) # revealed: Unknown | Weird
# infer `Unknown | str` here (`Weird` is not a possible type for the `w` attribute).
reveal_type(C().w) # revealed: Unknown
```

#### Attributes defined in tuple unpackings
Expand Down Expand Up @@ -410,6 +414,11 @@ class C:
[... for self.a in IntIterable()]
[... for (self.b, self.c) in TupleIterable()]
[... for self.d in IntIterable() for self.e in IntIterable()]
[[... for self.f in IntIterable()] for _ in IntIterable()]
[[... for self.g in IntIterable()] for self in [D()]]

class D:
g: int

c_instance = C()

Expand All @@ -418,6 +427,9 @@ reveal_type(c_instance.b) # revealed: Unknown | int
reveal_type(c_instance.c) # revealed: Unknown | str
reveal_type(c_instance.d) # revealed: Unknown | int
reveal_type(c_instance.e) # revealed: Unknown | int
reveal_type(c_instance.f) # revealed: Unknown | int
# TODO: This should be an unresolved attribute
reveal_type(c_instance.g) # revealed: Unknown | int
```

#### Conditionally declared / bound attributes
Expand Down Expand Up @@ -721,8 +733,8 @@ reveal_type(C.pure_class_variable) # revealed: Unknown
# error: [invalid-attribute-access] "Cannot assign to instance attribute `pure_class_variable` from the class object `<class 'C'>`"
C.pure_class_variable = "overwritten on class"

# TODO: should be `Unknown | Literal["value set in class method"]` or
# Literal["overwritten on class"]`, once/if we support local narrowing.
# TODO: should be `Literal["overwritten on class"]`.
# Once this attribute resolution is supported, narrowing by assignment should work.
# error: [unresolved-attribute]
reveal_type(C.pure_class_variable) # revealed: Unknown

Expand Down Expand Up @@ -762,19 +774,12 @@ reveal_type(c_instance.variable_with_class_default2) # revealed: Unknown | Lite
c_instance.variable_with_class_default1 = "value set on instance"

reveal_type(C.variable_with_class_default1) # revealed: str

# TODO: Could be Literal["value set on instance"], or still `str` if we choose not to
# narrow the type.
reveal_type(c_instance.variable_with_class_default1) # revealed: str
reveal_type(c_instance.variable_with_class_default1) # revealed: Literal["value set on instance"]

C.variable_with_class_default1 = "overwritten on class"

# TODO: Could be `Literal["overwritten on class"]`, or still `str` if we choose not to
# narrow the type.
reveal_type(C.variable_with_class_default1) # revealed: str

# TODO: should still be `Literal["value set on instance"]`, or `str`.
reveal_type(c_instance.variable_with_class_default1) # revealed: str
reveal_type(C.variable_with_class_default1) # revealed: Literal["overwritten on class"]
reveal_type(c_instance.variable_with_class_default1) # revealed: Literal["value set on instance"]
```

#### Descriptor attributes as class variables
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,7 @@ class C:
descriptor = Descriptor()

C.descriptor = "something else"

# This could also be `Literal["something else"]` if we support narrowing of attribute types based on assignments
reveal_type(C.descriptor) # revealed: Unknown | int
reveal_type(C.descriptor) # revealed: Literal["something else"]
```

### Possibly unbound descriptor attributes
Expand Down
Loading
Loading