diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 830232cf373..a8f045074bd 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -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, + + /// 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>, } 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(), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f085ce23e3f..dc2b2b75ab6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -164,11 +164,6 @@ pub struct Inherited<'a, 'tcx: 'a> { tables: &'a RefCell>, - // 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>>>, - // 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 = - 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, }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6e60f926b7c..3cdc9b55944 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -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[..]); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 2c18a245159..cfab28f923e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -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>(&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)); + } } } }