Save bodies of functions for inlining into other crates

This is quite hacky and I hope to refactor it a bit, but at least it
seems to work.
This commit is contained in:
Florian Diebold 2016-11-01 18:57:13 +01:00 committed by Florian Diebold
parent 1ac338c2a7
commit 16eedd2a78
11 changed files with 178 additions and 143 deletions

View File

@ -25,6 +25,7 @@ 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;
@ -151,6 +152,7 @@ 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 {
@ -173,12 +175,18 @@ 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)
@ -196,6 +204,21 @@ impl<'a> FnLikeNode<'a> {
|c: ClosureParts| c.id)
}
pub fn constness(self) -> ast::Constness {
if let map::NodeInlinedItem(..) = self.node {
return ast::Constness::Const;
}
match self.kind() {
FnKind::ItemFn(_, _, _, constness, ..) => {
constness
}
FnKind::Method(_, m, ..) => {
m.constness
}
_ => ast::Constness::NotConst
}
}
pub fn kind(self) -> FnKind<'a> {
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
@ -254,7 +277,7 @@ impl<'a> FnLikeNode<'a> {
bug!("impl method FnLikeNode that is not fn-like")
}
}
}
},
map::NodeExpr(e) => match e.node {
ast::ExprClosure(_, ref decl, block, _fn_decl_span) =>
closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)),

View File

@ -18,7 +18,6 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use middle::cstore::InlinedItem as II;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi;
@ -61,6 +60,8 @@ pub enum Node<'ast> {
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam),
NodeVisibility(&'ast Visibility),
NodeInlinedItem(&'ast InlinedItem),
}
/// Represents an entry and its parent NodeID.
@ -120,6 +121,8 @@ impl<'ast> MapEntry<'ast> {
NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n),
NodeVisibility(n) => EntryVisibility(p, n),
NodeInlinedItem(n) => RootInlinedParent(n),
}
}
@ -168,6 +171,7 @@ impl<'ast> MapEntry<'ast> {
EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n),
EntryVisibility(_, n) => NodeVisibility(n),
RootInlinedParent(n) => NodeInlinedItem(n),
_ => return None
})
}
@ -328,12 +332,8 @@ impl<'ast> Map<'ast> {
EntryVisibility(p, _) =>
id = p,
RootInlinedParent(parent) => match *parent {
InlinedItem::Item(def_id, _) |
InlinedItem::TraitItem(def_id, _) |
InlinedItem::ImplItem(def_id, _) =>
return DepNode::MetaData(def_id)
},
RootInlinedParent(parent) =>
return DepNode::MetaData(parent.def_id),
RootCrate =>
bug!("node {} has crate ancestor but is inlined", id0),
@ -556,8 +556,7 @@ impl<'ast> Map<'ast> {
pub fn get_parent_did(&self, id: NodeId) -> DefId {
let parent = self.get_parent(id);
match self.find_entry(parent) {
Some(RootInlinedParent(&II::TraitItem(did, _))) |
Some(RootInlinedParent(&II::ImplItem(did, _))) => did,
Some(RootInlinedParent(ii)) => ii.def_id, // TODO: is this wrong for items?
_ => self.local_def_id(parent)
}
}
@ -962,6 +961,8 @@ impl<'a> NodePrinter for pprust::State<'a> {
// printing.
NodeLocal(_) => bug!("cannot print isolated Local"),
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
NodeInlinedItem(_) => bug!("cannot print inlined item"),
}
}
}
@ -1075,6 +1076,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
Some(NodeVisibility(ref vis)) => {
format!("visibility {:?}{}", vis, id_str)
}
Some(NodeInlinedItem(_)) => {
format!("inlined item {}", id_str)
}
None => {
format!("unknown node{}", id_str)
}

View File

@ -43,7 +43,7 @@ use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
use hir::intravisit::Visitor;
use hir::intravisit::{self, Visitor};
use rustc_back::PanicStrategy;
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
@ -137,18 +137,100 @@ pub struct NativeLibrary {
/// part of the AST that we parse from a file, but it becomes part of the tree
/// that we trans.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum InlinedItem {
Item(DefId /* def-id in source crate */, P<hir::Item>),
TraitItem(DefId /* impl id */, P<hir::TraitItem>),
ImplItem(DefId /* impl id */, P<hir::ImplItem>)
pub struct InlinedItem {
pub def_id: DefId,
pub body: P<hir::Expr>,
pub kind: InlinedItemKind,
}
/// A borrowed version of `hir::InlinedItem`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum InlinedItemKind {
Const(P<hir::Ty>),
Fn(P<hir::FnDecl>)
}
/// 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)]
pub enum InlinedItemRef<'a> {
Item(DefId, &'a hir::Item),
TraitItem(DefId, &'a hir::TraitItem),
ImplItem(DefId, &'a hir::ImplItem)
pub struct InlinedItemRef<'a> {
pub def_id: DefId,
pub body: &'a hir::Expr,
pub kind: InlinedItemKindRef<'a>,
}
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)]
pub enum InlinedItemKindRef<'a> {
Const(&'a hir::Ty),
Fn(&'a hir::FnDecl)
}
impl<'a> InlinedItemRef<'a> {
pub fn from_item<'ast: 'a>(def_id: DefId, item: &'a hir::Item, map: &hir_map::Map<'ast>) -> InlinedItemRef<'a> {
let (body, kind) = 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)),
_ => bug!("InlinedItemRef::from_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
kind: kind
}
}
pub fn from_trait_item(def_id: DefId, item: &'a hir::TraitItem, _map: &hir_map::Map) -> InlinedItemRef<'a> {
let (body, kind) = match item.node {
hir::ConstTraitItem(ref ty, Some(ref body)) => (&**body, InlinedItemKindRef::Const(ty)),
_ => bug!("InlinedItemRef::from_trait_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
kind: kind
}
}
pub fn from_impl_item<'ast: 'a>(def_id: DefId, item: &'a hir::ImplItem, map: &hir_map::Map<'ast>) -> InlinedItemRef<'a> {
let (body, kind) = 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)),
_ => bug!("InlinedItemRef::from_impl_item wrong kind")
};
InlinedItemRef {
def_id: def_id,
body: body,
kind: kind
}
}
pub fn visit<V>(&self, visitor: &mut V)
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)
}
}
}
impl InlinedItem {
pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
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
}
}
}
pub enum LoadedMacro {
@ -292,18 +374,6 @@ pub trait CrateStore<'tcx> {
fn metadata_encoding_version(&self) -> &[u8];
}
impl InlinedItem {
pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
where V: Visitor<'ast>
{
match *self {
InlinedItem::Item(_, ref i) => visitor.visit_item(&i),
InlinedItem::TraitItem(_, ref ti) => visitor.visit_trait_item(ti),
InlinedItem::ImplItem(_, ref ii) => visitor.visit_impl_item(ii),
}
}
}
// FIXME: find a better place for this?
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
let mut err_count = 0;

View File

