# Buggy code
def collect_attributes(self) -> Optional[List[DataclassAttribute]]:
    """Collect all attributes declared in the dataclass and its parents.

    All assignments of the form

      a: SomeType
      b: SomeOtherType = ...

    are collected.
    """
    # First, collect attributes belonging to the current class.
    ctx = self._ctx
    cls = self._ctx.cls
    attrs = []  # type: List[DataclassAttribute]
    known_attrs = set()  # type: Set[str]
    for stmt in cls.defs.body:
        # Any assignment that doesn't use the new type declaration
        # syntax can be ignored out of hand.
        if not (isinstance(stmt, AssignmentStmt) and stmt.new_syntax):
            continue

        # a: int, b: str = 1, 'foo' is not supported syntax so we
        # don't have to worry about it.
        lhs = stmt.lvalues[0]
        if not isinstance(lhs, NameExpr):
            continue

        sym = cls.info.names.get(lhs.name)
        if sym is None:
            # This name is likely blocked by a star import. We don't need to defer because
            # defer() is already called by mark_incomplete().
            continue

        node = sym.node
        if isinstance(node, PlaceholderNode):
            # This node is not ready yet.
            return None
        assert isinstance(node, Var)

        # x: ClassVar[int] is ignored by dataclasses.
        if node.is_classvar:
            continue

        # x: InitVar[int] is turned into x: int and is removed from the class.
        is_init_var = False
        node_type = get_proper_type(node.type)
        if (
            isinstance(node_type, Instance)
            and node_type.type.fullname == "dataclasses.InitVar"
        ):
            is_init_var = True
            node.type = node_type.args[0]

        has_field_call, field_args = _collect_field_args(stmt.rvalue)

        is_in_init_param = field_args.get("init")
        if is_in_init_param is None:
            is_in_init = True
        else:
            is_in_init = bool(ctx.api.parse_bool(is_in_init_param))

        has_default = False
        # Ensure that something like x: int = field() is rejected
        # after an attribute with a default.
        if has_field_call:
            has_default = "default" in field_args or "default_factory" in field_args

        # All other assignments are already type checked.
        elif not isinstance(stmt.rvalue, TempNode):
            has_default = True

        if not has_default:
            # Make all non-default attributes implicit because they are de-facto set
            # on self in the generated __init__(), not in the class body.
            sym.implicit = True

        known_attrs.add(lhs.name)
        attrs.append(
            DataclassAttribute(
                name=lhs.name,
                is_in_init=is_in_init,
                is_init_var=is_init_var,
                has_default=has_default,
                line=stmt.line,
                column=stmt.column,
            )
        )

    # Next, collect attributes belonging to any class in the MRO
    # as long as those attributes weren't already collected.  This
    # makes it possible to overwrite attributes in subclasses.
    # copy() because we potentially modify all_attrs below and if this code requires debugging
    # we'll have unmodified attrs laying around.
    all_attrs = attrs.copy()
    for info in cls.info.mro[1:-1]:
        if "dataclass" not in info.metadata:
            continue

        super_attrs = []
        # Each class depends on the set of attributes in its dataclass ancestors.
        ctx.api.add_plugin_dependency(make_wildcard_trigger(info.fullname))

        for data in info.metadata["dataclass"]["attributes"]:
            name = data["name"]  # type: str
            if name not in known_attrs:
                attr = DataclassAttribute.deserialize(info, data)
                if attr.is_init_var:
                    # InitVars are removed from classes so, in order for them to be inherited
                    # properly, we need to re-inject them into subclasses' sym tables here.
                    # To do that, we look 'em up from the parents' __init__.  These variables
                    # are subsequently removed from the sym table at the end of
                    # DataclassTransformer.transform.
                    superclass_init = info.get_method("__init__")
                    if isinstance(superclass_init, FuncDef):
                        attr_node = _get_arg_from_init(superclass_init, attr.name)
                        if attr_node is None:
                            # Continue the loop: we will look it up in the next MRO entry.
                            # Don't add it to the known or super attrs because we don't know
                            # anything about it yet
                            continue
                        else:
                            cls.info.names[attr.name] = attr_node
                known_attrs.add(name)
                super_attrs.append(attr)
            elif all_attrs:
                # How early in the attribute list an attribute appears is determined by the
                # reverse MRO, not simply MRO.
                # See https://docs.python.org/3/library/dataclasses.html#inheritance for
                # details.
                for attr in all_attrs:
                    if attr.name == name:
                        all_attrs.remove(attr)
                        super_attrs.append(attr)
                        break
        all_attrs = super_attrs + all_attrs

    # Ensure that arguments without a default don't follow
    # arguments that have a default.
    found_default = False
    for attr in all_attrs:
        # If we find any attribute that is_in_init but that
        # doesn't have a default after one that does have one,
        # then that's an error.
        if found_default and attr.is_in_init and not attr.has_default:
            # If the issue comes from merging different classes, report it
            # at the class definition point.
            context = (
                Context(line=attr.line, column=attr.column)
                if attr in attrs
                else ctx.cls
            )
            ctx.api.fail(
                "Attributes without a default cannot follow attributes with one",
                context,
            )

        found_default = found_default or (attr.has_default and attr.is_in_init)

    return all_attrs


