mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Merge pull request #19111 from ShoyuVanilla/issue-19021
fix: Apply adjustments to proper expr when invoking `CoerceMany`
This commit is contained in:
commit
c9838ec62d
@ -1239,7 +1239,29 @@ impl<'a> InferenceContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
|
fn write_expr_adj(&mut self, expr: ExprId, adjustments: Vec<Adjustment>) {
|
||||||
self.result.expr_adjustments.insert(expr, adjustments);
|
if adjustments.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match self.result.expr_adjustments.entry(expr) {
|
||||||
|
std::collections::hash_map::Entry::Occupied(mut entry) => {
|
||||||
|
match (&mut entry.get_mut()[..], &adjustments[..]) {
|
||||||
|
(
|
||||||
|
[Adjustment { kind: Adjust::NeverToAny, target }],
|
||||||
|
[.., Adjustment { target: new_target, .. }],
|
||||||
|
) => {
|
||||||
|
// NeverToAny coercion can target any type, so instead of adding a new
|
||||||
|
// adjustment on top we can change the target.
|
||||||
|
*target = new_target.clone();
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
*entry.get_mut() = adjustments;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::collections::hash_map::Entry::Vacant(entry) => {
|
||||||
|
entry.insert(adjustments);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
|
fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
|
||||||
|
@ -163,10 +163,27 @@ impl CoerceMany {
|
|||||||
// type is a type variable and the new one is `!`, trying it the other
|
// type is a type variable and the new one is `!`, trying it the other
|
||||||
// way around first would mean we make the type variable `!`, instead of
|
// way around first would mean we make the type variable `!`, instead of
|
||||||
// just marking it as possibly diverging.
|
// just marking it as possibly diverging.
|
||||||
|
//
|
||||||
|
// - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335)
|
||||||
|
// First try to coerce the new expression to the type of the previous ones,
|
||||||
|
// but only if the new expression has no coercion already applied to it.
|
||||||
|
if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) {
|
||||||
if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
|
if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) {
|
||||||
self.final_ty = Some(res);
|
self.final_ty = Some(res);
|
||||||
} else if let Ok(res) = ctx.coerce(expr, &self.merged_ty(), &expr_ty, CoerceNever::Yes) {
|
if let Some(expr) = expr {
|
||||||
|
self.expressions.push(expr);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok((adjustments, res)) =
|
||||||
|
ctx.coerce_inner(&self.merged_ty(), &expr_ty, CoerceNever::Yes)
|
||||||
|
{
|
||||||
self.final_ty = Some(res);
|
self.final_ty = Some(res);
|
||||||
|
for &e in &self.expressions {
|
||||||
|
ctx.write_expr_adj(e, adjustments.clone());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match cause {
|
match cause {
|
||||||
CoercionCause::Expr(id) => {
|
CoercionCause::Expr(id) => {
|
||||||
@ -244,14 +261,23 @@ impl InferenceContext<'_> {
|
|||||||
// between places and values.
|
// between places and values.
|
||||||
coerce_never: CoerceNever,
|
coerce_never: CoerceNever,
|
||||||
) -> Result<Ty, TypeError> {
|
) -> Result<Ty, TypeError> {
|
||||||
let from_ty = self.resolve_ty_shallow(from_ty);
|
let (adjustments, ty) = self.coerce_inner(from_ty, to_ty, coerce_never)?;
|
||||||
let to_ty = self.resolve_ty_shallow(to_ty);
|
|
||||||
let (adjustments, ty) = self.table.coerce(&from_ty, &to_ty, coerce_never)?;
|
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
self.write_expr_adj(expr, adjustments);
|
self.write_expr_adj(expr, adjustments);
|
||||||
}
|
}
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn coerce_inner(
|
||||||
|
&mut self,
|
||||||
|
from_ty: &Ty,
|
||||||
|
to_ty: &Ty,
|
||||||
|
coerce_never: CoerceNever,
|
||||||
|
) -> Result<(Vec<Adjustment>, Ty), TypeError> {
|
||||||
|
let from_ty = self.resolve_ty_shallow(from_ty);
|
||||||
|
let to_ty = self.resolve_ty_shallow(to_ty);
|
||||||
|
self.table.coerce(&from_ty, &to_ty, coerce_never)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InferenceTable<'_> {
|
impl InferenceTable<'_> {
|
||||||
|
@ -912,3 +912,36 @@ fn main() {
|
|||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn regression_19021() {
|
||||||
|
check_pass(
|
||||||
|
r#"
|
||||||
|
//- minicore: deref
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
#[lang = "owned_box"]
|
||||||
|
struct Box<T>(T);
|
||||||
|
|
||||||
|
impl<T> Deref for Box<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = Box(Foo);
|
||||||
|
let y = &Foo;
|
||||||
|
|
||||||
|
|| match x {
|
||||||
|
ref x => x,
|
||||||
|
_ => y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -185,11 +185,10 @@ fn test() {
|
|||||||
let t = &mut 1;
|
let t = &mut 1;
|
||||||
let x = match 1 {
|
let x = match 1 {
|
||||||
1 => t as *mut i32,
|
1 => t as *mut i32,
|
||||||
|
//^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
|
||||||
2 => t as &i32,
|
2 => t as &i32,
|
||||||
//^^^^^^^^^ expected *mut i32, got &'? i32
|
//^^^^^^^^^ expected *mut i32, got &'? i32
|
||||||
_ => t as *const i32,
|
_ => t as *const i32,
|
||||||
// ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
|
|
||||||
|
|
||||||
};
|
};
|
||||||
x;
|
x;
|
||||||
//^ type: *const i32
|
//^ type: *const i32
|
||||||
|
Loading…
x
Reference in New Issue
Block a user