Skip to content

Commit 6ee56c9

Browse files
committed
auto merge of rust-lang#18688 : bkoropoff/rust/unboxed-closure-subst-fixes, r=nikomatsakis
This resolves some issues that remained after adding support for monomorphizing unboxed closures in trans. There were a few places where a set of substitutions for an unboxed closure type were dropped on the floor and later recalculated from scratch based on the def ID, but this failed spectacularly when the closure originated from a different param environment. The substitutions are now plumbed through end-to-end. Closes rust-lang#18661 There was also a conflict in the meaning of the self param space within the body of the unboxed closure. Trans attempted to insert the unboxed closure type as the self type, but this could conflict with the self type from the param environment when an unboxed closure was used within a default method on a trait. Since the body of an unboxed closure cannot refer to its own self type or value, there's no need for it to actually use the self space. The downstream consumers of the substitutions in trans do not seem to need it either since they look up the type of the closure some other way, so I just stopped setting it. Closes rust-lang#18685. r? @pcwalton @nikomatsakis
2 parents 0a3cbf8 + ddb17b2 commit 6ee56c9

File tree

9 files changed

+99
-50
lines changed

9 files changed

+99
-50
lines changed

src/librustc/middle/traits/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub enum Vtable<N> {
176176
/// ID is the ID of the closure expression. This is a `VtableImpl`
177177
/// in spirit, but the impl is generated by the compiler and does
178178
/// not appear in the source.
179-
VtableUnboxedClosure(ast::DefId),
179+
VtableUnboxedClosure(ast::DefId, subst::Substs),
180180

181181
/// Successful resolution to an obligation provided by the caller
182182
/// for some type parameter.
@@ -338,7 +338,7 @@ impl<N> Vtable<N> {
338338
pub fn iter_nested(&self) -> Items<N> {
339339
match *self {
340340
VtableImpl(ref i) => i.iter_nested(),
341-
VtableUnboxedClosure(_) => (&[]).iter(),
341+
VtableUnboxedClosure(..) => (&[]).iter(),
342342
VtableParam(_) => (&[]).iter(),
343343
VtableBuiltin(ref i) => i.iter_nested(),
344344
}
@@ -347,7 +347,7 @@ impl<N> Vtable<N> {
347347
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<M> {
348348
match *self {
349349
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
350-
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
350+
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
351351
VtableParam(ref p) => VtableParam((*p).clone()),
352352
VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
353353
}
@@ -356,7 +356,7 @@ impl<N> Vtable<N> {
356356
pub fn map_move_nested<M>(self, op: |N| -> M) -> Vtable<M> {
357357
match self {
358358
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
359-
VtableUnboxedClosure(d) => VtableUnboxedClosure(d),
359+
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
360360
VtableParam(p) => VtableParam(p),
361361
VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),
362362
}

src/librustc/middle/traits/select.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1582,9 +1582,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15821582
Ok(VtableImpl(vtable_impl))
15831583
}
15841584

1585-
UnboxedClosureCandidate(closure_def_id, ref substs) => {
1586-
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs));
1587-
Ok(VtableUnboxedClosure(closure_def_id))
1585+
UnboxedClosureCandidate(closure_def_id, substs) => {
1586+
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs));
1587+
Ok(VtableUnboxedClosure(closure_def_id, substs))
15881588
}
15891589
}
15901590
}

src/librustc/middle/traits/util.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,10 @@ impl<N:Repr> Repr for super::Vtable<N> {
311311
super::VtableImpl(ref v) =>
312312
v.repr(tcx),
313313

314-
super::VtableUnboxedClosure(ref d) =>
315-
format!("VtableUnboxedClosure({})",
316-
d.repr(tcx)),
314+
super::VtableUnboxedClosure(ref d, ref s) =>
315+
format!("VtableUnboxedClosure({},{})",
316+
d.repr(tcx),
317+
s.repr(tcx)),
317318

318319
super::VtableParam(ref v) =>
319320
format!("VtableParam({})", v.repr(tcx)),

src/librustc/middle/trans/callee.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,9 @@ pub fn trans_fn_ref_with_substs(
490490
};
491491

492492
// If this is an unboxed closure, redirect to it.
493-
match closure::get_or_create_declaration_if_unboxed_closure(bcx, def_id) {
493+
match closure::get_or_create_declaration_if_unboxed_closure(bcx,
494+
def_id,
495+
&substs) {
494496
None => {}
495497
Some(llfn) => return llfn,
496498
}

src/librustc/middle/trans/closure.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use middle::trans::monomorphize::MonoId;
2727
use middle::trans::type_of::*;
2828
use middle::trans::type_::Type;
2929
use middle::ty;
30+
use middle::subst::{Subst, Substs};
3031
use util::ppaux::Repr;
3132
use util::ppaux::ty_to_string;
3233

@@ -420,15 +421,21 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
420421
/// Returns the LLVM function declaration for an unboxed closure, creating it
421422
/// if necessary. If the ID does not correspond to a closure ID, returns None.
422423
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
423-
closure_id: ast::DefId)
424+
closure_id: ast::DefId,
425+
substs: &Substs)
424426
-> Option<ValueRef> {
425427
let ccx = bcx.ccx();
426428
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
427429
// Not an unboxed closure.
428430
return None
429431
}
430432

431-
let function_type = node_id_type(bcx, closure_id.node);
433+
let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node);
434+
let function_type = function_type.subst(bcx.tcx(), substs);
435+
436+
// Normalize type so differences in regions and typedefs don't cause
437+
// duplicate declarations
438+
let function_type = ty::normalize_ty(bcx.tcx(), function_type);
432439
let params = match ty::get(function_type).sty {
433440
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
434441
_ => unreachable!()
@@ -447,7 +454,6 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
447454
None => {}
448455
}
449456

450-
let function_type = node_id_type(bcx, closure_id.node);
451457
let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
452458
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
453459
});
@@ -480,7 +486,8 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
480486
let closure_id = ast_util::local_def(id);
481487
let llfn = get_or_create_declaration_if_unboxed_closure(
482488
bcx,
483-
closure_id).unwrap();
489+
closure_id,
490+
&bcx.fcx.param_substs.substs).unwrap();
484491

485492
let unboxed_closures = bcx.tcx().unboxed_closures.borrow();
486493
let function_type = (*unboxed_closures)[closure_id]

src/librustc/middle/trans/meth.rs

+13-34
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,13 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
355355

356356
Callee { bcx: bcx, data: Fn(llfn) }
357357
}
358-
traits::VtableUnboxedClosure(closure_def_id) => {
359-
let self_ty = node_id_type(bcx, closure_def_id.node);
360-
let callee_substs = get_callee_substitutions_for_unboxed_closure(
361-
bcx,
362-
self_ty);
363-
358+
traits::VtableUnboxedClosure(closure_def_id, substs) => {
359+
// The substitutions should have no type parameters remaining
360+
// after passing through fulfill_obligation
364361
let llfn = trans_fn_ref_with_substs(bcx,
365362
closure_def_id,
366363
MethodCall(method_call),
367-
callee_substs);
364+
substs);
368365

369366
Callee {
370367
bcx: bcx,
@@ -518,24 +515,6 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
518515
};
519516
}
520517

521-
/// Looks up the substitutions for an unboxed closure and adds the
522-
/// self type
523-
fn get_callee_substitutions_for_unboxed_closure(bcx: Block,
524-
self_ty: ty::t)
525-
-> subst::Substs {
526-
match ty::get(self_ty).sty {
527-
ty::ty_unboxed_closure(_, _, ref substs) => {
528-
substs.with_self_ty(ty::mk_rptr(bcx.tcx(),
529-
ty::ReStatic,
530-
ty::mt {
531-
ty: self_ty,
532-
mutbl: ast::MutMutable,
533-
}))
534-
},
535-
_ => unreachable!()
536-
}
537-
}
538-
539518
/// Creates a returns a dynamic vtable for the given type and vtable origin.
540519
/// This is used only for objects.
541520
///
@@ -580,19 +559,19 @@ pub fn get_vtable(bcx: Block,
580559
nested: _ }) => {
581560
emit_vtable_methods(bcx, id, substs).into_iter()
582561
}
583-
traits::VtableUnboxedClosure(closure_def_id) => {
584-
let self_ty = node_id_type(bcx, closure_def_id.node);
585-
586-
let callee_substs =
587-
get_callee_substitutions_for_unboxed_closure(
588-
bcx,
589-
self_ty.clone());
562+
traits::VtableUnboxedClosure(closure_def_id, substs) => {
563+
// Look up closure type
564+
let self_ty = ty::node_id_to_type(bcx.tcx(), closure_def_id.node);
565+
// Apply substitutions from closure param environment.
566+
// The substitutions should have no type parameters
567+
// remaining after passing through fulfill_obligation
568+
let self_ty = self_ty.subst(bcx.tcx(), &substs);
590569

591570
let mut llfn = trans_fn_ref_with_substs(
592571
bcx,
593572
closure_def_id,
594573
ExprId(0),
595-
callee_substs.clone());
574+
substs.clone());
596575

597576
{
598577
let unboxed_closures = bcx.tcx()
@@ -645,7 +624,7 @@ pub fn get_vtable(bcx: Block,
645624
llfn,
646625
&closure_type,
647626
closure_def_id,
648-
callee_substs);
627+
substs);
649628
}
650629
}
651630

src/librustc/middle/ty_fold.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,9 @@ impl<N:TypeFoldable> TypeFoldable for traits::Vtable<N> {
414414
fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<N> {
415415
match *self {
416416
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
417-
traits::VtableUnboxedClosure(d) => traits::VtableUnboxedClosure(d),
417+
traits::VtableUnboxedClosure(d, ref s) => {
418+
traits::VtableUnboxedClosure(d, s.fold_with(folder))
419+
}
418420
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
419421
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
420422
}

src/test/run-pass/issue-18661.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that param substitutions from the correct environment are
12+
// used when translating unboxed closure calls.
13+
14+
#![feature(unboxed_closures)]
15+
16+
pub fn inside<F: Fn()>(c: F) {
17+
c.call(());
18+
}
19+
20+
// Use different number of type parameters and closure type to trigger
21+
// an obvious ICE when param environments are mixed up
22+
pub fn outside<A,B>() {
23+
inside(|&:| {});
24+
}
25+
26+
fn main() {
27+
outside::<(),()>();
28+
}

src/test/run-pass/issue-18685.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the self param space is not used in a conflicting
12+
// manner by unboxed closures within a default method on a trait
13+
14+
#![feature(unboxed_closures, overloaded_calls)]
15+
16+
trait Tr {
17+
fn foo(&self);
18+
19+
fn bar(&self) {
20+
(|:| { self.foo() })()
21+
}
22+
}
23+
24+
impl Tr for () {
25+
fn foo(&self) {}
26+
}
27+
28+
fn main() {
29+
().bar();
30+
}

0 commit comments

Comments
 (0)