From ed9754eb91ea59ba298a5015f1d9f5e1ce622bf3 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 2 Jul 2019 14:19:59 +0100 Subject: [PATCH 1/2] New semantic analyzer: add comments and refactor Document deferral logic in some detail and remove redundant calls to `defer()`. --- mypy/newsemanal/semanal.py | 21 ++++++++++++++++----- mypy/newsemanal/typeanal.py | 6 +++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py index e9fb958f11e65..d341d1913a41f 100644 --- a/mypy/newsemanal/semanal.py +++ b/mypy/newsemanal/semanal.py @@ -2182,7 +2182,6 @@ def process_type_annotation(self, s: AssignmentStmt) -> None: analyzed = self.anal_type(s.type, allow_tuple_literal=allow_tuple_literal) # Don't store not ready types (including placeholders). if analyzed is None or has_placeholder(analyzed): - self.defer() return s.type = analyzed if (self.type and self.type.is_protocol and isinstance(lvalue, NameExpr) and @@ -3565,7 +3564,6 @@ def analyze_type_application_args(self, expr: IndexExpr) -> Optional[List[Type]] analyzed = self.anal_type(typearg, allow_unbound_tvars=True, allow_placeholder=True) if analyzed is None: - self.defer() return None types.append(analyzed) return types @@ -4507,9 +4505,22 @@ def anal_type(self, third_pass: bool = False) -> Optional[Type]: """Semantically analyze a type. - Return None only if some part of the type couldn't be bound *and* it referred - to an incomplete namespace. In case of other errors, report an error message - and return AnyType. + 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 also defer + as needed. During a final iteration this won't return None; instead + report an error if the type can't be analyzed and return AnyType. + + In case of other errors, report an error message and return AnyType. + + NOTE: The caller shouldn't defer even if this returns None or a + placeholder type. """ a = self.type_analyzer(tvar_scope=tvar_scope, allow_unbound_tvars=allow_unbound_tvars, diff --git a/mypy/newsemanal/typeanal.py b/mypy/newsemanal/typeanal.py index 8cacc3fd0ae41..79e3016f0a0b2 100644 --- a/mypy/newsemanal/typeanal.py +++ b/mypy/newsemanal/typeanal.py @@ -94,7 +94,11 @@ def no_subscript_builtin_alias(name: str, propose_alt: bool = True) -> str: class TypeAnalyser(SyntheticTypeVisitor[Type], TypeAnalyzerPluginInterface): """Semantic analyzer for types. - Converts unbound types into bound types. + Converts unbound types into bound types. This is a no-op for already + bound types. + + If an incomplete reference is encountered, this does a defer. The + caller never needs to defer. """ # Is this called from an untyped function definition? From 0217d20f3507aee83206cef78923f848f20624d3 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 2 Jul 2019 17:25:57 +0100 Subject: [PATCH 2/2] Respond to feedback --- mypy/newsemanal/semanal.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mypy/newsemanal/semanal.py b/mypy/newsemanal/semanal.py index d341d1913a41f..87199d5f8ea73 100644 --- a/mypy/newsemanal/semanal.py +++ b/mypy/newsemanal/semanal.py @@ -4513,9 +4513,10 @@ def anal_type(self, 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 also defer - as needed. During a final iteration this won't return None; instead - report an error if the type can't be analyzed and return AnyType. + referred to an incomplete namespace or definition. In this case also + defer as needed. During a final iteration this won't return None; + instead report an error if the type can't be analyzed and return + AnyType. In case of other errors, report an error message and return AnyType.