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).
This commit is contained in:
parent
dd1491cfbe
commit
d0ae2c8142
6 changed files with 91 additions and 102 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -870,6 +870,12 @@ pub struct Expr {
|
|||
pub attrs: ThinVec<Attribute>,
|
||||
}
|
||||
|
||||
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))
|
||||
|
|
|
|||
|
|
@ -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<hir::Expr>,
|
||||
pub kind: InlinedItemKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum InlinedItemKind {
|
||||
Const(P<hir::Ty>),
|
||||
Fn(P<hir::FnDecl>)
|
||||
pub const_fn_args: Vec<DefId>,
|
||||
}
|
||||
|
||||
/// 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<DefId>,
|
||||
}
|
||||
|
||||
#[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<DefId> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<FnLikeNode<'tcx>>
|
||||
-> Option<ConstFnNode<'tcx>>
|
||||
{
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
let qualif = qualif.unwrap_or_else(|| {
|
||||
self.fn_like(fn_like.kind(),
|
||||
fn_like.decl(),
|
||||
fn_like.body(),
|
||||
fn_like.span(),
|
||||
fn_like.id())
|
||||
});
|
||||
self.add_qualif(qualif);
|
||||
|
||||
self.add_qualif(qualif);
|
||||
if ret_ty.type_contents(self.tcx).interior_unsafe() {
|
||||
self.add_qualif(ConstQualif::MUTABLE_MEM);
|
||||
}
|
||||
|
||||
if ret_ty.type_contents(self.tcx).interior_unsafe() {
|
||||
self.add_qualif(ConstQualif::MUTABLE_MEM);
|
||||
}
|
||||
true
|
||||
},
|
||||
Some(ConstFnNode::Inlined(ii)) => {
|
||||
let node_id = ii.body.id;
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
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
|
||||
},
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue