3939 get_proper_types ,
4040 split_with_prefix_and_suffix ,
4141)
42+ from mypy .typevartuples import erased_vars
4243
4344
4445class TypeArgumentAnalyzer (MixedTraverserVisitor ):
@@ -89,7 +90,14 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None:
8990 return
9091 self .seen_aliases .add (t )
9192 assert t .alias is not None , f"Unfixed type alias { t .type_ref } "
92- is_error = self .validate_args (t .alias .name , tuple (t .args ), t .alias .alias_tvars , t )
93+ is_error , is_invalid = self .validate_args (
94+ t .alias .name , tuple (t .args ), t .alias .alias_tvars , t
95+ )
96+ if is_invalid :
97+ # If there is an arity error (e.g. non-Parameters used for ParamSpec etc.),
98+ # then it is safer to erase the arguments completely, to avoid crashes later.
99+ # TODO: can we move this logic to typeanal.py?
100+ t .args = erased_vars (t .alias .alias_tvars , TypeOfAny .from_error )
93101 if not is_error :
94102 # If there was already an error for the alias itself, there is no point in checking
95103 # the expansion, most likely it will result in the same kind of error.
@@ -113,7 +121,9 @@ def visit_instance(self, t: Instance) -> None:
113121 info = t .type
114122 if isinstance (info , FakeInfo ):
115123 return # https://github.com/python/mypy/issues/11079
116- self .validate_args (info .name , t .args , info .defn .type_vars , t )
124+ _ , is_invalid = self .validate_args (info .name , t .args , info .defn .type_vars , t )
125+ if is_invalid :
126+ t .args = tuple (erased_vars (info .defn .type_vars , TypeOfAny .from_error ))
117127 if t .type .fullname == "builtins.tuple" and len (t .args ) == 1 :
118128 # Normalize Tuple[*Tuple[X, ...], ...] -> Tuple[X, ...]
119129 arg = t .args [0 ]
@@ -125,7 +135,7 @@ def visit_instance(self, t: Instance) -> None:
125135
126136 def validate_args (
127137 self , name : str , args : tuple [Type , ...], type_vars : list [TypeVarLikeType ], ctx : Context
128- ) -> bool :
138+ ) -> tuple [ bool , bool ] :
129139 if any (isinstance (v , TypeVarTupleType ) for v in type_vars ):
130140 prefix = next (i for (i , v ) in enumerate (type_vars ) if isinstance (v , TypeVarTupleType ))
131141 tvt = type_vars [prefix ]
@@ -136,10 +146,11 @@ def validate_args(
136146 args = start + (TupleType (list (middle ), tvt .tuple_fallback ),) + end
137147
138148 is_error = False
149+ is_invalid = False
139150 for (i , arg ), tvar in zip (enumerate (args ), type_vars ):
140151 if isinstance (tvar , TypeVarType ):
141152 if isinstance (arg , ParamSpecType ):
142- is_error = True
153+ is_invalid = True
143154 self .fail (
144155 INVALID_PARAM_SPEC_LOCATION .format (format_type (arg , self .options )),
145156 ctx ,
@@ -152,7 +163,7 @@ def validate_args(
152163 )
153164 continue
154165 if isinstance (arg , Parameters ):
155- is_error = True
166+ is_invalid = True
156167 self .fail (
157168 f"Cannot use { format_type (arg , self .options )} for regular type variable,"
158169 " only for ParamSpec" ,
@@ -205,13 +216,16 @@ def validate_args(
205216 if not isinstance (
206217 get_proper_type (arg ), (ParamSpecType , Parameters , AnyType , UnboundType )
207218 ):
219+ is_invalid = True
208220 self .fail (
209221 "Can only replace ParamSpec with a parameter types list or"
210222 f" another ParamSpec, got { format_type (arg , self .options )} " ,
211223 ctx ,
212224 code = codes .VALID_TYPE ,
213225 )
214- return is_error
226+ if is_invalid :
227+ is_error = True
228+ return is_error , is_invalid
215229
216230 def visit_unpack_type (self , typ : UnpackType ) -> None :
217231 super ().visit_unpack_type (typ )
0 commit comments