mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-22 03:15:44 +00:00
[ty] Emit error for invalid binary operations in type expressions (#18991)
## Summary This PR adds diagnostic for invalid binary operators in type expressions. It should close https://github.com/astral-sh/ty/issues/706 if merged. Please feel free to suggest better wordings for the diagnostic message. ## Test Plan I modified `mdtest/annotations/invalid.md` and added a test for each binary operator, and fixed tests that was broken by the new diagnostic.
This commit is contained in:
parent
9469a982cc
commit
0ec2ad2fa5
4 changed files with 46 additions and 2 deletions
|
@ -91,6 +91,40 @@ async def outer(): # avoid unrelated syntax errors on yield, yield from, and aw
|
||||||
reveal_type(p) # revealed: Unknown
|
reveal_type(p) # revealed: Unknown
|
||||||
reveal_type(q) # revealed: int | Unknown
|
reveal_type(q) # revealed: int | Unknown
|
||||||
reveal_type(r) # revealed: @Todo(unknown type subscript)
|
reveal_type(r) # revealed: @Todo(unknown type subscript)
|
||||||
|
|
||||||
|
class Mat:
|
||||||
|
def __init__(self, value: int):
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def __matmul__(self, other) -> int:
|
||||||
|
return 42
|
||||||
|
|
||||||
|
def invalid_binary_operators(
|
||||||
|
a: "1" + "2", # error: [invalid-type-form] "Invalid binary operator `+` in type annotation"
|
||||||
|
b: 3 - 5.0, # error: [invalid-type-form] "Invalid binary operator `-` in type annotation"
|
||||||
|
c: 4 * -2, # error: [invalid-type-form] "Invalid binary operator `*` in type annotation"
|
||||||
|
d: Mat(4) @ Mat(2), # error: [invalid-type-form] "Invalid binary operator `@` in type annotation"
|
||||||
|
e: 10 / 2, # error: [invalid-type-form] "Invalid binary operator `/` in type annotation"
|
||||||
|
f: 10 % 3, # error: [invalid-type-form] "Invalid binary operator `%` in type annotation"
|
||||||
|
g: 2**-0.5, # error: [invalid-type-form] "Invalid binary operator `**` in type annotation"
|
||||||
|
h: 10 // 3, # error: [invalid-type-form] "Invalid binary operator `//` in type annotation"
|
||||||
|
i: 1 << 2, # error: [invalid-type-form] "Invalid binary operator `<<` in type annotation"
|
||||||
|
j: 4 >> 42, # error: [invalid-type-form] "Invalid binary operator `>>` in type annotation"
|
||||||
|
k: 5 ^ 3, # error: [invalid-type-form] "Invalid binary operator `^` in type annotation"
|
||||||
|
l: 5 & 3, # error: [invalid-type-form] "Invalid binary operator `&` in type annotation"
|
||||||
|
):
|
||||||
|
reveal_type(a) # revealed: Unknown
|
||||||
|
reveal_type(b) # revealed: Unknown
|
||||||
|
reveal_type(c) # revealed: Unknown
|
||||||
|
reveal_type(d) # revealed: Unknown
|
||||||
|
reveal_type(e) # revealed: Unknown
|
||||||
|
reveal_type(f) # revealed: Unknown
|
||||||
|
reveal_type(g) # revealed: Unknown
|
||||||
|
reveal_type(h) # revealed: Unknown
|
||||||
|
reveal_type(i) # revealed: Unknown
|
||||||
|
reveal_type(j) # revealed: Unknown
|
||||||
|
reveal_type(k) # revealed: Unknown
|
||||||
|
reveal_type(l) # revealed: Unknown
|
||||||
```
|
```
|
||||||
|
|
||||||
## Invalid Collection based AST nodes
|
## Invalid Collection based AST nodes
|
||||||
|
|
|
@ -154,6 +154,7 @@ shouldn't panic.
|
||||||
```py
|
```py
|
||||||
a: "1 or 2"
|
a: "1 or 2"
|
||||||
b: "(x := 1)"
|
b: "(x := 1)"
|
||||||
|
# error: [invalid-type-form]
|
||||||
c: "1 + 2"
|
c: "1 + 2"
|
||||||
d: "lambda x: x"
|
d: "lambda x: x"
|
||||||
e: "x if True else y"
|
e: "x if True else y"
|
||||||
|
|
|
@ -251,7 +251,7 @@ static_assert(is_disjoint_from(Intersection[int, Any], Not[int]))
|
||||||
static_assert(is_disjoint_from(Not[int], Intersection[int, Any]))
|
static_assert(is_disjoint_from(Not[int], Intersection[int, Any]))
|
||||||
|
|
||||||
# TODO https://github.com/astral-sh/ty/issues/216
|
# TODO https://github.com/astral-sh/ty/issues/216
|
||||||
static_assert(is_disjoint_from(AlwaysFalsy, LiteralString & ~Literal[""])) # error: [static-assert-error]
|
static_assert(is_disjoint_from(AlwaysFalsy, Intersection[LiteralString, Not[Literal[""]]])) # error: [static-assert-error]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Special types
|
## Special types
|
||||||
|
|
|
@ -8416,8 +8416,17 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||||
UnionType::from_elements(self.db(), [left_ty, right_ty])
|
UnionType::from_elements(self.db(), [left_ty, right_ty])
|
||||||
}
|
}
|
||||||
// anything else is an invalid annotation:
|
// anything else is an invalid annotation:
|
||||||
_ => {
|
op => {
|
||||||
self.infer_binary_expression(binary);
|
self.infer_binary_expression(binary);
|
||||||
|
if let Some(mut diag) = self.report_invalid_type_expression(
|
||||||
|
expression,
|
||||||
|
format_args!(
|
||||||
|
"Invalid binary operator `{}` in type annotation",
|
||||||
|
op.as_str()
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
diag.info("Did you mean to use `|`?");
|
||||||
|
}
|
||||||
Type::unknown()
|
Type::unknown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue