"""Generic node traverser visitor"""

from __future__ import annotations

from mypy_extensions import mypyc_attr, trait

from mypy.nodes import (
    REVEAL_TYPE,
    AssertStmt,
    AssertTypeExpr,
    AssignmentExpr,
    AssignmentStmt,
    AwaitExpr,
    Block,
    BreakStmt,
    BytesExpr,
    CallExpr,
    CastExpr,
    ClassDef,
    ComparisonExpr,
    ComplexExpr,
    ConditionalExpr,
    ContinueStmt,
    Decorator,
    DelStmt,
    DictExpr,
    DictionaryComprehension,
    EllipsisExpr,
    EnumCallExpr,
    Expression,
    ExpressionStmt,
    FloatExpr,
    ForStmt,
    FuncBase,
    FuncDef,
    FuncItem,
    GeneratorExpr,
    GlobalDecl,
    IfStmt,
    Import,
    ImportAll,
    ImportFrom,
    IndexExpr,
    IntExpr,
    LambdaExpr,
    ListComprehension,
    ListExpr,
    MatchStmt,
    MemberExpr,
    MypyFile,
    NamedTupleExpr,
    NameExpr,
    NewTypeExpr,
    Node,
    NonlocalDecl,
    OperatorAssignmentStmt,
    OpExpr,
    OverloadedFuncDef,
    ParamSpecExpr,
    PassStmt,
    RaiseStmt,
    ReturnStmt,
    RevealExpr,
    SetComprehension,
    SetExpr,
    SliceExpr,
    StarExpr,
    StrExpr,
    SuperExpr,
    TryStmt,
    TupleExpr,
    TypeAlias,
    TypeAliasExpr,
    TypeAliasStmt,
    TypeApplication,
    TypedDictExpr,
    TypeVarExpr,
    TypeVarTupleExpr,
    UnaryExpr,
    WhileStmt,
    WithStmt,
    YieldExpr,
    YieldFromExpr,
)
from mypy.patterns import (
    AsPattern,
    ClassPattern,
    MappingPattern,
    OrPattern,
    SequencePattern,
    SingletonPattern,
    StarredPattern,
    ValuePattern,
)
from mypy.visitor import NodeVisitor

@trait
@mypyc_attr(allow_interpreted_subclasses=True)
class TraverserVisitor(NodeVisitor[None]):
    """A parse tree visitor that traverses the parse tree during visiting.

    It does not perform any actions outside the traversal. Subclasses
    should override visit methods to perform actions during
    traversal. Calling the superclass method allows reusing the
    traversal implementation.
    """

    def __init__(self) -> None:
        pass

    # Visit methods

    def visit_mypy_file(self, o: MypyFile) -> None:
        for d in o.defs:
            d.accept(self)

    def visit_block(self, block: Block) -> None:
        for s in block.body:
            s.accept(self)

    def visit_func(self, o: FuncItem) -> None:
        if o.arguments is not None:
            for arg in o.arguments:
                init = arg.initializer
                if init is not None:
                    init.accept(self)

            for arg in o.arguments:
                self.visit_var(arg.variable)

        o.body.accept(self)

    def visit_func_def(self, o: FuncDef) -> None:
        self.visit_func(o)

    def visit_overloaded_func_def(self, o: OverloadedFuncDef) -> None:
        for item in o.items:
            item.accept(self)
        if o.impl:
            o.impl.accept(self)

    def visit_class_def(self, o: ClassDef) -> None:
        for d in o.decorators:
            d.accept(self)
        for base in o.base_type_exprs:
            base.accept(self)
        if o.metaclass:
            o.metaclass.accept(self)
        for v in o.keywords.values():
            v.accept(self)
        o.defs.accept(self)
        if o.analyzed:
            o.analyzed.accept(self)

    def visit_decorator(self, o: Decorator) -> None:
        o.func.accept(self)
        o.var.accept(self)
        for decorator in o.decorators:
            decorator.accept(self)

    def visit_expression_stmt(self, o: ExpressionStmt) -> None:
        o.expr.accept(self)

    def visit_assignment_stmt(self, o: AssignmentStmt) -> None:
        o.rvalue.accept(self)
        for l in o.lvalues:
            l.accept(self)

    def visit_operator_assignment_stmt(self, o: OperatorAssignmentStmt) -> None:
        o.rvalue.accept(self)
        o.lvalue.accept(self)

    def visit_while_stmt(self, o: WhileStmt) -> None:
        o.expr.accept(self)
        o.body.accept(self)
        if o.else_body:
            o.else_body.accept(self)

    def visit_for_stmt(self, o: ForStmt) -> None:
        o.index.accept(self)
        o.expr.accept(self)
        o.body.accept(self)
        if o.else_body:
            o.else_body.accept(self)

    def visit_return_stmt(self, o: ReturnStmt) -> None:
        if o.expr is not None:
            o.expr.accept(self)

    def visit_assert_stmt(self, o: AssertStmt) -> None:
        if o.expr is not None:
            o.expr.accept(self)
        if o.msg is not None:
            o.msg.accept(self)

    def visit_del_stmt(self, o: DelStmt) -> None:
        if o.expr is not None:
            o.expr.accept(self)

    def visit_if_stmt(self, o: IfStmt) -> None:
        for e in o.expr:
            e.accept(self)
        for b in o.body:
            b.accept(self)
        if o.else_body:
            o.else_body.accept(self)

    def visit_raise_stmt(self, o: RaiseStmt) -> None:
        if o.expr is not None:
            o.expr.accept(self)
        if o.from_expr is not None:
            o.from_expr.accept(self)

    def visit_try_stmt(self, o: TryStmt) -> None:
        o.body.accept(self)
        for i in range(len(o.types)):
            tp = o.types[i]
            if tp is not None:
                tp.accept(self)
            o.handlers[i].accept(self)
        for v in o.vars:
            if v is not None:
                v.accept(self)
        if o.else_body is not None:
            o.else_body.accept(self)
        if o.finally_body is not None:
            o.finally_body.accept(self)

    def visit_with_stmt(self, o: WithStmt) -> None:
        for i in range(len(o.expr)):
            o.expr[i].accept(self)
            targ = o.target[i]
            if targ is not None:
                targ.accept(self)
        o.body.accept(self)

    def visit_match_stmt(self, o: MatchStmt) -> None:
        o.subject.accept(self)
        for i in range(len(o.patterns)):
            o.patterns[i].accept(self)
            guard = o.guards[i]
            if guard is not None:
                guard.accept(self)
            o.bodies[i].accept(self)

    def visit_type_alias_stmt(self, o: TypeAliasStmt) -> None:
        o.name.accept(self)
        o.value.accept(self)

    def visit_member_expr(self, o: MemberExpr) -> None:
        o.expr.accept(self)

    def visit_yield_from_expr(self, o: YieldFromExpr) -> None:
        o.expr.accept(self)

    def visit_yield_expr(self, o: YieldExpr) -> None:
        if o.expr:
            o.expr.accept(self)

    def visit_call_expr(self, o: CallExpr) -> None:
        o.callee.accept(self)
        for a in o.args:
            a.accept(self)
        if o.analyzed:
            o.analyzed.accept(self)

    def visit_op_expr(self, o: OpExpr) -> None:
        o.left.accept(self)
        o.right.accept(self)
        if o.analyzed is not None:
            o.analyzed.accept(self)

    def visit_comparison_expr(self, o: ComparisonExpr) -> None:
        for operand in o.operands:
            operand.accept(self)

    def visit_slice_expr(self, o: SliceExpr) -> None:
        if o.begin_index is not None:
            o.begin_index.accept(self)
        if o.end_index is not None:
            o.end_index.accept(self)
        if o.stride is not None:
            o.stride.accept(self)

    def visit_cast_expr(self, o: CastExpr) -> None:
        o.expr.accept(self)

    def visit_assert_type_expr(self, o: AssertTypeExpr) -> None:
        o.expr.accept(self)

    def visit_reveal_expr(self, o: RevealExpr) -> None:
        if o.kind == REVEAL_TYPE:
            assert o.expr is not None
            o.expr.accept(self)
        else:
            # RevealLocalsExpr doesn't have an inner expression
            pass

    def visit_assignment_expr(self, o: AssignmentExpr) -> None:
        o.target.accept(self)
        o.value.accept(self)

    def visit_unary_expr(self, o: UnaryExpr) -> None:
        o.expr.accept(self)

    def visit_list_expr(self, o: ListExpr) -> None:
        for item in o.items:
            item.accept(self)

    def visit_tuple_expr(self, o: TupleExpr) -> None:
        for item in o.items:
            item.accept(self)

    def visit_dict_expr(self, o: DictExpr) -> None:
        for k, v in o.items:
            if k is not None:
                k.accept(self)
            v.accept(self)

    def visit_set_expr(self, o: SetExpr) -> None:
        for item in o.items:
            item.accept(self)

    def visit_index_expr(self, o: IndexExpr) -> None:
        o.base.accept(self)
        o.index.accept(self)
        if o.analyzed:
            o.analyzed.accept(self)

    def visit_generator_expr(self, o: GeneratorExpr) -> None:
        for index, sequence, conditions in zip(o.indices, o.sequences, o.condlists):
            sequence.accept(self)
            index.accept(self)
            for cond in conditions:
                cond.accept(self)
        o.left_expr.accept(self)

    def visit_dictionary_comprehension(self, o: DictionaryComprehension) -> None:
        for index, sequence, conditions in zip(o.indices, o.sequences, o.condlists):
            sequence.accept(self)
            index.accept(self)
            for cond in conditions:
                cond.accept(self)
        o.key.accept(self)
        o.value.accept(self)

    def visit_list_comprehension(self, o: ListComprehension) -> None:
        o.generator.accept(self)

    def visit_set_comprehension(self, o: SetComprehension) -> None:
        o.generator.accept(self)

    def visit_conditional_expr(self, o: ConditionalExpr) -> None:
        o.cond.accept(self)
        o.if_expr.accept(self)
        o.else_expr.accept(self)

    def visit_type_application(self, o: TypeApplication) -> None:
        o.expr.accept(self)

    def visit_lambda_expr(self, o: LambdaExpr) -> None:
        self.visit_func(o)

    def visit_star_expr(self, o: StarExpr) -> None:
        o.expr.accept(self)

    def visit_await_expr(self, o: AwaitExpr) -> None:
        o.expr.accept(self)

    def visit_super_expr(self, o: SuperExpr) -> None:
        o.call.accept(self)

    def visit_as_pattern(self, o: AsPattern) -> None:
        if o.pattern is not None:
            o.pattern.accept(self)
        if o.name is not None:
            o.name.accept(self)

    def visit_or_pattern(self, o: OrPattern) -> None:
        for p in o.patterns:
            p.accept(self)

    def visit_value_pattern(self, o: ValuePattern) -> None:
        o.expr.accept(self)

    def visit_sequence_pattern(self, o: SequencePattern) -> None:
        for p in o.patterns:
            p.accept(self)

    def visit_starred_pattern(self, o: StarredPattern) -> None:
        if o.capture is not None:
            o.capture.accept(self)

    def visit_mapping_pattern(self, o: MappingPattern) -> None:
        for key in o.keys:
            key.accept(self)
        for value in o.values:
            value.accept(self)
        if o.rest is not None:
            o.rest.accept(self)

    def visit_class_pattern(self, o: ClassPattern) -> None:
        o.class_ref.accept(self)
        for p in o.positionals:
            p.accept(self)
        for v in o.keyword_values:
            v.accept(self)

    def visit_import(self, o: Import) -> None:
        for a in o.assignments:
            a.accept(self)

    def visit_import_from(self, o: ImportFrom) -> None:
        for a in o.assignments:
            a.accept(self)

class ExtendedTraverserVisitor(TraverserVisitor):
    """This is a more flexible traverser.

    In addition to the base traverser it:
        * has visit_ methods for leaf nodes
        * has common method that is called for all nodes
        * allows to skip recursing into a node

    Note that this traverser still doesn't visit some internal
    mypy constructs like _promote expression and Var.
    """

    def visit(self, o: Node) -> bool:
        # If returns True, will continue to nested nodes.
        return True

    def visit_mypy_file(self, o: MypyFile) -> None:
        if not self.visit(o):
            return
        super().visit_mypy_file(o)

    # Module structure

    def visit_import(self, o: Import) -> None:
        if not self.visit(o):
            return
        super().visit_import(o)

    def visit_import_from(self, o: ImportFrom) -> None:
        if not self.visit(o):
            return
        super().visit_import_from(o)

    def visit_import_all(self, o: ImportAll) -> None:
        if not self.visit(o):
            return
        super().visit_import_all(o)

    # Definitions

    def visit_func_def(self, o: FuncDef) -> None:
        if not self.visit(o):
            return
        super().visit_func_def(o)

    def visit_overloaded_func_def(self, o: OverloadedFuncDef) -> None:
        if not self.visit(o):
            return
        super().visit_overloaded_func_def(o)

    def visit_class_def(self, o: ClassDef) -> None:
        if not self.visit(o):
            return
        super().visit_class_def(o)

    def visit_global_decl(self, o: GlobalDecl) -> None:
        if not self.visit(o):
            return
        super().visit_global_decl(o)

    def visit_nonlocal_decl(self, o: NonlocalDecl) -> None:
        if not self.visit(o):
            return
        super().visit_nonlocal_decl(o)

    def visit_decorator(self, o: Decorator) -> None:
        if not self.visit(o):
            return
        super().visit_decorator(o)

    def visit_type_alias(self, o: TypeAlias) -> None:
        if not self.visit(o):
            return
        super().visit_type_alias(o)

    # Statements

    def visit_block(self, block: Block) -> None:
        if not self.visit(block):
            return
        super().visit_block(block)

    def visit_expression_stmt(self, o: ExpressionStmt) -> None:
        if not self.visit(o):
            return
        super().visit_expression_stmt(o)

    def visit_assignment_stmt(self, o: AssignmentStmt) -> None:
        if not self.visit(o):
            return
        super().visit_assignment_stmt(o)

    def visit_operator_assignment_stmt(self, o: OperatorAssignmentStmt) -> None:
        if not self.visit(o):
            return
        super().visit_operator_assignment_stmt(o)

    def visit_while_stmt(self, o: WhileStmt) -> None:
        if not self.visit(o):
            return
        super().visit_while_stmt(o)

    def visit_for_stmt(self, o: ForStmt) -> None:
        if not self.visit(o):
            return
        super().visit_for_stmt(o)

    def visit_return_stmt(self, o: ReturnStmt) -> None:
        if not self.visit(o):
            return
        super().visit_return_stmt(o)

    def visit_assert_stmt(self, o: AssertStmt) -> None:
        if not self.visit(o):
            return
        super().visit_assert_stmt(o)

    def visit_del_stmt(self, o: DelStmt) -> None:
        if not self.visit(o):
            return
        super().visit_del_stmt(o)

    def visit_if_stmt(self, o: IfStmt) -> None:
        if not self.visit(o):
            return
        super().visit_if_stmt(o)

    def visit_break_stmt(self, o: BreakStmt) -> None:
        if not self.visit(o):
            return
        super().visit_break_stmt(o)

    def visit_continue_stmt(self, o: ContinueStmt) -> None:
        if not self.visit(o):
            return
        super().visit_continue_stmt(o)

    def visit_pass_stmt(self, o: PassStmt) -> None:
        if not self.visit(o):
            return
        super().visit_pass_stmt(o)

    def visit_raise_stmt(self, o: RaiseStmt) -> None:
        if not self.visit(o):
            return
        super().visit_raise_stmt(o)

    def visit_try_stmt(self, o: TryStmt) -> None:
        if not self.visit(o):
            return
        super().visit_try_stmt(o)

    def visit_with_stmt(self, o: WithStmt) -> None:
        if not self.visit(o):
            return
        super().visit_with_stmt(o)

    def visit_match_stmt(self, o: MatchStmt) -> None:
        if not self.visit(o):
            return
        super().visit_match_stmt(o)

    # Expressions (default no-op implementation)

    def visit_int_expr(self, o: IntExpr) -> None:
        if not self.visit(o):
            return
        super().visit_int_expr(o)

    def visit_str_expr(self, o: StrExpr) -> None:
        if not self.visit(o):
            return
        super().visit_str_expr(o)

    def visit_bytes_expr(self, o: BytesExpr) -> None:
        if not self.visit(o):
            return
        super().visit_bytes_expr(o)

    def visit_float_expr(self, o: FloatExpr) -> None:
        if not self.visit(o):
            return
        super().visit_float_expr(o)

    def visit_complex_expr(self, o: ComplexExpr) -> None:
        if not self.visit(o):
            return
        super().visit_complex_expr(o)

    def visit_ellipsis(self, o: EllipsisExpr) -> None:
        if not self.visit(o):
            return
        super().visit_ellipsis(o)

    def visit_star_expr(self, o: StarExpr) -> None:
        if not self.visit(o):
            return
        super().visit_star_expr(o)

    def visit_name_expr(self, o: NameExpr) -> None:
        if not self.visit(o):
            return
        super().visit_name_expr(o)

    def visit_member_expr(self, o: MemberExpr) -> None:
        if not self.visit(o):
            return
        super().visit_member_expr(o)

    def visit_yield_from_expr(self, o: YieldFromExpr) -> None:
        if not self.visit(o):
            return
        super().visit_yield_from_expr(o)

    def visit_yield_expr(self, o: YieldExpr) -> None:
        if not self.visit(o):
            return
        super().visit_yield_expr(o)

    def visit_call_expr(self, o: CallExpr) -> None:
        if not self.visit(o):
            return
        super().visit_call_expr(o)

    def visit_op_expr(self, o: OpExpr) -> None:
        if not self.visit(o):
            return
        super().visit_op_expr(o)

    def visit_comparison_expr(self, o: ComparisonExpr) -> None:
        if not self.visit(o):
            return
        super().visit_comparison_expr(o)

    def visit_cast_expr(self, o: CastExpr) -> None:
        if not self.visit(o):
            return
        super().visit_cast_expr(o)

    def visit_assert_type_expr(self, o: AssertTypeExpr) -> None:
        if not self.visit(o):
            return
        super().visit_assert_type_expr(o)

    def visit_reveal_expr(self, o: RevealExpr) -> None:
        if not self.visit(o):
            return
        super().visit_reveal_expr(o)

    def visit_super_expr(self, o: SuperExpr) -> None:
        if not self.visit(o):
            return
        super().visit_super_expr(o)

    def visit_assignment_expr(self, o: AssignmentExpr) -> None:
        if not self.visit(o):
            return
        super().visit_assignment_expr(o)

    def visit_unary_expr(self, o: UnaryExpr) -> None:
        if not self.visit(o):
            return
        super().visit_unary_expr(o)

    def visit_list_expr(self, o: ListExpr) -> None:
        if not self.visit(o):
            return
        super().visit_list_expr(o)

    def visit_dict_expr(self, o: DictExpr) -> None:
        if not self.visit(o):
            return
        super().visit_dict_expr(o)

    def visit_tuple_expr(self, o: TupleExpr) -> None:
        if not self.visit(o):
            return
        super().visit_tuple_expr(o)

    def visit_set_expr(self, o: SetExpr) -> None:
        if not self.visit(o):
            return
        super().visit_set_expr(o)

    def visit_index_expr(self, o: IndexExpr) -> None:
        if not self.visit(o):
            return
        super().visit_index_expr(o)

    def visit_type_application(self, o: TypeApplication) -> None:
        if not self.visit(o):
            return
        super().visit_type_application(o)

    def visit_lambda_expr(self, o: LambdaExpr) -> None:
        if not self.visit(o):
            return
        super().visit_lambda_expr(o)

    def visit_list_comprehension(self, o: ListComprehension) -> None:
        if not self.visit(o):
            return
        super().visit_list_comprehension(o)

    def visit_set_comprehension(self, o: SetComprehension) -> None:
        if not self.visit(o):
            return
        super().visit_set_comprehension(o)

    def visit_dictionary_comprehension(self, o: DictionaryComprehension) -> None:
        if not self.visit(o):
            return
        super().visit_dictionary_comprehension(o)

    def visit_generator_expr(self, o: GeneratorExpr) -> None:
        if not self.visit(o):
            return
        super().visit_generator_expr(o)

    def visit_slice_expr(self, o: SliceExpr) -> None:
        if not self.visit(o):
            return
        super().visit_slice_expr(o)

    def visit_conditional_expr(self, o: ConditionalExpr) -> None:
        if not self.visit(o):
            return
        super().visit_conditional_expr(o)

    def visit_type_var_expr(self, o: TypeVarExpr) -> None:
        if not self.visit(o):
            return
        super().visit_type_var_expr(o)

    def visit_paramspec_expr(self, o: ParamSpecExpr) -> None:
        if not self.visit(o):
            return
        super().visit_paramspec_expr(o)

    def visit_type_var_tuple_expr(self, o: TypeVarTupleExpr) -> None:
        if not self.visit(o):
            return
        super().visit_type_var_tuple_expr(o)

    def visit_type_alias_expr(self, o: TypeAliasExpr) -> None:
        if not self.visit(o):
            return
        super().visit_type_alias_expr(o)

    def visit_namedtuple_expr(self, o: NamedTupleExpr) -> None:
        if not self.visit(o):
            return
        super().visit_namedtuple_expr(o)

    def visit_enum_call_expr(self, o: EnumCallExpr) -> None:
        if not self.visit(o):
            return
        super().visit_enum_call_expr(o)

    def visit_typeddict_expr(self, o: TypedDictExpr) -> None:
        if not self.visit(o):
            return
        super().visit_typeddict_expr(o)

    def visit_newtype_expr(self, o: NewTypeExpr) -> None:
        if not self.visit(o):
            return
        super().visit_newtype_expr(o)

    def visit_await_expr(self, o: AwaitExpr) -> None:
        if not self.visit(o):
            return
        super().visit_await_expr(o)

    # Patterns

    def visit_as_pattern(self, o: AsPattern) -> None:
        if not self.visit(o):
            return
        super().visit_as_pattern(o)

    def visit_or_pattern(self, o: OrPattern) -> None:
        if not self.visit(o):
            return
        super().visit_or_pattern(o)

    def visit_value_pattern(self, o: ValuePattern) -> None:
        if not self.visit(o):
            return
        super().visit_value_pattern(o)

    def visit_singleton_pattern(self, o: SingletonPattern) -> None:
        if not self.visit(o):
            return
        super().visit_singleton_pattern(o)

    def visit_sequence_pattern(self, o: SequencePattern) -> None:
        if not self.visit(o):
            return
        super().visit_sequence_pattern(o)

    def visit_starred_pattern(self, o: StarredPattern) -> None:
        if not self.visit(o):
            return
        super().visit_starred_pattern(o)

    def visit_mapping_pattern(self, o: MappingPattern) -> None:
        if not self.visit(o):
            return
        super().visit_mapping_pattern(o)

    def visit_class_pattern(self, o: ClassPattern) -> None:
        if not self.visit(o):
            return
        super().visit_class_pattern(o)

