Skip to content

Commit fb09d63

Browse files
authored
[red-knot] Prefix Type::call and dunder_call with try (#16261)
1 parent 16d0625 commit fb09d63

File tree

4 files changed

+50
-87
lines changed

4 files changed

+50
-87
lines changed

crates/red_knot_python_semantic/src/semantic_index.rs

-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ impl<'db> SemanticIndex<'db> {
246246
}
247247

248248
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
249-
#[allow(unused)]
250249
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter {
251250
AncestorsIter::new(self, scope)
252251
}

crates/red_knot_python_semantic/src/types.rs

+34-71
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ impl<'db> Type<'db> {
14681468
};
14691469

14701470
if let Ok(Type::BooleanLiteral(bool_val)) = bool_method
1471-
.call_bound(db, instance_ty, &CallArguments::positional([]))
1471+
.try_call_bound(db, instance_ty, &CallArguments::positional([]))
14721472
.map(|outcome| outcome.return_type(db))
14731473
{
14741474
bool_val.into()
@@ -1541,20 +1541,23 @@ impl<'db> Type<'db> {
15411541
return usize_len.try_into().ok().map(Type::IntLiteral);
15421542
}
15431543

1544-
let return_ty = match self.call_dunder(db, "__len__", &CallArguments::positional([*self])) {
1545-
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => outcome.return_type(db),
1544+
let return_ty =
1545+
match self.try_call_dunder(db, "__len__", &CallArguments::positional([*self])) {
1546+
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => {
1547+
outcome.return_type(db)
1548+
}
15461549

1547-
// TODO: emit a diagnostic
1548-
Err(err) => err.return_type(db)?,
1549-
};
1550+
// TODO: emit a diagnostic
1551+
Err(err) => err.return_type(db)?,
1552+
};
15501553

15511554
non_negative_int_literal(db, return_ty)
15521555
}
15531556

15541557
/// Calls `self`
15551558
///
15561559
/// Returns `Ok` if the call with the given arguments is successful and `Err` otherwise.
1557-
fn call(
1560+
fn try_call(
15581561
self,
15591562
db: &'db dyn Db,
15601563
arguments: &CallArguments<'_, 'db>,
@@ -1672,7 +1675,7 @@ impl<'db> Type<'db> {
16721675

16731676
instance_ty @ Type::Instance(_) => {
16741677
instance_ty
1675-
.call_dunder(db, "__call__", &arguments.with_self(instance_ty))
1678+
.try_call_dunder(db, "__call__", &arguments.with_self(instance_ty))
16761679
.map_err(|err| match err {
16771680
CallDunderError::Call(CallError::NotCallable { .. }) => {
16781681
// Turn "`<type of illegal '__call__'>` not callable" into
@@ -1712,7 +1715,7 @@ impl<'db> Type<'db> {
17121715
Type::Dynamic(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(self))),
17131716

17141717
Type::Union(union) => {
1715-
CallOutcome::try_call_union(db, union, |element| element.call(db, arguments))
1718+
CallOutcome::try_call_union(db, union, |element| element.try_call(db, arguments))
17161719
}
17171720

17181721
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
@@ -1731,7 +1734,7 @@ impl<'db> Type<'db> {
17311734
/// `receiver_ty` must be `Type::Instance(_)` or `Type::ClassLiteral`.
17321735
///
17331736
/// TODO: handle `super()` objects properly
1734-
fn call_bound(
1737+
fn try_call_bound(
17351738
self,
17361739
db: &'db dyn Db,
17371740
receiver_ty: &Type<'db>,
@@ -1743,16 +1746,16 @@ impl<'db> Type<'db> {
17431746
Type::FunctionLiteral(..) => {
17441747
// Functions are always descriptors, so this would effectively call
17451748
// the function with the instance as the first argument
1746-
self.call(db, &arguments.with_self(*receiver_ty))
1749+
self.try_call(db, &arguments.with_self(*receiver_ty))
17471750
}
17481751

17491752
Type::Instance(_) | Type::ClassLiteral(_) => {
17501753
// TODO descriptor protocol. For now, assume non-descriptor and call without `self` argument.
1751-
self.call(db, arguments)
1754+
self.try_call(db, arguments)
17521755
}
17531756

17541757
Type::Union(union) => CallOutcome::try_call_union(db, union, |element| {
1755-
element.call_bound(db, receiver_ty, arguments)
1758+
element.try_call_bound(db, receiver_ty, arguments)
17561759
}),
17571760

17581761
Type::Intersection(_) => Ok(CallOutcome::Single(CallBinding::from_return_type(
@@ -1769,16 +1772,16 @@ impl<'db> Type<'db> {
17691772
}
17701773

17711774
/// Look up a dunder method on the meta type of `self` and call it.
1772-
fn call_dunder(
1775+
fn try_call_dunder(
17731776
self,
17741777
db: &'db dyn Db,
17751778
name: &str,
17761779
arguments: &CallArguments<'_, 'db>,
17771780
) -> Result<CallOutcome<'db>, CallDunderError<'db>> {
17781781
match self.to_meta_type(db).member(db, name) {
1779-
Symbol::Type(callable_ty, Boundness::Bound) => Ok(callable_ty.call(db, arguments)?),
1782+
Symbol::Type(callable_ty, Boundness::Bound) => Ok(callable_ty.try_call(db, arguments)?),
17801783
Symbol::Type(callable_ty, Boundness::PossiblyUnbound) => {
1781-
let call = callable_ty.call(db, arguments)?;
1784+
let call = callable_ty.try_call(db, arguments)?;
17821785
Err(CallDunderError::PossiblyUnbound(call))
17831786
}
17841787
Symbol::Unbound => Err(CallDunderError::MethodNotAvailable),
@@ -1801,12 +1804,12 @@ impl<'db> Type<'db> {
18011804
}
18021805

18031806
let dunder_iter_result =
1804-
self.call_dunder(db, "__iter__", &CallArguments::positional([self]));
1807+
self.try_call_dunder(db, "__iter__", &CallArguments::positional([self]));
18051808
match &dunder_iter_result {
18061809
Ok(outcome) | Err(CallDunderError::PossiblyUnbound(outcome)) => {
18071810
let iterator_ty = outcome.return_type(db);
18081811

1809-
return match iterator_ty.call_dunder(
1812+
return match iterator_ty.try_call_dunder(
18101813
db,
18111814
"__next__",
18121815
&CallArguments::positional([iterator_ty]),
@@ -1855,7 +1858,7 @@ impl<'db> Type<'db> {
18551858
//
18561859
// TODO(Alex) this is only valid if the `__getitem__` method is annotated as
18571860
// accepting `int` or `SupportsIndex`
1858-
match self.call_dunder(
1861+
match self.try_call_dunder(
18591862
db,
18601863
"__getitem__",
18611864
&CallArguments::positional([self, KnownClass::Int.to_instance(db)]),
@@ -2693,52 +2696,8 @@ pub enum KnownInstanceType<'db> {
26932696
}
26942697

26952698
impl<'db> KnownInstanceType<'db> {
2696-
pub const fn as_str(self) -> &'static str {
2697-
match self {
2698-
Self::Annotated => "Annotated",
2699-
Self::Literal => "Literal",
2700-
Self::LiteralString => "LiteralString",
2701-
Self::Optional => "Optional",
2702-
Self::Union => "Union",
2703-
Self::TypeVar(_) => "TypeVar",
2704-
Self::NoReturn => "NoReturn",
2705-
Self::Never => "Never",
2706-
Self::Any => "Any",
2707-
Self::Tuple => "Tuple",
2708-
Self::Type => "Type",
2709-
Self::TypeAliasType(_) => "TypeAliasType",
2710-
Self::TypingSelf => "Self",
2711-
Self::Final => "Final",
2712-
Self::ClassVar => "ClassVar",
2713-
Self::Callable => "Callable",
2714-
Self::Concatenate => "Concatenate",
2715-
Self::Unpack => "Unpack",
2716-
Self::Required => "Required",
2717-
Self::NotRequired => "NotRequired",
2718-
Self::TypeAlias => "TypeAlias",
2719-
Self::TypeGuard => "TypeGuard",
2720-
Self::TypeIs => "TypeIs",
2721-
Self::List => "List",
2722-
Self::Dict => "Dict",
2723-
Self::DefaultDict => "DefaultDict",
2724-
Self::Set => "Set",
2725-
Self::FrozenSet => "FrozenSet",
2726-
Self::Counter => "Counter",
2727-
Self::Deque => "Deque",
2728-
Self::ChainMap => "ChainMap",
2729-
Self::OrderedDict => "OrderedDict",
2730-
Self::ReadOnly => "ReadOnly",
2731-
Self::Unknown => "Unknown",
2732-
Self::AlwaysTruthy => "AlwaysTruthy",
2733-
Self::AlwaysFalsy => "AlwaysFalsy",
2734-
Self::Not => "Not",
2735-
Self::Intersection => "Intersection",
2736-
Self::TypeOf => "TypeOf",
2737-
}
2738-
}
2739-
27402699
/// Evaluate the known instance in boolean context
2741-
pub const fn bool(self) -> Truthiness {
2700+
pub(crate) const fn bool(self) -> Truthiness {
27422701
match self {
27432702
Self::Annotated
27442703
| Self::Literal
@@ -2783,7 +2742,7 @@ impl<'db> KnownInstanceType<'db> {
27832742
}
27842743

27852744
/// Return the repr of the symbol at runtime
2786-
pub fn repr(self, db: &'db dyn Db) -> &'db str {
2745+
pub(crate) fn repr(self, db: &'db dyn Db) -> &'db str {
27872746
match self {
27882747
Self::Annotated => "typing.Annotated",
27892748
Self::Literal => "typing.Literal",
@@ -2828,7 +2787,7 @@ impl<'db> KnownInstanceType<'db> {
28282787
}
28292788

28302789
/// Return the [`KnownClass`] which this symbol is an instance of
2831-
pub const fn class(self) -> KnownClass {
2790+
pub(crate) const fn class(self) -> KnownClass {
28322791
match self {
28332792
Self::Annotated => KnownClass::SpecialForm,
28342793
Self::Literal => KnownClass::SpecialForm,
@@ -2877,16 +2836,20 @@ impl<'db> KnownInstanceType<'db> {
28772836
/// For example, the symbol `typing.Literal` is an instance of `typing._SpecialForm`,
28782837
/// so `KnownInstanceType::Literal.instance_fallback(db)`
28792838
/// returns `Type::Instance(InstanceType { class: <typing._SpecialForm> })`.
2880-
pub fn instance_fallback(self, db: &dyn Db) -> Type {
2839+
pub(crate) fn instance_fallback(self, db: &dyn Db) -> Type {
28812840
self.class().to_instance(db)
28822841
}
28832842

28842843
/// Return `true` if this symbol is an instance of `class`.
2885-
pub fn is_instance_of(self, db: &'db dyn Db, class: Class<'db>) -> bool {
2844+
pub(crate) fn is_instance_of(self, db: &'db dyn Db, class: Class<'db>) -> bool {
28862845
self.class().is_subclass_of(db, class)
28872846
}
28882847

2889-
pub fn try_from_file_and_name(db: &'db dyn Db, file: File, symbol_name: &str) -> Option<Self> {
2848+
pub(crate) fn try_from_file_and_name(
2849+
db: &'db dyn Db,
2850+
file: File,
2851+
symbol_name: &str,
2852+
) -> Option<Self> {
28902853
let candidate = match symbol_name {
28912854
"Any" => Self::Any,
28922855
"ClassVar" => Self::ClassVar,
@@ -2937,7 +2900,7 @@ impl<'db> KnownInstanceType<'db> {
29372900
///
29382901
/// Most variants can only exist in one module, which is the same as `self.class().canonical_module()`.
29392902
/// Some variants could validly be defined in either `typing` or `typing_extensions`, however.
2940-
pub fn check_module(self, module: KnownModule) -> bool {
2903+
pub(crate) fn check_module(self, module: KnownModule) -> bool {
29412904
match self {
29422905
Self::Any
29432906
| Self::ClassVar
@@ -3668,7 +3631,7 @@ impl<'db> Class<'db> {
36683631
// TODO: Other keyword arguments?
36693632
let arguments = CallArguments::positional([name, bases, namespace]);
36703633

3671-
let return_ty_result = match metaclass.call(db, &arguments) {
3634+
let return_ty_result = match metaclass.try_call(db, &arguments) {
36723635
Ok(outcome) => Ok(outcome.return_type(db)),
36733636

36743637
Err(CallError::NotCallable { not_callable_ty }) => Err(MetaclassError {

crates/red_knot_python_semantic/src/types/infer.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -1616,7 +1616,7 @@ impl<'db> TypeInferenceBuilder<'db> {
16161616
}
16171617

16181618
let target_ty = enter_ty
1619-
.call(self.db(), &CallArguments::positional([context_expression_ty]))
1619+
.try_call(self.db(), &CallArguments::positional([context_expression_ty]))
16201620
.map(|outcome| outcome.return_type(self.db()))
16211621
.unwrap_or_else(|err| {
16221622
// TODO: Use more specific error messages for the different error cases.
@@ -1659,7 +1659,7 @@ impl<'db> TypeInferenceBuilder<'db> {
16591659
}
16601660

16611661
if exit_ty
1662-
.call(
1662+
.try_call(
16631663
self.db(),
16641664
&CallArguments::positional([
16651665
context_manager_ty,
@@ -2209,7 +2209,7 @@ impl<'db> TypeInferenceBuilder<'db> {
22092209
if let Symbol::Type(class_member, boundness) =
22102210
class.class_member(self.db(), op.in_place_dunder())
22112211
{
2212-
let call = class_member.call(
2212+
let call = class_member.try_call(
22132213
self.db(),
22142214
&CallArguments::positional([target_type, value_type]),
22152215
);
@@ -3247,7 +3247,7 @@ impl<'db> TypeInferenceBuilder<'db> {
32473247
.unwrap_or_default();
32483248

32493249
let call_arguments = self.infer_arguments(arguments, parameter_expectations);
3250-
let call = function_type.call(self.db(), &call_arguments);
3250+
let call = function_type.try_call(self.db(), &call_arguments);
32513251

32523252
match call {
32533253
Ok(outcome) => {
@@ -3747,7 +3747,7 @@ impl<'db> TypeInferenceBuilder<'db> {
37473747
}
37483748
};
37493749

3750-
match operand_type.call_dunder(
3750+
match operand_type.try_call_dunder(
37513751
self.db(),
37523752
unary_dunder_method,
37533753
&CallArguments::positional([operand_type]),
@@ -3996,15 +3996,15 @@ impl<'db> TypeInferenceBuilder<'db> {
39963996
&& rhs_reflected != left_class.member(self.db(), reflected_dunder)
39973997
{
39983998
return right_ty
3999-
.call_dunder(
3999+
.try_call_dunder(
40004000
self.db(),
40014001
reflected_dunder,
40024002
&CallArguments::positional([right_ty, left_ty]),
40034003
)
40044004
.map(|outcome| outcome.return_type(self.db()))
40054005
.or_else(|_| {
40064006
left_ty
4007-
.call_dunder(
4007+
.try_call_dunder(
40084008
self.db(),
40094009
op.dunder(),
40104010
&CallArguments::positional([left_ty, right_ty]),
@@ -4020,7 +4020,7 @@ impl<'db> TypeInferenceBuilder<'db> {
40204020
left_class.member(self.db(), op.dunder())
40214021
{
40224022
class_member
4023-
.call(self.db(), &CallArguments::positional([left_ty, right_ty]))
4023+
.try_call(self.db(), &CallArguments::positional([left_ty, right_ty]))
40244024
.map(|outcome| outcome.return_type(self.db()))
40254025
.ok()
40264026
} else {
@@ -4036,7 +4036,10 @@ impl<'db> TypeInferenceBuilder<'db> {
40364036
{
40374037
// TODO: Use `call_dunder`
40384038
class_member
4039-
.call(self.db(), &CallArguments::positional([right_ty, left_ty]))
4039+
.try_call(
4040+
self.db(),
4041+
&CallArguments::positional([right_ty, left_ty]),
4042+
)
40404043
.map(|outcome| outcome.return_type(self.db()))
40414044
.ok()
40424045
} else {
@@ -4610,7 +4613,7 @@ impl<'db> TypeInferenceBuilder<'db> {
46104613
// TODO: How do we want to handle possibly unbound dunder methods?
46114614
match left.class.class_member(db, op.dunder()) {
46124615
Symbol::Type(class_member_dunder, Boundness::Bound) => class_member_dunder
4613-
.call(
4616+
.try_call(
46144617
db,
46154618
&CallArguments::positional([Type::Instance(left), Type::Instance(right)]),
46164619
)
@@ -4660,7 +4663,7 @@ impl<'db> TypeInferenceBuilder<'db> {
46604663
Symbol::Type(contains_dunder, Boundness::Bound) => {
46614664
// If `__contains__` is available, it is used directly for the membership test.
46624665
contains_dunder
4663-
.call(
4666+
.try_call(
46644667
db,
46654668
&CallArguments::positional([Type::Instance(right), Type::Instance(left)]),
46664669
)
@@ -4917,7 +4920,7 @@ impl<'db> TypeInferenceBuilder<'db> {
49174920
// If the class defines `__getitem__`, return its return type.
49184921
//
49194922
// See: https://docs.python.org/3/reference/datamodel.html#class-getitem-versus-getitem
4920-
match value_ty.call_dunder(
4923+
match value_ty.try_call_dunder(
49214924
self.db(),
49224925
"__getitem__",
49234926
&CallArguments::positional([value_ty, slice_ty]),
@@ -4981,7 +4984,7 @@ impl<'db> TypeInferenceBuilder<'db> {
49814984
}
49824985

49834986
return ty
4984-
.call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
4987+
.try_call(self.db(), &CallArguments::positional([value_ty, slice_ty]))
49854988
.map(|outcome| outcome.return_type(self.db()))
49864989
.unwrap_or_else(|err| {
49874990
self.context.report_lint(

crates/ruff_db/src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ mod tests {
7474
///
7575
/// ## Panics
7676
/// If there are pending database snapshots.
77-
#[allow(unused)]
7877
pub(crate) fn take_salsa_events(&mut self) -> Vec<salsa::Event> {
7978
let inner = Arc::get_mut(&mut self.events)
8079
.expect("expected no pending salsa database snapshots.");
@@ -86,7 +85,6 @@ mod tests {
8685
///
8786
/// ## Panics
8887
/// If there are pending database snapshots.
89-
#[allow(unused)]
9088
pub(crate) fn clear_salsa_events(&mut self) {
9189
self.take_salsa_events();
9290
}

0 commit comments

Comments
 (0)