Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not use ImplDerivedObligationCause for inherent impl method error reporting #110133

Merged
merged 1 commit into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
43 changes: 25 additions & 18 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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"),
Expand All @@ -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);
Expand Down Expand Up @@ -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:?}`"),
Expand Down
49 changes: 49 additions & 0 deletions tests/ui/methods/inherent-bound-in-probe.rs
Original file line number Diff line number Diff line change
@@ -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<Item = &'a u8>` 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<Item = &'a u8>,
{
iter: <&'a T as IntoIterator>::IntoIter,
}

struct Helper<'a, T>
where
&'a T: IntoIterator<Item = &'a u8>,
{
buf: SeqBuffer<'a, T>,
}

impl<'a, T> Helper<'a, T>
where
&'a T: IntoIterator<Item = &'a u8>,
{
fn new(sq: &'a T) -> Self {
loop {}
}
}

struct BitReaderWrapper<T>(T);

impl<'a, T> IntoIterator for &'a BitReaderWrapper<T>
where
&'a T: IntoIterator<Item = &'a u8>,
{
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() {}
38 changes: 38 additions & 0 deletions tests/ui/methods/inherent-bound-in-probe.stderr
Original file line number Diff line number Diff line change
@@ -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<T>
| ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
LL | where
LL | &'a T: IntoIterator<Item = &'a u8>,
| ------------- unsatisfied trait bound introduced here
= note: 126 redundant requirements hidden
= note: required for `&BitReaderWrapper<BitReaderWrapper<BitReaderWrapper<BitReaderWrapper<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<Item = &'a u8>,
| ^^^^^^^^^^^^^ 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`.