diff --git a/mypy/semanal.py b/mypy/semanal.py index 160c319e0e9b..3b281194d537 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -3007,11 +3007,14 @@ def process_type_annotation(self, s: AssignmentStmt) -> None: ): self.fail("All protocol members must have explicitly declared types", s) # Set the type if the rvalue is a simple literal (even if the above error occurred). - # We skip this step for type scope because it messes up with class attribute - # inference for literal types (also annotated and non-annotated variables at class - # scope are semantically different, so we should not souch statement type). - if len(s.lvalues) == 1 and isinstance(s.lvalues[0], RefExpr) and not self.type: - if s.lvalues[0].is_inferred_def: + if len(s.lvalues) == 1 and isinstance(s.lvalues[0], RefExpr): + ref_expr = s.lvalues[0] + safe_literal_inference = True + if self.type and isinstance(ref_expr, NameExpr) and len(self.type.mro) > 1: + # Check if there is a definition in supertype. If yes, we can't safely + # decide here what to infer: int or Literal[42]. + safe_literal_inference = self.type.mro[1].get(ref_expr.name) is None + if safe_literal_inference and ref_expr.is_inferred_def: s.type = self.analyze_simple_literal_type(s.rvalue, s.is_final_def) if s.type: # Store type into nodes. diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 26b468342beb..c09424138e49 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -3337,3 +3337,19 @@ class A: class B(A): args = value [builtins fixtures/dict.pyi] + +[case testInferSimpleLiteralInClassBodyCycle] +import a +[file a.py] +import b +reveal_type(b.B.x) +class A: + x = 42 +[file b.py] +import a +reveal_type(a.A.x) +class B: + x = 42 +[out] +tmp/b.py:2: note: Revealed type is "builtins.int" +tmp/a.py:2: note: Revealed type is "builtins.int"