@@ -3608,6 +3608,12 @@ def visit_op_expr(self, e: OpExpr) -> Type:
36083608 if e .op == "*" and isinstance (e .left , ListExpr ):
36093609 # Expressions of form [...] * e get special type inference.
36103610 return self .check_list_multiply (e )
3611+ if e .op == "+" :
3612+ # Expressions of form list + list under a list type context get special
3613+ # type inference so literals/comprehensions honor the outer context.
3614+ ctx = get_proper_type (self .type_context [- 1 ])
3615+ if is_named_instance (ctx , "builtins.list" ):
3616+ return self .check_list_add (e )
36113617 if e .op == "%" :
36123618 if isinstance (e .left , BytesExpr ):
36133619 return self .strfrm_checker .check_str_interpolation (e .left , e .right )
@@ -4505,6 +4511,23 @@ def check_list_multiply(self, e: OpExpr) -> Type:
45054511 e .method_type = method_type
45064512 return result
45074513
4514+ def check_list_add (self , e : OpExpr ) -> Type :
4515+ """Type check list concatenation under an outer list type context.
4516+
4517+ Like list literals and '[...] * n', both operands should see the outer
4518+ list[...] context so that e.g. ``x: list[int | None] = [0] + [1]`` works.
4519+ """
4520+ ctx = self .type_context [- 1 ]
4521+ left_type = self .accept (e .left , type_context = ctx )
4522+ right_type = self .accept (e .right , type_context = ctx )
4523+ # check_op re-accepts the right operand; keep the context-aware type.
4524+ with self .type_overrides_set ([e .right ], [right_type ]):
4525+ result , method_type = self .check_op (
4526+ "__add__" , left_type , e .right , e , allow_reverse = True
4527+ )
4528+ e .method_type = method_type
4529+ return result
4530+
45084531 def visit_assignment_expr (self , e : AssignmentExpr ) -> Type :
45094532 value = self .accept (e .value )
45104533 binder_version = self .chk .binder .version
0 commit comments