Skip to content

Commit

Permalink
Rollup merge of rust-lang#110133 - compiler-errors:issue-110131, r=pe…
Browse files Browse the repository at this point in the history
…trochenkov

Do not use ImplDerivedObligationCause for inherent impl method error reporting

We were constructing a `TraitRef` out of impl substs, for an *inherent* impl that has no corresponding trait. Instead of doing that, let's construct a meaningful obligation cause code, and instead adjust the error reporting machinery to handle that correctly.

Fixes rust-lang#110131
cc rust-lang#106702, which introduced this regression
  • Loading branch information
compiler-errors authored Apr 11, 2023
2 parents b912d4c + b369c8e commit 48ddb5d
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 35 deletions.
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 @@ -1531,23 +1531,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`.

0 comments on commit 48ddb5d

Please sign in to comment.