diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index ec855b4debd04..06d882a309489 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -20,8 +20,8 @@ use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use crate::error_reporting::traits::{FindExprBySpan, to_pretty_impl_header}; -use crate::traits::ObligationCtxt; use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{FulfillmentError, ObligationCtxt}; #[derive(Debug)] pub enum CandidateSource { @@ -174,10 +174,43 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( } impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + /// The term of an ambiguous obligation's predicate that gets blamed for the + /// missing type annotation: the first one still containing inference variables. + /// + /// Besides `maybe_report_ambiguity` pointing its diagnostics at this term, + /// `report_fulfillment_errors` merges the ambiguity errors whose blamed terms + /// share an inference variable into a single diagnostic. + pub(super) fn ambiguity_term(&self, predicate: ty::Predicate<'tcx>) -> Option> { + match predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => data + .trait_ref + .args + .iter() + .filter_map(ty::GenericArg::as_term) + .find(|term| term.has_non_region_infer()), + ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => data + .projection_term + .args + .iter() + .filter_map(ty::GenericArg::as_term) + .chain([data.term]) + .find(|term| term.has_non_region_infer()), + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => Some(term), + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { + data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer()) + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => Some(ct.into()), + ty::PredicateKind::Subtype(data) => Some(data.a.into()), + ty::PredicateKind::NormalizesTo(data) if data.term.is_infer() => Some(data.term), + _ => None, + } + } + #[instrument(skip(self), level = "debug")] pub(super) fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, + related: &[&FulfillmentError<'tcx>], ) -> ErrorGuaranteed { // Unable to successfully determine, probably means // insufficient type information, but could mean @@ -255,12 +288,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Pick the first generic parameter that still contains inference variables as the one // we're going to emit an error for. If there are none (see above), fall back to // a more general error. - let term = data - .trait_ref - .args - .iter() - .filter_map(ty::GenericArg::as_term) - .find(|s| s.has_non_region_infer()); + let term = self.ambiguity_term(predicate); let mut err = if let Some(term) = term { let candidates: Vec<_> = self @@ -306,34 +334,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .with_long_ty_path(long_ty_path) }; - let mut ambiguities = compute_applicable_impls_for_diagnostics( - self.infcx, - &obligation.with(self.tcx, trait_pred), - false, - ); - let has_non_region_infer = trait_pred - .skip_binder() - .trait_ref - .args - .types() - .any(|t| !t.is_ty_or_numeric_infer()); - // It doesn't make sense to talk about applicable impls if there are more than a - // handful of them. If there are a lot of them, but only a few of them have no type - // params, we only show those, as they are more likely to be useful/intended. - if ambiguities.len() > 5 { - let infcx = self.infcx; - if !ambiguities.iter().all(|option| match option { - CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, - CandidateSource::ParamEnv(_) => true, - }) { - // If not all are blanket impls, we filter blanked impls out. - ambiguities.retain(|option| match option { - CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, - CandidateSource::ParamEnv(_) => true, - }); - } - } - if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { + if let Some(ambiguities) = self.applicable_impls_to_mention(obligation, trait_pred) + { if let Some(e) = self.tainted_by_errors() && term.is_none() { @@ -590,13 +592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // other `Foo` impls are incoherent. return guar; } - let term = data - .projection_term - .args - .iter() - .filter_map(ty::GenericArg::as_term) - .chain([data.term]) - .find(|g| g.has_non_region_infer()); + let term = self.ambiguity_term(predicate); let predicate = self.tcx.short_string(predicate, &mut long_ty_path); if let Some(term) = term { self.emit_inference_failure_err( @@ -621,16 +617,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) => { if let Err(e) = predicate.error_reported() { return e; } if let Some(e) = self.tainted_by_errors() { return e; } - let term = - data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer()); - if let Some(term) = term { + if let Some(term) = self.ambiguity_term(predicate) { self.emit_inference_failure_err( obligation.cause.body_def_id, span, @@ -713,10 +707,119 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .with_long_ty_path(long_ty_path) } }; + + // The related obligations are ambiguous because of the same inference variable, + // so they belong to this diagnostic: annotating the variable has to satisfy all + // of them at once. Mention their requirements, except for bookkeeping predicates + // (`WellFormed`, sizedness, ...) whose mention wouldn't be actionable. + let mut mentioned = vec![predicate]; + let mut mentioned_strs: Vec = vec![]; + for &error in related { + let related_pred = self.resolve_vars_if_possible(error.obligation.predicate); + if mentioned.contains(&related_pred) { + continue; + } + let note = match related_pred.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) + if !matches!( + self.tcx.as_lang_item(data.def_id()), + Some(LangItem::Sized | LangItem::MetaSized | LangItem::PointeeSized) + ) => + { + let clause = related_pred.kind().rebind(data); + if let ty::Infer(_) = clause.self_ty().skip_binder().kind() { + let tr = self.tcx.short_string( + clause.print_modifiers_and_trait_path(), + &mut err.long_ty_path(), + ); + format!("the type must also implement `{tr}`") + } else { + let pred = self.tcx.short_string(related_pred, &mut err.long_ty_path()); + let note = format!("cannot satisfy `{pred}`"); + // The self type is known, so the `impl`s that could have applied to it are + // few and worth pointing at, like the blamed bound does. When it is still + // an inference variable the list is every `impl` of the trait, which is + // why the branch above only names the trait. + // + // `tainted_by_errors` is checked because `annotate_source_of_ambiguity` + // downgrades the whole diagnostic once an error was already emitted. + if !mentioned_strs.contains(¬e) + && self.tainted_by_errors().is_none() + && let Some(ambiguities) = + self.applicable_impls_to_mention(&error.obligation, clause) + { + self.annotate_source_of_ambiguity(&mut err, &ambiguities, related_pred); + mentioned_strs.push(note); + mentioned.push(related_pred); + continue; + } + note + } + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + let pred = self.tcx.short_string(related_pred, &mut err.long_ty_path()); + format!("cannot satisfy `{pred}`") + } + _ => { + mentioned.push(related_pred); + continue; + } + }; + // Two predicates can print identically (e.g. `From` and `From` both show as + // `From<_>`); only emit each unique note string once. + if !mentioned_strs.contains(¬e) { + err.note(note.clone()); + mentioned_strs.push(note); + } + mentioned.push(related_pred); + } + self.note_obligation_cause(&mut err, obligation); + // The merged errors are not reported on their own anymore, so the bounds they came from + // have to be explained here too. Causes shared with the blamed obligation are already + // described by the call above. + for &error in related { + if error.obligation.cause.code() != obligation.cause.code() { + self.note_obligation_cause(&mut err, &error.obligation); + } + } err.emit() } + /// The `impl`s and `where` clauses that could have satisfied `trait_pred`, when listing them + /// is likely to help. `None` means the caller should describe the bound some other way. + fn applicable_impls_to_mention( + &self, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> Option> { + let mut ambiguities = compute_applicable_impls_for_diagnostics( + self.infcx, + &obligation.with(self.tcx, trait_pred), + false, + ); + let has_non_region_infer = + trait_pred.skip_binder().trait_ref.args.types().any(|t| !t.is_ty_or_numeric_infer()); + // It doesn't make sense to talk about applicable impls if there are more than a + // handful of them. If there are a lot of them, but only a few of them have no type + // params, we only show those, as they are more likely to be useful/intended. + if ambiguities.len() > 5 { + let infcx = self.infcx; + if !ambiguities.iter().all(|option| match option { + CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, + CandidateSource::ParamEnv(_) => true, + }) { + // If not all are blanket impls, we filter blanked impls out. + ambiguities.retain(|option| match option { + CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0, + CandidateSource::ParamEnv(_) => true, + }); + } + } + (ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer) + .then_some(ambiguities) + } + fn annotate_source_of_ambiguity( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 76b4900367bde..8bf5814b9fe13 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -11,6 +11,7 @@ use rustc_crate_store::{ExternCrate, ExternCrateSource}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err}; +use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, AmbigArg}; @@ -21,6 +22,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_next_trait_solver::solve::TyOrConstInferVar; use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span}; use thin_vec::ThinVec; use tracing::{info, instrument}; @@ -250,12 +252,99 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + // Ambiguity errors blaming the same inference variable describe a single problem: + // annotating that one variable has to satisfy all of them at once. Reporting them + // separately loses all but the first, as the rest get canceled as duplicates once + // the `infcx` is tainted (see `maybe_report_ambiguity`), hiding their requirements + // from the user. Instead, report the first one (the sort above placed the most + // informative obligation first) and mention the requirements of the others in it. + // + // Type variables that are only related through a pending `Coerce` or `Subtype` + // obligation still concern the same annotation, so compare their sub-unification + // roots, like `need_type_info` does when looking for the annotation source. + let ambiguity_infer_var = |error: &FulfillmentError<'tcx>| match error.code { + FulfillmentErrorCode::Ambiguity { overflow: None } => self + .ambiguity_term(self.resolve_vars_if_possible(error.obligation.predicate)) + .and_then(|term| { + ty::GenericArg::from(term) + .walk() + .find_map(TyOrConstInferVar::maybe_from_generic_arg::>) + }) + .map(|var| match var { + TyOrConstInferVar::Ty(vid) => { + TyOrConstInferVar::Ty(self.sub_unification_table_root_var(vid)) + } + other => other, + }), + _ => None, + }; + let infer_vars: Vec<_> = errors.iter().map(ambiguity_infer_var).collect(); + let mut reported = None; + let mut merged = vec![None; errors.len()]; + let mut reported_as_primary = vec![false; errors.len()]; for from_expansion in [false, true] { - for (error, suppressed) in iter::zip(&errors, &is_suppressed) { + for (index, (error, suppressed)) in iter::zip(&errors, &is_suppressed).enumerate() { if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { if !error.references_error() { - let guar = self.report_fulfillment_error(error); + let guar = if let Some(guar) = merged[index] { + guar + } else { + let group: Vec = match infer_vars[index] { + Some(var) => (0..errors.len()) + .filter(|&other| { + other != index && infer_vars[other] == Some(var) + }) + .collect(), + None => vec![], + }; + // Only merge errors that a note on this diagnostic can fully + // represent. An error blaming a different expression labels that + // expression and suggests how to annotate it, and one whose + // predicate we can't phrase as a note (e.g. const evaluatability) + // says nothing here, so both keep their own error. + let merges = |other: usize| { + errors[other].obligation.cause.span == error.obligation.cause.span + && match errors[other].obligation.predicate.kind().skip_binder() + { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + !matches!( + self.tcx.as_lang_item(data.def_id()), + Some( + LangItem::Sized + | LangItem::MetaSized + | LangItem::PointeeSized + ) + ) + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection( + _, + )) => true, + _ => false, + } + }; + let related: Vec<_> = group + .iter() + .filter(|&&other| { + // Exclude already-reported primaries: they were their own + // canonical error and adding them as notes here would + // produce duplicate information. + merges(other) + && !is_suppressed[other] + && !errors[other].references_error() + && !reported_as_primary[other] + }) + .map(|&other| &errors[other]) + .collect(); + let guar = self.report_fulfillment_error(error, &related); + for &other in &group { + if merges(other) { + merged[other] = Some(guar); + } + } + reported_as_primary[index] = true; + guar + }; self.infcx.set_tainted_by_errors(guar); reported = Some(guar); // We want to ignore desugarings here: spans are equivalent even @@ -286,7 +375,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "debug")] - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { + fn report_fulfillment_error( + &self, + error: &FulfillmentError<'tcx>, + related: &[&FulfillmentError<'tcx>], + ) -> ErrorGuaranteed { let mut error = FulfillmentError { obligation: error.obligation.clone(), code: error.code.clone(), @@ -311,7 +404,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.report_projection_error(&error.obligation, e) } FulfillmentErrorCode::Ambiguity { overflow: None } => { - self.maybe_report_ambiguity(&error.obligation) + self.maybe_report_ambiguity(&error.obligation, related) } FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 3f5ad1ed9a8f5..5905d6172c2da 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -1012,9 +1012,10 @@ pub enum ComputeGoalFastPathOutcome { TriviallyStalled { stalled_on: GoalStalledOn }, } -/// Helper for `InferCtxt::ty_or_const_infer_var_changed` (see comment on that), currently -/// used only for `traits::fulfill`'s list of `stalled_on` inference variables. -#[derive(Copy, Clone, Debug)] +/// Helper for `InferCtxt::ty_or_const_infer_var_changed` (see comment on that), used +/// for `traits::fulfill`'s list of `stalled_on` inference variables and for merging +/// ambiguity errors caused by the same inference variable during error reporting. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum TyOrConstInferVar { /// Equivalent to `ty::Infer(ty::TyVar(_))`. Ty(TyVid), diff --git a/tests/ui/closures/unique-closure-type-mismatch.stderr b/tests/ui/closures/unique-closure-type-mismatch.stderr index 3a31b6db4f62b..7d2a05b1d148b 100644 --- a/tests/ui/closures/unique-closure-type-mismatch.stderr +++ b/tests/ui/closures/unique-closure-type-mismatch.stderr @@ -18,6 +18,7 @@ LL | 1 => |c| c + 1, | ^ - type must be known at this point | = note: cannot satisfy `<_ as Add>::Output == _` + = note: the type must also implement `Add` help: consider giving this closure parameter an explicit type | LL | 1 => |c: /* Type */| c + 1, diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr index e0bf63f4b066d..366711e6d43c7 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -29,6 +29,7 @@ error[E0284]: type annotations needed for `([(); _], [(); 10])` LL | let (mut arr, mut arr_with_weird_len) = proj(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point | + = note: cannot satisfy `::PROJ<_> == 10` note: required by a const generic parameter in `proj` --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:44:9 | diff --git a/tests/ui/errors/span-format_args-issue-140578.stderr b/tests/ui/errors/span-format_args-issue-140578.stderr index b5394b6c33afc..c4a2911d3fb07 100644 --- a/tests/ui/errors/span-format_args-issue-140578.stderr +++ b/tests/ui/errors/span-format_args-issue-140578.stderr @@ -2,31 +2,57 @@ error[E0282]: type annotations needed --> $DIR/span-format_args-issue-140578.rs:2:28 | LL | print!("{:?} {a} {a:?}", [], a = 1 + 1); - | ^^ cannot infer type + | ---- ^^ cannot infer type + | | + | required by this formatting parameter + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error[E0282]: type annotations needed --> $DIR/span-format_args-issue-140578.rs:7:30 | LL | println!("{:?} {a} {a:?}", [], a = 1 + 1); - | ^^ cannot infer type + | ---- ^^ cannot infer type + | | + | required by this formatting parameter + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error[E0282]: type annotations needed --> $DIR/span-format_args-issue-140578.rs:12:35 | LL | println!("{:?} {:?} {a} {a:?}", [], [], a = 1 + 1); - | ^^ cannot infer type + | ---- ^^ cannot infer type + | | + | required by this formatting parameter + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error[E0282]: type annotations needed --> $DIR/span-format_args-issue-140578.rs:17:41 | LL | println!("{:?} {:?} {a} {a:?} {b:?}", [], [], a = 1 + 1, b = []); - | ^^ cannot infer type + | ---- ^^ cannot infer type + | | + | required by this formatting parameter + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error[E0282]: type annotations needed --> $DIR/span-format_args-issue-140578.rs:26:9 | +LL | {:?} {:?} + | ---- required by this formatting parameter +... LL | [], | ^^ cannot infer type + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error: aborting due to 5 previous errors diff --git a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr index 58ed71fad4a66..0dcc5f11d4861 100644 --- a/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr +++ b/tests/ui/generic-associated-types/ambig-hr-projection-issue-93340.old.stderr @@ -5,6 +5,7 @@ LL | cmp_eq | ^^^^^^ cannot infer type of the type parameter `A` declared on the function `cmp_eq` | = note: the type must implement `Scalar` + = note: cannot satisfy `::RefType<'_> == _` note: required by a bound in `cmp_eq` --> $DIR/ambig-hr-projection-issue-93340.rs:10:22 | diff --git a/tests/ui/generic-associated-types/bugs/issue-88382.stderr b/tests/ui/generic-associated-types/bugs/issue-88382.stderr index 0567e1c55a96f..8b6c8929dd608 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88382.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-88382.stderr @@ -2,7 +2,9 @@ error[E0283]: type annotations needed --> $DIR/issue-88382.rs:26:40 | LL | do_something(SomeImplementation(), test); - | ^^^^ cannot infer type of the type parameter `I` declared on the function `test` + | ------------ ^^^^ cannot infer type of the type parameter `I` declared on the function `test` + | | + | required by a bound introduced by this call | = note: the type must implement `Iterable` help: the trait `Iterable` is implemented for `SomeImplementation` @@ -10,11 +12,17 @@ help: the trait `Iterable` is implemented for `SomeImplementation` | LL | impl Iterable for SomeImplementation { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: cannot satisfy `<_ as Iterable>::Iterator<'_> == std::iter::Empty` note: required by a bound in `test` --> $DIR/issue-88382.rs:29:16 | LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} | ^^^^^^^^ required by this bound in `test` +note: required by a bound in `do_something` + --> $DIR/issue-88382.rs:20:48 + | +LL | fn do_something(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something` help: consider specifying a concrete type for the type parameter `I` | LL | do_something(SomeImplementation(), test::); diff --git a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr index 8abced84ab86b..edef7a5e0a2c7 100644 --- a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr +++ b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr @@ -8,6 +8,7 @@ LL | loop {} | ------- return type was inferred to be `!` here | = note: the type must implement `Future` + = note: cannot satisfy `<_ as Future>::Output == ()` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 52b63ae8177ea..a0cdc8ee89382 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -389,6 +389,7 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for SyncView where F: Sync, F: Fn, Args: std::marker::Tuple; + = note: cannot satisfy `<_ as FnOnce<()>>::Output == impl Debug` error: unconstrained opaque type --> $DIR/where-allowed.rs:122:16 diff --git a/tests/ui/inference/ambiguity-errors-single-diagnostic.rs b/tests/ui/inference/ambiguity-errors-single-diagnostic.rs new file mode 100644 index 0000000000000..7e8403b217ec4 --- /dev/null +++ b/tests/ui/inference/ambiguity-errors-single-diagnostic.rs @@ -0,0 +1,25 @@ +//! Ambiguity errors blaming the same inference variable are merged into a single +//! diagnostic that mentions every unsatisfied requirement, instead of only the +//! first one while the others get canceled as tainted-by-error duplicates. +//! +//! Regression test for . + +trait Trait {} +impl Trait for String {} +struct NotDefault; +impl Trait for NotDefault {} + +fn as_input(_: T) {} +fn constrained(_: T) {} + +fn two_bounds() { + as_input(Default::default()); + //~^ ERROR type annotations needed +} + +fn three_bounds() { + constrained(Default::default()); + //~^ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/inference/ambiguity-errors-single-diagnostic.stderr b/tests/ui/inference/ambiguity-errors-single-diagnostic.stderr new file mode 100644 index 0000000000000..4488032717ce2 --- /dev/null +++ b/tests/ui/inference/ambiguity-errors-single-diagnostic.stderr @@ -0,0 +1,65 @@ +error[E0283]: type annotations needed + --> $DIR/ambiguity-errors-single-diagnostic.rs:16:5 + | +LL | as_input(Default::default()); + | ^^^^^^^^ ------------------ type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `as_input` + | + = note: the type must implement `Trait` +help: the following types implement trait `Trait` + --> $DIR/ambiguity-errors-single-diagnostic.rs:8:1 + | +LL | impl Trait for String {} + | ^^^^^^^^^^^^^^^^^^^^^ `String` +LL | struct NotDefault; +LL | impl Trait for NotDefault {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `NotDefault` + = note: the type must also implement `Default` +note: required by a bound in `as_input` + --> $DIR/ambiguity-errors-single-diagnostic.rs:12:16 + | +LL | fn as_input(_: T) {} + | ^^^^^ required by this bound in `as_input` +help: consider specifying a concrete type for the type parameter `T` + | +LL | as_input::(Default::default()); + | ++++++++++++++ + +error[E0283]: type annotations needed + --> $DIR/ambiguity-errors-single-diagnostic.rs:21:5 + | +LL | constrained(Default::default()); + | ^^^^^^^^^^^ ------------------ type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `constrained` + | + = note: the type must implement `Trait` +help: the following types implement trait `Trait` + --> $DIR/ambiguity-errors-single-diagnostic.rs:8:1 + | +LL | impl Trait for String {} + | ^^^^^^^^^^^^^^^^^^^^^ `String` +LL | struct NotDefault; +LL | impl Trait for NotDefault {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `NotDefault` + = note: the type must also implement `Clone` + = note: the type must also implement `Default` +note: required by a bound in `constrained` + --> $DIR/ambiguity-errors-single-diagnostic.rs:13:19 + | +LL | fn constrained(_: T) {} + | ^^^^^ required by this bound in `constrained` +note: required by a bound in `constrained` + --> $DIR/ambiguity-errors-single-diagnostic.rs:13:27 + | +LL | fn constrained(_: T) {} + | ^^^^^ required by this bound in `constrained` +help: consider specifying a concrete type for the type parameter `T` + | +LL | constrained::(Default::default()); + | ++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/inference/issue-12028.stderr b/tests/ui/inference/issue-12028.stderr index 0d8ef1c938d4c..92cfd85d96f85 100644 --- a/tests/ui/inference/issue-12028.stderr +++ b/tests/ui/inference/issue-12028.stderr @@ -5,6 +5,14 @@ LL | self.input_stream(&mut stream); | ^^^^^^^^^^^^ | = note: cannot satisfy `<_ as StreamHasher>::S == ::S` + = note: the type must also implement `StreamHasher` +note: required by a bound in `StreamHash::input_stream` + --> $DIR/issue-12028.rs:20:21 + | +LL | trait StreamHash: Hash { + | ^^^^^^^^^^^^ required by this bound in `StreamHash::input_stream` +LL | fn input_stream(&self, stream: &mut H::S); + | ------------ required by a bound in this associated function help: try using a fully qualified path to specify the expected types | LL - self.input_stream(&mut stream); diff --git a/tests/ui/inference/issue-70082.stderr b/tests/ui/inference/issue-70082.stderr index 926ecff4a4fb5..5dc2311272e67 100644 --- a/tests/ui/inference/issue-70082.stderr +++ b/tests/ui/inference/issue-70082.stderr @@ -7,6 +7,9 @@ LL | let y: f64 = 0.01f64 * 1i16.into(); | type must be known at this point | = note: cannot satisfy `>::Output == f64` + = note: multiple `impl`s satisfying `f64: Mul<_>` found in the `core` crate: + - impl Mul for f64; + - impl Mul<&f64> for f64; help: try using a fully qualified path to specify the expected types | LL - let y: f64 = 0.01f64 * 1i16.into(); diff --git a/tests/ui/inference/issue-71584.stderr b/tests/ui/inference/issue-71584.stderr index 4bbfef6c44afa..1439ae6a51583 100644 --- a/tests/ui/inference/issue-71584.stderr +++ b/tests/ui/inference/issue-71584.stderr @@ -7,6 +7,10 @@ LL | d = d % n.into(); | type must be known at this point | = note: cannot satisfy `>::Output == u64` + = note: multiple `impl`s satisfying `u64: Rem<_>` found in the `core` crate: + - impl Rem for u64; + - impl Rem<&u64> for u64; + - impl Rem> for u64; help: try using a fully qualified path to specify the expected types | LL - d = d % n.into(); diff --git a/tests/ui/inference/issue-71732.stderr b/tests/ui/inference/issue-71732.stderr index 3b46a24e01088..04be1ce6c07f4 100644 --- a/tests/ui/inference/issue-71732.stderr +++ b/tests/ui/inference/issue-71732.stderr @@ -10,6 +10,12 @@ LL | .get(&"key".into()) - impl Borrow for String; - impl Borrow for T where T: ?Sized; + = note: the type must also implement `Hash` + = note: the type must also implement `Eq` +note: required by a bound in `HashMap::::get` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +note: required by a bound in `HashMap::::get` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying a concrete type for the type parameter `Q` diff --git a/tests/ui/inference/issue-80816.rs b/tests/ui/inference/issue-80816.rs index 4d319b44987e2..e5aae3abcb973 100644 --- a/tests/ui/inference/issue-80816.rs +++ b/tests/ui/inference/issue-80816.rs @@ -49,6 +49,7 @@ pub fn foo() { let s: Arc>> = unimplemented!(); let guard: Guard> = s.load(); //~^ ERROR: type annotations needed + //~| NOTE: cannot satisfy `> as Access<_>>::Guard == Guard>` //~| HELP: try using a fully qualified path to specify the expected types } diff --git a/tests/ui/inference/issue-80816.stderr b/tests/ui/inference/issue-80816.stderr index bca7cd4c3adbb..7230fd042df0f 100644 --- a/tests/ui/inference/issue-80816.stderr +++ b/tests/ui/inference/issue-80816.stderr @@ -12,6 +12,7 @@ LL | impl Access for ArcSwapAny { ... LL | impl Access for ArcSwapAny> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: cannot satisfy `> as Access<_>>::Guard == Guard>` note: required for `Arc>>` to implement `Access<_>` --> $DIR/issue-80816.rs:31:45 | diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr index ff668f88d4d15..14d671f80e095 100644 --- a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr +++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr @@ -2,7 +2,12 @@ error[E0282]: type annotations needed --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:22 | LL | println!("{:?}", []); - | ^^ cannot infer type + | ---- ^^ cannot infer type + | | + | required by this formatting parameter + | + = note: the type must also implement `Debug` + = note: required for `[_; 0]` to implement `Debug` error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/single-type-generic-suggestion.stderr b/tests/ui/inference/need_type_info/single-type-generic-suggestion.stderr index fe696847eab7a..d1dcafcbc1d4d 100644 --- a/tests/ui/inference/need_type_info/single-type-generic-suggestion.stderr +++ b/tests/ui/inference/need_type_info/single-type-generic-suggestion.stderr @@ -5,6 +5,9 @@ LL | "".parse(); | ^^^^^ cannot infer type of the type parameter `F` declared on the method `parse` | = note: cannot satisfy `<_ as FromStr>::Err == _` + = note: the type must also implement `FromStr` +note: required by a bound in `core::str::::parse` + --> $SRC_DIR/core/src/str/mod.rs:LL:COL help: consider specifying a concrete type for the type parameter `F` | LL | "".parse::(); diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr index 22f3a258e6986..429c4edcad339 100644 --- a/tests/ui/traits/issue-77982.stderr +++ b/tests/ui/traits/issue-77982.stderr @@ -10,12 +10,28 @@ LL | opts.get(opt.as_ref()); - impl Borrow for String; - impl Borrow for T where T: ?Sized; + = note: the type must also implement `Hash` + = note: the type must also implement `Eq` +note: required by a bound in `HashMap::::get` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +note: required by a bound in `HashMap::::get` + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL note: required by a bound in `HashMap::::get` --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL help: consider specifying a concrete type for the type parameter `Q` | LL | opts.get::(opt.as_ref()); | ++++++++++++++ +help: consider removing this method call, as the receiver has type `String` and `String: Hash` trivially holds + | +LL - opts.get(opt.as_ref()); +LL + opts.get(opt); + | +help: consider removing this method call, as the receiver has type `String` and `String: Eq` trivially holds + | +LL - opts.get(opt.as_ref()); +LL + opts.get(opt); + | error[E0283]: type annotations needed --> $DIR/issue-77982.rs:11:10 diff --git a/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr index 3c5a00744a636..90cd6a36d9c0b 100644 --- a/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr +++ b/tests/ui/traits/next-solver/unexpected-pointer-deref-issue-154568.stderr @@ -5,6 +5,7 @@ LL | let handshake = Handshake(callback.0.clone()); | ^^^^^^^^^ ----------------------------- type must be known at this point | = note: the type must implement `Role` + = note: cannot satisfy `<_ as Role>::Inner == ()` note: required by a bound in `Handshake` --> $DIR/unexpected-pointer-deref-issue-154568.rs:9:21 | diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index dbe8a656812a5..d1113d0a3e6b6 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -14,11 +14,17 @@ LL | x = unconstrained_map(); where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - impl Fn for SyncView where F: Sync, F: Fn, Args: std::marker::Tuple; + = note: cannot satisfy `<_ as FnOnce<()>>::Output == _` note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 | LL | fn unconstrained_map U, U>() -> as Mirror>::Assoc { todo!() } | ^^^^^^^^^ required by this bound in `unconstrained_map` +note: required by a bound in `unconstrained_map` + --> $DIR/well-formed-in-relate.rs:21:33 + | +LL | fn unconstrained_map U, U>() -> as Mirror>::Assoc { todo!() } + | ^ required by this bound in `unconstrained_map` help: consider giving `x` an explicit type, where the type for type parameter `T` is specified | LL | let x: Map; diff --git a/tests/ui/type-inference/index-expr-ambiguous-type.stderr b/tests/ui/type-inference/index-expr-ambiguous-type.stderr index 83de98d80cae6..1e2ea9ab32215 100644 --- a/tests/ui/type-inference/index-expr-ambiguous-type.stderr +++ b/tests/ui/type-inference/index-expr-ambiguous-type.stderr @@ -11,6 +11,9 @@ LL | let _foo = 0 + [1, 2, 3][bad_idx.into()]; | ^^^^ cannot infer type | = note: cannot satisfy `>::Output == _` + = note: multiple `impl`s satisfying `i32: Add<_>` found in the `core` crate: + - impl Add for i32; + - impl Add<&i32> for i32; error[E0283]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:21:34 @@ -41,6 +44,9 @@ LL | let _foo = 0u64 + [1i32, 2, 3][bad_idx.into()]; | ^ cannot infer type | = note: cannot satisfy `>::Output == _` + = note: multiple `impl`s satisfying `u64: Add<_>` found in the `core` crate: + - impl Add for u64; + - impl Add<&u64> for u64; error[E0284]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:44:38 @@ -49,6 +55,7 @@ LL | let _foo = 1u32 << [0u8][bad_idx.into()]; | ^^^^ cannot infer type | = note: cannot satisfy `>::Output == _` + = note: cannot satisfy `u32: Shl<_>` error[E0283]: type annotations needed --> $DIR/index-expr-ambiguous-type.rs:50:45 diff --git a/tests/ui/type-inference/or_else-multiple-type-params.stderr b/tests/ui/type-inference/or_else-multiple-type-params.stderr index 9bcd07f8bf164..ea64b91b726d7 100644 --- a/tests/ui/type-inference/or_else-multiple-type-params.stderr +++ b/tests/ui/type-inference/or_else-multiple-type-params.stderr @@ -3,7 +3,13 @@ error[E0282]: type annotations needed for `Result` | LL | .or_else(|err| { | ^^^^^ +LL | panic!("oh no: {:?}", err); +LL | }).unwrap(); + | ------ required by a bound introduced by this call | + = note: the type must also implement `Debug` +note: required by a bound in `Result::::unwrap` + --> $SRC_DIR/core/src/result.rs:LL:COL help: try giving this closure an explicit return type | LL | .or_else(|err| -> Result<_, F> { diff --git a/tests/ui/type-inference/panic-with-unspecified-type.stderr b/tests/ui/type-inference/panic-with-unspecified-type.stderr index 99c6e83ef3225..99949d4901a4e 100644 --- a/tests/ui/type-inference/panic-with-unspecified-type.stderr +++ b/tests/ui/type-inference/panic-with-unspecified-type.stderr @@ -6,8 +6,13 @@ LL | panic!(std::default::Default::default()); | | | | | cannot infer type | required by a bound introduced by this call + | required by a bound introduced by this call | = note: the type must implement `Any` + = note: the type must also implement `Send` + = note: the type must also implement `Default` +note: required by a bound in `std::rt::begin_panic` + --> $SRC_DIR/std/src/panicking.rs:LL:COL note: required by a bound in `std::rt::begin_panic` --> $SRC_DIR/std/src/panicking.rs:LL:COL diff --git a/tests/ui/typeck/type-inference-for-associated-types-69683.rs b/tests/ui/typeck/type-inference-for-associated-types-69683.rs index f18adcae23b05..756a0112710d9 100644 --- a/tests/ui/typeck/type-inference-for-associated-types-69683.rs +++ b/tests/ui/typeck/type-inference-for-associated-types-69683.rs @@ -29,6 +29,5 @@ fn main() { let b: [u8; 3] = [0u8; 3]; 0u16.foo(b); //~ ERROR type annotations needed - //~^ ERROR type annotations needed //>::foo(0u16, b); } diff --git a/tests/ui/typeck/type-inference-for-associated-types-69683.stderr b/tests/ui/typeck/type-inference-for-associated-types-69683.stderr index 5d49d442c55d0..46ddd4556e96f 100644 --- a/tests/ui/typeck/type-inference-for-associated-types-69683.stderr +++ b/tests/ui/typeck/type-inference-for-associated-types-69683.stderr @@ -5,18 +5,6 @@ LL | 0u16.foo(b); | ^^^ | = note: cannot satisfy `>::Array == [u8; 3]` -help: try using a fully qualified path to specify the expected types - | -LL - 0u16.foo(b); -LL + >::foo(0u16, b); - | - -error[E0283]: type annotations needed - --> $DIR/type-inference-for-associated-types-69683.rs:31:10 - | -LL | 0u16.foo(b); - | ^^^ - | note: multiple `impl`s satisfying `u8: Element<_>` found --> $DIR/type-inference-for-associated-types-69683.rs:6:1 | @@ -39,7 +27,6 @@ LL - 0u16.foo(b); LL + >::foo(0u16, b); | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0283, E0284. -For more information about an error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`.