# Traceback (AssertionError)
bug.py:11: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.701
Traceback (most recent call last):
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/bin/mypy", line 10, in <module>
sys.exit(console_entry())
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/__main__.py", line 7, in console_entry
main(None)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/main.py", line 84, in main
res = build.build(sources, options, None, flush_errors, fscache)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 163, in build
result = _build(sources, options, alt_lib_path, flush_errors, fscache)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 218, in _build
graph = dispatch(sources, manager)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 2461, in dispatch
process_graph(graph, manager)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 2761, in process_graph
process_stale_scc(graph, scc, manager)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 2862, in process_stale_scc
graph[id].semantic_analysis()
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/build.py", line 1997, in semantic_analysis
self.manager.semantic_analyzer.visit_file(self.tree, self.xpath, self.options, patches)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 309, in visit_file
self.accept(d)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 3791, in accept
node.accept(self)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/nodes.py", line 896, in accept
return visitor.visit_class_def(self)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 807, in visit_class_def
self.analyze_class(defn)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 825, in analyze_class
self.analyze_class_body_common(defn)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 833, in analyze_class_body_common
self.apply_class_plugin_hooks(defn)
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/semanal.py", line 895, in apply_class_plugin_hooks
hook(ClassDefContext(defn, decorator, self))
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/plugins/dataclasses.py", line 330, in dataclass_class_maker_callback
transformer.transform()
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/plugins/dataclasses.py", line 100, in transform
return_type=NoneTyp(),
File "/Users/ezyang/Dev/oss/dl-hmc-calc-env/lib/python3.7/site-packages/mypy/plugins/common.py", line 97, in add_method
assert arg.type_annotation, 'All arguments must be fully typed.'
AssertionError: All arguments must be fully typed.
bug.py:11: : note: use --pdb to drop into pdb

# Fixed code
def collect_attributes(self) -> Optional[List[DataclassAttribute]]:
    """Collect all attributes declared in the dataclass and its parents.

    All assignments of the form

      a: SomeType
      b: SomeOtherType = ...

    are collected.
    """
    # First, collect attributes belonging to the current class.
    ctx = self._ctx
    cls = self._ctx.cls
    attrs = []  # type: List[DataclassAttribute]
    known_attrs = set()  # type: Set[str]
    for stmt in cls.defs.body:
        # Any assignment that doesn't use the new type declaration
        # syntax can be ignored out of hand.
        if not (isinstance(stmt, AssignmentStmt) and stmt.new_syntax):
            continue

        # a: int, b: str = 1, 'foo' is not supported syntax so we
        # don't have to worry about it.
        lhs = stmt.lvalues[0]
        if not isinstance(lhs, NameExpr):
            continue

        sym = cls.info.names.get(lhs.name)
        if sym is None:
            # This name is likely blocked by a star import. We don't need to defer because
            # defer() is already called by mark_incomplete().
            continue

        node = sym.node
        if isinstance(node, PlaceholderNode):
            # This node is not ready yet.
            return None
        assert isinstance(node, Var)

        # x: ClassVar[int] is ignored by dataclasses.
        if node.is_classvar:
            continue

        # x: InitVar[int] is turned into x: int and is removed from the class.
        is_init_var = False
        node_type = get_proper_type(node.type)
        if (
            isinstance(node_type, Instance)
            and node_type.type.fullname == "dataclasses.InitVar"
        ):
            is_init_var = True
            node.type = node_type.args[0]

        has_field_call, field_args = _collect_field_args(stmt.rvalue)

        is_in_init_param = field_args.get("init")
        if is_in_init_param is None:
            is_in_init = True
        else:
            is_in_init = bool(ctx.api.parse_bool(is_in_init_param))

        has_default = False
        # Ensure that something like x: int = field() is rejected
        # after an attribute with a default.
        if has_field_call:
            has_default = "default" in field_args or "default_factory" in field_args

        # All other assignments are already type checked.
        elif not isinstance(stmt.rvalue, TempNode):
            has_default = True

        if not has_default:
            # Make all non-default attributes implicit because they are de-facto set
            # on self in the generated __init__(), not in the class body.
            sym.implicit = True

        known_attrs.add(lhs.name)
        attrs.append(
            DataclassAttribute(
                name=lhs.name,
                is_in_init=is_in_init,
                is_init_var=is_init_var,
                has_default=has_default,
                line=stmt.line,
                column=stmt.column,
                type=sym.type,
            )
        )

    # Next, collect attributes belonging to any class in the MRO
    # as long as those attributes weren't already collected.  This
    # makes it possible to overwrite attributes in subclasses.
    # copy() because we potentially modify all_attrs below and if this code requires debugging
    # we'll have unmodified attrs laying around.
    all_attrs = attrs.copy()
    for info in cls.info.mro[1:-1]:
        if "dataclass" not in info.metadata:
            continue

        super_attrs = []
        # Each class depends on the set of attributes in its dataclass ancestors.
        ctx.api.add_plugin_dependency(make_wildcard_trigger(info.fullname))

        for data in info.metadata["dataclass"]["attributes"]:
            name = data["name"]  # type: str
            if name not in known_attrs:
                attr = DataclassAttribute.deserialize(info, data, ctx.api)
                known_attrs.add(name)
                super_attrs.append(attr)
            elif all_attrs:
                # How early in the attribute list an attribute appears is determined by the
                # reverse MRO, not simply MRO.
                # See https://docs.python.org/3/library/dataclasses.html#inheritance for
                # details.
                for attr in all_attrs:
                    if attr.name == name:
                        all_attrs.remove(attr)
                        super_attrs.append(attr)
                        break
        all_attrs = super_attrs + all_attrs

    # Ensure that arguments without a default don't follow
    # arguments that have a default.
    found_default = False
    for attr in all_attrs:
        # If we find any attribute that is_in_init but that
        # doesn't have a default after one that does have one,
        # then that's an error.
        if found_default and attr.is_in_init and not attr.has_default:
            # If the issue comes from merging different classes, report it
            # at the class definition point.
            context = (
                Context(line=attr.line, column=attr.column)
                if attr in attrs
                else ctx.cls
            )
            ctx.api.fail(
                "Attributes without a default cannot follow attributes with one",
                context,
            )

        found_default = found_default or (attr.has_default and attr.is_in_init)

    return all_attrs