mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 12:55:05 +00:00
[red-knot] Prefix Type::call
and dunder_call
with try
(#16261)
This commit is contained in:
parent
16d0625dfb
commit
fb09d63e55
4 changed files with 50 additions and 87 deletions
|
@ -246,7 +246,6 @@ impl<'db> SemanticIndex<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
|
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
|
||||||
#[allow(unused)]
|
|
||||||
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter {
|
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter {
|
||||||
AncestorsIter::new(self, scope)
|
AncestorsIter::new(self, scope)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1468,7 +1468,7 @@ impl<'db> Type<'db> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(Type::BooleanLiteral(bool_val)) = bool_method
|
if let Ok(Type::BooleanLiteral(bool_val)) = bool_method
|
||||||
.call_bound(db, instance_ty, &CallArguments::positional([]))
|
.try_call_bound(db, instance_ty, &CallArguments::positional([]))
|
||||||
.map(|outcome| outcome.return_type(db))
|
.map(|outcome| outcome.return_type(db))
|
||||||
{
|
{
|
||||||
bool_val.into()
|
bool_val.into()
|
||||||
|
@ -1541,12 +1541,15 @@ impl<'db> Type<'db> {
|
||||||
return usize_len.try_into().ok().map(Type::IntLiteral);
|
return usize_len.try_into().ok().map(Type::IntLiteral);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_ty = match self.call_dunder(db, "__len__", &CallArguments::positional([*self])) {
|
let return_ty =
|
||||||
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => outcome.return_type(db),
|
match self.try_call_dunder(db, "__len__", &CallArguments::positional([*self])) {
|
||||||
|
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => {
|
||||||
|
outcome.return_type(db)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: emit a diagnostic
|
// TODO: emit a diagnostic
|
||||||
Err(err) => err.return_type(db)?,
|
Err(err) => err.return_type(db)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
non_negative_int_literal(db, return_ty)
|
non_negative_int_literal(db, return_ty)
|
||||||
}
|
}
|
||||||
|
@ -1554,7 +1557,7 @@ impl<'db> Type<'db> {
|
||||||
/// Calls `self`
|
/// Calls `self`
|
||||||
///
|
///
|
||||||
/// Returns `Ok` if the call with the given arguments is successful and `Err` otherwise.
|
/// Returns `Ok` if the call with the given arguments is successful and `Err` otherwise.
|
||||||
fn call(
|
fn try_call(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
arguments: &CallArguments<'_, 'db>,
|
arguments: &CallArguments<'_, 'db>,
|
||||||
|
@ -1672,7 +1675,7 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
instance_ty @ Type::Instance(_) => {
|
instance_ty @ Type::Instance(_) => {
|
||||||
instance_ty
|
instance_ty
|
||||||
.call_dunder(db, "__call__", &arguments.with_self(instance_ty))
|
.try_call_dunder(db, "__call__", &arguments.with_self(instance_ty))
|
||||||
.map_err(|err| match err {
|
.map_err(|err| match err {
|
||||||
CallDunderError::Call(CallError::NotCallable { .. }) => {
|
CallDunderError::Call(CallError::NotCallable { .. }) => {
|
||||||
// Turn "`<type of illegal '__call__'>` not callable" into
|
// Turn "`<type of illegal '__call__'>` not callable" into
|
||||||
|
@ -1712,7 +1715,7 @@ impl<'db> Type<'db> {
|
||||||
Type::Dynamic(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(self))),
|
Type::Dynamic(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(self))),
|
||||||
|
|
||||||
Type::Union(union) => {
|
Type::Union(union) => {
|
||||||
CallOutcome::try_call_union(db, union, |element| element.call(db, arguments))
|
CallOutcome::try_call_union(db, union, |element| element.try_call(db, arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
|
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
|
||||||
|
@ -1731,7 +1734,7 @@ impl<'db> Type<'db> {
|
||||||
/// `receiver_ty` must be `Type::Instance(_)` or `Type::ClassLiteral`.
|
/// `receiver_ty` must be `Type::Instance(_)` or `Type::ClassLiteral`.
|
||||||
///
|
///
|
||||||
/// TODO: handle `super()` objects properly
|
/// TODO: handle `super()` objects properly
|
||||||
fn call_bound(
|
fn try_call_bound(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
receiver_ty: &Type<'db>,
|
receiver_ty: &Type<'db>,
|
||||||
|
@ -1743,16 +1746,16 @@ impl<'db> Type<'db> {
|
||||||
Type::FunctionLiteral(..) => {
|
Type::FunctionLiteral(..) => {
|
||||||
// Functions are always descriptors, so this would effectively call
|
// Functions are always descriptors, so this would effectively call
|
||||||
// the function with the instance as the first argument
|
// the function with the instance as the first argument
|
||||||
self.call(db, &arguments.with_self(*receiver_ty))
|
self.try_call(db, &arguments.with_self(*receiver_ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Instance(_) | Type::ClassLiteral(_) => {
|
Type::Instance(_) | Type::ClassLiteral(_) => {
|
||||||
// TODO descriptor protocol. For now, assume non-descriptor and call without `self` argument.
|
// TODO descriptor protocol. For now, assume non-descriptor and call without `self` argument.
|
||||||
self.call(db, arguments)
|
self.try_call(db, arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Union(union) => CallOutcome::try_call_union(db, union, |element| {
|
Type::Union(union) => CallOutcome::try_call_union(db, union, |element| {
|
||||||
element.call_bound(db, receiver_ty, arguments)
|
element.try_call_bound(db, receiver_ty, arguments)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
|
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
|
||||||
|
@ -1769,16 +1772,16 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look up a dunder method on the meta type of `self` and call it.
|
/// Look up a dunder method on the meta type of `self` and call it.
|
||||||
fn call_dunder(
|
fn try_call_dunder(
|
||||||
self,
|
self,
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
name: &str,
|
name: &str,
|
||||||
arguments: &CallArguments<'_, 'db>,
|
arguments: &CallArguments<'_, 'db>,
|
||||||
) -> Result<CallOutcome<'db>, CallDunderError<'db>> {
|
) -> Result<CallOutcome<'db>, CallDunderError<'db>> {
|
||||||
match self.to_meta_type(db).member(db, name) {
|
match self.to_meta_type(db).member(db, name) {
|
||||||
Symbol::Type(callable_ty, Boundness::Bound) => Ok(callable_ty.call(db, arguments)?),
|
Symbol::Type(callable_ty, Boundness::Bound) => Ok(callable_ty.try_call(db, arguments)?),
|
||||||
Symbol::Type(callable_ty, Boundness::PossiblyUnbound) => {
|
Symbol::Type(callable_ty, Boundness::PossiblyUnbound) => {
|
||||||
let call = callable_ty.call(db, arguments)?;
|
let call = callable_ty.try_call(db, arguments)?;
|
||||||
Err(CallDunderError::PossiblyUnbound(call))
|
Err(CallDunderError::PossiblyUnbound(call))
|
||||||
}
|
}
|
||||||
Symbol::Unbound => Err(CallDunderError::MethodNotAvailable),
|
Symbol::Unbound => Err(CallDunderError::MethodNotAvailable),
|
||||||
|
@ -1801,12 +1804,12 @@ impl<'db> Type<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dunder_iter_result =
|
let dunder_iter_result =
|
||||||
self.call_dunder(db, "__iter__", &CallArguments::positional([self]));
|
self.try_call_dunder(db, "__iter__", &CallArguments::positional([self]));
|
||||||
match &dunder_iter_result {
|
match &dunder_iter_result {
|
||||||
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => {
|
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => {
|
||||||
let iterator_ty = outcome.return_type(db);
|
let iterator_ty = outcome.return_type(db);
|
||||||
|
|
||||||
return match iterator_ty.call_dunder(
|
return match iterator_ty.try_call_dunder(
|
||||||
db,
|
db,
|
||||||
"__next__",
|
"__next__",
|
||||||
&CallArguments::positional([iterator_ty]),
|
&CallArguments::positional([iterator_ty]),
|
||||||
|
@ -1855,7 +1858,7 @@ impl<'db> Type<'db> {
|
||||||
//
|
//
|
||||||
// TODO(Alex) this is only valid if the `__getitem__` method is annotated as
|
// TODO(Alex) this is only valid if the `__getitem__` method is annotated as
|
||||||
// accepting `int` or `SupportsIndex`
|
// accepting `int` or `SupportsIndex`
|
||||||
match self.call_dunder(
|
match self.try_call_dunder(
|
||||||
db,
|
db,
|
||||||
"__getitem__",
|
"__getitem__",
|
||||||
&CallArguments::positional([self, KnownClass::Int.to_instance(db)]),
|
&CallArguments::positional([self, KnownClass::Int.to_instance(db)]),
|
||||||
|
@ -2693,52 +2696,8 @@ pub enum KnownInstanceType<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> KnownInstanceType<'db> {
|
impl<'db> KnownInstanceType<'db> {
|
||||||
pub const fn as_str(self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Annotated => "Annotated",
|
|
||||||
Self::Literal => "Literal",
|
|
||||||
Self::LiteralString => "LiteralString",
|
|
||||||
Self::Optional => "Optional",
|
|
||||||
Self::Union => "Union",
|
|
||||||
Self::TypeVar(_) => "TypeVar",
|
|
||||||
Self::NoReturn => "NoReturn",
|
|
||||||
Self::Never => "Never",
|
|
||||||
Self::Any => "Any",
|
|
||||||
Self::Tuple => "Tuple",
|
|
||||||
Self::Type => "Type",
|
|
||||||
Self::TypeAliasType(_) => "TypeAliasType",
|
|
||||||
Self::TypingSelf => "Self",
|
|
||||||
Self::Final => "Final",
|
|
||||||
Self::ClassVar => "ClassVar",
|
|
||||||
Self::Callable => "Callable",
|
|
||||||
Self::Concatenate => "Concatenate",
|
|
||||||
Self::Unpack => "Unpack",
|
|
||||||
Self::Required => "Required",
|
|
||||||
Self::NotRequired => "NotRequired",
|
|
||||||
Self::TypeAlias => "TypeAlias",
|
|
||||||
Self::TypeGuard => "TypeGuard",
|
|
||||||
Self::TypeIs => "TypeIs",
|
|
||||||
Self::List => "List",
|
|
||||||
Self::Dict => "Dict",
|
|
||||||
Self::DefaultDict => "DefaultDict",
|
|
||||||
Self::Set => "Set",
|
|
||||||
Self::FrozenSet => "FrozenSet",
|
|
||||||
Self::Counter => "Counter",
|
|
||||||
Self::Deque => "Deque",
|
|
||||||
Self::ChainMap => "ChainMap",
|
|
||||||
Self::OrderedDict => "OrderedDict",
|
|
||||||
Self::ReadOnly => "ReadOnly",
|
|
||||||
Self::Unknown => "Unknown",
|
|
||||||
Self::AlwaysTruthy => "AlwaysTruthy",
|
|
||||||
Self::AlwaysFalsy => "AlwaysFalsy",
|
|
||||||
Self::Not => "Not",
|
|
||||||
Self::Intersection => "Intersection",
|
|
||||||
Self::TypeOf => "TypeOf",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate the known instance in boolean context
|
/// Evaluate the known instance in boolean context
|
||||||
pub const fn bool(self) -> Truthiness {
|
pub(crate) const fn bool(self) -> Truthiness {
|
||||||
match self {
|
match self {
|
||||||
Self::Annotated
|
Self::Annotated
|
||||||
| Self::Literal
|
| Self::Literal
|
||||||
|
@ -2783,7 +2742,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the repr of the symbol at runtime
|
/// Return the repr of the symbol at runtime
|
||||||
pub fn repr(self, db: &'db dyn Db) -> &'db str {
|
pub(crate) fn repr(self, db: &'db dyn Db) -> &'db str {
|
||||||
match self {
|
match self {
|
||||||
Self::Annotated => "typing.Annotated",
|
Self::Annotated => "typing.Annotated",
|
||||||
Self::Literal => "typing.Literal",
|
Self::Literal => "typing.Literal",
|
||||||
|
@ -2828,7 +2787,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the [`KnownClass`] which this symbol is an instance of
|
/// Return the [`KnownClass`] which this symbol is an instance of
|
||||||
pub const fn class(self) -> KnownClass {
|
pub(crate) const fn class(self) -> KnownClass {
|
||||||
match self {
|
match self {
|
||||||
Self::Annotated => KnownClass::SpecialForm,
|
Self::Annotated => KnownClass::SpecialForm,
|
||||||
Self::Literal => KnownClass::SpecialForm,
|
Self::Literal => KnownClass::SpecialForm,
|
||||||
|
@ -2877,16 +2836,20 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
/// For example, the symbol `typing.Literal` is an instance of `typing._SpecialForm`,
|
/// For example, the symbol `typing.Literal` is an instance of `typing._SpecialForm`,
|
||||||
/// so `KnownInstanceType::Literal.instance_fallback(db)`
|
/// so `KnownInstanceType::Literal.instance_fallback(db)`
|
||||||
/// returns `Type::Instance(InstanceType { class: <typing._SpecialForm> })`.
|
/// returns `Type::Instance(InstanceType { class: <typing._SpecialForm> })`.
|
||||||
pub fn instance_fallback(self, db: &dyn Db) -> Type {
|
pub(crate) fn instance_fallback(self, db: &dyn Db) -> Type {
|
||||||
self.class().to_instance(db)
|
self.class().to_instance(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if this symbol is an instance of `class`.
|
/// Return `true` if this symbol is an instance of `class`.
|
||||||
pub fn is_instance_of(self, db: &'db dyn Db, class: Class<'db>) -> bool {
|
pub(crate) fn is_instance_of(self, db: &'db dyn Db, class: Class<'db>) -> bool {
|
||||||
self.class().is_subclass_of(db, class)
|
self.class().is_subclass_of(db, class)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_from_file_and_name(db: &'db dyn Db, file: File, symbol_name: &str) -> Option<Self> {
|
pub(crate) fn try_from_file_and_name(
|
||||||
|
db: &'db dyn Db,
|
||||||
|
file: File,
|
||||||
|
symbol_name: &str,
|
||||||
|
) -> Option<Self> {
|
||||||
let candidate = match symbol_name {
|
let candidate = match symbol_name {
|
||||||
"Any" => Self::Any,
|
"Any" => Self::Any,
|
||||||
"ClassVar" => Self::ClassVar,
|
"ClassVar" => Self::ClassVar,
|
||||||
|
@ -2937,7 +2900,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
///
|
///
|
||||||
/// Most variants can only exist in one module, which is the same as `self.class().canonical_module()`.
|
/// Most variants can only exist in one module, which is the same as `self.class().canonical_module()`.
|
||||||
/// Some variants could validly be defined in either `typing` or `typing_extensions`, however.
|
/// Some variants could validly be defined in either `typing` or `typing_extensions`, however.
|
||||||
pub fn check_module(self, module: KnownModule) -> bool {
|
pub(crate) fn check_module(self, module: KnownModule) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Any
|
Self::Any
|
||||||
| Self::ClassVar
|
| Self::ClassVar
|
||||||
|
@ -3668,7 +3631,7 @@ impl<'db> Class<'db> {
|
||||||
// TODO: Other keyword arguments?
|
// TODO: Other keyword arguments?
|
||||||
let arguments = CallArguments::positional([name, bases, namespace]);
|
let arguments = CallArguments::positional([name, bases, namespace]);
|
||||||
|
|
||||||
let return_ty_result = match metaclass.call(db, &arguments) {
|
let return_ty_result = match metaclass.try_call(db, &arguments) {
|
||||||
Ok(outcome) => Ok(outcome.return_type(db)),
|
Ok(outcome) => Ok(outcome.return_type(db)),
|
||||||
|
|
||||||
Err(CallError::NotCallable { not_callable_ty }) => Err(MetaclassError {
|
Err(CallError::NotCallable { not_callable_ty }) => Err(MetaclassError {
|
||||||
|
|
|
@ -1616,7 +1616,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_ty = enter_ty
|
let target_ty = enter_ty
|
||||||
.call(self.db(), &CallArguments::positional([context_expression_ty]))
|
.try_call(self.db(), &CallArguments::positional([context_expression_ty]))
|
||||||
.map(|outcome| outcome.return_type(self.db()))
|
.map(|outcome| outcome.return_type(self.db()))
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
// TODO: Use more specific error messages for the different error cases.
|
// TODO: Use more specific error messages for the different error cases.
|
||||||
|
@ -1659,7 +1659,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if exit_ty
|
if exit_ty
|
||||||
.call(
|
.try_call(
|
||||||
self.db(),
|
self.db(),
|
||||||
&CallArguments::positional([
|
&CallArguments::positional([
|
||||||
context_manager_ty,
|
context_manager_ty,
|
||||||
|
@ -2209,7 +2209,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
if let Symbol::Type(class_member, boundness) =
|
if let Symbol::Type(class_member, boundness) =
|
||||||
class.class_member(self.db(), op.in_place_dunder())
|
class.class_member(self.db(), op.in_place_dunder())
|
||||||
{
|
{
|
||||||
let call = class_member.call(
|
let call = class_member.try_call(
|
||||||
self.db(),
|
self.db(),
|
||||||
&CallArguments::positional([target_type, value_type]),
|
&CallArguments::positional([target_type, value_type]),
|
||||||
);
|
);
|
||||||
|
@ -3247,7 +3247,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let call_arguments = self.infer_arguments(arguments, parameter_expectations);
|
let call_arguments = self.infer_arguments(arguments, parameter_expectations);
|
||||||
let call = function_type.call(self.db(), &call_arguments);
|
let call = function_type.try_call(self.db(), &call_arguments);
|
||||||
|
|
||||||
match call {
|
match call {
|
||||||
Ok(outcome) => {
|
Ok(outcome) => {
|
||||||
|
@ -3747,7 +3747,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match operand_type.call_dunder(
|
match operand_type.try_call_dunder(
|
||||||
self.db(),
|
self.db(),
|
||||||
unary_dunder_method,
|
unary_dunder_method,
|
||||||
&CallArguments::positional([operand_type]),
|
&CallArguments::positional([operand_type]),
|
||||||
|
@ -3996,7 +3996,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
&& rhs_reflected != left_class.member(self.db(), reflected_dunder)
|
&& rhs_reflected != left_class.member(self.db(), reflected_dunder)
|
||||||
{
|
{
|
||||||
return right_ty
|
return right_ty
|
||||||
.call_dunder(
|
.try_call_dunder(
|
||||||
self.db(),
|
self.db(),
|
||||||
reflected_dunder,
|
reflected_dunder,
|
||||||
&CallArguments::positional([right_ty, left_ty]),
|
&CallArguments::positional([right_ty, left_ty]),
|
||||||
|
@ -4004,7 +4004,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
.map(|outcome| outcome.return_type(self.db()))
|
.map(|outcome| outcome.return_type(self.db()))
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
left_ty
|
left_ty
|
||||||
.call_dunder(
|
.try_call_dunder(
|
||||||
self.db(),
|
self.db(),
|
||||||
op.dunder(),
|
op.dunder(),
|
||||||
&CallArguments::positional([left_ty, right_ty]),
|
&CallArguments::positional([left_ty, right_ty]),
|
||||||
|
@ -4020,7 +4020,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
left_class.member(self.db(), op.dunder())
|
left_class.member(self.db(), op.dunder())
|
||||||
{
|
{
|
||||||
class_member
|
class_member
|
||||||
.call(self.db(), &CallArguments::positional([left_ty, right_ty]))
|
.try_call(self.db(), &CallArguments::positional([left_ty, right_ty]))
|
||||||
.map(|outcome| outcome.return_type(self.db()))
|
.map(|outcome| outcome.return_type(self.db()))
|
||||||
.ok()
|
.ok()
|
||||||
} else {
|
} else {
|
||||||
|
@ -4036,7 +4036,10 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
{
|
{
|
||||||
// TODO: Use `call_dunder`
|
// TODO: Use `call_dunder`
|
||||||
class_member
|
class_member
|
||||||
.call(self.db(), &CallArguments::positional([right_ty, left_ty]))
|
.try_call(
|
||||||
|
self.db(),
|
||||||
|
&CallArguments::positional([right_ty, left_ty]),
|
||||||
|
)
|
||||||
.map(|outcome| outcome.return_type(self.db()))
|
.map(|outcome| outcome.return_type(self.db()))
|
||||||
.ok()
|
.ok()
|
||||||
} else {
|
} else {
|
||||||
|
@ -4610,7 +4613,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
// TODO: How do we want to handle possibly unbound dunder methods?
|
// TODO: How do we want to handle possibly unbound dunder methods?
|
||||||
match left.class.class_member(db, op.dunder()) {
|
match left.class.class_member(db, op.dunder()) {
|
||||||
Symbol::Type(class_member_dunder, Boundness::Bound) => class_member_dunder
|
Symbol::Type(class_member_dunder, Boundness::Bound) => class_member_dunder
|
||||||
.call(
|
.try_call(
|
||||||
db,
|
db,
|
||||||
&CallArguments::positional([Type::Instance(left), Type::Instance(right)]),
|
&CallArguments::positional([Type::Instance(left), Type::Instance(right)]),
|
||||||
)
|
)
|
||||||
|
@ -4660,7 +4663,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
Symbol::Type(contains_dunder, Boundness::Bound) => {
|
Symbol::Type(contains_dunder, Boundness::Bound) => {
|
||||||
// If `__contains__` is available, it is used directly for the membership test.
|
// If `__contains__` is available, it is used directly for the membership test.
|
||||||
contains_dunder
|
contains_dunder
|
||||||
.call(
|
.try_call(
|
||||||
db,
|
db,
|
||||||
&CallArguments::positional([Type::Instance(right), Type::Instance(left)]),
|
&CallArguments::positional([Type::Instance(right), Type::Instance(left)]),
|
||||||
)
|
)
|
||||||
|
@ -4917,7 +4920,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
// If the class defines `__getitem__`, return its return type.
|
// If the class defines `__getitem__`, return its return type.
|
||||||
//
|
//
|
||||||
// See: https://docs.python.org/3/reference/datamodel.html#class-getitem-versus-getitem
|
// See: https://docs.python.org/3/reference/datamodel.html#class-getitem-versus-getitem
|
||||||
match value_ty.call_dunder(
|
match value_ty.try_call_dunder(
|
||||||
self.db(),
|
self.db(),
|
||||||
"__getitem__",
|
"__getitem__",
|
||||||
&CallArguments::positional([value_ty, slice_ty]),
|
&CallArguments::positional([value_ty, slice_ty]),
|
||||||
|
@ -4981,7 +4984,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ty
|
return ty
|
||||||
.call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
|
.try_call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
|
||||||
.map(|outcome| outcome.return_type(self.db()))
|
.map(|outcome| outcome.return_type(self.db()))
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
self.context.report_lint(
|
self.context.report_lint(
|
||||||
|
|
|
@ -74,7 +74,6 @@ mod tests {
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
/// If there are pending database snapshots.
|
/// If there are pending database snapshots.
|
||||||
#[allow(unused)]
|
|
||||||
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
|
||||||
let inner = Arc::get_mut(&mut self.events)
|
let inner = Arc::get_mut(&mut self.events)
|
||||||
.expect("expected no pending salsa database snapshots.");
|
.expect("expected no pending salsa database snapshots.");
|
||||||
|
@ -86,7 +85,6 @@ mod tests {
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
/// If there are pending database snapshots.
|
/// If there are pending database snapshots.
|
||||||
#[allow(unused)]
|
|
||||||
pub(crate) fn clear_salsa_events(&mut self) {
|
pub(crate) fn clear_salsa_events(&mut self) {
|
||||||
self.take_salsa_events();
|
self.take_salsa_events();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue