diff --git a/mypy/checkmember.py b/mypy/checkmember.py index c8dc69bdfbe4..4057314c606b 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -227,6 +227,13 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, # The associated Var node of a decorator contains the type. v = vv.var + if isinstance(vv, TypeInfo): + # If the associated variable is a TypeInfo synthesize a Var node for + # the purposes of type checking. This enables us to type check things + # like accessing class attributes on an inner class. + v = Var(name, type=type_object_type(vv, builtin_type)) + v.info = info + if isinstance(v, Var): return analyze_var(name, v, itype, info, node, is_lvalue, msg, original_type, not_ready_callback, chk=chk) diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index f8f27d3a2178..499e0611a01f 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -681,6 +681,21 @@ def produce() -> Bar: reveal_type(Bar().make_int) # E: Revealed type is 'def () -> builtins.int' return Bar() +[case testInnerClassPropertyAccess] +class Foo: + class Meta: + name = 'Bar' + meta = Meta + +reveal_type(Foo.Meta) # E: Revealed type is 'def () -> __main__.Foo.Meta' +reveal_type(Foo.meta) # E: Revealed type is 'def () -> __main__.Foo.Meta' +reveal_type(Foo.Meta.name) # E: Revealed type is 'builtins.str' +reveal_type(Foo.meta.name) # E: Revealed type is 'builtins.str' +reveal_type(Foo().Meta) # E: Revealed type is 'def () -> __main__.Foo.Meta' +reveal_type(Foo().meta) # E: Revealed type is 'def () -> __main__.Foo.Meta' +reveal_type(Foo().meta.name) # E: Revealed type is 'builtins.str' +reveal_type(Foo().Meta.name) # E: Revealed type is 'builtins.str' + -- Declaring attribute type in method -- ----------------------------------