Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions mypy/message_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def with_additional_msg(self, info: str) -> ErrorMessage:
"Await expression cannot be used as a type variable bound", codes.SYNTAX
)

TYPE_VAR_GENERIC_CONSTRAINT_TYPE: Final = ErrorMessage(
"TypeVar constraint type cannot be parametrized by type variables", codes.MISC
)

TYPE_ALIAS_WITH_YIELD_EXPRESSION: Final = ErrorMessage(
"Yield expression cannot be used within a type alias", codes.SYNTAX
)
Expand Down
15 changes: 12 additions & 3 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@
UnpackType,
get_proper_type,
get_proper_types,
has_type_vars,
is_named_instance,
remove_dups,
type_vars_as_args,
Expand Down Expand Up @@ -1856,13 +1857,17 @@ def analyze_type_param(
else:
default = AnyType(TypeOfAny.from_omitted_generics)
if type_param.kind == TYPE_VAR_KIND:
values = []
values: list[Type] = []
if type_param.values:
for value in type_param.values:
analyzed = self.anal_type(value, allow_placeholder=True)
if analyzed is None:
analyzed = PlaceholderType(None, [], context.line)
values.append(analyzed)
if has_type_vars(analyzed):
self.fail(message_registry.TYPE_VAR_GENERIC_CONSTRAINT_TYPE, context)
values.append(AnyType(TypeOfAny.from_error))
else:
values.append(analyzed)
return TypeVarExpr(
name=type_param.name,
fullname=fullname,
Expand Down Expand Up @@ -5044,7 +5049,11 @@ def analyze_value_types(self, items: list[Expression]) -> list[Type]:
# soon, even if some value is not ready yet, see process_typevar_parameters()
# for an example.
analyzed = PlaceholderType(None, [], node.line)
result.append(analyzed)
if has_type_vars(analyzed):
self.fail(message_registry.TYPE_VAR_GENERIC_CONSTRAINT_TYPE, node)
result.append(AnyType(TypeOfAny.from_error))
else:
result.append(analyzed)
except TypeTranslationError:
self.fail("Type expected", node)
result.append(AnyType(TypeOfAny.from_error))
Expand Down
23 changes: 23 additions & 0 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,29 @@ reveal_type(E[str]().a) # N: Revealed type is "builtins.list[Any]"
[builtins fixtures/type.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695TypeAliasInvalidGenericConstraint]
class A[T]:
class a[S: (int, list[T])]: pass # E: Name "T" is not defined
type b[S: (int, list[T])] = S # E: TypeVar constraint type cannot be parametrized by type variables
def c[S: (int, list[T])](self) -> None: ... # E: TypeVar constraint type cannot be parametrized by type variables
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695TypeAliasUnboundTypeVarConstraint]
from typing import TypeVar
T = TypeVar("T")
class a[S: (int, list[T])]: pass # E: Type variable "__main__.T" is unbound \
# N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \
# N: (Hint: Use "T" in function signature to bind "T" inside a function)
type b[S: (int, list[T])] = S # E: Type variable "__main__.T" is unbound \
# N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \
# N: (Hint: Use "T" in function signature to bind "T" inside a function)
def c[S: (int, list[T])](self) -> None: ... # E: Type variable "__main__.T" is unbound \
# N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \
# N: (Hint: Use "T" in function signature to bind "T" inside a function)
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testPEP695RedefineAsTypeAlias1]
class C: pass
type C = int # E: Name "C" already defined on line 1
Expand Down
16 changes: 16 additions & 0 deletions test-data/unit/semanal-errors.test
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,22 @@ S = TypeVar('S', covariant=True, contravariant=True) \
# E: TypeVar cannot be both covariant and contravariant
[builtins fixtures/bool.pyi]

[case testInvalidTypevarArgumentsGenericConstraint]
from typing import Generic, List, TypeVar
from typing_extensions import Self

T = TypeVar("T")

def f(x: T) -> None:
Bad = TypeVar("Bad", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables
class C(Generic[T]):
Bad = TypeVar("Bad", int, List[T]) # E: TypeVar constraint type cannot be parametrized by type variables
class D:
Bad = TypeVar("Bad", int, List[Self]) # E: TypeVar constraint type cannot be parametrized by type variables
S = TypeVar("S", int, List[T]) # E: Type variable "__main__.T" is unbound \
# N: (Hint: Use "Generic[T]" or "Protocol[T]" base class to bind "T" inside a class) \
# N: (Hint: Use "T" in function signature to bind "T" inside a function)

[case testInvalidTypevarValues]
from typing import TypeVar
b = TypeVar('b', *[int]) # E: Unexpected argument to "TypeVar()"
Expand Down