From f66199f087f4b94b5d3f9c05fa9a438b251b3ccb Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Thu, 25 May 2023 08:30:37 -0700 Subject: [PATCH] Propagate TypeVarType column in TypeAnalyser (#15304) Also use keyword arguments + copy_modified for this in many places --- mypy/checkexpr.py | 12 ++++++------ mypy/copytype.py | 10 +--------- mypy/plugins/attrs.py | 6 +++++- mypy/plugins/dataclasses.py | 6 +++++- mypy/semanal.py | 4 +++- mypy/semanal_namedtuple.py | 10 +++++----- mypy/tvar_scope.py | 6 +++--- mypy/typeanal.py | 26 +++++++++----------------- mypy/types.py | 28 ++++++++++++++-------------- mypy/typevars.py | 11 +---------- 10 files changed, 52 insertions(+), 67 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 13373474786b2..e58ddfc0799fe 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -4189,7 +4189,7 @@ def check_lst_expr(self, e: ListExpr | SetExpr | TupleExpr, fullname: str, tag: # Used for list and set expressions, as well as for tuples # containing star expressions that don't refer to a # Tuple. (Note: "lst" stands for list-set-tuple. :-) - tv = TypeVarType("T", "T", -1, [], self.object_type()) + tv = TypeVarType("T", "T", id=-1, values=[], upper_bound=self.object_type()) constructor = CallableType( [tv], [nodes.ARG_STAR], @@ -4357,8 +4357,8 @@ def visit_dict_expr(self, e: DictExpr) -> Type: return dt # Define type variables (used in constructors below). - kt = TypeVarType("KT", "KT", -1, [], self.object_type()) - vt = TypeVarType("VT", "VT", -2, [], self.object_type()) + kt = TypeVarType("KT", "KT", id=-1, values=[], upper_bound=self.object_type()) + vt = TypeVarType("VT", "VT", id=-2, values=[], upper_bound=self.object_type()) # Collect function arguments, watching out for **expr. args: list[Expression] = [] @@ -4722,7 +4722,7 @@ def check_generator_or_comprehension( # Infer the type of the list comprehension by using a synthetic generic # callable type. - tv = TypeVarType("T", "T", -1, [], self.object_type()) + tv = TypeVarType("T", "T", id=-1, values=[], upper_bound=self.object_type()) tv_list: list[Type] = [tv] constructor = CallableType( tv_list, @@ -4742,8 +4742,8 @@ def visit_dictionary_comprehension(self, e: DictionaryComprehension) -> Type: # Infer the type of the list comprehension by using a synthetic generic # callable type. - ktdef = TypeVarType("KT", "KT", -1, [], self.object_type()) - vtdef = TypeVarType("VT", "VT", -2, [], self.object_type()) + ktdef = TypeVarType("KT", "KT", id=-1, values=[], upper_bound=self.object_type()) + vtdef = TypeVarType("VT", "VT", id=-2, values=[], upper_bound=self.object_type()) constructor = CallableType( [ktdef, vtdef], [nodes.ARG_POS, nodes.ARG_POS], diff --git a/mypy/copytype.py b/mypy/copytype.py index 6024e527705bb..46c307f3dd84d 100644 --- a/mypy/copytype.py +++ b/mypy/copytype.py @@ -69,15 +69,7 @@ def visit_instance(self, t: Instance) -> ProperType: return self.copy_common(t, dup) def visit_type_var(self, t: TypeVarType) -> ProperType: - dup = TypeVarType( - t.name, - t.fullname, - t.id, - values=t.values, - upper_bound=t.upper_bound, - variance=t.variance, - ) - return self.copy_common(t, dup) + return self.copy_common(t, t.copy_modified()) def visit_param_spec(self, t: ParamSpecType) -> ProperType: dup = ParamSpecType(t.name, t.fullname, t.id, t.flavor, t.upper_bound, prefix=t.prefix) diff --git a/mypy/plugins/attrs.py b/mypy/plugins/attrs.py index 4c96003ca326f..bd09eeb0264a2 100644 --- a/mypy/plugins/attrs.py +++ b/mypy/plugins/attrs.py @@ -767,7 +767,11 @@ def _add_order(ctx: mypy.plugin.ClassDefContext, adder: MethodAdder) -> None: # def __lt__(self: AT, other: AT) -> bool # This way comparisons with subclasses will work correctly. tvd = TypeVarType( - SELF_TVAR_NAME, ctx.cls.info.fullname + "." + SELF_TVAR_NAME, -1, [], object_type + SELF_TVAR_NAME, + ctx.cls.info.fullname + "." + SELF_TVAR_NAME, + id=-1, + values=[], + upper_bound=object_type, ) self_tvar_expr = TypeVarExpr( SELF_TVAR_NAME, ctx.cls.info.fullname + "." + SELF_TVAR_NAME, [], object_type diff --git a/mypy/plugins/dataclasses.py b/mypy/plugins/dataclasses.py index a577784217aa9..0e195b9668d80 100644 --- a/mypy/plugins/dataclasses.py +++ b/mypy/plugins/dataclasses.py @@ -268,7 +268,11 @@ def transform(self) -> bool: # the self type. obj_type = self._api.named_type("builtins.object") order_tvar_def = TypeVarType( - SELF_TVAR_NAME, info.fullname + "." + SELF_TVAR_NAME, -1, [], obj_type + SELF_TVAR_NAME, + info.fullname + "." + SELF_TVAR_NAME, + id=-1, + values=[], + upper_bound=obj_type, ) order_return_type = self._api.named_type("builtins.bool") order_args = [ diff --git a/mypy/semanal.py b/mypy/semanal.py index 68092e6c3a677..6bc8ff55d4529 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -1075,7 +1075,9 @@ def setup_self_type(self) -> None: ) else: return - info.self_type = TypeVarType("Self", f"{info.fullname}.Self", 0, [], fill_typevars(info)) + info.self_type = TypeVarType( + "Self", f"{info.fullname}.Self", id=0, values=[], upper_bound=fill_typevars(info) + ) def visit_overloaded_func_def(self, defn: OverloadedFuncDef) -> None: self.statement = defn diff --git a/mypy/semanal_namedtuple.py b/mypy/semanal_namedtuple.py index a9f12ceae5c2c..ab5a0f993b6a0 100644 --- a/mypy/semanal_namedtuple.py +++ b/mypy/semanal_namedtuple.py @@ -544,11 +544,11 @@ def add_field( assert info.tuple_type is not None # Set by update_tuple_type() above. tvd = TypeVarType( - SELF_TVAR_NAME, - info.fullname + "." + SELF_TVAR_NAME, - self.api.tvar_scope.new_unique_func_id(), - [], - info.tuple_type, + name=SELF_TVAR_NAME, + fullname=info.fullname + "." + SELF_TVAR_NAME, + id=self.api.tvar_scope.new_unique_func_id(), + values=[], + upper_bound=info.tuple_type, ) selftype = tvd diff --git a/mypy/tvar_scope.py b/mypy/tvar_scope.py index 9b432d8e68ec5..1716df89aa390 100644 --- a/mypy/tvar_scope.py +++ b/mypy/tvar_scope.py @@ -90,9 +90,9 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType: namespace = "" if isinstance(tvar_expr, TypeVarExpr): tvar_def: TypeVarLikeType = TypeVarType( - name, - tvar_expr.fullname, - TypeVarId(i, namespace=namespace), + name=name, + fullname=tvar_expr.fullname, + id=TypeVarId(i, namespace=namespace), values=tvar_expr.values, upper_bound=tvar_expr.upper_bound, variance=tvar_expr.variance, diff --git a/mypy/typeanal.py b/mypy/typeanal.py index 95acb71b45d2e..b5e7e9e7a3f98 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -343,16 +343,7 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool) f'Type variable "{t.name}" used with arguments', t, code=codes.VALID_TYPE ) # Change the line number - return TypeVarType( - tvar_def.name, - tvar_def.fullname, - tvar_def.id, - tvar_def.values, - tvar_def.upper_bound, - tvar_def.variance, - line=t.line, - column=t.column, - ) + return tvar_def.copy_modified(line=t.line, column=t.column) if isinstance(sym.node, TypeVarTupleExpr) and ( tvar_def is not None and self.defining_alias @@ -1553,13 +1544,14 @@ def anal_type(self, t: Type, nested: bool = True, *, allow_param_spec: bool = Fa def anal_var_def(self, var_def: TypeVarLikeType) -> TypeVarLikeType: if isinstance(var_def, TypeVarType): return TypeVarType( - var_def.name, - var_def.fullname, - var_def.id.raw_id, - self.anal_array(var_def.values), - var_def.upper_bound.accept(self), - var_def.variance, - var_def.line, + name=var_def.name, + fullname=var_def.fullname, + id=var_def.id.raw_id, + values=self.anal_array(var_def.values), + upper_bound=var_def.upper_bound.accept(self), + variance=var_def.variance, + line=var_def.line, + column=var_def.column, ) else: return var_def diff --git a/mypy/types.py b/mypy/types.py index 0e1374466341a..ab4816bac6fda 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -596,14 +596,14 @@ def copy_modified( column: int = _dummy_int, ) -> TypeVarType: return TypeVarType( - self.name, - self.fullname, - self.id if id is _dummy else id, - self.values if values is _dummy else values, - self.upper_bound if upper_bound is _dummy else upper_bound, - self.variance, - self.line if line == _dummy_int else line, - self.column if column == _dummy_int else column, + name=self.name, + fullname=self.fullname, + id=self.id if id is _dummy else id, + values=self.values if values is _dummy else values, + upper_bound=self.upper_bound if upper_bound is _dummy else upper_bound, + variance=self.variance, + line=self.line if line == _dummy_int else line, + column=self.column if column == _dummy_int else column, ) def accept(self, visitor: TypeVisitor[T]) -> T: @@ -638,12 +638,12 @@ def serialize(self) -> JsonDict: def deserialize(cls, data: JsonDict) -> TypeVarType: assert data[".class"] == "TypeVarType" return TypeVarType( - data["name"], - data["fullname"], - TypeVarId(data["id"], namespace=data["namespace"]), - [deserialize_type(v) for v in data["values"]], - deserialize_type(data["upper_bound"]), - data["variance"], + name=data["name"], + fullname=data["fullname"], + id=TypeVarId(data["id"], namespace=data["namespace"]), + values=[deserialize_type(v) for v in data["values"]], + upper_bound=deserialize_type(data["upper_bound"]), + variance=data["variance"], ) diff --git a/mypy/typevars.py b/mypy/typevars.py index 69c2eed37fa4f..e43afe4f13748 100644 --- a/mypy/typevars.py +++ b/mypy/typevars.py @@ -27,16 +27,7 @@ def fill_typevars(typ: TypeInfo) -> Instance | TupleType: tv: TypeVarLikeType | UnpackType = typ.defn.type_vars[i] # Change the line number if isinstance(tv, TypeVarType): - tv = TypeVarType( - tv.name, - tv.fullname, - tv.id, - tv.values, - tv.upper_bound, - tv.variance, - line=-1, - column=-1, - ) + tv = tv.copy_modified(line=-1, column=-1) elif isinstance(tv, TypeVarTupleType): tv = UnpackType( TypeVarTupleType(