11from __future__ import annotations
22
3+ from collections .abc import Callable
4+ from typing_extensions import TypeAlias as _TypeAlias
5+
36from mypy .nodes import (
7+ Context ,
48 ParamSpecExpr ,
59 SymbolTableNode ,
610 TypeVarExpr ,
711 TypeVarLikeExpr ,
812 TypeVarTupleExpr ,
913)
1014from mypy .types import (
15+ AnyType ,
1116 ParamSpecFlavor ,
1217 ParamSpecType ,
18+ TrivialSyntheticTypeTranslator ,
19+ Type ,
20+ TypeAliasType ,
21+ TypeOfAny ,
1322 TypeVarId ,
1423 TypeVarLikeType ,
1524 TypeVarTupleType ,
1625 TypeVarType ,
1726)
18- from mypy .typetraverser import TypeTraverserVisitor
19-
20-
21- class TypeVarLikeNamespaceSetter (TypeTraverserVisitor ):
22- """Set namespace for all TypeVarLikeTypes types."""
2327
24- def __init__ (self , namespace : str ) -> None :
25- self .namespace = namespace
28+ FailFunc : _TypeAlias = Callable [[str , Context ], None ]
2629
27- def visit_type_var (self , t : TypeVarType ) -> None :
28- t .id .namespace = self .namespace
29- super ().visit_type_var (t )
3030
31- def visit_param_spec (self , t : ParamSpecType ) -> None :
32- t .id .namespace = self .namespace
33- return super ().visit_param_spec (t )
31+ class TypeVarLikeDefaultFixer (TrivialSyntheticTypeTranslator ):
32+ """Set namespace for all TypeVarLikeTypes types."""
3433
35- def visit_type_var_tuple (self , t : TypeVarTupleType ) -> None :
36- t .id .namespace = self .namespace
37- super ().visit_type_var_tuple (t )
34+ def __init__ (
35+ self ,
36+ scope : TypeVarLikeScope ,
37+ fail_func : FailFunc ,
38+ source_tv : TypeVarLikeExpr ,
39+ context : Context ,
40+ ) -> None :
41+ self .scope = scope
42+ self .fail_func = fail_func
43+ self .source_tv = source_tv
44+ self .context = context
45+ super ().__init__ ()
46+
47+ def visit_type_var (self , t : TypeVarType ) -> Type :
48+ existing = self .scope .get_binding (t .fullname )
49+ if existing is None :
50+ self ._report_unbound_tvar (t )
51+ return AnyType (TypeOfAny .from_error )
52+ return existing
53+
54+ def visit_param_spec (self , t : ParamSpecType ) -> Type :
55+ existing = self .scope .get_binding (t .fullname )
56+ if existing is None :
57+ self ._report_unbound_tvar (t )
58+ return AnyType (TypeOfAny .from_error )
59+ return existing
60+
61+ def visit_type_var_tuple (self , t : TypeVarTupleType ) -> Type :
62+ existing = self .scope .get_binding (t .fullname )
63+ if existing is None :
64+ self ._report_unbound_tvar (t )
65+ return AnyType (TypeOfAny .from_error )
66+ return existing
67+
68+ def visit_type_alias_type (self , t : TypeAliasType ) -> Type :
69+ return t
70+
71+ def _report_unbound_tvar (self , tvar : TypeVarLikeType ) -> None :
72+ self .fail_func (
73+ f"Type variable { tvar .name } referenced in the default"
74+ f" of { self .source_tv .name } is unbound" ,
75+ self .context ,
76+ )
3877
3978
4079class TypeVarLikeScope :
@@ -98,15 +137,25 @@ def new_unique_func_id(self) -> TypeVarId:
98137 self .func_id -= 1
99138 return TypeVarId (self .func_id )
100139
101- def bind_new (self , name : str , tvar_expr : TypeVarLikeExpr ) -> TypeVarLikeType :
140+ def bind_new (
141+ self , name : str , tvar_expr : TypeVarLikeExpr , fail_func : FailFunc , context : Context
142+ ) -> TypeVarLikeType :
102143 if self .is_class_scope :
103144 self .class_id += 1
104145 i = self .class_id
105146 else :
106147 self .func_id -= 1
107148 i = self .func_id
108149 namespace = self .namespace
109- tvar_expr .default .accept (TypeVarLikeNamespaceSetter (namespace ))
150+
151+ # Defaults may reference other type variables. That is only valid when the
152+ # referenced variable is already in scope (textually precedes the definition we're
153+ # processing now).
154+ default = tvar_expr .default .accept (
155+ TypeVarLikeDefaultFixer (
156+ self , fail_func = fail_func , source_tv = tvar_expr , context = context
157+ )
158+ )
110159
111160 if isinstance (tvar_expr , TypeVarExpr ):
112161 tvar_def : TypeVarLikeType = TypeVarType (
@@ -115,7 +164,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
115164 id = TypeVarId (i , namespace = namespace ),
116165 values = tvar_expr .values ,
117166 upper_bound = tvar_expr .upper_bound ,
118- default = tvar_expr . default ,
167+ default = default ,
119168 variance = tvar_expr .variance ,
120169 line = tvar_expr .line ,
121170 column = tvar_expr .column ,
@@ -127,7 +176,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
127176 id = TypeVarId (i , namespace = namespace ),
128177 flavor = ParamSpecFlavor .BARE ,
129178 upper_bound = tvar_expr .upper_bound ,
130- default = tvar_expr . default ,
179+ default = default ,
131180 line = tvar_expr .line ,
132181 column = tvar_expr .column ,
133182 )
@@ -138,7 +187,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
138187 id = TypeVarId (i , namespace = namespace ),
139188 upper_bound = tvar_expr .upper_bound ,
140189 tuple_fallback = tvar_expr .tuple_fallback ,
141- default = tvar_expr . default ,
190+ default = default ,
142191 line = tvar_expr .line ,
143192 column = tvar_expr .column ,
144193 )
0 commit comments