diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9c376c6c93e2e..e424a51d01c97 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -23,7 +23,7 @@ use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{InternalSubsts, Subst}; +use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}; use rustc_session::lint; use rustc_span::hygiene::Transparency; @@ -153,11 +153,8 @@ where tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, ) -> ControlFlow { - 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) - } + const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root(tcx) { + ACNode::Leaf(leaf) => self.visit_const(leaf), ACNode::Cast(_, _, ty) => self.visit_ty(ty), ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { ControlFlow::CONTINUE diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ddabe5967d79c..076597587f510 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -80,9 +80,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( Concrete, } let mut failure_kind = FailureKind::Concrete; - walk_abstract_const::(tcx, ct, |node| match node.root() { + walk_abstract_const::(tcx, ct, |node| match node.root(tcx) { Node::Leaf(leaf) => { - let leaf = leaf.subst(tcx, ct.substs); if leaf.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if leaf.definitely_has_param_types_or_consts(tcx) { @@ -92,7 +91,6 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } Node::Cast(_, _, ty) => { - let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; } else if ty.definitely_has_param_types_or_consts(tcx) { @@ -187,8 +185,8 @@ pub fn is_const_evaluatable<'cx, 'tcx>( pub struct AbstractConst<'tcx> { // FIXME: Consider adding something like `IndexSlice` // and use this here. - pub inner: &'tcx [Node<'tcx>], - pub substs: SubstsRef<'tcx>, + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, } impl<'tcx> AbstractConst<'tcx> { @@ -218,8 +216,14 @@ impl<'tcx> AbstractConst<'tcx> { } #[inline] - pub fn root(self) -> Node<'tcx> { - self.inner.last().copied().unwrap() + pub fn root(self, tcx: TyCtxt<'tcx>) -> Node<'tcx> { + let node = self.inner.last().copied().unwrap(); + match node { + Node::Leaf(leaf) => Node::Leaf(leaf.subst(tcx, self.substs)), + Node::Cast(kind, operand, ty) => Node::Cast(kind, operand, ty.subst(tcx, self.substs)), + // Don't perform substitution on the following as they can't directly contain generic params + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => node, + } } } @@ -587,7 +591,7 @@ where f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow, ) -> ControlFlow { f(ct)?; - let root = ct.root(); + let root = ct.root(tcx); match root { Node::Leaf(_) => ControlFlow::CONTINUE, Node::Binop(_, l, r) => { @@ -615,16 +619,14 @@ pub(super) fn try_unify<'tcx>( // We substitute generics repeatedly to allow AbstractConsts to unify where a // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g. // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])] - while let Node::Leaf(a_ct) = a.root() { - let a_ct = a_ct.subst(tcx, a.substs); + while let Node::Leaf(a_ct) = a.root(tcx) { match AbstractConst::from_const(tcx, a_ct) { Ok(Some(a_act)) => a = a_act, Ok(None) => break, Err(_) => return true, } } - while let Node::Leaf(b_ct) = b.root() { - let b_ct = b_ct.subst(tcx, b.substs); + while let Node::Leaf(b_ct) = b.root(tcx) { match AbstractConst::from_const(tcx, b_ct) { Ok(Some(b_act)) => b = b_act, Ok(None) => break, @@ -632,10 +634,8 @@ pub(super) fn try_unify<'tcx>( } } - match (a.root(), b.root()) { + match (a.root(tcx), b.root(tcx)) { (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { - let a_ct = a_ct.subst(tcx, a.substs); - let b_ct = b_ct.subst(tcx, b.substs); if a_ct.ty != b_ct.ty { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 57b8a84300ff9..4eaa3ea47325f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -838,14 +838,13 @@ 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::new(self.tcx, uv.shrink()) { - 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) - } - Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE + const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { + match node.root(self.tcx) { + Node::Leaf(leaf) => self.visit_const(leaf), + Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } } }) } else {