fix: infer lhs first on ordinary assignment expressions

This commit is contained in:
Ryo Yoshida 2022-07-03 01:57:23 +09:00
parent d101439c77
commit afdbd6cce2
No known key found for this signature in database
GPG key ID: E25698A930586171
2 changed files with 66 additions and 2 deletions

View file

@ -593,8 +593,28 @@ impl<'a> InferenceContext<'a> {
} }
Expr::BinaryOp { lhs, rhs, op } => match op { Expr::BinaryOp { lhs, rhs, op } => match op {
Some(BinaryOp::Assignment { op: None }) => { Some(BinaryOp::Assignment { op: None }) => {
let rhs_ty = self.infer_expr(*rhs, &Expectation::none()); let lhs = *lhs;
self.infer_assignee_expr(*lhs, &rhs_ty); 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() self.result.standard_types.unit.clone()
} }
Some(BinaryOp::LogicOp(_)) => { Some(BinaryOp::LogicOp(_)) => {

View file

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