[ty] Rename call-possibly-unbound-method to possibly-unbound-implicit-call (#18017)

This commit is contained in:
InSync 2025-05-22 22:25:51 +07:00 committed by GitHub
parent 91b7a570c2
commit bcefa459f4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 127 additions and 101 deletions

View file

@ -158,10 +158,10 @@ def _(flag: bool) -> None:
def __new__(cls):
return object.__new__(cls)
# error: [call-possibly-unbound-method]
# error: [possibly-unbound-implicit-call]
reveal_type(Foo()) # revealed: Foo
# error: [call-possibly-unbound-method]
# error: [possibly-unbound-implicit-call]
# error: [too-many-positional-arguments]
reveal_type(Foo(1)) # revealed: Foo
```

View file

@ -112,7 +112,7 @@ def _(flag: bool):
this_fails = ThisFails()
# error: [call-possibly-unbound-method]
# error: [possibly-unbound-implicit-call]
reveal_type(this_fails[0]) # revealed: Unknown | str
```
@ -236,6 +236,6 @@ def _(flag: bool):
return str(key)
c = C()
# error: [call-possibly-unbound-method]
# error: [possibly-unbound-implicit-call]
reveal_type(c[0]) # revealed: str
```

View file

@ -63,7 +63,7 @@ def _(flag: bool):
else:
class Spam: ...
# error: [call-possibly-unbound-method] "Method `__class_getitem__` of type `<class 'Spam'> | <class 'Spam'>` is possibly unbound"
# error: [possibly-unbound-implicit-call] "Method `__class_getitem__` of type `<class 'Spam'> | <class 'Spam'>` is possibly unbound"
# revealed: str
reveal_type(Spam[42])
```

View file

@ -8,7 +8,7 @@ use bitflags::bitflags;
use call::{CallDunderError, CallError, CallErrorKind};
use context::InferContext;
use diagnostic::{
CALL_POSSIBLY_UNBOUND_METHOD, INVALID_CONTEXT_MANAGER, INVALID_SUPER_ARGUMENT, NOT_ITERABLE,
INVALID_CONTEXT_MANAGER, INVALID_SUPER_ARGUMENT, NOT_ITERABLE, POSSIBLY_UNBOUND_IMPLICIT_CALL,
UNAVAILABLE_IMPLICIT_SUPER_ARGUMENTS,
};
use ruff_db::diagnostic::{
@ -6652,7 +6652,7 @@ impl<'db> ConstructorCallError<'db> {
let report_init_error = |call_dunder_error: &CallDunderError<'db>| match call_dunder_error {
CallDunderError::MethodNotAvailable => {
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
context.report_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL, context_expression_node)
{
// If we are using vendored typeshed, it should be impossible to have missing
// or unbound `__init__` method on a class, as all classes have `object` in MRO.
@ -6666,7 +6666,7 @@ impl<'db> ConstructorCallError<'db> {
}
CallDunderError::PossiblyUnbound(bindings) => {
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
context.report_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL, context_expression_node)
{
builder.into_diagnostic(format_args!(
"Method `__init__` on type `{}` is possibly unbound.",
@ -6684,7 +6684,7 @@ impl<'db> ConstructorCallError<'db> {
let report_new_error = |error: &DunderNewCallError<'db>| match error {
DunderNewCallError::PossiblyUnbound(call_error) => {
if let Some(builder) =
context.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, context_expression_node)
context.report_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL, context_expression_node)
{
builder.into_diagnostic(format_args!(
"Method `__new__` on type `{}` is possibly unbound.",

View file

@ -24,7 +24,7 @@ use std::fmt::Formatter;
/// Registers all known type check lints.
pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
registry.register_lint(&CALL_NON_CALLABLE);
registry.register_lint(&CALL_POSSIBLY_UNBOUND_METHOD);
registry.register_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL);
registry.register_lint(&CONFLICTING_ARGUMENT_FORMS);
registry.register_lint(&CONFLICTING_DECLARATIONS);
registry.register_lint(&CONFLICTING_METACLASS);
@ -107,12 +107,25 @@ declare_lint! {
declare_lint! {
/// ## What it does
/// Checks for calls to possibly unbound methods.
/// Checks for implicit calls to possibly unbound methods.
///
/// ## Why is this bad?
/// Expressions such as `x[y]` and `x * y` call methods
/// under the hood (`__getitem__` and `__mul__` respectively).
/// Calling an unbound method will raise an `AttributeError` at runtime.
pub(crate) static CALL_POSSIBLY_UNBOUND_METHOD = {
summary: "detects calls to possibly unbound methods",
///
/// ## Examples
/// ```python
/// import datetime
///
/// class A:
/// if datetime.date.today().weekday() != 6:
/// def __getitem__(self, v): ...
///
/// A()[0] # TypeError: 'A' object is not subscriptable
/// ```
pub(crate) static POSSIBLY_UNBOUND_IMPLICIT_CALL = {
summary: "detects implicit calls to possibly unbound methods",
status: LintStatus::preview("1.0.0"),
default_level: Level::Warn,
}

View file

@ -67,12 +67,12 @@ use crate::symbol::{
use crate::types::call::{Argument, Bindings, CallArgumentTypes, CallArguments, CallError};
use crate::types::class::{MetaclassErrorKind, SliceLiteral};
use crate::types::diagnostic::{
self, CALL_NON_CALLABLE, CALL_POSSIBLY_UNBOUND_METHOD, CONFLICTING_DECLARATIONS,
CONFLICTING_METACLASS, CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, INCONSISTENT_MRO,
INVALID_ARGUMENT_TYPE, INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE,
INVALID_DECLARATION, INVALID_GENERIC_CLASS, INVALID_LEGACY_TYPE_VARIABLE,
INVALID_PARAMETER_DEFAULT, INVALID_TYPE_ALIAS_TYPE, INVALID_TYPE_FORM,
INVALID_TYPE_VARIABLE_CONSTRAINTS, POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics,
self, CALL_NON_CALLABLE, CONFLICTING_DECLARATIONS, CONFLICTING_METACLASS,
CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, INCONSISTENT_MRO, INVALID_ARGUMENT_TYPE,
INVALID_ASSIGNMENT, INVALID_ATTRIBUTE_ACCESS, INVALID_BASE, INVALID_DECLARATION,
INVALID_GENERIC_CLASS, INVALID_LEGACY_TYPE_VARIABLE, INVALID_PARAMETER_DEFAULT,
INVALID_TYPE_ALIAS_TYPE, INVALID_TYPE_FORM, INVALID_TYPE_VARIABLE_CONSTRAINTS,
POSSIBLY_UNBOUND_IMPLICIT_CALL, POSSIBLY_UNBOUND_IMPORT, TypeCheckDiagnostics,
UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE, UNRESOLVED_IMPORT, UNSUPPORTED_OPERATOR,
report_implicit_return_type, report_invalid_arguments_to_annotated,
report_invalid_arguments_to_callable, report_invalid_assignment,
@ -7428,7 +7428,7 @@ impl<'db> TypeInferenceBuilder<'db> {
Err(err @ CallDunderError::PossiblyUnbound { .. }) => {
if let Some(builder) = self
.context
.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, value_node)
.report_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL, value_node)
{
builder.into_diagnostic(format_args!(
"Method `__getitem__` of type `{}` is possibly unbound",
@ -7476,7 +7476,7 @@ impl<'db> TypeInferenceBuilder<'db> {
if boundness == Boundness::PossiblyUnbound {
if let Some(builder) = self
.context
.report_lint(&CALL_POSSIBLY_UNBOUND_METHOD, value_node)
.report_lint(&POSSIBLY_UNBOUND_IMPLICIT_CALL, value_node)
{
builder.into_diagnostic(format_args!(
"Method `__class_getitem__` of type `{}` \