## Summary Improve the diagnostic range for `invalid-assignment` diagnostics, and add source annotations for the value and target type. closes https://github.com/astral-sh/ty/issues/1556 ### Before <img width="836" height="601" alt="image" src="https://github.com/user-attachments/assets/a48219bb-58a8-4a83-b290-d09ef50ce5f0" /> ### After <img width="857" height="742" alt="image" src="https://github.com/user-attachments/assets/cfcaa4f4-94fb-459e-8d64-97050dfecb50" /> ## Ecosystem impact Very good! Due to the wider diagnostic range, we now pick up more `# type: ignore` directives that were supposed to suppress an invalid assignment diagnostic. ## Test Plan New snapshot tests
2.0 KiB
Ellipsis
Function and methods
The ellipsis literal ... can be used as a placeholder default value for a function parameter, in a
stub file only, regardless of the type of the parameter.
def f(x: int = ...) -> None:
reveal_type(x) # revealed: int
def f2(x: str = ...) -> None:
reveal_type(x) # revealed: str
Class and module symbols
The ellipsis literal can be assigned to a class or module symbol, regardless of its declared type, in a stub file only.
y: bytes = ...
reveal_type(y) # revealed: bytes
x = ...
reveal_type(x) # revealed: Unknown
class Foo:
y: int = ...
reveal_type(Foo.y) # revealed: int
Unpacking ellipsis literal in assignment
No diagnostic is emitted if an ellipsis literal is "unpacked" in a stub file as part of an assignment statement:
x, y = ...
reveal_type(x) # revealed: Unknown
reveal_type(y) # revealed: Unknown
Unpacking ellipsis literal in for loops
Iterating over an ellipsis literal as part of a for loop in a stub is invalid, however, and
results in a diagnostic:
# error: [not-iterable] "Object of type `EllipsisType` is not iterable"
for a, b in ...:
reveal_type(a) # revealed: Unknown
reveal_type(b) # revealed: Unknown
Ellipsis usage in non stub file
In a non-stub file, there's no special treatment of ellipsis literals. An ellipsis literal can only
be assigned if EllipsisType is actually assignable to the annotated type.
# error: [invalid-parameter-default] "Default value of type `EllipsisType` is not assignable to annotated parameter type `int`"
def f(x: int = ...) -> None: ...
# error: [invalid-assignment] "Object of type `EllipsisType` is not assignable to `int`"
a: int = ...
b = ...
reveal_type(b) # revealed: EllipsisType
Use of Ellipsis symbol
There is no special treatment of the builtin name Ellipsis in stubs, only of ... literals.
# error: [invalid-parameter-default] "Default value of type `EllipsisType` is not assignable to annotated parameter type `int`"
def f(x: int = Ellipsis) -> None: ...