Skip to content

Commit 4773a38

Browse files
committed
Move this logic closer to binder, stop putting AssignmentExpr directly
1 parent 914f6c8 commit 4773a38

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

mypy/binder.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@
88

99
from mypy.erasetype import remove_instance_last_known_values
1010
from mypy.literals import Key, extract_var_from_literal_hash, literal, literal_hash, subkeys
11-
from mypy.nodes import Expression, IndexExpr, MemberExpr, NameExpr, RefExpr, TypeInfo, Var
11+
from mypy.nodes import (
12+
LITERAL_NO,
13+
Expression,
14+
IndexExpr,
15+
MemberExpr,
16+
NameExpr,
17+
RefExpr,
18+
TypeInfo,
19+
Var,
20+
)
1221
from mypy.options import Options
1322
from mypy.subtypes import is_same_type, is_subtype
1423
from mypy.typeops import make_simplified_union
@@ -173,6 +182,15 @@ def _get(self, key: Key, index: int = -1) -> CurrentType | None:
173182
return self.frames[i].types[key]
174183
return None
175184

185+
@classmethod
186+
def can_put_directly(cls, expr: Expression) -> bool:
187+
"""Will `.put()` on this expression be successful?
188+
189+
This is inlined in `.put()` because the logic is rather hot and must be kept
190+
in sync.
191+
"""
192+
return isinstance(expr, (IndexExpr, MemberExpr, NameExpr)) and literal(expr) > LITERAL_NO
193+
176194
def put(self, expr: Expression, typ: Type, *, from_assignment: bool = True) -> None:
177195
"""Directly set the narrowed type of expression (if it supports it).
178196

mypy/checker.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5478,6 +5478,9 @@ def visit_continue_stmt(self, s: ContinueStmt) -> None:
54785478

54795479
def visit_match_stmt(self, s: MatchStmt) -> None:
54805480
named_subject = self._make_named_statement_for_match(s)
5481+
# In sync with similar actions elsewhere, narrow the target if
5482+
# we are matching an AssignmentExpr
5483+
unwrapped_subject = collapse_walrus(s.subject)
54815484
with self.binder.frame_context(can_skip=False, fall_through=0):
54825485
subject_type = get_proper_type(self.expr_checker.accept(s.subject))
54835486

@@ -5513,9 +5516,9 @@ def visit_match_stmt(self, s: MatchStmt) -> None:
55135516
# Maybe the subject type can be inferred from constraints on
55145517
# its attribute/item?
55155518
if pattern_map and named_subject in pattern_map:
5516-
pattern_map[s.subject] = pattern_map[named_subject]
5519+
pattern_map[unwrapped_subject] = pattern_map[named_subject]
55175520
if else_map and named_subject in else_map:
5518-
else_map[s.subject] = else_map[named_subject]
5521+
else_map[unwrapped_subject] = else_map[named_subject]
55195522
pattern_map = self.propagate_up_typemap_info(pattern_map)
55205523
else_map = self.propagate_up_typemap_info(else_map)
55215524
self.remove_capture_conflicts(pattern_type.captures, inferred_types)
@@ -5571,7 +5574,7 @@ def visit_match_stmt(self, s: MatchStmt) -> None:
55715574
def _make_named_statement_for_match(self, s: MatchStmt) -> Expression:
55725575
"""Construct a fake NameExpr for inference if a match clause is complex."""
55735576
subject = s.subject
5574-
if isinstance(subject, (NameExpr, AssignmentExpr)):
5577+
if self.binder.can_put_directly(subject):
55755578
# Already named - we should infer type of it as given
55765579
return subject
55775580
elif s.subject_dummy is not None:

test-data/unit/check-python310.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,9 +2179,11 @@ def f() -> None:
21792179
match x := returns_a_or_none():
21802180
case A():
21812181
reveal_type(x.a) # N: Revealed type is "builtins.int"
2182+
reveal_type(x) # N: Revealed type is "Union[__main__.A, None]"
21822183
match x := returns_a():
21832184
case A():
21842185
reveal_type(x.a) # N: Revealed type is "builtins.int"
2186+
reveal_type(x) # N: Revealed type is "__main__.A"
21852187
y = returns_a_or_none()
21862188
match y:
21872189
case A():

0 commit comments

Comments
 (0)