Skip to content

Resolve anon const's parent predicates to direct parent instead of opaque's parent #125501

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

Merged
merged 1 commit into from
May 24, 2024
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
122 changes: 47 additions & 75 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,83 +461,55 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let parent_def_id = tcx.hir().get_parent_item(hir_id);

if let Some(defaulted_param_def_id) =
tcx.hir().opt_const_param_default_param_def_id(hir_id)
{
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
//
// struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
// ^^^ explicit_predicates_of on
// parent item we dont have set as the
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
// and we would be calling `explicit_predicates_of(Foo)` here
let parent_preds = tcx.explicit_predicates_of(parent_def_id);

// If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
// will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
// to #106994 is implemented.
let filtered_predicates = parent_preds
.predicates
.into_iter()
.filter(|(pred, _)| {
if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
match ct.kind() {
ty::ConstKind::Param(param_const) => {
let defaulted_param_idx = tcx
.generics_of(parent_def_id)
.param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
param_const.index < defaulted_param_idx
}
_ => bug!(
"`ConstArgHasType` in `predicates_of`\
that isn't a `Param` const"
),
if matches!(def_kind, DefKind::AnonConst)
&& tcx.features().generic_const_exprs
&& let Some(defaulted_param_def_id) =
tcx.hir().opt_const_param_default_param_def_id(tcx.local_def_id_to_hir_id(def_id))
{
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
//
// struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
// ^^^ explicit_predicates_of on
// parent item we dont have set as the
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
// and we would be calling `explicit_predicates_of(Foo)` here
let parent_def_id = tcx.local_parent(def_id);
let parent_preds = tcx.explicit_predicates_of(parent_def_id);

// If we dont filter out `ConstArgHasType` predicates then every single defaulted const parameter
// will ICE because of #106994. FIXME(generic_const_exprs): remove this when a more general solution
// to #106994 is implemented.
let filtered_predicates = parent_preds
.predicates
.into_iter()
.filter(|(pred, _)| {
if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
match ct.kind() {
ty::ConstKind::Param(param_const) => {
let defaulted_param_idx = tcx
.generics_of(parent_def_id)
.param_def_id_to_index[&defaulted_param_def_id.to_def_id()];
param_const.index < defaulted_param_idx
}
} else {
true
_ => bug!(
"`ConstArgHasType` in `predicates_of`\
that isn't a `Param` const"
),
}
})
.cloned();
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
};
}

let parent_def_kind = tcx.def_kind(parent_def_id);
if matches!(parent_def_kind, DefKind::OpaqueTy) {
// In `instantiate_identity` we inherit the predicates of our parent.
// However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
// that we lose out on the predicates of our actual parent if we dont return those predicates here.
//
//
// fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
// ^^^^^^^^^^^^^^^^^^^ the def id we are calling
// explicit_predicates_of on
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`.
// However, the anon const cannot inherit predicates from its parent since it's opaque.
//
// To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.

// In the above example this is `foo::{opaque#0}` or `impl Iterator`
let parent_hir_id = tcx.local_def_id_to_hir_id(parent_def_id.def_id);

// In the above example this is the function `foo`
let item_def_id = tcx.hir().get_parent_item(parent_hir_id);

// In the above code example we would be calling `explicit_predicates_of(foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
} else {
true
}
})
.cloned();
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
};
}
gather_explicit_predicates_of(tcx, def_id)
}
Expand Down
8 changes: 0 additions & 8 deletions tests/crashes/118403.rs

This file was deleted.

8 changes: 0 additions & 8 deletions tests/crashes/121574-2.rs

This file was deleted.

6 changes: 0 additions & 6 deletions tests/crashes/121574.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ check-pass

#![feature(generic_const_exprs)]
//~^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use

pub fn y<'a, U: 'a>() -> impl IntoIterator<Item = impl IntoIterator<Item = [u8; { 1 + 2 }]> + 'a> {
[[[1, 2, 3]]]
}
// Make sure that the `predicates_of` for `{ 1 + 2 }` don't mention the duplicated lifetimes of
// the *outer* iterator. Whether they should mention the duplicated lifetimes of the *inner*
// iterator are another question, but not really something we need to answer immediately.

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/double-opaque-parent-predicates.rs:3:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default

warning: 1 warning emitted

Loading