auto merge of #18144 : bkoropoff/rust/mighty-monomorphizin-unboxed-closures, 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
This commit is contained in:
bors 2014-10-28 03:26:52 +00:00
commit 823f805453
23 changed files with 238 additions and 145 deletions

View File

@ -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();

View File

@ -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");

View File

@ -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);

View File

@ -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)),
}

View File

@ -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)

View File

@ -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 {

View File

@ -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,
}

View File

@ -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<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");
@ -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();

View File

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

View File

@ -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) => {

View File

@ -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,
},
};

View File

@ -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())
}

View File

@ -962,7 +962,7 @@ pub enum sty {
ty_closure(Box<ClosureTy>),
ty_trait(Box<TyTrait>),
ty_struct(DefId, Substs),
ty_unboxed_closure(DefId, Region),
ty_unboxed_closure(DefId, Region, Substs),
ty_tup(Vec<t>),
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<ast::DefId> {
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<UnboxedClosureUpvar> {
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::Region>,
..
}) |
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<ty::Region>,
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::Region>,
ty_open(_) |
ty_err => {}
}
})
});
fn accum_substs(accumulator: &mut Vec<Region>, 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.

View File

@ -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(_) |

View File

@ -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);
}

View File

@ -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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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());

View File

@ -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<subst::Substs>
{
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<t
Ok(ty::mk_struct(tcx, a_id, substs))
}
(&ty::ty_unboxed_closure(a_id, a_region),
&ty::ty_unboxed_closure(b_id, b_region))
(&ty::ty_unboxed_closure(a_id, a_region, ref a_substs),
&ty::ty_unboxed_closure(b_id, b_region, ref b_substs))
if a_id == b_id => {
// 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)) => {

View File

@ -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) => {

View File

@ -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) => {

View File

@ -0,0 +1,36 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that unboxed closures in contexts with free type parameters
// monomorphize correctly (issue #16791)
#![feature(unboxed_closures)]
fn main(){
fn bar<'a, T:'a> (t: T) -> Box<FnOnce<(),T> + 'a> {
box move |:| t
}
let f = bar(42u);
assert_eq!(f.call_once(()), 42);
let f = bar("forty-two");
assert_eq!(f.call_once(()), "forty-two");
let x = 42u;
let f = bar(&x);
assert_eq!(f.call_once(()), &x);
#[deriving(Show, PartialEq)]
struct Foo(uint, &'static str);
let x = Foo(42, "forty-two");
let f = bar(x);
assert_eq!(f.call_once(()), x);
}