From 9b2913814b95e1b8f123da59ddecb1bc6b3813af Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 16:14:01 +0100 Subject: [PATCH] as casts and block exprs --- .../rustc_middle/src/mir/abstract_const.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 84 ++++++++++++------- .../src/traits/object_safety.rs | 2 +- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index e75f084e79e..1158a9f4f80 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -1,5 +1,5 @@ //! A subset of a mir body used for const evaluatability checking. -use crate::mir::{self, CastKind}; +use crate::mir; use crate::ty::{self, Ty}; rustc_index::newtype_index! { @@ -18,7 +18,7 @@ pub enum Node<'tcx> { UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), Block(&'tcx [NodeId], Option), - Cast(CastKind, NodeId, Ty<'tcx>), + Cast(NodeId, Ty<'tcx>), } #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 26e1c3e7b8c..7d0f6767900 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -158,7 +158,7 @@ where let leaf = leaf.subst(tcx, ct.substs); self.visit_const(leaf) } - ACNode::Cast(_, _, ty) => self.visit_ty(ty), + ACNode::Cast(_, ty) => self.visit_ty(ty), ACNode::Block(_, _) | ACNode::Binop(..) | ACNode::UnaryOp(..) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4e11fefdc81..461ebba58d9 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -92,7 +92,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Cast(_, _, ty) => { + Node::Cast(_, ty) => { let ty = ty.subst(tcx, ct.substs); if ty.has_infer_types_or_consts() { failure_kind = FailureKind::MentionsInfer; @@ -292,7 +292,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { stmts.iter().for_each(|&id| self.nodes[id].used = true); opt_expr.map(|e| self.nodes[e].used = true); } - Node::Cast(_, operand, _) => { + Node::Cast(operand, _) => { self.nodes[operand].used = true; } } @@ -335,6 +335,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + // FIXME I dont even think we can get unused nodes anymore with thir abstract const if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { self.error(Some(unused.span), "dead code")?; } @@ -352,6 +353,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::PlaceTypeAscription { source, .. } | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + // subtle: associated consts are literals this arm handles + // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), @@ -375,14 +378,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.add_node(Node::UnaryOp(op, arg), node.span) }, - // HACK: without this arm the following doesn't compile: - // ``` - // fn foo(_: [(); N + 1]) { - // bar::<{ N + 1}>(); - // } - // ``` - // we ought to properly handle this in `try_unify` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, ExprKind::Block { body } => { let mut stmts = Vec::with_capacity(body.stmts.len()); for &id in body.stmts.iter() { @@ -398,26 +393,34 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?; self.add_node(Node::Block(stmts, opt_expr), node.span) } - &ExprKind::Cast { source } => todo!(), + + // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // "coercion cast" i.e. using a coercion or is a no-op. + // this is important so that `N as usize as usize` doesnt unify with `N as usize` + &ExprKind::Use { source} + | &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.add_node(Node::Cast(arg, node.ty), node.span) + }, // never can arise even without panic/fail to terminate &ExprKind::NeverToAny { source } => todo!(), - // i think this is a dummy usage of the expr to allow coercions - &ExprKind::Use { source } => todo!(), - ExprKind::Return { .. } - | ExprKind::Box { .. } // allocations not allowed in constants - | ExprKind::AssignOp { .. } - | ExprKind::AddressOf { .. } // FIXME(generic_const_exprs) - | ExprKind::Borrow { .. } // FIXME(generic_const_exprs) - | ExprKind::Deref { .. } // FIXME(generic_const_exprs) - | ExprKind::Repeat { .. } // FIXME(generic_const_exprs) - | ExprKind::Array { .. } // FIXME(generic_const_exprs) - | ExprKind::Tuple { .. } // FIXME(generic_const_exprs) - | ExprKind::Index { .. } // FIXME(generic_const_exprs) - | ExprKind::Field { .. } // FIXME(generic_const_exprs) - | ExprKind::ConstBlock { .. } // FIXME(generic_const_exprs) - | ExprKind::Adt(_) // FIXME(generic_const_exprs) we *should* permit this but dont currently - | ExprKind::Match { .. } + // FIXME(generic_const_exprs) we want to support these + ExprKind::AddressOf { .. } + | ExprKind::Borrow { .. } + | ExprKind::Deref { .. } + | ExprKind::Repeat { .. } + | ExprKind::Array { .. } + | ExprKind::Tuple { .. } + | ExprKind::Index { .. } + | ExprKind::Field { .. } + | ExprKind::ConstBlock { .. } + | ExprKind::Adt(_) => return self.error( + Some(node.span), + "unsupported operation in generic constant, this may be supported in the future", + ).map(|never| never), + + ExprKind::Match { .. } | ExprKind::VarRef { .. } // | ExprKind::UpvarRef { .. } // we dont permit let stmts so... | ExprKind::Closure { .. } @@ -433,6 +436,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Pointer { .. } // dont know if this is correct | ExprKind::ThreadLocalRef(_) | ExprKind::LlvmInlineAsm { .. } + | ExprKind::Return { .. } + | ExprKind::Box { .. } // allocations not allowed in constants + | ExprKind::AssignOp { .. } | ExprKind::InlineAsm { .. } | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never), }) @@ -521,7 +527,7 @@ where } ControlFlow::CONTINUE } - Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), + Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -604,11 +610,27 @@ pub(super) fn try_unify<'tcx>( && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } - (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty)) - if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) => + (Node::Cast(a_operand, a_ty), Node::Cast(b_operand, b_ty)) + if (a_ty == b_ty) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - _ => false, + (Node::Block(a_stmts, a_opt_expr), Node::Block(b_stmts, b_opt_expr)) + if a_stmts.len() == b_stmts.len() => { + a_stmts.iter().zip(b_stmts.iter()).all(|(&a_stmt, &b_stmt)| { + try_unify(tcx, a.subtree(a_stmt), b.subtree(b_stmt)) + }) && match (a_opt_expr, b_opt_expr) { + (Some(a_expr), Some(b_expr)) => try_unify(tcx, a.subtree(a_expr), b.subtree(b_expr)), + (None, None) => true, + _ => false, + } + } + // use this over `_ => false` to make adding variants to `Node` less error prone + (Node::Block(..), _) + | (Node::Cast(..), _) + | (Node::FunctionCall(..), _) + | (Node::UnaryOp(..), _) + | (Node::Binop(..), _) + | (Node::Leaf(..), _) => false, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e64cc9e4b8f..3527aede609 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -843,7 +843,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Cast(_, _, ty) => self.visit_ty(ty), + Node::Cast(_, ty) => self.visit_ty(ty), Node::Block(_, _) | Node::Binop(..) | Node::UnaryOp(..)