Auto merge of #109557 - fee1-dead-contrib:mv-const-traits, r=oli-obk
Move const trait bounds checks to MIR constck Fixes #109543. When checking paths in HIR typeck, we don't want to check for const predicates since all we want might just be a function pointer. Therefore we move this to MIR constck and check that bounds are met during MIR constck. r? `@oli-obk`
This commit is contained in:
commit
60660371ef
27 changed files with 440 additions and 323 deletions
|
@ -722,6 +722,32 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// Check that all trait bounds that are marked as `~const` can be satisfied.
|
||||
//
|
||||
// Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
|
||||
// which path expressions are getting called on and which path expressions are only used
|
||||
// as function pointers. This is required for correctness.
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
|
||||
let cause = ObligationCause::new(
|
||||
terminator.source_info.span,
|
||||
self.body.source.def_id().expect_local(),
|
||||
ObligationCauseCode::ItemObligation(callee),
|
||||
);
|
||||
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
|
||||
ocx.register_obligations(traits::predicates_for_generics(
|
||||
|_, _| cause.clone(),
|
||||
self.param_env,
|
||||
normalized_predicates,
|
||||
));
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors);
|
||||
}
|
||||
|
||||
// Attempting to call a trait method?
|
||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||
trace!("attempting to call a trait method");
|
||||
|
@ -749,31 +775,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
selcx.select(&obligation)
|
||||
};
|
||||
|
||||
// do a well-formedness check on the trait method being called. This is because typeck only does a
|
||||
// "non-const" check. This is required for correctness here.
|
||||
{
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
|
||||
let cause = ObligationCause::new(
|
||||
terminator.source_info.span,
|
||||
self.body.source.def_id().expect_local(),
|
||||
ObligationCauseCode::ItemObligation(callee),
|
||||
);
|
||||
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
|
||||
ocx.register_obligations(traits::predicates_for_generics(
|
||||
|_, _| cause.clone(),
|
||||
self.param_env,
|
||||
normalized_predicates,
|
||||
));
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors);
|
||||
}
|
||||
}
|
||||
|
||||
match implsrc {
|
||||
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
|
||||
debug!(
|
||||
|
|
|
@ -1416,41 +1416,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) {
|
||||
let param_env = self.param_env;
|
||||
|
||||
let remap = match self.tcx.def_kind(def_id) {
|
||||
// Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
|
||||
// `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
|
||||
// Therefore we have to remap the param env here to be non-const.
|
||||
hir::def::DefKind::AssocConst => true,
|
||||
hir::def::DefKind::AssocFn
|
||||
if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
|
||||
{
|
||||
// N.B.: All callsites to this function involve checking a path expression.
|
||||
//
|
||||
// When instantiating a trait method as a function item, it does not actually matter whether
|
||||
// the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
|
||||
// `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
|
||||
// check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
|
||||
// `const fn` pointer.
|
||||
//
|
||||
// FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
|
||||
// `~const FnOnce` or can be coerced to `const fn` pointer.
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
let bounds = self.instantiate_bounds(span, def_id, &substs);
|
||||
|
||||
for mut obligation in traits::predicates_for_generics(
|
||||
for obligation in traits::predicates_for_generics(
|
||||
|idx, predicate_span| {
|
||||
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
|
||||
},
|
||||
param_env,
|
||||
bounds,
|
||||
) {
|
||||
if remap {
|
||||
obligation = obligation.without_const(self.tcx);
|
||||
}
|
||||
self.register_predicate(obligation);
|
||||
// N.B. We are remapping all predicates to non-const since we don't know if we just
|
||||
// want them as function pointers or we are calling them from a const-context. The
|
||||
// actual checking will occur in `rustc_const_eval::transform::check_consts`.
|
||||
self.register_predicate(obligation.without_const(self.tcx));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue