Skip to content

Commit

Permalink
Fix self-referential upper bound in new-style type variables (#17407)
Browse files Browse the repository at this point in the history
Fixes #17347

This copies old-style `TypeVar` logic 1:1 (I know it is ugly, but I
don't think there is anything better now). Also while I am touching this
code, I am removing `third_pass` argument (third pass is not a thing for
~5 years now).
  • Loading branch information
ilevkivskyi committed Jun 20, 2024
1 parent c4470f1 commit f9d8f3a
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 8 deletions.
1 change: 0 additions & 1 deletion mypy/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,6 @@ def anal_type(
allow_tuple_literal: bool = False,
allow_unbound_tvars: bool = False,
report_invalid_types: bool = True,
third_pass: bool = False,
) -> Type | None:
"""Analyze an unbound type.
Expand Down
13 changes: 6 additions & 7 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1738,10 +1738,12 @@ def analyze_type_param(
) -> TypeVarLikeExpr | None:
fullname = self.qualified_name(type_param.name)
if type_param.upper_bound:
upper_bound = self.anal_type(type_param.upper_bound)
upper_bound = self.anal_type(type_param.upper_bound, allow_placeholder=True)
# TODO: we should validate the upper bound is valid for a given kind.
if upper_bound is None:
return None
# This and below copies special-casing for old-style type variables, that
# is equally necessary for new-style classes to break a vicious circle.
upper_bound = PlaceholderType(None, [], context.line)
else:
if type_param.kind == TYPE_VAR_TUPLE_KIND:
upper_bound = self.named_type("builtins.tuple", [self.object_type()])
Expand All @@ -1752,9 +1754,9 @@ def analyze_type_param(
values = []
if type_param.values:
for value in type_param.values:
analyzed = self.anal_type(value)
analyzed = self.anal_type(value, allow_placeholder=True)
if analyzed is None:
return None
analyzed = PlaceholderType(None, [], context.line)
values.append(analyzed)
return TypeVarExpr(
name=type_param.name,
Expand Down Expand Up @@ -7192,16 +7194,13 @@ def anal_type(
report_invalid_types: bool = True,
prohibit_self_type: str | None = None,
allow_type_any: bool = False,
third_pass: bool = False,
) -> Type | None:
"""Semantically analyze a type.
Args:
typ: Type to analyze (if already analyzed, this is a no-op)
allow_placeholder: If True, may return PlaceholderType if
encountering an incomplete definition
third_pass: Unused; only for compatibility with old semantic
analyzer
Return None only if some part of the type couldn't be bound *and* it
referred to an incomplete namespace or definition. In this case also
Expand Down
13 changes: 13 additions & 0 deletions test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,19 @@ d: E[int] # E: Type argument "int" of "E" must be a subtype of "str"
[builtins fixtures/tuple.pyi]
[typing fixtures/typing-full.pyi]

[case testCurrentClassWorksAsBound]
# flags: --enable-incomplete-feature=NewGenericSyntax
from typing import Protocol

class Comparable[T: Comparable](Protocol):
def compare(self, other: T) -> bool: ...

class Good:
def compare(self, other: Good) -> bool: ...

x: Comparable[Good]
y: Comparable[int] # E: Type argument "int" of "Comparable" must be a subtype of "Comparable[Any]"

[case testPEP695TypeAliasWithDifferentTargetTypes]
# flags: --enable-incomplete-feature=NewGenericSyntax
import types # We need GenericAlias from here, and test stubs don't bring in 'types'
Expand Down

0 comments on commit f9d8f3a

Please sign in to comment.