Skip to content

Commit afdbd6c

Browse files
committed
fix: infer lhs first on ordinary assignment expressions
1 parent d101439 commit afdbd6c

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,28 @@ impl<'a> InferenceContext<'a> {
593593
}
594594
Expr::BinaryOp { lhs, rhs, op } => match op {
595595
Some(BinaryOp::Assignment { op: None }) => {
596-
let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
597-
self.infer_assignee_expr(*lhs, &rhs_ty);
596+
let lhs = *lhs;
597+
let is_ordinary = match &self.body[lhs] {
598+
Expr::Array(_)
599+
| Expr::RecordLit { .. }
600+
| Expr::Tuple { .. }
601+
| Expr::Underscore => false,
602+
Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
603+
_ => true,
604+
};
605+
606+
// In ordinary (non-destructuring) assignments, the type of
607+
// `lhs` must be inferred first so that the ADT fields
608+
// instantiations in RHS can be coerced to it. Note that this
609+
// cannot happen in destructuring assignments because of how
610+
// they are desugared.
611+
if is_ordinary {
612+
let lhs_ty = self.infer_expr(lhs, &Expectation::none());
613+
self.infer_expr_coerce(*rhs, &Expectation::has_type(lhs_ty));
614+
} else {
615+
let rhs_ty = self.infer_expr(*rhs, &Expectation::none());
616+
self.infer_assignee_expr(lhs, &rhs_ty);
617+
}
598618
self.result.standard_types.unit.clone()
599619
}
600620
Some(BinaryOp::LogicOp(_)) => {

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,3 +709,47 @@ fn test() {
709709
"#,
710710
);
711711
}
712+
713+
#[test]
714+
fn assign_coerce_struct_fields() {
715+
check_no_mismatches(
716+
r#"
717+
//- minicore: coerce_unsized
718+
struct S;
719+
trait Tr {}
720+
impl Tr for S {}
721+
struct V<T> { t: T }
722+
723+
fn main() {
724+
let a: V<&dyn Tr>;
725+
a = V { t: &S };
726+
727+
let mut a: V<&dyn Tr> = V { t: &S };
728+
a = V { t: &S };
729+
}
730+
"#,
731+
);
732+
}
733+
734+
#[test]
735+
fn destructuring_assign_coerce_struct_fields() {
736+
check(
737+
r#"
738+
//- minicore: coerce_unsized
739+
struct S;
740+
trait Tr {}
741+
impl Tr for S {}
742+
struct V<T> { t: T }
743+
744+
fn main() {
745+
let a: V<&dyn Tr>;
746+
(a,) = V { t: &S };
747+
//^^^^expected V<&S>, got (V<&dyn Tr>,)
748+
749+
let mut a: V<&dyn Tr> = V { t: &S };
750+
(a,) = V { t: &S };
751+
//^^^^expected V<&S>, got (V<&dyn Tr>,)
752+
}
753+
"#,
754+
);
755+
}

0 commit comments

Comments
 (0)