class ReturnSeeker(TraverserVisitor):
    def __init__(self) -> None:
        self.found = False

    def visit_return_stmt(self, o: ReturnStmt) -> None:
        if o.expr is None or isinstance(o.expr, NameExpr) and o.expr.name == "None":
            return
        self.found = True

def has_return_statement(fdef: FuncBase) -> bool:
    """Find if a function has a non-trivial return statement.

    Plain 'return' and 'return None' don't count.
    """
    seeker = ReturnSeeker()
    fdef.accept(seeker)
    return seeker.found

class FuncCollectorBase(TraverserVisitor):
    def __init__(self) -> None:
        self.inside_func = False

    def visit_func_def(self, defn: FuncDef) -> None:
        if not self.inside_func:
            self.inside_func = True
            super().visit_func_def(defn)
            self.inside_func = False

class YieldSeeker(FuncCollectorBase):
    def __init__(self) -> None:
        super().__init__()
        self.found = False

    def visit_yield_expr(self, o: YieldExpr) -> None:
        self.found = True

def has_yield_expression(fdef: FuncBase) -> bool:
    seeker = YieldSeeker()
    fdef.accept(seeker)
    return seeker.found

class YieldFromSeeker(FuncCollectorBase):
    def __init__(self) -> None:
        super().__init__()
        self.found = False

    def visit_yield_from_expr(self, o: YieldFromExpr) -> None:
        self.found = True

def has_yield_from_expression(fdef: FuncBase) -> bool:
    seeker = YieldFromSeeker()
    fdef.accept(seeker)
    return seeker.found

class AwaitSeeker(TraverserVisitor):
    def __init__(self) -> None:
        super().__init__()
        self.found = False

    def visit_await_expr(self, o: AwaitExpr) -> None:
        self.found = True

def has_await_expression(expr: Expression) -> bool:
    seeker = AwaitSeeker()
    expr.accept(seeker)
    return seeker.found

class ReturnCollector(FuncCollectorBase):
    def __init__(self) -> None:
        super().__init__()
        self.return_statements: list[ReturnStmt] = []

    def visit_return_stmt(self, stmt: ReturnStmt) -> None:
        self.return_statements.append(stmt)

def all_return_statements(node: Node) -> list[ReturnStmt]:
    v = ReturnCollector()
    node.accept(v)
    return v.return_statements

class YieldCollector(FuncCollectorBase):
    def __init__(self) -> None:
        super().__init__()
        self.in_assignment = False
        self.yield_expressions: list[tuple[YieldExpr, bool]] = []

    def visit_assignment_stmt(self, stmt: AssignmentStmt) -> None:
        self.in_assignment = True
        super().visit_assignment_stmt(stmt)
        self.in_assignment = False

    def visit_yield_expr(self, expr: YieldExpr) -> None:
        self.yield_expressions.append((expr, self.in_assignment))

def all_yield_expressions(node: Node) -> list[tuple[YieldExpr, bool]]:
    v = YieldCollector()
    node.accept(v)
    return v.yield_expressions

class YieldFromCollector(FuncCollectorBase):
    def __init__(self) -> None:
        super().__init__()
        self.in_assignment = False
        self.yield_from_expressions: list[tuple[YieldFromExpr, bool]] = []

    def visit_assignment_stmt(self, stmt: AssignmentStmt) -> None:
        self.in_assignment = True
        super().visit_assignment_stmt(stmt)
        self.in_assignment = False

    def visit_yield_from_expr(self, expr: YieldFromExpr) -> None:
        self.yield_from_expressions.append((expr, self.in_assignment))

def all_yield_from_expressions(node: Node) -> list[tuple[YieldFromExpr, bool]]:
    v = YieldFromCollector()
    node.accept(v)
    return v.yield_from_expressions


"""Base visitor that implements an identity AST transform.

Subclass TransformVisitor to perform non-trivial transformations.
"""

from __future__ import annotations

from typing import Iterable, Optional, cast

from mypy.nodes import (
    GDEF,
    REVEAL_TYPE,
    Argument,
    AssertStmt,
    AssertTypeExpr,
    AssignmentExpr,
    AssignmentStmt,
    AwaitExpr,
    Block,
    BreakStmt,
    BytesExpr,
    CallExpr,
    CastExpr,
    ClassDef,
    ComparisonExpr,
    ComplexExpr,
    ConditionalExpr,
    ContinueStmt,
    Decorator,
    DelStmt,
    DictExpr,
    DictionaryComprehension,
    EllipsisExpr,
    EnumCallExpr,
    Expression,
    ExpressionStmt,
    FloatExpr,
    ForStmt,
    FuncDef,
    FuncItem,
    GeneratorExpr,
    GlobalDecl,
    IfStmt,
    Import,
    ImportAll,
    ImportFrom,
    IndexExpr,
    IntExpr,
    LambdaExpr,
    ListComprehension,
    ListExpr,
    MatchStmt,
    MemberExpr,
    MypyFile,
    NamedTupleExpr,
    NameExpr,
    NewTypeExpr,
    Node,
    NonlocalDecl,
    OperatorAssignmentStmt,
    OpExpr,
    OverloadedFuncDef,
    OverloadPart,
    ParamSpecExpr,
    PassStmt,
    PromoteExpr,
    RaiseStmt,
    RefExpr,
    ReturnStmt,
    RevealExpr,
    SetComprehension,
    SetExpr,
    SliceExpr,
    StarExpr,
    Statement,
    StrExpr,
    SuperExpr,
    SymbolTable,
    TempNode,
    TryStmt,
    TupleExpr,
    TypeAliasExpr,
    TypeApplication,
    TypedDictExpr,
    TypeVarExpr,
    TypeVarTupleExpr,
    UnaryExpr,
    Var,
    WhileStmt,
    WithStmt,
    YieldExpr,
    YieldFromExpr,
)
from mypy.patterns import (
    AsPattern,
    ClassPattern,
    MappingPattern,
    OrPattern,
    Pattern,
    SequencePattern,
    SingletonPattern,
    StarredPattern,
    ValuePattern,
)
from mypy.traverser import TraverserVisitor
from mypy.types import FunctionLike, ProperType, Type
from mypy.util import replace_object_state
from mypy.visitor import NodeVisitor

class TransformVisitor(NodeVisitor[Node]):
    """Transform a semantically analyzed AST (or subtree) to an identical copy.

    Use the node() method to transform an AST node.

    Subclass to perform a non-identity transform.

    Notes:

     * This can only be used to transform functions or classes, not top-level
       statements, and/or modules as a whole.
     * Do not duplicate TypeInfo nodes. This would generally not be desirable.
     * Only update some name binding cross-references, but only those that
       refer to Var, Decorator or FuncDef nodes, not those targeting ClassDef or
       TypeInfo nodes.
     * Types are not transformed, but you can override type() to also perform
       type transformation.

    TODO nested classes and functions have not been tested well enough
    """

    def __init__(self) -> None:
        # To simplify testing, set this flag to True if you want to transform
        # all statements in a file (this is prohibited in normal mode).
        self.test_only = False
        # There may be multiple references to a Var node. Keep track of
        # Var translations using a dictionary.
        self.var_map: dict[Var, Var] = {}
        # These are uninitialized placeholder nodes used temporarily for nested
        # functions while we are transforming a top-level function. This maps an
        # untransformed node to a placeholder (which will later become the
        # transformed node).
        self.func_placeholder_map: dict[FuncDef, FuncDef] = {}

    def visit_mypy_file(self, node: MypyFile) -> MypyFile:
        assert self.test_only, "This visitor should not be used for whole files."
        # NOTE: The 'names' and 'imports' instance variables will be empty!
        ignored_lines = {line: codes.copy() for line, codes in node.ignored_lines.items()}
        new = MypyFile(self.statements(node.defs), [], node.is_bom, ignored_lines=ignored_lines)
        new._fullname = node._fullname
        new.path = node.path
        new.names = SymbolTable()
        return new

    def visit_import(self, node: Import) -> Import:
        return Import(node.ids.copy())

    def visit_import_from(self, node: ImportFrom) -> ImportFrom:
        return ImportFrom(node.id, node.relative, node.names.copy())

    def visit_import_all(self, node: ImportAll) -> ImportAll:
        return ImportAll(node.id, node.relative)

    def copy_argument(self, argument: Argument) -> Argument:
        arg = Argument(
            self.visit_var(argument.variable),
            argument.type_annotation,
            argument.initializer,
            argument.kind,
        )

        # Refresh lines of the inner things
        arg.set_line(argument)

        return arg

    def visit_func_def(self, node: FuncDef) -> FuncDef:
        # Note that a FuncDef must be transformed to a FuncDef.

        # These contortions are needed to handle the case of recursive
        # references inside the function being transformed.
        # Set up placeholder nodes for references within this function
        # to other functions defined inside it.
        # Don't create an entry for this function itself though,
        # since we want self-references to point to the original
        # function if this is the top-level node we are transforming.
        init = FuncMapInitializer(self)
        for stmt in node.body.body:
            stmt.accept(init)

        new = FuncDef(
            node.name,
            [self.copy_argument(arg) for arg in node.arguments],
            self.block(node.body),
            cast(Optional[FunctionLike], self.optional_type(node.type)),
        )

        self.copy_function_attributes(new, node)

        new._fullname = node._fullname
        new.is_decorated = node.is_decorated
        new.is_conditional = node.is_conditional
        new.abstract_status = node.abstract_status
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.is_final = node.is_final
        new.original_def = node.original_def

        if node in self.func_placeholder_map:
            # There is a placeholder definition for this function. Replace
            # the attributes of the placeholder with those form the transformed
            # function. We know that the classes will be identical (otherwise
            # this wouldn't work).
            result = self.func_placeholder_map[node]
            replace_object_state(result, new)
            return result
        else:
            return new

    def visit_lambda_expr(self, node: LambdaExpr) -> LambdaExpr:
        new = LambdaExpr(
            [self.copy_argument(arg) for arg in node.arguments],
            self.block(node.body),
            cast(Optional[FunctionLike], self.optional_type(node.type)),
        )
        self.copy_function_attributes(new, node)
        return new

    def copy_function_attributes(self, new: FuncItem, original: FuncItem) -> None:
        new.info = original.info
        new.min_args = original.min_args
        new.max_pos = original.max_pos
        new.is_overload = original.is_overload
        new.is_generator = original.is_generator
        new.is_coroutine = original.is_coroutine
        new.is_async_generator = original.is_async_generator
        new.is_awaitable_coroutine = original.is_awaitable_coroutine
        new.line = original.line

    def visit_overloaded_func_def(self, node: OverloadedFuncDef) -> OverloadedFuncDef:
        items = [cast(OverloadPart, item.accept(self)) for item in node.items]
        for newitem, olditem in zip(items, node.items):
            newitem.line = olditem.line
        new = OverloadedFuncDef(items)
        new._fullname = node._fullname
        new_type = self.optional_type(node.type)
        assert isinstance(new_type, ProperType)
        new.type = new_type
        new.info = node.info
        new.is_static = node.is_static
        new.is_class = node.is_class
        new.is_property = node.is_property
        new.is_final = node.is_final
        if node.impl:
            new.impl = cast(OverloadPart, node.impl.accept(self))
        return new

    def visit_class_def(self, node: ClassDef) -> ClassDef:
        new = ClassDef(
            node.name,
            self.block(node.defs),
            node.type_vars,
            self.expressions(node.base_type_exprs),
            self.optional_expr(node.metaclass),
        )
        new.fullname = node.fullname
        new.info = node.info
        new.decorators = [self.expr(decorator) for decorator in node.decorators]
        return new

    def visit_global_decl(self, node: GlobalDecl) -> GlobalDecl:
        return GlobalDecl(node.names.copy())

    def visit_nonlocal_decl(self, node: NonlocalDecl) -> NonlocalDecl:
        return NonlocalDecl(node.names.copy())

    def visit_block(self, node: Block) -> Block:
        return Block(self.statements(node.body))

    def visit_decorator(self, node: Decorator) -> Decorator:
        # Note that a Decorator must be transformed to a Decorator.
        func = self.visit_func_def(node.func)
        func.line = node.func.line
        new = Decorator(func, self.expressions(node.decorators), self.visit_var(node.var))
        new.is_overload = node.is_overload
        return new

    def visit_var(self, node: Var) -> Var:
        # Note that a Var must be transformed to a Var.
        if node in self.var_map:
            return self.var_map[node]
        new = Var(node.name, self.optional_type(node.type))
        new.line = node.line
        new._fullname = node._fullname
        new.info = node.info
        new.is_self = node.is_self
        new.is_ready = node.is_ready
        new.is_initialized_in_class = node.is_initialized_in_class
        new.is_staticmethod = node.is_staticmethod
        new.is_classmethod = node.is_classmethod
        new.is_property = node.is_property
        new.is_final = node.is_final
        new.final_value = node.final_value
        new.final_unset_in_class = node.final_unset_in_class
        new.final_set_in_init = node.final_set_in_init
        new.set_line(node)
        self.var_map[node] = new
        return new

    def visit_expression_stmt(self, node: ExpressionStmt) -> ExpressionStmt:
        return ExpressionStmt(self.expr(node.expr))

    def visit_assignment_stmt(self, node: AssignmentStmt) -> AssignmentStmt:
        return self.duplicate_assignment(node)

    def duplicate_assignment(self, node: AssignmentStmt) -> AssignmentStmt:
        new = AssignmentStmt(
            self.expressions(node.lvalues),
            self.expr(node.rvalue),
            self.optional_type(node.unanalyzed_type),
        )
        new.line = node.line
        new.is_final_def = node.is_final_def
        new.type = self.optional_type(node.type)
        return new

    def visit_operator_assignment_stmt(
        self, node: OperatorAssignmentStmt
    ) -> OperatorAssignmentStmt:
        return OperatorAssignmentStmt(node.op, self.expr(node.lvalue), self.expr(node.rvalue))

    def visit_while_stmt(self, node: WhileStmt) -> WhileStmt:
        return WhileStmt(
            self.expr(node.expr), self.block(node.body), self.optional_block(node.else_body)
        )

    def visit_for_stmt(self, node: ForStmt) -> ForStmt:
        new = ForStmt(
            self.expr(node.index),
            self.expr(node.expr),
            self.block(node.body),
            self.optional_block(node.else_body),
            self.optional_type(node.unanalyzed_index_type),
        )
        new.is_async = node.is_async
        new.index_type = self.optional_type(node.index_type)
        return new

    def visit_return_stmt(self, node: ReturnStmt) -> ReturnStmt:
        return ReturnStmt(self.optional_expr(node.expr))

    def visit_assert_stmt(self, node: AssertStmt) -> AssertStmt:
        return AssertStmt(self.expr(node.expr), self.optional_expr(node.msg))

    def visit_del_stmt(self, node: DelStmt) -> DelStmt:
        return DelStmt(self.expr(node.expr))

    def visit_if_stmt(self, node: IfStmt) -> IfStmt:
        return IfStmt(
            self.expressions(node.expr),
            self.blocks(node.body),
            self.optional_block(node.else_body),
        )

    def visit_break_stmt(self, node: BreakStmt) -> BreakStmt:
        return BreakStmt()

    def visit_continue_stmt(self, node: ContinueStmt) -> ContinueStmt:
        return ContinueStmt()

    def visit_pass_stmt(self, node: PassStmt) -> PassStmt:
        return PassStmt()

    def visit_raise_stmt(self, node: RaiseStmt) -> RaiseStmt:
        return RaiseStmt(self.optional_expr(node.expr), self.optional_expr(node.from_expr))

    def visit_try_stmt(self, node: TryStmt) -> TryStmt:
        new = TryStmt(
            self.block(node.body),
            self.optional_names(node.vars),
            self.optional_expressions(node.types),
            self.blocks(node.handlers),
            self.optional_block(node.else_body),
            self.optional_block(node.finally_body),
        )
        new.is_star = node.is_star
        return new

    def visit_with_stmt(self, node: WithStmt) -> WithStmt:
        new = WithStmt(
            self.expressions(node.expr),
            self.optional_expressions(node.target),
            self.block(node.body),
            self.optional_type(node.unanalyzed_type),
        )
        new.is_async = node.is_async
        new.analyzed_types = [self.type(typ) for typ in node.analyzed_types]
        return new

    def visit_as_pattern(self, p: AsPattern) -> AsPattern:
        return AsPattern(
            pattern=self.pattern(p.pattern) if p.pattern is not None else None,
            name=self.duplicate_name(p.name) if p.name is not None else None,
        )

    def visit_or_pattern(self, p: OrPattern) -> OrPattern:
        return OrPattern([self.pattern(pat) for pat in p.patterns])

    def visit_value_pattern(self, p: ValuePattern) -> ValuePattern:
        return ValuePattern(self.expr(p.expr))

    def visit_singleton_pattern(self, p: SingletonPattern) -> SingletonPattern:
        return SingletonPattern(p.value)

    def visit_sequence_pattern(self, p: SequencePattern) -> SequencePattern:
        return SequencePattern([self.pattern(pat) for pat in p.patterns])

    def visit_starred_pattern(self, p: StarredPattern) -> StarredPattern:
        return StarredPattern(self.duplicate_name(p.capture) if p.capture is not None else None)

    def visit_mapping_pattern(self, p: MappingPattern) -> MappingPattern:
        return MappingPattern(
            keys=[self.expr(expr) for expr in p.keys],
            values=[self.pattern(pat) for pat in p.values],
            rest=self.duplicate_name(p.rest) if p.rest is not None else None,
        )

    def visit_class_pattern(self, p: ClassPattern) -> ClassPattern:
        class_ref = p.class_ref.accept(self)
        assert isinstance(class_ref, RefExpr)
        return ClassPattern(
            class_ref=class_ref,
            positionals=[self.pattern(pat) for pat in p.positionals],
            keyword_keys=list(p.keyword_keys),
            keyword_values=[self.pattern(pat) for pat in p.keyword_values],
        )

    def visit_match_stmt(self, o: MatchStmt) -> MatchStmt:
        return MatchStmt(
            subject=self.expr(o.subject),
            patterns=[self.pattern(p) for p in o.patterns],
            guards=self.optional_expressions(o.guards),
            bodies=self.blocks(o.bodies),
        )

    def visit_star_expr(self, node: StarExpr) -> StarExpr:
        return StarExpr(node.expr)

    def visit_int_expr(self, node: IntExpr) -> IntExpr:
        return IntExpr(node.value)

    def visit_str_expr(self, node: StrExpr) -> StrExpr:
        return StrExpr(node.value)

    def visit_bytes_expr(self, node: BytesExpr) -> BytesExpr:
        return BytesExpr(node.value)

    def visit_float_expr(self, node: FloatExpr) -> FloatExpr:
        return FloatExpr(node.value)

    def visit_complex_expr(self, node: ComplexExpr) -> ComplexExpr:
        return ComplexExpr(node.value)

    def visit_ellipsis(self, node: EllipsisExpr) -> EllipsisExpr:
        return EllipsisExpr()

    def visit_name_expr(self, node: NameExpr) -> NameExpr:
        return self.duplicate_name(node)

    def duplicate_name(self, node: NameExpr) -> NameExpr:
        # This method is used when the transform result must be a NameExpr.
        # visit_name_expr() is used when there is no such restriction.
        new = NameExpr(node.name)
        self.copy_ref(new, node)
        new.is_special_form = node.is_special_form
        return new

    def visit_member_expr(self, node: MemberExpr) -> MemberExpr:
        member = MemberExpr(self.expr(node.expr), node.name)
        if node.def_var:
            # This refers to an attribute and we don't transform attributes by default,
            # just normal variables.
            member.def_var = node.def_var
        self.copy_ref(member, node)
        return member

    def copy_ref(self, new: RefExpr, original: RefExpr) -> None:
        new.kind = original.kind
        new.fullname = original.fullname
        target = original.node
        if isinstance(target, Var):
            # Do not transform references to global variables. See
            # testGenericFunctionAliasExpand for an example where this is important.
            if original.kind != GDEF:
                target = self.visit_var(target)
        elif isinstance(target, Decorator):
            target = self.visit_var(target.var)
        elif isinstance(target, FuncDef):
            # Use a placeholder node for the function if it exists.
            target = self.func_placeholder_map.get(target, target)
        new.node = target
        new.is_new_def = original.is_new_def
        new.is_inferred_def = original.is_inferred_def

    def visit_yield_from_expr(self, node: YieldFromExpr) -> YieldFromExpr:
        return YieldFromExpr(self.expr(node.expr))

    def visit_yield_expr(self, node: YieldExpr) -> YieldExpr:
        return YieldExpr(self.optional_expr(node.expr))

    def visit_await_expr(self, node: AwaitExpr) -> AwaitExpr:
        return AwaitExpr(self.expr(node.expr))

    def visit_call_expr(self, node: CallExpr) -> CallExpr:
        return CallExpr(
            self.expr(node.callee),
            self.expressions(node.args),
            node.arg_kinds.copy(),
            node.arg_names.copy(),
            self.optional_expr(node.analyzed),
        )

    def visit_op_expr(self, node: OpExpr) -> OpExpr:
        new = OpExpr(
            node.op,
            self.expr(node.left),
            self.expr(node.right),
            cast(Optional[TypeAliasExpr], self.optional_expr(node.analyzed)),
        )
        new.method_type = self.optional_type(node.method_type)
        return new

    def visit_comparison_expr(self, node: ComparisonExpr) -> ComparisonExpr:
        new = ComparisonExpr(node.operators, self.expressions(node.operands))
        new.method_types = [self.optional_type(t) for t in node.method_types]
        return new

    def visit_cast_expr(self, node: CastExpr) -> CastExpr:
        return CastExpr(self.expr(node.expr), self.type(node.type))

    def visit_assert_type_expr(self, node: AssertTypeExpr) -> AssertTypeExpr:
        return AssertTypeExpr(self.expr(node.expr), self.type(node.type))

    def visit_reveal_expr(self, node: RevealExpr) -> RevealExpr:
        if node.kind == REVEAL_TYPE:
            assert node.expr is not None
            return RevealExpr(kind=REVEAL_TYPE, expr=self.expr(node.expr))
        else:
            # Reveal locals expressions don't have any sub expressions
            return node

    def visit_super_expr(self, node: SuperExpr) -> SuperExpr:
        call = self.expr(node.call)
        assert isinstance(call, CallExpr)
        new = SuperExpr(node.name, call)
        new.info = node.info
        return new

    def visit_assignment_expr(self, node: AssignmentExpr) -> AssignmentExpr:
        return AssignmentExpr(self.expr(node.target), self.expr(node.value))

    def visit_unary_expr(self, node: UnaryExpr) -> UnaryExpr:
        new = UnaryExpr(node.op, self.expr(node.expr))
        new.method_type = self.optional_type(node.method_type)
        return new

    def visit_list_expr(self, node: ListExpr) -> ListExpr:
        return ListExpr(self.expressions(node.items))

    def visit_dict_expr(self, node: DictExpr) -> DictExpr:
        return DictExpr(
            [(self.expr(key) if key else None, self.expr(value)) for key, value in node.items]
        )

    def visit_tuple_expr(self, node: TupleExpr) -> TupleExpr:
        return TupleExpr(self.expressions(node.items))

    def visit_set_expr(self, node: SetExpr) -> SetExpr:
        return SetExpr(self.expressions(node.items))

    def visit_index_expr(self, node: IndexExpr) -> IndexExpr:
        new = IndexExpr(self.expr(node.base), self.expr(node.index))
        if node.method_type:
            new.method_type = self.type(node.method_type)
        if node.analyzed:
            if isinstance(node.analyzed, TypeApplication):
                new.analyzed = self.visit_type_application(node.analyzed)
            else:
                new.analyzed = self.visit_type_alias_expr(node.analyzed)
            new.analyzed.set_line(node.analyzed)
        return new

    def visit_type_application(self, node: TypeApplication) -> TypeApplication:
        return TypeApplication(self.expr(node.expr), self.types(node.types))

    def visit_list_comprehension(self, node: ListComprehension) -> ListComprehension:
        generator = self.duplicate_generator(node.generator)
        generator.set_line(node.generator)
        return ListComprehension(generator)

    def visit_set_comprehension(self, node: SetComprehension) -> SetComprehension:
        generator = self.duplicate_generator(node.generator)
        generator.set_line(node.generator)
        return SetComprehension(generator)

    def visit_dictionary_comprehension(
        self, node: DictionaryComprehension
    ) -> DictionaryComprehension:
        return DictionaryComprehension(
            self.expr(node.key),
            self.expr(node.value),
            [self.expr(index) for index in node.indices],
            [self.expr(s) for s in node.sequences],
            [[self.expr(cond) for cond in conditions] for conditions in node.condlists],
            node.is_async,
        )

    def visit_generator_expr(self, node: GeneratorExpr) -> GeneratorExpr:
        return self.duplicate_generator(node)

    def duplicate_generator(self, node: GeneratorExpr) -> GeneratorExpr:
        return GeneratorExpr(
            self.expr(node.left_expr),
            [self.expr(index) for index in node.indices],
            [self.expr(s) for s in node.sequences],
            [[self.expr(cond) for cond in conditions] for conditions in node.condlists],
            node.is_async,
        )

    def visit_slice_expr(self, node: SliceExpr) -> SliceExpr:
        return SliceExpr(
            self.optional_expr(node.begin_index),
            self.optional_expr(node.end_index),
            self.optional_expr(node.stride),
        )

    def visit_conditional_expr(self, node: ConditionalExpr) -> ConditionalExpr:
        return ConditionalExpr(
            self.expr(node.cond), self.expr(node.if_expr), self.expr(node.else_expr)
        )

    def visit_type_var_expr(self, node: TypeVarExpr) -> TypeVarExpr:
        return TypeVarExpr(
            node.name,
            node.fullname,
            self.types(node.values),
            self.type(node.upper_bound),
            self.type(node.default),
            variance=node.variance,
        )

    def visit_paramspec_expr(self, node: ParamSpecExpr) -> ParamSpecExpr:
        return ParamSpecExpr(
            node.name,
            node.fullname,
            self.type(node.upper_bound),
            self.type(node.default),
            variance=node.variance,
        )

    def visit_type_var_tuple_expr(self, node: TypeVarTupleExpr) -> TypeVarTupleExpr:
        return TypeVarTupleExpr(
            node.name,
            node.fullname,
            self.type(node.upper_bound),
            node.tuple_fallback,
            self.type(node.default),
            variance=node.variance,
        )

    def visit_type_alias_expr(self, node: TypeAliasExpr) -> TypeAliasExpr:
        return TypeAliasExpr(node.node)

    def visit_newtype_expr(self, node: NewTypeExpr) -> NewTypeExpr:
        res = NewTypeExpr(node.name, node.old_type, line=node.line, column=node.column)
        res.info = node.info
        return res

    def visit_namedtuple_expr(self, node: NamedTupleExpr) -> NamedTupleExpr:
        return NamedTupleExpr(node.info)

    def visit_enum_call_expr(self, node: EnumCallExpr) -> EnumCallExpr:
        return EnumCallExpr(node.info, node.items, node.values)

    def visit_typeddict_expr(self, node: TypedDictExpr) -> Node:
        return TypedDictExpr(node.info)

    def visit__promote_expr(self, node: PromoteExpr) -> PromoteExpr:
        return PromoteExpr(node.type)

    def visit_temp_node(self, node: TempNode) -> TempNode:
        return TempNode(self.type(node.type))

    def node(self, node: Node) -> Node:
        new = node.accept(self)
        new.set_line(node)
        return new

    def mypyfile(self, node: MypyFile) -> MypyFile:
        new = node.accept(self)
        assert isinstance(new, MypyFile)
        new.set_line(node)
        return new

    def expr(self, expr: Expression) -> Expression:
        new = expr.accept(self)
        assert isinstance(new, Expression)
        new.set_line(expr)
        return new

    def stmt(self, stmt: Statement) -> Statement:
        new = stmt.accept(self)
        assert isinstance(new, Statement)
        new.set_line(stmt)
        return new

    def pattern(self, pattern: Pattern) -> Pattern:
        new = pattern.accept(self)
        assert isinstance(new, Pattern)
        new.set_line(pattern)
        return new

    # Helpers
    #
    # All the node helpers also propagate line numbers.

    def optional_expr(self, expr: Expression | None) -> Expression | None:
        if expr:
            return self.expr(expr)
        else:
            return None

    def block(self, block: Block) -> Block:
        new = self.visit_block(block)
        new.line = block.line
        return new

    def optional_block(self, block: Block | None) -> Block | None:
        if block:
            return self.block(block)
        else:
            return None

    def statements(self, statements: list[Statement]) -> list[Statement]:
        return [self.stmt(stmt) for stmt in statements]

    def expressions(self, expressions: list[Expression]) -> list[Expression]:
        return [self.expr(expr) for expr in expressions]

    def optional_expressions(
        self, expressions: Iterable[Expression | None]
    ) -> list[Expression | None]:
        return [self.optional_expr(expr) for expr in expressions]

    def blocks(self, blocks: list[Block]) -> list[Block]:
        return [self.block(block) for block in blocks]

    def names(self, names: list[NameExpr]) -> list[NameExpr]:
        return [self.duplicate_name(name) for name in names]

    def optional_names(self, names: Iterable[NameExpr | None]) -> list[NameExpr | None]:
        result: list[NameExpr | None] = []
        for name in names:
            if name:
                result.append(self.duplicate_name(name))
            else:
                result.append(None)
        return result

    def type(self, type: Type) -> Type:
        # Override this method to transform types.
        return type

    def optional_type(self, type: Type | None) -> Type | None:
        if type:
            return self.type(type)
        else:
            return None

    def types(self, types: list[Type]) -> list[Type]:
        return [self.type(type) for type in types]

