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 { - 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 { +pub(crate) fn deref_by_trait( + table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>, + ty: Ty, +) -> Option { 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 core::ops::Deref for Box { type Target = T; fn deref(&self) -> &T { - &self.inner + unsafe { &*self.inner } } } @@ -3062,23 +3062,25 @@ fn foo() { }"#, expect![[r#" 154..158 'self': &Box - 166..193 '{ ... }': &T - 176..187 '&self.inner': &*mut T - 177..181 'self': &Box - 177..187 'self.inner': *mut T - 206..296 '{ ...&s); }': () - 216..217 's': Option - 220..224 'None': Option - 234..235 'f': Box)> - 269..282 'box (|ps| {})': Box<|&Option| -> ()> - 274..281 '|ps| {}': |&Option| -> () - 275..277 'ps': &Option - 279..281 '{}': () - 288..289 'f': Box)> - 288..293 'f(&s)': () - 290..292 '&s': &Option - 291..292 's': Option - 269..282: expected Box)>, got Box<|&Option| -> ()> + 166..205 '{ ... }': &T + 176..199 'unsafe...nner }': &T + 185..197 '&*self.inner': &T + 186..197 '*self.inner': T + 187..191 'self': &Box + 187..197 'self.inner': *mut T + 218..308 '{ ...&s); }': () + 228..229 's': Option + 232..236 'None': Option + 246..247 'f': Box)> + 281..294 'box (|ps| {})': Box<|&Option| -> ()> + 286..293 '|ps| {}': |&Option| -> () + 287..289 'ps': &Option + 291..293 '{}': () + 300..301 'f': Box)> + 300..305 'f(&s)': () + 302..304 '&s': &Option + 303..304 's': Option + 281..294: expected Box)>, got Box<|&Option| -> ()> "#]], ); }