Skip to content

Flip the default for recursive aliases flag #13516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 29, 2022
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: 2 additions & 2 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,9 +975,9 @@ def add_invertible_flag(
help="Use a custom typing module",
)
internals_group.add_argument(
"--enable-recursive-aliases",
"--disable-recursive-aliases",
action="store_true",
help="Experimental support for recursive type aliases",
help="Disable experimental support for recursive type aliases",
)
internals_group.add_argument(
"--custom-typeshed-dir", metavar="DIR", help="Use the custom typeshed in DIR"
Expand Down
4 changes: 2 additions & 2 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ def __init__(self) -> None:
# skip most errors after this many messages have been reported.
# -1 means unlimited.
self.many_errors_threshold = defaults.MANY_ERRORS_THRESHOLD
# Enable recursive type aliases (currently experimental)
self.enable_recursive_aliases = False
# Disable recursive type aliases (currently experimental)
self.disable_recursive_aliases = False

# To avoid breaking plugin compatibility, keep providing new_semantic_analyzer
@property
Expand Down
4 changes: 2 additions & 2 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -3238,7 +3238,7 @@ def check_and_set_up_type_alias(self, s: AssignmentStmt) -> bool:
)
if not res:
return False
if self.options.enable_recursive_aliases and not self.is_func_scope():
if not self.options.disable_recursive_aliases and not self.is_func_scope():
# Only marking incomplete for top-level placeholders makes recursive aliases like
# `A = Sequence[str | A]` valid here, similar to how we treat base classes in class
# definitions, allowing `class str(Sequence[str]): ...`
Expand Down Expand Up @@ -5749,7 +5749,7 @@ def process_placeholder(self, name: str, kind: str, ctx: Context) -> None:

def cannot_resolve_name(self, name: str, kind: str, ctx: Context) -> None:
self.fail(f'Cannot resolve {kind} "{name}" (possible cyclic definition)', ctx)
if self.options.enable_recursive_aliases and self.is_func_scope():
if not self.options.disable_recursive_aliases and self.is_func_scope():
self.note("Recursive types are not allowed at function scope", ctx)

