# Buggy code
def build_namedtuple_typeinfo(
    self,
    name: str,
    items: List[str],
    types: List[Type],
    default_items: Dict[str, Expression],
) -> TypeInfo:
    strtype = self.str_type()
    basetuple_type = self.named_type("__builtins__.tuple", [AnyType()])
    dictype = (
        self.named_type_or_none("builtins.dict", [strtype, AnyType()])
        or self.object_type()
    )
    # Actual signature should return OrderedDict[str, Union[types]]
    ordereddictype = (
        self.named_type_or_none("builtins.dict", [strtype, AnyType()])
        or self.object_type()
    )
    # 'builtins.tuple' has only one type parameter, the corresponding type argument
    #  in the fallback instance is a join of all item types.
    fallback = self.named_type("__builtins__.tuple", [join.join_type_list(types)])
    # Note: actual signature should accept an invariant version of Iterable[UnionType[types]].
    # but it can't be expressed. 'new' and 'len' should be callable types.
    iterable_type = self.named_type_or_none("typing.Iterable", [AnyType()])
    function_type = self.named_type("__builtins__.function")

    info = self.basic_new_typeinfo(name, fallback)
    info.is_named_tuple = True
    info.tuple_type = TupleType(types, fallback)

    def add_field(
        var: Var, is_initialized_in_class: bool = False, is_property: bool = False
    ) -> None:
        var.info = info
        var.is_initialized_in_class = is_initialized_in_class
        var.is_property = is_property
        info.names[var.name()] = SymbolTableNode(MDEF, var)

    vars = [Var(item, typ) for item, typ in zip(items, types)]
    for var in vars:
        add_field(var, is_property=True)

    tuple_of_strings = TupleType([strtype for _ in items], basetuple_type)
    add_field(Var("_fields", tuple_of_strings), is_initialized_in_class=True)
    add_field(Var("_field_types", dictype), is_initialized_in_class=True)
    add_field(Var("_field_defaults", dictype), is_initialized_in_class=True)
    add_field(Var("_source", strtype), is_initialized_in_class=True)

    tvd = TypeVarDef("NT", 1, [], info.tuple_type)
    selftype = TypeVarType(tvd)

    def add_method(
        funcname: str,
        ret: Type,
        args: List[Argument],
        name: str = None,
        is_classmethod: bool = False,
    ) -> None:
        if is_classmethod:
            first = [Argument(Var("cls"), TypeType(selftype), None, ARG_POS)]
        else:
            first = [Argument(Var("self"), selftype, None, ARG_POS)]
        args = first + args

        types = [arg.type_annotation for arg in args]
        items = [arg.variable.name() for arg in args]
        arg_kinds = [arg.kind for arg in args]
        signature = CallableType(
            types,
            arg_kinds,
            items,
            ret,
            function_type,
            name=name or info.name() + "." + funcname,
        )
        signature.variables = [tvd]
        func = FuncDef(funcname, args, Block([]), typ=signature)
        func.info = info
        func.is_class = is_classmethod
        if is_classmethod:
            v = Var(funcname, signature)
            v.is_classmethod = True
            v.info = info
            dec = Decorator(func, [NameExpr("classmethod")], v)
            info.names[funcname] = SymbolTableNode(MDEF, dec)
        else:
            info.names[funcname] = SymbolTableNode(MDEF, func)

    add_method(
        "_replace",
        ret=selftype,
        args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars],
    )

    def make_init_arg(var: Var) -> Argument:
        default = default_items.get(var.name(), None)
        kind = ARG_POS if default is None else ARG_OPT
        return Argument(var, var.type, default, kind)

    add_method(
        "__init__",
        ret=NoneTyp(),
        name=info.name(),
        args=[make_init_arg(var) for var in vars],
    )
    add_method("_asdict", args=[], ret=ordereddictype)
    add_method(
        "_make",
        ret=selftype,
        is_classmethod=True,
        args=[
            Argument(Var("iterable", iterable_type), iterable_type, None, ARG_POS),
            Argument(Var("new"), AnyType(), EllipsisExpr(), ARG_NAMED_OPT),
            Argument(Var("len"), AnyType(), EllipsisExpr(), ARG_NAMED_OPT),
        ],
    )
    return info


# Traceback (AssertionError)
(venv) jelle@devjelle:~/mypy$ cat testnt.py
from typing import NamedTuple

class A(NamedTuple):
b: 'B'
x: int

class B:
pass
(venv) jelle@devjelle:~/mypy$ python -m mypy --show-traceback testnt.py
testnt.py:3: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.510-dev-09e7b124b82dae1207d9eac6805b64a98290015c
Traceback (most recent call last):
File "/home/jelle/ans/venv64/lib/python3.6/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/home/jelle/ans/venv64/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/__main__.py", line 5, in <module>
main(None)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/main.py", line 46, in main
res = type_check_only(sources, bin_dir, options)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/main.py", line 93, in type_check_only
options=options)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/build.py", line 188, in build
graph = dispatch(sources, manager)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/build.py", line 1595, in dispatch
process_graph(graph, manager)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/build.py", line 1838, in process_graph
process_stale_scc(graph, scc, manager)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/build.py", line 1931, in process_stale_scc
graph[id].semantic_analysis()
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/build.py", line 1495, in semantic_analysis
self.manager.semantic_analyzer.visit_file(self.tree, self.xpath, self.options)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 257, in visit_file
self.accept(d)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 3279, in accept
node.accept(self)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/nodes.py", line 749, in accept
return visitor.visit_class_def(self)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 617, in visit_class_def
with self.analyze_class_body(defn) as should_continue:
File "/home/jelle/ans/venv64/lib/python3.6/contextlib.py", line 82, in __enter__
return next(self.gen)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 629, in analyze_class_body
if self.analyze_namedtuple_classdef(defn):
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 819, in analyze_namedtuple_classdef
defn.name, items, types, default_items)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/semanal.py", line 2053, in build_namedtuple_typeinfo
fallback = self.named_type('__builtins__.tuple', [join.join_type_list(types)])
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/join.py", line 388, in join_type_list
joined = join_types(joined, t)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/join.py", line 88, in join_types
return t.accept(TypeJoinVisitor(s))
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/types.py", line 411, in accept
return visitor.visit_instance(self)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/join.py", line 141, in visit_instance
return join_instances(t, self.s)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/join.py", line 295, in join_instances
return join_instances_via_supertype(s, t)
File "/home/jelle/mypy/venv/lib/python3.6/site-packages/mypy/join.py", line 314, in join_instances_via_supertype
assert best is not None
AssertionError:
testnt.py:3: note: use --pdb to drop into pdb

