| from __future__ import annotations |
| |
| from mypy.erasetype import erase_typevars |
| from mypy.nodes import TypeInfo |
| from mypy.types import ( |
| Instance, |
| ParamSpecType, |
| ProperType, |
| TupleType, |
| Type, |
| TypeOfAny, |
| TypeVarLikeType, |
| TypeVarTupleType, |
| TypeVarType, |
| UnpackType, |
| ) |
| from mypy.typevartuples import erased_vars |
| |
| |
| def fill_typevars(typ: TypeInfo) -> Instance | TupleType: |
| """For a non-generic type, return instance type representing the type. |
| |
| For a generic G type with parameters T1, .., Tn, return G[T1, ..., Tn]. |
| """ |
| tvs: list[Type] = [] |
| # TODO: why do we need to keep both typ.type_vars and typ.defn.type_vars? |
| for i in range(len(typ.defn.type_vars)): |
| tv: TypeVarLikeType | UnpackType = typ.defn.type_vars[i] |
| # Change the line number |
| if isinstance(tv, TypeVarType): |
| tv = tv.copy_modified(line=-1, column=-1) |
| elif isinstance(tv, TypeVarTupleType): |
| tv = UnpackType( |
| TypeVarTupleType( |
| tv.name, |
| tv.fullname, |
| tv.id, |
| tv.upper_bound, |
| tv.tuple_fallback, |
| tv.default, |
| line=-1, |
| column=-1, |
| ) |
| ) |
| else: |
| assert isinstance(tv, ParamSpecType) |
| tv = ParamSpecType( |
| tv.name, |
| tv.fullname, |
| tv.id, |
| tv.flavor, |
| tv.upper_bound, |
| tv.default, |
| line=-1, |
| column=-1, |
| ) |
| tvs.append(tv) |
| inst = Instance(typ, tvs) |
| # TODO: do we need to also handle typeddict_type here and below? |
| if typ.tuple_type is None: |
| return inst |
| return typ.tuple_type.copy_modified(fallback=inst) |
| |
| |
| def fill_typevars_with_any(typ: TypeInfo) -> Instance | TupleType: |
| """Apply a correct number of Any's as type arguments to a type.""" |
| inst = Instance(typ, erased_vars(typ.defn.type_vars, TypeOfAny.special_form)) |
| if typ.tuple_type is None: |
| return inst |
| erased_tuple_type = erase_typevars(typ.tuple_type, {tv.id for tv in typ.defn.type_vars}) |
| assert isinstance(erased_tuple_type, ProperType) |
| if isinstance(erased_tuple_type, TupleType): |
| return typ.tuple_type.copy_modified(fallback=inst) |
| return inst |
| |
| |
| def has_no_typevars(typ: Type) -> bool: |
| # We test if a type contains type variables by erasing all type variables |
| # and comparing the result to the original type. We use comparison by equality that |
| # in turn uses `__eq__` defined for types. Note: we can't use `is_same_type` because |
| # it is not safe with unresolved forward references, while this function may be called |
| # before forward references resolution patch pass. Note also that it is not safe to use |
| # `is` comparison because `erase_typevars` doesn't preserve type identity. |
| return typ == erase_typevars(typ) |