I agree the problem of the scope of type variables is thorny. I worry that thinking about it too much in terms of "fewest changes to the compiler" might over-constrain the solution space though.
I re-read some earlier messages in this thread. For a while Eric seemed in favor of putting typevars in a new scope, especially after hitting upon the idea of lambda lifting, but eventually soured on it for several reasons: compiler complexity, walrus operators in the inner scope, and worries about runtime overhead and debugger compatibility.
**Compiler complexity.**
This is the least worrisome to me. If it's the right thing for the user, we should do it even if it's complex to implement. (This is often a tenet of Python these days, despite what you may read in the Zen of Python.) The notion that occurrences of T are translated to an expression that at runtime constructs a new instance of some dummy type doesn't seem easy to explain to users, and I worry about 3rd party tools that do runtime introspection of annotations (not just runtime type checkers).
**Walrus in the inner scope.**
There are only two types of places where a walrus could occur: type annotations (for arguments and return value) and default values. I don't think a walrus in a type annotation would be useful (and I believe most static type checkers don't allow them, since annotations are required to follow a simpler syntax), so I assume this is about defaults. Example:
```
def foo[T](arg: T = (x := f())) -> T: ...
```
Using the lambda lifting approach we could compute the default in the outer scope and pass it into the helper:
```
def __foo(T, __arg):
def foo(arg: T = __arg) -> T: ...
return foo
foo = __foo(TypeVar("T"), (x := f()))
```
Now, this means we can't use a walrus in the type annotation, but I don't think that's a useful pattern. Certainly static type checkers don't allow it. It's likely that someone, somewhere is using a walrus in a type annotation that's only for consumption by some dynamic tool, but that (in my expectation highly uncommon) scenario could easily be fixed by moving the walrus out of the annotation into an assignment statement preceding the function definition:
```
# Old, would not work with lambda lifting:
def foo(arg: X := Y): ...
# New, also works in 3.11 and before:
TypeOfArg = (X := Y)
def foo(arg: TypeOfArg): ...
```
So I think it's fine to declare any use of a walrus in an annotation illegal. Or perhaps only when occurring in a class -- that's s similar constraint as PEP 572 imposes on using a walrus in a comprehension:
```
class C:
a = [x := i for i in range(3)]
```
This gives the following error:
```
SyntaxError: assignment expression within a comprehension cannot be used in a class body
```
**Runtime overhead**
I presume this is a concern about the cost of the extra function definition and call used by lambda lifting. This would be the biggest concern for generic functions (class construction is already relatively slow). It would turn every (generic) function definition into two function definitions plus a call. A highly unscientific experiment using `timeit` tells me that on my computer the simplest definition costs 65 ns and the simplest call costs 35 ns. OTOH, calling `TypeVar("T")` costs 850 ns. So what are we even talking about? At best this concern is premature.
**Debugger compatibility**
I don't want to speculate about this, but I note that 3.11 broke compatibility for debuggers and we are addressing this (for the long term) by adding better APIs for debuggers to do what they want to do.
**Other stuff**
In a private message Eric mentioned to me that his current prototype generates bytecode to import e.g. TypeVar from the typing module. A production-quality implementation would have to reimplement TypeVar, TypeVarTuple, ParamSpec and Generic in C. That's a fair amount of work, but I'm confident that we can do it if the PEP is accepted. As long as it's a proof-of-concept prototype I don't think it will matter.
**Final words**
Despite several hurdles, I still favor the introduction of an actual new scope holding the type variables belonging to a given generic class, function or type alias, over Eric's (indubitably clever) current hack.
--Guido
PS. Regarding the syntax to indicate subclass constraints, I am fine with ":".