bpo-44791: Fix substitution of ParamSpec in Concatenate with different parameter expressions (GH-27518)


* Substitution with a list of types returns now a tuple of types.
* Substitution with Concatenate returns now a Concatenate with
  concatenated lists of arguments.
* Substitution with Ellipsis is not supported.
(cherry picked from commit ecfacc362dd7fef7715dcd94f2e2ca6c622ef115)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
diff --git a/Lib/typing.py b/Lib/typing.py
index 705331a..aca3f7a 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -598,7 +598,7 @@ def Concatenate(self, parameters):
         raise TypeError("The last parameter to Concatenate should be a "
                         "ParamSpec variable.")
     msg = "Concatenate[arg, ...]: each arg must be a type."
-    parameters = tuple(_type_check(p, msg) for p in parameters)
+    parameters = (*(_type_check(p, msg) for p in parameters[:-1]), parameters[-1])
     return _ConcatenateGenericAlias(self, parameters)
 
 
@@ -1274,6 +1274,16 @@ def __init__(self, *args, **kwargs):
                          _typevar_types=(TypeVar, ParamSpec),
                          _paramspec_tvars=True)
 
+    def copy_with(self, params):
+        if isinstance(params[-1], (list, tuple)):
+            return (*params[:-1], *params[-1])
+        if isinstance(params[-1], _ConcatenateGenericAlias):
+            params = (*params[:-1], *params[-1].__args__)
+        elif not isinstance(params[-1], ParamSpec):
+            raise TypeError("The last parameter to Concatenate should be a "
+                            "ParamSpec variable.")
+        return super().copy_with(params)
+
 
 class Generic:
     """Abstract base class for generic types.