Skip to content

Commit e797479

Browse files
committed
fix: Handle box and raw pointers correctly in builtin_deref
1 parent 5351c21 commit e797479

File tree

5 files changed

+62
-39
lines changed

5 files changed

+62
-39
lines changed

crates/hir-ty/src/autoderef.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
use std::sync::Arc;
77

88
use chalk_ir::cast::Cast;
9-
use hir_def::lang_item::LangItem;
9+
use hir_def::{
10+
lang_item::{LangItem, LangItemTarget},
11+
AdtId,
12+
};
1013
use hir_expand::name::name;
1114
use limit::Limit;
1215

@@ -76,7 +79,7 @@ pub(crate) fn autoderef_step(
7679
table: &mut InferenceTable<'_>,
7780
ty: Ty,
7881
) -> Option<(AutoderefKind, Ty)> {
79-
if let Some(derefed) = builtin_deref(&ty) {
82+
if let Some(derefed) = builtin_deref(table, &ty, false) {
8083
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
8184
} else {
8285
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
@@ -99,26 +102,41 @@ pub fn autoderef(
99102
v.into_iter()
100103
}
101104

102-
pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
103-
let _p = profile::span("deref");
104-
autoderef_step(table, ty).map(|(_, ty)| ty)
105-
}
106-
107-
fn builtin_deref(ty: &Ty) -> Option<&Ty> {
105+
pub(crate) fn builtin_deref<'ty>(
106+
table: &mut InferenceTable<'_>,
107+
ty: &'ty Ty,
108+
explicit: bool,
109+
) -> Option<&'ty Ty> {
108110
match ty.kind(Interner) {
109-
TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty),
111+
TyKind::Ref(.., ty) => Some(ty),
112+
// FIXME: Maybe accept this but diagnose if its not explicit?
113+
TyKind::Raw(.., ty) if explicit => Some(ty),
114+
&TyKind::Adt(chalk_ir::AdtId(AdtId::StructId(strukt)), ref substs) => {
115+
if Some(strukt)
116+
== table
117+
.db
118+
.lang_item(table.trait_env.krate, LangItem::OwnedBox)
119+
.and_then(LangItemTarget::as_struct)
120+
{
121+
substs.at(Interner, 0).ty(Interner)
122+
} else {
123+
None
124+
}
125+
}
110126
_ => None,
111127
}
112128
}
113129

114-
fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
130+
pub(crate) fn deref_by_trait(
131+
table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
132+
ty: Ty,
133+
) -> Option<Ty> {
115134
let _p = profile::span("deref_by_trait");
116135
if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
117136
// don't try to deref unknown variables
118137
return None;
119138
}
120139

121-
let db = table.db;
122140
let deref_trait =
123141
db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
124142
let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;

crates/hir-ty/src/consteval/tests/intrinsics.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fn offset() {
8686
];
8787
let ar: *const [(u8, u8, u8)] = ar;
8888
let ar = ar as *const (u8, u8, u8);
89-
let element = offset(ar, 2);
89+
let element = *offset(ar, 2);
9090
element.1
9191
};
9292
"#,
@@ -113,7 +113,7 @@ fn arith_offset() {
113113
];
114114
let ar: *const [(u8, u8, u8)] = ar;
115115
let ar = ar as *const (u8, u8, u8);
116-
let element = arith_offset(arith_offset(ar, 102), -100);
116+
let element = *arith_offset(arith_offset(ar, 102), -100);
117117
element.1
118118
};
119119
"#,

crates/hir-ty/src/infer/expr.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -661,11 +661,7 @@ impl<'a> InferenceContext<'a> {
661661
// FIXME: Note down method resolution her
662662
match op {
663663
UnaryOp::Deref => {
664-
if let Some(deref_trait) = self
665-
.db
666-
.lang_item(self.table.trait_env.krate, LangItem::Deref)
667-
.and_then(|l| l.as_trait())
668-
{
664+
if let Some(deref_trait) = self.resolve_lang_trait(LangItem::Deref) {
669665
if let Some(deref_fn) =
670666
self.db.trait_data(deref_trait).method_by_name(&name![deref])
671667
{
@@ -678,7 +674,14 @@ impl<'a> InferenceContext<'a> {
678674
);
679675
}
680676
}
681-
autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
677+
if let Some(derefed) =
678+
autoderef::builtin_deref(&mut self.table, &inner_ty, true)
679+
{
680+
self.resolve_ty_shallow(derefed)
681+
} else {
682+
autoderef::deref_by_trait(&mut self.table, inner_ty)
683+
.unwrap_or_else(|| self.err_ty())
684+
}
682685
}
683686
UnaryOp::Neg => {
684687
match inner_ty.kind(Interner) {

crates/hir-ty/src/tests/simple.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,9 +854,9 @@ fn test2(a1: *const A, a2: *mut A) {
854854
237..239 'a2': *mut A
855855
249..272 '{ ...2.b; }': ()
856856
255..257 'a1': *const A
857-
255..259 'a1.b': B
857+
255..259 'a1.b': {unknown}
858858
265..267 'a2': *mut A
859-
265..269 'a2.b': B
859+
265..269 'a2.b': {unknown}
860860
"#]],
861861
);
862862
}

crates/hir-ty/src/tests/traits.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,7 +3051,7 @@ impl<T: ?Sized> core::ops::Deref for Box<T> {
30513051
type Target = T;
30523052
30533053
fn deref(&self) -> &T {
3054-
&self.inner
3054+
unsafe { &*self.inner }
30553055
}
30563056
}
30573057
@@ -3062,23 +3062,25 @@ fn foo() {
30623062
}"#,
30633063
expect![[r#"
30643064
154..158 'self': &Box<T>
3065-
166..193 '{ ... }': &T
3066-
176..187 '&self.inner': &*mut T
3067-
177..181 'self': &Box<T>
3068-
177..187 'self.inner': *mut T
3069-
206..296 '{ ...&s); }': ()
3070-
216..217 's': Option<i32>
3071-
220..224 'None': Option<i32>
3072-
234..235 'f': Box<dyn FnOnce(&Option<i32>)>
3073-
269..282 'box (|ps| {})': Box<|&Option<i32>| -> ()>
3074-
274..281 '|ps| {}': |&Option<i32>| -> ()
3075-
275..277 'ps': &Option<i32>
3076-
279..281 '{}': ()
3077-
288..289 'f': Box<dyn FnOnce(&Option<i32>)>
3078-
288..293 'f(&s)': ()
3079-
290..292 '&s': &Option<i32>
3080-
291..292 's': Option<i32>
3081-
269..282: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
3065+
166..205 '{ ... }': &T
3066+
176..199 'unsafe...nner }': &T
3067+
185..197 '&*self.inner': &T
3068+
186..197 '*self.inner': T
3069+
187..191 'self': &Box<T>
3070+
187..197 'self.inner': *mut T
3071+
218..308 '{ ...&s); }': ()
3072+
228..229 's': Option<i32>
3073+
232..236 'None': Option<i32>
3074+
246..247 'f': Box<dyn FnOnce(&Option<i32>)>
3075+
281..294 'box (|ps| {})': Box<|&Option<i32>| -> ()>
3076+
286..293 '|ps| {}': |&Option<i32>| -> ()
3077+
287..289 'ps': &Option<i32>
3078+
291..293 '{}': ()
3079+
300..301 'f': Box<dyn FnOnce(&Option<i32>)>
3080+
300..305 'f(&s)': ()
3081+
302..304 '&s': &Option<i32>
3082+
303..304 's': Option<i32>
3083+
281..294: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|&Option<i32>| -> ()>
30823084
"#]],
30833085
);
30843086
}

0 commit comments

Comments
 (0)