class FuncMapInitializer(TraverserVisitor):
    """This traverser creates mappings from nested FuncDefs to placeholder FuncDefs.

    The placeholders will later be replaced with transformed nodes.
    """

    def __init__(self, transformer: TransformVisitor) -> None:
        self.transformer = transformer

    def visit_func_def(self, node: FuncDef) -> None:
        if node not in self.transformer.func_placeholder_map:
            # Haven't seen this FuncDef before, so create a placeholder node.
            self.transformer.func_placeholder_map[node] = FuncDef(
                node.name, node.arguments, node.body, None
            )
        super().visit_func_def(node)


from __future__ import annotations

from mypy.nodes import (
    ParamSpecExpr,
    SymbolTableNode,
    TypeVarExpr,
    TypeVarLikeExpr,
    TypeVarTupleExpr,
)
from mypy.types import (
    ParamSpecFlavor,
    ParamSpecType,
    TypeVarId,
    TypeVarLikeType,
    TypeVarTupleType,
    TypeVarType,
)
from mypy.typetraverser import TypeTraverserVisitor

class TypeVarLikeNamespaceSetter(TypeTraverserVisitor):
    """Set namespace for all TypeVarLikeTypes types."""

    def __init__(self, namespace: str) -> None:
        self.namespace = namespace

    def visit_type_var(self, t: TypeVarType) -> None:
        t.id.namespace = self.namespace
        super().visit_type_var(t)

    def visit_param_spec(self, t: ParamSpecType) -> None:
        t.id.namespace = self.namespace
        return super().visit_param_spec(t)

    def visit_type_var_tuple(self, t: TypeVarTupleType) -> None:
        t.id.namespace = self.namespace
        super().visit_type_var_tuple(t)

