mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
fix: infer lhs first on ordinary assignment expressions
This commit is contained in:
parent
d101439c77
commit
afdbd6cce2
2 changed files with 66 additions and 2 deletions
|
@ -593,8 +593,28 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
Expr::BinaryOp { lhs, rhs, op } => match op {
|
||||
Some(BinaryOp::Assignment { op: None }) => {
|
||||
let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
|
||||
self.infer_assignee_expr(*lhs, &rhs_ty);
|
||||
let lhs = *lhs;
|
||||
let is_ordinary = match &self.body[lhs] {
|
||||
Expr::Array(_)
|
||||
| Expr::RecordLit { .. }
|
||||
| Expr::Tuple { .. }
|
||||
| Expr::Underscore => false,
|
||||
Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
// In ordinary (non-destructuring) assignments, the type of
|
||||
// `lhs` must be inferred first so that the ADT fields
|
||||
// instantiations in RHS can be coerced to it. Note that this
|
||||
// cannot happen in destructuring assignments because of how
|
||||
// they are desugared.
|
||||
if is_ordinary {
|
||||
let lhs_ty = self.infer_expr(lhs, &Expectation::none());
|
||||
self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
|
||||
} else {
|
||||
let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
|
||||
self.infer_assignee_expr(lhs, &rhs_ty);
|
||||
}
|
||||
self.result.standard_types.unit.clone()
|
||||
}
|
||||
Some(BinaryOp::LogicOp(_)) => {
|
||||
|
|
|
@ -709,3 +709,47 @@ fn test() {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_coerce_struct_fields() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
struct S;
|
||||
trait Tr {}
|
||||
impl Tr for S {}
|
||||
struct V<T> { t: T }
|
||||
|
||||
fn main() {
|
||||
let a: V<&dyn Tr>;
|
||||
a = V { t: &S };
|
||||
|
||||
let mut a: V<&dyn Tr> = V { t: &S };
|
||||
a = V { t: &S };
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destructuring_assign_coerce_struct_fields() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
struct S;
|
||||
trait Tr {}
|
||||
impl Tr for S {}
|
||||
struct V<T> { t: T }
|
||||
|
||||
fn main() {
|
||||
let a: V<&dyn Tr>;
|
||||
(a,) = V { t: &S };
|
||||
//^^^^expected V<&S>, got (V<&dyn Tr>,)
|
||||
|
||||
let mut a: V<&dyn Tr> = V { t: &S };
|
||||
(a,) = V { t: &S };
|
||||
//^^^^expected V<&S>, got (V<&dyn Tr>,)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue