diff --git a/mypy/checker.py b/mypy/checker.py index 6d0d6e5bc86b..3ad6794c6617 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1836,7 +1836,6 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type infer_lvalue_type) else: lvalue_type, index_lvalue, inferred = self.check_lvalue(lvalue) - # If we're assigning to __getattr__ or similar methods, check that the signature is # valid. if isinstance(lvalue, NameExpr) and lvalue.node: @@ -1853,7 +1852,9 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type else: self.check_getattr_method(signature, lvalue, name) - if isinstance(lvalue, RefExpr): + # Defer PartialType's super type checking. + if (isinstance(lvalue, RefExpr) and + not (isinstance(lvalue_type, PartialType) and lvalue_type.type is None)): if self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue): # We hit an error on this line; don't check for any others return @@ -1883,6 +1884,11 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type # Try to infer a partial type. No need to check the return value, as # an error will be reported elsewhere. self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type) + # Handle None PartialType's super type checking here, after it's resolved. + if (isinstance(lvalue, RefExpr) and + self.check_compatibility_all_supers(lvalue, lvalue_type, rvalue)): + # We hit an error on this line; don't check for any others + return elif (is_literal_none(rvalue) and isinstance(lvalue, NameExpr) and isinstance(lvalue.node, Var) and diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 9d7887d05ae9..6ff500205050 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -2696,3 +2696,31 @@ reveal_type(x) # E: Revealed type is 'builtins.list[Any]' reveal_type(y) # E: Revealed type is 'builtins.dict[Any, Any]' [builtins fixtures/dict.pyi] + +[case testInheritedAttributeNoStrictOptional] +# flags: --no-strict-optional +class A: + x: str + +class B(A): + x = None + x = '' + reveal_type(x) # E: Revealed type is 'builtins.str' + +[case testIncompatibleInheritedAttributeNoStrictOptional] +# flags: --no-strict-optional +class A: + x: str + +class B(A): + x = None + x = 2 # E: Incompatible types in assignment (expression has type "int", base class "A" defined the type as "str") + +[case testInheritedAttributeStrictOptional] +# flags: --strict-optional +class A: + x: str + +class B(A): + x = None # E: Incompatible types in assignment (expression has type "None", base class "A" defined the type as "str") + x = ''