Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/expr.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/expr.rs | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 3cb7afef74..6dee0322a9 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -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(_)) => { @@ -891,7 +911,15 @@ impl<'a> InferenceContext<'a> { let lhs_ty = self.insert_type_vars_shallow(lhs_ty); let ty = match self.coerce(None, &rhs_ty, &lhs_ty) { Ok(ty) => ty, - Err(_) => self.err_ty(), + Err(_) => { + self.result.type_mismatches.insert( + lhs.into(), + TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() }, + ); + // `rhs_ty` is returned so no further type mismatches are + // reported because of this mismatch. + rhs_ty + } }; self.write_expr_ty(lhs, ty.clone()); return ty; |