Skip to content

Instantly share code, notes, and snippets.

@madsmtm
Created December 1, 2023 05:23
Show Gist options
  • Save madsmtm/264d509057d3e8e2ad716773abaa2dca to your computer and use it in GitHub Desktop.
Save madsmtm/264d509057d3e8e2ad716773abaa2dca to your computer and use it in GitHub Desktop.
Pseudo-code for Rust method-call expressions
/// 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