Skip to content

Conversation

@pareshjoshij
Copy link

Fixes #20308

Summary
This PR fixes a false positive [type-arg] error when reassigning a generic PEP 695 TypeAliasType to a variable without type arguments.

The Fix
Modified is_type_ref in semanal.py to return False when the target is a generic TypeAliasType used without subscripts. This forces the analyzer to treat it as a variable assignment rather than a type definition.

Verification
I verified this locally with a reproduction script.

@github-actions

This comment has been minimized.

Copy link
Collaborator

@hauntsaninja hauntsaninja left a comment

Choose a reason for hiding this comment

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

Would you mind adding tests for the new behaviour? test-data/unit/check-python312.test is a good place to add them

@pareshjoshij
Copy link
Author

Would you mind adding tests for the new behaviour? test-data/unit/check-python312.test is a good place to add them

@hauntsaninja Thanks for the review.

I added the regression test to check-python312.test, but I am hitting a persistent test fixture error locally: AssertionError: Var(TypeVar).

It seems the test environment defines TypeVar as a Var, but checkexpr.py expects it to be a TypeInfo (class) when analyzing the TypeAliasType assignment.

I tried adding [builtins fixtures/list.pyi] and [builtins fixtures/dict.pyi] to the test case to load full definitions, but the assertion failure persists.

Could you advise on which fixture is required for testing PEP 695 TypeAliasType assignments?

Here is the test case I am adding:

[[case testPep695GenericTypeAliasReassignment]
from typing import reveal_type

type A[T] = T | str
B = A
reveal_type(B)
[out]
main:5: note: Revealed type is "typing.TypeAliasType"
[builtins fixtures/tuple.pyi]

@pareshjoshij pareshjoshij force-pushed the fix-pep695-alias-reassignment branch from e7bda08 to c1f3b1e Compare November 29, 2025 05:17
@pareshjoshij
Copy link
Author

Would you mind adding tests for the new behaviour? test-data/unit/check-python312.test is a good place to add them

@hauntsaninja Thanks for the review.

I added the regression test to check-python312.test, but I am hitting a persistent test fixture error locally: AssertionError: Var(TypeVar).

It seems the test environment defines TypeVar as a Var, but checkexpr.py expects it to be a TypeInfo (class) when analyzing the TypeAliasType assignment.

I tried adding [builtins fixtures/list.pyi] and [builtins fixtures/dict.pyi] to the test case to load full definitions, but the assertion failure persists.

Could you advise on which fixture is required for testing PEP 695 TypeAliasType assignments?

Here is the test case I am adding:

[[case testPep695GenericTypeAliasReassignment]
from typing import reveal_type

type A[T] = T | str
B = A
reveal_type(B)
[out]
main:5: note: Revealed type is "typing.TypeAliasType"
[builtins fixtures/tuple.pyi]

Quick update: I managed to resolve the fixture issue mentioned above.

I found that explicitly adding [typing fixtures/typing-full.pyi] was required to ensure TypeVar is loaded as a TypeInfo (class) rather than a Var in the test environment. The regression test is now added and passing locally.

Please let me know if any further changes are required. Thanks for your kind attention to this matter!

@github-actions
Copy link
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Copy link
Collaborator

@hauntsaninja hauntsaninja left a comment

Choose a reason for hiding this comment

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

Nice, thanks for adding the test cases and fighting the fixtures (they're the most annoying part about developing mypy).

Hmm, looking at your test case I think this prevents the use of B in type annotations entirely. That is, def foo(x: B) -> None: ... will now emit an error Variable "B" is not valid as a type. I'm guessing that's not what @jorenham expects

Maybe there is a solution that involves looking at whether the right hand side is a Python 3.12 type alias in typeanal.py, maybe somewhere around instantiate_type_alias

@pareshjoshij
Copy link
Author

Nice, thanks for adding the test cases and fighting the fixtures (they're the most annoying part about developing mypy).

Hmm, looking at your test case I think this prevents the use of B in type annotations entirely. That is, def foo(x: B) -> None: ... will now emit an error Variable "B" is not valid as a type. I'm guessing that's not what @jorenham expects

Maybe there is a solution that involves looking at whether the right hand side is a Python 3.12 type alias in typeanal.py, maybe somewhere around instantiate_type_alias

@hauntsaninja Thank you again for your patience and detailed guidance. I want to confirm the final implementation strategy before pushing:

I will revert the logic in semanal.py back to its original state.

The fix will be implemented inside instantiate_type_alias in typeanal.py. We will add a check there that, if a generic PEP 695 alias is used with zero arguments (act_len == 0), the function immediately returns the raw TypeAliasType(node, []) object, bypassing the argument count error.

My understanding is that this solves the original assignment issue while preserving B as a valid generic type for later use (e.g., x: B[int]).

Does this core strategy align with your expectations?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

reassignment of a TypeAliasType should not be evaluated as type expression

2 participants