From 9d8fb13fc299f33ee0a457a5552c9159412e35f3 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 17 Oct 2021 19:37:39 +0000 Subject: [PATCH 01/14] Evaluate binops a second time with resolved rhs type for suggestions --- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- .../rustc_typeck/src/check/method/confirm.rs | 1 + compiler/rustc_typeck/src/check/method/mod.rs | 5 +- compiler/rustc_typeck/src/check/op.rs | 94 +++++++++++++++++-- src/test/ui/binop/binop-mul-i32-f32.stderr | 13 ++- src/test/ui/binop/issue-77910-1.rs | 2 +- src/test/ui/binop/issue-77910-1.stderr | 2 +- src/test/ui/binop/issue-77910-2.rs | 2 +- src/test/ui/binop/issue-77910-2.stderr | 2 +- .../const-eval/const-eval-overflow-3b.stderr | 25 +++-- .../const-eval/const-eval-overflow-4b.stderr | 25 +++-- src/test/ui/fn/fn-compare-mismatch.rs | 2 +- src/test/ui/fn/fn-compare-mismatch.stderr | 2 +- src/test/ui/impl-trait/equality.stderr | 12 +-- src/test/ui/issues/issue-11771.rs | 4 +- src/test/ui/issues/issue-11771.stderr | 22 +++-- src/test/ui/issues/issue-31076.rs | 2 +- src/test/ui/issues/issue-31076.stderr | 22 ++++- src/test/ui/issues/issue-50582.stderr | 12 +-- src/test/ui/issues/issue-59488.rs | 6 +- src/test/ui/issues/issue-59488.stderr | 6 +- src/test/ui/issues/issue-62375.rs | 2 +- src/test/ui/issues/issue-62375.stderr | 2 +- .../issues/issue-66667-function-cmp-cycle.rs | 6 +- .../issue-66667-function-cmp-cycle.stderr | 6 +- ...sue-70724-add_type_neq_err_label-unwrap.rs | 2 +- ...70724-add_type_neq_err_label-unwrap.stderr | 2 +- src/test/ui/mismatched_types/binops.stderr | 23 ++--- src/test/ui/parser/lex-bad-char-literals-6.rs | 4 +- .../ui/parser/lex-bad-char-literals-6.stderr | 26 ++--- src/test/ui/partialeq_help.fixed | 8 ++ src/test/ui/partialeq_help.rs | 3 +- src/test/ui/partialeq_help.stderr | 23 +++-- src/test/ui/shift-various-bad-types.rs | 6 +- src/test/ui/shift-various-bad-types.stderr | 28 +++--- src/test/ui/span/multiline-span-simple.stderr | 17 ++-- .../missing-trait-bound-for-op.fixed | 2 +- .../suggestions/missing-trait-bound-for-op.rs | 2 +- .../missing-trait-bound-for-op.stderr | 2 +- src/test/ui/typeck/issue-81293.rs | 3 +- src/test/ui/typeck/issue-81293.stderr | 35 +++---- 41 files changed, 301 insertions(+), 164 deletions(-) create mode 100644 src/test/ui/partialeq_help.fixed diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index ac4bb65224486..788ff2a41cea9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -656,7 +656,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn select_obligations_where_possible( &self, fallback_has_occurred: bool, - mutate_fulfillment_errors: impl Fn(&mut Vec>), + mut mutate_fulfillment_errors: impl FnMut(&mut Vec>), ) { let result = self .fulfillment_cx diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index dc54f63f49c8d..e7a6f194c7ed2 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -128,6 +128,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { def_id: pick.item.def_id, substs: all_substs, sig: method_sig.skip_binder(), + trait_def_id: pick.item.container.id(), }; ConfirmResult { callee, illegal_sized_bound } } diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index f0f2470e80a8c..5c315d22a7e6c 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -44,6 +44,9 @@ pub struct MethodCallee<'tcx> { /// substituted, normalized, and has had late-bound /// lifetimes replaced with inference variables. pub sig: ty::FnSig<'tcx>, + + /// Used only for diagnostics, to skip redundant E0277 errors. + pub trait_def_id: DefId, } #[derive(Debug)] @@ -432,7 +435,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx), )); - let callee = MethodCallee { def_id, substs, sig: fn_sig }; + let callee = MethodCallee { def_id, substs, sig: fn_sig, trait_def_id }; debug!("callee = {:?}", callee); diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 1bbdf910e420a..4b203866dcc10 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -206,6 +206,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); + let mut erased = false; + let mut non_binop_obligations = 0; + self.select_obligations_where_possible(false, |errors| { + errors.retain(|e| match (&result, e.obligation.predicate.kind().skip_binder()) { + (Ok(callee), ty::PredicateKind::Trait(predicate)) => { + // Skip the obligations coming from the binop, we want to emit E0369 instead + // of E0277. + erased = true; + callee.trait_def_id != predicate.def_id() + } + _ => true, + }); + non_binop_obligations = errors.len(); + }); + + // Run again with more accurate types for better diagnostics. Even if `result` was `Ok`, + // we can rerun with a more accurate rhs type for eager obligation errors. + let result = if result.is_ok() && erased && non_binop_obligations == 0 { + self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)) + } else { + result + }; let return_ty = match result { Ok(method) => { @@ -261,6 +283,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { let source_map = self.tcx.sess.source_map(); + let lhs_ty = self.resolve_vars_if_possible(lhs_ty); + let rhs_ty = self.resolve_vars_if_possible(rhs_ty); let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( @@ -344,11 +368,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true, ), hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), + // can't compare `&str` with `char` + if lhs_ty == rhs_ty { + format!( + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty, + ) + } else { + format!("can't compare `{}` with `{}`", lhs_ty, rhs_ty,) + }, Some("std::cmp::PartialEq"), false, ), @@ -356,11 +385,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::BinOpKind::Le | hir::BinOpKind::Gt | hir::BinOpKind::Ge => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), + if lhs_ty == rhs_ty { + format!( + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty + ) + } else { + format!("can't compare `{}` with `{}`", lhs_ty, rhs_ty,) + }, Some("std::cmp::PartialOrd"), false, ), @@ -398,6 +431,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, missing_trait, use_output) } }; + + let borrowed_rhs = self.tcx.mk_ref( + self.tcx.lifetimes.re_static, + ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, + ); + if self.lookup_op_method(lhs_ty, &[borrowed_rhs], Op::Binary(op, is_assign)).is_ok() + { + let borrowed_rhs = self.tcx.mk_ref( + self.tcx.lifetimes.re_erased, + ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, + ); + let msg = &format!( + "`{}{}` can be applied on `{}`", + op.node.as_str(), + match is_assign { + IsAssign::Yes => "=", + IsAssign::No => "", + }, + borrowed_rhs, + ); + err.span_suggestion_verbose( + rhs_expr.span.shrink_to_lo(), + msg, + "&".to_string(), + rustc_errors::Applicability::MachineApplicable, + ); + } + self.check_for_cast(&mut err, rhs_expr, rhs_ty, lhs_ty, Some(lhs_expr)); + self.check_for_cast(&mut err, lhs_expr, lhs_ty, rhs_ty, Some(rhs_expr)); if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) @@ -422,6 +484,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "*".to_string(), rustc_errors::Applicability::MachineApplicable, ); + } else if let IsAssign::No = is_assign { + let msg = &format!( + "`{}` can be used on `{}`, you can borrow it", + op.node.as_str(), + rty, + ); + err.span_suggestion_verbose( + rhs_expr.span.shrink_to_lo(), + msg, + "&".to_string(), + rustc_errors::Applicability::MaybeIncorrect, + ); } } } diff --git a/src/test/ui/binop/binop-mul-i32-f32.stderr b/src/test/ui/binop/binop-mul-i32-f32.stderr index 4a67fe2379b8d..a5bc5ac2f3ce8 100644 --- a/src/test/ui/binop/binop-mul-i32-f32.stderr +++ b/src/test/ui/binop/binop-mul-i32-f32.stderr @@ -1,11 +1,16 @@ -error[E0277]: cannot multiply `i32` by `f32` +error[E0369]: cannot multiply `i32` by `f32` --> $DIR/binop-mul-i32-f32.rs:2:7 | LL | x * y - | ^ no implementation for `i32 * f32` + | - ^ - f32 + | | + | i32 | - = help: the trait `Mul` is not implemented for `i32` +help: you can convert an `i32` to an `f32`, producing the floating point representation of the integer, rounded if necessary + | +LL | x as f32 * y + | ++++++ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/binop/issue-77910-1.rs b/src/test/ui/binop/issue-77910-1.rs index d786e33585984..987ced765d002 100644 --- a/src/test/ui/binop/issue-77910-1.rs +++ b/src/test/ui/binop/issue-77910-1.rs @@ -6,6 +6,6 @@ fn main() { let y; // we shouldn't ice with the bound var here. assert_eq!(foo, y); - //~^ ERROR binary operation `==` cannot be applied to type + //~^ ERROR can't compare //~| ERROR `for<'r> fn(&'r i32) -> &'r i32 {foo}` doesn't implement `Debug` } diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr index db854ae80d738..a83bc576d8f54 100644 --- a/src/test/ui/binop/issue-77910-1.stderr +++ b/src/test/ui/binop/issue-77910-1.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}` +error[E0369]: can't compare `for<'r> fn(&'r i32) -> &'r i32 {foo}` with `_` --> $DIR/issue-77910-1.rs:8:5 | LL | assert_eq!(foo, y); diff --git a/src/test/ui/binop/issue-77910-2.rs b/src/test/ui/binop/issue-77910-2.rs index 2bb48d3657617..dac0f35bd71eb 100644 --- a/src/test/ui/binop/issue-77910-2.rs +++ b/src/test/ui/binop/issue-77910-2.rs @@ -5,5 +5,5 @@ fn foo(s: &i32) -> &i32 { fn main() { let y; if foo == y {} - //~^ ERROR binary operation `==` cannot be applied to type + //~^ ERROR can't compare } diff --git a/src/test/ui/binop/issue-77910-2.stderr b/src/test/ui/binop/issue-77910-2.stderr index 5477a5762a8fd..9517a3b568d6d 100644 --- a/src/test/ui/binop/issue-77910-2.stderr +++ b/src/test/ui/binop/issue-77910-2.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `for<'r> fn(&'r i32) -> &'r i32 {foo}` +error[E0369]: can't compare `for<'r> fn(&'r i32) -> &'r i32 {foo}` with `_` --> $DIR/issue-77910-2.rs:7:12 | LL | if foo == y {} diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 2b96b66819286..5c7c2473976d4 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -1,18 +1,23 @@ -error[E0308]: mismatched types - --> $DIR/const-eval-overflow-3b.rs:16:22 +error[E0369]: cannot add `u8` to `i8` + --> $DIR/const-eval-overflow-3b.rs:16:20 | LL | = [0; (i8::MAX + 1u8) as usize]; - | ^^^ expected `i8`, found `u8` + | ------- ^ --- u8 + | | + | i8 + | +help: change the type of the numeric literal from `u8` to `i8` + | +LL | = [0; (i8::MAX + 1i8) as usize]; + | ~~ -error[E0277]: cannot add `u8` to `i8` - --> $DIR/const-eval-overflow-3b.rs:16:20 +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-3b.rs:16:22 | LL | = [0; (i8::MAX + 1u8) as usize]; - | ^ no implementation for `i8 + u8` - | - = help: the trait `Add` is not implemented for `i8` + | ^^^ expected `i8`, found `u8` error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 1e181c465dba7..7aead0bb6c789 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -1,16 +1,21 @@ -error[E0308]: mismatched types - --> $DIR/const-eval-overflow-4b.rs:9:30 +error[E0369]: cannot add `u8` to `i8` + --> $DIR/const-eval-overflow-4b.rs:9:28 | LL | : [u32; (i8::MAX as i8 + 1u8) as usize] - | ^^^ expected `i8`, found `u8` + | ------------- ^ --- u8 + | | + | i8 + | +help: change the type of the numeric literal from `u8` to `i8` + | +LL | : [u32; (i8::MAX as i8 + 1i8) as usize] + | ~~ -error[E0277]: cannot add `u8` to `i8` - --> $DIR/const-eval-overflow-4b.rs:9:28 +error[E0308]: mismatched types + --> $DIR/const-eval-overflow-4b.rs:9:30 | LL | : [u32; (i8::MAX as i8 + 1u8) as usize] - | ^ no implementation for `i8 + u8` - | - = help: the trait `Add` is not implemented for `i8` + | ^^^ expected `i8`, found `u8` error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:22:13 @@ -20,5 +25,5 @@ LL | : [u32; 5i8 as char as usize] error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0308, E0604. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369, E0604. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/fn/fn-compare-mismatch.rs b/src/test/ui/fn/fn-compare-mismatch.rs index d734d54e8b0a8..7f24c2b43e301 100644 --- a/src/test/ui/fn/fn-compare-mismatch.rs +++ b/src/test/ui/fn/fn-compare-mismatch.rs @@ -2,6 +2,6 @@ fn main() { fn f() { } fn g() { } let x = f == g; - //~^ ERROR binary operation `==` cannot be applied + //~^ ERROR can't compare //~| ERROR mismatched types } diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index 585f556abc8b5..d1ba7833bd651 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `fn() {f}` +error[E0369]: can't compare `fn() {f}` with `fn() {g}` --> $DIR/fn-compare-mismatch.rs:4:15 | LL | let x = f == g; diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 536a4726c6de2..1e8007c58dbd7 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -26,15 +26,15 @@ LL | 0_u32 = note: for information on trait objects, see = help: you could instead create a new `enum` with a variant for each returned type -error[E0277]: cannot add `impl Foo` to `u32` +error[E0369]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:24:11 | LL | n + sum_to(n - 1) - | ^ no implementation for `u32 + impl Foo` - | - = help: the trait `Add` is not implemented for `u32` + | - ^ ------------- impl Foo + | | + | u32 error: aborting due to 2 previous errors; 1 warning emitted -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-11771.rs b/src/test/ui/issues/issue-11771.rs index c69cd1e79e372..7da8474228811 100644 --- a/src/test/ui/issues/issue-11771.rs +++ b/src/test/ui/issues/issue-11771.rs @@ -1,11 +1,11 @@ fn main() { let x = (); 1 + - x //~^ ERROR E0277 + x //~^ ERROR cannot add ; let x: () = (); 1 + - x //~^ ERROR E0277 + x //~^ ERROR cannot add ; } diff --git a/src/test/ui/issues/issue-11771.stderr b/src/test/ui/issues/issue-11771.stderr index 9f250925e5080..842ecfe4091e6 100644 --- a/src/test/ui/issues/issue-11771.stderr +++ b/src/test/ui/issues/issue-11771.stderr @@ -1,19 +1,23 @@ -error[E0277]: cannot add `()` to `{integer}` +error[E0369]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:3:7 | LL | 1 + - | ^ no implementation for `{integer} + ()` - | - = help: the trait `Add<()>` is not implemented for `{integer}` + | - ^ + | | + | {integer} +LL | x + | - () -error[E0277]: cannot add `()` to `{integer}` +error[E0369]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:8:7 | LL | 1 + - | ^ no implementation for `{integer} + ()` - | - = help: the trait `Add<()>` is not implemented for `{integer}` + | - ^ + | | + | {integer} +LL | x + | - () error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/issues/issue-31076.rs index cdb196d4ff23f..37db634f4fcbc 100644 --- a/src/test/ui/issues/issue-31076.rs +++ b/src/test/ui/issues/issue-31076.rs @@ -11,7 +11,7 @@ impl Add for i32 {} fn main() { let x = 5 + 6; - //~^ ERROR cannot add `i32` to `{integer}` + //~^ ERROR cannot add `i32` to `i32` let y = 5i32 + 6i32; //~^ ERROR cannot add `i32` to `i32` } diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index ac0d9dc752879..85a7104dae302 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -1,10 +1,19 @@ -error[E0369]: cannot add `i32` to `{integer}` +error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:13:15 | LL | let x = 5 + 6; | - ^ - i32 | | - | {integer} + | i32 + | +help: you can convert an `i32` to an `i32` + | +LL | let x = 5 + 6.into(); + | +++++++ +help: you can convert an `i32` to an `i32` + | +LL | let x = 5.into() + 6; + | +++++++ error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:15:18 @@ -13,6 +22,15 @@ LL | let y = 5i32 + 6i32; | ---- ^ ---- i32 | | | i32 + | +help: change the type of the numeric literal from `i32` to `i32` + | +LL | let y = 5i32 + 6i32; + | ~~~ +help: change the type of the numeric literal from `i32` to `i32` + | +LL | let y = 5i32 + 6i32; + | ~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-50582.stderr b/src/test/ui/issues/issue-50582.stderr index 465fb9baac3f0..c540203386b3d 100644 --- a/src/test/ui/issues/issue-50582.stderr +++ b/src/test/ui/issues/issue-50582.stderr @@ -7,15 +7,15 @@ LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); = note: see issue #87575 for more information = help: add `#![feature(const_for)]` to the crate attributes to enable -error[E0277]: cannot add `()` to `{integer}` +error[E0369]: cannot add `()` to `{integer}` --> $DIR/issue-50582.rs:2:18 | LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); - | ^ no implementation for `{integer} + ()` - | - = help: the trait `Add<()>` is not implemented for `{integer}` + | - ^ ---------------- () + | | + | {integer} error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0369, E0658. +For more information about an error, try `rustc --explain E0369`. diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/issues/issue-59488.rs index 922b593935aa8..7dc2062c4326f 100644 --- a/src/test/ui/issues/issue-59488.rs +++ b/src/test/ui/issues/issue-59488.rs @@ -12,18 +12,18 @@ enum Foo { fn main() { foo > 12; - //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~^ ERROR can't compare //~| ERROR mismatched types [E0308] bar > 13; - //~^ ERROR binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` [E0369] + //~^ ERROR can't compare //~| ERROR mismatched types [E0308] foo > foo; //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] foo > bar; - //~^ ERROR binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~^ ERROR can't compare //~| ERROR mismatched types [E0308] let i = Foo::Bar; diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index f739557e001f5..d733e470888e7 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` +error[E0369]: can't compare `fn() -> i32 {foo}` with `{integer}` --> $DIR/issue-59488.rs:14:9 | LL | foo > 12; @@ -16,7 +16,7 @@ LL | foo > 12; = note: expected fn item `fn() -> i32 {foo}` found type `i32` -error[E0369]: binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` +error[E0369]: can't compare `fn(i64) -> i64 {bar}` with `{integer}` --> $DIR/issue-59488.rs:18:9 | LL | bar > 13; @@ -51,7 +51,7 @@ help: you might have forgotten to call this function LL | foo > foo(); | ~~~~~ -error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` +error[E0369]: can't compare `fn() -> i32 {foo}` with `fn(i64) -> i64 {bar}` --> $DIR/issue-59488.rs:25:9 | LL | foo > bar; diff --git a/src/test/ui/issues/issue-62375.rs b/src/test/ui/issues/issue-62375.rs index a2c8fe551bb03..eba7d36bdb48c 100644 --- a/src/test/ui/issues/issue-62375.rs +++ b/src/test/ui/issues/issue-62375.rs @@ -5,5 +5,5 @@ enum A { fn main() { let a = A::Value(()); a == A::Value; - //~^ ERROR binary operation `==` cannot be applied to type `A` + //~^ ERROR can't compare } diff --git a/src/test/ui/issues/issue-62375.stderr b/src/test/ui/issues/issue-62375.stderr index 478e025bed230..ccfc80d61f99f 100644 --- a/src/test/ui/issues/issue-62375.stderr +++ b/src/test/ui/issues/issue-62375.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `A` +error[E0369]: can't compare `A` with `fn(()) -> A {A::Value}` --> $DIR/issue-62375.rs:7:7 | LL | a == A::Value; diff --git a/src/test/ui/issues/issue-66667-function-cmp-cycle.rs b/src/test/ui/issues/issue-66667-function-cmp-cycle.rs index 7b025be11a09e..8a516ebf60bae 100644 --- a/src/test/ui/issues/issue-66667-function-cmp-cycle.rs +++ b/src/test/ui/issues/issue-66667-function-cmp-cycle.rs @@ -1,15 +1,15 @@ fn first() { - second == 1 //~ ERROR binary operation + second == 1 //~ ERROR can't compare //~^ ERROR mismatched types } fn second() { - first == 1 //~ ERROR binary operation + first == 1 //~ ERROR can't compare //~^ ERROR mismatched types } fn bar() { - bar == 1 //~ ERROR binary operation + bar == 1 //~ ERROR can't compare //~^ ERROR mismatched types } diff --git a/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr b/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr index 887699ef5ce85..58b2a68d9a587 100644 --- a/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr +++ b/src/test/ui/issues/issue-66667-function-cmp-cycle.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `fn() {second}` +error[E0369]: can't compare `fn() {second}` with `{integer}` --> $DIR/issue-66667-function-cmp-cycle.rs:2:12 | LL | second == 1 @@ -15,7 +15,7 @@ LL | second == 1 = note: expected fn item `fn() {second}` found type `{integer}` -error[E0369]: binary operation `==` cannot be applied to type `fn() {first}` +error[E0369]: can't compare `fn() {first}` with `{integer}` --> $DIR/issue-66667-function-cmp-cycle.rs:7:11 | LL | first == 1 @@ -32,7 +32,7 @@ LL | first == 1 = note: expected fn item `fn() {first}` found type `{integer}` -error[E0369]: binary operation `==` cannot be applied to type `fn() {bar}` +error[E0369]: can't compare `fn() {bar}` with `{integer}` --> $DIR/issue-66667-function-cmp-cycle.rs:12:9 | LL | bar == 1 diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs index c2683157f797f..f93a7bb4f4efc 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs @@ -4,7 +4,7 @@ fn a() -> i32 { pub fn main() { assert_eq!(a, 0); - //~^ ERROR binary operation `==` cannot + //~^ ERROR can't compare //~| ERROR mismatched types //~| ERROR doesn't implement } diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index cd4cc969200a6..58be5d66a2454 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `fn() -> i32 {a}` +error[E0369]: can't compare `fn() -> i32 {a}` with `{integer}` --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 | LL | assert_eq!(a, 0); diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 19e921dd04d73..62bd6374c91f8 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -14,29 +14,29 @@ LL | 2 as usize - Some(1); | = help: the trait `Sub>` is not implemented for `usize` -error[E0277]: cannot multiply `{integer}` by `()` +error[E0369]: cannot multiply `{integer}` by `()` --> $DIR/binops.rs:4:7 | LL | 3 * (); - | ^ no implementation for `{integer} * ()` - | - = help: the trait `Mul<()>` is not implemented for `{integer}` + | - ^ -- () + | | + | {integer} -error[E0277]: cannot divide `{integer}` by `&str` +error[E0369]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 | LL | 4 / ""; - | ^ no implementation for `{integer} / &str` - | - = help: the trait `Div<&str>` is not implemented for `{integer}` + | - ^ -- &str + | | + | {integer} error[E0277]: can't compare `{integer}` with `String` --> $DIR/binops.rs:6:7 | LL | 5 < String::new(); - | ^ no implementation for `{integer} < String` and `{integer} > String` + | ^ no implementation for `{integer} == String` | - = help: the trait `PartialOrd` is not implemented for `{integer}` + = help: the trait `PartialEq` is not implemented for `{integer}` error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` --> $DIR/binops.rs:7:7 @@ -48,4 +48,5 @@ LL | 6 == Ok(1); error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/lex-bad-char-literals-6.rs b/src/test/ui/parser/lex-bad-char-literals-6.rs index 4379b4fa6d777..7de85aa9cb919 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.rs +++ b/src/test/ui/parser/lex-bad-char-literals-6.rs @@ -7,10 +7,10 @@ fn main() { //~^ ERROR: character literal may only contain one codepoint if x == y {} - //~^ ERROR: can't compare `&str` with `char` + //~^ ERROR can't compare if y == z {} // no error here if x == z {} - //~^ ERROR: can't compare `&str` with `char` + //~^ ERROR can't compare let a: usize = ""; //~^ ERROR: mismatched types diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index 4332bdefcb258..b23ca280c7739 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -31,13 +31,21 @@ help: if you meant to write a `str` literal, use double quotes LL | let z = "ef"; | ~~~~ -error[E0277]: can't compare `&str` with `char` +error[E0369]: can't compare `&str` with `char` --> $DIR/lex-bad-char-literals-6.rs:9:10 | LL | if x == y {} - | ^^ no implementation for `&str == char` + | - ^^ - char + | | + | &str + +error[E0369]: can't compare `&str` with `char` + --> $DIR/lex-bad-char-literals-6.rs:12:10 | - = help: the trait `PartialEq` is not implemented for `&str` +LL | if x == z {} + | - ^^ - char + | | + | &str error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -47,15 +55,7 @@ LL | let a: usize = ""; | | | expected due to this -error[E0277]: can't compare `&str` with `char` - --> $DIR/lex-bad-char-literals-6.rs:12:10 - | -LL | if x == z {} - | ^^ no implementation for `&str == char` - | - = help: the trait `PartialEq` is not implemented for `&str` - error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/partialeq_help.fixed b/src/test/ui/partialeq_help.fixed new file mode 100644 index 0000000000000..e28566048eea2 --- /dev/null +++ b/src/test/ui/partialeq_help.fixed @@ -0,0 +1,8 @@ +// run-rustfix +fn foo(a: &T, b: T) { + let _ = a == &b; //~ ERROR can't compare +} + +fn main() { + foo(&1, 1); +} diff --git a/src/test/ui/partialeq_help.rs b/src/test/ui/partialeq_help.rs index c3ba805405b33..8fd4dcb20b464 100644 --- a/src/test/ui/partialeq_help.rs +++ b/src/test/ui/partialeq_help.rs @@ -1,5 +1,6 @@ +// run-rustfix fn foo(a: &T, b: T) { - a == b; //~ ERROR E0277 + let _ = a == b; //~ ERROR can't compare } fn main() { diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 528306b22dd5a..87868d2ac2d45 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -1,15 +1,20 @@ -error[E0277]: can't compare `&T` with `T` - --> $DIR/partialeq_help.rs:2:7 +error[E0369]: can't compare `&T` with `T` + --> $DIR/partialeq_help.rs:3:15 | -LL | a == b; - | ^^ no implementation for `&T == T` +LL | let _ = a == b; + | - ^^ - T + | | + | &T | - = help: the trait `PartialEq` is not implemented for `&T` -help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement +help: `==` can be applied on `&T` | -LL | fn foo(a: &T, b: T) where &T: PartialEq { - | ++++++++++++++++++++++ +LL | let _ = a == &b; + | + +help: consider further restricting this bound + | +LL | fn foo(a: &T, b: T) { + | +++++++++++++++++++++ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/shift-various-bad-types.rs b/src/test/ui/shift-various-bad-types.rs index 31224bbca1efc..0bd966d01251d 100644 --- a/src/test/ui/shift-various-bad-types.rs +++ b/src/test/ui/shift-various-bad-types.rs @@ -7,13 +7,13 @@ struct Panolpy { fn foo(p: &Panolpy) { 22 >> p.char; - //~^ ERROR E0277 + //~^ ERROR no implementation for 22 >> p.str; - //~^ ERROR E0277 + //~^ ERROR no implementation for 22 >> p; - //~^ ERROR E0277 + //~^ ERROR no implementation for let x; 22 >> x; // ambiguity error winds up being suppressed diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index 932a435143b0c..e9cd9314d7c9d 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -1,26 +1,26 @@ -error[E0277]: no implementation for `{integer} >> char` +error[E0369]: no implementation for `{integer} >> char` --> $DIR/shift-various-bad-types.rs:9:8 | LL | 22 >> p.char; - | ^^ no implementation for `{integer} >> char` - | - = help: the trait `Shr` is not implemented for `{integer}` + | -- ^^ ------ char + | | + | {integer} -error[E0277]: no implementation for `{integer} >> &str` +error[E0369]: no implementation for `{integer} >> &str` --> $DIR/shift-various-bad-types.rs:12:8 | LL | 22 >> p.str; - | ^^ no implementation for `{integer} >> &str` - | - = help: the trait `Shr<&str>` is not implemented for `{integer}` + | -- ^^ ----- &str + | | + | {integer} -error[E0277]: no implementation for `{integer} >> &Panolpy` +error[E0369]: no implementation for `{integer} >> &Panolpy` --> $DIR/shift-various-bad-types.rs:15:8 | LL | 22 >> p; - | ^^ no implementation for `{integer} >> &Panolpy` - | - = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` + | -- ^^ - &Panolpy + | | + | {integer} error[E0308]: mismatched types --> $DIR/shift-various-bad-types.rs:25:18 @@ -37,5 +37,5 @@ LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); error: aborting due to 4 previous errors -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 13ef0d1820881..35258984148b0 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -1,11 +1,16 @@ -error[E0277]: cannot add `()` to `u32` +error[E0369]: cannot add `()` to `u32` --> $DIR/multiline-span-simple.rs:13:18 | -LL | foo(1 as u32 + - | ^ no implementation for `u32 + ()` - | - = help: the trait `Add<()>` is not implemented for `u32` +LL | foo(1 as u32 + + | -------- ^ + | | + | u32 +LL | +LL | / bar(x, +LL | | +LL | | y), + | |______________- () error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.fixed b/src/test/ui/suggestions/missing-trait-bound-for-op.fixed index 6b24375e41503..8e00dd342886c 100644 --- a/src/test/ui/suggestions/missing-trait-bound-for-op.fixed +++ b/src/test/ui/suggestions/missing-trait-bound-for-op.fixed @@ -1,7 +1,7 @@ // run-rustfix pub fn foo(s: &[T], t: &[T]) { - let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]` + let _ = s == t; //~ ERROR can't compare } fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.rs b/src/test/ui/suggestions/missing-trait-bound-for-op.rs index df47be070c9ea..e47ad16520b9f 100644 --- a/src/test/ui/suggestions/missing-trait-bound-for-op.rs +++ b/src/test/ui/suggestions/missing-trait-bound-for-op.rs @@ -1,7 +1,7 @@ // run-rustfix pub fn foo(s: &[T], t: &[T]) { - let _ = s == t; //~ ERROR binary operation `==` cannot be applied to type `&[T]` + let _ = s == t; //~ ERROR can't compare } fn main() {} diff --git a/src/test/ui/suggestions/missing-trait-bound-for-op.stderr b/src/test/ui/suggestions/missing-trait-bound-for-op.stderr index cde0755012594..aff5492db6f56 100644 --- a/src/test/ui/suggestions/missing-trait-bound-for-op.stderr +++ b/src/test/ui/suggestions/missing-trait-bound-for-op.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `&[T]` +error[E0369]: can't compare `&[T]` with `&[T]` --> $DIR/missing-trait-bound-for-op.rs:4:15 | LL | let _ = s == t; diff --git a/src/test/ui/typeck/issue-81293.rs b/src/test/ui/typeck/issue-81293.rs index 076b8c944b8a4..0c39703af09dd 100644 --- a/src/test/ui/typeck/issue-81293.rs +++ b/src/test/ui/typeck/issue-81293.rs @@ -4,6 +4,5 @@ fn main() { let c: usize = 5; a = c + b * 5; //~ ERROR: mismatched types [E0308] - //~| ERROR: mismatched types [E0308] - //~| ERROR: cannot add `u16` to `usize` [E0277] + //~| ERROR: cannot add `u16` to `usize` } diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr index 1e6ff3b5f9ee7..f8ba81d077625 100644 --- a/src/test/ui/typeck/issue-81293.stderr +++ b/src/test/ui/typeck/issue-81293.stderr @@ -1,24 +1,27 @@ -error[E0308]: mismatched types - --> $DIR/issue-81293.rs:6:13 +error[E0369]: cannot add `u16` to `usize` + --> $DIR/issue-81293.rs:6:11 | LL | a = c + b * 5; - | ^^^^^ expected `usize`, found `u16` - -error[E0308]: mismatched types - --> $DIR/issue-81293.rs:6:9 + | - ^ ----- u16 + | | + | usize | -LL | a = c + b * 5; - | ^^^^^^^^^ expected `u16`, found `usize` +help: you can convert a `u16` to a `usize` + | +LL | a = c + (b * 5).into(); + | + ++++++++ +help: you can convert `b * 5` from `u16` to `usize`, matching the type of `c` + | +LL | a = c + usize::from(b * 5); + | ++++++++++++ + -error[E0277]: cannot add `u16` to `usize` - --> $DIR/issue-81293.rs:6:11 +error[E0308]: mismatched types + --> $DIR/issue-81293.rs:6:13 | LL | a = c + b * 5; - | ^ no implementation for `usize + u16` - | - = help: the trait `Add` is not implemented for `usize` + | ^^^^^ expected `usize`, found `u16` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. From dc7785ce2ca2986baceb4ca89f9eb6553503f2ba Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 17 Oct 2021 19:38:27 +0000 Subject: [PATCH 02/14] Add FIXME comment for follow up work --- compiler/rustc_resolve/src/late/diagnostics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1748a9be8e13e..129e773247f15 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -966,6 +966,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { match (res, source) { (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => { + // FIXME: peek at the next token to see if it is one of `(`, `[` or `{`. err.span_label(span, fallback_label); err.span_suggestion_verbose( span.shrink_to_hi(), From 2f499dda1a2f1c491a43dce1ad21059e5ded0df8 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 08:21:16 +0000 Subject: [PATCH 03/14] Suggest replacement of existing bound instead of further contraining --- compiler/rustc_middle/src/ty/diagnostics.rs | 16 +++++++++ compiler/rustc_typeck/src/check/op.rs | 35 +++++++++++-------- ...types-invalid-trait-ref-issue-18865.stderr | 6 ++-- src/test/ui/partialeq_help.fixed | 2 +- src/test/ui/partialeq_help.stderr | 6 ++-- .../trait-where-clause.stderr | 12 +++---- 6 files changed, 49 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 092eae0fc5c23..b7e6813d8637e 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -238,6 +238,22 @@ pub fn suggest_constraining_type_param( suggest_removing_unsized_bound(generics, err, param_name, param, def_id); return true; } + + for bound in param.bounds { + if def_id.is_some() && def_id == bound.trait_ref().and_then(|tr| tr.trait_def_id()) { + // FIXME: This can happen when we have `Foo` when `Foo` was intended, but it + // can also happen when using `Foo` where `~const Foo`. Right now the later isn't + // accounted for, but it is still a nightly feature, so I haven't tried to clean it up. + err.span_suggestion_verbose( + bound.span(), + &format!("consider changing this type parameter bound to `{}`", constraint), + constraint.to_string(), + Applicability::MaybeIncorrect, + ); + return false; + } + } + let mut suggest_restrict = |span| { err.span_suggestion_verbose( span, diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 4b203866dcc10..f5f081f4d0f47 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -5,6 +5,7 @@ use super::{has_expected_num_generic_args, FnCtxt}; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -16,7 +17,7 @@ use rustc_middle::ty::{ }; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; @@ -532,6 +533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty, rhs_ty, missing_trait, + self.op_metadata(Op::Binary(op, is_assign), op.span).1, p, use_output, ); @@ -801,19 +803,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn lookup_op_method( - &self, - lhs_ty: Ty<'tcx>, - other_tys: &[Ty<'tcx>], - op: Op, - ) -> Result, Vec>> { + fn op_metadata(&self, op: Op, span: Span) -> (Symbol, Option) { let lang = self.tcx.lang_items(); - - let span = match op { - Op::Binary(op, _) => op.span, - Op::Unary(_, span) => span, - }; - let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { + if let Op::Binary(op, IsAssign::Yes) = op { match op.node { hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), @@ -864,8 +856,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (sym::neg, lang.neg_trait()) } else { bug!("lookup_op_method: op not supported: {:?}", op) - }; + } + } + fn lookup_op_method( + &self, + lhs_ty: Ty<'tcx>, + other_tys: &[Ty<'tcx>], + op: Op, + ) -> Result, Vec>> { + let span = match op { + Op::Binary(op, _) => op.span, + Op::Unary(_, span) => span, + }; + let (opname, trait_did) = self.op_metadata(op, span); debug!( "lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", lhs_ty, op, opname, trait_did @@ -1043,6 +1047,7 @@ fn suggest_constraining_param( lhs_ty: Ty<'_>, rhs_ty: Ty<'_>, missing_trait: &str, + trait_def_id: Option, p: ty::ParamTy, set_output: bool, ) { @@ -1068,7 +1073,7 @@ fn suggest_constraining_param( &mut err, &format!("{}", lhs_ty), &format!("{}{}", missing_trait, output), - None, + trait_def_id, ); } else { let span = tcx.def_span(param_def_id); diff --git a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr index 8fecfdf7b932b..7ec7c5cdd9faa 100644 --- a/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr +++ b/src/test/ui/associated-types/associated-types-invalid-trait-ref-issue-18865.stderr @@ -4,10 +4,10 @@ error[E0277]: the trait bound `T: Foo` is not satisfied LL | let u: >::Bar = t.get_bar(); | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `T` | -help: consider further restricting this bound +help: consider changing this type parameter bound to `Foo` | -LL | fn f + Foo>(t: &T) { - | ++++++++++++ +LL | fn f>(t: &T) { + | ~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/partialeq_help.fixed b/src/test/ui/partialeq_help.fixed index e28566048eea2..5a24c79275ed2 100644 --- a/src/test/ui/partialeq_help.fixed +++ b/src/test/ui/partialeq_help.fixed @@ -1,5 +1,5 @@ // run-rustfix -fn foo(a: &T, b: T) { +fn foo(a: &T, b: T) { let _ = a == &b; //~ ERROR can't compare } diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 87868d2ac2d45..4d17405ca522c 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -10,10 +10,10 @@ help: `==` can be applied on `&T` | LL | let _ = a == &b; | + -help: consider further restricting this bound +help: consider changing this type parameter bound to `std::cmp::PartialEq` | -LL | fn foo(a: &T, b: T) { - | +++++++++++++++++++++ +LL | fn foo(a: &T, b: T) { + | ~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr index 4a4544c16c941..f6bc9e766a8b9 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr @@ -9,10 +9,10 @@ note: required by `Foo::b` | LL | fn b() where Self: ~const Bar; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: consider further restricting this bound +help: consider changing this type parameter bound to `Bar` | -LL | const fn test1() { - | +++++ +LL | const fn test1() { + | ~~~ error[E0277]: the trait bound `T: Bar` is not satisfied --> $DIR/trait-where-clause.rs:16:5 @@ -25,10 +25,10 @@ note: required by a bound in `Foo::c` | LL | fn c(); | ^ required by this bound in `Foo::c` -help: consider further restricting this bound +help: consider changing this type parameter bound to `Bar` | -LL | const fn test1() { - | +++++ +LL | const fn test1() { + | ~~~ error[E0277]: the trait bound `T: Bar` is not satisfied --> $DIR/trait-where-clause.rs:28:5 From 2e6cab8b0282d97b30e5f8f1d6a61b62a0997424 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 09:10:53 +0000 Subject: [PATCH 04/14] Fix output formatting for numeric cast --- compiler/rustc_typeck/src/check/demand.rs | 6 +++--- src/test/ui/numeric/numeric-cast.stderr | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 540365956a8fb..eb58f8873e245 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -1059,8 +1059,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Missing try_into implementation for `{integer}` to `{float}` err.multipart_suggestion_verbose( &format!( - "{}, producing the floating point representation of the integer, - rounded if necessary", + "{}, producing the floating point representation of the integer, \ + rounded if necessary", cast_msg, ), cast_suggestion, @@ -1091,7 +1091,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.multipart_suggestion_verbose( &format!( "{}, producing the floating point representation of the integer, \ - rounded if necessary", + rounded if necessary", &msg, ), cast_suggestion, diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index 3e2bc5bc82d42..b8f2d88ab4957 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -994,8 +994,8 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f64`, found `usize` | -help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, - | rounded if necessary +help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, rounded if necessary + | LL | foo::(x_usize as f64); | ++++++ @@ -1005,8 +1005,8 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f64`, found `u64` | -help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, - | rounded if necessary +help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, rounded if necessary + | LL | foo::(x_u64 as f64); | ++++++ @@ -1115,8 +1115,8 @@ error[E0308]: mismatched types LL | foo::(x_usize); | ^^^^^^^ expected `f32`, found `usize` | -help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, - | rounded if necessary +help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, rounded if necessary + | LL | foo::(x_usize as f32); | ++++++ @@ -1126,8 +1126,8 @@ error[E0308]: mismatched types LL | foo::(x_u64); | ^^^^^ expected `f32`, found `u64` | -help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, - | rounded if necessary +help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, rounded if necessary + | LL | foo::(x_u64 as f32); | ++++++ @@ -1137,8 +1137,8 @@ error[E0308]: mismatched types LL | foo::(x_u32); | ^^^^^ expected `f32`, found `u32` | -help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, - | rounded if necessary +help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, rounded if necessary + | LL | foo::(x_u32 as f32); | ++++++ From 86aeb233251b7665f981515bd7f88f409b45003c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 09:27:17 +0000 Subject: [PATCH 05/14] More accurate tracking of cast suggestions --- compiler/rustc_typeck/src/check/demand.rs | 32 ++++---- compiler/rustc_typeck/src/check/op.rs | 95 ++++++++++++++--------- src/test/ui/issues/issue-31076.stderr | 8 -- src/test/ui/typeck/issue-81293.stderr | 4 - 4 files changed, 76 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index eb58f8873e245..c580470088587 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -915,19 +915,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suggestion, Applicability::MachineApplicable, ); + true }; let suggest_to_change_suffix_or_into = |err: &mut DiagnosticBuilder<'_>, found_to_exp_is_fallible: bool, exp_to_found_is_fallible: bool| { - let exp_is_lhs = + let exp_is_assign_lhs = expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false); - if exp_is_lhs { - return; + if exp_is_assign_lhs { + return false; } - let always_fallible = found_to_exp_is_fallible && (exp_to_found_is_fallible || expected_ty_expr.is_none()); let msg = if literal_is_ty_suffixed(expr) { @@ -938,10 +938,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // expected type. let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty); err.note(&msg); - return; + return false; } else if in_const_context { // Do not recommend `into` or `try_into` in const contexts. - return; + return false; } else if found_to_exp_is_fallible { return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible); } else { @@ -953,6 +953,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { into_suggestion.clone() }; err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable); + true }; match (&expected_ty.kind(), &checked_ty.kind()) { @@ -966,8 +967,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, _) | (_, None) => (true, true), _ => (false, false), }; - suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); - true + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible) } (&ty::Uint(ref exp), &ty::Uint(ref found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) @@ -979,8 +979,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, _) | (_, None) => (true, true), _ => (false, false), }; - suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); - true + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible) } (&ty::Int(exp), &ty::Uint(found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) @@ -989,8 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, Some(8)) => (false, true), _ => (true, true), }; - suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); - true + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible) } (&ty::Uint(exp), &ty::Int(found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) @@ -999,12 +997,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (Some(8), None) => (true, false), _ => (true, true), }; - suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible); - true + suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible) } (&ty::Float(ref exp), &ty::Float(ref found)) => { if found.bit_width() < exp.bit_width() { - suggest_to_change_suffix_or_into(err, false, true); + return suggest_to_change_suffix_or_into(err, false, true); } else if literal_is_ty_suffixed(expr) { err.multipart_suggestion_verbose( &lit_msg, @@ -1028,6 +1025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { suffix_suggestion, Applicability::MachineApplicable, ); + true } else if can_cast { // Missing try_into implementation for `{float}` to `{integer}` err.multipart_suggestion_verbose( @@ -1035,8 +1033,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cast_suggestion, Applicability::MaybeIncorrect, // lossy conversion ); + true + } else { + false } - true } (&ty::Float(ref exp), &ty::Uint(ref found)) => { // if `found` is `None` (meaning found is `usize`), don't suggest `.into()` diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index f5f081f4d0f47..e7ba4b6c9ef3b 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -202,7 +202,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: rhs_expr.span, }); - let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); + let mut orig_result = + self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); @@ -210,7 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut erased = false; let mut non_binop_obligations = 0; self.select_obligations_where_possible(false, |errors| { - errors.retain(|e| match (&result, e.obligation.predicate.kind().skip_binder()) { + errors.retain(|e| match (&orig_result, e.obligation.predicate.kind().skip_binder()) { (Ok(callee), ty::PredicateKind::Trait(predicate)) => { // Skip the obligations coming from the binop, we want to emit E0369 instead // of E0277. @@ -224,10 +225,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Run again with more accurate types for better diagnostics. Even if `result` was `Ok`, // we can rerun with a more accurate rhs type for eager obligation errors. - let result = if result.is_ok() && erased && non_binop_obligations == 0 { - self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)) - } else { - result + let result = match orig_result { + Ok(_) if erased && non_binop_obligations == 0 => { + self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)) + } + Ok(method) => Ok(method), + Err(ref mut err) => Err(std::mem::take(err)), }; let return_ty = match result { @@ -433,34 +436,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let borrowed_rhs = self.tcx.mk_ref( - self.tcx.lifetimes.re_static, - ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, - ); - if self.lookup_op_method(lhs_ty, &[borrowed_rhs], Op::Binary(op, is_assign)).is_ok() - { - let borrowed_rhs = self.tcx.mk_ref( - self.tcx.lifetimes.re_erased, - ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, - ); - let msg = &format!( - "`{}{}` can be applied on `{}`", - op.node.as_str(), - match is_assign { - IsAssign::Yes => "=", - IsAssign::No => "", - }, - borrowed_rhs, - ); - err.span_suggestion_verbose( - rhs_expr.span.shrink_to_lo(), - msg, - "&".to_string(), - rustc_errors::Applicability::MachineApplicable, - ); - } - self.check_for_cast(&mut err, rhs_expr, rhs_ty, lhs_ty, Some(lhs_expr)); - self.check_for_cast(&mut err, lhs_expr, lhs_ty, rhs_ty, Some(rhs_expr)); + let mut suggested = self + .check_binop_borrow(&mut err, lhs_ty, rhs_ty, rhs_expr, op, is_assign) + || self.check_for_cast(&mut err, rhs_expr, rhs_ty, lhs_ty, Some(lhs_expr)) + || self.check_for_cast(&mut err, lhs_expr, lhs_ty, rhs_ty, Some(rhs_expr)); + if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) @@ -485,6 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "*".to_string(), rustc_errors::Applicability::MachineApplicable, ); + suggested = true; } else if let IsAssign::No = is_assign { let msg = &format!( "`{}` can be used on `{}`, you can borrow it", @@ -497,6 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "&".to_string(), rustc_errors::Applicability::MaybeIncorrect, ); + suggested = true; } } } @@ -537,6 +519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { p, use_output, ); + suggested = true; } else if *ty != lhs_ty { // When we know that a missing bound is responsible, we don't show // this note as it is redundant. @@ -551,13 +534,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.emit(); - self.tcx.ty_error() + if !suggested { + orig_result.map_or(self.tcx.ty_error(), |method| method.sig.output()) + } else { + self.tcx.ty_error() + } } }; (lhs_ty, rhs_ty, return_ty) } + fn check_binop_borrow( + &self, + err: &mut DiagnosticBuilder<'tcx>, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>, + rhs_expr: &'tcx hir::Expr<'tcx>, + op: hir::BinOp, + is_assign: IsAssign, + ) -> bool { + let borrowed_rhs = self.tcx.mk_ref( + self.tcx.lifetimes.re_static, + ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, + ); + if self.lookup_op_method(lhs_ty, &[borrowed_rhs], Op::Binary(op, is_assign)).is_ok() { + let borrowed_rhs = self.tcx.mk_ref( + self.tcx.lifetimes.re_erased, + ty::TypeAndMut { ty: rhs_ty, mutbl: hir::Mutability::Not }, + ); + let msg = &format!( + "`{}{}` can be applied on `{}`", + op.node.as_str(), + match is_assign { + IsAssign::Yes => "=", + IsAssign::No => "", + }, + borrowed_rhs, + ); + err.span_suggestion_verbose( + rhs_expr.span.shrink_to_lo(), + msg, + "&".to_string(), + rustc_errors::Applicability::MachineApplicable, + ); + return true; + } + false + } + /// If one of the types is an uncalled function and calling it would yield the other type, /// suggest calling the function. Returns `true` if suggestion would apply (even if not given). fn add_type_neq_err_label( diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 85a7104dae302..3b3afa48d611e 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -10,10 +10,6 @@ help: you can convert an `i32` to an `i32` | LL | let x = 5 + 6.into(); | +++++++ -help: you can convert an `i32` to an `i32` - | -LL | let x = 5.into() + 6; - | +++++++ error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:15:18 @@ -27,10 +23,6 @@ help: change the type of the numeric literal from `i32` to `i32` | LL | let y = 5i32 + 6i32; | ~~~ -help: change the type of the numeric literal from `i32` to `i32` - | -LL | let y = 5i32 + 6i32; - | ~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr index f8ba81d077625..a327e0e644103 100644 --- a/src/test/ui/typeck/issue-81293.stderr +++ b/src/test/ui/typeck/issue-81293.stderr @@ -10,10 +10,6 @@ help: you can convert a `u16` to a `usize` | LL | a = c + (b * 5).into(); | + ++++++++ -help: you can convert `b * 5` from `u16` to `usize`, matching the type of `c` - | -LL | a = c + usize::from(b * 5); - | ++++++++++++ + error[E0308]: mismatched types --> $DIR/issue-81293.rs:6:13 From 56b12d7122083fe873f98643070bcca1537aeec3 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 09:42:14 +0000 Subject: [PATCH 06/14] Remove useless comment --- compiler/rustc_typeck/src/check/op.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index e7ba4b6c9ef3b..21e2b74228f02 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -372,7 +372,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true, ), hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( - // can't compare `&str` with `char` if lhs_ty == rhs_ty { format!( "binary operation `{}` cannot be applied to type `{}`", From bee875280240e23b6759e1ba4551c34486685b6d Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 14:23:41 +0000 Subject: [PATCH 07/14] Tweak output --- compiler/rustc_typeck/src/check/op.rs | 14 +++++++------- .../ui/consts/const-eval/const-eval-overflow-3b.rs | 3 +-- .../const-eval/const-eval-overflow-3b.stderr | 11 ++--------- .../ui/consts/const-eval/const-eval-overflow-4b.rs | 4 +--- .../const-eval/const-eval-overflow-4b.stderr | 14 ++++---------- src/test/ui/issues/issue-31076.rs | 2 +- src/test/ui/issues/issue-31076.stderr | 9 ++------- src/test/ui/mismatched_types/binops.rs | 1 + src/test/ui/mismatched_types/binops.stderr | 12 ++++++++++-- src/test/ui/typeck/issue-81293.rs | 3 +-- src/test/ui/typeck/issue-81293.stderr | 11 ++--------- 11 files changed, 32 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 21e2b74228f02..b632d3d5d6bb6 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -209,7 +209,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); let mut erased = false; - let mut non_binop_obligations = 0; self.select_obligations_where_possible(false, |errors| { errors.retain(|e| match (&orig_result, e.obligation.predicate.kind().skip_binder()) { (Ok(callee), ty::PredicateKind::Trait(predicate)) => { @@ -220,19 +219,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => true, }); - non_binop_obligations = errors.len(); }); // Run again with more accurate types for better diagnostics. Even if `result` was `Ok`, // we can rerun with a more accurate rhs type for eager obligation errors. let result = match orig_result { - Ok(_) if erased && non_binop_obligations == 0 => { - self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)) - } + Ok(_) if erased => self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)), Ok(method) => Ok(method), Err(ref mut err) => Err(std::mem::take(err)), }; + // If we show labels with the types pointing at both sides of a binop, we replace these + // with `TyErr` to avoid unnecessary E0308s from `enforce_builtin_binop_types`. + let mut lhs_ty = lhs_ty; + let mut rhs_ty = rhs_ty; let return_ty = match result { Ok(method) => { let by_ref_binop = !op.node.is_by_value(); @@ -287,8 +287,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { let source_map = self.tcx.sess.source_map(); - let lhs_ty = self.resolve_vars_if_possible(lhs_ty); - let rhs_ty = self.resolve_vars_if_possible(rhs_ty); let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( @@ -536,6 +534,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !suggested { orig_result.map_or(self.tcx.ty_error(), |method| method.sig.output()) } else { + lhs_ty = self.tcx.ty_error(); + rhs_ty = self.tcx.ty_error(); self.tcx.ty_error() } } diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs index 480069e67fa28..866b2412483e9 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.rs @@ -14,8 +14,7 @@ use std::fmt; const A_I8_I : [u32; (i8::MAX as usize) + 1] = [0; (i8::MAX + 1u8) as usize]; -//~^ ERROR mismatched types -//~| ERROR cannot add `u8` to `i8` +//~^ ERROR cannot add `u8` to `i8` fn main() { foo(&A_I8_I[..]); diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 5c7c2473976d4..8ea68f6529cc5 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -11,13 +11,6 @@ help: change the type of the numeric literal from `u8` to `i8` LL | = [0; (i8::MAX + 1i8) as usize]; | ~~ -error[E0308]: mismatched types - --> $DIR/const-eval-overflow-3b.rs:16:22 - | -LL | = [0; (i8::MAX + 1u8) as usize]; - | ^^^ expected `i8`, found `u8` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0369. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs b/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs index ce9c980de0dd2..f13c0e05357e6 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.rs @@ -7,9 +7,7 @@ const A_I8_T : [u32; (i8::MAX as i8 + 1u8) as usize] - //~^ ERROR mismatched types - //~| expected `i8`, found `u8` - //~| ERROR cannot add `u8` to `i8` + //~^ ERROR cannot add `u8` to `i8` = [0; (i8::MAX as usize) + 1]; diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 7aead0bb6c789..6283877530ef5 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -11,19 +11,13 @@ help: change the type of the numeric literal from `u8` to `i8` LL | : [u32; (i8::MAX as i8 + 1i8) as usize] | ~~ -error[E0308]: mismatched types - --> $DIR/const-eval-overflow-4b.rs:9:30 - | -LL | : [u32; (i8::MAX as i8 + 1u8) as usize] - | ^^^ expected `i8`, found `u8` - error[E0604]: only `u8` can be cast as `char`, not `i8` - --> $DIR/const-eval-overflow-4b.rs:22:13 + --> $DIR/const-eval-overflow-4b.rs:20:13 | LL | : [u32; 5i8 as char as usize] | ^^^^^^^^^^^ invalid cast -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0369, E0604. -For more information about an error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0369, E0604. +For more information about an error, try `rustc --explain E0369`. diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/issues/issue-31076.rs index 37db634f4fcbc..cdb196d4ff23f 100644 --- a/src/test/ui/issues/issue-31076.rs +++ b/src/test/ui/issues/issue-31076.rs @@ -11,7 +11,7 @@ impl Add for i32 {} fn main() { let x = 5 + 6; - //~^ ERROR cannot add `i32` to `i32` + //~^ ERROR cannot add `i32` to `{integer}` let y = 5i32 + 6i32; //~^ ERROR cannot add `i32` to `i32` } diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 3b3afa48d611e..a1dcb903769d1 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -1,15 +1,10 @@ -error[E0369]: cannot add `i32` to `i32` +error[E0369]: cannot add `i32` to `{integer}` --> $DIR/issue-31076.rs:13:15 | LL | let x = 5 + 6; | - ^ - i32 | | - | i32 - | -help: you can convert an `i32` to an `i32` - | -LL | let x = 5 + 6.into(); - | +++++++ + | {integer} error[E0369]: cannot add `i32` to `i32` --> $DIR/issue-31076.rs:15:18 diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index f359451dfb8f9..445c534ff42f7 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -4,5 +4,6 @@ fn main() { 3 * (); //~ ERROR cannot multiply `{integer}` by `()` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` 5 < String::new(); //~ ERROR can't compare `{integer}` with `String` + //~^ ERROR can't compare `{integer}` with `String` 6 == Ok(1); //~ ERROR can't compare `{integer}` with `Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 62bd6374c91f8..07bc9f392a82b 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -38,15 +38,23 @@ LL | 5 < String::new(); | = help: the trait `PartialEq` is not implemented for `{integer}` +error[E0369]: can't compare `{integer}` with `String` + --> $DIR/binops.rs:6:7 + | +LL | 5 < String::new(); + | - ^ ------------- String + | | + | {integer} + error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` - --> $DIR/binops.rs:7:7 + --> $DIR/binops.rs:8:7 | LL | 6 == Ok(1); | ^^ no implementation for `{integer} == Result<{integer}, _>` | = help: the trait `PartialEq>` is not implemented for `{integer}` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/typeck/issue-81293.rs b/src/test/ui/typeck/issue-81293.rs index 0c39703af09dd..da60d7a0401e8 100644 --- a/src/test/ui/typeck/issue-81293.rs +++ b/src/test/ui/typeck/issue-81293.rs @@ -3,6 +3,5 @@ fn main() { let b: u16 = 42; let c: usize = 5; - a = c + b * 5; //~ ERROR: mismatched types [E0308] - //~| ERROR: cannot add `u16` to `usize` + a = c + b * 5; //~ ERROR cannot add `u16` to `usize` } diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr index a327e0e644103..65ace16efd814 100644 --- a/src/test/ui/typeck/issue-81293.stderr +++ b/src/test/ui/typeck/issue-81293.stderr @@ -11,13 +11,6 @@ help: you can convert a `u16` to a `usize` LL | a = c + (b * 5).into(); | + ++++++++ -error[E0308]: mismatched types - --> $DIR/issue-81293.rs:6:13 - | -LL | a = c + b * 5; - | ^^^^^ expected `usize`, found `u16` - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0369. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0369`. From 1e48ab4d7ea5edfb68f0a9348629ecdecd21b9e2 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 14:57:25 +0000 Subject: [PATCH 08/14] Remove mutable bindings --- compiler/rustc_typeck/src/check/op.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index b632d3d5d6bb6..b0dcd1ca3f334 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -229,11 +229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(ref mut err) => Err(std::mem::take(err)), }; - // If we show labels with the types pointing at both sides of a binop, we replace these - // with `TyErr` to avoid unnecessary E0308s from `enforce_builtin_binop_types`. - let mut lhs_ty = lhs_ty; - let mut rhs_ty = rhs_ty; - let return_ty = match result { + match result { Ok(method) => { let by_ref_binop = !op.node.is_by_value(); if is_assign == IsAssign::Yes || by_ref_binop { @@ -281,10 +277,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.write_method_call(expr.hir_id, method); - method.sig.output() + (lhs_ty, rhs_ty, method.sig.output()) } // error types are considered "builtin" - Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), + Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => { + (self.tcx.ty_error(), self.tcx.ty_error(), self.tcx.ty_error()) + } Err(errors) => { let source_map = self.tcx.sess.source_map(); let (mut err, missing_trait, use_output) = match is_assign { @@ -531,17 +529,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.emit(); - if !suggested { - orig_result.map_or(self.tcx.ty_error(), |method| method.sig.output()) + if suggested { + // If we show labels with the types pointing at both sides of a binop, we replace these + // with `TyErr` to avoid unnecessary E0308s from `enforce_builtin_binop_types`. + let ty = self.tcx.ty_error(); + (ty, ty, orig_result.map_or(ty, |method| method.sig.output())) } else { - lhs_ty = self.tcx.ty_error(); - rhs_ty = self.tcx.ty_error(); - self.tcx.ty_error() + (lhs_ty, rhs_ty, self.tcx.ty_error()) } } - }; - - (lhs_ty, rhs_ty, return_ty) + } } fn check_binop_borrow( From 5b0c7f637f67f0978417e13d4d166c5c8a34b782 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 15:34:14 +0000 Subject: [PATCH 09/14] Account for "int to float suffix" to include `.0` in the suggestion --- compiler/rustc_typeck/src/check/demand.rs | 13 ++++++++ src/test/ui/numeric/numeric-suffix.fixed | 20 ++++++------ src/test/ui/numeric/numeric-suffix.stderr | 40 +++++++++++------------ 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index c580470088587..7581c09c6bbad 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -844,6 +844,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut into_suggestion = sugg.clone(); into_suggestion.push((expr.span.shrink_to_hi(), format!("{}.into()", close_paren))); let mut suffix_suggestion = sugg.clone(); + + if matches!( + (&expected_ty.kind(), &checked_ty.kind()), + (ty::Float(_), ty::Int(_) | ty::Uint(_)) + ) { + // Add fractional part from literal, for example `42.0f32` into `42` + let len = src.trim_end_matches(&checked_ty.to_string()).len(); + let len = src[..len].trim_end_matches("_").len(); + let pos = expr.span.lo() + BytePos(len as u32); + let span = expr.span.with_lo(pos).with_hi(pos); + suffix_suggestion.push((span, ".0".to_string())); + }; + suffix_suggestion.push(( if matches!( (&expected_ty.kind(), &checked_ty.kind()), diff --git a/src/test/ui/numeric/numeric-suffix.fixed b/src/test/ui/numeric/numeric-suffix.fixed index 53c5fe0f435f9..43e2c59c6c8e7 100644 --- a/src/test/ui/numeric/numeric-suffix.fixed +++ b/src/test/ui/numeric/numeric-suffix.fixed @@ -243,9 +243,9 @@ fn main() { foo::(42i8); //~^ ERROR mismatched types - foo::(42_f64); + foo::(42.0_f64); //~^ ERROR mismatched types - foo::(42_f64); + foo::(42.0_f64); //~^ ERROR mismatched types foo::(42_u32.into()); //~^ ERROR mismatched types @@ -253,9 +253,9 @@ fn main() { //~^ ERROR mismatched types foo::(42_u8.into()); //~^ ERROR mismatched types - foo::(42_f64); + foo::(42.0_f64); //~^ ERROR mismatched types - foo::(42_f64); + foo::(42.0_f64); //~^ ERROR mismatched types foo::(42_i32.into()); //~^ ERROR mismatched types @@ -267,21 +267,21 @@ fn main() { foo::(42.0_f64); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types foo::(42_u16.into()); //~^ ERROR mismatched types foo::(42_u8.into()); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types - foo::(42_f32); + foo::(42.0_f32); //~^ ERROR mismatched types foo::(42_i16.into()); //~^ ERROR mismatched types diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr index b829946e52226..9dfa63f583564 100644 --- a/src/test/ui/numeric/numeric-suffix.stderr +++ b/src/test/ui/numeric/numeric-suffix.stderr @@ -1216,8 +1216,8 @@ LL | foo::(42_usize); | help: change the type of the numeric literal from `usize` to `f64` | -LL | foo::(42_f64); - | ~~~ +LL | foo::(42.0_f64); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:248:16 @@ -1227,8 +1227,8 @@ LL | foo::(42_u64); | help: change the type of the numeric literal from `u64` to `f64` | -LL | foo::(42_f64); - | ~~~ +LL | foo::(42.0_f64); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:250:16 @@ -1271,8 +1271,8 @@ LL | foo::(42_isize); | help: change the type of the numeric literal from `isize` to `f64` | -LL | foo::(42_f64); - | ~~~ +LL | foo::(42.0_f64); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:258:16 @@ -1282,8 +1282,8 @@ LL | foo::(42_i64); | help: change the type of the numeric literal from `i64` to `f64` | -LL | foo::(42_f64); - | ~~~ +LL | foo::(42.0_f64); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:260:16 @@ -1337,8 +1337,8 @@ LL | foo::(42_usize); | help: change the type of the numeric literal from `usize` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:272:16 @@ -1348,8 +1348,8 @@ LL | foo::(42_u64); | help: change the type of the numeric literal from `u64` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:274:16 @@ -1359,8 +1359,8 @@ LL | foo::(42_u32); | help: change the type of the numeric literal from `u32` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:276:16 @@ -1392,8 +1392,8 @@ LL | foo::(42_isize); | help: change the type of the numeric literal from `isize` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:282:16 @@ -1403,8 +1403,8 @@ LL | foo::(42_i64); | help: change the type of the numeric literal from `i64` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:284:16 @@ -1414,8 +1414,8 @@ LL | foo::(42_i32); | help: change the type of the numeric literal from `i32` to `f32` | -LL | foo::(42_f32); - | ~~~ +LL | foo::(42.0_f32); + | ++ ~~~ error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:286:16 From 7110131a041c699e9a2fc4c835c1780fbdd0bf33 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 16:51:08 +0000 Subject: [PATCH 10/14] Add a new inference context once we have the rhs ty --- compiler/rustc_typeck/src/check/op.rs | 67 +++++++++++-------- src/test/ui/block-result/issue-22645.rs | 2 +- src/test/ui/block-result/issue-22645.stderr | 13 ++-- src/test/ui/consts/too_generic_eval_ice.rs | 1 + .../ui/consts/too_generic_eval_ice.stderr | 13 +++- ...nicode-confusable-in-float-literal-expt.rs | 1 + ...de-confusable-in-float-literal-expt.stderr | 13 +++- src/test/ui/issues/issue-24352.rs | 4 +- src/test/ui/issues/issue-24352.stderr | 13 +++- .../issue-67039-unsound-pin-partialeq.rs | 3 +- .../issue-67039-unsound-pin-partialeq.stderr | 23 ++++++- src/test/ui/mismatched_types/binops.rs | 21 ++++-- src/test/ui/mismatched_types/binops.stderr | 38 +++++++++-- 13 files changed, 153 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index b0dcd1ca3f334..76efcbaa392a1 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -202,31 +202,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: rhs_expr.span, }); - let mut orig_result = - self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); + let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); - let mut erased = false; - self.select_obligations_where_possible(false, |errors| { - errors.retain(|e| match (&orig_result, e.obligation.predicate.kind().skip_binder()) { - (Ok(callee), ty::PredicateKind::Trait(predicate)) => { - // Skip the obligations coming from the binop, we want to emit E0369 instead - // of E0277. - erased = true; - callee.trait_def_id != predicate.def_id() - } - _ => true, - }); - }); // Run again with more accurate types for better diagnostics. Even if `result` was `Ok`, // we can rerun with a more accurate rhs type for eager obligation errors. - let result = match orig_result { - Ok(_) if erased => self.lookup_op_method(lhs_ty, &[rhs_ty], Op::Binary(op, is_assign)), - Ok(method) => Ok(method), - Err(ref mut err) => Err(std::mem::take(err)), + let result = match result { + Ok(method) => { + let trait_did = self.op_metadata(Op::Binary(op, is_assign), op.span).1.unwrap(); + let (obligation, _) = + self.obligation_for_method(op.span, trait_did, lhs_ty, Some(&[rhs_ty])); + let mut fulfill = >::new(self.tcx); + fulfill.register_predicate_obligation(self, obligation); + match fulfill.select_where_possible(&self.infcx) { + Ok(_) => Ok(method), + Err(err) => { + self.select_obligations_where_possible(false, |errors| { + errors.retain(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(predicate) => { + // Skip the obligations coming from the binop, we want to emit E0369 instead + // of E0277. + method.trait_def_id != predicate.def_id() + } + _ => true, + }); + }); + Err(err) + } + } + } + Err(err) => Err(err), }; match result { @@ -529,13 +537,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.emit(); + let ty = self.tcx.ty_error(); if suggested { // If we show labels with the types pointing at both sides of a binop, we replace these // with `TyErr` to avoid unnecessary E0308s from `enforce_builtin_binop_types`. - let ty = self.tcx.ty_error(); - (ty, ty, orig_result.map_or(ty, |method| method.sig.output())) + (ty, ty, ty) } else { - (lhs_ty, rhs_ty, self.tcx.ty_error()) + (lhs_ty, rhs_ty, ty) } } } @@ -914,18 +922,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let opname = Ident::with_dummy_span(opname); - let method = trait_did.and_then(|trait_did| { - self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) - }); + let (trait_did, method) = match trait_did { + Some(trait_did) => ( + trait_did, + self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)), + ), + None => return Err(vec![]), + }; - match (method, trait_did) { - (Some(ok), _) => { + match method { + Some(ok) => { let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(false, |_| {}); Ok(method) } - (None, None) => Err(vec![]), - (None, Some(trait_did)) => { + None => { let (obligation, _) = self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys)); let mut fulfill = >::new(self.tcx); diff --git a/src/test/ui/block-result/issue-22645.rs b/src/test/ui/block-result/issue-22645.rs index 5f7fb8dd32bd2..3c575761450ae 100644 --- a/src/test/ui/block-result/issue-22645.rs +++ b/src/test/ui/block-result/issue-22645.rs @@ -13,5 +13,5 @@ impl Add for Bob { fn main() { let b = Bob + 3.5; b + 3 //~ ERROR E0277 - //~^ ERROR: mismatched types + //~^ ERROR cannot add `{integer}` to `Bob` } diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index 397bdac60513e..b7093ece5b0c9 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -12,16 +12,15 @@ note: required because of the requirements on the impl of `Add<{integer}>` for ` LL | impl Add for Bob { | ^^^^^^^^^ ^^^ -error[E0308]: mismatched types - --> $DIR/issue-22645.rs:15:3 +error[E0369]: cannot add `{integer}` to `Bob` + --> $DIR/issue-22645.rs:15:5 | -LL | fn main() { - | - expected `()` because of default return type -LL | let b = Bob + 3.5; LL | b + 3 - | ^^^^^ expected `()`, found struct `Bob` + | - ^ - {integer} + | | + | Bob error: aborting due to 2 previous errors -Some errors have detailed explanations: E0277, E0308. +Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs index af494e3734914..ed06cf81d939b 100644 --- a/src/test/ui/consts/too_generic_eval_ice.rs +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -8,6 +8,7 @@ impl Foo { //~^ ERROR constant expression depends on a generic parameter //~| ERROR constant expression depends on a generic parameter //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` + //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` } } diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index ac104ed4a5a58..28291a0feb445 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -22,6 +22,15 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` -error: aborting due to 3 previous errors +error[E0369]: can't compare `[{integer}; _]` with `[{integer}; 0]` + --> $DIR/too_generic_eval_ice.rs:7:30 + | +LL | [5; Self::HOST_SIZE] == [6; 0] + | -------------------- ^^ ------ [{integer}; 0] + | | + | [{integer}; _] + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs index 66d562d2eb519..8facf0c57cc3a 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs @@ -2,5 +2,6 @@ const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s //~^ ERROR expected at least one digit in exponent //~| ERROR unknown start of token: \u{2212} //~| ERROR cannot subtract `{integer}` from `{float}` +//~| ERROR cannot subtract `{integer}` from `{float}` fn main() {} diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index 83fc37e7e537f..c6e279bf6a4e0 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -23,6 +23,15 @@ LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹ | = help: the trait `Sub<{integer}>` is not implemented for `{float}` -error: aborting due to 3 previous errors +error[E0369]: cannot subtract `{integer}` from `{float}` + --> $DIR/issue-49746-unicode-confusable-in-float-literal-expt.rs:1:53 + | +LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² + | ------^-- {integer} + | | + | {float} + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-24352.rs b/src/test/ui/issues/issue-24352.rs index 5c8246d179f9d..ffb69663ad2d9 100644 --- a/src/test/ui/issues/issue-24352.rs +++ b/src/test/ui/issues/issue-24352.rs @@ -1,4 +1,6 @@ fn main() { 1.0f64 - 1.0; - 1.0f64 - 1 //~ ERROR E0277 + 1.0f64 - 1 + //~^ ERROR cannot subtract + //~| ERROR cannot subtract } diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/issues/issue-24352.stderr index 69cd7789065d7..a226d6cebbae9 100644 --- a/src/test/ui/issues/issue-24352.stderr +++ b/src/test/ui/issues/issue-24352.stderr @@ -6,6 +6,15 @@ LL | 1.0f64 - 1 | = help: the trait `Sub<{integer}>` is not implemented for `f64` -error: aborting due to previous error +error[E0369]: cannot subtract `{integer}` from `f64` + --> $DIR/issue-24352.rs:3:12 + | +LL | 1.0f64 - 1 + | ------ ^ - {integer} + | | + | f64 + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs index a496e58a79bdd..1c1d4c25cd0b5 100644 --- a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs +++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.rs @@ -23,5 +23,6 @@ impl PartialEq> for Apple { fn main() { let _ = Pin::new(Apple) == Rc::pin(Apple); - //~^ ERROR type mismatch resolving + //~^ ERROR can't compare + //~| ERROR type mismatch resolving } diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr index 733456a1a8bd1..3d46682359105 100644 --- a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr +++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr @@ -8,6 +8,25 @@ LL | let _ = Pin::new(Apple) == Rc::pin(Apple); found struct `Rc` = note: required because of the requirements on the impl of `PartialEq>>` for `Pin` -error: aborting due to previous error +error[E0369]: can't compare `Pin` with `Pin>` + --> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29 + | +LL | let _ = Pin::new(Apple) == Rc::pin(Apple); + | --------------- ^^ -------------- Pin> + | | + | Pin + | +note: an implementation of `PartialEq` might be missing for `Apple` + --> $DIR/issue-67039-unsound-pin-partialeq.rs:9:1 + | +LL | struct Apple; + | ^^^^^^^^^^^^^ must implement `PartialEq` +help: consider annotating `Apple` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0271, E0369. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 445c534ff42f7..7acf7d9b16a90 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -1,9 +1,18 @@ fn main() { - 1 + Some(1); //~ ERROR cannot add `Option<{integer}>` to `{integer}` - 2 as usize - Some(1); //~ ERROR cannot subtract `Option<{integer}>` from `usize` - 3 * (); //~ ERROR cannot multiply `{integer}` by `()` - 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` - 5 < String::new(); //~ ERROR can't compare `{integer}` with `String` + 1 + Some(1); + //~^ ERROR cannot add `Option<{integer}>` to `{integer}` + //~| ERROR cannot add `Option<{integer}>` to `{integer}` + 2 as usize - Some(1); + //~^ ERROR cannot subtract `Option<{integer}>` from `usize` + //~| ERROR cannot subtract `Option<{integer}>` from `usize` + 3 * (); + //~^ ERROR cannot multiply `{integer}` by `()` + 4 / ""; + //~^ ERROR cannot divide `{integer}` by `&str` + 5 < String::new(); //~^ ERROR can't compare `{integer}` with `String` - 6 == Ok(1); //~ ERROR can't compare `{integer}` with `Result<{integer}, _>` + //~| ERROR can't compare `{integer}` with `String` + 6 == Ok(1); + //~^ ERROR can't compare `{integer}` with `Result<{integer}, _>` + //~| ERROR can't compare `{integer}` with `Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 07bc9f392a82b..233bdac303b1f 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -6,16 +6,32 @@ LL | 1 + Some(1); | = help: the trait `Add>` is not implemented for `{integer}` +error[E0369]: cannot add `Option<{integer}>` to `{integer}` + --> $DIR/binops.rs:2:7 + | +LL | 1 + Some(1); + | - ^ ------- Option<{integer}> + | | + | {integer} + error[E0277]: cannot subtract `Option<{integer}>` from `usize` - --> $DIR/binops.rs:3:16 + --> $DIR/binops.rs:5:16 | LL | 2 as usize - Some(1); | ^ no implementation for `usize - Option<{integer}>` | = help: the trait `Sub>` is not implemented for `usize` +error[E0369]: cannot subtract `Option<{integer}>` from `usize` + --> $DIR/binops.rs:5:16 + | +LL | 2 as usize - Some(1); + | ---------- ^ ------- Option<{integer}> + | | + | usize + error[E0369]: cannot multiply `{integer}` by `()` - --> $DIR/binops.rs:4:7 + --> $DIR/binops.rs:8:7 | LL | 3 * (); | - ^ -- () @@ -23,7 +39,7 @@ LL | 3 * (); | {integer} error[E0369]: cannot divide `{integer}` by `&str` - --> $DIR/binops.rs:5:7 + --> $DIR/binops.rs:10:7 | LL | 4 / ""; | - ^ -- &str @@ -31,7 +47,7 @@ LL | 4 / ""; | {integer} error[E0277]: can't compare `{integer}` with `String` - --> $DIR/binops.rs:6:7 + --> $DIR/binops.rs:12:7 | LL | 5 < String::new(); | ^ no implementation for `{integer} == String` @@ -39,7 +55,7 @@ LL | 5 < String::new(); = help: the trait `PartialEq` is not implemented for `{integer}` error[E0369]: can't compare `{integer}` with `String` - --> $DIR/binops.rs:6:7 + --> $DIR/binops.rs:12:7 | LL | 5 < String::new(); | - ^ ------------- String @@ -47,14 +63,22 @@ LL | 5 < String::new(); | {integer} error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` - --> $DIR/binops.rs:8:7 + --> $DIR/binops.rs:15:7 | LL | 6 == Ok(1); | ^^ no implementation for `{integer} == Result<{integer}, _>` | = help: the trait `PartialEq>` is not implemented for `{integer}` -error: aborting due to 7 previous errors +error[E0369]: can't compare `{integer}` with `Result<{integer}, _>` + --> $DIR/binops.rs:15:7 + | +LL | 6 == Ok(1); + | - ^^ ----- Result<{integer}, _> + | | + | {integer} + +error: aborting due to 10 previous errors Some errors have detailed explanations: E0277, E0369. For more information about an error, try `rustc --explain E0277`. From c8506a889a23e6db65accfb60e6a6e7c6bdc692b Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Mon, 18 Oct 2021 17:05:30 +0000 Subject: [PATCH 11/14] Move tests to `binops` subdirectory --- src/test/ui/{issues => binop}/issue-11771.rs | 0 src/test/ui/{issues => binop}/issue-11771.stderr | 0 src/test/ui/{issues => binop}/issue-24352.rs | 0 src/test/ui/{issues => binop}/issue-24352.stderr | 0 src/test/ui/{issues => binop}/issue-31076.rs | 0 src/test/ui/{issues => binop}/issue-31076.stderr | 0 src/test/ui/{issues => binop}/issue-59488.rs | 0 src/test/ui/{issues => binop}/issue-59488.stderr | 0 src/test/ui/{issues => binop}/issue-62375.rs | 0 src/test/ui/{issues => binop}/issue-62375.stderr | 0 src/test/ui/{typeck => binop}/issue-81293.rs | 0 src/test/ui/{typeck => binop}/issue-81293.stderr | 0 src/test/ui/{ => binop}/partialeq_help.fixed | 0 src/test/ui/{ => binop}/partialeq_help.rs | 0 src/test/ui/{ => binop}/partialeq_help.stderr | 0 src/test/ui/{ => binop}/shift-various-bad-types.rs | 0 src/test/ui/{ => binop}/shift-various-bad-types.stderr | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{issues => binop}/issue-11771.rs (100%) rename src/test/ui/{issues => binop}/issue-11771.stderr (100%) rename src/test/ui/{issues => binop}/issue-24352.rs (100%) rename src/test/ui/{issues => binop}/issue-24352.stderr (100%) rename src/test/ui/{issues => binop}/issue-31076.rs (100%) rename src/test/ui/{issues => binop}/issue-31076.stderr (100%) rename src/test/ui/{issues => binop}/issue-59488.rs (100%) rename src/test/ui/{issues => binop}/issue-59488.stderr (100%) rename src/test/ui/{issues => binop}/issue-62375.rs (100%) rename src/test/ui/{issues => binop}/issue-62375.stderr (100%) rename src/test/ui/{typeck => binop}/issue-81293.rs (100%) rename src/test/ui/{typeck => binop}/issue-81293.stderr (100%) rename src/test/ui/{ => binop}/partialeq_help.fixed (100%) rename src/test/ui/{ => binop}/partialeq_help.rs (100%) rename src/test/ui/{ => binop}/partialeq_help.stderr (100%) rename src/test/ui/{ => binop}/shift-various-bad-types.rs (100%) rename src/test/ui/{ => binop}/shift-various-bad-types.stderr (100%) diff --git a/src/test/ui/issues/issue-11771.rs b/src/test/ui/binop/issue-11771.rs similarity index 100% rename from src/test/ui/issues/issue-11771.rs rename to src/test/ui/binop/issue-11771.rs diff --git a/src/test/ui/issues/issue-11771.stderr b/src/test/ui/binop/issue-11771.stderr similarity index 100% rename from src/test/ui/issues/issue-11771.stderr rename to src/test/ui/binop/issue-11771.stderr diff --git a/src/test/ui/issues/issue-24352.rs b/src/test/ui/binop/issue-24352.rs similarity index 100% rename from src/test/ui/issues/issue-24352.rs rename to src/test/ui/binop/issue-24352.rs diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/binop/issue-24352.stderr similarity index 100% rename from src/test/ui/issues/issue-24352.stderr rename to src/test/ui/binop/issue-24352.stderr diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/binop/issue-31076.rs similarity index 100% rename from src/test/ui/issues/issue-31076.rs rename to src/test/ui/binop/issue-31076.rs diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/binop/issue-31076.stderr similarity index 100% rename from src/test/ui/issues/issue-31076.stderr rename to src/test/ui/binop/issue-31076.stderr diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/binop/issue-59488.rs similarity index 100% rename from src/test/ui/issues/issue-59488.rs rename to src/test/ui/binop/issue-59488.rs diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/binop/issue-59488.stderr similarity index 100% rename from src/test/ui/issues/issue-59488.stderr rename to src/test/ui/binop/issue-59488.stderr diff --git a/src/test/ui/issues/issue-62375.rs b/src/test/ui/binop/issue-62375.rs similarity index 100% rename from src/test/ui/issues/issue-62375.rs rename to src/test/ui/binop/issue-62375.rs diff --git a/src/test/ui/issues/issue-62375.stderr b/src/test/ui/binop/issue-62375.stderr similarity index 100% rename from src/test/ui/issues/issue-62375.stderr rename to src/test/ui/binop/issue-62375.stderr diff --git a/src/test/ui/typeck/issue-81293.rs b/src/test/ui/binop/issue-81293.rs similarity index 100% rename from src/test/ui/typeck/issue-81293.rs rename to src/test/ui/binop/issue-81293.rs diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/binop/issue-81293.stderr similarity index 100% rename from src/test/ui/typeck/issue-81293.stderr rename to src/test/ui/binop/issue-81293.stderr diff --git a/src/test/ui/partialeq_help.fixed b/src/test/ui/binop/partialeq_help.fixed similarity index 100% rename from src/test/ui/partialeq_help.fixed rename to src/test/ui/binop/partialeq_help.fixed diff --git a/src/test/ui/partialeq_help.rs b/src/test/ui/binop/partialeq_help.rs similarity index 100% rename from src/test/ui/partialeq_help.rs rename to src/test/ui/binop/partialeq_help.rs diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/binop/partialeq_help.stderr similarity index 100% rename from src/test/ui/partialeq_help.stderr rename to src/test/ui/binop/partialeq_help.stderr diff --git a/src/test/ui/shift-various-bad-types.rs b/src/test/ui/binop/shift-various-bad-types.rs similarity index 100% rename from src/test/ui/shift-various-bad-types.rs rename to src/test/ui/binop/shift-various-bad-types.rs diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/binop/shift-various-bad-types.stderr similarity index 100% rename from src/test/ui/shift-various-bad-types.stderr rename to src/test/ui/binop/shift-various-bad-types.stderr From e9384893524cc247098fc1cf6e77835f42e05457 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 19 Oct 2021 10:18:39 +0000 Subject: [PATCH 12/14] Use `span_suggestion_verbose` for uncalled functions --- compiler/rustc_typeck/src/check/op.rs | 25 ++++++++----------- src/test/ui/binop/issue-59488.stderr | 16 +++++++++--- src/test/ui/fn/fn-compare-mismatch.stderr | 4 +-- ...70724-add_type_neq_err_label-unwrap.stderr | 5 +++- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 76efcbaa392a1..cd4749d92d57c 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -600,7 +600,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool /* did we suggest to call a function because of missing parentheses? */ { err.span_label(span, ty.to_string()); if let FnDef(def_id, _) = *ty.kind() { - let source_map = self.tcx.sess.source_map(); if !self.tcx.has_typeck_results(def_id) { return false; } @@ -627,20 +626,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .lookup_op_method(fn_sig.output(), &[other_ty], Op::Binary(op, is_assign)) .is_ok() { - if let Ok(snippet) = source_map.span_to_snippet(span) { - let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { - (format!("{}( /* arguments */ )", snippet), Applicability::HasPlaceholders) - } else { - (format!("{}()", snippet), Applicability::MaybeIncorrect) - }; + let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() { + ("( /* arguments */ )".to_string(), Applicability::HasPlaceholders) + } else { + ("()".to_string(), Applicability::MaybeIncorrect) + }; - err.span_suggestion( - span, - "you might have forgotten to call this function", - variable_snippet, - applicability, - ); - } + err.span_suggestion_verbose( + span.shrink_to_hi(), + "you might have forgotten to call this function", + variable_snippet, + applicability, + ); return true; } } diff --git a/src/test/ui/binop/issue-59488.stderr b/src/test/ui/binop/issue-59488.stderr index d733e470888e7..f3f84cf27fc63 100644 --- a/src/test/ui/binop/issue-59488.stderr +++ b/src/test/ui/binop/issue-59488.stderr @@ -5,7 +5,11 @@ LL | foo > 12; | --- ^ -- {integer} | | | fn() -> i32 {foo} - | help: you might have forgotten to call this function: `foo()` + | +help: you might have forgotten to call this function + | +LL | foo() > 12; + | ++ error[E0308]: mismatched types --> $DIR/issue-59488.rs:14:11 @@ -23,7 +27,11 @@ LL | bar > 13; | --- ^ -- {integer} | | | fn(i64) -> i64 {bar} - | help: you might have forgotten to call this function: `bar( /* arguments */ )` + | +help: you might have forgotten to call this function + | +LL | bar( /* arguments */ ) > 13; + | +++++++++++++++++++ error[E0308]: mismatched types --> $DIR/issue-59488.rs:18:11 @@ -45,11 +53,11 @@ LL | foo > foo; help: you might have forgotten to call this function | LL | foo() > foo; - | ~~~~~ + | ++ help: you might have forgotten to call this function | LL | foo > foo(); - | ~~~~~ + | ++ error[E0369]: can't compare `fn() -> i32 {foo}` with `fn(i64) -> i64 {bar}` --> $DIR/issue-59488.rs:25:9 diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index d1ba7833bd651..dd915e22d44f3 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -9,11 +9,11 @@ LL | let x = f == g; help: you might have forgotten to call this function | LL | let x = f() == g; - | ~~~ + | ++ help: you might have forgotten to call this function | LL | let x = f == g(); - | ~~~ + | ++ error[E0308]: mismatched types --> $DIR/fn-compare-mismatch.rs:4:18 diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index 58be5d66a2454..de7a5194ad371 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -6,9 +6,12 @@ LL | assert_eq!(a, 0); | | | fn() -> i32 {a} | {integer} - | help: you might have forgotten to call this function: `*left_val()` | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you might have forgotten to call this function + | +LL | if !(*left_val() == *right_val) { + | ++ error[E0308]: mismatched types --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 From 777e47700e1c31b1f6b35a27ef476086c177eb84 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 19 Oct 2021 11:19:30 +0000 Subject: [PATCH 13/14] Remove duplicated errors --- compiler/rustc_typeck/src/check/op.rs | 20 +++++++- src/test/ui/binop/issue-24352.rs | 4 +- src/test/ui/binop/issue-24352.stderr | 13 +---- src/test/ui/consts/too_generic_eval_ice.rs | 1 - .../ui/consts/too_generic_eval_ice.stderr | 13 +---- ...nicode-confusable-in-float-literal-expt.rs | 1 - ...de-confusable-in-float-literal-expt.stderr | 13 +---- src/test/ui/mismatched_types/binops.rs | 4 -- src/test/ui/mismatched_types/binops.stderr | 47 +++---------------- 9 files changed, 32 insertions(+), 84 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index cd4749d92d57c..393bb4a0aae1e 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -206,7 +206,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // see `NB` above let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var, Some(lhs_expr)); - let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); + let rhs_ty = self.resolve_vars_with_obligations_and_mutate_fulfillment(rhs_ty, |errors| { + if let Ok(method) = result { + errors.retain(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(predicate) => { + // Skip the obligations coming from the binop, we want to emit E0369 instead + // of E0277. + method.trait_def_id != predicate.def_id() + } + _ => true, + }); + } + }); // Run again with more accurate types for better diagnostics. Even if `result` was `Ok`, // we can rerun with a more accurate rhs type for eager obligation errors. @@ -221,11 +232,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(_) => Ok(method), Err(err) => { self.select_obligations_where_possible(false, |errors| { + let eq_trait = self.tcx.lang_items().eq_trait(); errors.retain(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Trait(predicate) => { // Skip the obligations coming from the binop, we want to emit E0369 instead // of E0277. - method.trait_def_id != predicate.def_id() + let def_id = predicate.def_id(); + // We also remove obligations for `PartialEq` because + // `PartialOrd` introduces them and this way we don't get + // duplicated output. + method.trait_def_id != def_id && eq_trait != Some(def_id) } _ => true, }); diff --git a/src/test/ui/binop/issue-24352.rs b/src/test/ui/binop/issue-24352.rs index ffb69663ad2d9..93c37f1469bef 100644 --- a/src/test/ui/binop/issue-24352.rs +++ b/src/test/ui/binop/issue-24352.rs @@ -1,6 +1,4 @@ fn main() { 1.0f64 - 1.0; - 1.0f64 - 1 - //~^ ERROR cannot subtract - //~| ERROR cannot subtract + 1.0f64 - 1 //~ ERROR cannot subtract } diff --git a/src/test/ui/binop/issue-24352.stderr b/src/test/ui/binop/issue-24352.stderr index a226d6cebbae9..57cf5f5a0d295 100644 --- a/src/test/ui/binop/issue-24352.stderr +++ b/src/test/ui/binop/issue-24352.stderr @@ -1,11 +1,3 @@ -error[E0277]: cannot subtract `{integer}` from `f64` - --> $DIR/issue-24352.rs:3:12 - | -LL | 1.0f64 - 1 - | ^ no implementation for `f64 - {integer}` - | - = help: the trait `Sub<{integer}>` is not implemented for `f64` - error[E0369]: cannot subtract `{integer}` from `f64` --> $DIR/issue-24352.rs:3:12 | @@ -14,7 +6,6 @@ LL | 1.0f64 - 1 | | | f64 -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0369. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/consts/too_generic_eval_ice.rs b/src/test/ui/consts/too_generic_eval_ice.rs index ed06cf81d939b..af494e3734914 100644 --- a/src/test/ui/consts/too_generic_eval_ice.rs +++ b/src/test/ui/consts/too_generic_eval_ice.rs @@ -8,7 +8,6 @@ impl Foo { //~^ ERROR constant expression depends on a generic parameter //~| ERROR constant expression depends on a generic parameter //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` - //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]` } } diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index 28291a0feb445..a04dcda7924eb 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -14,14 +14,6 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | = note: this may fail depending on what value the parameter takes -error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]` - --> $DIR/too_generic_eval_ice.rs:7:30 - | -LL | [5; Self::HOST_SIZE] == [6; 0] - | ^^ no implementation for `[{integer}; _] == [{integer}; 0]` - | - = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` - error[E0369]: can't compare `[{integer}; _]` with `[{integer}; 0]` --> $DIR/too_generic_eval_ice.rs:7:30 | @@ -30,7 +22,6 @@ LL | [5; Self::HOST_SIZE] == [6; 0] | | | [{integer}; _] -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0369. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs index 8facf0c57cc3a..66d562d2eb519 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs @@ -2,6 +2,5 @@ const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s //~^ ERROR expected at least one digit in exponent //~| ERROR unknown start of token: \u{2212} //~| ERROR cannot subtract `{integer}` from `{float}` -//~| ERROR cannot subtract `{integer}` from `{float}` fn main() {} diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index c6e279bf6a4e0..9a2249ed737a6 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -15,14 +15,6 @@ help: Unicode character '−' (Minus Sign) looks like '-' (Minus/Hyphen), but it LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e-11; // m³⋅kg⁻¹⋅s⁻² | ~ -error[E0277]: cannot subtract `{integer}` from `{float}` - --> $DIR/issue-49746-unicode-confusable-in-float-literal-expt.rs:1:53 - | -LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² - | ^ no implementation for `{float} - {integer}` - | - = help: the trait `Sub<{integer}>` is not implemented for `{float}` - error[E0369]: cannot subtract `{integer}` from `{float}` --> $DIR/issue-49746-unicode-confusable-in-float-literal-expt.rs:1:53 | @@ -31,7 +23,6 @@ LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹ | | | {float} -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0369. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 7acf7d9b16a90..8773d6b3dc4f1 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -1,18 +1,14 @@ fn main() { 1 + Some(1); //~^ ERROR cannot add `Option<{integer}>` to `{integer}` - //~| ERROR cannot add `Option<{integer}>` to `{integer}` 2 as usize - Some(1); //~^ ERROR cannot subtract `Option<{integer}>` from `usize` - //~| ERROR cannot subtract `Option<{integer}>` from `usize` 3 * (); //~^ ERROR cannot multiply `{integer}` by `()` 4 / ""; //~^ ERROR cannot divide `{integer}` by `&str` 5 < String::new(); //~^ ERROR can't compare `{integer}` with `String` - //~| ERROR can't compare `{integer}` with `String` 6 == Ok(1); //~^ ERROR can't compare `{integer}` with `Result<{integer}, _>` - //~| ERROR can't compare `{integer}` with `Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 233bdac303b1f..dd982cf2d472b 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,11 +1,3 @@ -error[E0277]: cannot add `Option<{integer}>` to `{integer}` - --> $DIR/binops.rs:2:7 - | -LL | 1 + Some(1); - | ^ no implementation for `{integer} + Option<{integer}>` - | - = help: the trait `Add>` is not implemented for `{integer}` - error[E0369]: cannot add `Option<{integer}>` to `{integer}` --> $DIR/binops.rs:2:7 | @@ -14,16 +6,8 @@ LL | 1 + Some(1); | | | {integer} -error[E0277]: cannot subtract `Option<{integer}>` from `usize` - --> $DIR/binops.rs:5:16 - | -LL | 2 as usize - Some(1); - | ^ no implementation for `usize - Option<{integer}>` - | - = help: the trait `Sub>` is not implemented for `usize` - error[E0369]: cannot subtract `Option<{integer}>` from `usize` - --> $DIR/binops.rs:5:16 + --> $DIR/binops.rs:4:16 | LL | 2 as usize - Some(1); | ---------- ^ ------- Option<{integer}> @@ -31,7 +15,7 @@ LL | 2 as usize - Some(1); | usize error[E0369]: cannot multiply `{integer}` by `()` - --> $DIR/binops.rs:8:7 + --> $DIR/binops.rs:6:7 | LL | 3 * (); | - ^ -- () @@ -39,46 +23,29 @@ LL | 3 * (); | {integer} error[E0369]: cannot divide `{integer}` by `&str` - --> $DIR/binops.rs:10:7 + --> $DIR/binops.rs:8:7 | LL | 4 / ""; | - ^ -- &str | | | {integer} -error[E0277]: can't compare `{integer}` with `String` - --> $DIR/binops.rs:12:7 - | -LL | 5 < String::new(); - | ^ no implementation for `{integer} == String` - | - = help: the trait `PartialEq` is not implemented for `{integer}` - error[E0369]: can't compare `{integer}` with `String` - --> $DIR/binops.rs:12:7 + --> $DIR/binops.rs:10:7 | LL | 5 < String::new(); | - ^ ------------- String | | | {integer} -error[E0277]: can't compare `{integer}` with `Result<{integer}, _>` - --> $DIR/binops.rs:15:7 - | -LL | 6 == Ok(1); - | ^^ no implementation for `{integer} == Result<{integer}, _>` - | - = help: the trait `PartialEq>` is not implemented for `{integer}` - error[E0369]: can't compare `{integer}` with `Result<{integer}, _>` - --> $DIR/binops.rs:15:7 + --> $DIR/binops.rs:12:7 | LL | 6 == Ok(1); | - ^^ ----- Result<{integer}, _> | | | {integer} -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0277, E0369. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0369`. From 4797ad938ccd37f24b242c3fd81376c3023965c0 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 19 Oct 2021 11:32:55 +0000 Subject: [PATCH 14/14] Fix formatting of comment --- compiler/rustc_typeck/src/check/op.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 393bb4a0aae1e..2bec5956db93d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -235,8 +235,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let eq_trait = self.tcx.lang_items().eq_trait(); errors.retain(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Trait(predicate) => { - // Skip the obligations coming from the binop, we want to emit E0369 instead - // of E0277. + // Skip the obligations coming from the binop, we want to emit + // E0369 instead of E0277. let def_id = predicate.def_id(); // We also remove obligations for `PartialEq` because // `PartialOrd` introduces them and this way we don't get