Unnamed repository; edit this file 'description' to name the repository.
-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 58744dd0c0..6a7ea8a990 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 371d5cab33..5c47e1f00a 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 322ef51167..6c1214c172 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 8322b9e1ca..17663ad38b 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 e9c26bf473..813beaa364 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>| -> ()>
"#]],
);
}