From d0ae2c814232bcffd83bbb2e3653dfb8c8746975 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 24 Nov 2016 18:25:59 +0100 Subject: [PATCH] Refactor inlined items some more They don't implement FnLikeNode anymore, instead are handled differently further up in the call tree. Also, keep less information (just def ids for the args). --- src/librustc/hir/map/blocks.rs | 14 ------- src/librustc/hir/mod.rs | 6 +++ src/librustc/middle/cstore.rs | 69 +++++++++++--------------------- src/librustc_const_eval/eval.rs | 47 +++++++++++++--------- src/librustc_metadata/encoder.rs | 6 +-- src/librustc_passes/consts.rs | 51 +++++++++++++---------- 6 files changed, 91 insertions(+), 102 deletions(-) diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 8116f7fd245a9..068e7ed8624ed 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -25,7 +25,6 @@ use hir as ast; use hir::map::{self, Node}; use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; -use middle::cstore::{InlinedItem, InlinedItemKind}; use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; use syntax_pos::Span; @@ -152,7 +151,6 @@ impl<'a> FnLikeNode<'a> { map::NodeTraitItem(tm) => tm.is_fn_like(), map::NodeImplItem(_) => true, map::NodeExpr(e) => e.is_fn_like(), - map::NodeInlinedItem(ii) => ii.is_fn(), _ => false }; if fn_like { @@ -175,21 +173,12 @@ impl<'a> FnLikeNode<'a> { } pub fn body(self) -> ast::ExprId { - if let map::NodeInlinedItem(ii) = self.node { - return ast::ExprId(ii.body.id); - } self.handle(|i: ItemFnParts<'a>| i.body, |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _| body, |c: ClosureParts<'a>| c.body) } pub fn decl(self) -> &'a FnDecl { - if let map::NodeInlinedItem(&InlinedItem { - kind: InlinedItemKind::Fn(ref decl), - .. - }) = self.node { - return &decl; - } self.handle(|i: ItemFnParts<'a>| &*i.decl, |_, _, sig: &'a ast::MethodSig, _, _, _, _| &sig.decl, |c: ClosureParts<'a>| c.decl) @@ -208,9 +197,6 @@ impl<'a> FnLikeNode<'a> { } pub fn constness(self) -> ast::Constness { - if let map::NodeInlinedItem(..) = self.node { - return ast::Constness::Const; - } match self.kind() { FnKind::ItemFn(_, _, _, constness, ..) => { constness diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f66e6788ee7fa..4fd8f96ba046a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -870,6 +870,12 @@ pub struct Expr { pub attrs: ThinVec, } +impl Expr { + pub fn expr_id(&self) -> ExprId { + ExprId(self.id) + } +} + impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "expr({}: {})", self.id, print::expr_to_string(self)) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 12e7735e4c0df..022cca5e7f281 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -43,7 +43,7 @@ use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_back::target::Target; use hir; -use hir::intravisit::{self, Visitor}; +use hir::intravisit::Visitor; use rustc_back::PanicStrategy; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; @@ -140,54 +140,47 @@ pub struct NativeLibrary { pub struct InlinedItem { pub def_id: DefId, pub body: P, - pub kind: InlinedItemKind, -} - -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum InlinedItemKind { - Const(P), - Fn(P) + pub const_fn_args: Vec, } /// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving /// a crate; it then gets read as an InlinedItem. -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)] pub struct InlinedItemRef<'a> { pub def_id: DefId, pub body: &'a hir::Expr, - pub kind: InlinedItemKindRef<'a>, + pub const_fn_args: Vec, } -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)] -pub enum InlinedItemKindRef<'a> { - Const(&'a hir::Ty), - Fn(&'a hir::FnDecl) +fn get_fn_args(tcx: TyCtxt, decl: &hir::FnDecl) -> Vec { + decl.inputs.iter().map(|arg| tcx.expect_def(arg.pat.id).def_id()).collect() } impl<'a> InlinedItemRef<'a> { - pub fn from_item<'ast: 'a>(def_id: DefId, + pub fn from_item<'b, 'tcx>(def_id: DefId, item: &'a hir::Item, - map: &hir_map::Map<'ast>) + tcx: TyCtxt<'b, 'a, 'tcx>) -> InlinedItemRef<'a> { - let (body, kind) = match item.node { + let (body, args) = match item.node { hir::ItemFn(ref decl, _, _, _, _, body_id) => - (map.expr(body_id), InlinedItemKindRef::Fn(&decl)), - hir::ItemConst(ref ty, ref body) => (&**body, InlinedItemKindRef::Const(ty)), + (tcx.map.expr(body_id), get_fn_args(tcx, decl)), + hir::ItemConst(_, ref body) => (&**body, Vec::new()), _ => bug!("InlinedItemRef::from_item wrong kind") }; InlinedItemRef { def_id: def_id, body: body, - kind: kind + const_fn_args: args } } pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, - _map: &hir_map::Map) + _tcx: TyCtxt) -> InlinedItemRef<'a> { - let (body, kind) = match item.node { - hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)), + let (body, args) = match item.node { + hir::ConstTraitItem(_, Some(ref body)) => + (&**body, Vec::new()), hir::ConstTraitItem(_, None) => { bug!("InlinedItemRef::from_trait_item called for const without body") }, @@ -196,24 +189,25 @@ impl<'a> InlinedItemRef<'a> { InlinedItemRef { def_id: def_id, body: body, - kind: kind + const_fn_args: args } } - pub fn from_impl_item<'ast: 'a>(def_id: DefId, + pub fn from_impl_item<'b, 'tcx>(def_id: DefId, item: &'a hir::ImplItem, - map: &hir_map::Map<'ast>) + tcx: TyCtxt<'b, 'a, 'tcx>) -> InlinedItemRef<'a> { - let (body, kind) = match item.node { + let (body, args) = match item.node { hir::ImplItemKind::Method(ref sig, body_id) => - (map.expr(body_id), InlinedItemKindRef::Fn(&sig.decl)), - hir::ImplItemKind::Const(ref ty, ref body) => (&**body, InlinedItemKindRef::Const(ty)), + (tcx.map.expr(body_id), get_fn_args(tcx, &sig.decl)), + hir::ImplItemKind::Const(_, ref body) => + (&**body, Vec::new()), _ => bug!("InlinedItemRef::from_impl_item wrong kind") }; InlinedItemRef { def_id: def_id, body: body, - kind: kind + const_fn_args: args } } @@ -221,10 +215,6 @@ impl<'a> InlinedItemRef<'a> { where V: Visitor<'a> { visitor.visit_expr(&self.body); - match self.kind { - InlinedItemKindRef::Const(ty) => visitor.visit_ty(ty), - InlinedItemKindRef::Fn(decl) => intravisit::walk_fn_decl(visitor, decl) - } } } @@ -233,17 +223,6 @@ impl InlinedItem { where V: Visitor<'ast> { visitor.visit_expr(&self.body); - match self.kind { - InlinedItemKind::Const(ref ty) => visitor.visit_ty(ty), - InlinedItemKind::Fn(ref decl) => intravisit::walk_fn_decl(visitor, decl) - } - } - - pub fn is_fn(&self) -> bool { - match self.kind { - InlinedItemKind::Const(_) => false, - InlinedItemKind::Fn(_) => true - } } } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 754bb53c29e55..6e074d8f53b37 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -17,7 +17,7 @@ use self::EvalHint::*; use rustc::hir::map as ast_map; use rustc::hir::map::blocks::FnLikeNode; -use rustc::middle::cstore::{InlinedItem, InlinedItemKind}; +use rustc::middle::cstore::InlinedItem; use rustc::traits; use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; @@ -142,9 +142,8 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let mut used_substs = false; let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - Some((&InlinedItem { body: ref const_expr, - kind: InlinedItemKind::Const(ref ty), .. }, _)) => { - Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty))) + Some((&InlinedItem { body: ref const_expr, .. }, _)) => { + Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id)))) } _ => None }; @@ -166,8 +165,9 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } else { expr_ty } - } - _ => expr_ty + }, + Some(Def::Const(..)) => expr_ty, + _ => None }; // If we used the substitutions, particularly to choose an impl // of a trait-associated const, don't cache that, because the next @@ -195,23 +195,29 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return None; } - let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) { - Some((&InlinedItem { kind: InlinedItemKind::Fn(_), .. }, node_id)) => Some(node_id), - _ => None - }; + let fn_id = tcx.sess.cstore.maybe_get_item_ast(tcx, def_id).map(|t| t.1); tcx.extern_const_fns.borrow_mut().insert(def_id, fn_id.unwrap_or(ast::DUMMY_NODE_ID)); fn_id } +pub enum ConstFnNode<'tcx> { + Local(FnLikeNode<'tcx>), + Inlined(&'tcx InlinedItem) +} + pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option> + -> Option> { let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) { node_id } else { if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) { - fn_id + if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) { + return Some(ConstFnNode::Inlined(ii)); + } else { + bug!("Got const fn from external crate, but it's not inlined") + } } else { return None; } @@ -223,7 +229,7 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI }; if fn_like.constness() == hir::Constness::Const { - Some(fn_like) + Some(ConstFnNode::Local(fn_like)) } else { None } @@ -858,16 +864,19 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), callee => signal!(e, CallOn(callee)), }; - let (decl, body_id) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { - (fn_like.decl(), fn_like.body()) - } else { - signal!(e, NonConstPath) + let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) { + Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()), + Some(ConstFnNode::Local(fn_like)) => + (fn_like.decl().inputs.iter() + .map(|arg| tcx.expect_def(arg.pat.id).def_id()).collect(), + fn_like.body()), + None => signal!(e, NonConstPath), }; let result = tcx.map.expr(body_id); - assert_eq!(decl.inputs.len(), args.len()); + assert_eq!(arg_defs.len(), args.len()); let mut call_args = DefIdMap(); - for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) { + for (arg, arg_expr) in arg_defs.iter().zip(args.iter()) { let arg_hint = ty_hint.erase_hint(); let arg_val = eval_const_expr_partial( tcx, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3584e6e68fe4c..67b0be0dfcdac 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -521,7 +521,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // (InlinedItemRef::from_trait_item panics otherwise) let trait_def_id = trait_item.container.id(); Some(self.encode_inlined_item( - InlinedItemRef::from_trait_item(trait_def_id, ast_item, &tcx.map) + InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx) )) } else { None @@ -594,7 +594,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ast: if ast { Some(self.encode_inlined_item( - InlinedItemRef::from_impl_item(impl_def_id, ast_item, &tcx.map) + InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx) )) } else { None @@ -826,7 +826,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::ItemConst(..) | hir::ItemFn(_, _, hir::Constness::Const, ..) => { Some(self.encode_inlined_item( - InlinedItemRef::from_item(def_id, item, &tcx.map) + InlinedItemRef::from_item(def_id, item, tcx) )) } _ => None, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 6b791e6907ca6..94110ca58f856 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -27,7 +27,7 @@ use rustc::dep_graph::DepNode; use rustc::ty::cast::CastKind; use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs}; -use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id}; +use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id}; use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}; use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}; use rustc_const_eval::ErrKind::UnresolvedPath; @@ -180,30 +180,39 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { /// Returns true if the call is to a const fn or method. fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool { - if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) { - let node_id = fn_like.body().node_id(); - let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) { - Entry::Occupied(entry) => Some(*entry.get()), - _ => None - }; + match lookup_const_fn_by_id(self.tcx, def_id) { + Some(ConstFnNode::Local(fn_like)) => { + let qualif = self.fn_like(fn_like.kind(), + fn_like.decl(), + fn_like.body(), + fn_like.span(), + fn_like.id()); + + self.add_qualif(qualif); - let qualif = qualif.unwrap_or_else(|| { - self.fn_like(fn_like.kind(), - fn_like.decl(), - fn_like.body(), - fn_like.span(), - fn_like.id()) - }); + if ret_ty.type_contents(self.tcx).interior_unsafe() { + self.add_qualif(ConstQualif::MUTABLE_MEM); + } - self.add_qualif(qualif); + true + }, + Some(ConstFnNode::Inlined(ii)) => { + let node_id = ii.body.id; - if ret_ty.type_contents(self.tcx).interior_unsafe() { - self.add_qualif(ConstQualif::MUTABLE_MEM); - } + let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) { + Entry::Occupied(entry) => *entry.get(), + _ => bug!("const qualif entry missing for inlined item") + }; + + self.add_qualif(qualif); + + if ret_ty.type_contents(self.tcx).interior_unsafe() { + self.add_qualif(ConstQualif::MUTABLE_MEM); + } - true - } else { - false + true + }, + None => false } }