diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 811d8a4b94e2c..a6f78dc8ab53f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -21,7 +21,7 @@ use crate::{ TupleArgumentsFlag::DontTupleArguments, }; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, @@ -2877,7 +2877,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); self.select_obligations_where_possible(|errors| { - self.point_at_index_if_possible(errors, idx.span) + self.point_at_index(errors, idx.span); }); element_ty } @@ -3036,16 +3036,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .ok() } - fn point_at_index_if_possible( - &self, - errors: &mut Vec>, - span: Span, - ) { + fn point_at_index(&self, errors: &mut Vec>, span: Span) { + let mut seen_preds = FxHashSet::default(); + // We re-sort here so that the outer most root obligations comes first, as we have the + // subsequent weird logic to identify *every* relevant obligation for proper deduplication + // of diagnostics. + errors.sort_by_key(|error| error.root_obligation.recursion_depth); for error in errors { - match error.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) - if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { + match ( + error.root_obligation.predicate.kind().skip_binder(), + error.obligation.predicate.kind().skip_binder(), + ) { + (ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)), _) + if self.tcx.lang_items().index_trait() == Some(predicate.trait_ref.def_id) => + { + seen_preds.insert(error.obligation.predicate.kind().skip_binder()); + } + (_, ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate))) + if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => + { + seen_preds.insert(error.obligation.predicate.kind().skip_binder()); } + (root, pred) if seen_preds.contains(&pred) || seen_preds.contains(&root) => {} _ => continue, } error.obligation.cause.span = span; diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 4223e503f5e22..aca6acd783b92 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -215,7 +215,7 @@ pub enum LayoutError<'tcx> { SizeOverflow(Ty<'tcx>), NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>), ReferencesError(ErrorGuaranteed), - Cycle, + Cycle(ErrorGuaranteed), } impl<'tcx> LayoutError<'tcx> { @@ -226,7 +226,7 @@ impl<'tcx> LayoutError<'tcx> { Unknown(_) => middle_unknown_layout, SizeOverflow(_) => middle_values_too_big, NormalizationFailure(_, _) => middle_cannot_be_normalized, - Cycle => middle_cycle, + Cycle(_) => middle_cycle, ReferencesError(_) => middle_layout_references_error, } } @@ -240,7 +240,7 @@ impl<'tcx> LayoutError<'tcx> { NormalizationFailure(ty, e) => { E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() } } - Cycle => E::Cycle, + Cycle(_) => E::Cycle, ReferencesError(_) => E::ReferencesError, } } @@ -261,7 +261,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { t, e.get_type_for_failure() ), - LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"), + LayoutError::Cycle(_) => write!(f, "a cycle occurred during layout computation"), LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"), } } @@ -333,7 +333,7 @@ impl<'tcx> SizeSkeleton<'tcx> { Err(err @ LayoutError::Unknown(_)) => err, // We can't extract SizeSkeleton info from other layout errors Err( - e @ LayoutError::Cycle + e @ LayoutError::Cycle(_) | e @ LayoutError::SizeOverflow(_) | e @ LayoutError::NormalizationFailure(..) | e @ LayoutError::ReferencesError(_), diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index f30993c9a694d..2b4ae37362699 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -114,12 +114,11 @@ impl<'tcx> Value> for ty::EarlyBinder> } impl<'tcx, T> Value> for Result> { - fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self { + fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self { // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // tcx.arena.alloc is pretty much equal to leaking). - // FIXME: `Cycle` should carry the ErrorGuaranteed - Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle))) + Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar)))) } } diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html index b8b7785a2a191..c75fc34a9dfe7 100644 --- a/src/librustdoc/html/templates/type_layout.html +++ b/src/librustdoc/html/templates/type_layout.html @@ -54,7 +54,7 @@

{# #} Note: Encountered an error during type layout; {#+ #} the type failed to be normalized. {# #}

{# #} - {% when Err(LayoutError::Cycle) %} + {% when Err(LayoutError::Cycle(_)) %}

{# #} Note: Encountered an error during type layout; {#+ #} the type's layout depended on the type's layout itself. {# #} diff --git a/tests/ui/indexing/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr index 6ea6bb600e944..3041c2c99a108 100644 --- a/tests/ui/indexing/indexing-requires-a-uint.stderr +++ b/tests/ui/indexing/indexing-requires-a-uint.stderr @@ -8,6 +8,8 @@ LL | [0][0u8]; = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `u8` = note: required for `[{integer}]` to implement `Index` + = note: 1 redundant requirement hidden + = note: required for `[{integer}; 1]` to implement `Index` error[E0308]: mismatched types --> $DIR/indexing-requires-a-uint.rs:12:18 diff --git a/tests/ui/indexing/point-at-index-for-obligation-failure.rs b/tests/ui/indexing/point-at-index-for-obligation-failure.rs new file mode 100644 index 0000000000000..e9c429b53ced1 --- /dev/null +++ b/tests/ui/indexing/point-at-index-for-obligation-failure.rs @@ -0,0 +1,7 @@ +fn main() { + let a = std::collections::HashMap::::new(); + let s = "hello"; + let _b = a[ + &s //~ ERROR E0277 + ]; +} diff --git a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr new file mode 100644 index 0000000000000..3e2fbc2ab6f2e --- /dev/null +++ b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `String: Borrow<&str>` is not satisfied + --> $DIR/point-at-index-for-obligation-failure.rs:5:9 + | +LL | &s + | ^^ the trait `Borrow<&str>` is not implemented for `String` + | + = help: the trait `Borrow` is implemented for `String` + = help: for that trait implementation, expected `str`, found `&str` + = note: required for `HashMap` to implement `Index<&&str>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/suggest-dereferencing-index.stderr b/tests/ui/suggestions/suggest-dereferencing-index.stderr index adf01339972e5..23f6657f092a7 100644 --- a/tests/ui/suggestions/suggest-dereferencing-index.stderr +++ b/tests/ui/suggestions/suggest-dereferencing-index.stderr @@ -8,6 +8,8 @@ LL | let one_item_please: i32 = [1, 2, 3][i]; = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize` = help: for that trait implementation, expected `usize`, found `&usize` = note: required for `[{integer}]` to implement `Index<&usize>` + = note: 1 redundant requirement hidden + = note: required for `[{integer}; 3]` to implement `Index<&usize>` help: dereference this index | LL | let one_item_please: i32 = [1, 2, 3][*i];