From b369c8ecbde710ab23977137c71b3c974a94d445 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 10 Apr 2023 06:06:01 +0000 Subject: [PATCH] Do not use ImplDerivedObligationCause for inherent impl method error reporting --- compiler/rustc_hir_typeck/src/method/probe.rs | 29 +++++------ .../rustc_hir_typeck/src/method/suggest.rs | 43 +++++++++------- tests/ui/methods/inherent-bound-in-probe.rs | 49 +++++++++++++++++++ .../ui/methods/inherent-bound-in-probe.stderr | 38 ++++++++++++++ 4 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 tests/ui/methods/inherent-bound-in-probe.rs create mode 100644 tests/ui/methods/inherent-bound-in-probe.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 0092bd2c6e641..badb1a3c1882d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1522,23 +1522,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Convert the bounds into obligations. let impl_obligations = traits::predicates_for_generics( - |_idx, span| { - let misc = traits::ObligationCause::misc(span, self.body_id); - let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate { - trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs), - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }); - misc.derived_cause(parent_trait_pred, |derived| { - traits::ImplDerivedObligation(Box::new( - traits::ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: impl_def_id, - impl_def_predicate_index: None, - span, - }, - )) - }) + |idx, span| { + let code = if span.is_dummy() { + traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) + } else { + traits::ExprBindingObligation( + impl_def_id, + span, + self.scope_expr_id, + idx, + ) + }; + ObligationCause::new(self.span, self.body_id, code) }, self.param_env, impl_bounds, diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 5c50619f4c3c4..6e77c7281074f 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -661,19 +661,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find all the requirements that come from a local `impl` block. let mut skip_list: FxHashSet<_> = Default::default(); let mut spanned_predicates = FxHashMap::default(); - for (p, parent_p, impl_def_id, cause) in unsatisfied_predicates - .iter() - .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c))) - .filter_map(|(p, parent, c)| match c.code() { - ObligationCauseCode::ImplDerivedObligation(data) - if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) => - { - Some((p, parent, data.impl_or_alias_def_id, data)) + for (p, parent_p, cause) in unsatisfied_predicates { + // Extract the predicate span and parent def id of the cause, + // if we have one. + let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) { + Some(ObligationCauseCode::ImplDerivedObligation(data)) => { + (data.impl_or_alias_def_id, data.span) } - _ => None, - }) - { - match self.tcx.hir().get_if_local(impl_def_id) { + Some( + ObligationCauseCode::ExprBindingObligation(def_id, span, _, _) + | ObligationCauseCode::BindingObligation(def_id, span), + ) => (*def_id, *span), + _ => continue, + }; + + // Don't point out the span of `WellFormed` predicates. + if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) { + continue; + }; + + match self.tcx.hir().get_if_local(item_def_id) { // Unmet obligation comes from a `derive` macro, point at it once to // avoid multiple span labels pointing at the same place. Some(Node::Item(hir::Item { @@ -718,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); for param in generics.params { - if param.span == cause.span && sized_pred { + if param.span == cause_span && sized_pred { let (sp, sugg) = match param.colon_span { Some(sp) => (sp.shrink_to_hi(), " ?Sized +"), None => (param.span.shrink_to_hi(), ": ?Sized"), @@ -741,9 +748,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (FxHashSet::default(), FxHashSet::default(), Vec::new()) }); entry.2.push(p); - if cause.span != *item_span { - entry.0.insert(cause.span); - entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + if cause_span != *item_span { + entry.0.insert(cause_span); + entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); } else { if let Some(trait_ref) = of_trait { entry.0.insert(trait_ref.path.span); @@ -775,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let entry = entry.or_insert_with(|| { (FxHashSet::default(), FxHashSet::default(), Vec::new()) }); - entry.0.insert(cause.span); + entry.0.insert(cause_span); entry.1.insert((ident.span, "")); - entry.1.insert((cause.span, "unsatisfied trait bound introduced here")); + entry.1.insert((cause_span, "unsatisfied trait bound introduced here")); entry.2.push(p); } Some(node) => unreachable!("encountered `{node:?}`"), diff --git a/tests/ui/methods/inherent-bound-in-probe.rs b/tests/ui/methods/inherent-bound-in-probe.rs new file mode 100644 index 0000000000000..81a99ca010e5d --- /dev/null +++ b/tests/ui/methods/inherent-bound-in-probe.rs @@ -0,0 +1,49 @@ +// normalize-stderr-test: "long-type-\d+" -> "long-type-hash" + +// Fixes #110131 +// +// The issue is that we were constructing an `ImplDerived` cause code for the +// `&'a T: IntoIterator` obligation for `Helper::new`, which is +// incorrect because derived obligations are only expected to come from *traits*. + +struct SeqBuffer<'a, T> +where + &'a T: IntoIterator, +{ + iter: <&'a T as IntoIterator>::IntoIter, +} + +struct Helper<'a, T> +where + &'a T: IntoIterator, +{ + buf: SeqBuffer<'a, T>, +} + +impl<'a, T> Helper<'a, T> +where + &'a T: IntoIterator, +{ + fn new(sq: &'a T) -> Self { + loop {} + } +} + +struct BitReaderWrapper(T); + +impl<'a, T> IntoIterator for &'a BitReaderWrapper +where + &'a T: IntoIterator, +{ + type Item = u32; + + type IntoIter = Helper<'a, T>; + //~^ ERROR `Helper<'a, T>` is not an iterator + + fn into_iter(self) -> Self::IntoIter { + Helper::new(&self.0) + //~^ ERROR overflow evaluating the requirement `&_: IntoIterator` + } +} + +fn main() {} diff --git a/tests/ui/methods/inherent-bound-in-probe.stderr b/tests/ui/methods/inherent-bound-in-probe.stderr new file mode 100644 index 0000000000000..ff03a7edb0542 --- /dev/null +++ b/tests/ui/methods/inherent-bound-in-probe.stderr @@ -0,0 +1,38 @@ +error[E0277]: `Helper<'a, T>` is not an iterator + --> $DIR/inherent-bound-in-probe.rs:40:21 + | +LL | type IntoIter = Helper<'a, T>; + | ^^^^^^^^^^^^^ `Helper<'a, T>` is not an iterator + | + = help: the trait `Iterator` is not implemented for `Helper<'a, T>` +note: required by a bound in `std::iter::IntoIterator::IntoIter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + +error[E0275]: overflow evaluating the requirement `&_: IntoIterator` + --> $DIR/inherent-bound-in-probe.rs:44:17 + | +LL | Helper::new(&self.0) + | ^^^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_bound_in_probe`) +note: required for `&BitReaderWrapper<_>` to implement `IntoIterator` + --> $DIR/inherent-bound-in-probe.rs:34:13 + | +LL | impl<'a, T> IntoIterator for &'a BitReaderWrapper + | ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ +LL | where +LL | &'a T: IntoIterator, + | ------------- unsatisfied trait bound introduced here + = note: 126 redundant requirements hidden + = note: required for `&BitReaderWrapper>>>>` to implement `IntoIterator` + = note: the full type name has been written to '$TEST_BUILD_DIR/methods/inherent-bound-in-probe/inherent-bound-in-probe.long-type-hash.txt' +note: required by a bound in `Helper<'a, T>` + --> $DIR/inherent-bound-in-probe.rs:25:25 + | +LL | &'a T: IntoIterator, + | ^^^^^^^^^^^^^ required by this bound in `Helper<'a, T>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`.