# Buggy code
def _process_one_annotation(
    self, node, annotation, name, stack, f_globals=None, f_locals=None, seen=None
):
    """Change annotation / record errors where required."""

    # Check for recursive type annotations so we can emit an error message
    # rather than crashing.
    if seen is None:
        seen = set()
    if isinstance(annotation, abstract.AbstractOrConcreteValue):
        if annotation in seen:
            self.vm.errorlog.not_supported_yet(
                stack,
                "Recursive type annotations",
                details="In annotation '%s' on %s" % (annotation.pyval, name),
            )
            return None
        seen = seen | {annotation}

    if isinstance(annotation, abstract.AnnotationContainer):
        annotation = annotation.base_cls

    if isinstance(annotation, typing_overlay.Union):
        self.vm.errorlog.invalid_annotation(stack, annotation, "Needs options", name)
        return None
    elif (
        name is not None
        and name != "return"
        and isinstance(annotation, typing_overlay.NoReturn)
    ):
        self.vm.errorlog.invalid_annotation(
            stack, annotation, "NoReturn is not allowed", name
        )
        return None
    elif isinstance(annotation, abstract.Instance) and (
        annotation.cls == self.vm.convert.str_type
        or annotation.cls == self.vm.convert.unicode_type
    ):
        # String annotations : Late evaluation
        if isinstance(annotation, mixin.PythonConstant):
            if f_globals is None:
                raise self.LateAnnotationError()
            else:
                try:
                    v = abstract_utils.eval_expr(
                        self.vm, node, f_globals, f_locals, annotation.pyval
                    )
                except abstract_utils.EvaluationError as e:
                    self.vm.errorlog.invalid_annotation(stack, annotation, e.details)
                    return None
                if len(v.data) == 1:
                    return self._process_one_annotation(
                        node, v.data[0], name, stack, f_globals, f_locals, seen
                    )
        self.vm.errorlog.invalid_annotation(stack, annotation, "Must be constant", name)
        return None
    elif annotation.cls == self.vm.convert.none_type:
        # PEP 484 allows to write "NoneType" as "None"
        return self.vm.convert.none_type
    elif isinstance(annotation, abstract.ParameterizedClass):
        for param_name, param in annotation.formal_type_parameters.items():
            processed = self._process_one_annotation(
                node, param, name, stack, f_globals, f_locals, seen
            )
            if processed is None:
                return None
            elif isinstance(processed, typing_overlay.NoReturn):
                self.vm.errorlog.invalid_annotation(
                    stack, param, "NoReturn is not allowed as inner type", name
                )
                return None
            annotation.formal_type_parameters[param_name] = processed
        return annotation
    elif isinstance(annotation, abstract.Union):
        options = []
        for option in annotation.options:
            processed = self._process_one_annotation(
                node, option, name, stack, f_globals, f_locals, seen
            )
            if processed is None:
                return None
            elif isinstance(processed, typing_overlay.NoReturn):
                self.vm.errorlog.invalid_annotation(
                    stack, option, "NoReturn is not allowed as inner type", name
                )
                return None
            options.append(processed)
        annotation.options = tuple(options)
        return annotation
    elif isinstance(
        annotation,
        (
            mixin.Class,
            abstract.AMBIGUOUS_OR_EMPTY,
            abstract.TypeParameter,
            typing_overlay.NoReturn,
        ),
    ):
        return annotation
    else:
        self.vm.errorlog.invalid_annotation(stack, annotation, "Not a type", name)
        return None


# Traceback (AttributeError)
from typing import Any
def __getattr__(name: Any) -> Any: ...
# Caught error in pytype: 'LateAnnotation' object has no attribute 'Bindings'
# Traceback (most recent call last):
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/io.py", line 131, in check_or_generate_pyi
#     input_filename=options.input, options=options, loader=loader)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/io.py", line 89, in generate_pyi
#     analyze.infer_types, input_filename, options, loader)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/io.py", line 62, in _call
#     deep=deep)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 668, in infer_types
#     tracer.exitpoint = tracer.analyze(loc, defs, maximum_depth)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 407, in analyze
#     return self.analyze_toplevel(node, defs)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 370, in analyze_toplevel
#     new_node = self.analyze_class(node, value)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 352, in analyze_class
#     node = self.analyze_method_var(node, name, b)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 202, in analyze_method_var
#     node2 = self.maybe_analyze_method(node1, val)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 157, in maybe_analyze_method
#     node, _ = self.call_function_with_args(node, val, args)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 121, in call_function_with_args
#     new_node, ret = self.call_function_in_frame(node, fvar, *args)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/analyze.py", line 132, in call_function_in_frame
#     state, var, args, kwargs, starargs, starstarargs)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 917, in call_function_with_state
#     starstarargs=starstarargs), fallback_to_unsolvable, allow_noreturn=True)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 953, in call_function
#     new_node, one_result = func.call(node, funcv, args)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/abstract.py", line 3247, in call
#     alias_map=self.alias_map)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/abstract.py", line 3051, in call
#     node2, ret = self.vm.run_frame(frame, node)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 292, in run_frame
#     state = self.run_instruction(op, state)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 253, in run_instruction
#     state = bytecode_fn(state, op)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 1980, in byte_LOAD_ATTR
#     state, val = self.load_attr(state, obj, name)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 1224, in load_attr
#     node, result, errors = self._retrieve_attr(state.node, obj, attr)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/vm.py", line 1195, in _retrieve_attr
#     node, val.data, attr, val)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 65, in get_attribute
#     return self._get_instance_attribute(node, obj, name, valself)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 234, in _get_instance_attribute
#     return self._get_attribute(node, obj, obj.cls, name, valself)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 270, in _get_attribute
#     node, attr = self.get_attribute(node, cls, name, valself)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 58, in get_attribute
#     return self._get_class_attribute(node, obj, name, valself)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 229, in _get_class_attribute
#     return self._get_attribute(node, cls, meta, name, valself)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 284, in _get_attribute
#     attr = self._filter_var(node, attr)
#   File "/Users/name/.pyenv/versions/3.7.3/envs/venv/lib/python3.7/site-packages/pytype/attribute.py", line 426, in _filter_var
#     bindings = var.Bindings(node, strict=False)
# AttributeError: 'LateAnnotation' object has no attribute 'Bindings'

