1
Fork 0

Fix handling of unboxed closure type param substitutions

- When selecting an implicit trait impl for an unboxed closure, plumb
  through and use the substitutions from impl selection instead of
  using those from the current param environment in trans, which may
  be incorrect.
- When generating a function declaration for an unboxed closure, plumb
  through the substitutions from the param environment of the closure
  as above.  Also normalize the type to avoid generating duplicate
  declarations due to regions being inconsistently replaced with
  ReStatic elsewhere.
- Do not place the closure type in the self param space when
  translating the unboxed closure callee, etc.  It is not actually
  used, and doing so conflicts with the self substitution from
  default trait methods.

Closes #18661
Closes #18685
This commit is contained in:
Brian Koropoff 2014-11-05 23:50:10 -08:00
parent 63c4f22f2b
commit daa215e8c5
7 changed files with 41 additions and 50 deletions

View file

@ -176,7 +176,7 @@ pub enum Vtable<N> {
/// ID is the ID of the closure expression. This is a `VtableImpl`
/// in spirit, but the impl is generated by the compiler and does
/// not appear in the source.
VtableUnboxedClosure(ast::DefId),
VtableUnboxedClosure(ast::DefId, subst::Substs),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter.
@ -338,7 +338,7 @@ impl<N> Vtable<N> {
pub fn iter_nested(&self) -> Items<N> {
match *self {
VtableImpl(ref i) => i.iter_nested(),
VtableUnboxedClosure(_) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
}
@ -347,7 +347,7 @@ impl<N> Vtable<N> {
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<M> {
match *self {
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
VtableParam(ref p) => VtableParam((*p).clone()),
VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
}
@ -356,7 +356,7 @@ impl<N> Vtable<N> {
pub fn map_move_nested<M>(self, op: |N| -> M) -> Vtable<M> {
match self {
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
VtableParam(p) => VtableParam(p),
VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),
}

View file

@ -1558,9 +1558,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(VtableImpl(vtable_impl))
}
UnboxedClosureCandidate(closure_def_id, ref substs) => {
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs));
Ok(VtableUnboxedClosure(closure_def_id))
UnboxedClosureCandidate(closure_def_id, substs) => {
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs));
Ok(VtableUnboxedClosure(closure_def_id, substs))
}
}
}

View file

@ -311,9 +311,10 @@ impl<N:Repr> Repr for super::Vtable<N> {
super::VtableImpl(ref v) =>
v.repr(tcx),
super::VtableUnboxedClosure(ref d) =>
format!("VtableUnboxedClosure({})",
d.repr(tcx)),
super::VtableUnboxedClosure(ref d, ref s) =>
format!("VtableUnboxedClosure({},{})",
d.repr(tcx),
s.repr(tcx)),
super::VtableParam(ref v) =>
format!("VtableParam({})", v.repr(tcx)),

View file

@ -490,7 +490,9 @@ 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(bcx, def_id) {
match closure::get_or_create_declaration_if_unboxed_closure(bcx,
def_id,
&substs) {
None => {}
Some(llfn) => return llfn,
}

View file

@ -27,6 +27,7 @@ use middle::trans::monomorphize::MonoId;
use middle::trans::type_of::*;
use middle::trans::type_::Type;
use middle::ty;
use middle::subst::{Subst, Substs};
use util::ppaux::Repr;
use util::ppaux::ty_to_string;
@ -420,7 +421,8 @@ 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<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
closure_id: ast::DefId)
closure_id: ast::DefId,
substs: &Substs)
-> Option<ValueRef> {
let ccx = bcx.ccx();
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
@ -428,7 +430,12 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
return None
}
let function_type = node_id_type(bcx, closure_id.node);
let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node);
let function_type = function_type.subst(bcx.tcx(), substs);
// Normalize type so differences in regions and typedefs don't cause
// duplicate declarations
let function_type = ty::normalize_ty(bcx.tcx(), function_type);
let params = match ty::get(function_type).sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!()
@ -447,7 +454,6 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
None => {}
}
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")
});
@ -480,7 +486,8 @@ 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,
closure_id).unwrap();
closure_id,
&bcx.fcx.param_substs.substs).unwrap();
let unboxed_closures = bcx.tcx().unboxed_closures.borrow();
let function_type = (*unboxed_closures)[closure_id]

View file

@ -355,16 +355,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Callee { bcx: bcx, data: Fn(llfn) }
}
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,
self_ty);
traits::VtableUnboxedClosure(closure_def_id, substs) => {
// The substitutions should have no type parameters remaining
// after passing through fulfill_obligation
let llfn = trans_fn_ref_with_substs(bcx,
closure_def_id,
MethodCall(method_call),
callee_substs);
substs);
Callee {
bcx: bcx,
@ -518,24 +515,6 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
};
}
/// Looks up the substitutions for an unboxed closure and adds the
/// self type
fn get_callee_substitutions_for_unboxed_closure(bcx: Block,
self_ty: ty::t)
-> subst::Substs {
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,
}))
},
_ => unreachable!()
}
}
/// Creates a returns a dynamic vtable for the given type and vtable origin.
/// This is used only for objects.
///
@ -580,19 +559,19 @@ pub fn get_vtable(bcx: Block,
nested: _ }) => {
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,
self_ty.clone());
traits::VtableUnboxedClosure(closure_def_id, substs) => {
// Look up closure type
let self_ty = ty::node_id_to_type(bcx.tcx(), closure_def_id.node);
// Apply substitutions from closure param environment.
// The substitutions should have no type parameters
// remaining after passing through fulfill_obligation
let self_ty = self_ty.subst(bcx.tcx(), &substs);
let mut llfn = trans_fn_ref_with_substs(
bcx,
closure_def_id,
ExprId(0),
callee_substs.clone());
substs.clone());
{
let unboxed_closures = bcx.tcx()
@ -645,7 +624,7 @@ pub fn get_vtable(bcx: Block,
llfn,
&closure_type,
closure_def_id,
callee_substs);
substs);
}
}

View file

@ -414,7 +414,9 @@ impl<N:TypeFoldable> TypeFoldable for traits::Vtable<N> {
fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<N> {
match *self {
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d),
traits::VtableUnboxedClosure(d, ref s) => {
traits::VtableUnboxedClosure(d, s.fold_with(folder))
}
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
}