Skip to content

Commit 0024062

Browse files
committed
Only infer LiteralType if one of thhe operands is a Literal
1 parent 3ef962d commit 0024062

2 files changed

Lines changed: 14 additions & 7 deletions

File tree

mypy/checkexpr.py

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

35863586
def literal_value_from_expr(
35873587
self, expr: Expression, typ: Type | None = None
3588-
) -> tuple[list[str | int], str] | None:
3588+
) -> tuple[list[str | int], str, bool] | None:
35893589
if isinstance(expr, StrExpr):
3590-
return [expr.value], "builtins.str"
3590+
return [expr.value], "builtins.str", False
35913591
if isinstance(expr, IntExpr):
3592-
return [expr.value], "builtins.int"
3592+
return [expr.value], "builtins.int", False
35933593
if isinstance(expr, BytesExpr):
3594-
return [expr.value], "builtins.bytes"
3594+
return [expr.value], "builtins.bytes", False
35953595

35963596
typ = typ or self.accept(expr)
35973597
ptype = get_proper_type(typ)
35983598

35993599
if isinstance(ptype, LiteralType) and not isinstance(ptype.value, (bool, float)):
3600-
return [ptype.value], ptype.fallback.type.fullname
3600+
return [ptype.value], ptype.fallback.type.fullname, True
36013601

36023602
if isinstance(ptype, UnionType):
36033603
fallback: str | None = None
@@ -3613,15 +3613,19 @@ def literal_value_from_expr(
36133613
values.append(pitem.value)
36143614
else:
36153615
assert fallback is not None
3616-
return values, fallback
3616+
return values, fallback, True
36173617
return None
36183618

36193619
def literal_expression_addition(self, e: OpExpr, left_type: Type) -> Type | None:
36203620
"""Check if literal values can be combined with addition."""
36213621
assert e.op == "+"
36223622
if not (lvalue := self.literal_value_from_expr(e.left, left_type)):
36233623
return None
3624-
if not (rvalue := self.literal_value_from_expr(e.right)) or lvalue[1] != rvalue[1]:
3624+
if (
3625+
not (rvalue := self.literal_value_from_expr(e.right))
3626+
or lvalue[1] != rvalue[1] # different fallback
3627+
or lvalue[2] + rvalue[2] == 0 # no LiteralType
3628+
):
36253629
return None
36263630

36273631
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
@@ -2999,6 +2999,7 @@ b: bytes
29992999

30003000
misc_union: Literal["a", 1]
30013001

3002+
reveal_type("a" + "b") # N: Revealed type is "builtins.str"
30023003
reveal_type(str_a + str_b) # N: Revealed type is "Literal['ab']"
30033004
reveal_type(str_a + "b") # N: Revealed type is "Literal['ab']"
30043005
reveal_type("a" + str_b) # N: Revealed type is "Literal['ab']"
@@ -3012,6 +3013,7 @@ reveal_type(s + str_a) # N: Revealed type is "builtins.str"
30123013
reveal_type(str_union_1 + s) # N: Revealed type is "builtins.str"
30133014
reveal_type(s + str_union_1) # N: Revealed type is "builtins.str"
30143015

3016+
reveal_type(1 + 2) # N: Revealed type is "builtins.int"
30153017
reveal_type(int_1 + int_2) # N: Revealed type is "Literal[3]"
30163018
reveal_type(int_1 + 1) # N: Revealed type is "Literal[2]"
30173019
reveal_type(1 + int_1) # N: Revealed type is "Literal[2]"
@@ -3025,6 +3027,7 @@ reveal_type(i + int_1) # N: Revealed type is "builtins.int"
30253027
reveal_type(int_union_1 + i) # N: Revealed type is "builtins.int"
30263028
reveal_type(i + int_union_1) # N: Revealed type is "builtins.int"
30273029

3030+
reveal_type(b"a" + b"b") # N: Revealed type is "builtins.bytes"
30283031
reveal_type(bytes_a + bytes_b) # N: Revealed type is "Literal[b'ab']"
30293032
reveal_type(bytes_a + b"b") # N: Revealed type is "Literal[b'ab']"
30303033
reveal_type(b"a" + bytes_b) # N: Revealed type is "Literal[b'ab']"

0 commit comments

Comments
 (0)