Skip to content

Commit 90f6a2f

Browse files
committed
Only infer LiteralType if one of thhe operands is a Literal
1 parent 76ea9a2 commit 90f6a2f

File tree

2 files changed

+14
-7
lines changed

2 files changed

+14
-7
lines changed

mypy/checkexpr.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3510,19 +3510,19 @@ def visit_op_expr(self, e: OpExpr) -> Type:
35103510

35113511
def literal_value_from_expr(
35123512
self, expr: Expression, typ: Type | None = None
3513-
) -> tuple[list[str | int], str] | None:
3513+
) -> tuple[list[str | int], str, bool] | None:
35143514
if isinstance(expr, StrExpr):
3515-
return [expr.value], "builtins.str"
3515+
return [expr.value], "builtins.str", False
35163516
if isinstance(expr, IntExpr):
3517-
return [expr.value], "builtins.int"
3517+
return [expr.value], "builtins.int", False
35183518
if isinstance(expr, BytesExpr):
3519-
return [expr.value], "builtins.bytes"
3519+
return [expr.value], "builtins.bytes", False
35203520

35213521
typ = typ or self.accept(expr)
35223522
ptype = get_proper_type(typ)
35233523

35243524
if isinstance(ptype, LiteralType) and not isinstance(ptype.value, (bool, float)):
3525-
return [ptype.value], ptype.fallback.type.fullname
3525+
return [ptype.value], ptype.fallback.type.fullname, True
35263526

35273527
if isinstance(ptype, UnionType):
35283528
fallback: str | None = None
@@ -3538,15 +3538,19 @@ def literal_value_from_expr(
35383538
values.append(pitem.value)
35393539
else:
35403540
assert fallback is not None
3541-
return values, fallback
3541+
return values, fallback, True
35423542
return None
35433543

35443544
def literal_expression_addition(self, e: OpExpr, left_type: Type) -> Type | None:
35453545
"""Check if literal values can be combined with addition."""
35463546
assert e.op == "+"
35473547
if not (lvalue := self.literal_value_from_expr(e.left, left_type)):
35483548
return None
3549-
if not (rvalue := self.literal_value_from_expr(e.right)) or lvalue[1] != rvalue[1]:
3549+
if (
3550+
not (rvalue := self.literal_value_from_expr(e.right))
3551+
or lvalue[1] != rvalue[1] # different fallback
3552+
or lvalue[2] + rvalue[2] == 0 # no LiteralType
3553+
):
35503554
return None
35513555

35523556
values: list[int | str] = sorted(

test-data/unit/check-literal.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,6 +2983,7 @@ b: bytes
29832983

29842984
misc_union: Literal["a", 1]
29852985

2986+
reveal_type("a" + "b") # N: Revealed type is "builtins.str"
29862987
reveal_type(str_a + str_b) # N: Revealed type is "Literal['ab']"
29872988
reveal_type(str_a + "b") # N: Revealed type is "Literal['ab']"
29882989
reveal_type("a" + str_b) # N: Revealed type is "Literal['ab']"
@@ -2996,6 +2997,7 @@ reveal_type(s + str_a) # N: Revealed type is "builtins.str"
29962997
reveal_type(str_union_1 + s) # N: Revealed type is "builtins.str"
29972998
reveal_type(s + str_union_1) # N: Revealed type is "builtins.str"
29982999

3000+
reveal_type(1 + 2) # N: Revealed type is "builtins.int"
29993001
reveal_type(int_1 + int_2) # N: Revealed type is "Literal[3]"
30003002
reveal_type(int_1 + 1) # N: Revealed type is "Literal[2]"
30013003
reveal_type(1 + int_1) # N: Revealed type is "Literal[2]"
@@ -3009,6 +3011,7 @@ reveal_type(i + int_1) # N: Revealed type is "builtins.int"
30093011
reveal_type(int_union_1 + i) # N: Revealed type is "builtins.int"
30103012
reveal_type(i + int_union_1) # N: Revealed type is "builtins.int"
30113013

3014+
reveal_type(b"a" + b"b") # N: Revealed type is "builtins.bytes"
30123015
reveal_type(bytes_a + bytes_b) # N: Revealed type is "Literal[b'ab']"
30133016
reveal_type(bytes_a + b"b") # N: Revealed type is "Literal[b'ab']"
30143017
reveal_type(b"a" + bytes_b) # N: Revealed type is "Literal[b'ab']"

0 commit comments

Comments
 (0)