Compare commits
2 Commits
micha/rele
...
micha/remo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df9847cce4 | ||
|
|
49302911c4 |
@@ -36,7 +36,7 @@ use crate::stdlib::{builtins_symbol, known_module_symbol, typing_extensions_symb
|
||||
use crate::suppression::check_suppressions;
|
||||
use crate::symbol::{Boundness, Symbol};
|
||||
use crate::types::call::{
|
||||
bind_call, CallArguments, CallBinding, CallDunderResult, CallOutcome, StaticAssertionErrorKind,
|
||||
bind_call, CallArguments, CallBinding, CallDunderOutcome, CallOutcome, StaticAssertionErrorKind,
|
||||
};
|
||||
use crate::types::class_base::ClassBase;
|
||||
use crate::types::diagnostic::INVALID_TYPE_FORM;
|
||||
@@ -1927,11 +1927,9 @@ impl<'db> Type<'db> {
|
||||
|
||||
let return_ty = match self.call_dunder(db, "__len__", &CallArguments::positional([*self])) {
|
||||
// TODO: emit a diagnostic
|
||||
CallDunderResult::MethodNotAvailable => return None,
|
||||
CallDunderOutcome::MethodNotAvailable => return None,
|
||||
|
||||
CallDunderResult::CallOutcome(outcome) | CallDunderResult::PossiblyUnbound(outcome) => {
|
||||
outcome.return_type(db)?
|
||||
}
|
||||
CallDunderOutcome::Call(outcome) => outcome.return_type(db)?,
|
||||
};
|
||||
|
||||
non_negative_int_literal(db, return_ty)
|
||||
@@ -2101,23 +2099,26 @@ impl<'db> Type<'db> {
|
||||
|
||||
instance_ty @ Type::Instance(_) => {
|
||||
match instance_ty.call_dunder(db, "__call__", &arguments.with_self(instance_ty)) {
|
||||
CallDunderResult::CallOutcome(CallOutcome::NotCallable { .. }) => {
|
||||
CallDunderOutcome::Call(CallOutcome::NotCallable { .. }) => {
|
||||
// Turn "`<type of illegal '__call__'>` not callable" into
|
||||
// "`X` not callable"
|
||||
CallOutcome::NotCallable {
|
||||
not_callable_ty: self,
|
||||
}
|
||||
}
|
||||
CallDunderResult::CallOutcome(outcome) => outcome,
|
||||
CallDunderResult::PossiblyUnbound(call_outcome) => {
|
||||
CallDunderOutcome::Call(outcome) => match outcome {
|
||||
// Turn "possibly unbound object of type `Literal['__call__']`"
|
||||
// into "`X` not callable (possibly unbound `__call__` method)"
|
||||
CallOutcome::PossiblyUnboundDunderCall {
|
||||
called_ty: self,
|
||||
call_outcome: Box::new(call_outcome),
|
||||
CallOutcome::PossiblyUnboundDunder { call_outcome, .. } => {
|
||||
CallOutcome::PossiblyUnboundDunder {
|
||||
called_ty: self,
|
||||
call_outcome,
|
||||
}
|
||||
}
|
||||
}
|
||||
CallDunderResult::MethodNotAvailable => {
|
||||
outcome => outcome,
|
||||
},
|
||||
|
||||
CallDunderOutcome::MethodNotAvailable => {
|
||||
// Turn "`X.__call__` unbound" into "`X` not callable"
|
||||
CallOutcome::NotCallable {
|
||||
not_callable_ty: self,
|
||||
@@ -2197,15 +2198,20 @@ impl<'db> Type<'db> {
|
||||
db: &'db dyn Db,
|
||||
name: &str,
|
||||
arguments: &CallArguments<'_, 'db>,
|
||||
) -> CallDunderResult<'db> {
|
||||
) -> CallDunderOutcome<'db> {
|
||||
match self.to_meta_type(db).member(db, name) {
|
||||
Symbol::Type(callable_ty, Boundness::Bound) => {
|
||||
CallDunderResult::CallOutcome(callable_ty.call(db, arguments))
|
||||
CallDunderOutcome::Call(callable_ty.call(db, arguments))
|
||||
}
|
||||
|
||||
Symbol::Type(callable_ty, Boundness::PossiblyUnbound) => {
|
||||
CallDunderResult::PossiblyUnbound(callable_ty.call(db, arguments))
|
||||
CallDunderOutcome::Call(CallOutcome::PossiblyUnboundDunder {
|
||||
called_ty: self,
|
||||
call_outcome: Box::new(callable_ty.call(db, arguments)),
|
||||
})
|
||||
}
|
||||
Symbol::Unbound => CallDunderResult::MethodNotAvailable,
|
||||
|
||||
Symbol::Unbound => CallDunderOutcome::MethodNotAvailable,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2227,8 +2233,7 @@ impl<'db> Type<'db> {
|
||||
let dunder_iter_result =
|
||||
self.call_dunder(db, "__iter__", &CallArguments::positional([self]));
|
||||
match dunder_iter_result {
|
||||
CallDunderResult::CallOutcome(ref call_outcome)
|
||||
| CallDunderResult::PossiblyUnbound(ref call_outcome) => {
|
||||
CallDunderOutcome::Call(ref call_outcome) => {
|
||||
let Some(iterator_ty) = call_outcome.return_type(db) else {
|
||||
return IterationOutcome::NotIterable {
|
||||
not_iterable_ty: self,
|
||||
@@ -2239,7 +2244,7 @@ impl<'db> Type<'db> {
|
||||
.call_dunder(db, "__next__", &CallArguments::positional([iterator_ty]))
|
||||
.return_type(db)
|
||||
{
|
||||
if matches!(dunder_iter_result, CallDunderResult::PossiblyUnbound(..)) {
|
||||
if call_outcome.is_possibly_unbound_dunder() {
|
||||
IterationOutcome::PossiblyUnboundDunderIter {
|
||||
iterable_ty: self,
|
||||
element_ty,
|
||||
@@ -2253,7 +2258,7 @@ impl<'db> Type<'db> {
|
||||
}
|
||||
};
|
||||
}
|
||||
CallDunderResult::MethodNotAvailable => {}
|
||||
CallDunderOutcome::MethodNotAvailable => {}
|
||||
}
|
||||
|
||||
// Although it's not considered great practice,
|
||||
@@ -4068,7 +4073,7 @@ impl<'db> Class<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
CallOutcome::PossiblyUnboundDunderCall { called_ty, .. } => Err(MetaclassError {
|
||||
CallOutcome::PossiblyUnboundDunder { called_ty, .. } => Err(MetaclassError {
|
||||
kind: MetaclassErrorKind::PartlyNotCallable(called_ty),
|
||||
}),
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(super) enum CallOutcome<'db> {
|
||||
called_ty: Type<'db>,
|
||||
outcomes: Box<[CallOutcome<'db>]>,
|
||||
},
|
||||
PossiblyUnboundDunderCall {
|
||||
PossiblyUnboundDunder {
|
||||
called_ty: Type<'db>,
|
||||
call_outcome: Box<CallOutcome<'db>>,
|
||||
},
|
||||
@@ -88,6 +88,10 @@ impl<'db> CallOutcome<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const fn is_possibly_unbound_dunder(&self) -> bool {
|
||||
matches!(self, Self::PossiblyUnboundDunder { .. })
|
||||
}
|
||||
|
||||
/// Get the return type of the call, or `None` if not callable.
|
||||
pub(super) fn return_type(&self, db: &'db dyn Db) -> Option<Type<'db>> {
|
||||
match self {
|
||||
@@ -113,7 +117,7 @@ impl<'db> CallOutcome<'db> {
|
||||
}
|
||||
})
|
||||
.map(UnionBuilder::build),
|
||||
Self::PossiblyUnboundDunderCall { call_outcome, .. } => call_outcome.return_type(db),
|
||||
Self::PossiblyUnboundDunder { call_outcome, .. } => call_outcome.return_type(db),
|
||||
Self::StaticAssertionError { .. } => Some(Type::none(db)),
|
||||
Self::AssertType {
|
||||
binding,
|
||||
@@ -224,7 +228,7 @@ impl<'db> CallOutcome<'db> {
|
||||
not_callable_ty: *not_callable_ty,
|
||||
return_ty: Type::unknown(),
|
||||
}),
|
||||
Self::PossiblyUnboundDunderCall {
|
||||
Self::PossiblyUnboundDunder {
|
||||
called_ty,
|
||||
call_outcome,
|
||||
} => Err(NotCallableError::PossiblyUnboundDunderCall {
|
||||
@@ -351,17 +355,22 @@ impl<'db> CallOutcome<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) enum CallDunderResult<'db> {
|
||||
CallOutcome(CallOutcome<'db>),
|
||||
PossiblyUnbound(CallOutcome<'db>),
|
||||
pub(super) enum CallDunderOutcome<'db> {
|
||||
Call(CallOutcome<'db>),
|
||||
MethodNotAvailable,
|
||||
}
|
||||
|
||||
impl<'db> CallDunderResult<'db> {
|
||||
impl<'db> CallDunderOutcome<'db> {
|
||||
pub(super) fn return_type(&self, db: &'db dyn Db) -> Option<Type<'db>> {
|
||||
match self {
|
||||
Self::CallOutcome(outcome) => outcome.return_type(db),
|
||||
Self::PossiblyUnbound { .. } => None,
|
||||
Self::Call(outcome) => {
|
||||
// TODO: Always call `outcome.return_type`, see https://github.com/astral-sh/ruff/issues/16123
|
||||
if outcome.is_possibly_unbound_dunder() {
|
||||
None
|
||||
} else {
|
||||
outcome.return_type(db)
|
||||
}
|
||||
}
|
||||
Self::MethodNotAvailable => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ use crate::types::mro::MroErrorKind;
|
||||
use crate::types::unpacker::{UnpackResult, Unpacker};
|
||||
use crate::types::{
|
||||
builtins_symbol, global_symbol, symbol, symbol_from_bindings, symbol_from_declarations,
|
||||
todo_type, typing_extensions_symbol, Boundness, CallDunderResult, Class, ClassLiteralType,
|
||||
todo_type, typing_extensions_symbol, Boundness, CallDunderOutcome, Class, ClassLiteralType,
|
||||
DynamicType, FunctionType, InstanceType, IntersectionBuilder, IntersectionType,
|
||||
IterationOutcome, KnownClass, KnownFunction, KnownInstanceType, MetaclassCandidate,
|
||||
MetaclassErrorKind, SliceLiteralType, SubclassOfType, Symbol, SymbolAndQualifiers, Truthiness,
|
||||
@@ -3567,8 +3567,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
}
|
||||
};
|
||||
|
||||
if let CallDunderResult::CallOutcome(call)
|
||||
| CallDunderResult::PossiblyUnbound(call) = operand_type.call_dunder(
|
||||
if let CallDunderOutcome::Call(call) = operand_type.call_dunder(
|
||||
self.db(),
|
||||
unary_dunder_method,
|
||||
&CallArguments::positional([operand_type]),
|
||||
|
||||
Reference in New Issue
Block a user