Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Double-test some existing tests
  • Loading branch information
ilevkivskyi committed Aug 1, 2022
commit e7914bf60197e0b0c6f523c6c6671bdaa4650c63
2 changes: 1 addition & 1 deletion mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4555,7 +4555,7 @@ def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]]
if self.found_incomplete_ref(tag):
return None
if self.basic_type_applications:
# Postpone the rest until we are sure this is not a r.h.s. of a type alias.
# Postpone the rest until we have more information (for r.h.s. of an assignment)
return None
types: List[Type] = []
if isinstance(index, TupleExpr):
Expand Down
120 changes: 120 additions & 0 deletions test-data/unit/check-recursive-types.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
-- Tests checking that basic functionality works

[case testRecursiveAliasBasic]
# flags: --enable-recursive-aliases
from typing import Dict, List, Union, TypeVar, Sequence
Expand Down Expand Up @@ -70,5 +72,123 @@ else:

[file test.pyi]
A = int | list[A]
[builtins fixtures/isinstancelist.pyi]

-- Tests duplicating some existing tests with recursive aliases enabled

[case testRecursiveAliasesMutual]
# flags: --enable-recursive-aliases
from typing import Type, Callable, Union

A = Union[B, int]
B = Callable[[C], int]
C = Type[A]
x: A
reveal_type(x) # N: Revealed type is "Union[def (Union[Type[def (...) -> builtins.int], Type[builtins.int]]) -> builtins.int, builtins.int]"

[case testRecursiveAliasesProhibited-skip]
# flags: --enable-recursive-aliases
from typing import Type, Callable, Union

A = Union[B, int]
B = Union[A, int]
C = Type[C]

[case testRecursiveAliasImported]
# flags: --enable-recursive-aliases
import lib
x: lib.A
reveal_type(x) # N: Revealed type is "builtins.list[builtins.list[...]]"

[file lib.pyi]
from typing import List
from other import B
A = List[B]

[file other.pyi]
from typing import List
from lib import A
B = List[A]
[builtins fixtures/list.pyi]

[case testRecursiveAliasViaBaseClass]
# flags: --enable-recursive-aliases
from typing import List

x: B
B = List[C]
class C(B): pass

reveal_type(x) # N: Revealed type is "builtins.list[__main__.C]"
reveal_type(x[0][0]) # N: Revealed type is "__main__.C"
[builtins fixtures/list.pyi]

[case testRecursiveAliasViaBaseClass2]
# flags: --enable-recursive-aliases
from typing import NewType, List

x: D
reveal_type(x[0][0]) # N: Revealed type is "__main__.C"

D = List[C]
C = NewType('C', B)

class B(D):
pass
[builtins fixtures/list.pyi]

[case testRecursiveAliasViaBaseClass3]
# flags: --enable-recursive-aliases
from typing import List, Generic, TypeVar, NamedTuple
T = TypeVar('T')

class C(A, B):
pass
class G(Generic[T]): pass
A = G[C]
class B(NamedTuple):
x: int

y: C
reveal_type(y.x) # N: Revealed type is "builtins.int"
reveal_type(y[0]) # N: Revealed type is "builtins.int"
x: A
reveal_type(x) # N: Revealed type is "__main__.G[Tuple[builtins.int, fallback=__main__.C]]"
[builtins fixtures/list.pyi]

[case testRecursiveAliasViaBaseClassImported]
# flags: --enable-recursive-aliases
import a
[file a.py]
from typing import List
from b import D

def f(x: B) -> List[B]: ...
B = List[C]
class C(B): pass

[file b.py]
from a import f
class D: ...
reveal_type(f) # N: Revealed type is "def (x: builtins.list[a.C]) -> builtins.list[builtins.list[a.C]]"
[builtins fixtures/list.pyi]

[case testRecursiveAliasViaNamedTuple]
# flags: --enable-recursive-aliases
from typing import List, NamedTuple, Union

Exp = Union['A', 'B']
class A(NamedTuple('A', [('attr', List[Exp])])): pass
class B(NamedTuple('B', [('val', object)])): pass

def my_eval(exp: Exp) -> int:
reveal_type(exp) # N: Revealed type is "Union[Tuple[builtins.list[...], fallback=__main__.A], Tuple[builtins.object, fallback=__main__.B]]"
if isinstance(exp, A):
my_eval(exp[0][0])
return my_eval(exp.attr[0])
if isinstance(exp, B):
return exp.val # E: Incompatible return value type (got "object", expected "int")
return 0

my_eval(A([B(1), B(2)]))
[builtins fixtures/isinstancelist.pyi]