mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] highlight the argument in static_assert
error messages (#19426)
Closes https://github.com/astral-sh/ty/issues/209. Before: ``` error[static-assert-error]: Static assertion error: custom message --> test.py:2:1 | 1 | from ty_extensions import static_assert 2 | static_assert(3 > 4, "custom message") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ``` After: ``` error[static-assert-error]: Static assertion error: custom message --> test.py:2:1 | 1 | from ty_extensions import static_assert 2 | static_assert(3 > 4, "custom message") | ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^ | | | Inferred type of argument is `Literal[False]` | ```
This commit is contained in:
parent
5a55bab3f3
commit
88bd82938f
5 changed files with 193 additions and 6 deletions
|
@ -1,5 +1,7 @@
|
|||
# `cast`
|
||||
|
||||
## Behavior
|
||||
|
||||
`cast()` takes two arguments, one type and one value, and returns a value of the given type.
|
||||
|
||||
The (inferred) type of the value and the given type do not need to have any correlation.
|
||||
|
@ -78,3 +80,15 @@ def f(x: Any, y: Unknown, z: Any | str | int):
|
|||
|
||||
e = cast(str | int | Any, z) # error: [redundant-cast]
|
||||
```
|
||||
|
||||
## Diagnostic snapshots
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
import secrets
|
||||
from typing import cast
|
||||
|
||||
# error: [redundant-cast] "Value is already of type `int`"
|
||||
cast(int, secrets.randbelow(10))
|
||||
```
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: cast.md - `cast` - Diagnostic snapshots
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/directives/cast.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | import secrets
|
||||
2 | from typing import cast
|
||||
3 |
|
||||
4 | # error: [redundant-cast] "Value is already of type `int`"
|
||||
5 | cast(int, secrets.randbelow(10))
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
warning[redundant-cast]: Value is already of type `int`
|
||||
--> src/mdtest_snippet.py:5:1
|
||||
|
|
||||
4 | # error: [redundant-cast] "Value is already of type `int`"
|
||||
5 | cast(int, secrets.randbelow(10))
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
info: rule `redundant-cast` is enabled by default
|
||||
|
||||
```
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: type_api.md - Type API (`ty_extensions`) - Diagnostic snapshots
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/type_api.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | from ty_extensions import static_assert
|
||||
2 | import secrets
|
||||
3 |
|
||||
4 | # a passing assert
|
||||
5 | static_assert(1 < 2)
|
||||
6 |
|
||||
7 | # evaluates to False
|
||||
8 | # error: [static-assert-error]
|
||||
9 | static_assert(1 > 2)
|
||||
10 |
|
||||
11 | # evaluates to False, with a message as the second argument
|
||||
12 | # error: [static-assert-error]
|
||||
13 | static_assert(1 > 2, "with a message")
|
||||
14 |
|
||||
15 | # evaluates to something falsey
|
||||
16 | # error: [static-assert-error]
|
||||
17 | static_assert("")
|
||||
18 |
|
||||
19 | # evaluates to something ambiguous
|
||||
20 | # error: [static-assert-error]
|
||||
21 | static_assert(secrets.randbelow(2))
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[static-assert-error]: Static assertion error: argument evaluates to `False`
|
||||
--> src/mdtest_snippet.py:9:1
|
||||
|
|
||||
7 | # evaluates to False
|
||||
8 | # error: [static-assert-error]
|
||||
9 | static_assert(1 > 2)
|
||||
| ^^^^^^^^^^^^^^-----^
|
||||
| |
|
||||
| Inferred type of argument is `Literal[False]`
|
||||
10 |
|
||||
11 | # evaluates to False, with a message as the second argument
|
||||
|
|
||||
info: rule `static-assert-error` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[static-assert-error]: Static assertion error: with a message
|
||||
--> src/mdtest_snippet.py:13:1
|
||||
|
|
||||
11 | # evaluates to False, with a message as the second argument
|
||||
12 | # error: [static-assert-error]
|
||||
13 | static_assert(1 > 2, "with a message")
|
||||
| ^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| Inferred type of argument is `Literal[False]`
|
||||
14 |
|
||||
15 | # evaluates to something falsey
|
||||
|
|
||||
info: rule `static-assert-error` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[static-assert-error]: Static assertion error: argument of type `Literal[""]` is statically known to be falsy
|
||||
--> src/mdtest_snippet.py:17:1
|
||||
|
|
||||
15 | # evaluates to something falsey
|
||||
16 | # error: [static-assert-error]
|
||||
17 | static_assert("")
|
||||
| ^^^^^^^^^^^^^^--^
|
||||
| |
|
||||
| Inferred type of argument is `Literal[""]`
|
||||
18 |
|
||||
19 | # evaluates to something ambiguous
|
||||
|
|
||||
info: rule `static-assert-error` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[static-assert-error]: Static assertion error: argument of type `int` has an ambiguous static truthiness
|
||||
--> src/mdtest_snippet.py:21:1
|
||||
|
|
||||
19 | # evaluates to something ambiguous
|
||||
20 | # error: [static-assert-error]
|
||||
21 | static_assert(secrets.randbelow(2))
|
||||
| ^^^^^^^^^^^^^^--------------------^
|
||||
| |
|
||||
| Inferred type of argument is `int`
|
||||
|
|
||||
info: rule `static-assert-error` is enabled by default
|
||||
|
||||
```
|
|
@ -266,6 +266,34 @@ shouted_message = "A custom message".upper()
|
|||
static_assert(False, shouted_message)
|
||||
```
|
||||
|
||||
## Diagnostic snapshots
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
from ty_extensions import static_assert
|
||||
import secrets
|
||||
|
||||
# a passing assert
|
||||
static_assert(1 < 2)
|
||||
|
||||
# evaluates to False
|
||||
# error: [static-assert-error]
|
||||
static_assert(1 > 2)
|
||||
|
||||
# evaluates to False, with a message as the second argument
|
||||
# error: [static-assert-error]
|
||||
static_assert(1 > 2, "with a message")
|
||||
|
||||
# evaluates to something falsey
|
||||
# error: [static-assert-error]
|
||||
static_assert("")
|
||||
|
||||
# evaluates to something ambiguous
|
||||
# error: [static-assert-error]
|
||||
static_assert(secrets.randbelow(2))
|
||||
```
|
||||
|
||||
## Type predicates
|
||||
|
||||
The `ty_extensions` module also provides predicates to test various properties of types. These are
|
||||
|
|
|
@ -1264,28 +1264,35 @@ impl KnownFunction {
|
|||
if truthiness.is_always_true() {
|
||||
return;
|
||||
}
|
||||
if let Some(message) = message
|
||||
let mut diagnostic = if let Some(message) = message
|
||||
.and_then(Type::into_string_literal)
|
||||
.map(|s| s.value(db))
|
||||
{
|
||||
builder.into_diagnostic(format_args!("Static assertion error: {message}"));
|
||||
builder.into_diagnostic(format_args!("Static assertion error: {message}"))
|
||||
} else if *parameter_ty == Type::BooleanLiteral(false) {
|
||||
builder.into_diagnostic(
|
||||
"Static assertion error: argument evaluates to `False`",
|
||||
);
|
||||
)
|
||||
} else if truthiness.is_always_false() {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Static assertion error: argument of type `{parameter_ty}` \
|
||||
is statically known to be falsy",
|
||||
parameter_ty = parameter_ty.display(db)
|
||||
));
|
||||
))
|
||||
} else {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Static assertion error: argument of type `{parameter_ty}` \
|
||||
has an ambiguous static truthiness",
|
||||
parameter_ty = parameter_ty.display(db)
|
||||
));
|
||||
}
|
||||
))
|
||||
};
|
||||
diagnostic.annotate(
|
||||
Annotation::secondary(context.span(&call_expression.arguments.args[0]))
|
||||
.message(format_args!(
|
||||
"Inferred type of argument is `{}`",
|
||||
parameter_ty.display(db)
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue