Rollup merge of #108136 - eggyal:unmet_trait_alias_bound_on_generic_impl, r=compiler-errors

Do not ICE on unmet trait alias impl bounds

Fixes #108132

I've also added some documentation to the `impl_def_id` field of `DerivedObligationCause` to try and minimise the risk of such errors in future.

r? `@compiler-errors`
This commit is contained in:
Matthias Krüger 2023-02-17 00:19:37 +01:00 committed by GitHub
commit ecdb7bcee8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 59 additions and 13 deletions

View File

@ -477,14 +477,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This is the "trait" (meaning, the predicate "proved" by this `impl`) which provides the `Self` type we care about.
// For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
// that struct type.
let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_def_id) {
let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
self.tcx.mk_trait_ref(
obligation.impl_def_id,
ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_def_id),
obligation.impl_or_alias_def_id,
ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
)
} else {
self.tcx
.impl_trait_ref(obligation.impl_def_id)
.impl_trait_ref(obligation.impl_or_alias_def_id)
.map(|impl_def| impl_def.skip_binder())
// It is possible that this is absent. In this case, we make no progress.
.ok_or(expr)?
@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let impl_self_ty: Ty<'tcx> = impl_trait_self_ref.self_ty();
let impl_predicates: ty::GenericPredicates<'tcx> =
self.tcx.predicates_of(obligation.impl_def_id);
self.tcx.predicates_of(obligation.impl_or_alias_def_id);
let Some(impl_predicate_index) = obligation.impl_def_predicate_index else {
// We don't have the index, so we can only guess.
return Err(expr);

View File

@ -1576,7 +1576,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
traits::ImplDerivedObligation(Box::new(
traits::ImplDerivedObligationCause {
derived,
impl_def_id,
impl_or_alias_def_id: impl_def_id,
impl_def_predicate_index: None,
span,
},

View File

@ -616,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ObligationCauseCode::ImplDerivedObligation(data)
if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) =>
{
Some((p, parent, data.impl_def_id, data))
Some((p, parent, data.impl_or_alias_def_id, data))
}
_ => None,
})
@ -714,7 +714,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
Some(Node::Item(hir::Item {
ident, kind: hir::ItemKind::Trait(..), ..
ident,
kind: hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..),
..
})) => {
skip_list.insert(p);
let entry = spanned_predicates.entry(ident.span);

View File

@ -158,7 +158,7 @@ impl<'tcx> Elaborator<'tcx> {
traits::ImplDerivedObligation(Box::new(
traits::ImplDerivedObligationCause {
derived,
impl_def_id: data.def_id(),
impl_or_alias_def_id: data.def_id(),
impl_def_predicate_index: Some(index),
span,
},

View File

@ -474,7 +474,11 @@ pub enum WellFormedLoc {
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedObligationCause<'tcx> {
pub derived: DerivedObligationCause<'tcx>,
pub impl_def_id: DefId,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
/// that exceptional case where appropriate.
pub impl_or_alias_def_id: DefId,
/// The index of the derived predicate in the parent impl's predicates.
pub impl_def_predicate_index: Option<usize>,
pub span: Span,

View File

@ -3143,7 +3143,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
parent_trait_pred.print_modifiers_and_trait_path()
);
let mut is_auto_trait = false;
match self.tcx.hir().get_if_local(data.impl_def_id) {
match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Trait(is_auto, ..),
ident,

View File

@ -1189,7 +1189,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let cause = obligation.derived_cause(|derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_def_id,
impl_or_alias_def_id: impl_def_id,
impl_def_predicate_index: None,
span: obligation.cause.span,
}))

View File

@ -2657,7 +2657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_def_id: def_id,
impl_or_alias_def_id: def_id,
impl_def_predicate_index: Some(index),
span,
}))

View File

@ -0,0 +1,15 @@
// Regression test for #108132: do not ICE upon unmet trait alias constraint in generic impl
#![feature(trait_alias)]
trait IteratorAlias = Iterator;
struct Foo<I>(I);
impl<I: IteratorAlias> Foo<I> {
fn f() {}
}
fn main() {
Foo::<()>::f() //~ trait bounds were not satisfied
}

View File

@ -0,0 +1,25 @@
error[E0599]: the function or associated item `f` exists for struct `Foo<()>`, but its trait bounds were not satisfied
--> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:14:16
|
LL | struct Foo<I>(I);
| ------------- function or associated item `f` not found for this struct
...
LL | Foo::<()>::f()
| ^ function or associated item cannot be called on `Foo<()>` due to unsatisfied trait bounds
|
note: trait bound `(): Iterator` was not satisfied
--> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:5:23
|
LL | trait IteratorAlias = Iterator;
| ------------- ^^^^^^^^ unsatisfied trait bound introduced here
note: trait bound `(): IteratorAlias` was not satisfied
--> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:9:9
|
LL | impl<I: IteratorAlias> Foo<I> {
| ^^^^^^^^^^^^^ ------
| |
| unsatisfied trait bound introduced here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.