Skip to content

Commit

Permalink
Auto merge of rust-lang#129532 - compiler-errors:remove-predicate-que…
Browse files Browse the repository at this point in the history
…ries, r=<try>

Remove predicate queries

Removes:
* `predicates_defined_on` - Not necessary. Literally unused.
* `trait_explicit_predicates_and_bounds` - Not necessary technically. The side-effect of this is that we now don't remove `where Self::Assoc: Bound` item bounds from the where clauses of traits. This may require more trait solving to be done, but should be fine. Let's see what the fallout of this is.

r? `@ghost`
  • Loading branch information
bors committed Aug 24, 2024
2 parents f167efa + 8ca62f0 commit 8104373
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 201 deletions.
32 changes: 1 addition & 31 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
use rustc_middle::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
Expand Down Expand Up @@ -70,13 +70,11 @@ pub fn provide(providers: &mut Providers) {
impl_super_outlives: item_bounds::impl_super_outlives,
generics_of: generics_of::generics_of,
predicates_of: predicates_of::predicates_of,
predicates_defined_on,
explicit_predicates_of: predicates_of::explicit_predicates_of,
explicit_super_predicates_of: predicates_of::explicit_super_predicates_of,
explicit_implied_predicates_of: predicates_of::explicit_implied_predicates_of,
explicit_supertraits_containing_assoc_item:
predicates_of::explicit_supertraits_containing_assoc_item,
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
adt_def,
Expand Down Expand Up @@ -1775,34 +1773,6 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>(
})
}

/// Returns a list of type predicates for the definition with ID `def_id`, including inferred
/// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus
/// inferred constraints concerning which regions outlive other regions.
#[instrument(level = "debug", skip(tcx))]
fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
let mut result = tcx.explicit_predicates_of(def_id);
debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result);
let inferred_outlives = tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() {
debug!(
"predicates_defined_on: inferred_outlives_of({:?}) = {:?}",
def_id, inferred_outlives,
);
let inferred_outlives_iter =
inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span));
if result.predicates.is_empty() {
result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
} else {
result.predicates = tcx.arena.alloc_from_iter(
result.predicates.into_iter().copied().chain(inferred_outlives_iter),
);
}
}

debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
result
}

fn compute_sig_of_foreign_fn_decl<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn associated_type_bounds<'tcx>(
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);

let trait_def_id = tcx.local_parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
let trait_predicates = tcx.predicates_of(trait_def_id);

let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
match pred.kind().skip_binder() {
Expand Down
180 changes: 69 additions & 111 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,26 @@ use crate::delegation::inherit_predicates_for_delegation_item;
use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason};

/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
/// `Self: Trait` predicates for traits.
/// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
/// inferred constraints concerning which regions outlive other regions.
#[instrument(level = "debug", skip(tcx))]
pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
let mut result = tcx.predicates_defined_on(def_id);
let mut result = tcx.explicit_predicates_of(def_id);
debug!("predicates_of: explicit_predicates_of({:?}) = {:?}", def_id, result);

let inferred_outlives = tcx.inferred_outlives_of(def_id);
if !inferred_outlives.is_empty() {
debug!("predicates_of: inferred_outlives_of({:?}) = {:?}", def_id, inferred_outlives,);
let inferred_outlives_iter =
inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span));
if result.predicates.is_empty() {
result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
} else {
result.predicates = tcx.arena.alloc_from_iter(
result.predicates.into_iter().copied().chain(inferred_outlives_iter),
);
}
}

if tcx.is_trait(def_id) {
// For traits, add `Self: Trait` predicate. This is
Expand Down Expand Up @@ -51,7 +67,8 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
.chain(std::iter::once((ty::TraitRef::identity(tcx, def_id).upcast(tcx), span))),
);
}
debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);

debug!("predicates_of({:?}) = {:?}", def_id, result);
result
}

Expand Down Expand Up @@ -442,122 +459,63 @@ fn const_evaluatable_predicates_of(
collector.preds
}

pub(super) fn trait_explicit_predicates_and_bounds(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> ty::GenericPredicates<'_> {
assert_eq!(tcx.def_kind(def_id), DefKind::Trait);
gather_explicit_predicates_of(tcx, def_id)
}

pub(super) fn explicit_predicates_of<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> ty::GenericPredicates<'tcx> {
let def_kind = tcx.def_kind(def_id);
if let DefKind::Trait = def_kind {
// Remove bounds on associated types from the predicates, they will be
// returned by `explicit_item_bounds`.
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id);
let trait_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);

