Auto merge of #132404 - makai410:suggest-swap-lhs-rhs, r=fee1-dead
Suggest swapping LHS and RHS when RHS impls `PartialEq<lhs_ty>` Closes: #130495 r? `@fee1-dead`
This commit is contained in:
commit
4d215e2426
@ -102,10 +102,30 @@ pub(super) fn check_expr_coercible_to_type(
|
|||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
|
) -> Ty<'tcx> {
|
||||||
|
self.check_expr_coercible_to_type_or_error(expr, expected, expected_ty_expr, |_, _| {})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn check_expr_coercible_to_type_or_error(
|
||||||
|
&self,
|
||||||
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
expected: Ty<'tcx>,
|
||||||
|
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
|
extend_err: impl FnOnce(&mut Diag<'_>, Ty<'tcx>),
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let ty = self.check_expr_with_hint(expr, expected);
|
let ty = self.check_expr_with_hint(expr, expected);
|
||||||
// checks don't need two phase
|
// checks don't need two phase
|
||||||
self.demand_coerce(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No)
|
match self.demand_coerce_diag(expr, ty, expected, expected_ty_expr, AllowTwoPhase::No) {
|
||||||
|
Ok(ty) => ty,
|
||||||
|
Err(mut err) => {
|
||||||
|
extend_err(&mut err, ty);
|
||||||
|
err.emit();
|
||||||
|
// Return the original type instead of an error type here, otherwise the type of `x` in
|
||||||
|
// `let x: u32 = ();` will be a type error, causing all subsequent usages of `x` to not
|
||||||
|
// report errors, even though `x` is definitely `u32`.
|
||||||
|
expected
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn check_expr_with_hint(
|
pub(super) fn check_expr_with_hint(
|
||||||
|
@ -3390,4 +3390,38 @@ pub(crate) fn suggest_return_binding_for_missing_tail_expr(
|
|||||||
err.span_label(block.span, "this block is missing a tail expression");
|
err.span_label(block.span, "this block is missing a tail expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn suggest_swapping_lhs_and_rhs(
|
||||||
|
&self,
|
||||||
|
err: &mut Diag<'_>,
|
||||||
|
rhs_ty: Ty<'tcx>,
|
||||||
|
lhs_ty: Ty<'tcx>,
|
||||||
|
rhs_expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
lhs_expr: &'tcx hir::Expr<'tcx>,
|
||||||
|
op: hir::BinOp,
|
||||||
|
) {
|
||||||
|
match op.node {
|
||||||
|
hir::BinOpKind::Eq => {
|
||||||
|
if let Some(partial_eq_def_id) = self.infcx.tcx.lang_items().eq_trait()
|
||||||
|
&& self
|
||||||
|
.infcx
|
||||||
|
.type_implements_trait(partial_eq_def_id, [rhs_ty, lhs_ty], self.param_env)
|
||||||
|
.must_apply_modulo_regions()
|
||||||
|
{
|
||||||
|
let sm = self.tcx.sess.source_map();
|
||||||
|
if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_expr.span)
|
||||||
|
&& let Ok(lhs_snippet) = sm.span_to_snippet(lhs_expr.span)
|
||||||
|
{
|
||||||
|
err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`"));
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"consider swapping the equality",
|
||||||
|
vec![(lhs_expr.span, rhs_snippet), (rhs_expr.span, lhs_snippet)],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,14 @@ fn check_overloaded_binop(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// see `NB` above
|
// see `NB` above
|
||||||
let rhs_ty = self.check_expr_coercible_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr));
|
let rhs_ty = self.check_expr_coercible_to_type_or_error(
|
||||||
|
rhs_expr,
|
||||||
|
rhs_ty_var,
|
||||||
|
Some(lhs_expr),
|
||||||
|
|err, ty| {
|
||||||
|
self.suggest_swapping_lhs_and_rhs(err, ty, lhs_ty, rhs_expr, lhs_expr, op);
|
||||||
|
},
|
||||||
|
);
|
||||||
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
|
let rhs_ty = self.resolve_vars_with_obligations(rhs_ty);
|
||||||
|
|
||||||
let return_ty = match result {
|
let return_ty = match result {
|
||||||
|
11
tests/ui/suggestions/partialeq_suggest_swap.rs
Normal file
11
tests/ui/suggestions/partialeq_suggest_swap.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
struct T(i32);
|
||||||
|
|
||||||
|
impl PartialEq<i32> for T {
|
||||||
|
fn eq(&self, other: &i32) -> bool {
|
||||||
|
&self.0 == other
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
4i32 == T(4); //~ mismatched types [E0308]
|
||||||
|
}
|
17
tests/ui/suggestions/partialeq_suggest_swap.stderr
Normal file
17
tests/ui/suggestions/partialeq_suggest_swap.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/partialeq_suggest_swap.rs:10:13
|
||||||
|
|
|
||||||
|
LL | 4i32 == T(4);
|
||||||
|
| ---- ^^^^ expected `i32`, found `T`
|
||||||
|
| |
|
||||||
|
| expected because this is `i32`
|
||||||
|
|
|
||||||
|
= note: `T` implements `PartialEq<i32>`
|
||||||
|
help: consider swapping the equality
|
||||||
|
|
|
||||||
|
LL | T(4) == 4i32;
|
||||||
|
| ~~~~ ~~~~
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user