op,
is_assign);
- let lhs_needs = match is_assign {
- IsAssign::Yes => Needs::MutPlace,
- IsAssign::No => Needs::None
+ let lhs_ty = match is_assign {
+ IsAssign::No => {
+ // Find a suitable supertype of the LHS expression's type, by coercing to
+ // a type variable, to pass as the `Self` to the trait, avoiding invariant
+ // trait matching creating lifetime constraints that are too strict.
+ // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
+ // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
+ let lhs_ty = self.check_expr_with_needs(lhs_expr, Needs::None);
+ let fresh_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span));
+ self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No)
+ }
+ IsAssign::Yes => {
+ // rust-lang/rust#52126: We have to use strict
+ // equivalence on the LHS of an assign-op like `+=`;
+ // overwritten or mutably-borrowed places cannot be
+ // coerced to a supertype.
+ self.check_expr_with_needs(lhs_expr, Needs::MutPlace)
+ }
};
- // Find a suitable supertype of the LHS expression's type, by coercing to
- // a type variable, to pass as the `Self` to the trait, avoiding invariant
- // trait matching creating lifetime constraints that are too strict.
- // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
- // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
- let lhs_ty = self.check_expr_with_needs(lhs_expr, lhs_needs);
- let fresh_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span));
- let lhs_ty = self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No);
let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
// NB: As we have not yet type-checked the RHS, we don't have the