@ -30,7 +30,7 @@ use syntax_pos::Span;
use rustc::hir;
use rustc::hir::Expr;
use rustc::hir::intravisit;
use rustc::hir::intravisit::Visitor;
use rustc::hir::intravisit::{Visitor, NestedVisitMode};
use self::restrictions::RestrictionResult;
@ -520,8 +520,12 @@ struct StaticInitializerCtxt<'a, 'tcx: 'a> {
item_id: ast::NodeId
}
impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
fn visit_expr(&mut self, ex: &Expr) {
impl<'a, 'tcx> Visitor<'tcx> for StaticInitializerCtxt<'a, 'tcx> {
fn nested_visit_map(&mut self) -> Option<(&hir::map::Map<'tcx>, NestedVisitMode)> {
Some((&self.bccx.tcx.map, NestedVisitMode::OnlyBodies))
}
fn visit_expr(&mut self, ex: &'tcx Expr) {
if let hir::ExprAddrOf(mutbl, ref base) = ex.node {
let param_env = ty::ParameterEnvironment::for_item(self.bccx.tcx,
self.item_id);
@ -542,9 +546,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> {
}
}
pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt,
item_id: ast::NodeId,
expr: &hir::Expr) {
pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
item_id: ast::NodeId,
expr: &'tcx hir::Expr) {
debug!("gather_loans_in_static_initializer(expr={:?})", expr);

View File

@ -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;
use rustc::middle::cstore::{InlinedItem, InlinedItemKind};
use rustc::traits;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
@ -141,33 +141,9 @@ 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::Item(_, ref item), _)) => match item.node {
hir::ItemConst(ref ty, ref const_expr) => {
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
},
_ => None
},
Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
hir::ConstTraitItem(..) => {
used_substs = true;
if let Some(substs) = substs {
// As mentioned in the comments above for in-crate
// constants, we only try to find the expression for
// a trait-associated const if the caller gives us
// the substitutions for the reference to it.
resolve_trait_associated_const(tcx, ti, trait_id, substs)
} else {
None
}
}
_ => None
},
Some((&InlinedItem::ImplItem(_, ref ii), _)) => match ii.node {
hir::ImplItemKind::Const(ref ty, ref expr) => {
Some((&**expr, tcx.ast_ty_to_prim_ty(ty)))
},
_ => None
},
Some((&InlinedItem { body: ref const_expr, kind: InlinedItemKind::Const(ref ty), .. }, _)) => {
Some((&**const_expr, tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
};
// If we used the substitutions, particularly to choose an impl
@ -197,8 +173,7 @@ fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let fn_id = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
Some((&InlinedItem::Item(_, ref item), _)) => Some(item.id),
Some((&InlinedItem::ImplItem(_, ref item), _)) => Some(item.id),
Some((&InlinedItem { kind: InlinedItemKind::Fn(_), .. }, node_id)) => Some(node_id),
_ => None
};
tcx.extern_const_fns.borrow_mut().insert(def_id,
@ -224,18 +199,10 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
None => return None
};
match fn_like.kind() {
FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
Some(fn_like)
}
FnKind::Method(_, m, ..) => {
if m.constness == hir::Constness::Const {
Some(fn_like)
} else {
None
}
}
_ => None
if fn_like.constness() == hir::Constness::Const {
Some(fn_like)
} else {
None
}
}

View File

@ -46,11 +46,7 @@ enum TableEntry<'tcx> {
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
match ii {
InlinedItemRef::Item(_, i) => id_visitor.visit_item(i),
InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti),
InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii),
}
ii.visit(&mut id_visitor);
let ii_pos = self.position();
ii.encode(self).unwrap();
@ -61,11 +57,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ecx: self,
count: 0,
};
match ii {
InlinedItemRef::Item(_, i) => visitor.visit_item(i),
InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti),
InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii),
}
ii.visit(&mut visitor);
visitor.count
};
@ -127,17 +119,13 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
}];
let ii = ast.item.decode((cdata, tcx, id_ranges));
let item_node_id = tcx.sess.next_node_id();
let ii = ast_map::map_decoded_item(&tcx.map,
parent_def_path,
parent_did,
ii,
tcx.sess.next_node_id());
item_node_id);
let item_node_id = match ii {
&InlinedItem::Item(_, ref i) => i.id,
&InlinedItem::TraitItem(_, ref ti) => ti.id,
&InlinedItem::ImplItem(_, ref ii) => ii.id,
};
let inlined_did = tcx.map.local_def_id(item_node_id);
let ty = tcx.item_type(orig_did);
let generics = tcx.item_generics(orig_did);

View File