# Fixed code
def _process_one_annotation(self, node, annotation, name, stack, seen=None):
    """Change annotation / record errors where required."""
    # Make sure we pass in a frozen snapshot of the frame stack, rather than the
    # actual stack, since late annotations need to snapshot the stack at time of
    # creation in order to get the right line information for error messages.
    assert isinstance(stack, tuple), "stack must be an immutable sequence"

    # Check for recursive type annotations so we can emit an error message
    # rather than crashing.
    if seen is None:
        seen = set()
    if annotation.is_late_annotation():
        if annotation in seen:
            self.vm.errorlog.not_supported_yet(
                stack,
                "Recursive type annotations",
                details="In annotation '%s' on %s" % (annotation.expr, name),
            )
            return None
        seen = seen | {annotation}

    if isinstance(annotation, abstract.AnnotationContainer):
        annotation = annotation.base_cls

    if isinstance(annotation, typing_overlay.Union):
        self.vm.errorlog.invalid_annotation(stack, annotation, "Needs options", name)
        return None
    elif (
        name is not None
        and name != "return"
        and isinstance(annotation, typing_overlay.NoReturn)
    ):
        self.vm.errorlog.invalid_annotation(
            stack, annotation, "NoReturn is not allowed", name
        )
        return None
    elif isinstance(annotation, abstract.Instance) and (
        annotation.cls == self.vm.convert.str_type
        or annotation.cls == self.vm.convert.unicode_type
    ):
        # String annotations : Late evaluation
        if isinstance(annotation, mixin.PythonConstant):
            expr = annotation.pyval
            if not expr:
                self.vm.errorlog.invalid_annotation(
                    stack, annotation, "Cannot be an empty string", name
                )
                return None
            frame = self.vm.frame
            try:
                # Immediately try to evaluate the reference, generating
                # LateAnnotation objects as needed. We don't store the entire string
                # as a LateAnnotation because:
                # - Starting in 3.8, or in 3.7 with __future__.annotations, all
                #   annotations look like forward references - most of them don't need
                #   to be late evaluated.
                # - Given an expression like "Union[str, NotYetDefined]", we want to
                #   evaluate the union immediately so we don't end up with a complex
                #   LateAnnotation, which can lead to bugs when instantiated.
                with self.vm.generate_late_annotations(stack):
                    v = abstract_utils.eval_expr(
                        self.vm, node, frame.f_globals, frame.f_locals, expr
                    )
            except abstract_utils.EvaluationError as e:
                self.vm.errorlog.invalid_annotation(stack, annotation, e.details)
                return None
            if len(v.data) == 1:
                return self._process_one_annotation(node, v.data[0], name, stack, seen)
        self.vm.errorlog.invalid_annotation(stack, annotation, "Must be constant", name)
        return None
    elif annotation.cls == self.vm.convert.none_type:
        # PEP 484 allows to write "NoneType" as "None"
        return self.vm.convert.none_type
    elif isinstance(annotation, abstract.ParameterizedClass):
        for param_name, param in annotation.formal_type_parameters.items():
            processed = self._process_one_annotation(node, param, name, stack, seen)
            if processed is None:
                return None
            elif isinstance(processed, typing_overlay.NoReturn):
                self.vm.errorlog.invalid_annotation(
                    stack, param, "NoReturn is not allowed as inner type", name
                )
                return None
            annotation.formal_type_parameters[param_name] = processed
        return annotation
    elif isinstance(annotation, abstract.Union):
        options = []
        for option in annotation.options:
            processed = self._process_one_annotation(node, option, name, stack, seen)
            if processed is None:
                return None
            elif isinstance(processed, typing_overlay.NoReturn):
                self.vm.errorlog.invalid_annotation(
                    stack, option, "NoReturn is not allowed as inner type", name
                )
                return None
            options.append(processed)
        annotation.options = tuple(options)
        return annotation
    elif isinstance(
        annotation,
        (
            mixin.Class,
            abstract.AMBIGUOUS_OR_EMPTY,
            abstract.TypeParameter,
            typing_overlay.NoReturn,
        ),
    ):
        return annotation
    else:
        self.vm.errorlog.invalid_annotation(stack, annotation, "Not a type", name)
        return None