Auto merge of #14440 - Veykril:deref-fix, r=Veykril

fix: Handle box and raw pointers correctly in builtin_deref
This commit is contained in:
bors 2023-03-29 19:39:02 +00:00
commit 17e31b7d3b
5 changed files with 62 additions and 39 deletions

View file

@ -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])?;

View file

@ -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
};
"#,

View file

@ -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) {

View file

@ -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}
"#]],
);
}

View file

@ -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>| -> ()>
"#]],
);
}