about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Kirszenberg <alex.kirszenberg@vercel.com>2023-06-23 15:35:41 +0200
committerAlex Kirszenberg <alex.kirszenberg@vercel.com>2023-06-23 15:35:41 +0200
commit5991f0d8691719ec0fcc654cc2bf24c61a76c3d4 (patch)
tree1978370e2b5fe94e0f2a870c6acf708e8df00761
parent246d11b2a5618c8e7a116d7eb5b4e866a32c5552 (diff)
downloadrust-5991f0d8691719ec0fcc654cc2bf24c61a76c3d4.tar.gz
rust-5991f0d8691719ec0fcc654cc2bf24c61a76c3d4.zip
Follow raw pointers in autoderef chain when resolving methods with custom receiver
-rw-r--r--crates/hir-ty/src/autoderef.rs13
-rw-r--r--crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs4
-rw-r--r--crates/hir-ty/src/method_resolution.rs10
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs46
5 files changed, 61 insertions, 14 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 3860bccec8b..4625a3b01a3 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -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
@@ -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 {
@@ -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;
@@ -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)?))
@@ -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) {
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 05a476f632d..7a3a79ef881 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -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;
 
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 194471f0048..a7185d66432 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -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() {
@@ -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) {
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index ab6430e8f19..38959b18bfc 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -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);
@@ -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,
@@ -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,
@@ -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,
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 1e57a4ae296..a8e146b096a 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1216,6 +1216,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(
         r#"