Created
December 1, 2023 05:23
-
-
Save madsmtm/264d509057d3e8e2ad716773abaa2dca to your computer and use it in GitHub Desktop.
Pseudo-code for Rust method-call expressions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Pseudo-code for how [method-call expressions] work. | |
/// | |
/// [method-call expressions]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html | |
fn lookup_method(mut T: Type, method_name: &str) -> Method { | |
// The first step is to build a list of candidate receiver types. | |
let mut candidate_receiver_types = vec![T]; | |
// Obtain these by repeatedly dereferencing the receiver expression's | |
// type, adding each type encountered to the list, | |
while let Some(U) = <T as Deref>::Target { | |
T = U; | |
candidate_receiver_types.push(T); | |
} | |
// then finally attempting an unsized coercion at the end, and adding the | |
// result type if that is successful. | |
if let Some(U) = T::UnsizedCoercion { | |
candidate_receiver_types.push(U); | |
} | |
// Then, for each candidate `T`, add `&T` and `&mut T` to the list | |
// immediately after `T`. | |
let candidate_receiver_types = candidate_receiver_types.map(|T| [T, &T, &mut T]).flatten(); | |
// Then, for each candidate type `T`, | |
for T in candidate_receiver_types { | |
// search for a visible method with a receiver of that type | |
let find_method = |methods: Map<&str, Method>| { | |
methods | |
.get(method_name) | |
.filter(|m| m.is_visible() && m.receiver == T) | |
}; | |
// in the following places: | |
// 1. `T`'s inherent methods (methods implemented directly on `T`). | |
if let Some(method) = find_method(T.inherent_impl.methods) { | |
return method; | |
} | |
// 2. Any of the methods provided by a visible trait implemented by | |
// `T`. If `T` is a type parameter, methods provided by trait | |
// bounds on `T` are looked up first. Then all remaining methods in | |
// scope are looked up. | |
let mut prioritized_candidate_methods = vec![]; | |
let mut candidate_methods = vec![]; | |
for Trait in TRAITS.visible() { | |
if let Some(TraitImpl) = T.implements(Trait) { | |
if let Some(method) = find_method(TraitImpl.methods) { | |
if T.is_type_parameter() && T.has_bounds_of(Trait) { | |
prioritized_candidate_methods.push(method); | |
} else { | |
candidate_methods.push(method); | |
} | |
} | |
} | |
} | |
// If this results in multiple possible candidates, then it is an | |
// error, and the receiver must be converted to an appropriate | |
// receiver type to make the method call. | |
match prioritized_candidate_methods { | |
[] => None, // Continue | |
[method] => Some(method), | |
_ => panic!("multiple applicable items in scope"), | |
} | |
match candidate_methods { | |
[] => None, // Continue | |
[method] => Some(method), | |
_ => panic!("multiple applicable items in scope"), | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment