diff options
| author | Jonas Schievink <jonasschievink@gmail.com> | 2021-02-02 12:14:59 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-02-02 12:14:59 +0100 |
| commit | efec2bbbce3c547559fed6a6398703f7041649c4 (patch) | |
| tree | db09e831a7aa03b9551e32b21aa3215b15fd844c | |
| parent | 30f12a037952d2c08348d3eae69b4185ac1b52ae (diff) | |
| parent | 7f8530f16b8cc908cb77970967addf39ae1a975d (diff) | |
| download | rust-efec2bbbce3c547559fed6a6398703f7041649c4.tar.gz rust-efec2bbbce3c547559fed6a6398703f7041649c4.zip | |
Rollup merge of #81577 - BoxyUwU:subexpr_const_evaluatable, r=oli-obk
const_evaluatable: consider sub-expressions to be evaluatable see [zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/const_evaluatable.3A.20subexpressions) for more info cc `@lcnr` r? `@oli-obk`
5 files changed, 42 insertions, 13 deletions
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 3fade2c4437..631dcb60594 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -132,7 +132,7 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow<V::BreakTy> { - const_evaluatable::walk_abstract_const(tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() { ACNode::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index b587ed6487e..3facdd5f84c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -50,11 +50,24 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if b_def == def && b_substs == substs { debug!("is_const_evaluatable: caller_bound ~~> ok"); return Ok(()); - } else if AbstractConst::new(tcx, b_def, b_substs)? - .map_or(false, |b_ct| try_unify(tcx, ct, b_ct)) - { - debug!("is_const_evaluatable: abstract_const ~~> ok"); - return Ok(()); + } + + if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? { + // Try to unify with each subtree in the AbstractConst to allow for + // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` + // predicate for `(N + 1) * 2` + let result = + walk_abstract_const(tcx, b_ct, |b_ct| { + match try_unify(tcx, ct, b_ct) { + true => ControlFlow::BREAK, + false => ControlFlow::CONTINUE, + } + }); + + if let ControlFlow::Break(()) = result { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } } } _ => {} // don't care @@ -78,7 +91,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::<!, _>(tcx, ct, |node| match node { + walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { @@ -580,15 +593,15 @@ pub fn walk_abstract_const<'tcx, R, F>( mut f: F, ) -> ControlFlow<R> where - F: FnMut(Node<'tcx>) -> ControlFlow<R>, + F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, { fn recurse<'tcx, R>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<R>, + f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>, ) -> ControlFlow<R> { + f(ct)?; let root = ct.root(); - f(root)?; match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a9723611f81..3852005ee3f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -828,7 +828,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // constants which are not considered const evaluatable. use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) @@ -849,7 +849,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // take a `ty::Const` instead. use rustc_middle::mir::abstract_const::Node; if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { - const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node { + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { Node::Leaf(leaf) => { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) diff --git a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs index 1428f774b0d..4d0b87efc77 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/nested_uneval_unification-1.rs @@ -21,7 +21,6 @@ where fn substs3<const L: usize>() -> Substs1<{ (L - 1) * 2 }> where - [(); (L - 1)]: , [(); (L - 1) * 2 + 1]: , { substs2::<{ L - 1 }>() diff --git a/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs b/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs new file mode 100644 index 00000000000..11c0760cdfe --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/subexprs_are_const_evalutable.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn make_array<const M: usize>() -> [(); M + 1] { + [(); M + 1] +} + +fn foo<const N: usize>() -> [(); (N * 2) + 1] { + make_array::<{ N * 2 }>() +} + +fn main() { + assert_eq!(foo::<10>(), [(); 10 * 2 + 1]) +} + +// Tests that N * 2 is considered const_evalutable by appearing as part of the (N * 2) + 1 const |
