Skip to content

Commit 6998c73

Browse files
committed
Suggest swapping LHS and RHS for PartialEq
1 parent c8b8378 commit 6998c73

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+29
Original file line numberDiff line numberDiff line change
@@ -3390,4 +3390,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
33903390
err.span_label(block.span, "this block is missing a tail expression");
33913391
}
33923392
}
3393+
3394+
pub(crate) fn suggest_swapping_lhs_and_rhs(
3395+
&self,
3396+
err: &mut Diag<'_>,
3397+
checked_ty: Ty<'tcx>,
3398+
expected_ty_expr: &'tcx hir::Expr<'tcx>,
3399+
op: hir::BinOp,
3400+
) {
3401+
match op.node {
3402+
hir::BinOpKind::Eq => {
3403+
if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
3404+
&& let lhs_ty = self.check_expr(expected_ty_expr)
3405+
&& self
3406+
.infcx
3407+
.type_implements_trait(
3408+
partial_eq_def_id,
3409+
[checked_ty, lhs_ty],
3410+
self.param_env,
3411+
)
3412+
.must_apply_modulo_regions()
3413+
{
3414+
let trait_name = self.infcx.tcx.item_name(partial_eq_def_id);
3415+
err.note(format!("`{}` implements `{}<{}>`", checked_ty, trait_name, lhs_ty));
3416+
err.help(format!("consider swapping the LHS and RHS of the equality"));
3417+
}
3418+
}
3419+
_ => {}
3420+
}
3421+
}
33933422
}

compiler/rustc_hir_typeck/src/op.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
198198
}
199199
}
200200

201+
fn check_expr_coercible_to_type_or_error(
202+
&self,
203+
expr: &'tcx hir::Expr<'tcx>,
204+
expected: Ty<'tcx>,
205+
expected_ty_expr: &'tcx hir::Expr<'tcx>,
206+
op: hir::BinOp,
207+
) -> Ty<'tcx> {
208+
let ty = self.check_expr_with_hint(expr, expected);
209+
// checks don't need two phase
210+
match self.demand_coerce_diag(expr, ty, expected, Some(expected_ty_expr), AllowTwoPhase::No)
211+
{
212+
Ok(ty) => ty,
213+
Err(mut err) => {
214+
self.suggest_swapping_lhs_and_rhs(&mut err, ty, expected_ty_expr, op);
215+
err.emit();
216+
// Return the original type instead of an error type here, otherwise the type of `x` in
217+
// `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not
218+
// report errors, even though `x` is definitely `u32`.
219+
expected
220+
}
221+
}
222+
}
223+
201224
fn check_overloaded_binop(
202225
&self,
203226
expr: &'tcx hir::Expr<'tcx>,
@@ -249,7 +272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
249272
);
250273

251274
// see `NB` above
252-
let rhs_ty = self.check_expr_coercible_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
275+
let rhs_ty = self.check_expr_coercible_to_type_or_error(rhs_expr, rhs_ty_var, lhs_expr, op);
253276
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
254277

255278
let return_ty = match result {

0 commit comments

Comments
 (0)