Skip to content

Commit 4a15593

Browse files
authored
Merge pull request rust-lang#19111 from ShoyuVanilla/issue-19021
fix: Apply adjustments to proper expr when invoking `CoerceMany`
2 parents 53e6870 + 7201010 commit 4a15593

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,29 @@ impl<'a> InferenceContext<'a> {
12391239
}
12401240

12411241
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
1242-
self.result.expr_adjustments.insert(expr, adjustments);
1242+
if adjustments.is_empty() {
1243+
return;
1244+
}
1245+
match self.result.expr_adjustments.entry(expr) {
1246+
std::collections::hash_map::Entry::Occupied(mut entry) => {
1247+
match (&mut entry.get_mut()[..], &adjustments[..]) {
1248+
(
1249+
[Adjustment { kind: Adjust::NeverToAny, target }],
1250+
[.., Adjustment { target: new_target, .. }],
1251+
) => {
1252+
// NeverToAny coercion can target any type, so instead of adding a new
1253+
// adjustment on top we can change the target.
1254+
*target = new_target.clone();
1255+
}
1256+
_ => {
1257+
*entry.get_mut() = adjustments;
1258+
}
1259+
}
1260+
}
1261+
std::collections::hash_map::Entry::Vacant(entry) => {
1262+
entry.insert(adjustments);
1263+
}
1264+
}
12431265
}
12441266

12451267
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {

src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,27 @@ impl CoerceMany {
163163
// type is a type variable and the new one is `!`, trying it the other
164164
// way around first would mean we make the type variable `!`, instead of
165165
// just marking it as possibly diverging.
166-
if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
167-
self.final_ty = Some(res);
168-
} else if let Ok(res) = ctx.coerce(expr, &self.merged_ty(), &expr_ty, CoerceNever::Yes) {
166+
//
167+
// - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
168+
// First try to coerce the new expression to the type of the previous ones,
169+
// but only if the new expression has no coercion already applied to it.
170+
if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) {
171+
if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
172+
self.final_ty = Some(res);
173+
if let Some(expr) = expr {
174+
self.expressions.push(expr);
175+
}
176+
return;
177+
}
178+
}
179+
180+
if let Ok((adjustments, res)) =
181+
ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes)
182+
{
169183
self.final_ty = Some(res);
184+
for &e in &self.expressions {
185+
ctx.write_expr_adj(e, adjustments.clone());
186+
}
170187
} else {
171188
match cause {
172189
CoercionCause::Expr(id) => {
@@ -244,14 +261,23 @@ impl InferenceContext<'_> {
244261
// between places and values.
245262
coerce_never: CoerceNever,
246263
) -> Result<Ty, TypeError> {
247-
let from_ty = self.resolve_ty_shallow(from_ty);
248-
let to_ty = self.resolve_ty_shallow(to_ty);
249-
let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty, coerce_never)?;
264+
let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?;
250265
if let Some(expr) = expr {
251266
self.write_expr_adj(expr, adjustments);
252267
}
253268
Ok(ty)
254269
}
270+
271+
fn coerce_inner(
272+
&mut self,
273+
from_ty: &Ty,
274+
to_ty: &Ty,
275+
coerce_never: CoerceNever,
276+
) -> Result<(Vec<Adjustment>, Ty), TypeError> {
277+
let from_ty = self.resolve_ty_shallow(from_ty);
278+
let to_ty = self.resolve_ty_shallow(to_ty);
279+
self.table.coerce(&from_ty, &to_ty, coerce_never)
280+
}
255281
}
256282

257283
impl InferenceTable<'_> {

src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,3 +912,36 @@ fn main() {
912912
"",
913913
);
914914
}
915+
916+
#[test]
917+
fn regression_19021() {
918+
check_pass(
919+
r#"
920+
//- minicore: deref
921+
use core::ops::Deref;
922+
923+
#[lang = "owned_box"]
924+
struct Box<T>(T);
925+
926+
impl<T> Deref for Box<T> {
927+
type Target = T;
928+
929+
fn deref(&self) -> &Self::Target {
930+
&self.0
931+
}
932+
}
933+
934+
struct Foo;
935+
936+
fn main() {
937+
let x = Box(Foo);
938+
let y = &Foo;
939+
940+
|| match x {
941+
ref x => x,
942+
_ => y,
943+
};
944+
}
945+
"#,
946+
);
947+
}

src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,10 @@ fn test() {
185185
let t = &mut 1;
186186
let x = match 1 {
187187
1 => t as *mut i32,
188+
//^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
188189
2 => t as &i32,
189190
//^^^^^^^^^ expected *mut i32, got &'? i32
190191
_ => t as *const i32,
191-
// ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
192-
193192
};
194193
x;
195194
//^ type: *const i32

0 commit comments

Comments
 (0)