@@ -4096,28 +4096,15 @@ def process_typevar_parameters(
40964096 if has_values :
40974097 self .fail ("TypeVar cannot have both values and an upper bound" , context )
40984098 return None
4099- try :
4100- # We want to use our custom error message below, so we suppress
4101- # the default error message for invalid types here.
4102- analyzed = self .expr_to_analyzed_type (
4103- param_value , allow_placeholder = True , report_invalid_types = False
4104- )
4105- if analyzed is None :
4106- # Type variables are special: we need to place them in the symbol table
4107- # soon, even if upper bound is not ready yet. Otherwise avoiding
4108- # a "deadlock" in this common pattern would be tricky:
4109- # T = TypeVar('T', bound=Custom[Any])
4110- # class Custom(Generic[T]):
4111- # ...
4112- analyzed = PlaceholderType (None , [], context .line )
4113- upper_bound = get_proper_type (analyzed )
4114- if isinstance (upper_bound , AnyType ) and upper_bound .is_from_error :
4115- self .fail (message_registry .TYPEVAR_BOUND_MUST_BE_TYPE , param_value )
4116- # Note: we do not return 'None' here -- we want to continue
4117- # using the AnyType as the upper bound.
4118- except TypeTranslationError :
4119- self .fail (message_registry .TYPEVAR_BOUND_MUST_BE_TYPE , param_value )
4099+ tv_arg = self .get_typevarlike_argument (param_name , param_value , context )
4100+ if tv_arg is None :
4101+ return None
4102+ upper_bound = tv_arg
4103+ elif param_name == "default" :
4104+ tv_arg = self .get_typevarlike_argument (param_name , param_value , context )
4105+ if tv_arg is None :
41204106 return None
4107+ default = tv_arg
41214108 elif param_name == "values" :
41224109 # Probably using obsolete syntax with values=(...). Explain the current syntax.
41234110 self .fail ('TypeVar "values" argument not supported' , context )
@@ -4145,6 +4132,35 @@ def process_typevar_parameters(
41454132 variance = INVARIANT
41464133 return variance , upper_bound , default
41474134
4135+ def get_typevarlike_argument (
4136+ self , param_name : str , param_value : Expression , context : Context
4137+ ) -> ProperType | None :
4138+ try :
4139+ # We want to use our custom error message below, so we suppress
4140+ # the default error message for invalid types here.
4141+ analyzed = self .expr_to_analyzed_type (
4142+ param_value , allow_placeholder = True , report_invalid_types = False
4143+ )
4144+ if analyzed is None :
4145+ # Type variables are special: we need to place them in the symbol table
4146+ # soon, even if upper bound is not ready yet. Otherwise avoiding
4147+ # a "deadlock" in this common pattern would be tricky:
4148+ # T = TypeVar('T', bound=Custom[Any])
4149+ # class Custom(Generic[T]):
4150+ # ...
4151+ analyzed = PlaceholderType (None , [], context .line )
4152+ typ = get_proper_type (analyzed )
4153+ if isinstance (typ , AnyType ) and typ .is_from_error :
4154+ self .fail (
4155+ message_registry .TYPEVAR_ARG_MUST_BE_TYPE .format (param_name ), param_value
4156+ )
4157+ # Note: we do not return 'None' here -- we want to continue
4158+ # using the AnyType as the upper bound.
4159+ return typ
4160+ except TypeTranslationError :
4161+ self .fail (message_registry .TYPEVAR_ARG_MUST_BE_TYPE .format (param_name ), param_value )
4162+ return None
4163+
41484164 def extract_typevarlike_name (self , s : AssignmentStmt , call : CallExpr ) -> str | None :
41494165 if not call :
41504166 return None
@@ -4177,13 +4193,27 @@ def process_paramspec_declaration(self, s: AssignmentStmt) -> bool:
41774193 if name is None :
41784194 return False
41794195
4180- # ParamSpec is different from a regular TypeVar:
4181- # arguments are not semantically valid. But, allowed in runtime.
4182- # So, we need to warn users about possible invalid usage.
4183- if len (call .args ) > 1 :
4184- self .fail ("Only the first argument to ParamSpec has defined semantics" , s )
4196+ n_values = call .arg_kinds [1 :].count (ARG_POS )
4197+ if n_values != 0 :
4198+ self .fail ("Only the first positional argument to ParamSpec has defined semantics" , s )
41854199
41864200 default : Type = AnyType (TypeOfAny .from_omitted_generics )
4201+ for param_value , param_name in zip (
4202+ call .args [1 + n_values :], call .arg_names [1 + n_values :]
4203+ ):
4204+ if param_name == "default" :
4205+ tv_arg = self .get_typevarlike_argument (param_name , param_value , s )
4206+ if tv_arg is None :
4207+ return False
4208+ default = tv_arg
4209+ else :
4210+ # ParamSpec is different from a regular TypeVar:
4211+ # arguments are not semantically valid. But, allowed in runtime.
4212+ # So, we need to warn users about possible invalid usage.
4213+ self .fail (
4214+ "The variance and bound arguments to ParamSpec do not have defined semantics yet" ,
4215+ s ,
4216+ )
41874217
41884218 # PEP 612 reserves the right to define bound, covariant and contravariant arguments to
41894219 # ParamSpec in a later PEP. If and when that happens, we should do something
@@ -4211,10 +4241,31 @@ def process_typevartuple_declaration(self, s: AssignmentStmt) -> bool:
42114241 if not call :
42124242 return False
42134243
4214- if len (call .args ) > 1 :
4215- self .fail ("Only the first argument to TypeVarTuple has defined semantics" , s )
4244+ n_values = call .arg_kinds [1 :].count (ARG_POS )
4245+ if n_values != 0 :
4246+ self .fail (
4247+ "Only the first positional argument to TypeVarTuple has defined semantics" , s
4248+ )
42164249
42174250 default : Type = AnyType (TypeOfAny .from_omitted_generics )
4251+ for param_value , param_name in zip (
4252+ call .args [1 + n_values :], call .arg_names [1 + n_values :]
4253+ ):
4254+ if param_name == "default" :
4255+ tv_arg = self .get_typevarlike_argument (param_name , param_value , s )
4256+ if tv_arg is None :
4257+ return False
4258+ default = tv_arg
4259+ if not isinstance (default , UnpackType ):
4260+ self .fail (
4261+ "The default argument to TypeVarTuple must be an Unpacked tuple" , default
4262+ )
4263+ return False
4264+ else :
4265+ self .fail (
4266+ "The variance and bound arguments to TypeVarTuple do not have defined semantics yet" ,
4267+ s ,
4268+ )
42184269
42194270 if not self .incomplete_feature_enabled (TYPE_VAR_TUPLE , s ):
42204271 return False
0 commit comments