# 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()
    init_method = cls.info.get_method("__init__")
    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 and isinstance(init_method, FuncDef):
                    # 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.
                    for arg, arg_name in zip(
                        init_method.arguments, init_method.arg_names
                    ):
                        if arg_name == attr.name:
                            cls.info.names[attr.name] = SymbolTableNode(
                                MDEF, arg.variable
                            )

                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 (flush_error)
crash_mypy_2.py:14: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 0.750+dev.596cde6bd8ddcdbbe5ca2b0d0019ec689a7e8b9c
Traceback (most recent call last):
File "/Users/jake/.pyenv/versions/dbt38/bin/mypy", line 11, in <module>
load_entry_point('mypy', 'console_scripts', 'mypy')()
File "/Users/jake/src/mypy/mypy/__main__.py", line 8, in console_entry
main(None, sys.stdout, sys.stderr)
File "/Users/jake/src/mypy/mypy/main.py", line 89, in main
res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
File "/Users/jake/src/mypy/mypy/build.py", line 166, in build
result = _build(
File "/Users/jake/src/mypy/mypy/build.py", line 235, in _build
graph = dispatch(sources, manager, stdout)
File "/Users/jake/src/mypy/mypy/build.py", line 2620, in dispatch
process_graph(graph, manager)
File "/Users/jake/src/mypy/mypy/build.py", line 2929, in process_graph
process_stale_scc(graph, scc, manager)
File "/Users/jake/src/mypy/mypy/build.py", line 3022, in process_stale_scc
mypy.semanal_main.semantic_analysis_for_scc(graph, scc, manager.errors)
File "/Users/jake/src/mypy/mypy/semanal_main.py", line 77, in semantic_analysis_for_scc
process_top_levels(graph, scc, patches)
File "/Users/jake/src/mypy/mypy/semanal_main.py", line 198, in process_top_levels
deferred, incomplete, progress = semantic_analyze_target(next_id, state,
File "/Users/jake/src/mypy/mypy/semanal_main.py", line 325, in semantic_analyze_target
analyzer.refresh_partial(refresh_node,
File "/Users/jake/src/mypy/mypy/semanal.py", line 378, in refresh_partial
self.refresh_top_level(node)
File "/Users/jake/src/mypy/mypy/semanal.py", line 389, in refresh_top_level
self.accept(d)
File "/Users/jake/src/mypy/mypy/semanal.py", line 4659, in accept
node.accept(self)
File "/Users/jake/src/mypy/mypy/nodes.py", line 939, in accept
return visitor.visit_class_def(self)
File "/Users/jake/src/mypy/mypy/semanal.py", line 1029, in visit_class_def
self.analyze_class(defn)
File "/Users/jake/src/mypy/mypy/semanal.py", line 1106, in analyze_class
self.analyze_class_body_common(defn)
File "/Users/jake/src/mypy/mypy/semanal.py", line 1115, in analyze_class_body_common
self.apply_class_plugin_hooks(defn)
File "/Users/jake/src/mypy/mypy/semanal.py", line 1161, in apply_class_plugin_hooks
hook(ClassDefContext(defn, decorator, self))
File "/Users/jake/src/mypy/mypy/plugins/dataclasses.py", line 374, in dataclass_class_maker_callback
transformer.transform()
File "/Users/jake/src/mypy/mypy/plugins/dataclasses.py", line 87, in transform
assert attr.is_init_var and not attr.is_in_init

# 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,
            )
        )

    # 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 not None:
                            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