11from __future__ import annotations
22
3+ from mypy .messages import MessageBuilder
34from mypy .nodes import (
5+ Context ,
46 ParamSpecExpr ,
57 SymbolTableNode ,
68 TypeVarExpr ,
79 TypeVarLikeExpr ,
810 TypeVarTupleExpr ,
911)
1012from mypy .types import (
13+ AnyType ,
1114 ParamSpecFlavor ,
1215 ParamSpecType ,
16+ TrivialSyntheticTypeTranslator ,
17+ Type ,
18+ TypeAliasType ,
19+ TypeOfAny ,
1320 TypeVarId ,
1421 TypeVarLikeType ,
1522 TypeVarTupleType ,
1623 TypeVarType ,
1724)
18- from mypy .typetraverser import TypeTraverserVisitor
1925
2026
21- class TypeVarLikeNamespaceSetter ( TypeTraverserVisitor ):
27+ class TypeVarLikeDefaultFixer ( TrivialSyntheticTypeTranslator ):
2228 """Set namespace for all TypeVarLikeTypes types."""
2329
24- def __init__ (self , namespace : str ) -> None :
25- self .namespace = namespace
26-
27- def visit_type_var (self , t : TypeVarType ) -> None :
28- t .id .namespace = self .namespace
29- super ().visit_type_var (t )
30-
31- def visit_param_spec (self , t : ParamSpecType ) -> None :
32- t .id .namespace = self .namespace
33- return super ().visit_param_spec (t )
34-
35- def visit_type_var_tuple (self , t : TypeVarTupleType ) -> None :
36- t .id .namespace = self .namespace
37- super ().visit_type_var_tuple (t )
30+ def __init__ (
31+ self , scope : TypeVarLikeScope , source_tv : TypeVarLikeExpr , context : Context
32+ ) -> None :
33+ self .scope = scope
34+ self .source_tv = source_tv
35+ self .context = context
36+ super ().__init__ ()
37+
38+ def visit_type_var (self , t : TypeVarType ) -> Type :
39+ existing = self .scope .get_binding (t .fullname )
40+ if existing is None :
41+ self ._report_unbound_tvar (t )
42+ return AnyType (TypeOfAny .from_error )
43+ return existing
44+
45+ def visit_param_spec (self , t : ParamSpecType ) -> Type :
46+ existing = self .scope .get_binding (t .fullname )
47+ if existing is None :
48+ self ._report_unbound_tvar (t )
49+ return AnyType (TypeOfAny .from_error )
50+ return existing
51+
52+ def visit_type_var_tuple (self , t : TypeVarTupleType ) -> Type :
53+ existing = self .scope .get_binding (t .fullname )
54+ if existing is None :
55+ self ._report_unbound_tvar (t )
56+ return AnyType (TypeOfAny .from_error )
57+ return existing
58+
59+ def visit_type_alias_type (self , t : TypeAliasType ) -> Type :
60+ return t
61+
62+ def _report_unbound_tvar (self , tvar : TypeVarLikeType ) -> None :
63+ self .scope .msg .fail (
64+ f"Type variable { tvar .name } referenced in the default"
65+ f" of { self .source_tv .name } is unbound" ,
66+ self .context ,
67+ )
3868
3969
4070class TypeVarLikeScope :
@@ -49,6 +79,8 @@ def __init__(
4979 is_class_scope : bool = False ,
5080 prohibited : TypeVarLikeScope | None = None ,
5181 namespace : str = "" ,
82+ * ,
83+ msg : MessageBuilder ,
5284 ) -> None :
5385 """Initializer for TypeVarLikeScope
5486
@@ -65,6 +97,7 @@ def __init__(
6597 self .is_class_scope = is_class_scope
6698 self .prohibited = prohibited
6799 self .namespace = namespace
100+ self .msg = msg
68101 if parent is not None :
69102 self .func_id = parent .func_id
70103 self .class_id = parent .class_id
@@ -87,26 +120,34 @@ def allow_binding(self, fullname: str) -> bool:
87120
88121 def method_frame (self , namespace : str ) -> TypeVarLikeScope :
89122 """A new scope frame for binding a method"""
90- return TypeVarLikeScope (self , False , None , namespace = namespace )
123+ return TypeVarLikeScope (self , False , None , namespace = namespace , msg = self . msg )
91124
92125 def class_frame (self , namespace : str ) -> TypeVarLikeScope :
93126 """A new scope frame for binding a class. Prohibits *this* class's tvars"""
94- return TypeVarLikeScope (self .get_function_scope (), True , self , namespace = namespace )
127+ return TypeVarLikeScope (
128+ self .get_function_scope (), True , self , namespace = namespace , msg = self .msg
129+ )
95130
96131 def new_unique_func_id (self ) -> TypeVarId :
97132 """Used by plugin-like code that needs to make synthetic generic functions."""
98133 self .func_id -= 1
99134 return TypeVarId (self .func_id )
100135
101- def bind_new (self , name : str , tvar_expr : TypeVarLikeExpr ) -> TypeVarLikeType :
136+ def bind_new (self , name : str , tvar_expr : TypeVarLikeExpr , context : Context ) -> TypeVarLikeType :
102137 if self .is_class_scope :
103138 self .class_id += 1
104139 i = self .class_id
105140 else :
106141 self .func_id -= 1
107142 i = self .func_id
108143 namespace = self .namespace
109- tvar_expr .default .accept (TypeVarLikeNamespaceSetter (namespace ))
144+
145+ # Defaults may reference other type variables. That is only valid when the
146+ # referenced variable is already in scope (textually precedes the definition we're
147+ # processing now).
148+ default = tvar_expr .default .accept (
149+ TypeVarLikeDefaultFixer (self , tvar_expr , context = context )
150+ )
110151
111152 if isinstance (tvar_expr , TypeVarExpr ):
112153 tvar_def : TypeVarLikeType = TypeVarType (
@@ -115,7 +156,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
115156 id = TypeVarId (i , namespace = namespace ),
116157 values = tvar_expr .values ,
117158 upper_bound = tvar_expr .upper_bound ,
118- default = tvar_expr . default ,
159+ default = default ,
119160 variance = tvar_expr .variance ,
120161 line = tvar_expr .line ,
121162 column = tvar_expr .column ,
@@ -127,7 +168,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
127168 id = TypeVarId (i , namespace = namespace ),
128169 flavor = ParamSpecFlavor .BARE ,
129170 upper_bound = tvar_expr .upper_bound ,
130- default = tvar_expr . default ,
171+ default = default ,
131172 line = tvar_expr .line ,
132173 column = tvar_expr .column ,
133174 )
@@ -138,7 +179,7 @@ def bind_new(self, name: str, tvar_expr: TypeVarLikeExpr) -> TypeVarLikeType:
138179 id = TypeVarId (i , namespace = namespace ),
139180 upper_bound = tvar_expr .upper_bound ,
140181 tuple_fallback = tvar_expr .tuple_fallback ,
141- default = tvar_expr . default ,
182+ default = default ,
142183 line = tvar_expr .line ,
143184 column = tvar_expr .column ,
144185 )
0 commit comments