class TypeVarLikeScope:
    """Scope that holds bindings for type variables and parameter specifications.

    Node fullname -> TypeVarLikeType.
    """

    def __init__(
        self,
        parent: TypeVarLikeScope | None = None,
        is_class_scope: bool = False,
        prohibited: TypeVarLikeScope | None = None,
        namespace: str = "",
    ) -> None:
        """Initializer for TypeVarLikeScope

        Parameters:
          parent: the outer scope for this scope
          is_class_scope: True if this represents a generic class
          prohibited: Type variables that aren't strictly in scope exactly,
                      but can't be bound because they're part of an outer class's scope.
        """
        self.scope: dict[str, TypeVarLikeType] = {}
        self.parent = parent
        self.func_id = 0
        self.class_id = 0
        self.is_class_scope = is_class_scope
        self.prohibited = prohibited
        self.namespace = namespace
        if parent is not None:
            self.func_id = parent.func_id
            self.class_id = parent.class_id

    def get_function_scope(self) -> TypeVarLikeScope | None:
        """Get the nearest parent that's a function scope, not a class scope"""
        it: TypeVarLikeScope | None = self
        while it is not None and it.is_class_scope:
            it = it.parent
        return it

    def allow_binding(self, fullname: str) -> bool:
        if fullname in self.scope:
            return False
        elif self.parent and not self.parent.allow_binding(fullname):
            return False
        elif self.prohibited and not self.prohibited.allow_binding(fullname):
            return False
        return True

    def method_frame(self, namespace: str) -> TypeVarLikeScope:
        """A new scope frame for binding a method"""
        return TypeVarLikeScope(self, False, None, namespace=namespace)

    def class_frame(self, namespace: str) -> TypeVarLikeScope:
        """A new scope frame for binding a class. Prohibits *this* class's tvars"""
        return TypeVarLikeScope(self.get_function_scope(), True, self, namespace=namespace)

    def new_unique_func_id(self) -> TypeVarId:
        """Used by plugin-like code that needs to make synthetic generic functions."""
        self.func_id -= 1
        return TypeVarId(self.func_id)

    def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
        if self.is_class_scope:
            self.class_id += 1
            i = self.class_id
        else:
            self.func_id -= 1
            i = self.func_id
        namespace = self.namespace
        tvar_expr.default.accept(TypeVarLikeNamespaceSetter(namespace))

        if isinstance(tvar_expr, TypeVarExpr):
            tvar_def: TypeVarLikeType = TypeVarType(
                name=name,
                fullname=tvar_expr.fullname,
                id=TypeVarId(i, namespace=namespace),
                values=tvar_expr.values,
                upper_bound=tvar_expr.upper_bound,
                default=tvar_expr.default,
                variance=tvar_expr.variance,
                line=tvar_expr.line,
                column=tvar_expr.column,
            )
        elif isinstance(tvar_expr, ParamSpecExpr):
            tvar_def = ParamSpecType(
                name=name,
                fullname=tvar_expr.fullname,
                id=TypeVarId(i, namespace=namespace),
                flavor=ParamSpecFlavor.BARE,
                upper_bound=tvar_expr.upper_bound,
                default=tvar_expr.default,
                line=tvar_expr.line,
                column=tvar_expr.column,
            )
        elif isinstance(tvar_expr, TypeVarTupleExpr):
            tvar_def = TypeVarTupleType(
                name=name,
                fullname=tvar_expr.fullname,
                id=TypeVarId(i, namespace=namespace),
                upper_bound=tvar_expr.upper_bound,
                tuple_fallback=tvar_expr.tuple_fallback,
                default=tvar_expr.default,
                line=tvar_expr.line,
                column=tvar_expr.column,
            )
        else:
            assert False
        self.scope[tvar_expr.fullname] = tvar_def
        return tvar_def

    def bind_existing(self, tvar_def: TypeVarLikeType) -> None:
        self.scope[tvar_def.fullname] = tvar_def

    def get_binding(self, item: str | SymbolTableNode) -> TypeVarLikeType | None:
        fullname = item.fullname if isinstance(item, SymbolTableNode) else item
        assert fullname
        if fullname in self.scope:
            return self.scope[fullname]
        elif self.parent is not None:
            return self.parent.get_binding(fullname)
        else:
            return None

    def __str__(self) -> str:
        me = ", ".join(f"{k}: {v.name}`{v.id}" for k, v in self.scope.items())
        if self.parent is None:
            return me
        return f"{self.parent} <- {me}"


"""Type visitor classes.

This module defines the type visitors that are intended to be
subclassed by other code.  They have been separated out into their own
module to ease converting mypy to run under mypyc, since currently
mypyc-extension classes can extend interpreted classes but not the
other way around. Separating them out, then, allows us to compile
types before we can compile everything that uses a TypeVisitor.

The visitors are all re-exported from mypy.types and that is how
other modules refer to them.
"""

from __future__ import annotations

from abc import abstractmethod
from typing import Any, Callable, Final, Generic, Iterable, Sequence, TypeVar, cast

from mypy_extensions import mypyc_attr, trait

from mypy.types import (
    AnyType,
    CallableArgument,
    CallableType,
    DeletedType,
    EllipsisType,
    ErasedType,
    Instance,
    LiteralType,
    NoneType,
    Overloaded,
    Parameters,
    ParamSpecType,
    PartialType,
    PlaceholderType,
    RawExpressionType,
    TupleType,
    Type,
    TypeAliasType,
    TypedDictType,
    TypeList,
    TypeType,
    TypeVarLikeType,
    TypeVarTupleType,
    TypeVarType,
    UnboundType,
    UninhabitedType,
    UnionType,
    UnpackType,
    get_proper_type,
)

T = TypeVar("T")

@trait
@mypyc_attr(allow_interpreted_subclasses=True)
class TypeVisitor(Generic[T]):
    """Visitor class for types (Type subclasses).

    The parameter T is the return type of the visit methods.
    """

    @abstractmethod
    def visit_unbound_type(self, t: UnboundType) -> T:
        pass

    @abstractmethod
    def visit_any(self, t: AnyType) -> T:
        pass

    @abstractmethod
    def visit_none_type(self, t: NoneType) -> T:
        pass

    @abstractmethod
    def visit_uninhabited_type(self, t: UninhabitedType) -> T:
        pass

    @abstractmethod
    def visit_erased_type(self, t: ErasedType) -> T:
        pass

    @abstractmethod
    def visit_deleted_type(self, t: DeletedType) -> T:
        pass

    @abstractmethod
    def visit_type_var(self, t: TypeVarType) -> T:
        pass

    @abstractmethod
    def visit_param_spec(self, t: ParamSpecType) -> T:
        pass

    @abstractmethod
    def visit_parameters(self, t: Parameters) -> T:
        pass

    @abstractmethod
    def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
        pass

    @abstractmethod
    def visit_instance(self, t: Instance) -> T:
        pass

    @abstractmethod
    def visit_callable_type(self, t: CallableType) -> T:
        pass

    @abstractmethod
    def visit_overloaded(self, t: Overloaded) -> T:
        pass

    @abstractmethod
    def visit_tuple_type(self, t: TupleType) -> T:
        pass

    @abstractmethod
    def visit_typeddict_type(self, t: TypedDictType) -> T:
        pass

    @abstractmethod
    def visit_literal_type(self, t: LiteralType) -> T:
        pass

    @abstractmethod
    def visit_union_type(self, t: UnionType) -> T:
        pass

    @abstractmethod
    def visit_partial_type(self, t: PartialType) -> T:
        pass

    @abstractmethod
    def visit_type_type(self, t: TypeType) -> T:
        pass

    @abstractmethod
    def visit_type_alias_type(self, t: TypeAliasType) -> T:
        pass

    @abstractmethod
    def visit_unpack_type(self, t: UnpackType) -> T:
        pass

@trait
@mypyc_attr(allow_interpreted_subclasses=True)
class SyntheticTypeVisitor(TypeVisitor[T]):
    """A TypeVisitor that also knows how to visit synthetic AST constructs.

    Not just real types.
    """

    @abstractmethod
    def visit_type_list(self, t: TypeList) -> T:
        pass

    @abstractmethod
    def visit_callable_argument(self, t: CallableArgument) -> T:
        pass

    @abstractmethod
    def visit_ellipsis_type(self, t: EllipsisType) -> T:
        pass

    @abstractmethod
    def visit_raw_expression_type(self, t: RawExpressionType) -> T:
        pass

    @abstractmethod
    def visit_placeholder_type(self, t: PlaceholderType) -> T:
        pass

@mypyc_attr(allow_interpreted_subclasses=True)
class TypeTranslator(TypeVisitor[Type]):
    """Identity type transformation.

    Subclass this and override some methods to implement a non-trivial
    transformation.

    We cache the results of certain translations to avoid
    massively expanding the sizes of types.
    """

    def __init__(self, cache: dict[Type, Type] | None = None) -> None:
        # For deduplication of results
        self.cache = cache

    def get_cached(self, t: Type) -> Type | None:
        if self.cache is None:
            return None
        return self.cache.get(t)

    def set_cached(self, orig: Type, new: Type) -> None:
        if self.cache is None:
            # Minor optimization: construct lazily
            self.cache = {}
        self.cache[orig] = new

    def visit_unbound_type(self, t: UnboundType) -> Type:
        return t

    def visit_any(self, t: AnyType) -> Type:
        return t

    def visit_none_type(self, t: NoneType) -> Type:
        return t

    def visit_uninhabited_type(self, t: UninhabitedType) -> Type:
        return t

    def visit_erased_type(self, t: ErasedType) -> Type:
        return t

    def visit_deleted_type(self, t: DeletedType) -> Type:
        return t

    def visit_instance(self, t: Instance) -> Type:
        last_known_value: LiteralType | None = None
        if t.last_known_value is not None:
            raw_last_known_value = t.last_known_value.accept(self)
            assert isinstance(raw_last_known_value, LiteralType)  # type: ignore[misc]
            last_known_value = raw_last_known_value
        return Instance(
            typ=t.type,
            args=self.translate_types(t.args),
            line=t.line,
            column=t.column,
            last_known_value=last_known_value,
            extra_attrs=t.extra_attrs,
        )

    def visit_type_var(self, t: TypeVarType) -> Type:
        return t

    def visit_param_spec(self, t: ParamSpecType) -> Type:
        return t

    def visit_parameters(self, t: Parameters) -> Type:
        return t.copy_modified(arg_types=self.translate_types(t.arg_types))

    def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
        return t

    def visit_partial_type(self, t: PartialType) -> Type:
        return t

    def visit_unpack_type(self, t: UnpackType) -> Type:
        return UnpackType(t.type.accept(self))

    def visit_callable_type(self, t: CallableType) -> Type:
        return t.copy_modified(
            arg_types=self.translate_types(t.arg_types),
            ret_type=t.ret_type.accept(self),
            variables=self.translate_variables(t.variables),
        )

    def visit_tuple_type(self, t: TupleType) -> Type:
        return TupleType(
            self.translate_types(t.items),
            # TODO: This appears to be unsafe.
            cast(Any, t.partial_fallback.accept(self)),
            t.line,
            t.column,
        )

    def visit_typeddict_type(self, t: TypedDictType) -> Type:
        # Use cache to avoid O(n**2) or worse expansion of types during translation
        if cached := self.get_cached(t):
            return cached
        items = {item_name: item_type.accept(self) for (item_name, item_type) in t.items.items()}
        result = TypedDictType(
            items,
            t.required_keys,
            t.readonly_keys,
            # TODO: This appears to be unsafe.
            cast(Any, t.fallback.accept(self)),
            t.line,
            t.column,
        )
        self.set_cached(t, result)
        return result

    def visit_literal_type(self, t: LiteralType) -> Type:
        fallback = t.fallback.accept(self)
        assert isinstance(fallback, Instance)  # type: ignore[misc]
        return LiteralType(value=t.value, fallback=fallback, line=t.line, column=t.column)

    def visit_union_type(self, t: UnionType) -> Type:
        # Use cache to avoid O(n**2) or worse expansion of types during translation
        # (only for large unions, since caching adds overhead)
        use_cache = len(t.items) > 3
        if use_cache and (cached := self.get_cached(t)):
            return cached

        result = UnionType(
            self.translate_types(t.items),
            t.line,
            t.column,
            uses_pep604_syntax=t.uses_pep604_syntax,
        )
        if use_cache:
            self.set_cached(t, result)
        return result

    def translate_types(self, types: Iterable[Type]) -> list[Type]:
        return [t.accept(self) for t in types]

    def translate_variables(
        self, variables: Sequence[TypeVarLikeType]
    ) -> Sequence[TypeVarLikeType]:
        return variables

    def visit_overloaded(self, t: Overloaded) -> Type:
        items: list[CallableType] = []
        for item in t.items:
            new = item.accept(self)
            assert isinstance(new, CallableType)  # type: ignore[misc]
            items.append(new)
        return Overloaded(items=items)

    def visit_type_type(self, t: TypeType) -> Type:
        return TypeType.make_normalized(t.item.accept(self), line=t.line, column=t.column)

    @abstractmethod
    def visit_type_alias_type(self, t: TypeAliasType) -> Type:
        # This method doesn't have a default implementation for type translators,
        # because type aliases are special: some information is contained in the
        # TypeAlias node, and we normally don't generate new nodes. Every subclass
        # must implement this depending on its semantics.
        pass

@mypyc_attr(allow_interpreted_subclasses=True)
class TypeQuery(SyntheticTypeVisitor[T]):
    """Visitor for performing queries of types.

    strategy is used to combine results for a series of types,
    common use cases involve a boolean query using `any` or `all`.

    Note: this visitor keeps an internal state (tracks type aliases to avoid
    recursion), so it should *never* be re-used for querying different types,
    create a new visitor instance instead.

    # TODO: check that we don't have existing violations of this rule.
    """

    def __init__(self, strategy: Callable[[list[T]], T]) -> None:
        self.strategy = strategy
        # Keep track of the type aliases already visited. This is needed to avoid
        # infinite recursion on types like A = Union[int, List[A]].
        self.seen_aliases: set[TypeAliasType] = set()
        # By default, we eagerly expand type aliases, and query also types in the
        # alias target. In most cases this is a desired behavior, but we may want
        # to skip targets in some cases (e.g. when collecting type variables).
        self.skip_alias_target = False

    def visit_unbound_type(self, t: UnboundType) -> T:
        return self.query_types(t.args)

    def visit_type_list(self, t: TypeList) -> T:
        return self.query_types(t.items)

    def visit_callable_argument(self, t: CallableArgument) -> T:
        return t.typ.accept(self)

    def visit_any(self, t: AnyType) -> T:
        return self.strategy([])

    def visit_uninhabited_type(self, t: UninhabitedType) -> T:
        return self.strategy([])

    def visit_none_type(self, t: NoneType) -> T:
        return self.strategy([])

    def visit_erased_type(self, t: ErasedType) -> T:
        return self.strategy([])

    def visit_deleted_type(self, t: DeletedType) -> T:
        return self.strategy([])

    def visit_type_var(self, t: TypeVarType) -> T:
        return self.query_types([t.upper_bound, t.default] + t.values)

    def visit_param_spec(self, t: ParamSpecType) -> T:
        return self.query_types([t.upper_bound, t.default, t.prefix])

    def visit_type_var_tuple(self, t: TypeVarTupleType) -> T:
        return self.query_types([t.upper_bound, t.default])

    def visit_unpack_type(self, t: UnpackType) -> T:
        return self.query_types([t.type])

    def visit_parameters(self, t: Parameters) -> T:
        return self.query_types(t.arg_types)

    def visit_partial_type(self, t: PartialType) -> T:
        return self.strategy([])

    def visit_instance(self, t: Instance) -> T:
        return self.query_types(t.args)

    def visit_callable_type(self, t: CallableType) -> T:
        # FIX generics
        return self.query_types(t.arg_types + [t.ret_type])

    def visit_tuple_type(self, t: TupleType) -> T:
        return self.query_types(t.items)

    def visit_typeddict_type(self, t: TypedDictType) -> T:
        return self.query_types(t.items.values())

    def visit_raw_expression_type(self, t: RawExpressionType) -> T:
        return self.strategy([])

    def visit_literal_type(self, t: LiteralType) -> T:
        return self.strategy([])

    def visit_union_type(self, t: UnionType) -> T:
        return self.query_types(t.items)

    def visit_overloaded(self, t: Overloaded) -> T:
        return self.query_types(t.items)

    def visit_type_type(self, t: TypeType) -> T:
        return t.item.accept(self)

    def visit_ellipsis_type(self, t: EllipsisType) -> T:
        return self.strategy([])

    def visit_placeholder_type(self, t: PlaceholderType) -> T:
        return self.query_types(t.args)

    def visit_type_alias_type(self, t: TypeAliasType) -> T:
        # Skip type aliases already visited types to avoid infinite recursion.
        # TODO: Ideally we should fire subvisitors here (or use caching) if we care
        #       about duplicates.
        if t in self.seen_aliases:
            return self.strategy([])
        self.seen_aliases.add(t)
        if self.skip_alias_target:
            return self.query_types(t.args)
        return get_proper_type(t).accept(self)

    def query_types(self, types: Iterable[Type]) -> T:
        """Perform a query for a list of types using the strategy to combine the results."""
        return self.strategy([t.accept(self) for t in types])

# Return True if at least one type component returns True
ANY_STRATEGY: Final = 0
# Return True if no type component returns False
ALL_STRATEGY: Final = 1

class BoolTypeQuery(SyntheticTypeVisitor[bool]):
    """Visitor for performing recursive queries of types with a bool result.

    Use TypeQuery if you need non-bool results.

    'strategy' is used to combine results for a series of types. It must
    be ANY_STRATEGY or ALL_STRATEGY.

    Note: This visitor keeps an internal state (tracks type aliases to avoid
    recursion), so it should *never* be re-used for querying different types
    unless you call reset() first.
    """

    def __init__(self, strategy: int) -> None:
        self.strategy = strategy
        if strategy == ANY_STRATEGY:
            self.default = False
        else:
            assert strategy == ALL_STRATEGY
            self.default = True
        # Keep track of the type aliases already visited. This is needed to avoid
        # infinite recursion on types like A = Union[int, List[A]]. An empty set is
        # represented as None as a micro-optimization.
        self.seen_aliases: set[TypeAliasType] | None = None
        # By default, we eagerly expand type aliases, and query also types in the
        # alias target. In most cases this is a desired behavior, but we may want
        # to skip targets in some cases (e.g. when collecting type variables).
        self.skip_alias_target = False

    def reset(self) -> None:
        """Clear mutable state (but preserve strategy).

        This *must* be called if you want to reuse the visitor.
        """
        self.seen_aliases = None

    def visit_unbound_type(self, t: UnboundType) -> bool:
        return self.query_types(t.args)

    def visit_type_list(self, t: TypeList) -> bool:
        return self.query_types(t.items)

    def visit_callable_argument(self, t: CallableArgument) -> bool:
        return t.typ.accept(self)

    def visit_any(self, t: AnyType) -> bool:
        return self.default

    def visit_uninhabited_type(self, t: UninhabitedType) -> bool:
        return self.default

    def visit_none_type(self, t: NoneType) -> bool:
        return self.default

    def visit_erased_type(self, t: ErasedType) -> bool:
        return self.default

    def visit_deleted_type(self, t: DeletedType) -> bool:
        return self.default

    def visit_type_var(self, t: TypeVarType) -> bool:
        return self.query_types([t.upper_bound, t.default] + t.values)

    def visit_param_spec(self, t: ParamSpecType) -> bool:
        return self.query_types([t.upper_bound, t.default])

    def visit_type_var_tuple(self, t: TypeVarTupleType) -> bool:
        return self.query_types([t.upper_bound, t.default])

    def visit_unpack_type(self, t: UnpackType) -> bool:
        return self.query_types([t.type])

    def visit_parameters(self, t: Parameters) -> bool:
        return self.query_types(t.arg_types)

    def visit_partial_type(self, t: PartialType) -> bool:
        return self.default

    def visit_instance(self, t: Instance) -> bool:
        return self.query_types(t.args)

    def visit_callable_type(self, t: CallableType) -> bool:
        # FIX generics
        # Avoid allocating any objects here as an optimization.
        args = self.query_types(t.arg_types)
        ret = t.ret_type.accept(self)
        if self.strategy == ANY_STRATEGY:
            return args or ret
        else:
            return args and ret

    def visit_tuple_type(self, t: TupleType) -> bool:
        return self.query_types(t.items)

    def visit_typeddict_type(self, t: TypedDictType) -> bool:
        return self.query_types(list(t.items.values()))

    def visit_raw_expression_type(self, t: RawExpressionType) -> bool:
        return self.default

    def visit_literal_type(self, t: LiteralType) -> bool:
        return self.default

    def visit_union_type(self, t: UnionType) -> bool:
        return self.query_types(t.items)

    def visit_overloaded(self, t: Overloaded) -> bool:
        return self.query_types(t.items)  # type: ignore[arg-type]

    def visit_type_type(self, t: TypeType) -> bool:
        return t.item.accept(self)

    def visit_ellipsis_type(self, t: EllipsisType) -> bool:
        return self.default

    def visit_placeholder_type(self, t: PlaceholderType) -> bool:
        return self.query_types(t.args)

    def visit_type_alias_type(self, t: TypeAliasType) -> bool:
        # Skip type aliases already visited types to avoid infinite recursion.
        # TODO: Ideally we should fire subvisitors here (or use caching) if we care
        #       about duplicates.
        if self.seen_aliases is None:
            self.seen_aliases = set()
        elif t in self.seen_aliases:
            return self.default
        self.seen_aliases.add(t)
        if self.skip_alias_target:
            return self.query_types(t.args)
        return get_proper_type(t).accept(self)

    def query_types(self, types: list[Type] | tuple[Type, ...]) -> bool:
        """Perform a query for a sequence of types using the strategy to combine the results."""
        # Special-case for lists and tuples to allow mypyc to produce better code.
        if isinstance(types, list):
            if self.strategy == ANY_STRATEGY:
                return any(t.accept(self) for t in types)
            else:
                return all(t.accept(self) for t in types)
        else:
            if self.strategy == ANY_STRATEGY:
                return any(t.accept(self) for t in types)
            else:
                return all(t.accept(self) for t in types)