Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Follow raw pointers in autoderef chain when resolving methods with custom receiver #15118

Merged
merged 1 commit into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions crates/hir-ty/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn autoderef(
) -> impl Iterator<Item = Ty> {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
let mut autoderef = Autoderef::new(&mut table, ty);
let mut autoderef = Autoderef::new(&mut table, ty, false);
let mut v = Vec::new();
while let Some((ty, _steps)) = autoderef.next() {
// `ty` may contain unresolved inference variables. Since there's no chance they would be
Expand All @@ -63,12 +63,13 @@ pub(crate) struct Autoderef<'a, 'db> {
ty: Ty,
at_start: bool,
steps: Vec<(AutoderefKind, Ty)>,
explicit: bool,
}

impl<'a, 'db> Autoderef<'a, 'db> {
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
let ty = table.resolve_ty_shallow(&ty);
Autoderef { table, ty, at_start: true, steps: Vec::new() }
Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
}

pub(crate) fn step_count(&self) -> usize {
Expand Down Expand Up @@ -97,7 +98,7 @@ impl Iterator for Autoderef<'_, '_> {
return None;
}

let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?;
let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;

self.steps.push((kind, self.ty.clone()));
self.ty = new_ty;
Expand All @@ -109,8 +110,9 @@ impl Iterator for Autoderef<'_, '_> {
pub(crate) fn autoderef_step(
table: &mut InferenceTable<'_>,
ty: Ty,
explicit: bool,
) -> Option<(AutoderefKind, Ty)> {
if let Some(derefed) = builtin_deref(table, &ty, false) {
if let Some(derefed) = builtin_deref(table, &ty, explicit) {
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
} else {
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
Expand All @@ -124,7 +126,6 @@ pub(crate) fn builtin_deref<'ty>(
) -> Option<&'ty Ty> {
match ty.kind(Interner) {
TyKind::Ref(.., ty) => Some(ty),
// FIXME: Maybe accept this but diagnose if its not explicit?
TyKind::Raw(.., ty) if explicit => Some(ty),
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
if crate::lang_items::is_box(table.db, adt) {
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/infer/coerce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ impl<'a> InferenceTable<'a> {

let snapshot = self.snapshot();

let mut autoderef = Autoderef::new(self, from_ty.clone());
let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
let mut first_error = None;
let mut found = None;

Expand Down
4 changes: 2 additions & 2 deletions crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ impl<'a> InferenceContext<'a> {
}
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
let (res, derefed_callee) = 'b: {
// manual loop to be able to access `derefs.table`
while let Some((callee_deref_ty, _)) = derefs.next() {
Expand Down Expand Up @@ -1385,7 +1385,7 @@ impl<'a> InferenceContext<'a> {
receiver_ty: &Ty,
name: &Name,
) -> Option<(Ty, Option<FieldId>, Vec<Adjustment>, bool)> {
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone());
let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
let mut private_field = None;
let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
let (field_id, parameters) = match derefed_ty.kind(Interner) {
Expand Down
10 changes: 5 additions & 5 deletions crates/hir-ty/src/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ impl ReceiverAdjustments {
let mut ty = table.resolve_ty_shallow(&ty);
let mut adjust = Vec::new();
for _ in 0..self.autoderefs {
match autoderef::autoderef_step(table, ty.clone()) {
match autoderef::autoderef_step(table, ty.clone(), true) {
None => {
never!("autoderef not possible for {:?}", ty);
ty = TyKind::Error.intern(Interner);
Expand Down Expand Up @@ -1012,8 +1012,8 @@ fn iterate_method_candidates_by_receiver(
let snapshot = table.snapshot();
// We're looking for methods with *receiver* type receiver_ty. These could
// be found in any of the derefs of receiver_ty, so we have to go through
// that.
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
// that, including raw derefs.
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() {
iterate_inherent_methods(
&self_ty,
Expand All @@ -1028,7 +1028,7 @@ fn iterate_method_candidates_by_receiver(

table.rollback_to(snapshot);

let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
while let Some((self_ty, _)) = autoderef.next() {
iterate_trait_method_candidates(
&self_ty,
Expand Down Expand Up @@ -1504,7 +1504,7 @@ fn autoderef_method_receiver(
ty: Ty,
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
let mut deref_chain: Vec<_> = Vec::new();
let mut autoderef = autoderef::Autoderef::new(table, ty);
let mut autoderef = autoderef::Autoderef::new(table, ty, true);
while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push((
autoderef.table.canonicalize(ty).value,
Expand Down
46 changes: 46 additions & 0 deletions crates/hir-ty/src/tests/method_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,52 @@ fn main() {
);
}

#[test]
fn inherent_method_deref_raw() {
check_types(
r#"
struct Val;

impl Val {
pub fn method(self: *const Val) -> u32 {
0
}
}

fn main() {
let foo: *const Val;
foo.method();
// ^^^^^^^^^^^^ u32
}
"#,
);
}

#[test]
fn trait_method_deref_raw() {
check_types(
r#"
trait Trait {
fn method(self: *const Self) -> u32;
}

struct Val;

impl Trait for Val {
fn method(self: *const Self) -> u32 {
0
}
}

fn main() {
let foo: *const Val;
foo.method();
// ^^^^^^^^^^^^ u32
}
"#,
);
}

#[test]
fn method_on_dyn_impl() {
check_types(
Expand Down