handle nested obligations in satisfied_from_param_env
This commit is contained in:
parent
5bb1a9febc
commit
8c729bd0f3
7 changed files with 126 additions and 45 deletions
|
@ -18,6 +18,8 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitable, TypeVisitor};
|
|||
use rustc_span::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
/// Check if a given constant can be evaluated.
|
||||
#[instrument(skip(infcx), level = "debug")]
|
||||
pub fn is_const_evaluatable<'tcx>(
|
||||
|
@ -71,26 +73,27 @@ pub fn is_const_evaluatable<'tcx>(
|
|||
// See #74595 for more details about this.
|
||||
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
|
||||
match concrete {
|
||||
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
||||
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
||||
// compilation with a useful error.
|
||||
Err(_) if tcx.sess.is_nightly_build()
|
||||
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
||||
&& let ty::ConstKind::Expr(_) = ac.kind() => {
|
||||
tcx.sess
|
||||
.struct_span_fatal(
|
||||
// Slightly better span than just using `span` alone
|
||||
if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
|
||||
"failed to evaluate generic const expression",
|
||||
)
|
||||
.note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
|
||||
.span_suggestion_verbose(
|
||||
rustc_span::DUMMY_SP,
|
||||
"consider enabling this feature",
|
||||
"#![feature(generic_const_exprs)]\n",
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit()
|
||||
// If we're evaluating a generic foreign constant, under a nightly compiler while
|
||||
// the current crate does not enable `feature(generic_const_exprs)`, abort
|
||||
// compilation with a useful error.
|
||||
Err(_) if tcx.sess.is_nightly_build()
|
||||
&& let Ok(Some(ac)) = tcx.expand_abstract_consts(ct)
|
||||
&& let ty::ConstKind::Expr(_) = ac.kind() =>
|
||||
{
|
||||
tcx.sess
|
||||
.struct_span_fatal(
|
||||
// Slightly better span than just using `span` alone
|
||||
if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
|
||||
"failed to evaluate generic const expression",
|
||||
)
|
||||
.note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
|
||||
.span_suggestion_verbose(
|
||||
rustc_span::DUMMY_SP,
|
||||
"consider enabling this feature",
|
||||
"#![feature(generic_const_exprs)]\n",
|
||||
rustc_errors::Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit()
|
||||
}
|
||||
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
|
@ -130,12 +133,17 @@ fn satisfied_from_param_env<'tcx>(
|
|||
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
|
||||
type BreakTy = ();
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if c.ty() == self.ct.ty()
|
||||
&& let Ok(_nested_obligations) = self
|
||||
.infcx
|
||||
.at(&ObligationCause::dummy(), self.param_env)
|
||||
.eq(c, self.ct)
|
||||
{
|
||||
if let Ok(()) = self.infcx.commit_if_ok(|_| {
|
||||
let ocx = ObligationCtxt::new_in_snapshot(self.infcx);
|
||||
if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty())
|
||||
&& let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct)
|
||||
&& ocx.select_all_or_error().is_empty()
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}) {
|
||||
ControlFlow::BREAK
|
||||
} else if let ty::ConstKind::Expr(e) = c.kind() {
|
||||
e.visit_with(self)
|
||||
|
|
|
@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_data_structures::obligation_forest::ProcessResult;
|
||||
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
|
||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::traits::ProjectionCacheKey;
|
||||
use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
|
@ -465,6 +464,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
// Let's just see where this breaks :shrug:
|
||||
match (c1.kind(), c2.kind()) {
|
||||
(ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) => {
|
||||
// FIXME: remove
|
||||
use rustc_hir::def::DefKind;
|
||||
if tcx.def_kind(a.def.did) == DefKind::AssocConst
|
||||
|| tcx.def_kind(b.def.did) == DefKind::AssocConst
|
||||
{
|
||||
|
@ -477,16 +478,17 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
),
|
||||
);
|
||||
}
|
||||
if let (Ok(Some(a)), Ok(Some(b))) = (
|
||||
tcx.expand_abstract_consts(c1),
|
||||
tcx.expand_abstract_consts(c2),
|
||||
) && a.ty() == b.ty() &&
|
||||
let Ok(new_obligations) = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(a, b) {
|
||||
return ProcessResult::Changed(mk_pending(
|
||||
new_obligations.into_obligations(),
|
||||
));
|
||||
|
||||
if let Ok(Some(a)) = tcx.expand_abstract_consts(c1)
|
||||
&& let Ok(Some(b)) = tcx.expand_abstract_consts(c2)
|
||||
&& a.ty() == b.ty()
|
||||
&& let Ok(new_obligations) = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(a, b)
|
||||
{
|
||||
return ProcessResult::Changed(mk_pending(
|
||||
new_obligations.into_obligations(),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue