Skip to content

Commit

Permalink
Use elaboration to turn ~const bounds into non-const bounds
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Oct 18, 2023
1 parent 61c1894 commit 3dd95d2
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 107 deletions.
90 changes: 48 additions & 42 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,15 +1084,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let mut matching_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
});
let mut const_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
});
let mut matching_candidates = all_candidates()
.filter(|r| {
self.trait_defines_associated_item_named(
r.def_id(),
ty::AssocKind::Type,
assoc_name,
)
})
// For the purposes of an associated type, we only care
// about supertraits where the host effect is set to true.
.filter(|trait_ref| {
let tcx = self.tcx();
let generics = tcx.generics_of(trait_ref.def_id());
generics.host_effect_index.map_or(true, |idx| {
trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_
})
});
let mut const_candidates = all_candidates()
.filter(|r| {
self.trait_defines_associated_item_named(
r.def_id(),
ty::AssocKind::Const,
assoc_name,
)
})
// For the purposes of an associated const, we only care
// about supertraits where the host effect is set to true.
.filter(|trait_ref| {
let tcx = self.tcx();
let generics = tcx.generics_of(trait_ref.def_id());
generics.host_effect_index.map_or(true, |idx| {
trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_
})
});

let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
{
let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
(Some(bound), _) => (bound, matching_candidates.next()),
(None, Some(bound)) => (bound, const_candidates.next()),
(None, None) => {
Expand All @@ -1108,37 +1135,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
debug!(?bound);

// look for a candidate that is not the same as our first bound, disregarding
// whether the bound is const.
while let Some(mut bound2) = next_cand {
debug!(?bound2);
let tcx = self.tcx();
if bound2.bound_vars() != bound.bound_vars() {
break;
}

let generics = tcx.generics_of(bound.def_id());
let Some(host_index) = generics.host_effect_index else { break };

// always return the bound that contains the host param.
if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() {
(bound, bound2) = (bound2, bound);
}

let unconsted_args = bound
.skip_binder()
.args
.iter()
.enumerate()
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });

if unconsted_args.eq(bound2.skip_binder().args.iter()) {
next_cand = matching_candidates.next().or_else(|| const_candidates.next());
} else {
break;
}
}

if let Some(bound2) = next_cand {
debug!(?bound2);

Expand Down Expand Up @@ -1226,9 +1222,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
assoc_name: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
let mut matching_candidates = all_candidates.filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
});
let mut matching_candidates = all_candidates
.filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
})
// For the purposes of an RTN bound, we only care
// about supertraits where the host effect is set to true.
.filter(|trait_ref| {
let tcx = self.tcx();
let generics = tcx.generics_of(trait_ref.def_id());
generics.host_effect_index.map_or(true, |idx| {
trait_ref.skip_binder().args.const_at(idx) == tcx.consts.true_
})
});

let candidate = match matching_candidates.next() {
Some(candidate) => candidate,
Expand Down
27 changes: 0 additions & 27 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,6 @@ impl<'tcx> Bounds<'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::ImplPolarity,
) {
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);

// if we have a host param, we push an unconst trait bound in addition
// to the const one.
// FIXME(effects) we should find a better way than name matching
if tcx.features().effects && trait_ref.skip_binder().args.host_effect_param().is_some() {
let generics = tcx.generics_of(trait_ref.def_id());
let Some(host_index) = generics.host_effect_index else { return };
let trait_ref = trait_ref.map_bound(|mut trait_ref| {
trait_ref.args =
tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| {
if host_index == n { tcx.consts.true_.into() } else { arg }
}));
trait_ref
});

self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
}
}

fn push_trait_bound_inner(
&mut self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
polarity: ty::ImplPolarity,
) {
self.clauses.push((
trait_ref
Expand Down
37 changes: 5 additions & 32 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_span::{Span, DUMMY_SP};

/// 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
Expand All @@ -38,38 +38,11 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
// an obligation and instead be skipped. Otherwise we'd use
// `tcx.def_span(def_id);`
let span = rustc_span::DUMMY_SP;
let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) {
// when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound,
// because only implementing `Self: Trait<.., false>` is currently not possible.
Some((
ty::TraitRef::new(
tcx,
def_id,
ty::GenericArgs::for_item(tcx, def_id, |param, _| {
if param.is_host_effect() {
tcx.consts.true_.into()
} else {
tcx.mk_param_from_def(param)
}
}),
)
.to_predicate(tcx),
result.predicates =
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
span,
))
} else {
None
};
result.predicates = tcx.arena.alloc_from_iter(
result
.predicates
.iter()
.copied()
.chain(std::iter::once((
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
span,
)))
.chain(non_const_bound),
);
))));
}
debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
result
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
ty::GenericPredicates {
parent: None,
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))
}
_ => None,
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_infer/src/traits/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,22 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
});
debug!(?data, ?obligations, "super_predicates");
self.extend_deduped(obligations);

// Also elaborate `~const Trait` into `Trait`.
let generics = tcx.generics_of(data.def_id());
if let Some(host_param_idx) = generics.host_effect_index
&& data.trait_ref.args.const_at(host_param_idx) != tcx.consts.true_
{
let mut trait_predicate_with_host = data;
trait_predicate_with_host.trait_ref.args = tcx.mk_args_from_iter(
data.trait_ref.args.iter().enumerate().map(|(idx, arg)| {
if idx == host_param_idx { tcx.consts.true_.into() } else { arg }
}),
);
self.extend_deduped([
elaboratable.child(trait_predicate_with_host.to_predicate(tcx))
]);
}
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => {
// Currently, we do not elaborate WF predicates,
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_middle/src/ty/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,6 @@ impl GenericParamDef {
}
}

pub fn is_host_effect(&self) -> bool {
matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
}

pub fn default_value<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
Expand Down

0 comments on commit 3dd95d2

Please sign in to comment.