add predicate evaluation logic
This commit is contained in:
parent
e919d7e348
commit
90c8d6bbe4
9 changed files with 124 additions and 18 deletions
|
@ -9,8 +9,8 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::ty::subst::InternalSubsts;
|
||||
use rustc_middle::ty::ToPredicate;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericPredicates, ToPredicate};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
|
@ -151,7 +151,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
trace!(?generics);
|
||||
|
||||
// Collect the predicates that were written inline by the user on each
|
||||
// type parameter (e.g., `<T: Foo>`).
|
||||
// type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
|
||||
// for each const parameter.
|
||||
for param in ast_generics.params {
|
||||
match param.kind {
|
||||
// We already dealt with early bound lifetimes above.
|
||||
|
@ -175,7 +176,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
|||
trace!(?predicates);
|
||||
}
|
||||
GenericParamKind::Const { .. } => {
|
||||
// Bounds on const parameters are currently not possible.
|
||||
let name = param.name.ident().name;
|
||||
let param_const = ty::ParamConst::new(index, name);
|
||||
|
||||
let ct_ty = tcx.type_of(param.def_id.to_def_id()).subst_identity();
|
||||
|
||||
let ct = tcx.mk_const(param_const, ct_ty);
|
||||
|
||||
let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
|
||||
ty::Clause::ConstArgHasType(ct, ct_ty),
|
||||
))
|
||||
.to_predicate(tcx);
|
||||
predicates.insert((predicate, param.span));
|
||||
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +452,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
|
||||
let parent_def_id = tcx.hir().get_parent_item(hir_id);
|
||||
|
||||
if tcx.hir().opt_const_param_default_param_def_id(hir_id).is_some() {
|
||||
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)
|
||||
|
@ -452,7 +467,39 @@ pub(super) fn explicit_predicates_of<'tcx>(
|
|||
//
|
||||
// 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
|
||||
return tcx.explicit_predicates_of(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::PredicateKind::Clause(ty::Clause::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"
|
||||
),
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.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);
|
||||
|
|
|
@ -496,6 +496,16 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
|||
)
|
||||
.emit();
|
||||
}
|
||||
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..)) => {
|
||||
// FIXME(min_specialization), FIXME(const_generics):
|
||||
// It probably isn't right to allow _every_ `ConstArgHasType` but I am somewhat unsure
|
||||
// about the actual rules that would be sound. Can't just always error here because otherwise
|
||||
// std/core doesn't even compile as they have `const N: usize` in some specializing impls.
|
||||
//
|
||||
// While we do not support constructs like `<T, const N: T>` there is probably no risk of
|
||||
// soundness bugs, but when we support generic const parameter types this will need to be
|
||||
// revisited.
|
||||
}
|
||||
_ => {
|
||||
tcx.sess
|
||||
.struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue