rustc: const-qualify const fn function and method calls.
This commit is contained in:
parent
af3795721c
commit
1bd420555e
8 changed files with 288 additions and 57 deletions
|
|
@ -262,3 +262,5 @@ pub const tag_item_super_predicates: usize = 0xa3;
|
|||
pub const tag_defaulted_trait: usize = 0xa4;
|
||||
|
||||
pub const tag_impl_coerce_unsized_kind: usize = 0xa5;
|
||||
|
||||
pub const tag_items_data_item_constness: usize = 0xa6;
|
||||
|
|
|
|||
|
|
@ -384,6 +384,11 @@ pub fn is_typedef(cstore: &cstore::CStore, did: ast::DefId) -> bool {
|
|||
decoder::is_typedef(&*cdata, did.node)
|
||||
}
|
||||
|
||||
pub fn is_const_fn(cstore: &cstore::CStore, did: ast::DefId) -> bool {
|
||||
let cdata = cstore.get_crate_data(did.krate);
|
||||
decoder::is_const_fn(&*cdata, did.node)
|
||||
}
|
||||
|
||||
pub fn get_stability(cstore: &cstore::CStore,
|
||||
def: ast::DefId)
|
||||
-> Option<attr::Stability> {
|
||||
|
|
|
|||
|
|
@ -178,6 +178,19 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility {
|
|||
}
|
||||
}
|
||||
|
||||
fn fn_constness(item: rbml::Doc) -> ast::Constness {
|
||||
match reader::maybe_get_doc(item, tag_items_data_item_constness) {
|
||||
None => ast::Constness::NotConst,
|
||||
Some(constness_doc) => {
|
||||
match reader::doc_as_u8(constness_doc) as char {
|
||||
'c' => ast::Constness::Const,
|
||||
'n' => ast::Constness::NotConst,
|
||||
_ => panic!("unknown constness character")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn item_sort(item: rbml::Doc) -> Option<char> {
|
||||
let mut ret = None;
|
||||
reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
|
||||
|
|
@ -1525,6 +1538,14 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
match fn_constness(item_doc) {
|
||||
ast::Constness::Const => true,
|
||||
ast::Constness::NotConst => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_generics<'tcx>(base_doc: rbml::Doc,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
cdata: Cmd,
|
||||
|
|
|
|||
|
|
@ -581,6 +581,16 @@ fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) {
|
|||
rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
|
||||
}
|
||||
|
||||
fn encode_constness(rbml_w: &mut Encoder, constness: ast::Constness) {
|
||||
rbml_w.start_tag(tag_items_data_item_constness);
|
||||
let ch = match constness {
|
||||
ast::Constness::Const => 'c',
|
||||
ast::Constness::NotConst => 'n',
|
||||
};
|
||||
rbml_w.wr_str(&ch.to_string());
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_explicit_self(rbml_w: &mut Encoder,
|
||||
explicit_self: &ty::ExplicitSelfCategory) {
|
||||
let tag = tag_item_trait_method_explicit_self;
|
||||
|
|
@ -867,10 +877,14 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
|||
encode_attributes(rbml_w, &impl_item.attrs);
|
||||
let scheme = ty::lookup_item_type(ecx.tcx, m.def_id);
|
||||
let any_types = !scheme.generics.types.is_empty();
|
||||
if any_types || is_default_impl || attr::requests_inline(&impl_item.attrs) {
|
||||
let needs_inline = any_types || is_default_impl ||
|
||||
attr::requests_inline(&impl_item.attrs);
|
||||
let constness = ast_method.pe_constness();
|
||||
if needs_inline || constness == ast::Constness::Const {
|
||||
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
|
||||
impl_item));
|
||||
}
|
||||
encode_constness(rbml_w, constness);
|
||||
if !any_types {
|
||||
encode_symbol(ecx, rbml_w, m.def_id.node);
|
||||
}
|
||||
|
|
@ -1049,7 +1063,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_stability(rbml_w, stab);
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
ast::ItemFn(ref decl, _, _, _, ref generics, _) => {
|
||||
ast::ItemFn(ref decl, _, constness, _, ref generics, _) => {
|
||||
add_to_index(item, rbml_w, index);
|
||||
rbml_w.start_tag(tag_items_data_item);
|
||||
encode_def_id(rbml_w, def_id);
|
||||
|
|
@ -1059,12 +1073,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_name(rbml_w, item.ident.name);
|
||||
encode_path(rbml_w, path);
|
||||
encode_attributes(rbml_w, &item.attrs);
|
||||
if tps_len > 0 || attr::requests_inline(&item.attrs) {
|
||||
let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
|
||||
if needs_inline || constness == ast::Constness::Const {
|
||||
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
|
||||
}
|
||||
if tps_len == 0 {
|
||||
encode_symbol(ecx, rbml_w, item.id);
|
||||
}
|
||||
encode_constness(rbml_w, constness);
|
||||
encode_visibility(rbml_w, vis);
|
||||
encode_stability(rbml_w, stab);
|
||||
encode_method_argument_names(rbml_w, &**decl);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ use util::nodemap::NodeMap;
|
|||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util::PostExpansionMethod;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
|
|
@ -79,6 +80,7 @@ bitflags! {
|
|||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
enum Mode {
|
||||
Const,
|
||||
ConstFn,
|
||||
Static,
|
||||
StaticMut,
|
||||
|
||||
|
|
@ -136,10 +138,87 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn fn_like(&mut self,
|
||||
fk: visit::FnKind,
|
||||
fd: &ast::FnDecl,
|
||||
b: &ast::Block,
|
||||
s: Span,
|
||||
fn_id: ast::NodeId)
|
||||
-> ConstQualif {
|
||||
match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
|
||||
Entry::Occupied(entry) => return *entry.get(),
|
||||
Entry::Vacant(entry) => {
|
||||
// Prevent infinite recursion on re-entry.
|
||||
entry.insert(PURE_CONST);
|
||||
}
|
||||
}
|
||||
|
||||
let mode = match fk {
|
||||
visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
|
||||
Mode::ConstFn
|
||||
}
|
||||
visit::FkMethod(_, _, m) => {
|
||||
if m.pe_constness() == ast::Constness::Const {
|
||||
Mode::ConstFn
|
||||
} else {
|
||||
Mode::Var
|
||||
}
|
||||
}
|
||||
_ => Mode::Var
|
||||
};
|
||||
|
||||
// Ensure the arguments are simple, not mutable/by-ref or patterns.
|
||||
if mode == Mode::ConstFn {
|
||||
for arg in &fd.inputs {
|
||||
match arg.pat.node {
|
||||
ast::PatIdent(ast::BindByValue(ast::MutImmutable), _, None) => {}
|
||||
_ => {
|
||||
span_err!(self.tcx.sess, arg.pat.span, E0022,
|
||||
"arguments of constant functions can only \
|
||||
be immutable by-value bindings");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let qualif = self.with_mode(mode, |this| {
|
||||
this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
|
||||
visit::walk_fn(this, fk, fd, b, s);
|
||||
this.qualif
|
||||
});
|
||||
|
||||
// Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
|
||||
// and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
|
||||
let qualif = qualif & (NON_ZERO_SIZED | PREFER_IN_PLACE);
|
||||
|
||||
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
|
||||
qualif
|
||||
}
|
||||
|
||||
fn add_qualif(&mut self, qualif: ConstQualif) {
|
||||
self.qualif = self.qualif | qualif;
|
||||
}
|
||||
|
||||
/// Returns true if the call is to a const fn or method.
|
||||
fn handle_const_fn_call(&mut self, def_id: ast::DefId, ret_ty: Ty<'tcx>) -> bool {
|
||||
if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
|
||||
let qualif = self.fn_like(fn_like.kind(),
|
||||
fn_like.decl(),
|
||||
fn_like.body(),
|
||||
fn_like.span(),
|
||||
fn_like.id());
|
||||
self.add_qualif(qualif);
|
||||
|
||||
if ty::type_contents(self.tcx, ret_ty).interior_unsafe() {
|
||||
self.add_qualif(MUTABLE_MEM);
|
||||
}
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn record_borrow(&mut self, id: ast::NodeId, mutbl: ast::Mutability) {
|
||||
match self.rvalue_borrows.entry(id) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
|
|
@ -158,6 +237,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
|||
fn msg(&self) -> &'static str {
|
||||
match self.mode {
|
||||
Mode::Const => "constant",
|
||||
Mode::ConstFn => "constant function",
|
||||
Mode::StaticMut | Mode::Static => "static",
|
||||
Mode::Var => unreachable!(),
|
||||
}
|
||||
|
|
@ -251,9 +331,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
|
|||
b: &'v ast::Block,
|
||||
s: Span,
|
||||
fn_id: ast::NodeId) {
|
||||
assert!(self.mode == Mode::Var);
|
||||
self.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
|
||||
visit::walk_fn(self, fk, fd, b, s);
|
||||
self.fn_like(fk, fd, b, s, fn_id);
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &ast::Pat) {
|
||||
|
|
@ -269,6 +347,35 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, block: &ast::Block) {
|
||||
// Check all statements in the block
|
||||
for stmt in &block.stmts {
|
||||
let span = match stmt.node {
|
||||
ast::StmtDecl(ref decl, _) => {
|
||||
match decl.node {
|
||||
ast::DeclLocal(_) => decl.span,
|
||||
|
||||
// Item statements are allowed
|
||||
ast::DeclItem(_) => continue
|
||||
}
|
||||
}
|
||||
ast::StmtExpr(ref expr, _) => expr.span,
|
||||
ast::StmtSemi(ref semi, _) => semi.span,
|
||||
ast::StmtMac(..) => {
|
||||
self.tcx.sess.span_bug(stmt.span, "unexpanded statement \
|
||||
macro in const?!")
|
||||
}
|
||||
};
|
||||
self.add_qualif(NOT_CONST);
|
||||
if self.mode != Mode::Var {
|
||||
span_err!(self.tcx.sess, span, E0016,
|
||||
"blocks in {}s are limited to items and \
|
||||
tail expressions", self.msg());
|
||||
}
|
||||
}
|
||||
visit::walk_block(self, block);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, ex: &ast::Expr) {
|
||||
let mut outer = self.qualif;
|
||||
self.qualif = ConstQualif::empty();
|
||||
|
|
@ -473,10 +580,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
Some(def::DefStatic(..)) => {
|
||||
match v.mode {
|
||||
Mode::Static | Mode::StaticMut => {}
|
||||
Mode::Const => {
|
||||
Mode::Const | Mode::ConstFn => {
|
||||
span_err!(v.tcx.sess, e.span, E0013,
|
||||
"constants cannot refer to other statics, \
|
||||
insert an intermediate constant instead");
|
||||
"{}s cannot refer to other statics, insert \
|
||||
an intermediate constant instead", v.msg());
|
||||
}
|
||||
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
|
||||
}
|
||||
|
|
@ -493,6 +600,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
doesn't point to a constant");
|
||||
}
|
||||
}
|
||||
Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
|
||||
// Sadly, we can't determine whether the types are zero-sized.
|
||||
v.add_qualif(NOT_CONST | NON_ZERO_SIZED);
|
||||
}
|
||||
def => {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
|
|
@ -517,19 +628,26 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
};
|
||||
}
|
||||
let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
|
||||
match def {
|
||||
Some(def::DefStruct(..)) => {}
|
||||
let is_const = match def {
|
||||
Some(def::DefStruct(..)) => true,
|
||||
Some(def::DefVariant(..)) => {
|
||||
// Count the discriminator.
|
||||
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0015,
|
||||
"function calls in {}s are limited to \
|
||||
struct and enum constructors", v.msg());
|
||||
}
|
||||
Some(def::DefMethod(did, def::FromImpl(_))) |
|
||||
Some(def::DefFn(did, _)) => {
|
||||
v.handle_const_fn_call(did, node_ty)
|
||||
}
|
||||
_ => false
|
||||
};
|
||||
if !is_const {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0015,
|
||||
"function calls in {}s are limited to \
|
||||
constant functions, \
|
||||
struct and enum constructors", v.msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -538,27 +656,28 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
let mut block_span_err = |span| {
|
||||
v.add_qualif(ConstQualif::NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, span, E0016,
|
||||
"blocks in {}s are limited to items and \
|
||||
tail expressions", v.msg());
|
||||
span_err!(v.tcx.sess, e.span, E0015,
|
||||
"function calls in {}s are limited to \
|
||||
constant functions, \
|
||||
struct and enum constructors", v.msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprMethodCall(..) => {
|
||||
let method_did = match v.tcx.method_map.borrow()[method_call].origin {
|
||||
ty::MethodStatic(did) => Some(did),
|
||||
_ => None
|
||||
};
|
||||
for stmt in &block.stmts {
|
||||
match stmt.node {
|
||||
ast::StmtDecl(ref decl, _) => {
|
||||
match decl.node {
|
||||
ast::DeclLocal(_) => block_span_err(decl.span),
|
||||
|
||||
// Item statements are allowed
|
||||
ast::DeclItem(_) => {}
|
||||
}
|
||||
}
|
||||
ast::StmtExpr(ref expr, _) => block_span_err(expr.span),
|
||||
ast::StmtSemi(ref semi, _) => block_span_err(semi.span),
|
||||
ast::StmtMac(..) => {
|
||||
v.tcx.sess.span_bug(e.span, "unexpanded statement \
|
||||
macro in const?!")
|
||||
}
|
||||
let is_const = match method_did {
|
||||
Some(did) => v.handle_const_fn_call(did, node_ty),
|
||||
None => false
|
||||
};
|
||||
if !is_const {
|
||||
v.add_qualif(NOT_CONST);
|
||||
if v.mode != Mode::Var {
|
||||
span_err!(v.tcx.sess, e.span, E0021,
|
||||
"method calls in {}s are limited to \
|
||||
constant inherent methods", v.msg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -579,7 +698,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
}
|
||||
|
||||
ast::ExprClosure(..) => {
|
||||
// Paths in constant constexts cannot refer to local variables,
|
||||
// Paths in constant contexts cannot refer to local variables,
|
||||
// as there are none, and thus closures can't have upvars there.
|
||||
if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) {
|
||||
assert!(v.mode == Mode::Var,
|
||||
|
|
@ -588,6 +707,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
ast::ExprBlock(_) |
|
||||
ast::ExprUnary(..) |
|
||||
ast::ExprBinary(..) |
|
||||
ast::ExprIndex(..) |
|
||||
|
|
@ -616,8 +736,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
// Miscellaneous expressions that could be implemented.
|
||||
ast::ExprRange(..) |
|
||||
|
||||
// Various other expressions.
|
||||
ast::ExprMethodCall(..) |
|
||||
// Expressions with side-effects.
|
||||
ast::ExprAssign(..) |
|
||||
ast::ExprAssignOp(..) |
|
||||
ast::ExprInlineAsm(_) |
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ use util::num::ToPrimitive;
|
|||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::ast::{self, Expr};
|
||||
use syntax::ast_map::blocks::FnLikeNode;
|
||||
use syntax::ast_util::{self, PostExpansionMethod};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::feature_gate;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::ptr::P;
|
||||
use syntax::{ast_map, ast_util, codemap};
|
||||
use syntax::{ast_map, codemap, visit};
|
||||
|
||||
use std::borrow::{Cow, IntoCow};
|
||||
use std::num::wrapping::OverflowingOps;
|
||||
|
|
@ -198,6 +200,63 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId)
|
||||
-> Option<ast::NodeId> {
|
||||
match tcx.extern_const_fns.borrow().get(&def_id) {
|
||||
Some(&ast::DUMMY_NODE_ID) => return None,
|
||||
Some(&fn_id) => return Some(fn_id),
|
||||
None => {}
|
||||
}
|
||||
|
||||
if !csearch::is_const_fn(&tcx.sess.cstore, def_id) {
|
||||
tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
|
||||
return None;
|
||||
}
|
||||
|
||||
let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
|
||||
box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
|
||||
csearch::FoundAst::Found(&ast::IIItem(ref item)) => Some(item.id),
|
||||
csearch::FoundAst::Found(&ast::IIImplItem(_, ast::MethodImplItem(ref m))) => Some(m.id),
|
||||
_ => None
|
||||
};
|
||||
tcx.extern_const_fns.borrow_mut().insert(def_id,
|
||||
fn_id.unwrap_or(ast::DUMMY_NODE_ID));
|
||||
fn_id
|
||||
}
|
||||
|
||||
pub fn lookup_const_fn_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
|
||||
-> Option<FnLikeNode<'a>> {
|
||||
|
||||
let fn_id = if !ast_util::is_local(def_id) {
|
||||
if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
|
||||
fn_id
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
def_id.node
|
||||
};
|
||||
|
||||
let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
|
||||
Some(fn_like) => fn_like,
|
||||
None => return None
|
||||
};
|
||||
|
||||
match fn_like.kind() {
|
||||
visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
|
||||
Some(fn_like)
|
||||
}
|
||||
visit::FkMethod(_, _, m) => {
|
||||
if m.pe_constness() == ast::Constness::Const {
|
||||
Some(fn_like)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum const_val {
|
||||
const_float(f64),
|
||||
|
|
|
|||
|
|
@ -775,10 +775,10 @@ pub struct ctxt<'tcx> {
|
|||
/// Borrows
|
||||
pub upvar_capture_map: RefCell<UpvarCaptureMap>,
|
||||
|
||||
/// These two caches are used by const_eval when decoding external statics
|
||||
/// and variants that are found.
|
||||
/// These caches are used by const_eval when decoding external constants.
|
||||
pub extern_const_statics: RefCell<DefIdMap<ast::NodeId>>,
|
||||
pub extern_const_variants: RefCell<DefIdMap<ast::NodeId>>,
|
||||
pub extern_const_fns: RefCell<DefIdMap<ast::NodeId>>,
|
||||
|
||||
pub method_map: MethodMap<'tcx>,
|
||||
|
||||
|
|
@ -2808,6 +2808,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||
upvar_capture_map: RefCell::new(FnvHashMap()),
|
||||
extern_const_statics: RefCell::new(DefIdMap()),
|
||||
extern_const_variants: RefCell::new(DefIdMap()),
|
||||
extern_const_fns: RefCell::new(DefIdMap()),
|
||||
method_map: RefCell::new(FnvHashMap()),
|
||||
dependency_formats: RefCell::new(FnvHashMap()),
|
||||
closure_kinds: RefCell::new(DefIdMap()),
|
||||
|
|
|
|||
|
|
@ -96,20 +96,10 @@ impl<'a> Code<'a> {
|
|||
|
||||
/// Attempts to construct a Code from presumed FnLike or Block node input.
|
||||
pub fn from_node(node: Node) -> Option<Code> {
|
||||
fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } }
|
||||
match node {
|
||||
ast_map::NodeItem(item) if item.is_fn_like() =>
|
||||
Some(FnLikeCode(new(node))),
|
||||
ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
|
||||
Some(FnLikeCode(new(node))),
|
||||
ast_map::NodeImplItem(_) =>
|
||||
Some(FnLikeCode(new(node))),
|
||||
ast_map::NodeExpr(e) if e.is_fn_like() =>
|
||||
Some(FnLikeCode(new(node))),
|
||||
ast_map::NodeBlock(block) =>
|
||||
Some(BlockCode(block)),
|
||||
_ =>
|
||||
None,
|
||||
if let ast_map::NodeBlock(block) = node {
|
||||
Some(BlockCode(block))
|
||||
} else {
|
||||
FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -145,6 +135,24 @@ impl<'a> ClosureParts<'a> {
|
|||
}
|
||||
|
||||
impl<'a> FnLikeNode<'a> {
|
||||
/// Attempts to construct a FnLikeNode from presumed FnLike node input.
|
||||
pub fn from_node(node: Node) -> Option<FnLikeNode> {
|
||||
let fn_like = match node {
|
||||
ast_map::NodeItem(item) => item.is_fn_like(),
|
||||
ast_map::NodeTraitItem(tm) => tm.is_fn_like(),
|
||||
ast_map::NodeImplItem(_) => true,
|
||||
ast_map::NodeExpr(e) => e.is_fn_like(),
|
||||
_ => false
|
||||
};
|
||||
if fn_like {
|
||||
Some(FnLikeNode {
|
||||
node: node
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_fn_parts(self) -> FnParts<'a> {
|
||||
FnParts {
|
||||
decl: self.decl(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue