| """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) |