From f0cc3a93651d237a8c5dda1571e823a3cba7ce60 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Sat, 18 Oct 2014 10:46:57 -0700 Subject: [PATCH] Fix monomorphization of unboxed closures This adds a `Substs` field to `ty_unboxed_closure` and plumbs basic handling of it throughout the compiler. trans now correctly monomorphizes captured free variables and llvm function defs. This fixes uses of unboxed closures which reference a free type or region parameter from their environment in either their signature or free variables. Closes #16791 --- src/librustc/metadata/tydecode.rs | 7 +- src/librustc/metadata/tyencode.rs | 6 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/traits/select.rs | 31 ++++--- src/librustc/middle/trans/adt.rs | 4 +- src/librustc/middle/trans/base.rs | 30 ++++--- src/librustc/middle/trans/callee.rs | 2 +- src/librustc/middle/trans/closure.rs | 33 +++++--- src/librustc/middle/trans/context.rs | 6 +- src/librustc/middle/trans/debuginfo.rs | 10 +-- src/librustc/middle/trans/meth.rs | 80 +++++++++---------- src/librustc/middle/trans/type_of.rs | 8 +- src/librustc/middle/ty.rs | 63 +++++++++------ src/librustc/middle/ty_fold.rs | 4 +- src/librustc/middle/typeck/check/method.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 3 +- src/librustc/middle/typeck/check/regionck.rs | 4 +- .../middle/typeck/check/regionmanip.rs | 14 +++- src/librustc/middle/typeck/coherence/mod.rs | 4 +- src/librustc/middle/typeck/infer/combine.rs | 22 +++-- src/librustc/middle/typeck/variance.rs | 5 +- src/librustc/util/ppaux.rs | 7 +- 22 files changed, 202 insertions(+), 145 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 0e57341a559..b5456e724d2 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -465,9 +465,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t { return ty::mk_struct(st.tcx, did, substs); } 'k' => { + assert_eq!(next(st), '['); let did = parse_def(st, NominalType, |x,y| conv(x,y)); - let region = parse_region(st, conv); - return ty::mk_unboxed_closure(st.tcx, did, region); + let region = parse_region(st, |x,y| conv(x,y)); + let substs = parse_substs(st, |x,y| conv(x,y)); + assert_eq!(next(st), ']'); + return ty::mk_unboxed_closure(st.tcx, did, region, substs); } 'e' => { return ty::mk_err(); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index e11385654cc..6c59537b377 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -285,9 +285,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) { enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::ty_unboxed_closure(def, region) => { - mywrite!(w, "k{}", (cx.ds)(def)); + ty::ty_unboxed_closure(def, region, ref substs) => { + mywrite!(w, "k[{}|", (cx.ds)(def)); enc_region(w, cx, region); + enc_substs(w, cx, substs); + mywrite!(w, "]"); } ty::ty_err => { mywrite!(w, "e"); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 08e14e8034e..abdbd80ebf2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -594,7 +594,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { }; self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false) } - ty::ty_unboxed_closure(closure_id, _) => { + ty::ty_unboxed_closure(closure_id, _, _) => { let unboxed_closures = self.typer.unboxed_closures().borrow(); let kind = (*unboxed_closures)[closure_id].kind; let mode = self.typer.capture_mode(fn_node_id); diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 8f1fcf77ee3..2f345e2e619 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -110,7 +110,7 @@ enum Candidate { BuiltinCandidate(ty::BuiltinBound), ParamCandidate(VtableParamData), ImplCandidate(ast::DefId), - UnboxedClosureCandidate(/* closure */ ast::DefId), + UnboxedClosureCandidate(/* closure */ ast::DefId, Substs), ErrorCandidate, } @@ -995,8 +995,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); - let closure_def_id = match ty::get(self_ty).sty { - ty::ty_unboxed_closure(id, _) => id, + let (closure_def_id, substs) = match ty::get(self_ty).sty { + ty::ty_unboxed_closure(id, _, ref substs) => (id, substs.clone()), ty::ty_infer(ty::TyVar(_)) => { candidates.ambiguous = true; return Ok(()); @@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; if closure_kind == kind { - candidates.vec.push(UnboxedClosureCandidate(closure_def_id)); + candidates.vec.push(UnboxedClosureCandidate(closure_def_id, substs.clone())); } Ok(()) @@ -1383,7 +1383,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(If(tys.clone())) } - ty::ty_unboxed_closure(def_id, _) => { + ty::ty_unboxed_closure(def_id, _, ref substs) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each @@ -1407,7 +1407,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(|freevar| { let freevar_def_id = freevar.def.def_id(); self.typer.node_ty(freevar_def_id.node) - .unwrap_or(ty::mk_err()) + .unwrap_or(ty::mk_err()).subst(self.tcx(), substs) }) .collect(); Ok(If(tys)) @@ -1548,8 +1548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(VtableImpl(vtable_impl)) } - UnboxedClosureCandidate(closure_def_id) => { - try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id)); + UnboxedClosureCandidate(closure_def_id, ref substs) => { + try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs)); Ok(VtableUnboxedClosure(closure_def_id)) } } @@ -1646,12 +1646,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_unboxed_closure_candidate(&mut self, obligation: &Obligation, - closure_def_id: ast::DefId) + closure_def_id: ast::DefId, + substs: &Substs) -> Result<(),SelectionError> { - debug!("confirm_unboxed_closure_candidate({},{})", + debug!("confirm_unboxed_closure_candidate({},{},{})", obligation.repr(self.tcx()), - closure_def_id.repr(self.tcx())); + closure_def_id.repr(self.tcx()), + substs.repr(self.tcx())); let closure_type = match self.typer.unboxed_closures().borrow().find(&closure_def_id) { Some(closure) => closure.closure_type.clone(), @@ -1678,7 +1680,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_ref = Rc::new(ty::TraitRef { def_id: obligation.trait_ref.def_id, substs: Substs::new_trait( - vec![arguments_tuple, new_signature.output], + vec![arguments_tuple.subst(self.tcx(), substs), + new_signature.output.subst(self.tcx(), substs)], vec![], obligation.self_ty()) }); @@ -1959,7 +1962,9 @@ impl Repr for Candidate { match *self { ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({})", b), - UnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c), + UnboxedClosureCandidate(c, ref s) => { + format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx)) + } ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index 438bb337e3f..2525da8863f 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -176,8 +176,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr { return Univariant(mk_struct(cx, ftys.as_slice(), packed, t), dtor) } - ty::ty_unboxed_closure(def_id, _) => { - let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id); + ty::ty_unboxed_closure(def_id, _, ref substs) => { + let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t), false) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index b92b9e84a95..a739f6e3db2 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -253,21 +253,19 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De } pub fn self_type_for_unboxed_closure(ccx: &CrateContext, - closure_id: ast::DefId) + closure_id: ast::DefId, + fn_ty: ty::t) -> ty::t { - let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(), - closure_id, - ty::ReStatic); let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); let unboxed_closure = &(*unboxed_closures)[closure_id]; match unboxed_closure.kind { ty::FnUnboxedClosureKind => { - ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type) + ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, fn_ty) } ty::FnMutUnboxedClosureKind => { - ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type) + ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, fn_ty) } - ty::FnOnceUnboxedClosureKind => unboxed_closure_type, + ty::FnOnceUnboxedClosureKind => fn_ty } } @@ -285,14 +283,14 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef { ty::ty_closure(ref f) => { (f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx))) } - ty::ty_unboxed_closure(closure_did, _) => { + ty::ty_unboxed_closure(closure_did, _, ref substs) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); let unboxed_closure = &(*unboxed_closures)[closure_did]; let function_type = unboxed_closure.closure_type.clone(); - let self_type = self_type_for_unboxed_closure(ccx, closure_did); + let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty); let llenvironment_type = type_of_explicit_arg(ccx, self_type); - (function_type.sig.inputs.clone(), - function_type.sig.output, + (function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(), + function_type.sig.output.subst(ccx.tcx(), substs), RustCall, Some(llenvironment_type)) } @@ -738,9 +736,9 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, } }) } - ty::ty_unboxed_closure(def_id, _) => { + ty::ty_unboxed_closure(def_id, _, ref substs) => { let repr = adt::represent_type(cx.ccx(), t); - let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id); + let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs); for (i, upvar) in upvars.iter().enumerate() { let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i); cx = f(cx, llupvar, upvar.ty); @@ -2351,12 +2349,12 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty { ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true), ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false), - ty::ty_unboxed_closure(closure_did, _) => { + ty::ty_unboxed_closure(closure_did, _, ref substs) => { let unboxed_closures = ccx.tcx().unboxed_closures.borrow(); let ref function_type = (*unboxed_closures)[closure_did] .closure_type; - (function_type.sig.clone(), RustCall, true) + (function_type.sig.subst(ccx.tcx(), substs), RustCall, true) } _ => ccx.sess().bug("expected closure or function.") }; @@ -2371,7 +2369,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) // These have an odd calling convention, so we need to manually // unpack the input ty's let input_tys = match ty::get(fn_ty).sty { - ty::ty_unboxed_closure(_, _) => { + ty::ty_unboxed_closure(_, _, _) => { assert!(abi == RustCall); match ty::get(fn_sig.inputs[0]).sty { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 22fd943b68c..b8895e9486a 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -491,7 +491,7 @@ pub fn trans_fn_ref_with_substs( }; // If this is an unboxed closure, redirect to it. - match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) { + match closure::get_or_create_declaration_if_unboxed_closure(bcx, def_id) { None => {} Some(llfn) => return llfn, } diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 94df7fa57db..d4e1473f0e5 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -23,6 +23,7 @@ use middle::trans::common::*; use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum}; use middle::trans::debuginfo; use middle::trans::expr; +use middle::trans::monomorphize::MonoId; use middle::trans::type_of::*; use middle::trans::type_::Type; use middle::ty; @@ -312,7 +313,8 @@ fn load_unboxed_closure_environment<'blk, 'tcx>( } // Special case for small by-value selfs. - let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id); + let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id, + node_id_type(bcx, closure_id.node)); let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id); let llenv = if kind == ty::FnOnceUnboxedClosureKind && !arg_is_indirect(bcx.ccx(), self_type) { @@ -418,15 +420,26 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Returns the LLVM function declaration for an unboxed closure, creating it /// if necessary. If the ID does not correspond to a closure ID, returns None. -pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext, - closure_id: ast::DefId) - -> Option { +pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + closure_id: ast::DefId) + -> Option { + let ccx = bcx.ccx(); if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) { // Not an unboxed closure. return None } - match ccx.unboxed_closure_vals().borrow().find(&closure_id) { + let function_type = node_id_type(bcx, closure_id.node); + let params = match ty::get(function_type).sty { + ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(), + _ => unreachable!() + }; + let mono_id = MonoId { + def: closure_id, + params: params + }; + + match ccx.unboxed_closure_vals().borrow().find(&mono_id) { Some(llfn) => { debug!("get_or_create_declaration_if_unboxed_closure(): found \ closure"); @@ -435,9 +448,7 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext, None => {} } - let function_type = ty::mk_unboxed_closure(ccx.tcx(), - closure_id, - ty::ReStatic); + let function_type = node_id_type(bcx, closure_id.node); let symbol = ccx.tcx().map.with_path(closure_id.node, |path| { mangle_internal_name_by_path_and_seq(path, "unboxed_closure") }); @@ -449,9 +460,9 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext, debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \ closure {} (type {})", - closure_id, + mono_id, ccx.tn().type_to_string(val_ty(llfn))); - ccx.unboxed_closure_vals().borrow_mut().insert(closure_id, llfn); + ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn); Some(llfn) } @@ -469,7 +480,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( let closure_id = ast_util::local_def(id); let llfn = get_or_create_declaration_if_unboxed_closure( - bcx.ccx(), + bcx, closure_id).unwrap(); let unboxed_closures = bcx.tcx().unboxed_closures.borrow(); diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 90159389688..64ad88630f4 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -138,7 +138,7 @@ pub struct LocalCrateContext { builder: BuilderRef_res, /// Holds the LLVM values for closure IDs. - unboxed_closure_vals: RefCell>, + unboxed_closure_vals: RefCell>, dbg_cx: Option, @@ -419,7 +419,7 @@ impl LocalCrateContext { int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), - unboxed_closure_vals: RefCell::new(DefIdMap::new()), + unboxed_closure_vals: RefCell::new(HashMap::new()), dbg_cx: dbg_cx, eh_personality: RefCell::new(None), intrinsics: RefCell::new(HashMap::new()), @@ -689,7 +689,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local.opaque_vec_type } - pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell> { + pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell> { &self.local.unboxed_closure_vals } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 3e07eaf9586..3368b2b7765 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -190,7 +190,7 @@ use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::*; use metadata::csearch; -use middle::subst; +use middle::subst::{mod, Subst}; use middle::trans::adt; use middle::trans::common::*; use middle::trans::machine; @@ -460,9 +460,9 @@ impl TypeMap { closure_ty.clone(), &mut unique_type_id); }, - ty::ty_unboxed_closure(ref def_id, _) => { + ty::ty_unboxed_closure(ref def_id, _, ref substs) => { let closure_ty = cx.tcx().unboxed_closures.borrow() - .find(def_id).unwrap().closure_type.clone(); + .find(def_id).unwrap().closure_type.subst(cx.tcx(), substs); self.get_unique_type_id_of_closure_type(cx, closure_ty, &mut unique_type_id); @@ -2911,9 +2911,9 @@ fn type_metadata(cx: &CrateContext, ty::ty_closure(ref closurety) => { subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span) } - ty::ty_unboxed_closure(ref def_id, _) => { + ty::ty_unboxed_closure(ref def_id, _, ref substs) => { let sig = cx.tcx().unboxed_closures.borrow() - .find(def_id).unwrap().closure_type.sig.clone(); + .find(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs); subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) } ty::ty_struct(def_id, ref substs) => { diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 24b41fe144a..bab11c30204 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -344,13 +344,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableUnboxedClosure(closure_def_id) => { - // The static region and type parameters are lies, but we're in - // trans so it doesn't matter. - // - // FIXME(pcwalton): Is this true in the case of type parameters? - let callee_substs = get_callee_substitutions_for_unboxed_closure( + let self_ty = node_id_type(bcx, closure_def_id.node); + let callee_substs = get_callee_substitutions_for_unboxed_closure( bcx, - closure_def_id); + self_ty); let llfn = trans_fn_ref_with_substs(bcx, closure_def_id, @@ -504,24 +501,22 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; } -/// Creates the self type and (fake) callee substitutions for an unboxed -/// closure with the given def ID. The static region and type parameters are -/// lies, but we're in trans so it doesn't matter. +/// Looks up the substitutions for an unboxed closure and adds the +/// self type fn get_callee_substitutions_for_unboxed_closure(bcx: Block, - def_id: ast::DefId) + self_ty: ty::t) -> subst::Substs { - let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id, ty::ReStatic); - subst::Substs::erased( - VecPerParamSpace::new(Vec::new(), - vec![ - ty::mk_rptr(bcx.tcx(), - ty::ReStatic, - ty::mt { + match ty::get(self_ty).sty { + ty::ty_unboxed_closure(_, _, ref substs) => { + substs.with_self_ty(ty::mk_rptr(bcx.tcx(), + ty::ReStatic, + ty::mt { ty: self_ty, mutbl: ast::MutMutable, - }) - ], - Vec::new())) + })) + }, + _ => unreachable!() + } } /// Creates a returns a dynamic vtable for the given type and vtable origin. @@ -569,10 +564,12 @@ pub fn get_vtable(bcx: Block, emit_vtable_methods(bcx, id, substs).into_iter() } traits::VtableUnboxedClosure(closure_def_id) => { + let self_ty = node_id_type(bcx, closure_def_id.node); + let callee_substs = get_callee_substitutions_for_unboxed_closure( bcx, - closure_def_id); + self_ty.clone()); let mut llfn = trans_fn_ref_with_substs( bcx, @@ -590,25 +587,28 @@ pub fn get_vtable(bcx: Block, unboxed closure"); if closure_info.kind == ty::FnOnceUnboxedClosureKind { // Untuple the arguments and create an unboxing shim. - let mut new_inputs = vec![ - ty::mk_unboxed_closure(bcx.tcx(), - closure_def_id, - ty::ReStatic) - ]; - match ty::get(closure_info.closure_type - .sig - .inputs[0]).sty { - ty::ty_tup(ref elements) => { - for element in elements.iter() { - new_inputs.push(*element) + let (new_inputs, new_output) = match ty::get(self_ty).sty { + ty::ty_unboxed_closure(_, _, ref substs) => { + let mut new_inputs = vec![self_ty.clone()]; + match ty::get(closure_info.closure_type + .sig + .inputs[0]).sty { + ty::ty_tup(ref elements) => { + for element in elements.iter() { + new_inputs.push(element.subst(bcx.tcx(), substs)); + } + } + ty::ty_nil => {} + _ => { + bcx.tcx().sess.bug("get_vtable(): closure \ + type wasn't a tuple") + } } - } - ty::ty_nil => {} - _ => { - bcx.tcx().sess.bug("get_vtable(): closure \ - type wasn't a tuple") - } - } + (new_inputs, + closure_info.closure_type.sig.output.subst(bcx.tcx(), substs)) + }, + _ => bcx.tcx().sess.bug("get_vtable(): def wasn't an unboxed closure") + }; let closure_type = ty::BareFnTy { fn_style: closure_info.closure_type.fn_style, @@ -618,7 +618,7 @@ pub fn get_vtable(bcx: Block, .sig .binder_id, inputs: new_inputs, - output: closure_info.closure_type.sig.output, + output: new_output, variadic: false, }, }; diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 989ac63cd5c..6d7985767ab 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -309,11 +309,15 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { let name = llvm_type_name(cx, an_enum, did, tps); adt::incomplete_type_of(cx, &*repr, name.as_slice()) } - ty::ty_unboxed_closure(did, _) => { + ty::ty_unboxed_closure(did, _, ref substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, an_unboxed_closure, did, []); + // Unboxed closures can have substitutions in all spaces + // inherited from their environment, so we use entire + // contents of the VecPerParamSpace to to construct the llvm + // name + let name = llvm_type_name(cx, an_unboxed_closure, did, substs.types.as_slice()); adt::incomplete_type_of(cx, &*repr, name.as_slice()) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 569c256a738..7fedea67f79 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -962,7 +962,7 @@ pub enum sty { ty_closure(Box), ty_trait(Box), ty_struct(DefId, Substs), - ty_unboxed_closure(DefId, Region), + ty_unboxed_closure(DefId, Region, Substs), ty_tup(Vec), ty_param(ParamTy), // type parameter @@ -1636,7 +1636,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { flags = flags | HAS_PARAMS; } } - &ty_unboxed_closure(_, ref region) => flags = flags | rflags(*region), + &ty_unboxed_closure(_, ref region, ref substs) => { + flags = flags | rflags(*region); + flags = flags | sflags(substs); + } &ty_infer(_) => flags = flags | HAS_TY_INFER, &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => { flags = flags | sflags(substs); @@ -1885,9 +1888,9 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t { mk_t(cx, ty_struct(struct_id, substs)) } -pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId, region: Region) +pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId, region: Region, substs: Substs) -> t { - mk_t(cx, ty_unboxed_closure(closure_id, region)) + mk_t(cx, ty_unboxed_closure(closure_id, region, substs)) } pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) } @@ -1922,12 +1925,12 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) { } match get(ty).sty { ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {} + ty_str | ty_infer(_) | ty_param(_) | ty_err => {} ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f), ty_ptr(ref tm) | ty_rptr(_, ref tm) => { maybe_walk_ty(tm.ty, f); } - ty_enum(_, ref substs) | ty_struct(_, ref substs) | + ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_unboxed_closure(_, _, ref substs) | ty_trait(box TyTrait { ref substs, .. }) => { for subty in (*substs).types.iter() { maybe_walk_ty(*subty, |x| f(x)); @@ -2484,10 +2487,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents { apply_lang_items(cx, did, res) } - ty_unboxed_closure(did, r) => { + ty_unboxed_closure(did, r, ref substs) => { // FIXME(#14449): `borrowed_contents` below assumes `&mut` // unboxed closure. - let upvars = unboxed_closure_upvars(cx, did); + let upvars = unboxed_closure_upvars(cx, did, substs); TypeContents::union(upvars.as_slice(), |f| tc_ty(cx, f.ty, cache)) | borrowed_contents(r, MutMutable) @@ -2781,8 +2784,8 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool { r } - ty_unboxed_closure(did, _) => { - let upvars = unboxed_closure_upvars(cx, did); + ty_unboxed_closure(did, _, ref substs) => { + let upvars = unboxed_closure_upvars(cx, did, substs); upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty)) } @@ -2869,8 +2872,8 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { find_nonrepresentable(cx, sp, seen, iter) } - ty_unboxed_closure(did, _) => { - let upvars = unboxed_closure_upvars(cx, did); + ty_unboxed_closure(did, _, ref substs) => { + let upvars = unboxed_closure_upvars(cx, did, substs); find_nonrepresentable(cx, sp, seen, upvars.iter().map(|f| f.ty)) } _ => Representable, @@ -4225,7 +4228,7 @@ pub fn ty_to_def_id(ty: t) -> Option { ty_trait(box TyTrait { def_id: id, .. }) | ty_struct(id, _) | ty_enum(id, _) | - ty_unboxed_closure(id, _) => Some(id), + ty_unboxed_closure(id, _, _) => Some(id), _ => None } } @@ -4623,7 +4626,7 @@ pub struct UnboxedClosureUpvar { } // Returns a list of `UnboxedClosureUpvar`s for each upvar. -pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId) +pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId, substs: &Substs) -> Vec { if closure_id.krate == ast::LOCAL_CRATE { let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node); @@ -4632,7 +4635,8 @@ pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId) Some(ref freevars) => { freevars.iter().map(|freevar| { let freevar_def_id = freevar.def.def_id(); - let mut freevar_ty = node_id_to_type(tcx, freevar_def_id.node); + let freevar_ty = node_id_to_type(tcx, freevar_def_id.node); + let mut freevar_ty = freevar_ty.subst(tcx, substs); if capture_mode == ast::CaptureByRef { let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId { var_id: freevar_def_id.node, @@ -5226,7 +5230,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 { ty_open(_) => byte!(22), ty_infer(_) => unreachable!(), ty_err => byte!(23), - ty_unboxed_closure(d, r) => { + ty_unboxed_closure(d, r, _) => { byte!(24); did(&mut state, d); region(&mut state, r); @@ -5503,14 +5507,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, .. }) | ty_struct(_, ref substs) => { - match substs.regions { - subst::ErasedRegions => {} - subst::NonerasedRegions(ref regions) => { - for region in regions.iter() { - accumulator.push(*region) - } - } - } + accum_substs(accumulator, substs); } ty_closure(ref closure_ty) => { match closure_ty.store { @@ -5518,7 +5515,10 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, UniqTraitStore => {} } } - ty_unboxed_closure(_, ref region) => accumulator.push(*region), + ty_unboxed_closure(_, ref region, ref substs) => { + accumulator.push(*region); + accum_substs(accumulator, substs); + } ty_nil | ty_bot | ty_bool | @@ -5537,7 +5537,18 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_open(_) | ty_err => {} } - }) + }); + + fn accum_substs(accumulator: &mut Vec, substs: &Substs) { + match substs.regions { + subst::ErasedRegions => {} + subst::NonerasedRegions(ref regions) => { + for region in regions.iter() { + accumulator.push(*region) + } + } + } + } } /// A free variable referred to in a function. diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index fa0c29d8883..c7fe8a19937 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -534,8 +534,8 @@ pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, ty::ty_struct(did, ref substs) => { ty::ty_struct(did, substs.fold_with(this)) } - ty::ty_unboxed_closure(did, ref region) => { - ty::ty_unboxed_closure(did, region.fold_with(this)) + ty::ty_unboxed_closure(did, ref region, ref substs) => { + ty::ty_unboxed_closure(did, region.fold_with(this), substs.fold_with(this)) } ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 66693224c87..f8604eeb5c6 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -505,7 +505,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } ty_enum(did, _) | ty_struct(did, _) | - ty_unboxed_closure(did, _) => { + ty_unboxed_closure(did, _, _) => { if self.check_traits == CheckTraitsAndInherentMethods { self.push_inherent_impl_candidates_for_type(did); } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 3d1385bac3b..5f6795f24c1 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3270,7 +3270,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt, }; let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx, local_def(expr.id), - region); + region, + fcx.inh.param_env.free_substs.clone()); fcx.write_ty(expr.id, closure_type); check_fn(fcx.ccx, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index deeee67ac6e..8585cacdbc4 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -867,7 +867,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, } }); } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, region, _) => { if tcx.capture_modes.borrow().get_copy(&expr.id) == ast::CaptureByRef { ty::with_freevars(tcx, expr.id, |freevars| { if !freevars.is_empty() { @@ -908,7 +908,7 @@ fn check_expr_fn_block(rcx: &mut Rcx, ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars); }) } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, region, _) => { ty::with_freevars(tcx, expr.id, |freevars| { let bounds = ty::region_existential_bound(region); ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars); diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index a448a93c517..06b633ba15b 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -108,7 +108,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { self.accumulate_from_closure_ty(ty, c); } - ty::ty_unboxed_closure(_, region) => { + ty::ty_unboxed_closure(_, region, _) => { // An "unboxed closure type" is basically // modeled here as equivalent to a struct like // @@ -118,6 +118,18 @@ impl<'a, 'tcx> Wf<'a, 'tcx> { // // where the `'b` is the lifetime bound of the // contents (i.e., all contents must outlive 'b). + // + // Even though unboxed closures are glorified structs + // of upvars, we do not need to consider them as they + // can't generate any new constraints. The + // substitutions on the closure are equal to the free + // substitutions of the enclosing parameter + // environment. An upvar captured by value has the + // same type as the original local variable which is + // already checked for consistency. If the upvar is + // captured by reference it must also outlive the + // region bound on the closure, but this is explicitly + // handled by logic in regionck. self.push_region_constraint_from_top(region); } diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index cb4e878c22c..38ac317b7a3 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -105,7 +105,7 @@ fn get_base_type_def_id(inference_context: &InferCtxt, match get(base_type).sty { ty_enum(def_id, _) | ty_struct(def_id, _) | - ty_unboxed_closure(def_id, _) => { + ty_unboxed_closure(def_id, _, _) => { Some(def_id) } ty_ptr(ty::mt {ty, ..}) | @@ -445,7 +445,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match ty::get(self_type.ty).sty { ty::ty_enum(type_def_id, _) | ty::ty_struct(type_def_id, _) | - ty::ty_unboxed_closure(type_def_id, _) => { + ty::ty_unboxed_closure(type_def_id, _, _) => { tcx.destructor_for_type .borrow_mut() .insert(type_def_id, method_def_id.def_id()); diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d2e062a20d2..de59fb80ad5 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -105,6 +105,15 @@ pub trait Combine<'tcx> { } else { None }; + self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst) + } + + fn substs_variances(&self, + variances: Option<&ty::ItemVariances>, + a_subst: &subst::Substs, + b_subst: &subst::Substs) + -> cres + { let mut substs = subst::Substs::empty(); for &space in subst::ParamSpace::all().iter() { @@ -126,7 +135,7 @@ pub trait Combine<'tcx> { let mut invariance = Vec::new(); let r_variances = match variances { - Some(ref variances) => { + Some(variances) => { variances.regions.get_slice(space) } None => { @@ -138,7 +147,6 @@ pub trait Combine<'tcx> { }; let regions = try!(relate_region_params(self, - item_def_id, r_variances, a_regions, b_regions)); @@ -150,7 +158,6 @@ pub trait Combine<'tcx> { return Ok(substs); fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C, - item_def_id: ast::DefId, variances: &[ty::Variance], a_rs: &[ty::Region], b_rs: &[ty::Region]) @@ -159,11 +166,9 @@ pub trait Combine<'tcx> { let num_region_params = variances.len(); debug!("relate_region_params(\ - item_def_id={}, \ a_rs={}, \ b_rs={}, variances={})", - item_def_id.repr(tcx), a_rs.repr(tcx), b_rs.repr(tcx), variances.repr(tcx)); @@ -464,14 +469,15 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres { // All ty_unboxed_closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let region = try!(this.equate().regions(a_region, b_region)); - Ok(ty::mk_unboxed_closure(tcx, a_id, region)) + let substs = try!(this.substs_variances(None, a_substs, b_substs)); + Ok(ty::mk_unboxed_closure(tcx, a_id, region, substs)) } (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index d9838cc6444..d8541a54bd9 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -734,9 +734,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /* leaf type -- noop */ } - ty::ty_unboxed_closure(_, region) => { - let contra = self.contravariant(variance); - self.add_constraints_from_region(region, contra); + ty::ty_unboxed_closure(..) => { + self.tcx().sess.bug("Unexpected unboxed closure type in variance computation"); } ty::ty_rptr(region, ref mt) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 81deae86faa..943570743e8 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -425,7 +425,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { bound_str) } ty_str => "str".to_string(), - ty_unboxed_closure(..) => "closure".to_string(), + ty_unboxed_closure(ref did, _, ref substs) => { + let unboxed_closures = cx.unboxed_closures.borrow(); + unboxed_closures.find(did).map(|cl| { + closure_to_string(cx, &cl.closure_type.subst(cx, substs)) + }).unwrap_or_else(|| "closure".to_string()) + } ty_vec(t, sz) => { match sz { Some(n) => {