Skip to content

[ty] Add diagnostic hint for invalid assignments involving invariant generics#24032

Merged
sharkdp merged 2 commits intomainfrom
david/invariant-generics-hint
Mar 20, 2026
Merged

[ty] Add diagnostic hint for invalid assignments involving invariant generics#24032
sharkdp merged 2 commits intomainfrom
david/invariant-generics-hint

Conversation

@sharkdp
Copy link
Contributor

@sharkdp sharkdp commented Mar 18, 2026

Summary

Relates to this FAQ entry. Consider

def modify(xs: list[int]):
    xs.append(42)

answers: list[bool] = [True, False]
modify(answers)

With this change, we now emit some info hints in the invalid-assignment diagnostic:

image

Test Plan

New snapshot tests

@sharkdp sharkdp added the ty Multi-file analysis & type inference label Mar 18, 2026
@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 18, 2026

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 85.29%. The percentage of expected errors that received a diagnostic held steady at 78.13%. The number of fully passing files held steady at 64/132.

@sharkdp sharkdp force-pushed the david/invariant-generics-hint branch 2 times, most recently from 87e40a0 to fa11478 Compare March 18, 2026 14:43
@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 18, 2026

Memory usage report

Memory usage unchanged ✅

11 |
12 | def _(source: dict[bool, str]):
|
info: `dict` is invariant in its second type parameter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could also invest a bit more effort and refer to the name of the type parameter (_VT@dict in this case), if that seems helpful.

|
info: `dict` is invariant in its first type parameter
info: For more information, see https://docs.astral.sh/ty/reference/typing-faq/#invariant-generics
info: rule `invalid-assignment` is enabled by default
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, we test that we do not emit the "Consider using … collections.abc.Mapping" hint, because Mapping is still invariant in its key type, so that wouldn't help here.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Mar 18, 2026

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

41 |
42 | def _(source: MutableSequence[bool]):
|
info: `Counter` is invariant in its type parameter
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no covariant supertype suggestion for Counter because it's type parameter corresponds to a key-like parameter of dict.

Comment on lines +335 to +350
error[invalid-assignment]: Object of type `MutableSequence[bool]` is not assignable to `MutableSequence[int]`
--> src/mdtest_snippet.py:43:13
|
42 | def _(source: MutableSequence[bool]):
43 | target: MutableSequence[int] = source # error: [invalid-assignment]
| -------------------- ^^^^^^ Incompatible value of type `MutableSequence[bool]`
| |
| Declared type
44 |
45 | def _(source: MutableSet[bool]):
|
info: `MutableSequence` is invariant in its type parameter
info: Consider using the covariant supertype `collections.abc.Sequence`
info: For more information, see https://docs.astral.sh/ty/reference/typing-faq/#invariant-generics
info: rule `invalid-assignment` is enabled by default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about these. It seems a bit silly. If you explicitly annotated something with MutableSequence, you probably meant it?

63 | target: list[str] = source # error: [invalid-assignment]
|
info: `MyContainer` is invariant in its type parameter
info: For more information, see https://docs.astral.sh/ty/reference/typing-faq/#invariant-generics
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to refer to that FAQ entry even for user types.

Comment on lines +427 to +438
error[invalid-assignment]: Object of type `list[int]` is not assignable to `list[str]`
--> src/mdtest_snippet.py:63:13
|
61 | target: MyContainer[int] = source # error: [invalid-assignment]
62 | def _(source: list[int]):
63 | target: list[str] = source # error: [invalid-assignment]
| --------- ^^^^^^ Incompatible value of type `list[int]`
| |
| Declared type
64 | from collections.abc import Sequence
|
info: rule `invalid-assignment` is enabled by default
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that there is no hint at all here. Something is more fundamentally wrong with your code if you're trying to assign a list[str] to a list[int]. And it's unlikely that we can help you by teaching you about invariant generics.

@sharkdp sharkdp force-pushed the david/invariant-generics-hint branch from fa11478 to 1850d53 Compare March 18, 2026 20:26
@sharkdp sharkdp marked this pull request as ready for review March 18, 2026 20:26
@astral-sh-bot astral-sh-bot bot requested a review from oconnor663 March 18, 2026 20:26
@carljm carljm removed their request for review March 18, 2026 20:38
@oconnor663 oconnor663 removed their assignment Mar 19, 2026
@sharkdp sharkdp merged commit 11ef7f4 into main Mar 20, 2026
48 checks passed
@sharkdp sharkdp deleted the david/invariant-generics-hint branch March 20, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants