diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/const_evaluatable.rs')
-rw-r--r-- | compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 52 |
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 } |