let is_assoc_item_ty = |ty: Ty<'tcx>| {
// For a predicate from a where clause to become a bound on an
// associated type:
// * It must use the identity args of the item.
// * We're in the scope of the trait, so we can't name any
// parameters of the GAT. That means that all we need to
// check are that the args of the projection are the
// identity args of the trait.
// * It must be an associated type for this trait (*not* a
// supertrait).
if let ty::Alias(ty::Projection, projection) = ty.kind() {
projection.args == trait_identity_args
// FIXME(return_type_notation): This check should be more robust
&& !tcx.is_impl_trait_in_trait(projection.def_id)
&& tcx.associated_item(projection.def_id).container_id(tcx)
== def_id.to_def_id()
} else {
false
}
};

let predicates: Vec<_> = predicates_and_bounds
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
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
ty::ClauseKind::Projection(proj) => {
!is_assoc_item_ty(proj.projection_term.self_ty())
}
ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
_ => true,
})
.collect();
if predicates.len() == predicates_and_bounds.predicates.len() {
predicates_and_bounds
} else {
ty::GenericPredicates {
parent: predicates_and_bounds.parent,
predicates: tcx.arena.alloc_slice(&predicates),
effects_min_tys: predicates_and_bounds.effects_min_tys,
}
}
} else {
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
}
_ => bug!(
"`ConstArgHasType` in `predicates_of`\
that isn't a `Param` const"
),
.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) },
effects_min_tys: parent_preds.effects_min_tys,
};
}
gather_explicit_predicates_of(tcx, def_id)
} else {
true
}
})
.cloned();
return GenericPredicates {
parent: parent_preds.parent,
predicates: { tcx.arena.alloc_from_iter(filtered_predicates) },
effects_min_tys: parent_preds.effects_min_tys,
};
}
gather_explicit_predicates_of(tcx, def_id)
}

/// Ensures that the super-predicates of the trait with a `DefId`
Expand Down
37 changes: 0 additions & 37 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,17 +312,6 @@ rustc_queries! {
/// predicates (where-clauses) that must be proven true in order
/// to reference it. This is almost always the "predicates query"
/// that you want.
///
/// `predicates_of` builds on `predicates_defined_on` -- in fact,
/// it is almost always the same as that query, except for the
/// case of traits. For traits, `predicates_of` contains
/// an additional `Self: Trait<...>` predicate that users don't
/// actually write. This reflects the fact that to invoke the
/// trait (e.g., via `Default::default`) you must supply types
/// that actually implement the trait. (However, this extra
/// predicate gets in the way of some checks, which are intended
/// to operate over only the actual where-clauses written by the
/// user.)
query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
Expand Down Expand Up @@ -617,32 +606,6 @@ rustc_queries! {
desc { "getting wasm import module map" }
}

/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// predicates (where-clauses) directly defined on it. This is
/// equal to the `explicit_predicates_of` predicates plus the
/// `inferred_outlives_of` predicates.
query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
}

/// Returns everything that looks like a predicate written explicitly
/// by the user on a trait item.
///
/// Traits are unusual, because predicates on associated types are
/// converted into bounds on that type for backwards compatibility:
///
/// trait X where Self::U: Copy { type U; }
///
/// becomes
///
/// trait X { type U: Copy; }
///
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
/// the appropriate subsets of the predicates here.
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key) }
}

/// Returns the predicates written explicitly by the user.
///
/// You should probably use `predicates_of` unless you're looking for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ error[E0391]: cycle detected when computing predicates of `Foo`
LL | struct Foo {
| ^^^^^^^^^^
|
note: ...which requires computing predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
note: ...which requires computing inferred outlives predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ error[E0391]: cycle detected when computing predicates of `user`
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires computing predicates of `user`...
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
LL | fn user<T>() where S<T>::P: std::fmt::Debug {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires computing explicit predicates of `user`...
--> $DIR/cycle-iat-inside-of-where-predicate.rs:8:1
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ trait Foo {
}

impl Foo for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
type Assoc = bool;
//~^ ERROR the trait bound `bool: Bar` is not satisfied
}

trait Baz
Expand All @@ -16,7 +17,9 @@ where
}

impl Baz for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
type Assoc = bool;
//~^ ERROR the trait bound `bool: Bar` is not satisfied
//~| ERROR the trait bound `bool: Bar` is not satisfied
}

trait Bat
Expand All @@ -27,7 +30,9 @@ where
}

impl Bat for () {
type Assoc = bool; //~ ERROR the trait bound `bool: Bar` is not satisfied
type Assoc = bool;
//~^ ERROR the trait bound `bool: Bar` is not satisfied
//~| ERROR the trait bound `bool: Bar` is not satisfied
}

fn main() {}
Loading

0 comments on commit 8104373

Please sign in to comment.