Implement const effect predicate in new solver
This commit is contained in:
parent
a16d491054
commit
cde29b9ec9
127 changed files with 1702 additions and 1170 deletions
|
@ -181,6 +181,7 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
});
|
||||
|
||||
// Create mapping from trait method to impl method.
|
||||
let impl_def_id = impl_m.container_id(tcx);
|
||||
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_m.def_id).rebase_onto(
|
||||
tcx,
|
||||
impl_m.container_id(tcx),
|
||||
|
@ -204,6 +205,24 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
trait_m_predicates.instantiate_own(tcx, trait_to_impl_args).map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
// FIXME(effects): This should be replaced with a more dedicated method.
|
||||
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
|
||||
if check_const_if_const {
|
||||
// Augment the hybrid param-env with the const conditions
|
||||
// of the impl header and the trait method.
|
||||
hybrid_preds.extend(
|
||||
tcx.const_conditions(impl_def_id)
|
||||
.instantiate_identity(tcx)
|
||||
.into_iter()
|
||||
.chain(
|
||||
tcx.const_conditions(trait_m.def_id).instantiate_own(tcx, trait_to_impl_args),
|
||||
)
|
||||
.map(|(trait_ref, _)| {
|
||||
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
|
@ -230,6 +249,34 @@ fn compare_method_predicate_entailment<'tcx>(
|
|||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||
}
|
||||
|
||||
// If we're within a const implementation, we need to make sure that the method
|
||||
// does not assume stronger `~const` bounds than the trait definition.
|
||||
//
|
||||
// This registers the `~const` bounds of the impl method, which we will prove
|
||||
// using the hybrid param-env that we earlier augmented with the const conditions
|
||||
// from the impl header and trait method declaration.
|
||||
if check_const_if_const {
|
||||
for (const_condition, span) in
|
||||
tcx.const_conditions(impl_m.def_id).instantiate_own_identity()
|
||||
{
|
||||
let normalize_cause = traits::ObligationCause::misc(span, impl_m_def_id);
|
||||
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(span, impl_m_def_id, ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id: impl_m_def_id,
|
||||
trait_item_def_id: trait_m.def_id,
|
||||
kind: impl_m.kind,
|
||||
});
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
param_env,
|
||||
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// We now need to check that the signature of the impl method is
|
||||
// compatible with that of the trait method. We do this by
|
||||
// checking that `impl_fty <: trait_fty`.
|
||||
|
@ -1846,9 +1893,10 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
trait_ty: ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let impl_def_id = impl_ty.container_id(tcx);
|
||||
let trait_to_impl_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id).rebase_onto(
|
||||
tcx,
|
||||
impl_ty.container_id(tcx),
|
||||
impl_def_id,
|
||||
impl_trait_ref.args,
|
||||
);
|
||||
|
||||
|
@ -1856,7 +1904,9 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
let trait_ty_predicates = tcx.predicates_of(trait_ty.def_id);
|
||||
|
||||
let impl_ty_own_bounds = impl_ty_predicates.instantiate_own_identity();
|
||||
if impl_ty_own_bounds.len() == 0 {
|
||||
let impl_ty_own_const_conditions =
|
||||
tcx.const_conditions(impl_ty.def_id).instantiate_own_identity();
|
||||
if impl_ty_own_bounds.len() == 0 && impl_ty_own_const_conditions.len() == 0 {
|
||||
// Nothing to check.
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1881,6 +1931,23 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
let impl_ty_span = tcx.def_span(impl_ty_def_id);
|
||||
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
||||
|
||||
let check_const_if_const = tcx.constness(impl_def_id) == hir::Constness::Const;
|
||||
if check_const_if_const {
|
||||
// Augment the hybrid param-env with the const conditions
|
||||
// of the impl header and the trait assoc type.
|
||||
hybrid_preds.extend(
|
||||
tcx.const_conditions(impl_ty_predicates.parent.unwrap())
|
||||
.instantiate_identity(tcx)
|
||||
.into_iter()
|
||||
.chain(
|
||||
tcx.const_conditions(trait_ty.def_id).instantiate_own(tcx, trait_to_impl_args),
|
||||
)
|
||||
.map(|(trait_ref, _)| {
|
||||
trait_ref.to_host_effect_clause(tcx, ty::HostPolarity::Maybe)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
debug!(caller_bounds=?param_env.caller_bounds());
|
||||
|
@ -1901,6 +1968,27 @@ fn compare_type_predicate_entailment<'tcx>(
|
|||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||
}
|
||||
|
||||
if check_const_if_const {
|
||||
// Validate the const conditions of the impl associated type.
|
||||
for (const_condition, span) in impl_ty_own_const_conditions {
|
||||
let normalize_cause = traits::ObligationCause::misc(span, impl_ty_def_id);
|
||||
let const_condition = ocx.normalize(&normalize_cause, param_env, const_condition);
|
||||
|
||||
let cause =
|
||||
ObligationCause::new(span, impl_ty_def_id, ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id: impl_ty_def_id,
|
||||
trait_item_def_id: trait_ty.def_id,
|
||||
kind: impl_ty.kind,
|
||||
});
|
||||
ocx.register_obligation(traits::Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
param_env,
|
||||
const_condition.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all obligations are satisfied by the implementation's
|
||||
// version.
|
||||
let errors = ocx.select_all_or_error();
|
||||
|
@ -1983,7 +2071,7 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
|
||||
};
|
||||
|
||||
let obligations: Vec<_> = tcx
|
||||
let mut obligations: Vec<_> = tcx
|
||||
.explicit_item_bounds(trait_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, rebased_args)
|
||||
.map(|(concrete_ty_bound, span)| {
|
||||
|
@ -1991,6 +2079,22 @@ pub(super) fn check_type_bounds<'tcx>(
|
|||
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Only in a const implementation do we need to check that the `~const` item bounds hold.
|
||||
if tcx.constness(container_id) == hir::Constness::Const {
|
||||
obligations.extend(
|
||||
tcx.implied_const_bounds(trait_ty.def_id)
|
||||
.iter_instantiated_copied(tcx, rebased_args)
|
||||
.map(|(c, span)| {
|
||||
traits::Obligation::new(
|
||||
tcx,
|
||||
mk_cause(span),
|
||||
param_env,
|
||||
c.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
debug!(item_bounds=?obligations);
|
||||
|
||||
// Normalize predicates with the assumption that the GAT may always normalize
|
||||
|
|
|
@ -32,7 +32,8 @@ use rustc_trait_selection::traits::misc::{
|
|||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc,
|
||||
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
WellFormedLoc,
|
||||
};
|
||||
use rustc_type_ir::TypeFlags;
|
||||
use rustc_type_ir::solve::NoSolution;
|
||||
|
@ -86,7 +87,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
self.body_def_id,
|
||||
ObligationCauseCode::WellFormed(loc),
|
||||
);
|
||||
self.ocx.register_obligation(traits::Obligation::new(
|
||||
self.ocx.register_obligation(Obligation::new(
|
||||
self.tcx(),
|
||||
cause,
|
||||
self.param_env,
|
||||
|
@ -1173,7 +1174,7 @@ fn check_type_defn<'tcx>(
|
|||
wfcx.body_def_id,
|
||||
ObligationCauseCode::Misc,
|
||||
);
|
||||
wfcx.register_obligation(traits::Obligation::new(
|
||||
wfcx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
cause,
|
||||
wfcx.param_env,
|
||||
|
@ -1369,6 +1370,30 @@ fn check_impl<'tcx>(
|
|||
obligation.cause.span = hir_self_ty.span;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the `~const` where clauses of the trait hold for the impl.
|
||||
if tcx.constness(item.owner_id.def_id) == hir::Constness::Const {
|
||||
for (bound, _) in
|
||||
tcx.const_conditions(trait_ref.def_id).instantiate(tcx, trait_ref.args)
|
||||
{
|
||||
let bound = wfcx.normalize(
|
||||
item.span,
|
||||
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
|
||||
bound,
|
||||
);
|
||||
wfcx.register_obligation(Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
hir_self_ty.span,
|
||||
wfcx.body_def_id,
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
),
|
||||
wfcx.param_env,
|
||||
bound.to_host_effect_clause(tcx, ty::HostPolarity::Maybe),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
debug!(?obligations);
|
||||
wfcx.register_obligations(obligations);
|
||||
}
|
||||
|
@ -1561,7 +1586,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
|
|||
wfcx.body_def_id,
|
||||
ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
|
||||
);
|
||||
traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
|
||||
Obligation::new(tcx, cause, wfcx.param_env, pred)
|
||||
});
|
||||
|
||||
let predicates = predicates.instantiate_identity(tcx);
|
||||
|
@ -1852,7 +1877,7 @@ fn receiver_is_implemented<'tcx>(
|
|||
let tcx = wfcx.tcx();
|
||||
let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
|
||||
|
||||
let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
|
||||
let obligation = Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
|
||||
|
||||
if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) {
|
||||
true
|
||||
|
@ -2188,7 +2213,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
|||
.unwrap_or(obligation_span);
|
||||
}
|
||||
|
||||
let obligation = traits::Obligation::new(
|
||||
let obligation = Obligation::new(
|
||||
tcx,
|
||||
traits::ObligationCause::new(
|
||||
span,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue