summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/const_evaluatable.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs52
1 files changed, 31 insertions, 21 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 7c9fde274..f779d9dd8 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>(
} else if uv.has_non_region_param() {
NotConstEvaluatable::MentionsParam
} else {
- let guar = infcx.tcx.sess.delay_span_bug(
- span,
- format!("Missing value for constant, but no error reported?"),
- );
+ let guar = infcx
+ .tcx
+ .sess
+ .delay_span_bug(span, "Missing value for constant, but no error reported?");
NotConstEvaluatable::Error(guar)
};
@@ -168,24 +168,27 @@ fn satisfied_from_param_env<'tcx>(
param_env: ty::ParamEnv<'tcx>,
infcx: &'a InferCtxt<'tcx>,
+ single_match: Option<Result<ty::Const<'tcx>, ()>>,
}
+
impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> {
type BreakTy = ();
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("is_const_evaluatable: candidate={:?}", c);
- if let Ok(()) = self.infcx.commit_if_ok(|_| {
+ if self.infcx.probe(|_| {
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.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok()
+ && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok()
&& ocx.select_all_or_error().is_empty()
- {
- Ok(())
- } else {
- Err(())
- }
}) {
- ControlFlow::BREAK
- } else if let ty::ConstKind::Expr(e) = c.kind() {
+ self.single_match = match self.single_match {
+ None => Some(Ok(c)),
+ Some(Ok(o)) if o == c => Some(Ok(c)),
+ Some(_) => Some(Err(())),
+ };
+ }
+
+ if let ty::ConstKind::Expr(e) = c.kind() {
e.visit_with(self)
} else {
// FIXME(generic_const_exprs): This doesn't recurse into `<T as Trait<U>>::ASSOC`'s substs.
@@ -195,27 +198,34 @@ fn satisfied_from_param_env<'tcx>(
// If we start allowing directly writing `ConstKind::Expr` without an intermediate anon const
// this will be incorrect. It might be worth investigating making `predicates_of` elaborate
// all of the `ConstEvaluatable` bounds rather than having a visitor here.
- ControlFlow::CONTINUE
+ ControlFlow::Continue(())
}
}
}
+ let mut single_match: Option<Result<ty::Const<'tcx>, ()>> = None;
+
for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(ce) => {
let b_ct = tcx.expand_abstract_consts(ce);
- let mut v = Visitor { ct, infcx, param_env };
- let result = b_ct.visit_with(&mut v);
+ let mut v = Visitor { ct, infcx, param_env, single_match };
+ let _ = b_ct.visit_with(&mut v);
- if let ControlFlow::Break(()) = result {
- debug!("is_const_evaluatable: yes");
- return true;
- }
+ single_match = v.single_match;
}
_ => {} // don't care
}
}
+ if let Some(Ok(c)) = single_match {
+ let ocx = ObligationCtxt::new(infcx);
+ assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok());
+ assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok());
+ assert!(ocx.select_all_or_error().is_empty());
+ return true;
+ }
+
debug!("is_const_evaluatable: no");
false
}