mirror of https://github.com/astral-sh/ruff
[ty] Improve diagnostics when `NotImplemented` is called (#21523)
## Summary Fixes https://github.com/astral-sh/ty/issues/1571. I realised I was overcomplicating things when I described what we should do in that issue description. The simplest thing to do here is just to special-case call expressions and short-circuit the call-binding machinery entirely if we see it's `NotImplemented` being called. It doesn't really matter if the subdiagnostic doesn't fire when a union is called and one element of the union is `NotImplemented` -- the subdiagnostic doesn't need to be exhaustive; it's just to help people in some common cases. ## Test Plan Added snapshots
This commit is contained in:
parent
ce06094ada
commit
a8f7ccf2ca
|
|
@ -200,6 +200,9 @@ isinstance("", t.Any) # error: [invalid-argument-type]
|
|||
|
||||
## The builtin `NotImplemented` constant is not callable
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
NotImplemented() # error: [call-non-callable]
|
||||
raise NotImplemented() # error: [call-non-callable]
|
||||
raise NotImplemented("this module is not implemented yet!!!") # error: [call-non-callable]
|
||||
```
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: builtins.md - Calling builtins - The builtin `NotImplemented` constant is not callable
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/call/builtins.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | raise NotImplemented() # error: [call-non-callable]
|
||||
2 | raise NotImplemented("this module is not implemented yet!!!") # error: [call-non-callable]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[call-non-callable]: `NotImplemented` is not callable
|
||||
--> src/mdtest_snippet.py:1:7
|
||||
|
|
||||
1 | raise NotImplemented() # error: [call-non-callable]
|
||||
| --------------^^
|
||||
| |
|
||||
| Did you mean `NotImplementedError`?
|
||||
2 | raise NotImplemented("this module is not implemented yet!!!") # error: [call-non-callable]
|
||||
|
|
||||
info: rule `call-non-callable` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[call-non-callable]: `NotImplemented` is not callable
|
||||
--> src/mdtest_snippet.py:2:7
|
||||
|
|
||||
1 | raise NotImplemented() # error: [call-non-callable]
|
||||
2 | raise NotImplemented("this module is not implemented yet!!!") # error: [call-non-callable]
|
||||
| --------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| Did you mean `NotImplementedError`?
|
||||
|
|
||||
info: rule `call-non-callable` is enabled by default
|
||||
|
||||
```
|
||||
|
|
@ -7912,6 +7912,24 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
ty
|
||||
});
|
||||
|
||||
if callable_type.is_notimplemented(self.db()) {
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&CALL_NON_CALLABLE, call_expression)
|
||||
{
|
||||
let mut diagnostic = builder.into_diagnostic("`NotImplemented` is not callable");
|
||||
diagnostic.annotate(
|
||||
self.context
|
||||
.secondary(&**func)
|
||||
.message("Did you mean `NotImplementedError`?"),
|
||||
);
|
||||
diagnostic.set_concise_message(
|
||||
"`NotImplemented` is not callable - did you mean `NotImplementedError`?",
|
||||
);
|
||||
}
|
||||
return Type::unknown();
|
||||
}
|
||||
|
||||
// Special handling for `TypedDict` method calls
|
||||
if let ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
|
||||
let value_type = self.expression_type(value);
|
||||
|
|
|
|||
Loading…
Reference in New Issue