Skip to content

Commit f0cc3a9

Browse files
committed
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
1 parent bd7138d commit f0cc3a9

22 files changed

+202
-145
lines changed

src/librustc/metadata/tydecode.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -465,9 +465,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
465465
return ty::mk_struct(st.tcx, did, substs);
466466
}
467467
'k' => {
468+
assert_eq!(next(st), '[');
468469
let did = parse_def(st, NominalType, |x,y| conv(x,y));
469-
let region = parse_region(st, conv);
470-
return ty::mk_unboxed_closure(st.tcx, did, region);
470+
let region = parse_region(st, |x,y| conv(x,y));
471+
let substs = parse_substs(st, |x,y| conv(x,y));
472+
assert_eq!(next(st), ']');
473+
return ty::mk_unboxed_closure(st.tcx, did, region, substs);
471474
}
472475
'e' => {
473476
return ty::mk_err();

src/librustc/metadata/tyencode.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
285285
enc_substs(w, cx, substs);
286286
mywrite!(w, "]");
287287
}
288-
ty::ty_unboxed_closure(def, region) => {
289-
mywrite!(w, "k{}", (cx.ds)(def));
288+
ty::ty_unboxed_closure(def, region, ref substs) => {
289+
mywrite!(w, "k[{}|", (cx.ds)(def));
290290
enc_region(w, cx, region);
291+
enc_substs(w, cx, substs);
292+
mywrite!(w, "]");
291293
}
292294
ty::ty_err => {
293295
mywrite!(w, "e");

src/librustc/middle/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
594594
};
595595
self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false)
596596
}
597-
ty::ty_unboxed_closure(closure_id, _) => {
597+
ty::ty_unboxed_closure(closure_id, _, _) => {
598598
let unboxed_closures = self.typer.unboxed_closures().borrow();
599599
let kind = (*unboxed_closures)[closure_id].kind;
600600
let mode = self.typer.capture_mode(fn_node_id);

src/librustc/middle/traits/select.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ enum Candidate {
110110
BuiltinCandidate(ty::BuiltinBound),
111111
ParamCandidate(VtableParamData),
112112
ImplCandidate(ast::DefId),
113-
UnboxedClosureCandidate(/* closure */ ast::DefId),
113+
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs),
114114
ErrorCandidate,
115115
}
116116

@@ -995,8 +995,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
995995
};
996996

997997
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
998-
let closure_def_id = match ty::get(self_ty).sty {
999-
ty::ty_unboxed_closure(id, _) => id,
998+
let (closure_def_id, substs) = match ty::get(self_ty).sty {
999+
ty::ty_unboxed_closure(id, _, ref substs) => (id, substs.clone()),
10001000
ty::ty_infer(ty::TyVar(_)) => {
10011001
candidates.ambiguous = true;
10021002
return Ok(());
@@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10191019
};
10201020

10211021
if closure_kind == kind {
1022-
candidates.vec.push(UnboxedClosureCandidate(closure_def_id));
1022+
candidates.vec.push(UnboxedClosureCandidate(closure_def_id, substs.clone()));
10231023
}
10241024

10251025
Ok(())
@@ -1383,7 +1383,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13831383
Ok(If(tys.clone()))
13841384
}
13851385

1386-
ty::ty_unboxed_closure(def_id, _) => {
1386+
ty::ty_unboxed_closure(def_id, _, ref substs) => {
13871387
// FIXME -- This case is tricky. In the case of by-ref
13881388
// closures particularly, we need the results of
13891389
// inference to decide how to reflect the type of each
@@ -1407,7 +1407,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
14071407
.map(|freevar| {
14081408
let freevar_def_id = freevar.def.def_id();
14091409
self.typer.node_ty(freevar_def_id.node)
1410-
.unwrap_or(ty::mk_err())
1410+
.unwrap_or(ty::mk_err()).subst(self.tcx(), substs)
14111411
})
14121412
.collect();
14131413
Ok(If(tys))
@@ -1548,8 +1548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15481548
Ok(VtableImpl(vtable_impl))
15491549
}
15501550

1551-
UnboxedClosureCandidate(closure_def_id) => {
1552-
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id));
1551+
UnboxedClosureCandidate(closure_def_id, ref substs) => {
1552+
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs));
15531553
Ok(VtableUnboxedClosure(closure_def_id))
15541554
}
15551555
}
@@ -1646,12 +1646,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16461646

16471647
fn confirm_unboxed_closure_candidate(&mut self,
16481648
obligation: &Obligation,
1649-
closure_def_id: ast::DefId)
1649+
closure_def_id: ast::DefId,
1650+
substs: &Substs)
16501651
-> Result<(),SelectionError>
16511652
{
1652-
debug!("confirm_unboxed_closure_candidate({},{})",
1653+
debug!("confirm_unboxed_closure_candidate({},{},{})",
16531654
obligation.repr(self.tcx()),
1654-
closure_def_id.repr(self.tcx()));
1655+
closure_def_id.repr(self.tcx()),
1656+
substs.repr(self.tcx()));
16551657

16561658
let closure_type = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
16571659
Some(closure) => closure.closure_type.clone(),
@@ -1678,7 +1680,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16781680
let trait_ref = Rc::new(ty::TraitRef {
16791681
def_id: obligation.trait_ref.def_id,
16801682
substs: Substs::new_trait(
1681-
vec![arguments_tuple, new_signature.output],
1683+
vec![arguments_tuple.subst(self.tcx(), substs),
1684+
new_signature.output.subst(self.tcx(), substs)],
16821685
vec![],
16831686
obligation.self_ty())
16841687
});
@@ -1959,7 +1962,9 @@ impl Repr for Candidate {
19591962
match *self {
19601963
ErrorCandidate => format!("ErrorCandidate"),
19611964
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
1962-
UnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c),
1965+
UnboxedClosureCandidate(c, ref s) => {
1966+
format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
1967+
}
19631968
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
19641969
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
19651970
}

src/librustc/middle/trans/adt.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
176176

177177
return Univariant(mk_struct(cx, ftys.as_slice(), packed, t), dtor)
178178
}
179-
ty::ty_unboxed_closure(def_id, _) => {
180-
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
179+
ty::ty_unboxed_closure(def_id, _, ref substs) => {
180+
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
181181
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
182182
return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t),
183183
false)

src/librustc/middle/trans/base.rs

+14-16
Original file line numberDiff line numberDiff line change
@@ -253,21 +253,19 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
253253
}
254254

255255
pub fn self_type_for_unboxed_closure(ccx: &CrateContext,
256-
closure_id: ast::DefId)
256+
closure_id: ast::DefId,
257+
fn_ty: ty::t)
257258
-> ty::t {
258-
let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(),
259-
closure_id,
260-
ty::ReStatic);
261259
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
262260
let unboxed_closure = &(*unboxed_closures)[closure_id];
263261
match unboxed_closure.kind {
264262
ty::FnUnboxedClosureKind => {
265-
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
263+
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
266264
}
267265
ty::FnMutUnboxedClosureKind => {
268-
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
266+
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
269267
}
270-
ty::FnOnceUnboxedClosureKind => unboxed_closure_type,
268+
ty::FnOnceUnboxedClosureKind => fn_ty
271269
}
272270
}
273271

@@ -285,14 +283,14 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
285283
ty::ty_closure(ref f) => {
286284
(f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx)))
287285
}
288-
ty::ty_unboxed_closure(closure_did, _) => {
286+
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
289287
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
290288
let unboxed_closure = &(*unboxed_closures)[closure_did];
291289
let function_type = unboxed_closure.closure_type.clone();
292-
let self_type = self_type_for_unboxed_closure(ccx, closure_did);
290+
let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty);
293291
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
294-
(function_type.sig.inputs.clone(),
295-
function_type.sig.output,
292+
(function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(),
293+
function_type.sig.output.subst(ccx.tcx(), substs),
296294
RustCall,
297295
Some(llenvironment_type))
298296
}
@@ -738,9 +736,9 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
738736
}
739737
})
740738
}
741-
ty::ty_unboxed_closure(def_id, _) => {
739+
ty::ty_unboxed_closure(def_id, _, ref substs) => {
742740
let repr = adt::represent_type(cx.ccx(), t);
743-
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
741+
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
744742
for (i, upvar) in upvars.iter().enumerate() {
745743
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
746744
cx = f(cx, llupvar, upvar.ty);
@@ -2351,12 +2349,12 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
23512349
let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
23522350
ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
23532351
ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
2354-
ty::ty_unboxed_closure(closure_did, _) => {
2352+
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
23552353
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
23562354
let ref function_type = (*unboxed_closures)[closure_did]
23572355
.closure_type;
23582356

2359-
(function_type.sig.clone(), RustCall, true)
2357+
(function_type.sig.subst(ccx.tcx(), substs), RustCall, true)
23602358
}
23612359
_ => ccx.sess().bug("expected closure or function.")
23622360
};
@@ -2371,7 +2369,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
23712369
// These have an odd calling convention, so we need to manually
23722370
// unpack the input ty's
23732371
let input_tys = match ty::get(fn_ty).sty {
2374-
ty::ty_unboxed_closure(_, _) => {
2372+
ty::ty_unboxed_closure(_, _, _) => {
23752373
assert!(abi == RustCall);
23762374

23772375
match ty::get(fn_sig.inputs[0]).sty {

src/librustc/middle/trans/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ pub fn trans_fn_ref_with_substs(
491491
};
492492

493493
// If this is an unboxed closure, redirect to it.
494-
match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) {
494+
match closure::get_or_create_declaration_if_unboxed_closure(bcx, def_id) {
495495
None => {}
496496
Some(llfn) => return llfn,
497497
}

src/librustc/middle/trans/closure.rs

+22-11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use middle::trans::common::*;
2323
use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
2424
use middle::trans::debuginfo;
2525
use middle::trans::expr;
26+
use middle::trans::monomorphize::MonoId;
2627
use middle::trans::type_of::*;
2728
use middle::trans::type_::Type;
2829
use middle::ty;
@@ -312,7 +313,8 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
312313
}
313314

314315
// Special case for small by-value selfs.
315-
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id);
316+
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id,
317+
node_id_type(bcx, closure_id.node));
316318
let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id);
317319
let llenv = if kind == ty::FnOnceUnboxedClosureKind &&
318320
!arg_is_indirect(bcx.ccx(), self_type) {
@@ -418,15 +420,26 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
418420

419421
/// Returns the LLVM function declaration for an unboxed closure, creating it
420422
/// if necessary. If the ID does not correspond to a closure ID, returns None.
421-
pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
422-
closure_id: ast::DefId)
423-
-> Option<ValueRef> {
423+
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
424+
closure_id: ast::DefId)
425+
-> Option<ValueRef> {
426+
let ccx = bcx.ccx();
424427
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
425428
// Not an unboxed closure.
426429
return None
427430
}
428431

429-
match ccx.unboxed_closure_vals().borrow().find(&closure_id) {
432+
let function_type = node_id_type(bcx, closure_id.node);
433+
let params = match ty::get(function_type).sty {
434+
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
435+
_ => unreachable!()
436+
};
437+
let mono_id = MonoId {
438+
def: closure_id,
439+
params: params
440+
};
441+
442+
match ccx.unboxed_closure_vals().borrow().find(&mono_id) {
430443
Some(llfn) => {
431444
debug!("get_or_create_declaration_if_unboxed_closure(): found \
432445
closure");
@@ -435,9 +448,7 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
435448
None => {}
436449
}
437450

438-
let function_type = ty::mk_unboxed_closure(ccx.tcx(),
439-
closure_id,
440-
ty::ReStatic);
451+
let function_type = node_id_type(bcx, closure_id.node);
441452
let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
442453
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
443454
});
@@ -449,9 +460,9 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
449460

450461
debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
451462
closure {} (type {})",
452-
closure_id,
463+
mono_id,
453464
ccx.tn().type_to_string(val_ty(llfn)));
454-
ccx.unboxed_closure_vals().borrow_mut().insert(closure_id, llfn);
465+
ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn);
455466

456467
Some(llfn)
457468
}
@@ -469,7 +480,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
469480

470481
let closure_id = ast_util::local_def(id);
471482
let llfn = get_or_create_declaration_if_unboxed_closure(
472-
bcx.ccx(),
483+
bcx,
473484
closure_id).unwrap();
474485

475486
let unboxed_closures = bcx.tcx().unboxed_closures.borrow();

src/librustc/middle/trans/context.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub struct LocalCrateContext {
138138
builder: BuilderRef_res,
139139

140140
/// Holds the LLVM values for closure IDs.
141-
unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
141+
unboxed_closure_vals: RefCell<HashMap<MonoId, ValueRef>>,
142142

143143
dbg_cx: Option<debuginfo::CrateDebugContext>,
144144

@@ -419,7 +419,7 @@ impl LocalCrateContext {
419419
int_type: Type::from_ref(ptr::null_mut()),
420420
opaque_vec_type: Type::from_ref(ptr::null_mut()),
421421
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
422-
unboxed_closure_vals: RefCell::new(DefIdMap::new()),
422+
unboxed_closure_vals: RefCell::new(HashMap::new()),
423423
dbg_cx: dbg_cx,
424424
eh_personality: RefCell::new(None),
425425
intrinsics: RefCell::new(HashMap::new()),
@@ -689,7 +689,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
689689
self.local.opaque_vec_type
690690
}
691691

692-
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> {
692+
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<HashMap<MonoId,ValueRef>> {
693693
&self.local.unboxed_closure_vals
694694
}
695695

src/librustc/middle/trans/debuginfo.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ use llvm;
190190
use llvm::{ModuleRef, ContextRef, ValueRef};
191191
use llvm::debuginfo::*;
192192
use metadata::csearch;
193-
use middle::subst;
193+
use middle::subst::{mod, Subst};
194194
use middle::trans::adt;
195195
use middle::trans::common::*;
196196
use middle::trans::machine;
@@ -460,9 +460,9 @@ impl TypeMap {
460460
closure_ty.clone(),
461461
&mut unique_type_id);
462462
},
463-
ty::ty_unboxed_closure(ref def_id, _) => {
463+
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
464464
let closure_ty = cx.tcx().unboxed_closures.borrow()
465-
.find(def_id).unwrap().closure_type.clone();
465+
.find(def_id).unwrap().closure_type.subst(cx.tcx(), substs);
466466
self.get_unique_type_id_of_closure_type(cx,
467467
closure_ty,
468468
&mut unique_type_id);
@@ -2911,9 +2911,9 @@ fn type_metadata(cx: &CrateContext,
29112911
ty::ty_closure(ref closurety) => {
29122912
subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
29132913
}
2914-
ty::ty_unboxed_closure(ref def_id, _) => {
2914+
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
29152915
let sig = cx.tcx().unboxed_closures.borrow()
2916-
.find(def_id).unwrap().closure_type.sig.clone();
2916+
.find(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs);
29172917
subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)
29182918
}
29192919
ty::ty_struct(def_id, ref substs) => {

0 commit comments

Comments
 (0)