Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
18c248b
Make `NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE` deny-by-default in e2024
WaffleLapkin Jun 23, 2024
c147805
library: outline VaList into ffi::va_list
workingjubilee Jun 24, 2024
c1a29b3
core: erase redundant stability attrs in va_list
workingjubilee Jun 24, 2024
7566f41
Run alloc sync tests
ChrisDenton Jul 5, 2024
8c2ea71
Use field ident spans directly instead of the full field span in diag…
oli-obk Jul 6, 2024
c990e00
Add support for literals
c410-f3r Jul 6, 2024
58aad3c
iter_identity is a better name
compiler-errors Jul 6, 2024
39bb14e
Improve `run-make/output-type-permutations` code and improve `filenam…
GuillaumeGomez Jul 7, 2024
4f54193
Fix intrinsic const parameter counting with `effects`
fee1-dead Jul 7, 2024
8e7314f
rustdoc-json: add trait/type alias tests
its-the-shrimp Jul 7, 2024
b2e30bd
Add fundamental to trait def
compiler-errors Jul 6, 2024
a982471
Uplift trait_ref_is_knowable and friends
compiler-errors Jul 6, 2024
ab27c2f
Get rid of trait_ref_is_knowable from delegate
compiler-errors Jul 6, 2024
90423a7
Uplift elaboration
compiler-errors Jul 6, 2024
66eb346
Get rid of the redundant elaboration in middle
compiler-errors Jul 6, 2024
15d16f1
Finish uplifting supertraits
compiler-errors Jul 6, 2024
2c16d65
Rollup merge of #126841 - c410-f3r:concat-again, r=petrochenkov
jieyouxu Jul 8, 2024
29c1a43
Rollup merge of #126881 - WaffleLapkin:unsafe-code-affected-by-fallba…
jieyouxu Jul 8, 2024
adbcb1a
Rollup merge of #126921 - workingjubilee:outline-va-list, r=Nilstrieb
jieyouxu Jul 8, 2024
e76b017
Rollup merge of #127367 - ChrisDenton:run-sync, r=Nilstrieb
jieyouxu Jul 8, 2024
bd4ab30
Rollup merge of #127431 - oli-obk:feed_item_attrs, r=compiler-errors
jieyouxu Jul 8, 2024
928d71f
Rollup merge of #127437 - compiler-errors:uplift-trait-ref-is-knowabl…
jieyouxu Jul 8, 2024
ffb9336
Rollup merge of #127439 - compiler-errors:uplift-elaborate, r=lcnr
jieyouxu Jul 8, 2024
0332834
Rollup merge of #127451 - GuillaumeGomez:improve-output-type-permutat…
jieyouxu Jul 8, 2024
73593b9
Rollup merge of #127452 - fee1-dead-contrib:fx-intrinsic-counting, r=…
jieyouxu Jul 8, 2024
76be8f1
Rollup merge of #127459 - its-the-shrimp:rustdocjson_add_alias_tests,…
jieyouxu Jul 8, 2024
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
Prev Previous commit
Next Next commit
Uplift elaboration
  • Loading branch information
compiler-errors committed Jul 7, 2024
commit 90423a7abbddd98b6fbb22e9780991c736b51ca4
349 changes: 4 additions & 345 deletions compiler/rustc_infer/src/traits/util.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use smallvec::smallvec;

use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::ToPolyTraitRef;
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::Span;
use rustc_type_ir::outlives::{push_outlives_components, Component};
pub use rustc_type_ir::elaborate::*;

pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down Expand Up @@ -64,50 +62,9 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
}
}

///////////////////////////////////////////////////////////////////////////
// `Elaboration` iterator
///////////////////////////////////////////////////////////////////////////

/// "Elaboration" is the process of identifying all the predicates that
/// are implied by a source predicate. Currently, this basically means
/// walking the "supertraits" and other similar assumptions. For example,
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
/// `T: Foo`, then we know that `T: 'static`.
pub struct Elaborator<'tcx, O> {
stack: Vec<O>,
visited: PredicateSet<'tcx>,
mode: Filter,
}

enum Filter {
All,
OnlySelf,
}

/// Describes how to elaborate an obligation into a sub-obligation.
///
/// For [`Obligation`], a sub-obligation is combined with the current obligation's
/// param-env and cause code. For [`ty::Predicate`], none of this is needed, since
/// there is no param-env or cause code to copy over.
pub trait Elaboratable<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx>;

// Makes a new `Self` but with a different clause that comes from elaboration.
fn child(&self, clause: ty::Clause<'tcx>) -> Self;

// Makes a new `Self` but with a different clause and a different cause
// code (if `Self` has one, such as [`PredicateObligation`]).
fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
span: Span,
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
index: usize,
) -> Self;
}

impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
/// param-env and cause code.
impl<'tcx> Elaboratable<TyCtxt<'tcx>> for PredicateObligation<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx> {
self.predicate
}
Expand Down Expand Up @@ -145,270 +102,6 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
}
}

impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx> {
*self
}

fn child(&self, clause: ty::Clause<'tcx>) -> Self {
clause.as_predicate()
}

fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
clause.as_predicate()
}
}

impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
fn predicate(&self) -> ty::Predicate<'tcx> {
self.0
}

fn child(&self, clause: ty::Clause<'tcx>) -> Self {
(clause.as_predicate(), self.1)
}

fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
(clause.as_predicate(), self.1)
}
}

impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) {
fn predicate(&self) -> ty::Predicate<'tcx> {
self.0.as_predicate()
}

fn child(&self, clause: ty::Clause<'tcx>) -> Self {
(clause, self.1)
}

fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
(clause, self.1)
}
}

impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx> {
self.as_predicate()
}

fn child(&self, clause: ty::Clause<'tcx>) -> Self {
clause
}

fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
clause
}
}

pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
tcx: TyCtxt<'tcx>,
obligations: impl IntoIterator<Item = O>,
) -> Elaborator<'tcx, O> {
let mut elaborator =
Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), mode: Filter::All };
elaborator.extend_deduped(obligations);
elaborator
}

impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
// Only keep those bounds that we haven't already seen.
// This is necessary to prevent infinite recursion in some
// cases. One common case is when people define
// `trait Sized: Sized { }` rather than `trait Sized { }`.
// let visited = &mut self.visited;
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
}

/// Filter to only the supertraits of trait predicates, i.e. only the predicates
/// that have `Self` as their self type, instead of all implied predicates.
pub fn filter_only_self(mut self) -> Self {
self.mode = Filter::OnlySelf;
self
}

fn elaborate(&mut self, elaboratable: &O) {
let tcx = self.visited.tcx;

// We only elaborate clauses.
let Some(clause) = elaboratable.predicate().as_clause() else {
return;
};

let bound_clause = clause.kind();
match bound_clause.skip_binder() {
ty::ClauseKind::Trait(data) => {
// Negative trait bounds do not imply any supertrait bounds
if data.polarity != ty::PredicatePolarity::Positive {
return;
}
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
let predicates = match self.mode {
Filter::All => tcx.explicit_implied_predicates_of(data.def_id()),
Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()),
};

let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| {
elaboratable.child_with_derived_cause(
clause.instantiate_supertrait(tcx, bound_clause.rebind(data.trait_ref)),
span,
bound_clause.rebind(data),
index,
)
});
debug!(?data, ?obligations, "super_predicates");
self.extend_deduped(obligations);
}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
// We know that `T: 'a` for some type `T`. We can
// often elaborate this. For example, if we know that
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
// we know `&'a U: 'b`, then we know that `'a: 'b` and
// `U: 'b`.
//
// We can basically ignore bound regions here. So for
// example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
// `'a: 'b`.

// Ignore `for<'a> T: 'a` -- we might in the future
// consider this as evidence that `T: 'static`, but
// I'm a bit wary of such constructions and so for now
// I want to be conservative. --nmatsakis
if r_min.is_bound() {
return;
}

let mut components = smallvec![];
push_outlives_components(tcx, ty_max, &mut components);
self.extend_deduped(
components
.into_iter()
.filter_map(|component| match component {
Component::Region(r) => {
if r.is_bound() {
None
} else {
Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
r, r_min,
)))
}
}

Component::Param(p) => {
let ty = Ty::new_param(tcx, p.index, p.name);
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
}

Component::Placeholder(p) => {
let ty = Ty::new_placeholder(tcx, p);
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
}

Component::UnresolvedInferenceVariable(_) => None,

Component::Alias(alias_ty) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
alias_ty.to_ty(tcx),
r_min,
)))
}

Component::EscapingAlias(_) => {
// We might be able to do more here, but we don't
// want to deal with escaping vars right now.
None
}
})
.map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
);
}
ty::ClauseKind::RegionOutlives(..) => {
// Nothing to elaborate from `'a: 'b`.
}
ty::ClauseKind::WellFormed(..) => {
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
ty::ClauseKind::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
ty::ClauseKind::ConstEvaluatable(..) => {
// Currently, we do not elaborate const-evaluatable
// predicates.
}
ty::ClauseKind::ConstArgHasType(..) => {
// Nothing to elaborate
}
}
}
}

impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> {
type Item = O;

fn size_hint(&self) -> (usize, Option<usize>) {
(self.stack.len(), None)
}

fn next(&mut self) -> Option<Self::Item> {
// Extract next item from top-most stack frame, if any.
if let Some(obligation) = self.stack.pop() {
self.elaborate(&obligation);
Some(obligation)
} else {
None
}
}
}

///////////////////////////////////////////////////////////////////////////
// Supertrait iterator
///////////////////////////////////////////////////////////////////////////

pub fn supertraits<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
}

pub fn transitive_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> {
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
.filter_only_self()
.filter_to_traits()
}

/// A specialized variant of `elaborate` that only elaborates trait references that may
/// define the given associated item with the name `assoc_name`. It uses the
/// `explicit_supertraits_containing_assoc_item` query to avoid enumerating super-predicates that
Expand Down Expand Up @@ -443,37 +136,3 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
None
})
}

///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////

impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> {
fn filter_to_traits(self) -> FilterToTraits<Self> {
FilterToTraits { base_iterator: self }
}
}

/// A filter around an iterator of predicates that makes it yield up
/// just trait references.
pub struct FilterToTraits<I> {
base_iterator: I,
}

impl<'tcx, I: Iterator<Item = ty::Clause<'tcx>>> Iterator for FilterToTraits<I> {
type Item = ty::PolyTraitRef<'tcx>;

fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
while let Some(pred) = self.base_iterator.next() {
if let Some(data) = pred.as_trait_clause() {
return Some(data.map_bound(|t| t.trait_ref));
}
}
None
}

fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.base_iterator.size_hint();
(0, upper)
}
}
Loading