about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-03-29 21:38:32 +0200
committerLukas Wirth <lukastw97@gmail.com>2023-03-29 21:38:32 +0200
commite79747965197e362b375a7019571331b5be2394e (patch)
treefc52b1fb60ac9fa19316a71c400077b55ec25195
parent5351c21b7e57b556c88fb825da14d57522e80a26 (diff)
downloadrust-e79747965197e362b375a7019571331b5be2394e.tar.gz
rust-e79747965197e362b375a7019571331b5be2394e.zip
fix: Handle box and raw pointers correctly in builtin_deref
-rw-r--r--crates/hir-ty/src/autoderef.rs40
-rw-r--r--crates/hir-ty/src/consteval/tests/intrinsics.rs4
-rw-r--r--crates/hir-ty/src/infer/expr.rs15
-rw-r--r--crates/hir-ty/src/tests/simple.rs4
-rw-r--r--crates/hir-ty/src/tests/traits.rs38
5 files changed, 62 insertions, 39 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 58744dd0c0f..6a7ea8a990a 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -6,7 +6,10 @@
 use std::sync::Arc;
 
 use chalk_ir::cast::Cast;
-use hir_def::lang_item::LangItem;
+use hir_def::{
+    lang_item::{LangItem, LangItemTarget},
+    AdtId,
+};
 use hir_expand::name::name;
 use limit::Limit;
 
@@ -76,7 +79,7 @@ pub(crate) fn autoderef_step(
     table: &mut InferenceTable<'_>,
     ty: Ty,
 ) -> Option<(AutoderefKind, Ty)> {
-    if let Some(derefed) = builtin_deref(&ty) {
+    if let Some(derefed) = builtin_deref(table, &ty, false) {
         Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
     } else {
         Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
@@ -99,26 +102,41 @@ pub fn autoderef(
     v.into_iter()
 }
 
-pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
-    let _p = profile::span("deref");
-    autoderef_step(table, ty).map(|(_, ty)| ty)
-}
-
-fn builtin_deref(ty: &Ty) -> Option<&Ty> {
+pub(crate) fn builtin_deref<'ty>(
+    table: &mut InferenceTable<'_>,
+    ty: &'ty Ty,
+    explicit: bool,
+) -> Option<&'ty Ty> {
     match ty.kind(Interner) {
-        TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
+        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(AdtId::StructId(strukt)), ref substs) => {
+            if Some(strukt)
+                == table
+                    .db
+                    .lang_item(table.trait_env.krate, LangItem::OwnedBox)
+                    .and_then(LangItemTarget::as_struct)
+            {
+                substs.at(Interner, 0).ty(Interner)
+            } else {
+                None
+            }
+        }
         _ => None,
     }
 }
 
-fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
+pub(crate) fn deref_by_trait(
+    table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
+    ty: Ty,
+) -> Option<Ty> {
     let _p = profile::span("deref_by_trait");
     if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
         // don't try to deref unknown variables
         return None;
     }
 
-    let db = table.db;
     let deref_trait =
         db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
     let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs
index 371d5cab337..5c47e1f00a4 100644
--- a/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -86,7 +86,7 @@ fn offset() {
             ];
             let ar: *const [(u8, u8, u8)] = ar;
             let ar = ar as *const (u8, u8, u8);
-            let element = offset(ar, 2);
+            let element = *offset(ar, 2);
             element.1
         };
         "#,
@@ -113,7 +113,7 @@ fn arith_offset() {
             ];
             let ar: *const [(u8, u8, u8)] = ar;
             let ar = ar as *const (u8, u8, u8);
-            let element = arith_offset(arith_offset(ar, 102), -100);
+            let element = *arith_offset(arith_offset(ar, 102), -100);
             element.1
         };
         "#,
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 322ef51167a..6c1214c1726 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -661,11 +661,7 @@ impl<'a> InferenceContext<'a> {
                 // FIXME: Note down method resolution her
                 match op {
                     UnaryOp::Deref => {
-                        if let Some(deref_trait) = self
-                            .db
-                            .lang_item(self.table.trait_env.krate, LangItem::Deref)
-                            .and_then(|l| l.as_trait())
-                        {
+                        if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
                             if let Some(deref_fn) =
                                 self.db.trait_data(deref_trait).method_by_name(&name![deref])
                             {
@@ -678,7 +674,14 @@ impl<'a> InferenceContext<'a> {
                                 );
                             }
                         }
-                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
+                        if let Some(derefed) =
+                            autoderef::builtin_deref(&mut self.table, &inner_ty, true)
+                        {
+                            self.resolve_ty_shallow(derefed)
+                        } else {
+                            autoderef::deref_by_trait(&mut self.table, inner_ty)
+                                .unwrap_or_else(|| self.err_ty())
+                        }
                     }
                     UnaryOp::Neg => {
                         match inner_ty.kind(Interner) {
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 8322b9e1ca6..17663ad38b3 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -854,9 +854,9 @@ fn test2(a1: *const A, a2: *mut A) {
             237..239 'a2': *mut A
             249..272 '{     ...2.b; }': ()
             255..257 'a1': *const A
-            255..259 'a1.b': B
+            255..259 'a1.b': {unknown}
             265..267 'a2': *mut A
-            265..269 'a2.b': B
+            265..269 'a2.b': {unknown}
         "#]],
     );
 }
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index e9c26bf4734..813beaa3649 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -3051,7 +3051,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
     type Target = T;
 
     fn deref(&self) -> &T {
-        &self.inner
+        unsafe { &*self.inner }
     }
 }
 
@@ -3062,23 +3062,25 @@ fn foo() {
 }"#,
         expect![[r#"
             154..158 'self': &Box<T>
-            166..193 '{     ...     }': &T
-            176..187 '&self.inner': &*mut T
-            177..181 'self': &Box<T>
-            177..187 'self.inner': *mut T
-            206..296 '{     ...&s); }': ()
-            216..217 's': Option<i32>
-            220..224 'None': Option<i32>
-            234..235 'f': Box<dyn FnOnce(&Option<i32>)>
-            269..282 'box (|ps| {})': Box<|&Option<i32>| -> ()>
-            274..281 '|ps| {}': |&Option<i32>| -> ()
-            275..277 'ps': &Option<i32>
-            279..281 '{}': ()
-            288..289 'f': Box<dyn FnOnce(&Option<i32>)>
-            288..293 'f(&s)': ()
-            290..292 '&s': &Option<i32>
-            291..292 's': Option<i32>
-            269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
+            166..205 '{     ...     }': &T
+            176..199 'unsafe...nner }': &T
+            185..197 '&*self.inner': &T
+            186..197 '*self.inner': T
+            187..191 'self': &Box<T>
+            187..197 'self.inner': *mut T
+            218..308 '{     ...&s); }': ()
+            228..229 's': Option<i32>
+            232..236 'None': Option<i32>
+            246..247 'f': Box<dyn FnOnce(&Option<i32>)>
+            281..294 'box (|ps| {})': Box<|&Option<i32>| -> ()>
+            286..293 '|ps| {}': |&Option<i32>| -> ()
+            287..289 'ps': &Option<i32>
+            291..293 '{}': ()
+            300..301 'f': Box<dyn FnOnce(&Option<i32>)>
+            300..305 'f(&s)': ()
+            302..304 '&s': &Option<i32>
+            303..304 's': Option<i32>
+            281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
         "#]],
     );
 }