def qualified_name(self, name: str) -> str:
Expand Down
4 changes: 2 additions & 2 deletions mypy/semanal_namedtuple.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def check_namedtuple_classdef(
# it would be inconsistent with type aliases.
analyzed = self.api.anal_type(
stmt.type,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
if analyzed is None:
Expand Down Expand Up @@ -443,7 +443,7 @@ def parse_namedtuple_fields_with_types(
# We never allow recursive types at function scope.
analyzed = self.api.anal_type(
type,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
# Workaround #4987 and avoid introducing a bogus UnboundType
Expand Down
2 changes: 1 addition & 1 deletion mypy/semanal_newtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def check_newtype_args(
self.api.anal_type(
unanalyzed_type,
report_invalid_types=False,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
)
Expand Down
6 changes: 3 additions & 3 deletions mypy/semanal_typeddict.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def analyze_base_args(self, base: IndexExpr, ctx: Context) -> list[Type] | None:
analyzed = self.api.anal_type(
type,
allow_required=True,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
if analyzed is None:
Expand Down Expand Up @@ -289,7 +289,7 @@ def analyze_typeddict_classdef_fields(
analyzed = self.api.anal_type(
stmt.type,
allow_required=True,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
if analyzed is None:
Expand Down Expand Up @@ -484,7 +484,7 @@ def parse_typeddict_fields_with_types(
analyzed = self.api.anal_type(
type,
allow_required=True,
allow_placeholder=self.options.enable_recursive_aliases
allow_placeholder=not self.options.disable_recursive_aliases
and not self.api.is_func_scope(),
)
if analyzed is None:
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ def cannot_resolve_type(self, t: UnboundType) -> None:
# need access to MessageBuilder here. Also move the similar
# message generation logic in semanal.py.
self.api.fail(f'Cannot resolve name "{t.name}" (possible cyclic definition)', t)
if self.options.enable_recursive_aliases and self.api.is_func_scope():
if not self.options.disable_recursive_aliases and self.api.is_func_scope():
self.note("Recursive types are not allowed at function scope", t)

def apply_concatenate_operator(self, t: UnboundType) -> Type:
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4779,7 +4779,7 @@ class A(Tuple[int, str]): pass
-- -----------------------

[case testCrashOnSelfRecursiveNamedTupleVar]

# flags: --disable-recursive-aliases
from typing import NamedTuple

N = NamedTuple('N', [('x', N)]) # E: Cannot resolve name "N" (possible cyclic definition)
Expand Down Expand Up @@ -4809,7 +4809,7 @@ lst = [n, m]
[builtins fixtures/isinstancelist.pyi]

[case testCorrectJoinOfSelfRecursiveTypedDicts]

# flags: --disable-recursive-aliases
from mypy_extensions import TypedDict

class N(TypedDict):
Expand Down
1 change: 0 additions & 1 deletion test-data/unit/check-dataclasses.test
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,6 @@ takes_cp(MyDataclass)
[builtins fixtures/dataclasses.pyi]

[case testDataclassTypeAnnotationAliasUpdated]
# flags: --enable-recursive-aliases
import a
[file a.py]
from dataclasses import dataclass
Expand Down
10 changes: 5 additions & 5 deletions test-data/unit/check-incremental.test
Original file line number Diff line number Diff line change
Expand Up @@ -4600,7 +4600,7 @@ def outer() -> None:
[out2]

[case testRecursiveAliasImported]

# flags: --disable-recursive-aliases
import a

[file a.py]
Expand Down Expand Up @@ -5759,7 +5759,7 @@ class C:
[builtins fixtures/tuple.pyi]

[case testNamedTupleUpdateNonRecursiveToRecursiveCoarse]
# flags: --enable-recursive-aliases
# flags: --strict-optional
import c
[file a.py]
from b import M
Expand Down Expand Up @@ -5802,7 +5802,7 @@ tmp/c.py:5: error: Incompatible types in assignment (expression has type "Option
tmp/c.py:7: note: Revealed type is "Tuple[Union[Tuple[Union[..., None], builtins.int, fallback=b.M], None], builtins.int, fallback=a.N]"

[case testTupleTypeUpdateNonRecursiveToRecursiveCoarse]
# flags: --enable-recursive-aliases
# flags: --strict-optional
import c
[file a.py]
from b import M
Expand Down Expand Up @@ -5835,7 +5835,7 @@ tmp/c.py:4: note: Revealed type is "Tuple[Union[Tuple[Union[..., None], builtins
tmp/c.py:5: error: Incompatible types in assignment (expression has type "Optional[N]", variable has type "int")

[case testTypeAliasUpdateNonRecursiveToRecursiveCoarse]
# flags: --enable-recursive-aliases
# flags: --strict-optional
import c
[file a.py]
from b import M
Expand Down Expand Up @@ -5868,7 +5868,7 @@ tmp/c.py:4: note: Revealed type is "Tuple[Union[Tuple[Union[..., None], builtins
tmp/c.py:5: error: Incompatible types in assignment (expression has type "Optional[N]", variable has type "int")

[case testTypedDictUpdateNonRecursiveToRecursiveCoarse]
# flags: --enable-recursive-aliases
# flags: --strict-optional
import c
[file a.py]
from b import M
Expand Down
16 changes: 8 additions & 8 deletions test-data/unit/check-namedtuple.test
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ tmp/b.py:4: note: Revealed type is "Tuple[Any, fallback=a.N]"
tmp/b.py:7: note: Revealed type is "Tuple[Any, fallback=a.N]"

[case testSimpleSelfReferentialNamedTuple]

# flags: --disable-recursive-aliases
from typing import NamedTuple
class MyNamedTuple(NamedTuple):
parent: 'MyNamedTuple' # E: Cannot resolve name "MyNamedTuple" (possible cyclic definition)
Expand Down Expand Up @@ -655,7 +655,7 @@ class B:
[out]

[case testSelfRefNT1]

# flags: --disable-recursive-aliases
from typing import Tuple, NamedTuple

Node = NamedTuple('Node', [
Expand All @@ -667,7 +667,7 @@ reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ..
[builtins fixtures/tuple.pyi]

[case testSelfRefNT2]

# flags: --disable-recursive-aliases
from typing import Tuple, NamedTuple

A = NamedTuple('A', [
Expand All @@ -683,7 +683,7 @@ reveal_type(n) # N: Revealed type is "Tuple[builtins.str, builtins.tuple[Any, ..
[builtins fixtures/tuple.pyi]

[case testSelfRefNT3]

# flags: --disable-recursive-aliases
from typing import NamedTuple, Tuple

class B(NamedTuple):
Expand All @@ -703,7 +703,7 @@ reveal_type(lst[0]) # N: Revealed type is "Tuple[builtins.object, builtins.objec
[builtins fixtures/tuple.pyi]

[case testSelfRefNT4]

# flags: --disable-recursive-aliases
from typing import NamedTuple

class B(NamedTuple):
Expand All @@ -719,7 +719,7 @@ reveal_type(n.y[0]) # N: Revealed type is "Any"
[builtins fixtures/tuple.pyi]

[case testSelfRefNT5]

# flags: --disable-recursive-aliases
from typing import NamedTuple

B = NamedTuple('B', [
Expand All @@ -737,7 +737,7 @@ reveal_type(f) # N: Revealed type is "def (m: Tuple[Any, builtins.int, fallback=
[builtins fixtures/tuple.pyi]

[case testRecursiveNamedTupleInBases]

# flags: --disable-recursive-aliases
from typing import List, NamedTuple, Union

Exp = Union['A', 'B'] # E: Cannot resolve name "Exp" (possible cyclic definition) \
Expand Down Expand Up @@ -781,7 +781,7 @@ tp = NamedTuple('tp', [('x', int)])
[out]

[case testSubclassOfRecursiveNamedTuple]

# flags: --disable-recursive-aliases
from typing import List, NamedTuple

class Command(NamedTuple):
Expand Down
24 changes: 15 additions & 9 deletions test-data/unit/check-newsemanal.test
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ def main() -> None:
x # E: Name "x" is not defined

[case testNewAnalyzerCyclicDefinitions]
# flags: --disable-recursive-aliases
gx = gy # E: Cannot resolve name "gy" (possible cyclic definition)
gy = gx
def main() -> None:
Expand Down Expand Up @@ -1499,6 +1500,7 @@ reveal_type(x[0][0]) # N: Revealed type is "__main__.C"
[builtins fixtures/list.pyi]

[case testNewAnalyzerAliasToNotReadyDirectBase]
# flags: --disable-recursive-aliases
from typing import List

x: B
Expand All @@ -1509,11 +1511,11 @@ reveal_type(x)
reveal_type(x[0][0])
[builtins fixtures/list.pyi]
[out]
main:3: error: Cannot resolve name "B" (possible cyclic definition)
main:4: error: Cannot resolve name "B" (possible cyclic definition)
main:4: error: Cannot resolve name "C" (possible cyclic definition)
main:7: note: Revealed type is "Any"
main:5: error: Cannot resolve name "B" (possible cyclic definition)
main:5: error: Cannot resolve name "C" (possible cyclic definition)
main:8: note: Revealed type is "Any"
main:9: note: Revealed type is "Any"

[case testNewAnalyzerAliasToNotReadyTwoDeferralsFunction]
import a
Expand All @@ -1532,6 +1534,7 @@ reveal_type(f) # N: Revealed type is "def (x: builtins.list[a.C]) -> builtins.l
[builtins fixtures/list.pyi]

[case testNewAnalyzerAliasToNotReadyDirectBaseFunction]
# flags: --disable-recursive-aliases
import a
[file a.py]
from typing import List
Expand Down Expand Up @@ -2119,6 +2122,7 @@ class B(List[C]):
[builtins fixtures/list.pyi]

[case testNewAnalyzerNewTypeForwardClassAliasDirect]
# flags: --disable-recursive-aliases
from typing import NewType, List

x: D
Expand All @@ -2131,12 +2135,12 @@ class B(D):
pass
[builtins fixtures/list.pyi]
[out]
main:3: error: Cannot resolve name "D" (possible cyclic definition)
main:4: note: Revealed type is "Any"
main:6: error: Cannot resolve name "D" (possible cyclic definition)
main:6: error: Cannot resolve name "C" (possible cyclic definition)
main:7: error: Argument 2 to NewType(...) must be a valid type
main:7: error: Cannot resolve name "B" (possible cyclic definition)
main:4: error: Cannot resolve name "D" (possible cyclic definition)
main:5: note: Revealed type is "Any"
main:7: error: Cannot resolve name "D" (possible cyclic definition)
main:7: error: Cannot resolve name "C" (possible cyclic definition)
main:8: error: Argument 2 to NewType(...) must be a valid type
main:8: error: Cannot resolve name "B" (possible cyclic definition)

-- Copied from check-classes.test (tricky corner cases).
[case testNewAnalyzerNoCrashForwardRefToBrokenDoubleNewTypeClass]
Expand All @@ -2153,6 +2157,7 @@ class C:
[builtins fixtures/dict.pyi]

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

Expand Down Expand Up @@ -2593,6 +2598,7 @@ import n
def __getattr__(x): pass

[case testNewAnalyzerReportLoopInMRO2]
# flags: --disable-recursive-aliases
def f() -> None:
class A(A): ... # E: Cannot resolve name "A" (possible cyclic definition)

Expand Down
Loading