# Buggy code
def analyze_var(
    name: str,
    var: Var,
    itype: Instance,
    info: TypeInfo,
    mx: MemberContext,
    *,
    implicit: bool = False,
) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.

    itype is the class object in which var is defined
    original_type is the type of E in the expression E.var
    if implicit is True, the original Var was created as an assignment to self
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context)
        if mx.is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            mx.msg.read_only_property(name, itype.type, mx.context)
        if mx.is_lvalue and var.is_classvar:
            mx.msg.cant_assign_to_classvar(name, mx.context)
        t = get_proper_type(expand_type_by_instance(typ, itype))
        result = t  # type: Type
        typ = get_proper_type(typ)
        if (
            var.is_initialized_in_class
            and isinstance(typ, FunctionLike)
            and not typ.is_type_obj()
        ):
            if mx.is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        mx.msg.read_only_property(name, itype.type, mx.context)
                else:
                    mx.msg.cant_assign_to_method(mx.context)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound methods:
                # the former to the instance, the latter to the class.
                functype = typ
                # Use meet to narrow original_type to the dispatched type.
                # For example, assume
                # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
                # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
                # * x: Union[A1, B1]
                # In `x.f`, when checking `x` against A1 we assume x is compatible with A
                # and similarly for B1 when checking agains B
                dispatched_type = meet.meet_types(mx.original_type, itype)
                signature = freshen_function_type_vars(functype)
                signature = check_self_arg(
                    signature,
                    dispatched_type,
                    var.is_classmethod,
                    mx.context,
                    name,
                    mx.msg,
                )
                signature = bind_self(signature, mx.self_type, var.is_classmethod)
                expanded_signature = get_proper_type(
                    expand_type_by_instance(signature, itype)
                )
                if var.is_property:
                    # A property cannot have an overloaded type => the cast is fine.
                    assert isinstance(expanded_signature, CallableType)
                    result = expanded_signature.ret_type
                else:
                    result = expanded_signature
    else:
        if not var.is_ready:
            mx.not_ready_callback(var.name, mx.context)
        # Implicit 'Any' type.
        result = AnyType(TypeOfAny.special_form)
    fullname = "{}.{}".format(var.info.fullname, name)
    hook = mx.chk.plugin.get_attribute_hook(fullname)
    if result and not mx.is_lvalue and not implicit:
        result = analyze_descriptor_access(
            mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk
        )
    if hook:
        result = hook(
            AttributeContext(
                get_proper_type(mx.original_type), result, mx.context, mx.chk
            )
        )
    return result


# Traceback (AssertionError)
Traceback (most recent call last):
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/Users/jukka/src/mypy/mypy/__main__.py", line 12, in <module>
main(None, sys.stdout, sys.stderr)
File "/Users/jukka/src/mypy/mypy/main.py", line 89, in main
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/jukka/src/mypy/mypy/build.py", line 167, in build
sources, options, alt_lib_path, flush_errors, fscache, stdout, stderr, extra_plugins
File "/Users/jukka/src/mypy/mypy/build.py", line 235, in _build
graph = dispatch(sources, manager, stdout)
File "/Users/jukka/src/mypy/mypy/build.py", line 2620, in dispatch
process_graph(graph, manager)
File "/Users/jukka/src/mypy/mypy/build.py", line 2929, in process_graph
process_stale_scc(graph, scc, manager)
File "/Users/jukka/src/mypy/mypy/build.py", line 3047, in process_stale_scc
graph[id].write_cache()
File "/Users/jukka/src/mypy/mypy/build.py", line 2244, in write_cache
self.manager)
File "/Users/jukka/src/mypy/mypy/build.py", line 1410, in write_cache
data = tree.serialize()
File "/Users/jukka/src/mypy/mypy/nodes.py", line 302, in serialize
'names': self.names.serialize(self._fullname),
File "/Users/jukka/src/mypy/mypy/nodes.py", line 3083, in serialize
data[key] = value.serialize(fullname, key)
File "/Users/jukka/src/mypy/mypy/nodes.py", line 3021, in serialize
data['node'] = self.node.serialize()
File "/Users/jukka/src/mypy/mypy/nodes.py", line 882, in serialize
'type': None if self.type is None else self.type.serialize(),
File "/Users/jukka/src/mypy/mypy/types.py", line 1218, in serialize
'arg_types': [t.serialize() for t in self.arg_types],
File "/Users/jukka/src/mypy/mypy/types.py", line 1218, in <listcomp>
'arg_types': [t.serialize() for t in self.arg_types],
File "/Users/jukka/src/mypy/mypy/types.py", line 885, in serialize
assert not self.id.is_meta_var()
AssertionError

# Fixed code
def analyze_var(
    name: str,
    var: Var,
    itype: Instance,
    info: TypeInfo,
    mx: MemberContext,
    *,
    implicit: bool = False,
) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.

    itype is the class object in which var is defined
    original_type is the type of E in the expression E.var
    if implicit is True, the original Var was created as an assignment to self
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context)
        if mx.is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            mx.msg.read_only_property(name, itype.type, mx.context)
        if mx.is_lvalue and var.is_classvar:
            mx.msg.cant_assign_to_classvar(name, mx.context)
        t = get_proper_type(expand_type_by_instance(typ, itype))
        result = t  # type: Type
        typ = get_proper_type(typ)
        if (
            var.is_initialized_in_class
            and isinstance(typ, FunctionLike)
            and not typ.is_type_obj()
        ):
            if mx.is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        mx.msg.read_only_property(name, itype.type, mx.context)
                else:
                    mx.msg.cant_assign_to_method(mx.context)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound methods:
                # the former to the instance, the latter to the class.
                functype = typ
                # Use meet to narrow original_type to the dispatched type.
                # For example, assume
                # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
                # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
                # * x: Union[A1, B1]
                # In `x.f`, when checking `x` against A1 we assume x is compatible with A
                # and similarly for B1 when checking agains B
                dispatched_type = meet.meet_types(mx.original_type, itype)
                signature = freshen_function_type_vars(functype)
                signature = check_self_arg(
                    signature,
                    dispatched_type,
                    var.is_classmethod,
                    mx.context,
                    name,
                    mx.msg,
                )
                signature = bind_self(signature, mx.self_type, var.is_classmethod)
                expanded_signature = get_proper_type(
                    expand_type_by_instance(signature, itype)
                )
                freeze_type_vars(expanded_signature)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast is fine.
                    assert isinstance(expanded_signature, CallableType)
                    result = expanded_signature.ret_type
                else:
                    result = expanded_signature
    else:
        if not var.is_ready:
            mx.not_ready_callback(var.name, mx.context)
        # Implicit 'Any' type.
        result = AnyType(TypeOfAny.special_form)
    fullname = "{}.{}".format(var.info.fullname, name)
    hook = mx.chk.plugin.get_attribute_hook(fullname)
    if result and not mx.is_lvalue and not implicit:
        result = analyze_descriptor_access(
            mx.original_type, result, mx.builtin_type, mx.msg, mx.context, chk=mx.chk
        )
    if hook:
        result = hook(
            AttributeContext(
                get_proper_type(mx.original_type), result, mx.context, mx.chk
            )
        )
    return result