Introduce a "liberated fn sigs" map so that we have easy access to this

information when constructing MIR.
This commit is contained in:
Niko Matsakis 2015-10-21 15:46:30 -04:00
parent fffe075708
commit 6d7c66e6e8
4 changed files with 53 additions and 24 deletions

View file

@ -121,6 +121,13 @@ pub struct Tables<'tcx> {
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
pub closure_kinds: DefIdMap<ty::ClosureKind>,
/// For each fn, records the "liberated" types of its arguments
/// and return type. Liberated means that all bound regions
/// (including late-bound regions) are replaced with free
/// equivalents. This table is not used in trans (since regions
/// are erased there) and hence is not serialized to metadata.
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
}
impl<'tcx> Tables<'tcx> {
@ -133,6 +140,7 @@ impl<'tcx> Tables<'tcx> {
upvar_capture_map: FnvHashMap(),
closure_tys: DefIdMap(),
closure_kinds: DefIdMap(),
liberated_fn_sigs: NodeMap(),
}
}

View file

@ -164,11 +164,6 @@ pub struct Inherited<'a, 'tcx: 'a> {
tables: &'a RefCell<ty::Tables<'tcx>>,
// A mapping from each fn's id to its signature, with all bound
// regions replaced with free ones. Unlike the other tables, this
// one is never copied into the tcx: it is only used by regionck.
fn_sig_map: RefCell<NodeMap<Vec<Ty<'tcx>>>>,
// When we process a call like `c()` where `c` is a closure type,
// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or
// `FnOnce` closure. In that case, we defer full resolution of the
@ -314,7 +309,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), true),
locals: RefCell::new(NodeMap()),
tables: tables,
fn_sig_map: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
}
@ -620,22 +614,13 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
ccx: ccx
};
// Remember return type so that regionck can access it later.
let mut fn_sig_tys: Vec<Ty> =
arg_tys.iter()
.cloned()
.collect();
if let ty::FnConverging(ret_ty) = ret_ty {
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments
}
debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
fn_id,
fn_sig_tys);
debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig);
inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys);
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone());
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };

View file

@ -284,19 +284,32 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
// When we enter a function, we can derive
debug!("visit_fn_body(id={})", id);
let fn_sig_map = self.fcx.inh.fn_sig_map.borrow();
let fn_sig = match fn_sig_map.get(&id) {
Some(f) => f,
None => {
self.tcx().sess.bug(
&format!("No fn-sig entry for id={}", id));
let fn_sig = {
let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs;
match fn_sig_map.get(&id) {
Some(f) => f.clone(),
None => {
self.tcx().sess.bug(
&format!("No fn-sig entry for id={}", id));
}
}
};
let old_region_bounds_pairs_len = self.region_bound_pairs.len();
// Collect the types from which we create inferred bounds.
// For the return type, if diverging, substitute `bool` just
// because it will have no effect.
//
// FIXME(#25759) return types should not be implied bounds
let fn_sig_tys: Vec<_> =
fn_sig.inputs.iter()
.cloned()
.chain(Some(fn_sig.output.unwrap_or(self.tcx().types.bool)))
.collect();
let old_body_id = self.set_body_id(body.id);
self.relate_free_regions(&fn_sig[..], body.id, span);
self.relate_free_regions(&fn_sig_tys[..], body.id, span);
link_fn_args(self,
self.tcx().region_maps.node_extent(body.id),
&fn_decl.inputs[..]);

View file

@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
wbcx.visit_expr(e);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
}
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
}
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
}
///////////////////////////////////////////////////////////////////////////
@ -361,6 +363,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
fn visit_liberated_fn_sigs(&self) {
for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() {
let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id));
self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone());
}
}
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
t.fold_with(&mut Resolver::new(self.fcx, reason))
}
@ -376,6 +385,7 @@ enum ResolveReason {
ResolvingPattern(Span),
ResolvingUpvar(ty::UpvarId),
ResolvingClosure(DefId),
ResolvingFnSig(ast::NodeId),
}
impl ResolveReason {
@ -387,6 +397,9 @@ impl ResolveReason {
ResolvingUpvar(upvar_id) => {
tcx.expr_span(upvar_id.closure_expr_id)
}
ResolvingFnSig(id) => {
tcx.map.span(id)
}
ResolvingClosure(did) => {
if let Some(node_id) = tcx.map.as_local_node_id(did) {
tcx.expr_span(node_id)
@ -463,6 +476,16 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
span_err!(self.tcx.sess, span, E0196,
"cannot determine a type for this closure")
}
ResolvingFnSig(id) => {
// any failures here should also fail when
// resolving the patterns, closure types, or
// something else.
let span = self.reason.span(self.tcx);
self.tcx.sess.delay_span_bug(
span,
&format!("cannot resolve some aspect of fn sig for {:?}", id));
}
}
}
}