mirror of https://github.com/astral-sh/ruff
[ty] Improve `unsupported-base` and `invalid-super-argument` diagnostics to avoid extremely long lines when encountering verbose types (#22022)
This commit is contained in:
parent
421f88bb32
commit
0bd7a94c27
|
|
@ -615,6 +615,22 @@ def _(x: type[typing.Any], y: typing.Any):
|
|||
reveal_type(super(x, y)) # revealed: <super: Any, Any>
|
||||
```
|
||||
|
||||
### Diagnostic when the invalid type is rendered very verbosely
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
def coinflip() -> bool:
|
||||
return False
|
||||
|
||||
def f():
|
||||
if coinflip():
|
||||
class A: ...
|
||||
else:
|
||||
class A: ...
|
||||
super(A, A()) # error: [invalid-super-argument]
|
||||
```
|
||||
|
||||
### Instance Member Access via `super`
|
||||
|
||||
Accessing instance members through `super()` is not allowed.
|
||||
|
|
|
|||
|
|
@ -289,6 +289,14 @@ reveal_type(x) # revealed: <class 'A'> | <class 'B'>
|
|||
class Foo(x): ...
|
||||
|
||||
reveal_mro(Foo) # revealed: (<class 'Foo'>, Unknown, <class 'object'>)
|
||||
|
||||
def f():
|
||||
if returns_bool():
|
||||
class C: ...
|
||||
else:
|
||||
class C: ...
|
||||
|
||||
class D(C): ... # error: [unsupported-base]
|
||||
```
|
||||
|
||||
## `UnionType` instances are now allowed as a base
|
||||
|
|
|
|||
|
|
@ -31,17 +31,25 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/mro.md
|
|||
17 | class Foo(x): ...
|
||||
18 |
|
||||
19 | reveal_mro(Foo) # revealed: (<class 'Foo'>, Unknown, <class 'object'>)
|
||||
20 |
|
||||
21 | def f():
|
||||
22 | if returns_bool():
|
||||
23 | class C: ...
|
||||
24 | else:
|
||||
25 | class C: ...
|
||||
26 |
|
||||
27 | class D(C): ... # error: [unsupported-base]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
warning[unsupported-base]: Unsupported class base with type `<class 'A'> | <class 'B'>`
|
||||
warning[unsupported-base]: Unsupported class base
|
||||
--> src/mdtest_snippet.py:17:11
|
||||
|
|
||||
16 | # error: 11 [unsupported-base] "Unsupported class base with type `<class 'A'> | <class 'B'>`"
|
||||
17 | class Foo(x): ...
|
||||
| ^
|
||||
| ^ Has type `<class 'A'> | <class 'B'>`
|
||||
18 |
|
||||
19 | reveal_mro(Foo) # revealed: (<class 'Foo'>, Unknown, <class 'object'>)
|
||||
|
|
||||
|
|
@ -50,3 +58,18 @@ info: Only class objects or `Any` are supported as class bases
|
|||
info: rule `unsupported-base` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
warning[unsupported-base]: Unsupported class base
|
||||
--> src/mdtest_snippet.py:27:13
|
||||
|
|
||||
25 | class C: ...
|
||||
26 |
|
||||
27 | class D(C): ... # error: [unsupported-base]
|
||||
| ^ Has type `<class 'mdtest_snippet.<locals of function 'f'>.C @ src/mdtest_snippet.py:23'> | <class 'mdtest_snippet.<locals of function 'f'>.C @ src/mdtest_snippet.py:25'>`
|
||||
|
|
||||
info: ty cannot resolve a consistent MRO for class `D` due to this base
|
||||
info: Only class objects or `Any` are supported as class bases
|
||||
info: rule `unsupported-base` is enabled by default
|
||||
|
||||
```
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ info: rule `invalid-base` is enabled by default
|
|||
```
|
||||
|
||||
```
|
||||
warning[unsupported-base]: Unsupported class base with type `Foo`
|
||||
warning[unsupported-base]: Unsupported class base
|
||||
--> src/mdtest_snippet.py:6:11
|
||||
|
|
||||
4 | return ()
|
||||
5 |
|
||||
6 | class Bar(Foo()): ... # error: [unsupported-base]
|
||||
| ^^^^^
|
||||
| ^^^^^ Has type `Foo`
|
||||
7 | class Bad1:
|
||||
8 | def __mro_entries__(self, bases, extra_arg):
|
||||
|
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: super.md - Super - Invalid Usages - Diagnostic when the invalid type is rendered very verbosely
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/class/super.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | def coinflip() -> bool:
|
||||
2 | return False
|
||||
3 |
|
||||
4 | def f():
|
||||
5 | if coinflip():
|
||||
6 | class A: ...
|
||||
7 | else:
|
||||
8 | class A: ...
|
||||
9 | super(A, A()) # error: [invalid-super-argument]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-super-argument]: Argument is not a valid class
|
||||
--> src/mdtest_snippet.py:9:5
|
||||
|
|
||||
7 | else:
|
||||
8 | class A: ...
|
||||
9 | super(A, A()) # error: [invalid-super-argument]
|
||||
| ^^^^^^^^^^^^^ Argument has type `<class 'mdtest_snippet.<locals of function 'f'>.A @ src/mdtest_snippet.py:6'> | <class 'mdtest_snippet.<locals of function 'f'>.A @ src/mdtest_snippet.py:8'>`
|
||||
|
|
||||
info: rule `invalid-super-argument` is enabled by default
|
||||
|
||||
```
|
||||
|
|
@ -76,15 +76,25 @@ impl<'db> BoundSuperError<'db> {
|
|||
BoundSuperError::InvalidPivotClassType { pivot_class } => {
|
||||
if let Some(builder) = context.report_lint(&INVALID_SUPER_ARGUMENT, node) {
|
||||
match pivot_class {
|
||||
Type::GenericAlias(alias) => builder.into_diagnostic(format_args!(
|
||||
"`types.GenericAlias` instance `{}` is not a valid class",
|
||||
alias.display_with(context.db(), DisplaySettings::default()),
|
||||
)),
|
||||
_ => builder.into_diagnostic(format_args!(
|
||||
"`{pivot_class}` is not a valid class",
|
||||
pivot_class = pivot_class.display(context.db()),
|
||||
)),
|
||||
};
|
||||
Type::GenericAlias(alias) => {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"`types.GenericAlias` instance `{}` is not a valid class",
|
||||
alias.display_with(context.db(), DisplaySettings::default()),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
let mut diagnostic =
|
||||
builder.into_diagnostic("Argument is not a valid class");
|
||||
diagnostic.set_primary_message(format_args!(
|
||||
"Argument has type `{}`",
|
||||
pivot_class.display(context.db())
|
||||
));
|
||||
diagnostic.set_concise_message(format_args!(
|
||||
"`{}` is not a valid class",
|
||||
pivot_class.display(context.db()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BoundSuperError::FailingConditionCheck {
|
||||
|
|
|
|||
|
|
@ -3478,13 +3478,16 @@ fn report_unsupported_base(
|
|||
let Some(builder) = context.report_lint(&UNSUPPORTED_BASE, base_node) else {
|
||||
return;
|
||||
};
|
||||
let mut diagnostic = builder.into_diagnostic(format_args!(
|
||||
let db = context.db();
|
||||
let mut diagnostic = builder.into_diagnostic("Unsupported class base");
|
||||
diagnostic.set_primary_message(format_args!("Has type `{}`", base_type.display(db)));
|
||||
diagnostic.set_concise_message(format_args!(
|
||||
"Unsupported class base with type `{}`",
|
||||
base_type.display(context.db())
|
||||
base_type.display(db)
|
||||
));
|
||||
diagnostic.info(format_args!(
|
||||
"ty cannot resolve a consistent MRO for class `{}` due to this base",
|
||||
class.name(context.db())
|
||||
class.name(db)
|
||||
));
|
||||
diagnostic.info("Only class objects or `Any` are supported as class bases");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue