Skip to content

Commit d1ac462

Browse files
committed
Auto merge of rust-lang#12680 - lowr:fix/12428-regression, r=Veykril
fix regressions on assignment expressions This is a follow-up PR on rust-lang#12428. I'm not sure if this is everything I overlooked, so if there are more things that are not right, we may want to revert rust-lang#12428. This should also fix the increase of the type mismatches and the unknown types in diesel in the [metrics](https://rust-analyzer.github.io/metrics/?start=2022-06-23&end=2022-07-01) introduced by rust-lang#12428. The regressions are: - some coercions don't work in the ordinary (i.e. non-destructuring) assignments In order for coercions on ADT fields instantiations to work, lhs type has to be known before inferring rhs. rust-lang#12428 changed the inference order, making rhs inferred before lhs, breaking the coercion, so I restored the original inference mechanism for the ordinary assignments. Note that this kind of coercion doesn't happen in destructuring assigments, because when they are desugared, the struct expression is first assigned to a temporary, which is then assigned to the assignee, which is not coercion site anymore. - type mismatches on individual identifiers are not reported
2 parents d101439 + 649e1f5 commit d1ac462

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

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

+31-3
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(_)) => {
@@ -891,7 +911,15 @@ impl<'a> InferenceContext<'a> {
891911
let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
892912
let ty = match self.coerce(None, &rhs_ty, &lhs_ty) {
893913
Ok(ty) => ty,
894-
Err(_) => self.err_ty(),
914+
Err(_) => {
915+
self.result.type_mismatches.insert(
916+
lhs.into(),
917+
TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
918+
);
919+
// `rhs_ty` is returned so no further type mismatches are
920+
// reported because of this mismatch.
921+
rhs_ty
922+
}
895923
};
896924
self.write_expr_ty(lhs, ty.clone());
897925
return ty;

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

+44
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+
}

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

+27
Original file line numberDiff line numberDiff line change
@@ -3043,3 +3043,30 @@ fn main() {
30433043
"#,
30443044
);
30453045
}
3046+
3047+
#[test]
3048+
fn destructuring_assignment_type_mismatch_on_identifier() {
3049+
check(
3050+
r#"
3051+
struct S { v: i64 }
3052+
struct TS(i64);
3053+
fn main() {
3054+
let mut a: usize = 0;
3055+
(a,) = (0i64,);
3056+
//^expected i64, got usize
3057+
3058+
let mut a: usize = 0;
3059+
[a,] = [0i64,];
3060+
//^expected i64, got usize
3061+
3062+
let mut a: usize = 0;
3063+
S { v: a } = S { v: 0 };
3064+
//^expected i64, got usize
3065+
3066+
let mut a: usize = 0;
3067+
TS(a) = TS(0);
3068+
//^expected i64, got usize
3069+
}
3070+
"#,
3071+
);
3072+
}

0 commit comments

Comments
 (0)