@@ -2269,11 +2269,17 @@ class Foo(Bar, Generic[T]): ...
22692269 removed : list [int ] = []
22702270 declared_tvars : TypeVarLikeList = []
22712271 is_protocol = False
2272+ has_type_var_tuple = False
22722273 if defn .type_args is not None :
22732274 for p in defn .type_args :
22742275 node = self .lookup (p .name , context )
22752276 assert node is not None
22762277 assert isinstance (node .node , TypeVarLikeExpr )
2278+ if isinstance (node .node , TypeVarTupleExpr ):
2279+ if has_type_var_tuple :
2280+ self .fail ("Can only use one type var tuple in a class def" , context )
2281+ continue
2282+ has_type_var_tuple = True
22772283 declared_tvars .append ((p .name , node .node ))
22782284
22792285 for i , base_expr in enumerate (base_type_exprs ):
@@ -2286,7 +2292,7 @@ class Foo(Bar, Generic[T]): ...
22862292 except TypeTranslationError :
22872293 # This error will be caught later.
22882294 continue
2289- result = self .analyze_class_typevar_declaration (base )
2295+ result = self .analyze_class_typevar_declaration (base , has_type_var_tuple )
22902296 if result is not None :
22912297 tvars = result [0 ]
22922298 is_protocol |= result [1 ]
@@ -2340,7 +2346,9 @@ class Foo(Bar, Generic[T]): ...
23402346 tvar_defs = self .tvar_defs_from_tvars (declared_tvars , context )
23412347 return base_type_exprs , tvar_defs , is_protocol
23422348
2343- def analyze_class_typevar_declaration (self , base : Type ) -> tuple [TypeVarLikeList , bool ] | None :
2349+ def analyze_class_typevar_declaration (
2350+ self , base : Type , has_type_var_tuple : bool
2351+ ) -> tuple [TypeVarLikeList , bool ] | None :
23442352 """Analyze type variables declared using Generic[...] or Protocol[...].
23452353
23462354 Args:
@@ -2362,16 +2370,15 @@ def analyze_class_typevar_declaration(self, base: Type) -> tuple[TypeVarLikeList
23622370 ):
23632371 is_proto = sym .node .fullname != "typing.Generic"
23642372 tvars : TypeVarLikeList = []
2365- have_type_var_tuple = False
23662373 for arg in unbound .args :
23672374 tag = self .track_incomplete_refs ()
23682375 tvar = self .analyze_unbound_tvar (arg )
23692376 if tvar :
23702377 if isinstance (tvar [1 ], TypeVarTupleExpr ):
2371- if have_type_var_tuple :
2378+ if has_type_var_tuple :
23722379 self .fail ("Can only use one type var tuple in a class def" , base )
23732380 continue
2374- have_type_var_tuple = True
2381+ has_type_var_tuple = True
23752382 tvars .append (tvar )
23762383 elif not self .found_incomplete_ref (tag ):
23772384 self .fail ("Free type variable expected in %s[...]" % sym .node .name , base )
@@ -2455,7 +2462,7 @@ def tvar_defs_from_tvars(
24552462 self .fail (
24562463 message_registry .TYPE_VAR_REDECLARED_IN_NESTED_CLASS .format (name ), context
24572464 )
2458- tvar_def = self .tvar_scope .bind_new (name , tvar_expr )
2465+ tvar_def = self .tvar_scope .bind_new (name , tvar_expr , self . fail , context )
24592466 if last_tvar_name_with_default is not None and not tvar_def .has_default ():
24602467 self .msg .tvar_without_default_type (
24612468 tvar_def .name , last_tvar_name_with_default , context
@@ -2473,19 +2480,18 @@ def get_and_bind_all_tvars(self, type_exprs: list[Expression]) -> list[TypeVarLi
24732480 a simplified version of the logic we use for ClassDef bases. We duplicate
24742481 some amount of code, because it is hard to refactor common pieces.
24752482 """
2476- tvars = []
2483+ tvars : dict [ str , tuple [ TypeVarLikeExpr , Expression ]] = {}
24772484 for base_expr in type_exprs :
24782485 try :
24792486 base = self .expr_to_unanalyzed_type (base_expr )
24802487 except TypeTranslationError :
24812488 # This error will be caught later.
24822489 continue
2483- base_tvars = self .find_type_var_likes (base )
2484- tvars .extend (base_tvars )
2485- tvars = remove_dups (tvars ) # Variables are defined in order of textual appearance.
2490+ for name , expr in self .find_type_var_likes (base ):
2491+ tvars .setdefault (name , (expr , base_expr ))
24862492 tvar_defs = []
2487- for name , tvar_expr in tvars :
2488- tvar_def = self .tvar_scope .bind_new (name , tvar_expr )
2493+ for name , ( tvar_expr , context ) in tvars . items () :
2494+ tvar_def = self .tvar_scope .bind_new (name , tvar_expr , self . fail , context )
24892495 tvar_defs .append (tvar_def )
24902496 return tvar_defs
24912497
@@ -6505,7 +6511,9 @@ def _lookup(
65056511 implicit_node = node
65066512 # 2b. Class attributes __qualname__ and __module__
65076513 if self .type and not self .is_func_scope () and name in {"__qualname__" , "__module__" }:
6508- return SymbolTableNode (MDEF , Var (name , self .str_type ()))
6514+ v = Var (name , self .str_type ())
6515+ v ._fullname = self .qualified_name (name )
6516+ return SymbolTableNode (MDEF , v )
65096517 # 3. Local (function) scopes
65106518 for table in reversed (self .locals ):
65116519 if table is not None and name in table :
@@ -7022,7 +7030,12 @@ def add_symbol_table_node(
70227030 if not is_same_symbol (old , new ):
70237031 if isinstance (new , (FuncDef , Decorator , OverloadedFuncDef , TypeInfo )):
70247032 self .add_redefinition (names , name , symbol )
7025- if not (isinstance (new , (FuncDef , Decorator )) and self .set_original_def (old , new )):
7033+ if isinstance (old , Var ) and is_init_only (old ):
7034+ if old .has_explicit_value :
7035+ self .fail ("InitVar with default value cannot be redefined" , context )
7036+ elif not (
7037+ isinstance (new , (FuncDef , Decorator )) and self .set_original_def (old , new )
7038+ ):
70267039 self .name_already_defined (name , context , existing )
70277040 elif type_param or (
70287041 name not in self .missing_names [- 1 ] and "*" not in self .missing_names [- 1 ]
@@ -8271,3 +8284,10 @@ def halt(self, reason: str = ...) -> NoReturn:
82718284 return isinstance (stmt , PassStmt ) or (
82728285 isinstance (stmt , ExpressionStmt ) and isinstance (stmt .expr , EllipsisExpr )
82738286 )
8287+
8288+
8289+ def is_init_only (node : Var ) -> bool :
8290+ return (
8291+ isinstance (type := get_proper_type (node .type ), Instance )
8292+ and type .type .fullname == "dataclasses.InitVar"
8293+ )
0 commit comments