# Fixed code
def build_namedtuple_typeinfo(
    self,
    name: str,
    items: List[str],
    types: List[Type],
    default_items: Dict[str, Expression],
) -> TypeInfo:
    strtype = self.str_type()
    basetuple_type = self.named_type("__builtins__.tuple", [AnyType()])
    dictype = (
        self.named_type_or_none("builtins.dict", [strtype, AnyType()])
        or self.object_type()
    )
    # Actual signature should return OrderedDict[str, Union[types]]
    ordereddictype = (
        self.named_type_or_none("builtins.dict", [strtype, AnyType()])
        or self.object_type()
    )
    # 'builtins.tuple' has only one type parameter.
    #
    # TODO: The corresponding type argument in the fallback instance should be a join of
    #       all item types, but we can't do joins during this pass of semantic analysis
    #       and we are using Any as a workaround.
    fallback = self.named_type("__builtins__.tuple", [AnyType()])
    # Note: actual signature should accept an invariant version of Iterable[UnionType[types]].
    # but it can't be expressed. 'new' and 'len' should be callable types.
    iterable_type = self.named_type_or_none("typing.Iterable", [AnyType()])
    function_type = self.named_type("__builtins__.function")

    info = self.basic_new_typeinfo(name, fallback)
    info.is_named_tuple = True
    info.tuple_type = TupleType(types, fallback)

    def add_field(
        var: Var, is_initialized_in_class: bool = False, is_property: bool = False
    ) -> None:
        var.info = info
        var.is_initialized_in_class = is_initialized_in_class
        var.is_property = is_property
        info.names[var.name()] = SymbolTableNode(MDEF, var)

    vars = [Var(item, typ) for item, typ in zip(items, types)]
    for var in vars:
        add_field(var, is_property=True)

    tuple_of_strings = TupleType([strtype for _ in items], basetuple_type)
    add_field(Var("_fields", tuple_of_strings), is_initialized_in_class=True)
    add_field(Var("_field_types", dictype), is_initialized_in_class=True)
    add_field(Var("_field_defaults", dictype), is_initialized_in_class=True)
    add_field(Var("_source", strtype), is_initialized_in_class=True)

    tvd = TypeVarDef("NT", 1, [], info.tuple_type)
    selftype = TypeVarType(tvd)

    def add_method(
        funcname: str,
        ret: Type,
        args: List[Argument],
        name: str = None,
        is_classmethod: bool = False,
    ) -> None:
        if is_classmethod:
            first = [Argument(Var("cls"), TypeType(selftype), None, ARG_POS)]
        else:
            first = [Argument(Var("self"), selftype, None, ARG_POS)]
        args = first + args

        types = [arg.type_annotation for arg in args]
        items = [arg.variable.name() for arg in args]
        arg_kinds = [arg.kind for arg in args]
        signature = CallableType(
            types,
            arg_kinds,
            items,
            ret,
            function_type,
            name=name or info.name() + "." + funcname,
        )
        signature.variables = [tvd]
        func = FuncDef(funcname, args, Block([]), typ=signature)
        func.info = info
        func.is_class = is_classmethod
        if is_classmethod:
            v = Var(funcname, signature)
            v.is_classmethod = True
            v.info = info
            dec = Decorator(func, [NameExpr("classmethod")], v)
            info.names[funcname] = SymbolTableNode(MDEF, dec)
        else:
            info.names[funcname] = SymbolTableNode(MDEF, func)

    add_method(
        "_replace",
        ret=selftype,
        args=[Argument(var, var.type, EllipsisExpr(), ARG_NAMED_OPT) for var in vars],
    )

    def make_init_arg(var: Var) -> Argument:
        default = default_items.get(var.name(), None)
        kind = ARG_POS if default is None else ARG_OPT
        return Argument(var, var.type, default, kind)

    add_method(
        "__init__",
        ret=NoneTyp(),
        name=info.name(),
        args=[make_init_arg(var) for var in vars],
    )
    add_method("_asdict", args=[], ret=ordereddictype)
    add_method(
        "_make",
        ret=selftype,
        is_classmethod=True,
        args=[
            Argument(Var("iterable", iterable_type), iterable_type, None, ARG_POS),
            Argument(Var("new"), AnyType(), EllipsisExpr(), ARG_NAMED_OPT),
            Argument(Var("len"), AnyType(), EllipsisExpr(), ARG_NAMED_OPT),
        ],
    )
    return info