diff --git a/crates/ty_ide/src/inlay_hints.rs b/crates/ty_ide/src/inlay_hints.rs index 53d3fbbd88..9f6e2a5afe 100644 --- a/crates/ty_ide/src/inlay_hints.rs +++ b/crates/ty_ide/src/inlay_hints.rs @@ -2204,7 +2204,7 @@ mod tests { assert_snapshot!(test.inlay_hints(), @r#" a[: list[Unknown | int]] = [1, 2] - b[: list[Unknown | float]] = [1.0, 2.0] + b[: list[Unknown | int | float]] = [1.0, 2.0] c[: list[Unknown | bool]] = [True, False] d[: list[Unknown | None]] = [None, None] e[: list[Unknown | str]] = ["hel", "lo"] @@ -2229,7 +2229,7 @@ mod tests { | 2 | a[: list[Unknown | int]] = [1, 2] | ^^^^ - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | @@ -2247,7 +2247,7 @@ mod tests { | 2 | a[: list[Unknown | int]] = [1, 2] | ^^^^^^^ - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | @@ -2265,7 +2265,7 @@ mod tests { | 2 | a[: list[Unknown | int]] = [1, 2] | ^^^ - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | @@ -2281,7 +2281,7 @@ mod tests { --> main2.py:3:5 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] | ^^^^ 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] @@ -2300,12 +2300,31 @@ mod tests { --> main2.py:3:10 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] | ^^^^^^^ 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] | + info[inlay-hint-location]: Inlay Hint Target + --> stdlib/builtins.pyi:348:7 + | + 347 | @disjoint_base + 348 | class int: + | ^^^ + 349 | """int([x]) -> integer + 350 | int(x, base=10) -> integer + | + info: Source + --> main2.py:3:20 + | + 2 | a[: list[Unknown | int]] = [1, 2] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] + | ^^^ + 4 | c[: list[Unknown | bool]] = [True, False] + 5 | d[: list[Unknown | None]] = [None, None] + | + info[inlay-hint-location]: Inlay Hint Target --> stdlib/builtins.pyi:661:7 | @@ -2315,11 +2334,11 @@ mod tests { 662 | """Convert a string or number to a floating-point number, if possible.""" | info: Source - --> main2.py:3:20 + --> main2.py:3:26 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] - | ^^^^^ + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] + | ^^^^^ 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] | @@ -2336,7 +2355,7 @@ mod tests { --> main2.py:4:5 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | ^^^^ 5 | d[: list[Unknown | None]] = [None, None] @@ -2356,7 +2375,7 @@ mod tests { --> main2.py:4:10 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | ^^^^^^^ 5 | d[: list[Unknown | None]] = [None, None] @@ -2376,7 +2395,7 @@ mod tests { --> main2.py:4:20 | 2 | a[: list[Unknown | int]] = [1, 2] - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] | ^^^^ 5 | d[: list[Unknown | None]] = [None, None] @@ -2394,7 +2413,7 @@ mod tests { info: Source --> main2.py:5:5 | - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] | ^^^^ @@ -2414,7 +2433,7 @@ mod tests { info: Source --> main2.py:5:10 | - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] | ^^^^^^^ @@ -2434,7 +2453,7 @@ mod tests { info: Source --> main2.py:5:20 | - 3 | b[: list[Unknown | float]] = [1.0, 2.0] + 3 | b[: list[Unknown | int | float]] = [1.0, 2.0] 4 | c[: list[Unknown | bool]] = [True, False] 5 | d[: list[Unknown | None]] = [None, None] | ^^^^ @@ -2885,7 +2904,7 @@ mod tests { info: Source a: list[Unknown | int] = [1, 2] - b: list[Unknown | float] = [1.0, 2.0] + b: list[Unknown | int | float] = [1.0, 2.0] c: list[Unknown | bool] = [True, False] d: list[Unknown | None] = [None, None] e: list[Unknown | str] = ["hel", "lo"] diff --git a/crates/ty_python_semantic/resources/mdtest/literal_promotion.md b/crates/ty_python_semantic/resources/mdtest/literal_promotion.md index 65fc1c1602..fdf8fc67a6 100644 --- a/crates/ty_python_semantic/resources/mdtest/literal_promotion.md +++ b/crates/ty_python_semantic/resources/mdtest/literal_promotion.md @@ -7,6 +7,9 @@ python-version = "3.12" There are certain places where we promote literals to their common supertype. +We also promote `float` to `int | float` and `complex` to `int | float | complex`, even when not in +a type annotation. + ## All literal types are promotable ```py @@ -31,6 +34,9 @@ def _( reveal_type(promote(lit3)) # revealed: list[bool] reveal_type(promote(lit4)) # revealed: list[bytes] reveal_type(promote(lit5)) # revealed: list[MyEnum] + +reveal_type(promote(3.14)) # revealed: list[int | float] +reveal_type(promote(3.14j)) # revealed: list[int | float | complex] ``` Function types are also promoted to their `Callable` form: diff --git a/crates/ty_python_semantic/resources/mdtest/named_tuple.md b/crates/ty_python_semantic/resources/mdtest/named_tuple.md index cedb597b45..7034a74176 100644 --- a/crates/ty_python_semantic/resources/mdtest/named_tuple.md +++ b/crates/ty_python_semantic/resources/mdtest/named_tuple.md @@ -251,7 +251,7 @@ reveal_type(LegacyProperty("height", 42)) # revealed: LegacyProperty[int] reveal_type(LegacyProperty.value) # revealed: property reveal_type(LegacyProperty.value.fget) # revealed: (self, /) -> Unknown reveal_type(LegacyProperty[str].value.fget) # revealed: (self, /) -> str -reveal_type(LegacyProperty("height", 3.4).value) # revealed: float +reveal_type(LegacyProperty("height", 3.4).value) # revealed: int | float ``` ## Attributes on `NamedTuple` diff --git a/crates/ty_python_semantic/src/types.rs b/crates/ty_python_semantic/src/types.rs index 6bcd6756d6..e4dfee1af7 100644 --- a/crates/ty_python_semantic/src/types.rs +++ b/crates/ty_python_semantic/src/types.rs @@ -7948,6 +7948,14 @@ impl<'db> Type<'db> { method.self_instance(db).apply_type_mapping_impl(db, type_mapping, tcx, visitor), )), + Type::NominalInstance(instance) if matches!(type_mapping, TypeMapping::PromoteLiterals(PromoteLiteralsMode::On)) => { + match instance.known_class(db) { + Some(KnownClass::Complex) => KnownUnion::Complex.to_type(db), + Some(KnownClass::Float) => KnownUnion::Float.to_type(db), + _ => instance.apply_type_mapping_impl(db, type_mapping, tcx, visitor), + } + } + Type::NominalInstance(instance) => { instance.apply_type_mapping_impl(db, type_mapping, tcx, visitor) },