@ -443,12 +443,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
let find_inlined_item_root = |inlined_item_id| {
let mut node = inlined_item_id;
let mut path = Vec::with_capacity(10);
// If we can't find the inline root after a thousand hops, we can
// be pretty sure there's something wrong with the HIR map.
for _ in 0 .. 1000 {
path.push(node);
let parent_node = tcx.map.get_parent_node(node);
if parent_node == node {
return node;
@ -464,27 +462,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
.borrow_mut()
.insert(def_id, None);
}
Some(&InlinedItem::Item(d, ref item)) => {
assert_eq!(d, def_id);
let inlined_root_node_id = find_inlined_item_root(item.id);
cache_inlined_item(def_id, item.id, inlined_root_node_id);
}
Some(&InlinedItem::TraitItem(_, ref trait_item)) => {
let inlined_root_node_id = find_inlined_item_root(trait_item.id);
cache_inlined_item(def_id, trait_item.id, inlined_root_node_id);
// Associated consts already have to be evaluated in `typeck`, so
// the logic to do that already exists in `middle`. In order to
// reuse that code, it needs to be able to look up the traits for
// inlined items.
let ty_trait_item = tcx.associated_item(def_id).clone();
let trait_item_def_id = tcx.map.local_def_id(trait_item.id);
tcx.associated_items.borrow_mut()
.insert(trait_item_def_id, ty_trait_item);
}
Some(&InlinedItem::ImplItem(_, ref impl_item)) => {
let inlined_root_node_id = find_inlined_item_root(impl_item.id);
cache_inlined_item(def_id, impl_item.id, inlined_root_node_id);
Some(&InlinedItem { ref body, .. }) => {
let inlined_root_node_id = find_inlined_item_root(body.id);
cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
}
}

View File

@ -518,7 +518,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ast: if trait_item.kind == ty::AssociatedKind::Const {
let trait_def_id = trait_item.container.id();
Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item)))
Some(self.encode_inlined_item(InlinedItemRef::from_trait_item(trait_def_id, ast_item, &tcx.map)))
} else {
None
},
@ -527,6 +527,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
let tcx = self.tcx;
let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.map.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id);
@ -587,7 +589,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
predicates: Some(self.encode_predicates(def_id)),
ast: if ast {
Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item)))
Some(self.encode_inlined_item(InlinedItemRef::from_impl_item(impl_def_id, ast_item, &tcx.map)))
} else {
None
},
@ -817,7 +819,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
ast: match item.node {
hir::ItemConst(..) |
hir::ItemFn(_, _, hir::Constness::Const, ..) => {
Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item)))
Some(self.encode_inlined_item(InlinedItemRef::from_item(def_id, item, &tcx.map)))
}
_ => None,
},

View File

@ -23,7 +23,6 @@ use rustc_const_eval as const_eval;
use rustc_data_structures::indexed_vec::Idx;
use rustc::dep_graph::DepNode;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::infer::InferCtxt;
use rustc::ty::subst::Subst;
@ -51,11 +50,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
MirSource::Static(..) => hir::Constness::Const,
MirSource::Fn(id) => {
let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
match fn_like.map(|f| f.kind()) {
Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
Some(FnKind::Method(_, m, ..)) => m.constness,
_ => hir::Constness::NotConst
}
fn_like.map_or(hir::Constness::NotConst, |f| f.constness())
}
MirSource::Promoted(..) => bug!()
};

View File

@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc::hir;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::hir::intravisit::FnKind;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::traits::{self, Reveal};
use rustc::ty::{self, TyCtxt, Ty};
@ -116,15 +115,10 @@ impl fmt::Display for Mode {
pub fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
let fn_like = FnLikeNode::from_node(tcx.map.get(node_id));
match fn_like.map(|f| f.kind()) {
Some(FnKind::ItemFn(_, _, _, c, ..)) => {
c == hir::Constness::Const
}
Some(FnKind::Method(_, m, ..)) => {
m.constness == hir::Constness::Const
}
_ => false
if let Some(fn_like) = FnLikeNode::from_node(tcx.map.get(node_id)) {
fn_like.constness() == hir::Constness::Const
} else {
false
}
} else {
tcx.sess.cstore.is_const_fn(def_id)

View File

@ -181,11 +181,19 @@ 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 qualif = self.fn_like(fn_like.kind(),
fn_like.decl(),
fn_like.body(),
fn_like.span(),
fn_like.id());
let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(fn_like.body().node_id()) {
Entry::Occupied(entry) => Some(*entry.get()),
_ => None
};
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);
if ret_ty.type_contents(self.tcx).interior_unsafe() {