Skip to content

Commit

Permalink
auto merge of #18144 : bkoropoff/rust/mighty-monomorphizin-unboxed-cl…
Browse files Browse the repository at this point in the history
…osures, r=nikomatsakis

This allows unboxed closures that reference free type/region parameters to be monomorphized correctly in trans.

It was necessary to make `ty_unboxed_closure` carry around a `Substs` to accomplish this.  Plumbing this through typeck revealed several areas where type/region parameters in unboxed closure types are possibly not being handled correctly.  Since my goal was just to fix trans, I decided to leave FIXME comments on areas that still need attention and seek feedback on the best way to clean them up, possibly as a follow-up PR.

Closes #16791
  • Loading branch information
bors committed Oct 28, 2014
2 parents bd7138d + e46af8c commit 823f805
Show file tree
Hide file tree
Showing 23 changed files with 238 additions and 145 deletions.
7 changes: 5 additions & 2 deletions src/librustc/metadata/tydecode.rs
Expand Up @@ -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();
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/metadata/tyencode.rs
Expand Up @@ -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");
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -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);
Expand Down
31 changes: 18 additions & 13 deletions src/librustc/middle/traits/select.rs
Expand Up @@ -110,7 +110,7 @@ enum Candidate {
BuiltinCandidate(ty::BuiltinBound),
ParamCandidate(VtableParamData),
ImplCandidate(ast::DefId),
UnboxedClosureCandidate(/* closure */ ast::DefId),
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs),
ErrorCandidate,
}

Expand Down Expand Up @@ -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(());
Expand All @@ -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(())
Expand Down Expand Up @@ -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
Expand All @@ -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))
Expand Down Expand Up @@ -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))
}
}
Expand Down Expand Up @@ -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(),
Expand All @@ -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())
});
Expand Down Expand Up @@ -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)),
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/adt.rs
Expand Up @@ -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::<Vec<_>>();
return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t),
false)
Expand Down
30 changes: 14 additions & 16 deletions src/librustc/middle/trans/base.rs
Expand Up @@ -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
}
}

Expand All @@ -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))
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.")
};
Expand All @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/callee.rs
Expand Up @@ -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,
}
Expand Down
33 changes: 22 additions & 11 deletions src/librustc/middle/trans/closure.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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<ValueRef> {
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
closure_id: ast::DefId)
-> Option<ValueRef> {
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");
Expand All @@ -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")
});
Expand All @@ -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)
}
Expand All @@ -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();
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/trans/context.rs
Expand Up @@ -138,7 +138,7 @@ pub struct LocalCrateContext {
builder: BuilderRef_res,

/// Holds the LLVM values for closure IDs.
unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
unboxed_closure_vals: RefCell<HashMap<MonoId, ValueRef>>,

dbg_cx: Option<debuginfo::CrateDebugContext>,

Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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<DefIdMap<ValueRef>> {
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<HashMap<MonoId,ValueRef>> {
&self.local.unboxed_closure_vals
}

Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/trans/debuginfo.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) => {
Expand Down

0 comments on commit 823f805

Please sign in to comment.