@@ -248,6 +248,8 @@ def __init__(
248248 self .allow_final = allow_final
249249 # Are we in a context where ParamSpec literals are allowed?
250250 self .allow_param_spec_literals = allow_param_spec_literals
251+ # Are we in a context where ParamSpec values are accepted directly?
252+ self .allow_param_spec = False
251253 # Are we in context where literal "..." specifically is allowed?
252254 self .allow_ellipsis = False
253255 # Should we report an error whenever we encounter a RawExpressionType outside
@@ -461,6 +463,22 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
461463 special = self .try_analyze_special_unbound_type (t , fullname )
462464 if special is not None :
463465 return special
466+ if node .fullname in CONCATENATE_TYPE_NAMES :
467+ # Concatenate is an operator, no need for a proper type. Some callers analyze
468+ # annotations directly via accept(), so validate direct invalid uses here.
469+ result = self .apply_concatenate_operator (t )
470+ if not (self .allow_param_spec or self .allow_param_spec_literals ) and (
471+ isinstance (result , Parameters )
472+ or (
473+ isinstance (result , ParamSpecType )
474+ and result .flavor == ParamSpecFlavor .BARE
475+ and result .prefix .arg_types
476+ )
477+ ):
478+ self .fail ("Invalid location for Concatenate" , t , code = codes .VALID_TYPE )
479+ self .note ("You can use Concatenate as the first argument to Callable" , t )
480+ return AnyType (TypeOfAny .from_error )
481+ return result
464482 if isinstance (node , TypeAlias ):
465483 self .aliases_used .add (fullname )
466484 an_args = self .anal_array (
@@ -508,10 +526,6 @@ def visit_unbound_type_nonoptional(self, t: UnboundType, defining_literal: bool)
508526 return self .analyze_type_with_type_info (node , t .args , t , t .empty_tuple_index )
509527 elif node .fullname in TYPE_ALIAS_NAMES :
510528 return AnyType (TypeOfAny .special_form )
511- # Concatenate is an operator, no need for a proper type
512- elif node .fullname in CONCATENATE_TYPE_NAMES :
513- # We check the return type further up the stack for valid use locations
514- return self .apply_concatenate_operator (t )
515529 else :
516530 return self .analyze_unbound_type_without_type_info (t , sym , defining_literal )
517531 else : # sym is None
@@ -1918,6 +1932,8 @@ def anal_type(
19181932 self .allow_final = allow_final
19191933 old_allow_ellipsis = self .allow_ellipsis
19201934 self .allow_ellipsis = allow_ellipsis
1935+ old_allow_param_spec = self .allow_param_spec
1936+ self .allow_param_spec = allow_param_spec
19211937 old_allow_unpack = self .allow_unpack
19221938 self .allow_unpack = allow_unpack
19231939 try :
@@ -1927,6 +1943,7 @@ def anal_type(
19271943 self .nesting_level -= 1
19281944 self .allow_typed_dict_special_forms = old_allow_typed_dict_special_forms
19291945 self .allow_ellipsis = old_allow_ellipsis
1946+ self .allow_param_spec = old_allow_param_spec
19301947 self .allow_unpack = old_allow_unpack
19311948 if (
19321949 not allow_param_spec
0 commit comments