diff options
3 files changed, 38 insertions, 8 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index f449d360c16..4f0b5f59402 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -168,7 +168,9 @@ 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> { @@ -179,7 +181,9 @@ fn satisfied_from_param_env<'tcx>( && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() && ocx.select_all_or_error().is_empty() }) { - ControlFlow::BREAK + self.single_match = + if self.single_match.is_none() { Some(Ok(c)) } else { Some(Err(())) }; + ControlFlow::CONTINUE } else if let ty::ConstKind::Expr(e) = c.kind() { e.visit_with(self) } else { @@ -195,22 +199,37 @@ fn satisfied_from_param_env<'tcx>( } } + 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); - - if let ControlFlow::Break(()) = result { - debug!("is_const_evaluatable: yes"); - return true; + let mut v = Visitor { ct, infcx, param_env, single_match: None }; + let _ = b_ct.visit_with(&mut v); + if let Some(inner) = v.single_match { + single_match = if single_match.is_none() { Some(inner) } else { Some(Err(())) }; } } _ => {} // don't care } } + if let Some(c) = single_match { + if let Ok(c) = c { + let is_ok = infcx + .commit_if_ok(|_| { + let ocx = ObligationCtxt::new_in_snapshot(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()); + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(()) } + }) + .is_ok(); + assert!(is_ok); + } + return true; + } + debug!("is_const_evaluatable: no"); false } diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs index b96e210808b..d64468767eb 100644 --- a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs @@ -16,6 +16,7 @@ where { foo::<_, L>([(); L + 1 + L]); //~^ ERROR: unconstrained generic constant + //~| ERROR: mismatched types } fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr index 09e5e3f862a..da5194696e6 100644 --- a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr @@ -1,3 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/wf_obligation.rs:17:17 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L` + | + = note: expected constant `N + 1 + M` + found constant `L + 1 + L` + error: unconstrained generic constant --> $DIR/wf_obligation.rs:17:22 | @@ -6,5 +15,6 @@ LL | foo::<_, L>([(); L + 1 + L]); | = help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:` -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. |
