From 2987f4ba42b002c58ae485f7ae528cb29c3b1611 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 02:27:41 +0100 Subject: [PATCH 01/18] WIP state --- .../rustc_middle/src/mir/abstract_const.rs | 1 + compiler/rustc_mir_build/src/build/mod.rs | 8 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 + compiler/rustc_mir_build/src/thir/cx/mod.rs | 1 + compiler/rustc_privacy/src/lib.rs | 7 +- .../src/traits/const_evaluatable.rs | 360 +++++++----------- .../src/traits/object_safety.rs | 7 +- 7 files changed, 160 insertions(+), 227 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 1ef10241143b8..e75f084e79e21 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -17,6 +17,7 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), + Block(&'tcx [NodeId], Option), Cast(CastKind, NodeId, Ty<'tcx>), } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 0a760a740dcae..390ce59cb489c 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -28,6 +28,7 @@ crate fn mir_built<'tcx>( if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } + debug!("mir_built: def={:?}", def); let mut body = mir_build(tcx, def); if def.const_param_did.is_some() { @@ -40,6 +41,7 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { + debug!("mir_build: def={:?}", def); let id = tcx.hir().local_def_id_to_hir_id(def.did); let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); @@ -47,10 +49,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // Ensure unsafeck is ran before we steal the THIR. match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { - tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)) + tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); + tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did)); } ty::WithOptConstParam { did, const_param_did: None } => { - tcx.ensure().thir_check_unsafety(did) + tcx.ensure().thir_check_unsafety(did); + tcx.ensure().mir_abstract_const(did); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 66005be05df75..70a5a9286b0b3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -149,7 +149,9 @@ impl<'tcx> Cx<'tcx> { } fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { + debug!("Expr::make_mirror_unadjusted: expr={:?}", expr); let expr_ty = self.typeck_results().expr_ty(expr); + debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -762,6 +764,7 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err => unreachable!(), }; + debug!("Expr::make_mirror_unadjusted: finish"); Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5059dd939d92d..5310efbccd655 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -20,6 +20,7 @@ crate fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> (&'tcx Steal>, ExprId) { + debug!("thir_body: {:?}", owner_def); let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did))); let mut cx = Cx::new(tcx, owner_def); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 35e25e52dc5f9..26e1c3e7b8cf4 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,9 +159,10 @@ where self.visit_const(leaf) } ACNode::Cast(_, _, ty) => self.visit_ty(ty), - ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + ACNode::Block(_, _) + | 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..4e11fefdc81f3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,14 +8,15 @@ //! In this case we try to build an abstract representation of this constant using //! `mir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. +use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; +use rustc_middle::mir; use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::thir; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -101,9 +102,10 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + Node::Block(_, _) + | Node::Binop(_, _, _) + | Node::UnaryOp(_, _) + | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }); match failure_kind { @@ -232,7 +234,8 @@ struct WorkNode<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + body_id: thir::ExprId, + body: Lrc<&'a thir::Thir<'tcx>>, /// The current WIP node tree. /// /// We require all nodes to be used in the final abstract const, @@ -240,18 +243,18 @@ struct AbstractConstBuilder<'a, 'tcx> { /// if they are mentioned in an assert, so some used nodes are never /// actually reachable by walking the [`AbstractConst`]. nodes: IndexVec>, - locals: IndexVec, - /// We only allow field accesses if they access - /// the result of a checked operation. - checked_op_locals: BitSet, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn root_span(&self) -> Span { + self.body.exprs[self.body_id].span + } + fn error(&mut self, span: Option, msg: &str) -> Result { self.tcx .sess - .struct_span_err(self.body.span, "overly complex generic constant") - .span_label(span.unwrap_or(self.body.span), msg) + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span.unwrap_or(self.root_span()), msg) .help("consider moving this anonymous constant into a `const` function") .emit(); @@ -260,28 +263,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn new( tcx: TyCtxt<'tcx>, - body: &'a mir::Body<'tcx>, + (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let mut builder = AbstractConstBuilder { - tcx, - body, - nodes: IndexVec::new(), - locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls), - checked_op_locals: BitSet::new_empty(body.local_decls.len()), - }; - - // We don't have to look at concrete constants, as we - // can just evaluate them. - if !body.is_polymorphic { - return Ok(None); - } + let builder = + AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; - // We only allow consts without control flow, so - // we check for cycles here which simplifies the - // rest of this implementation. - if body.is_cfg_cyclic() { - builder.error(None, "cyclic anonymous constants are forbidden")?; - } + // FIXME non-constants should return Ok(None) Ok(Some(builder)) } @@ -301,6 +288,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes[func].used = true; nodes.iter().for_each(|&n| self.nodes[n].used = true); } + Node::Block(stmts, opt_expr) => { + stmts.iter().for_each(|&id| self.nodes[id].used = true); + opt_expr.map(|e| self.nodes[e].used = true); + } Node::Cast(_, operand, _) => { self.nodes[operand].used = true; } @@ -310,50 +301,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes.push(WorkNode { node, span, used: false }) } - fn place_to_local( - &mut self, - span: Span, - p: &mir::Place<'tcx>, - ) -> Result { - const ZERO_FIELD: mir::Field = mir::Field::from_usize(0); - // Do not allow any projections. - // - // One exception are field accesses on the result of checked operations, - // which are required to support things like `1 + 2`. - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - Ok(p) - } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() { - // Only allow field accesses if the given local - // contains the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - Ok(p.local) - } else { - self.error(Some(span), "unsupported projection")?; - } - } else { - self.error(Some(span), "unsupported projection")?; - } - } - - fn operand_to_node( - &mut self, - span: Span, - op: &mir::Operand<'tcx>, - ) -> Result { - debug!("operand_to_node: op={:?}", op); - match op { - mir::Operand::Copy(p) | mir::Operand::Move(p) => { - let local = self.place_to_local(span, p)?; - Ok(self.locals[local]) - } - mir::Operand::Constant(ct) => match ct.literal { - mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)), - mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?, - }, - } - } - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -373,148 +320,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { - debug!("AbstractConstBuilder: stmt={:?}", stmt); - let span = stmt.source_info.span; - match stmt.kind { - StatementKind::Assign(box (ref place, ref rvalue)) => { - let local = self.place_to_local(span, place)?; - match *rvalue { - Rvalue::Use(ref operand) => { - self.locals[local] = self.operand_to_node(span, operand)?; - Ok(()) - } - Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - if op.is_checkable() { - bug!("unexpected unchecked checkable binary operation"); - } else { - Ok(()) - } - } - Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) - if Self::check_binop(op) => - { - let lhs = self.operand_to_node(span, lhs)?; - let rhs = self.operand_to_node(span, rhs)?; - self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span); - self.checked_op_locals.insert(local); - Ok(()) - } - Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span); - Ok(()) - } - Rvalue::Cast(cast_kind, ref operand, ty) => { - let operand = self.operand_to_node(span, operand)?; - self.locals[local] = - self.add_node(Node::Cast(cast_kind, operand, ty), span); - Ok(()) - } - _ => self.error(Some(span), "unsupported rvalue")?, - } - } - // These are not actually relevant for us here, so we can ignore them. - StatementKind::AscribeUserType(..) - | StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) => Ok(()), - _ => self.error(Some(stmt.source_info.span), "unsupported statement")?, - } - } - - /// Possible return values: - /// - /// - `None`: unsupported terminator, stop building - /// - `Some(None)`: supported terminator, finish building - /// - `Some(Some(block))`: support terminator, build `block` next - fn build_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> Result, ErrorReported> { - debug!("AbstractConstBuilder: terminator={:?}", terminator); - match terminator.kind { - TerminatorKind::Goto { target } => Ok(Some(target)), - TerminatorKind::Return => Ok(None), - TerminatorKind::Call { - ref func, - ref args, - destination: Some((ref place, target)), - // We do not care about `cleanup` here. Any branch which - // uses `cleanup` will fail const-eval and they therefore - // do not matter when checking for const evaluatability. - // - // Do note that even if `panic::catch_unwind` is made const, - // we still do not have to care about this, as we do not look - // into functions. - cleanup: _, - // Do not allow overloaded operators for now, - // we probably do want to allow this in the future. - // - // This is currently fairly irrelevant as it requires `const Trait`s. - from_hir_call: true, - fn_span, - } => { - let local = self.place_to_local(fn_span, place)?; - let func = self.operand_to_node(fn_span, func)?; - let args = self.tcx.arena.alloc_from_iter( - args.iter() - .map(|arg| self.operand_to_node(terminator.source_info.span, arg)) - .collect::, _>>()?, - ); - self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span); - Ok(Some(target)) - } - TerminatorKind::Assert { ref cond, expected: false, target, .. } => { - let p = match cond { - mir::Operand::Copy(p) | mir::Operand::Move(p) => p, - mir::Operand::Constant(_) => bug!("unexpected assert"), - }; - - const ONE_FIELD: mir::Field = mir::Field::from_usize(1); - debug!("proj: {:?}", p.projection); - if let Some(p) = p.as_local() { - debug_assert!(!self.checked_op_locals.contains(p)); - // Mark locals directly used in asserts as used. - // - // This is needed because division does not use `CheckedBinop` but instead - // adds an explicit assert for `divisor != 0`. - self.nodes[self.locals[p]].used = true; - return Ok(Some(target)); - } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() { - // Only allow asserts checking the result of a checked operation. - if self.checked_op_locals.contains(p.local) { - return Ok(Some(target)); - } - } - - self.error(Some(terminator.source_info.span), "unsupported assertion")?; - } - _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?, - } - } - - /// Builds the abstract const by walking the mir from start to finish - /// and bailing out when encountering an unsupported operation. + /// Builds the abstract const by walking the thir and bailing out when + /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { - let mut block = &self.body.basic_blocks()[mir::START_BLOCK]; - // We checked for a cyclic cfg above, so this should terminate. - loop { - debug!("AbstractConstBuilder: block={:?}", block); - for stmt in block.statements.iter() { - self.build_statement(stmt)?; - } - - if let Some(next) = self.build_terminator(block.terminator())? { - block = &self.body.basic_blocks()[next]; - } else { - break; - } - } + debug!("Abstractconstbuilder::build: body={:?}", &*self.body); + let last = self.recurse_build(self.body_id)?; + self.nodes[last].used = true; - assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); for n in self.nodes.iter() { if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { // `AbstractConst`s should not contain any promoteds as they require references which @@ -523,13 +335,108 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } - self.nodes[self.locals[mir::RETURN_PLACE]].used = true; if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { self.error(Some(unused.span), "dead code")?; } Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) } + + fn recurse_build(&mut self, node: thir::ExprId) -> Result { + use thir::ExprKind; + let node = &self.body.clone().exprs[node]; + debug!("recurse_build: node={:?}", node); + Ok(match &node.kind { + // I dont know if handling of these 3 is correct + &ExprKind::Scope { value, .. } => self.recurse_build(value)?, + &ExprKind::PlaceTypeAscription { source, .. } | + &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + + &ExprKind::Literal { literal, .. } + | &ExprKind::StaticRef { literal, .. } => self.add_node(Node::Leaf(literal), node.span), + + // FIXME(generic_const_exprs) handle `from_hir_call` field + ExprKind::Call { fun, args, .. } => { + let fun = self.recurse_build(*fun)?; + + let mut new_args = Vec::::with_capacity(args.len()); + for &id in args.iter() { + new_args.push(self.recurse_build(id)?); + } + let new_args = self.tcx.arena.alloc_slice(&new_args); + self.add_node(Node::FunctionCall(fun, new_args), node.span) + }, + &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { + let lhs = self.recurse_build(lhs)?; + let rhs = self.recurse_build(rhs)?; + self.add_node(Node::Binop(op, lhs, rhs), node.span) + } + &ExprKind::Unary { op, arg } if Self::check_unop(op) => { + 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() { + match &self.body.stmts[id].kind { + thir::StmtKind::Let { .. } => return self.error( + Some(node.span), + "let statements are not supported in generic constants", + ).map(|never| never), + thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?), + } + }; + let stmts = self.tcx.arena.alloc_slice(&stmts); + 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!(), + // 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 { .. } + | ExprKind::VarRef { .. } // + | ExprKind::UpvarRef { .. } // we dont permit let stmts so... + | ExprKind::Closure { .. } + | ExprKind::Let { .. } // let expressions imply control flow + | ExprKind::Loop { .. } + | ExprKind::Assign { .. } + | ExprKind::LogicalOp { .. } + | ExprKind::Unary { .. } // + | ExprKind::Binary { .. } // we handle valid unary/binary ops above + | ExprKind::Break { .. } + | ExprKind::Continue { .. } + | ExprKind::If { .. } + | ExprKind::Pointer { .. } // dont know if this is correct + | ExprKind::ThreadLocalRef(_) + | ExprKind::LlvmInlineAsm { .. } + | ExprKind::InlineAsm { .. } + | ExprKind::Yield { .. } => return self.error(Some(node.span), "unsupported operation in generic constant").map(|never| never), + }) + } } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. @@ -547,8 +454,17 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - let body = tcx.mir_const(def).borrow(); - AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + debug!("mir_abstract_const: {:?}", def); + let body = tcx.thir_body(def); + + if body.0.borrow().exprs.is_empty() { + // type error in constant, there is no thir + return Err(ErrorReported); + } + + AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))? + .map(AbstractConstBuilder::build) + .transpose() } else { Ok(None) } @@ -599,6 +515,12 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } + Node::Block(stmts, opt_expr) => { + for id in stmts.iter().copied().chain(opt_expr) { + recurse(tcx, ct.subtree(id), f)?; + } + ControlFlow::CONTINUE + } Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 57b8a84300ff9..e64cc9e4b8f28 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,9 +844,10 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, _, ty) => self.visit_ty(ty), - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { - ControlFlow::CONTINUE - } + Node::Block(_, _) + | Node::Binop(..) + | Node::UnaryOp(..) + | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }) } else { ControlFlow::CONTINUE From 9b2913814b95e1b8f123da59ddecb1bc6b3813af Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 16:14:01 +0100 Subject: [PATCH 02/18] 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 e75f084e79e21..1158a9f4f8008 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 26e1c3e7b8cf4..7d0f6767900a3 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 4e11fefdc81f3..461ebba58d985 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 e64cc9e4b8f28..3527aede609a4 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(..) From 4483c2bdf64e213627998ac7e2340de7dafb3037 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 18:20:09 +0100 Subject: [PATCH 03/18] dont support blocks --- .../rustc_middle/src/mir/abstract_const.rs | 1 - compiler/rustc_privacy/src/lib.rs | 3 +- .../src/traits/const_evaluatable.rs | 51 ++++--------------- .../src/traits/object_safety.rs | 3 +- .../generic_const_exprs/unused_expr.stderr | 12 ++--- 5 files changed, 16 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs index 1158a9f4f8008..27849e4bdb0bf 100644 --- a/compiler/rustc_middle/src/mir/abstract_const.rs +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -17,7 +17,6 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), - Block(&'tcx [NodeId], Option), Cast(NodeId, Ty<'tcx>), } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 7d0f6767900a3..02ea34ea9743f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,8 +159,7 @@ where self.visit_const(leaf) } ACNode::Cast(_, ty) => self.visit_ty(ty), - ACNode::Block(_, _) - | ACNode::Binop(..) + 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 461ebba58d985..77fe1f514d901 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -102,8 +102,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Block(_, _) - | Node::Binop(_, _, _) + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }); @@ -288,10 +287,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.nodes[func].used = true; nodes.iter().for_each(|&n| self.nodes[n].used = true); } - Node::Block(stmts, opt_expr) => { - stmts.iter().for_each(|&id| self.nodes[id].used = true); - opt_expr.map(|e| self.nodes[e].used = true); - } Node::Cast(operand, _) => { self.nodes[operand].used = true; } @@ -378,22 +373,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.add_node(Node::UnaryOp(op, arg), node.span) }, - ExprKind::Block { body } => { - let mut stmts = Vec::with_capacity(body.stmts.len()); - for &id in body.stmts.iter() { - match &self.body.stmts[id].kind { - thir::StmtKind::Let { .. } => return self.error( - Some(node.span), - "let statements are not supported in generic constants", - ).map(|never| never), - thir::StmtKind::Expr { expr, .. } => stmts.push(self.recurse_build(*expr)?), - } - }; - let stmts = self.tcx.arena.alloc_slice(&stmts); - let opt_expr = body.expr.map(|e| self.recurse_build(e)).transpose()?; - self.add_node(Node::Block(stmts, opt_expr), node.span) - } - + // this is necessary so that the following compiles: + // + // ``` + // fn foo(a: [(); N + 1]) { + // bar::<{ N + 1 }>(); + // } + // ``` + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, // 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` @@ -411,6 +398,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Deref { .. } | ExprKind::Repeat { .. } | ExprKind::Array { .. } + | ExprKind::Block { .. } | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } @@ -521,12 +509,6 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } - Node::Block(stmts, opt_expr) => { - for id in stmts.iter().copied().chain(opt_expr) { - recurse(tcx, ct.subtree(id), f)?; - } - ControlFlow::CONTINUE - } Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -615,19 +597,8 @@ pub(super) fn try_unify<'tcx>( { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } - (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::Cast(..), _) | (Node::FunctionCall(..), _) | (Node::UnaryOp(..), _) | (Node::Binop(..), _) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 3527aede609a4..d9ea259155358 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,8 +844,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, ty) => self.visit_ty(ty), - Node::Block(_, _) - | Node::Binop(..) + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, }) diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr index 1687dbbcbe3f8..3da91b19a5ed9 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^-----^^^^^ - | | - | dead code + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -22,9 +18,7 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^------^^^^^ - | | - | dead code + | ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function From 47b16f4ac9145538e8375d2625181df281206be7 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 18:41:05 +0100 Subject: [PATCH 04/18] bless stderr --- .../array-size-in-generic-struct-param.full.stderr | 2 +- .../ui/const-generics/generic_const_exprs/closures.stderr | 2 +- .../generic_const_exprs/let-bindings.stderr | 8 ++------ src/test/ui/const-generics/issues/issue-67375.full.stderr | 6 +++--- .../ui/const-generics/issues/issue-67945-2.full.stderr | 3 +-- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index deb6f3bd12c1d..9b3c32a939779 100644 --- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,7 +10,7 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported projection + | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 9f0b7252e8326..95dae4ecc0431 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -4,7 +4,7 @@ error: overly complex generic constant LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported rvalue + | unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr index 5749defb3e12c..c9f847995223a 100644 --- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,9 +2,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function @@ -12,9 +10,7 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^-^^^^^^^^^^^^^ - | | - | unsupported statement + | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index 5386ef56a245a..d7b52063dc4db 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -2,9 +2,9 @@ error: overly complex generic constant --> $DIR/issue-67375.rs:7:17 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^^^----------^^^^^^^^^^^^ - | | - | unsupported rvalue + | ^^---------------^^^^^^^^ + | | + | unsupported operation in generic constant | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr index 118cf447c01e2..fe0351a829220 100644 --- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr @@ -5,11 +5,10 @@ LL | A: [(); { | _____________^ LL | | LL | | let x: Option> = None; - | | ---- unsupported rvalue LL | | LL | | 0 LL | | }], - | |_____^ + | |_____^ unsupported operation in generic constant, this may be supported in the future | = help: consider moving this anonymous constant into a `const` function From c170dcf04c62ffd79cbf28f340aaf6824e70f493 Mon Sep 17 00:00:00 2001 From: Ellen Date: Mon, 6 Sep 2021 23:18:25 +0100 Subject: [PATCH 05/18] tidy --- compiler/rustc_privacy/src/lib.rs | 6 ++-- .../src/traits/const_evaluatable.rs | 30 +++++++++---------- .../src/traits/object_safety.rs | 6 ++-- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 02ea34ea9743f..910249ecc479e 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -159,9 +159,9 @@ where self.visit_const(leaf) } ACNode::Cast(_, ty) => self.visit_ty(ty), - ACNode::Binop(..) - | ACNode::UnaryOp(..) - | ACNode::FunctionCall(_, _) => ControlFlow::CONTINUE, + 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 77fe1f514d901..7d69ec54bdf02 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -102,9 +102,9 @@ pub fn is_const_evaluatable<'cx, 'tcx>( ControlFlow::CONTINUE } - Node::Binop(_, _, _) - | Node::UnaryOp(_, _) - | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }); match failure_kind { @@ -348,8 +348,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` + // 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), @@ -381,10 +381,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // } // ``` ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, - // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // 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::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.add_node(Node::Cast(arg, node.ty), node.span) @@ -404,7 +404,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Field { .. } | ExprKind::ConstBlock { .. } | ExprKind::Adt(_) => return self.error( - Some(node.span), + Some(node.span), "unsupported operation in generic constant, this may be supported in the future", ).map(|never| never), @@ -417,7 +417,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Assign { .. } | ExprKind::LogicalOp { .. } | ExprKind::Unary { .. } // - | ExprKind::Binary { .. } // we handle valid unary/binary ops above + | ExprKind::Binary { .. } // we handle valid unary/binary ops above | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::If { .. } @@ -592,16 +592,14 @@ 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_operand, a_ty), Node::Cast(b_operand, b_ty)) - if (a_ty == b_ty) => - { + (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)) } // use this over `_ => false` to make adding variants to `Node` less error prone - (Node::Cast(..), _) - | (Node::FunctionCall(..), _) - | (Node::UnaryOp(..), _) - | (Node::Binop(..), _) + (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 d9ea259155358..63bd10994b1ac 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -844,9 +844,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( self.visit_const(leaf) } Node::Cast(_, ty) => self.visit_ty(ty), - Node::Binop(..) - | Node::UnaryOp(..) - | Node::FunctionCall(_, _) => ControlFlow::CONTINUE, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { ControlFlow::CONTINUE From 08e86440165619c57e0072eb742c7dad3cfd0950 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:05:24 +0100 Subject: [PATCH 06/18] move thir visitor to rustc_middle --- compiler/rustc_middle/src/thir.rs | 243 ++++++++++++++++++ .../rustc_mir_build/src/check_unsafety.rs | 2 +- compiler/rustc_mir_build/src/thir/mod.rs | 1 - compiler/rustc_mir_build/src/thir/visit.rs | 240 ----------------- 4 files changed, 244 insertions(+), 242 deletions(-) delete mode 100644 compiler/rustc_mir_build/src/thir/visit.rs diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 91a64e163e7c0..3012676c872bd 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -818,3 +818,246 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } } + +pub mod visit { + use super::*; + pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { + walk_expr(self, expr); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + walk_stmt(self, stmt); + } + + fn visit_block(&mut self, block: &Block) { + walk_block(self, block); + } + + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + walk_arm(self, arm); + } + + fn visit_pat(&mut self, pat: &Pat<'tcx>) { + walk_pat(self, pat); + } + + fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} + } + + pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { + use ExprKind::*; + match expr.kind { + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), + If { cond, then, else_opt, if_then_scope: _ } => { + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); + if let Some(else_expr) = else_opt { + visitor.visit_expr(&visitor.thir()[else_expr]); + } + } + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); + } + } + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), + Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); + } + } + Block { ref body } => visitor.visit_block(body), + Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), + Index { lhs, index } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); + } + VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Break { value, label: _ } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + Continue { label: _ } => {} + Return { value } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + ConstBlock { value } => visitor.visit_const(value), + Repeat { value, count } => { + visitor.visit_expr(&visitor.thir()[value]); + visitor.visit_const(count); + } + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); + } + } + Adt(box crate::thir::Adt { + ref fields, + ref base, + adt_def: _, + variant_index: _, + substs: _, + user_ty: _, + }) => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); + } + if let Some(base) = base { + visitor.visit_expr(&visitor.thir()[base.base]); + } + } + PlaceTypeAscription { source, user_ty: _ } + | ValueTypeAscription { source, user_ty: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } + Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), + StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { + use InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + visitor.visit_expr(&visitor.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + visitor.visit_expr(&visitor.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymStatic { def_id: _ } => {} + } + } + } + ThreadLocalRef(_) => {} + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); + } + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); + } + } + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + } + } + + pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { + match &stmt.kind { + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), + StmtKind::Let { + initializer, + remainder_scope: _, + init_scope: _, + ref pattern, + lint_level: _, + } => { + if let Some(init) = initializer { + visitor.visit_expr(&visitor.thir()[*init]); + } + visitor.visit_pat(pattern); + } + } + } + + pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); + } + if let Some(expr) = block.expr { + visitor.visit_expr(&visitor.thir()[expr]); + } + } + + pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), + Some(Guard::IfLet(ref pat, expr)) => { + visitor.visit_pat(pat); + visitor.visit_expr(&visitor.thir()[expr]); + } + None => {} + } + visitor.visit_pat(&arm.pattern); + visitor.visit_expr(&visitor.thir()[arm.body]); + } + + pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { + use PatKind::*; + match pat.kind.as_ref() { + AscribeUserType { subpattern, ascription: _ } + | Deref { subpattern } + | Binding { + subpattern: Some(subpattern), + mutability: _, + mode: _, + var: _, + ty: _, + is_primary: _, + name: _, + } => visitor.visit_pat(&subpattern), + Binding { .. } | Wild => {} + Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } + | Leaf { subpatterns } => { + for subpattern in subpatterns { + visitor.visit_pat(&subpattern.pattern); + } + } + Constant { value } => visitor.visit_const(value), + Range(range) => { + visitor.visit_const(range.lo); + visitor.visit_const(range.hi); + } + Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { + for subpattern in prefix { + visitor.visit_pat(&subpattern); + } + if let Some(pat) = slice { + visitor.visit_pat(pat); + } + for subpattern in suffix { + visitor.visit_pat(&subpattern); + } + } + Or { pats } => { + for pat in pats { + visitor.visit_pat(&pat); + } + } + }; + } +} diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 05a5fcef16ae5..0e82b18720142 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,5 +1,5 @@ use crate::build::ExprCategory; -use crate::thir::visit::{self, Visitor}; +use rustc_middle::thir::visit::{self, Visitor}; use rustc_errors::struct_span_err; use rustc_hir as hir; diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index e5123d8ef0c99..ddbe1b0b69c1e 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -11,4 +11,3 @@ crate mod cx; crate mod pattern; mod util; -pub mod visit; diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs deleted file mode 100644 index 51c371b872057..0000000000000 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ /dev/null @@ -1,240 +0,0 @@ -use rustc_middle::thir::{self, *}; -use rustc_middle::ty::Const; - -pub trait Visitor<'a, 'tcx: 'a>: Sized { - fn thir(&self) -> &'a Thir<'tcx>; - - fn visit_expr(&mut self, expr: &Expr<'tcx>) { - walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - walk_stmt(self, stmt); - } - - fn visit_block(&mut self, block: &Block) { - walk_block(self, block); - } - - fn visit_arm(&mut self, arm: &Arm<'tcx>) { - walk_arm(self, arm); - } - - fn visit_pat(&mut self, pat: &Pat<'tcx>) { - walk_pat(self, pat); - } - - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} -} - -pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { - use ExprKind::*; - match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } - Box { value } => visitor.visit_expr(&visitor.thir()[value]), - If { cond, then, else_opt, if_then_scope: _ } => { - visitor.visit_expr(&visitor.thir()[cond]); - visitor.visit_expr(&visitor.thir()[then]); - if let Some(else_expr) = else_opt { - visitor.visit_expr(&visitor.thir()[else_expr]); - } - } - Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(&visitor.thir()[fun]); - for &arg in &**args { - visitor.visit_expr(&visitor.thir()[arg]); - } - } - Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), - Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Cast { source } => visitor.visit_expr(&visitor.thir()[source]), - Use { source } => visitor.visit_expr(&visitor.thir()[source]), - NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), - Let { expr, .. } => { - visitor.visit_expr(&visitor.thir()[expr]); - } - Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { - visitor.visit_expr(&visitor.thir()[scrutinee]); - for &arm in &**arms { - visitor.visit_arm(&visitor.thir()[arm]); - } - } - Block { ref body } => visitor.visit_block(body), - Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), - Index { lhs, index } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[index]); - } - VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), - AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Break { value, label: _ } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - Continue { label: _ } => {} - Return { value } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - ConstBlock { value } => visitor.visit_const(value), - Repeat { value, count } => { - visitor.visit_expr(&visitor.thir()[value]); - visitor.visit_const(count); - } - Array { ref fields } | Tuple { ref fields } => { - for &field in &**fields { - visitor.visit_expr(&visitor.thir()[field]); - } - } - Adt(box thir::Adt { - ref fields, - ref base, - adt_def: _, - variant_index: _, - substs: _, - user_ty: _, - }) => { - for field in &**fields { - visitor.visit_expr(&visitor.thir()[field.expr]); - } - if let Some(base) = base { - visitor.visit_expr(&visitor.thir()[base.base]); - } - } - PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(&visitor.thir()[source]) - } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} - Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { - for op in &**operands { - use InlineAsmOperand::*; - match op { - In { expr, reg: _ } - | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), - SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(&visitor.thir()[*in_expr]); - if let Some(out_expr) = out_expr { - visitor.visit_expr(&visitor.thir()[*out_expr]); - } - } - Out { expr: None, reg: _, late: _ } - | Const { value: _, span: _ } - | SymStatic { def_id: _ } => {} - } - } - } - ThreadLocalRef(_) => {} - LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { - for &out_expr in &**outputs { - visitor.visit_expr(&visitor.thir()[out_expr]); - } - for &in_expr in &**inputs { - visitor.visit_expr(&visitor.thir()[in_expr]); - } - } - Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - } -} - -pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { - match &stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), - StmtKind::Let { - initializer, - remainder_scope: _, - init_scope: _, - ref pattern, - lint_level: _, - } => { - if let Some(init) = initializer { - visitor.visit_expr(&visitor.thir()[*init]); - } - visitor.visit_pat(pattern); - } - } -} - -pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { - for &stmt in &*block.stmts { - visitor.visit_stmt(&visitor.thir()[stmt]); - } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); - } -} - -pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} - } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); -} - -pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { - use PatKind::*; - match pat.kind.as_ref() { - AscribeUserType { subpattern, ascription: _ } - | Deref { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} - Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { - for subpattern in subpatterns { - visitor.visit_pat(&subpattern.pattern); - } - } - Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } - Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { - visitor.visit_pat(&subpattern); - } - if let Some(pat) = slice { - visitor.visit_pat(pat); - } - for subpattern in suffix { - visitor.visit_pat(&subpattern); - } - } - Or { pats } => { - for pat in pats { - visitor.visit_pat(&pat); - } - } - }; -} From fc63e9a8fb619ad79d2d24db06078652a2a6c1ba Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:05:59 +0100 Subject: [PATCH 07/18] dont build abstract const for monomorphic consts --- .../src/traits/const_evaluatable.rs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 7d69ec54bdf02..3e1719e08acfa 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -267,7 +267,36 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let builder = AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; - // FIXME non-constants should return Ok(None) + struct IsThirPolymorphic<'a, 'tcx> { + is_poly: bool, + thir: &'a thir::Thir<'tcx>, + tcx: TyCtxt<'tcx>, + } + + use thir::visit; + impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> { + fn thir(&self) -> &'a thir::Thir<'tcx> { + &self.thir + } + + fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { + self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly { + return; + } + visit::walk_expr(self, expr); + } + + fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { + self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx); + } + } + + let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; + visit::walk_expr(&mut is_poly_vis, &body[body_id]); + if is_poly_vis.is_poly == false { + return Ok(None); + } Ok(Some(builder)) } From 4cbcb0936a3ae16a99f977427a6a01646a1ed8dd Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:06:44 +0100 Subject: [PATCH 08/18] handle `ExprKind::NeverToAny` --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3e1719e08acfa..21423d415e3b9 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -418,8 +418,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { 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!(), // FIXME(generic_const_exprs) we want to support these ExprKind::AddressOf { .. } @@ -428,6 +426,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Repeat { .. } | ExprKind::Array { .. } | ExprKind::Block { .. } + | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } From 1f57f8b9032fa0f83aa59f634ac72f1e63a1cfa2 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 00:44:24 +0100 Subject: [PATCH 09/18] remove `WorkNode` --- .../src/traits/const_evaluatable.rs | 61 +++---------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 21423d415e3b9..c47b0c31ca01c 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -224,24 +224,13 @@ impl<'tcx> AbstractConst<'tcx> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct WorkNode<'tcx> { - node: Node<'tcx>, - span: Span, - used: bool, -} - struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body_id: thir::ExprId, + /// `Lrc` is used to avoid borrowck difficulties in `recurse_build` body: Lrc<&'a thir::Thir<'tcx>>, /// The current WIP node tree. - /// - /// We require all nodes to be used in the final abstract const, - /// so we store this here. Note that we also consider nodes as used - /// if they are mentioned in an assert, so some used nodes are never - /// actually reachable by walking the [`AbstractConst`]. - nodes: IndexVec>, + nodes: IndexVec>, } impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { @@ -301,30 +290,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(Some(builder)) } - fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId { - // Mark used nodes. - match node { - Node::Leaf(_) => (), - Node::Binop(_, lhs, rhs) => { - self.nodes[lhs].used = true; - self.nodes[rhs].used = true; - } - Node::UnaryOp(_, input) => { - self.nodes[input].used = true; - } - Node::FunctionCall(func, nodes) => { - self.nodes[func].used = true; - nodes.iter().for_each(|&n| self.nodes[n].used = true); - } - Node::Cast(operand, _) => { - self.nodes[operand].used = true; - } - } - - // Nodes start as unused. - self.nodes.push(WorkNode { node, span, used: false }) - } - /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; @@ -348,23 +313,17 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { /// encountering an unspported operation. fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> { debug!("Abstractconstbuilder::build: body={:?}", &*self.body); - let last = self.recurse_build(self.body_id)?; - self.nodes[last].used = true; + self.recurse_build(self.body_id)?; for n in self.nodes.iter() { - if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node { + if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n { // `AbstractConst`s should not contain any promoteds as they require references which // are not allowed. assert_eq!(ct.promoted, None); } } - // 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")?; - } - - Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node))) + Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter())) } fn recurse_build(&mut self, node: thir::ExprId) -> Result { @@ -380,7 +339,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // 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), + | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)), // FIXME(generic_const_exprs) handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { @@ -391,16 +350,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { new_args.push(self.recurse_build(id)?); } let new_args = self.tcx.arena.alloc_slice(&new_args); - self.add_node(Node::FunctionCall(fun, new_args), node.span) + self.nodes.push(Node::FunctionCall(fun, new_args)) }, &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { let lhs = self.recurse_build(lhs)?; let rhs = self.recurse_build(rhs)?; - self.add_node(Node::Binop(op, lhs, rhs), node.span) + self.nodes.push(Node::Binop(op, lhs, rhs)) } &ExprKind::Unary { op, arg } if Self::check_unop(op) => { let arg = self.recurse_build(arg)?; - self.add_node(Node::UnaryOp(op, arg), node.span) + self.nodes.push(Node::UnaryOp(op, arg)) }, // this is necessary so that the following compiles: // @@ -416,7 +375,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; - self.add_node(Node::Cast(arg, node.ty), node.span) + self.nodes.push(Node::Cast(arg, node.ty)) }, // FIXME(generic_const_exprs) we want to support these From 15101c8e95db6941f8c7d55fb301ad1b62748c7b Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 01:17:51 +0100 Subject: [PATCH 10/18] remove debug stmts --- compiler/rustc_mir_build/src/build/mod.rs | 2 -- compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 --- compiler/rustc_mir_build/src/thir/cx/mod.rs | 1 - compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 3 +-- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 390ce59cb489c..e931c686dde59 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -28,7 +28,6 @@ crate fn mir_built<'tcx>( if let Some(def) = def.try_upgrade(tcx) { return tcx.mir_built(def); } - debug!("mir_built: def={:?}", def); let mut body = mir_build(tcx, def); if def.const_param_did.is_some() { @@ -41,7 +40,6 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { - debug!("mir_build: def={:?}", def); let id = tcx.hir().local_def_id_to_hir_id(def.did); let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 70a5a9286b0b3..66005be05df75 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -149,9 +149,7 @@ impl<'tcx> Cx<'tcx> { } fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { - debug!("Expr::make_mirror_unadjusted: expr={:?}", expr); let expr_ty = self.typeck_results().expr_ty(expr); - debug!("Expr::make_mirror_unadjusted: expr_ty={:?}", expr_ty); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -764,7 +762,6 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::Err => unreachable!(), }; - debug!("Expr::make_mirror_unadjusted: finish"); Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5310efbccd655..5059dd939d92d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -20,7 +20,6 @@ crate fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam, ) -> (&'tcx Steal>, ExprId) { - debug!("thir_body: {:?}", owner_def); let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did))); let mut cx = Cx::new(tcx, owner_def); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index c47b0c31ca01c..4251dc5e93904 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -435,9 +435,8 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - debug!("mir_abstract_const: {:?}", def); + let body = tcx.thir_body(def); - if body.0.borrow().exprs.is_empty() { // type error in constant, there is no thir return Err(ErrorReported); From 406d2ab95de0e90f45e00f6c1be1e4e7912aa153 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 01:56:29 +0100 Subject: [PATCH 11/18] rename mir -> thir around abstract consts --- compiler/rustc_metadata/src/rmeta/decoder.rs | 9 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 8 +- compiler/rustc_metadata/src/rmeta/mod.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 1 - compiler/rustc_middle/src/mir/query.rs | 9 +- compiler/rustc_middle/src/query/mod.rs | 8 +- compiler/rustc_middle/src/thir.rs | 246 +----------------- .../src/{mir => thir}/abstract_const.rs | 0 compiler/rustc_middle/src/thir/visit.rs | 238 +++++++++++++++++ compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/ty/codec.rs | 5 +- compiler/rustc_mir_build/src/build/mod.rs | 4 +- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 2 +- .../rustc_query_impl/src/on_disk_cache.rs | 3 +- .../src/traits/const_evaluatable.rs | 12 +- .../src/traits/error_reporting/mod.rs | 2 +- .../src/traits/fulfill.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 10 +- .../src/traits/object_safety.rs | 2 +- .../src/traits/select/mod.rs | 2 +- 22 files changed, 287 insertions(+), 284 deletions(-) rename compiler/rustc_middle/src/{mir => thir}/abstract_const.rs (100%) create mode 100644 compiler/rustc_middle/src/thir/visit.rs diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index dd44e0cb1fa90..7ebea9ecc8ef2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; +use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; @@ -540,7 +541,7 @@ impl<'a, 'tcx> Decodable> for Span { } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) } @@ -1198,14 +1199,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } - fn get_mir_abstract_const( + fn get_thir_abstract_const( &self, tcx: TyCtxt<'tcx>, id: DefIndex, - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { self.root .tables - .mir_abstract_consts + .thir_abstract_consts .get(self, id) .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 41839c58021ab..1a147242619a7 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -117,7 +117,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) } mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) } promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) } - mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) } + thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d8b9a4799760e..60d7f0f85bb57 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, }; use rustc_middle::mir::interpret; +use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; @@ -344,7 +345,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Encodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) } @@ -1304,9 +1305,10 @@ impl EncodeContext<'a, 'tcx> { if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - let abstract_const = self.tcx.mir_abstract_const(def_id); + // FIXME this feels wrong to have in `encode_mir` + let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { - record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const); + record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); } } record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a487753f4628a..e59e9ad5d15d6 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; +use rustc_middle::thir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; @@ -305,7 +306,7 @@ define_tables! { mir: Table)>, mir_for_ctfe: Table)>, promoted_mir: Table>)>, - mir_abstract_consts: Table])>, + thir_abstract_consts: Table])>, const_defaults: Table>>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 38d4c5b4bd10e..ba8ccc71954ff 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; -pub mod abstract_const; pub mod coverage; mod generic_graph; pub mod generic_graphviz; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 1bdb6ca012b4a..a1c6a8bf99e79 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,6 +1,7 @@ //! Values computed by queries that use MIR. -use crate::mir::{abstract_const, Body, Promoted}; +use crate::mir::{Body, Promoted}; +use crate::thir::abstract_const; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -433,14 +434,14 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mir_abstract_const_opt_const_arg( + pub fn thir_abstract_const_opt_const_arg( self, def: ty::WithOptConstParam, ) -> Result]>, ErrorReported> { if let Some((did, param_did)) = def.as_const_arg() { - self.mir_abstract_const_of_const_arg((did, param_did)) + self.thir_abstract_const_of_const_arg((did, param_did)) } else { - self.mir_abstract_const(def.did) + self.thir_abstract_const(def.did) } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c93996162e3e3..19535195488b7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -295,17 +295,17 @@ rustc_queries! { } /// Try to build an abstract representation of the given constant. - query mir_abstract_const( + query thir_abstract_const( key: DefId - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for {}", tcx.def_path_str(key), } } /// Try to build an abstract representation of the given constant. - query mir_abstract_const_of_const_arg( + query thir_abstract_const_of_const_arg( key: (LocalDefId, DefId) - ) -> Result]>, ErrorReported> { + ) -> Result]>, ErrorReported> { desc { |tcx| "building an abstract representation for the const argument {}", diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3012676c872bd..8d6fd1e729d3b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; +pub mod abstract_const; +pub mod visit; + newtype_index! { /// An index to an [`Arm`] stored in [`Thir::arms`] #[derive(HashStable)] @@ -818,246 +821,3 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } } - -pub mod visit { - use super::*; - pub trait Visitor<'a, 'tcx: 'a>: Sized { - fn thir(&self) -> &'a Thir<'tcx>; - - fn visit_expr(&mut self, expr: &Expr<'tcx>) { - walk_expr(self, expr); - } - - fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { - walk_stmt(self, stmt); - } - - fn visit_block(&mut self, block: &Block) { - walk_block(self, block); - } - - fn visit_arm(&mut self, arm: &Arm<'tcx>) { - walk_arm(self, arm); - } - - fn visit_pat(&mut self, pat: &Pat<'tcx>) { - walk_pat(self, pat); - } - - fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} - } - - pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { - use ExprKind::*; - match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => { - visitor.visit_expr(&visitor.thir()[value]) - } - Box { value } => visitor.visit_expr(&visitor.thir()[value]), - If { cond, then, else_opt, if_then_scope: _ } => { - visitor.visit_expr(&visitor.thir()[cond]); - visitor.visit_expr(&visitor.thir()[then]); - if let Some(else_expr) = else_opt { - visitor.visit_expr(&visitor.thir()[else_expr]); - } - } - Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(&visitor.thir()[fun]); - for &arg in &**args { - visitor.visit_expr(&visitor.thir()[arg]); - } - } - Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), - Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Cast { source } => visitor.visit_expr(&visitor.thir()[source]), - Use { source } => visitor.visit_expr(&visitor.thir()[source]), - NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), - Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), - Let { expr, .. } => { - visitor.visit_expr(&visitor.thir()[expr]); - } - Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { - visitor.visit_expr(&visitor.thir()[scrutinee]); - for &arm in &**arms { - visitor.visit_arm(&visitor.thir()[arm]); - } - } - Block { ref body } => visitor.visit_block(body), - Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[rhs]); - } - Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), - Index { lhs, index } => { - visitor.visit_expr(&visitor.thir()[lhs]); - visitor.visit_expr(&visitor.thir()[index]); - } - VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), - AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), - Break { value, label: _ } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - Continue { label: _ } => {} - Return { value } => { - if let Some(value) = value { - visitor.visit_expr(&visitor.thir()[value]) - } - } - ConstBlock { value } => visitor.visit_const(value), - Repeat { value, count } => { - visitor.visit_expr(&visitor.thir()[value]); - visitor.visit_const(count); - } - Array { ref fields } | Tuple { ref fields } => { - for &field in &**fields { - visitor.visit_expr(&visitor.thir()[field]); - } - } - Adt(box crate::thir::Adt { - ref fields, - ref base, - adt_def: _, - variant_index: _, - substs: _, - user_ty: _, - }) => { - for field in &**fields { - visitor.visit_expr(&visitor.thir()[field.expr]); - } - if let Some(base) = base { - visitor.visit_expr(&visitor.thir()[base.base]); - } - } - PlaceTypeAscription { source, user_ty: _ } - | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(&visitor.thir()[source]) - } - Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} - Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), - StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { - for op in &**operands { - use InlineAsmOperand::*; - match op { - In { expr, reg: _ } - | Out { expr: Some(expr), reg: _, late: _ } - | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), - SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(&visitor.thir()[*in_expr]); - if let Some(out_expr) = out_expr { - visitor.visit_expr(&visitor.thir()[*out_expr]); - } - } - Out { expr: None, reg: _, late: _ } - | Const { value: _, span: _ } - | SymStatic { def_id: _ } => {} - } - } - } - ThreadLocalRef(_) => {} - LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { - for &out_expr in &**outputs { - visitor.visit_expr(&visitor.thir()[out_expr]); - } - for &in_expr in &**inputs { - visitor.visit_expr(&visitor.thir()[in_expr]); - } - } - Yield { value } => visitor.visit_expr(&visitor.thir()[value]), - } - } - - pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { - match &stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), - StmtKind::Let { - initializer, - remainder_scope: _, - init_scope: _, - ref pattern, - lint_level: _, - } => { - if let Some(init) = initializer { - visitor.visit_expr(&visitor.thir()[*init]); - } - visitor.visit_pat(pattern); - } - } - } - - pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { - for &stmt in &*block.stmts { - visitor.visit_stmt(&visitor.thir()[stmt]); - } - if let Some(expr) = block.expr { - visitor.visit_expr(&visitor.thir()[expr]); - } - } - - pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { - match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), - Some(Guard::IfLet(ref pat, expr)) => { - visitor.visit_pat(pat); - visitor.visit_expr(&visitor.thir()[expr]); - } - None => {} - } - visitor.visit_pat(&arm.pattern); - visitor.visit_expr(&visitor.thir()[arm.body]); - } - - pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { - use PatKind::*; - match pat.kind.as_ref() { - AscribeUserType { subpattern, ascription: _ } - | Deref { subpattern } - | Binding { - subpattern: Some(subpattern), - mutability: _, - mode: _, - var: _, - ty: _, - is_primary: _, - name: _, - } => visitor.visit_pat(&subpattern), - Binding { .. } | Wild => {} - Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } - | Leaf { subpatterns } => { - for subpattern in subpatterns { - visitor.visit_pat(&subpattern.pattern); - } - } - Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } - Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { - visitor.visit_pat(&subpattern); - } - if let Some(pat) = slice { - visitor.visit_pat(pat); - } - for subpattern in suffix { - visitor.visit_pat(&subpattern); - } - } - Or { pats } => { - for pat in pats { - visitor.visit_pat(&pat); - } - } - }; - } -} diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs similarity index 100% rename from compiler/rustc_middle/src/mir/abstract_const.rs rename to compiler/rustc_middle/src/thir/abstract_const.rs diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs new file mode 100644 index 0000000000000..21826ac89d3a9 --- /dev/null +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -0,0 +1,238 @@ +use super::*; +pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { + walk_expr(self, expr); + } + + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { + walk_stmt(self, stmt); + } + + fn visit_block(&mut self, block: &Block) { + walk_block(self, block); + } + + fn visit_arm(&mut self, arm: &Arm<'tcx>) { + walk_arm(self, arm); + } + + fn visit_pat(&mut self, pat: &Pat<'tcx>) { + walk_pat(self, pat); + } + + fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} +} + +pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { + use ExprKind::*; + match expr.kind { + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), + If { cond, then, else_opt, if_then_scope: _ } => { + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); + if let Some(else_expr) = else_opt { + visitor.visit_expr(&visitor.thir()[else_expr]); + } + } + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); + } + } + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), + Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Let { expr, .. } => { + visitor.visit_expr(&visitor.thir()[expr]); + } + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); + } + } + Block { ref body } => visitor.visit_block(body), + Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), + Index { lhs, index } => { + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); + } + VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Break { value, label: _ } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + Continue { label: _ } => {} + Return { value } => { + if let Some(value) = value { + visitor.visit_expr(&visitor.thir()[value]) + } + } + ConstBlock { value } => visitor.visit_const(value), + Repeat { value, count } => { + visitor.visit_expr(&visitor.thir()[value]); + visitor.visit_const(count); + } + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); + } + } + Adt(box crate::thir::Adt { + ref fields, + ref base, + adt_def: _, + variant_index: _, + substs: _, + user_ty: _, + }) => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); + } + if let Some(base) = base { + visitor.visit_expr(&visitor.thir()[base.base]); + } + } + PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { + visitor.visit_expr(&visitor.thir()[source]) + } + Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} + Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), + StaticRef { literal, def_id: _ } => visitor.visit_const(literal), + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { + use InlineAsmOperand::*; + match op { + In { expr, reg: _ } + | Out { expr: Some(expr), reg: _, late: _ } + | InOut { expr, reg: _, late: _ } + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), + SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + visitor.visit_expr(&visitor.thir()[*in_expr]); + if let Some(out_expr) = out_expr { + visitor.visit_expr(&visitor.thir()[*out_expr]); + } + } + Out { expr: None, reg: _, late: _ } + | Const { value: _, span: _ } + | SymStatic { def_id: _ } => {} + } + } + } + ThreadLocalRef(_) => {} + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); + } + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); + } + } + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), + } +} + +pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { + match &stmt.kind { + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]), + StmtKind::Let { + initializer, + remainder_scope: _, + init_scope: _, + ref pattern, + lint_level: _, + } => { + if let Some(init) = initializer { + visitor.visit_expr(&visitor.thir()[*init]); + } + visitor.visit_pat(pattern); + } + } +} + +pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); + } + if let Some(expr) = block.expr { + visitor.visit_expr(&visitor.thir()[expr]); + } +} + +pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { + match arm.guard { + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), + Some(Guard::IfLet(ref pat, expr)) => { + visitor.visit_pat(pat); + visitor.visit_expr(&visitor.thir()[expr]); + } + None => {} + } + visitor.visit_pat(&arm.pattern); + visitor.visit_expr(&visitor.thir()[arm.body]); +} + +pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { + use PatKind::*; + match pat.kind.as_ref() { + AscribeUserType { subpattern, ascription: _ } + | Deref { subpattern } + | Binding { + subpattern: Some(subpattern), + mutability: _, + mode: _, + var: _, + ty: _, + is_primary: _, + name: _, + } => visitor.visit_pat(&subpattern), + Binding { .. } | Wild => {} + Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => { + for subpattern in subpatterns { + visitor.visit_pat(&subpattern.pattern); + } + } + Constant { value } => visitor.visit_const(value), + Range(range) => { + visitor.visit_const(range.lo); + visitor.visit_const(range.hi); + } + Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { + for subpattern in prefix { + visitor.visit_pat(&subpattern); + } + if let Some(pat) = slice { + visitor.visit_pat(pat); + } + for subpattern in suffix { + visitor.visit_pat(&subpattern); + } + } + Or { pats } => { + for pat in pats { + visitor.visit_pat(&pat); + } + } + }; +} diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 74edb17fe32f1..e21a2d1034cdd 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -9,7 +9,7 @@ pub mod specialization_graph; mod structural_impls; use crate::infer::canonical::Canonical; -use crate::mir::abstract_const::NotConstEvaluatable; +use crate::thir::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; use crate::ty::{self, AdtKind, Ty, TyCtxt}; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 4edb6a327b035..8b70692960df9 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -12,6 +12,7 @@ use crate::mir::{ self, interpret::{AllocId, Allocation}, }; +use crate::thir; use crate::ty::subst::SubstsRef; use crate::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; @@ -362,7 +363,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) @@ -372,7 +373,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { Ok(decoder.tcx().arena.alloc_from_iter( (0..decoder.read_usize()?) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e931c686dde59..0ee740a646359 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -48,11 +48,11 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ match def { ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)); - tcx.ensure().mir_abstract_const_of_const_arg((did, const_param_did)); + tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did)); } ty::WithOptConstParam { did, const_param_did: None } => { tcx.ensure().thir_check_unsafety(did); - tcx.ensure().mir_abstract_const(did); + tcx.ensure().thir_abstract_const(did); } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 22abce65a4b7d..20232e635a2b8 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -307,7 +307,6 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 910249ecc479e..4dcb98ae7e960 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::{AccessLevel, AccessLevels}; -use rustc_middle::mir::abstract_const::Node as ACNode; use rustc_middle::span_bug; +use rustc_middle::thir::abstract_const::Node as ACNode; use rustc_middle::ty::fold::TypeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst}; diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 5c2803c67e73f..2903e220b3b07 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, interpret}; +use rustc_middle::thir; use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_query_system::dep_graph::DepContext; @@ -906,7 +907,7 @@ impl<'a, 'tcx> Decodable> } } -impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { +impl<'a, 'tcx> Decodable> for &'tcx [thir::abstract_const::Node<'tcx>] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4251dc5e93904..8c2a3d4abf41b 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -6,7 +6,7 @@ //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using -//! `mir_abstract_const` which can then be checked for structural equality with other +//! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; @@ -14,9 +14,9 @@ use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir; -use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir; +use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -197,7 +197,7 @@ impl<'tcx> AbstractConst<'tcx> { tcx: TyCtxt<'tcx>, uv: ty::Unevaluated<'tcx, ()>, ) -> Result>, ErrorReported> { - let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?; + let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; debug!("AbstractConst::new({:?}) = {:?}", uv, inner); Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) } @@ -421,10 +421,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. -pub(super) fn mir_abstract_const<'tcx>( +pub(super) fn thir_abstract_const<'tcx>( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, -) -> Result]>, ErrorReported> { +) -> Result]>, ErrorReported> { if tcx.features().generic_const_exprs { match tcx.def_kind(def.did) { // FIXME(generic_const_exprs): We currently only do this for anonymous constants, @@ -435,7 +435,7 @@ pub(super) fn mir_abstract_const<'tcx>( DefKind::AnonConst => (), _ => return Ok(None), } - + let body = tcx.thir_body(def); if body.0.borrow().exprs.is_empty() { // type error in constant, there is no thir diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9ce6c58a0f1df..4d3a8324d7987 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{ diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 18abcc72bcee8..b376f42929249 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 44c675243838a..ef208c44471cb 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, - mir_abstract_const: |tcx, def_id| { + thir_abstract_const: |tcx, def_id| { let def_id = def_id.expect_local(); if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { - tcx.mir_abstract_const_of_const_arg(def) + tcx.thir_abstract_const_of_const_arg(def) } else { - const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) } }, - mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { - const_evaluatable::mir_abstract_const( + thir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::thir_abstract_const( tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 63bd10994b1ac..e001bb7445e8c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // // This shouldn't really matter though as we can't really use any // constants which are not considered const evaluatable. - use rustc_middle::mir::abstract_const::Node; + use rustc_middle::thir::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) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 22013fb79cf79..01a38ffa7d0b2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -34,8 +34,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; -use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::thir::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; From 79be0802557089b408776ba161d95f8f4b5d0683 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 03:02:12 +0100 Subject: [PATCH 12/18] remove comment --- compiler/rustc_trait_selection/src/traits/const_evaluatable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8c2a3d4abf41b..1aaed7cade281 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Repeat { .. } | ExprKind::Array { .. } | ExprKind::Block { .. } - | ExprKind::NeverToAny { .. } // I dont think we can get this without adt construction + | ExprKind::NeverToAny { .. } | ExprKind::Tuple { .. } | ExprKind::Index { .. } | ExprKind::Field { .. } From 955e2b2da0ca29042206a56060baa820a2d961e7 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 12:05:11 +0100 Subject: [PATCH 13/18] nits --- compiler/rustc_middle/src/mir/query.rs | 13 ------- .../rustc_middle/src/thir/abstract_const.rs | 23 +++++++++-- compiler/rustc_middle/src/thir/visit.rs | 6 ++- .../src/traits/const_evaluatable.rs | 39 +++++++++---------- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a1c6a8bf99e79..567f65e83d98c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,7 +1,6 @@ //! Values computed by queries that use MIR. use crate::mir::{Body, Promoted}; -use crate::thir::abstract_const; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::vec_map::VecMap; @@ -432,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> { self.mir_for_ctfe(def.did) } } - - #[inline] - pub fn thir_abstract_const_opt_const_arg( - self, - def: ty::WithOptConstParam, - ) -> Result]>, ErrorReported> { - if let Some((did, param_did)) = def.as_const_arg() { - self.thir_abstract_const_of_const_arg((did, param_did)) - } else { - self.thir_abstract_const(def.did) - } - } } diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index 27849e4bdb0bf..00f1390eb4d4e 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -1,6 +1,7 @@ //! A subset of a mir body used for const evaluatability checking. use crate::mir; -use crate::ty::{self, Ty}; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_errors::ErrorReported; rustc_index::newtype_index! { /// An index into an `AbstractConst`. @@ -22,13 +23,13 @@ pub enum Node<'tcx> { #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum NotConstEvaluatable { - Error(rustc_errors::ErrorReported), + Error(ErrorReported), MentionsInfer, MentionsParam, } -impl From for NotConstEvaluatable { - fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable { +impl From for NotConstEvaluatable { + fn from(e: ErrorReported) -> NotConstEvaluatable { NotConstEvaluatable::Error(e) } } @@ -36,3 +37,17 @@ impl From for NotConstEvaluatable { TrivialTypeFoldableAndLiftImpls! { NotConstEvaluatable, } + +impl<'tcx> TyCtxt<'tcx> { + #[inline] + pub fn thir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam, + ) -> Result]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.thir_abstract_const_of_const_arg((did, param_did)) + } else { + self.thir_abstract_const(def.did) + } + } +} diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 21826ac89d3a9..7fc15e02fcd30 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -1,4 +1,8 @@ -use super::*; +use super::{ + Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, +}; +use rustc_middle::ty::Const; + pub trait Visitor<'a, 'tcx: 'a>: Sized { fn thir(&self) -> &'a Thir<'tcx>; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 1aaed7cade281..1845b9d1314b1 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -8,7 +8,6 @@ //! In this case we try to build an abstract representation of this constant using //! `thir_abstract_const` which can then be checked for structural equality with other //! generic constants mentioned in the `caller_bounds` of the current environment. -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorReported; use rustc_hir::def::DefKind; use rustc_index::vec::IndexVec; @@ -227,8 +226,7 @@ impl<'tcx> AbstractConst<'tcx> { struct AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, body_id: thir::ExprId, - /// `Lrc` is used to avoid borrowck difficulties in `recurse_build` - body: Lrc<&'a thir::Thir<'tcx>>, + body: &'a thir::Thir<'tcx>, /// The current WIP node tree. nodes: IndexVec>, } @@ -253,8 +251,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { tcx: TyCtxt<'tcx>, (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId), ) -> Result>, ErrorReported> { - let builder = - AbstractConstBuilder { tcx, body_id, body: Lrc::new(body), nodes: IndexVec::new() }; + let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() }; struct IsThirPolymorphic<'a, 'tcx> { is_poly: bool, @@ -328,7 +325,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn recurse_build(&mut self, node: thir::ExprId) -> Result { use thir::ExprKind; - let node = &self.body.clone().exprs[node]; + let node = &self.body.exprs[node]; debug!("recurse_build: node={:?}", node); Ok(match &node.kind { // I dont know if handling of these 3 is correct @@ -338,10 +335,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // subtle: associated consts are literals this arm handles // `::ASSOC` as well as `12` - &ExprKind::Literal { literal, .. } - | &ExprKind::StaticRef { literal, .. } => self.nodes.push(Node::Leaf(literal)), + &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - // FIXME(generic_const_exprs) handle `from_hir_call` field + // FIXME(generic_const_exprs): Handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; @@ -361,7 +357,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let arg = self.recurse_build(arg)?; self.nodes.push(Node::UnaryOp(op, arg)) }, - // this is necessary so that the following compiles: + // This is necessary so that the following compiles: // // ``` // fn foo(a: [(); N + 1]) { @@ -369,16 +365,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // } // ``` ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, - // ExprKind::Use happens when a `hir::ExprKind::Cast` is a + // `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` + // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) &ExprKind::Use { source} | &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(arg, node.ty)) }, - // FIXME(generic_const_exprs) we want to support these + // FIXME(generic_const_exprs): We may want to support these. ExprKind::AddressOf { .. } | ExprKind::Borrow { .. } | ExprKind::Deref { .. } @@ -390,21 +386,24 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | ExprKind::Index { .. } | ExprKind::Field { .. } | ExprKind::ConstBlock { .. } - | ExprKind::Adt(_) => return self.error( + | ExprKind::Adt(_) => 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... + // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen + | ExprKind::VarRef { .. } + | ExprKind::UpvarRef { .. } | ExprKind::Closure { .. } | ExprKind::Let { .. } // let expressions imply control flow | ExprKind::Loop { .. } | ExprKind::Assign { .. } + | ExprKind::StaticRef { .. } | ExprKind::LogicalOp { .. } - | ExprKind::Unary { .. } // - | ExprKind::Binary { .. } // we handle valid unary/binary ops above + // we handle valid unary/binary ops above + | ExprKind::Unary { .. } + | ExprKind::Binary { .. } | ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::If { .. } @@ -415,7 +414,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { | 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), + | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?, }) } } From 8c7954dc425e8c6ee4aaaf14be5015ad8982d540 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:24:04 +0100 Subject: [PATCH 14/18] add a `CastKind` to `Node::Cast` --- .../rustc_middle/src/thir/abstract_const.rs | 10 +++++++++- compiler/rustc_privacy/src/lib.rs | 2 +- .../src/traits/const_evaluatable.rs | 17 ++++++++++------- .../src/traits/object_safety.rs | 2 +- .../abstract-consts-as-cast-5.rs | 11 +++++++++++ .../abstract-consts-as-cast-5.stderr | 10 ++++++++++ 6 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs index 00f1390eb4d4e..f80beadd6e551 100644 --- a/compiler/rustc_middle/src/thir/abstract_const.rs +++ b/compiler/rustc_middle/src/thir/abstract_const.rs @@ -11,6 +11,14 @@ rustc_index::newtype_index! { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub enum CastKind { + /// thir::ExprKind::As + As, + /// thir::ExprKind::Use + Use, +} + /// A node of an `AbstractConst`. #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] pub enum Node<'tcx> { @@ -18,7 +26,7 @@ pub enum Node<'tcx> { Binop(mir::BinOp, NodeId, NodeId), UnaryOp(mir::UnOp, NodeId), FunctionCall(NodeId, &'tcx [NodeId]), - Cast(NodeId, Ty<'tcx>), + Cast(CastKind, 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 4dcb98ae7e960..391e43054239d 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::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 1845b9d1314b1..26c71a0f53921 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::mir; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::thir; -use rustc_middle::thir::abstract_const::{Node, NodeId, NotConstEvaluatable}; +use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable}; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_session::lint; @@ -91,7 +91,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; @@ -368,10 +368,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // `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`. (untested) - &ExprKind::Use { source} - | &ExprKind::Cast { source } => { + &ExprKind::Use { source } => { let arg = self.recurse_build(source)?; - self.nodes.push(Node::Cast(arg, node.ty)) + self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) + }, + &ExprKind::Cast { source } => { + let arg = self.recurse_build(source)?; + self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) }, // FIXME(generic_const_exprs): We may want to support these. @@ -494,7 +497,7 @@ where recurse(tcx, ct.subtree(func), f)?; args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) } - Node::Cast(operand, _) => recurse(tcx, ct.subtree(operand), f), + Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f), } } @@ -577,7 +580,7 @@ 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_operand, a_ty), Node::Cast(b_operand, b_ty)) if (a_ty == b_ty) => { + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } // use this over `_ => false` to make adding variants to `Node` less error prone diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index e001bb7445e8c..70cdbe4d5c7cb 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::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { ControlFlow::CONTINUE } diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs new file mode 100644 index 0000000000000..b3cde61f5e7f2 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs @@ -0,0 +1,11 @@ +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +fn foo(a: [(); N as usize]) { + bar::<{ N as usize as usize }>(); + //~^ error: unconstrained generic constant +} + +fn bar() {} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr new file mode 100644 index 0000000000000..d48b639dbdee3 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/abstract-consts-as-cast-5.rs:5:11 + | +LL | bar::<{ N as usize as usize }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:` + +error: aborting due to previous error + From 3212734bd744719dc197a19902d083c591670ab1 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:36:50 +0100 Subject: [PATCH 15/18] resolve `from_hir_call` FIXME --- .../src/traits/const_evaluatable.rs | 1 - .../abstract-consts-as-cast-5.rs | 2 +- .../unify-op-with-fn-call.rs | 23 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 26c71a0f53921..702b5a508b744 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -337,7 +337,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - // FIXME(generic_const_exprs): Handle `from_hir_call` field ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs index b3cde61f5e7f2..916d60c0e0def 100644 --- a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs +++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs @@ -8,4 +8,4 @@ fn foo(a: [(); N as usize]) { fn bar() {} -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs new file mode 100644 index 0000000000000..abbeb2c928ed4 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -0,0 +1,23 @@ +#![feature(generic_const_exprs, adt_const_params, const_trait_impl)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +struct Foo(u8); + +impl const std::ops::Add for Foo { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + self + } +} + +struct Evaluatable; + +fn foo(a: Evaluatable<{ N + N }>) { + bar::<{ std::ops::Add::add(N, N) }>(); +} + +fn bar() {} + +fn main() {} From cd2915eddb446df2d89922d3b68080d091dc247e Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 13:49:31 +0100 Subject: [PATCH 16/18] fmt --- .../rustc_trait_selection/src/traits/const_evaluatable.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 702b5a508b744..4f178f777afb2 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -579,7 +579,9 @@ 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_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) if (a_ty == b_ty) && (a_kind == b_kind) => { + (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty)) + if (a_ty == b_ty) && (a_kind == b_kind) => + { try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand)) } // use this over `_ => false` to make adding variants to `Node` less error prone From fd9bb30ab8fc65da735272f9cfd55d1368da9069 Mon Sep 17 00:00:00 2001 From: Ellen Date: Tue, 7 Sep 2021 14:27:07 +0100 Subject: [PATCH 17/18] CI please --- .../const-generics/generic_const_exprs/unify-op-with-fn-call.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs index abbeb2c928ed4..bb054bec6b6c2 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -1,3 +1,4 @@ +// check-pass #![feature(generic_const_exprs, adt_const_params, const_trait_impl)] #![allow(incomplete_features)] From 8295e4a6cfb12ce74c480172c2854f76d1428b8b Mon Sep 17 00:00:00 2001 From: Ellen Date: Thu, 9 Sep 2021 15:43:59 +0100 Subject: [PATCH 18/18] add test for builtin types N + N unifying with fn call --- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../src/traits/const_evaluatable.rs | 13 ++++++++++--- .../generic_const_exprs/unify-op-with-fn-call.rs | 13 ++++++++++++- .../unify-op-with-fn-call.stderr | 10 ++++++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 60d7f0f85bb57..97c0bca5d911c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1305,7 +1305,7 @@ impl EncodeContext<'a, 'tcx> { if encode_const { record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); - // FIXME this feels wrong to have in `encode_mir` + // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` let abstract_const = self.tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 4f178f777afb2..24fa5007f1ecd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -267,10 +267,16 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); - if self.is_poly { - return; + if self.is_poly == false { + visit::walk_expr(self, expr) + } + } + + fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { + self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); + if self.is_poly == false { + visit::walk_pat(self, pat); } - visit::walk_expr(self, expr); } fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { @@ -280,6 +286,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; visit::walk_expr(&mut is_poly_vis, &body[body_id]); + debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); if is_poly_vis.is_poly == false { return Ok(None); } diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs index bb054bec6b6c2..c0404d35b0887 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs @@ -1,7 +1,7 @@ -// check-pass #![feature(generic_const_exprs, adt_const_params, const_trait_impl)] #![allow(incomplete_features)] +// test `N + N` unifies with explicit function calls for non-builtin-types #[derive(PartialEq, Eq)] struct Foo(u8); @@ -21,4 +21,15 @@ fn foo(a: Evaluatable<{ N + N }>) { fn bar() {} +// test that `N + N` unifies with explicit function calls for builin-types +struct Evaluatable2; + +fn foo2(a: Evaluatable2<{ N + N }>) { + bar2::<{ std::ops::Add::add(N, N) }>(); + //~^ error: unconstrained generic constant + // FIXME(generic_const_exprs) make this not an error +} + +fn bar2() {} + fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr new file mode 100644 index 0000000000000..d18c7916f5f6f --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/unify-op-with-fn-call.rs:28:12 + | +LL | bar2::<{ std::ops::Add::add(N, N) }>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:` + +error: aborting due to previous error +