8000 New semantic analyzer: enable remaining tests and fix issues (#6969) · python/mypy@16ade15 · GitHub
[go: up one dir, main page]

Skip to content

Commit 16ade15

Browse files
authored
New semantic analyzer: enable remaining tests and fix issues (#6969)
This enables incremental mode tests for the new semantic analyzer. Some tests are skipped, mostly because of issues related to recursive type definitions and plugins. Also fix some issues related to type aliases and recursive definitions. Remove support for skipping test files when using the new semantic analyzer.
1 parent 9684b30 commit 16ade15

File tree

6 files changed

+113
-47
lines changed

6 files changed

+113
-47
lines changed

mypy/newsemanal/semanal.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,6 +2302,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
23022302
23032303
Return True if it is a type alias (even if the target is not ready),
23042304
or False otherwise.
2305+
23052306
Note: the resulting types for subscripted (including generic) aliases
23062307
are also stored in rvalue.analyzed.
23072308
"""
@@ -2320,11 +2321,13 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
23202321
# B = int
23212322
# B = float # Error!
23222323
# Don't create an alias in these cases:
2323-
if existing and (isinstance(existing.node, Var) or # existing variable
2324-
isinstance(existing.node, TypeAlias) and not s.is_alias_def or # existing alias
2325-
(isinstance(existing.node, PlaceholderNode) and
2326-
# TODO: find a more robust way to track the order of definitions.
2327-
existing.node.node.line < s.line)): # or previous incomplete definition
2324+
if (existing
2325+
and (isinstance(existing.node, Var) # existing variable
2326+
or (isinstance(existing.node, TypeAlias)
2327+
and not s.is_alias_def) # existing alias
2328+
or (isinstance(existing.node, PlaceholderNode)
2329+
and existing.node.node.line < s.line))): # previous incomplete definition
2330+
# TODO: find a more robust way to track the order of definitions.
23282331
# Note: if is_alias_def=True, this is just a node from previous iteration.
23292332
if isinstance(existing.node, TypeAlias) and not s.is_alias_def:
23302333
self.fail('Cannot assign multiple types to name "{}"'
@@ -2349,6 +2352,10 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
23492352
if not self.can_be_type_alias(rvalue):
23502353
return False
23512354

2355+
if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)):
2356+
# Cannot redefine existing node as type alias.
2357+
return False
2358+
23522359
res = None # type: Optional[Type]
23532360
if self.is_none_alias(rvalue):
23542361
res = NoneType()
@@ -2390,21 +2397,27 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
23902397
alias_node = TypeAlias(res, self.qualified_name(lvalue.name), s.line, s.column,
23912398
alias_tvars=alias_tvars, no_args=no_args)
23922399
if existing:
2393-
# Did alias get updated?
2394-
if (isinstance(existing.node, PlaceholderNode) or
2395-
isinstance(existing.node, TypeAlias) and existing.node.target != res):
2396-
self.progress = True
2397-
# We need to defer so that this change can get propagated to base classes.
2398-
self.defer()
2400+
# An alias gets updated.
2401+
if self.final_iteration:
2402+
self.cannot_resolve_name(lvalue.name, 'name', s)
2403+
return True
2404+
updated = False
23992405
if isinstance(existing.node, TypeAlias):
2400-
# Copy expansion to the existing alias, this matches how we update base classes
2401-
# for a TypeInfo _in place_ if there are nested placeholders.
2402-
existing.node.target = res
2403-
existing.node.alias_tvars = alias_tvars
2404-
existing.node.no_args = no_args
2406+
if existing.node.target != res:
2407+
# Copy expansion to the existing alias, this matches how we update base classes
2408+
# for a TypeInfo _in place_ if there are nested placeholders.
2409+
existing.node.target = res
2410+
existing.node.alias_tvars = alias_tvars
2411+
existing.node.no_args = no_args
2412+
updated = True
24052413
else:
24062414
# Otherwise just replace existing placeholder with type alias.
24072415
existing.node = alias_node
2416+
updated = True
2417+
if updated:
2418+
self.progress = True
2419+
# We need to defer so that this change can get propagated to base classes.
2420+
self.defer()
24082421
else:
24092422
self.add_symbol(lvalue.name, alias_node, s)
24102423
if isinstance(rvalue, RefExpr) and isinstance(rvalue.node, TypeAlias):

mypy/newsemanal/typeanal.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,21 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
165165
if node.becomes_typeinfo:
166166
# Reference to placeholder type.
167167
if self.api.final_iteration:
168-
# TODO: Move error message generation to messages.py. We'd first
169-
# need access to MessageBuilder here. Also move the similar
170-
# message generation logic in semanal.py.
171-
self.api.fail(
172-
'Cannot resolve name "{}" (possible cyclic definition)'.format(t.name),
173-
t)
168+
self.cannot_resolve_type(t)
174169
return AnyType(TypeOfAny.from_error)
175170
elif self.allow_placeholder:
176171
self.api.defer()
177172
else:
178173
self.api.record_incomplete_ref()
179174
return PlaceholderType(node.fullname(), self.anal_array(t.args), t.line)
180175
else:
181-
# Reference to an unknown placeholder node.
182-
self.api.record_incomplete_ref()
183-
return AnyType(TypeOfAny.special_form)
176+
if self.api.final_iteration:
177+
self.cannot_resolve_type(t)
178+
return AnyType(TypeOfAny.from_error)
179+
else:
180+
# Reference to an unknown placeholder node.
181+
self.api.record_incomplete_ref()
182+
return AnyType(TypeOfAny.special_form)
184183
if node is None:
185184
self.fail('Internal error (node is None, kind={})'.format(sym.kind), t)
186185
return AnyType(TypeOfAny.special_form)
@@ -224,6 +223,14 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
224223
else: # sym is None
225224
return AnyType(TypeOfAny.special_form)
226225

226+
def cannot_resolve_type(self, t: UnboundType) -> None:
227+
# TODO: Move error message generation to messages.py. We'd first
228+
# need access to MessageBuilder here. Also move the similar
229+
# message generation logic in semanal.py.
230+
self.api.fail(
231+
'Cannot resolve name "{}" (possible cyclic definition)'.format(t.name),
232+
t)
233+
227234
def try_analyze_special_unbound_type(self, t: UnboundType, fullname: str) -> Optional[Type]:
228235
"""Bind special type that is recognized through magic name such as 'typing.Any'.
229236

mypy/test/data.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from typing import List, Tuple, Set, Optional, Iterator, Any, Dict, NamedTuple, Union
1515

1616
from mypy.test.config import test_data_prefix, test_temp_dir, PREFIX
17-
from mypy.test.hacks import new_semanal_blacklist
1817

1918
root_dir = os.path.normpath(PREFIX)
2019

@@ -205,8 +204,6 @@ def __init__(self,
205204
if ((platform == 'windows' and sys.platform != 'win32')
206205
or (platform == 'posix' and sys.platform == 'win32')):
207206
skip = True
208-
if os.getenv('NEWSEMANAL') and os.path.split(file)[-1] in new_semanal_blacklist:
209-
skip = True
210207
self.skip = skip
211208
self.data = data
212209
self.line = line

mypy/test/hacks.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

test-data/unit/check-incremental.test

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,6 +2465,7 @@ x: int = C()[0][0]
24652465
[out]
24662466

24672467
[case testForwardTypeAliasInBase2]
2468+
# flags: --new-semantic-analyzer
24682469
from typing import List, Generic, TypeVar, NamedTuple
24692470
T = TypeVar('T')
24702471

@@ -2475,12 +2476,13 @@ A = G[C]
24752476
class B(NamedTuple):
24762477
x: int
24772478

2478-
C().x
2479-
C()[0]
2479+
C(1).x
2480+
C(1)[0]
24802481
[builtins fixtures/list.pyi]
24812482
[out]
24822483

24832484
[case testSerializeRecursiveAliases1]
2485+
# flags: --no-new-semantic-analyzer
24842486
from typing import Type, Callable, Union
24852487

24862488
A = Union[A, int] # type: ignore
@@ -2489,6 +2491,7 @@ C = Type[C] # type: ignore
24892491
[out]
24902492

24912493
[case testSerializeRecursiveAliases2]
2494+
# flags: --no-new-semantic-analyzer
24922495
from typing import Type, Callable, Union
24932496

24942497
A = Union[B, int] # type: ignore
@@ -2497,6 +2500,7 @@ C = Type[A] # type: ignore
24972500
[out]
24982501

24992502
[case testSerializeRecursiveAliases3]
2503+
# flags: --no-new-semantic-analyzer
25002504
from typing import Type, Callable, Union, NamedTuple
25012505

25022506
A = Union[B, int] # type: ignore
@@ -2566,6 +2570,7 @@ M = NamedTuple('M', [('x', int)])
25662570
[out]
25672571

25682572
[case testSelfRefNTIncremental1]
2573+
# flags: --no-new-semantic-analyzer
25692574
from typing import Tuple, NamedTuple
25702575

25712576
Node = NamedTuple('Node', [ # type: ignore
@@ -2576,6 +2581,7 @@ n: Node
25762581
[builtins fixtures/tuple.pyi]
25772582

25782583
[case testSelfRefNTIncremental2]
2584+
# flags: --no-new-semantic-analyzer
25792585
from typing import Tuple, NamedTuple
25802586

25812587
A = NamedTuple('A', [ # type: ignore
@@ -2590,6 +2596,7 @@ n: A
25902596
[builtins fixtures/tuple.pyi]
25912597

25922598
[case testSelfRefNTIncremental3]
2599+
# flags: --no-new-semantic-analyzer
25932600
from typing import NamedTuple, Tuple
25942601

25952602
class B(NamedTuple): # type: ignore
@@ -2605,6 +2612,7 @@ lst = [m, n]
26052612
[builtins fixtures/tuple.pyi]
26062613

26072614
[case testSelfRefNTIncremental4]
2615+
# flags: --no-new-semantic-analyzer
26082616
from typing import NamedTuple
26092617

26102618
class B(NamedTuple): # type: ignore
@@ -2618,6 +2626,7 @@ n: A
26182626
[builtins fixtures/tuple.pyi]
26192627

26202628
[case testSelfRefNTIncremental5]
2629+
# flags: --no-new-semantic-analyzer
26212630
from typing import NamedTuple
26222631

26232632
B = NamedTuple('B', [ # type: ignore
@@ -3272,6 +3281,7 @@ main:8: error: Revealed type is 'def (x: builtins.str) -> __main__.A@6'
32723281
main:8: error: Revealed type is 'def (x: builtins.str) -> __main__.A@6'
32733282

32743283
[case testAttrsIncrementalConverterInSubmoduleForwardRef]
3284+
# flags: --no-new-semantic-analyzer
32753285
from a.a import A
32763286
reveal_type(A)
32773287
[file a/__init__.py]
@@ -3289,11 +3299,12 @@ F = List[int]
32893299

32903300
[builtins fixtures/list.pyi]
32913301
[out1]
3292-
main:2: error: Revealed type is 'def (x: builtins.list[builtins.int]) -> a.a.A'
3302+
main:3: error: Revealed type is 'def (x: builtins.list[builtins.int]) -> a.a.A'
32933303
[out2]
3294-
main:2: error: Revealed type is 'def (x: builtins.list[builtins.int]) -> a.a.A'
3304+
main:3: error: Revealed type is 'def (x: builtins.list[builtins.int]) -> a.a.A'
32953305

32963306
[case testAttrsIncrementalConverterType]
3307+
# flags: --no-new-semantic-analyzer
32973308
from a import C
32983309
import attr
32993310
o = C("1", "2", "3", "4")
@@ -3324,11 +3335,11 @@ class C:
33243335
d: int = attr.ib(converter=parse)
33253336
[builtins fixtures/attr.pyi]
33263337
[out1]
3327-
main:5: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str]) -> a.C'
3328-
main:9: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str], x: builtins.str) -> __main__.D'
3338+
main:6: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str]) -> a.C'
3339+
main:10: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str], x: builtins.str) -> __main__.D'
33293340
[out2]
3330-
main:5: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str]) -> a.C'
3331-
main:9: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str], x: builtins.str) -> __main__.D'
3341+
main:6: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str]) -> a.C'
3342+
main:10: error: Revealed type is 'def (a: Union[builtins.float, builtins.str], b: Union[builtins.str, builtins.bytes, builtins.int], c: builtins.str, d: Union[builtins.int, builtins.str], x: builtins.str) -> __main__.D'
33323343

33333344
[case testAttrsIncrementalThreeRuns]
33343345
from a import A
@@ -4461,6 +4472,7 @@ def outer() -> None:
44614472
[out2]
44624473

44634474
[case testRecursiveAliasImported]
4475+
# flags: --no-new-semantic-analyzer
44644476
import a
44654477
[file a.py]
44664478
import lib
@@ -4482,7 +4494,38 @@ B = List[A]
44824494
[out2]
44834495
tmp/a.py:3: error: Revealed type is 'builtins.list[builtins.list[builtins.list[Any]]]'
44844496

4497+
[case testRecursiveAliasImported2]
4498+
# flags: --new-semantic-analyzer
4499+
import a
4500+
[file a.py]
4501+
import lib
4502+
x: int
4503+
[file a.py.2]
4504+
import lib
4505+
x: lib.A
4506+
reveal_type(x)
4507+
[file lib.pyi]
4508+
from typing import List
4509+
from other import B
4510+
A = List[B] # type: ignore
4511+
[file other.pyi]
4512+
from typing import List
4513+
from lib import A
4514+
B = List[A]
4515+
[builtins fixtures/list.pyi]
4516+
[out]
4517+
tmp/other.pyi:2: error: Module 'lib' has no attribute 'A'
4518+
tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition)
4519+
tmp/lib.pyi:2: error: Module 'other' has no attribute 'B'
4520+
[out2]
4521+
tmp/other.pyi:2: error: Module 'lib' has no attribute 'A'
4522+
tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition)
4523+
tmp/lib.pyi:2: error: Module 'other' has no attribute 'B'
4524+
tmp/a.py:2: error: Cannot resolve name "lib.A" (possible cyclic definition)
4525+
tmp/a.py:3: error: Revealed type is 'Any'
4526+
44854527
[case testRecursiveNamedTupleTypedDict]
4528+
# flags: --no-new-semantic-analyzer
44864529
import a
44874530
[file a.py]
44884531
import lib
@@ -4576,6 +4619,8 @@ def f(x: str) -> None: pass
45764619
tmp/main.py:2: error: Argument 1 to "f" has incompatible type "int"; expected "str"
45774620

45784621
[case testOverrideByIdemAlias]
4622+
# https://github.com/python/mypy/issues/6404
4623+
# flags: --no-new-semantic-analyzer
45794624
import a
45804625
[file a.py]
45814626
import lib

test-data/unit/check-newsemanal.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,3 +2446,18 @@ def dec(f): pass
24462446
# 5 padding
24472447
# 6 padding
24482448
def f(): pass
2449+
2450+
[case testNewAnalyzerOverrideClassWithTypeAlias]
2451+
from typing import Generic, TypeVar
2452+
2453+
T = TypeVar('T')
2454+
2455+
class C(Generic[T]):
2456+
pass
2457+
# TODO: Error message is confusing
2458+
C = C[int] # E: Cannot assign to a type \
2459+
# E: Incompatible types in assignment (expression has type "Type[__main__.C[Any]]", variable has type "Type[__main__.C[Any]]")
2460+
x: C
2461+
reveal_type(x) # E: Revealed type is '__main__.C[Any]'
2462+
[out]
2463+
[out2]

0 commit comments

Comments
 (0)
0