Skip to content

Commit 5de1e01

Browse files
committed
librustc: Implement the unboxed closure trait hierarchy.
This makes `FnMut` require `FnOnce` and `Fn` require `FnMut`. Therefore, this change breaks code that implements the `FnMut` and/or `Fn` traits directly, without also implementing their dependencies. A simple forwarding implementation that defines `FnOnce` in terms of `FnMut` and/or `Fn` in terms of `FnMut` will suffice. This does not affect code that simply uses the `|&:|`/`|&mut:|`/`|:|` unboxed closure construction notation. Part of RFC rust-lang#44; needed to implement RFC rust-lang#63. Part of issue rust-lang#12831. [breaking-change]
1 parent 2550243 commit 5de1e01

39 files changed

+549
-161
lines changed

src/libcore/ops.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,15 +848,15 @@ pub trait DerefMut<Sized? Result>: Deref<Result> {
848848

849849
/// A version of the call operator that takes an immutable receiver.
850850
#[lang="fn"]
851-
pub trait Fn<Args,Result> {
851+
pub trait Fn<Args,Result> : FnMut<Args,Result> {
852852
/// This is called when the call operator is used.
853853
#[rust_call_abi_hack]
854854
fn call(&self, args: Args) -> Result;
855855
}
856856

857857
/// A version of the call operator that takes a mutable receiver.
858858
#[lang="fn_mut"]
859-
pub trait FnMut<Args,Result> {
859+
pub trait FnMut<Args,Result> : FnOnce<Args,Result> {
860860
/// This is called when the call operator is used.
861861
#[rust_call_abi_hack]
862862
fn call_mut(&mut self, args: Args) -> Result;
@@ -872,6 +872,28 @@ pub trait FnOnce<Args,Result> {
872872

873873
macro_rules! def_fn_mut(
874874
($($args:ident)*) => (
875+
impl<Result$(,$args)*>
876+
FnOnce<($($args,)*),Result>
877+
for extern "Rust" fn($($args: $args,)*) -> Result {
878+
#[rust_call_abi_hack]
879+
#[allow(non_snake_case)]
880+
fn call_once(self, args: ($($args,)*)) -> Result {
881+
let ($($args,)*) = args;
882+
self($($args,)*)
883+
}
884+
}
885+
886+
impl<Result$(,$args)*>
887+
Fn<($($args,)*),Result>
888+
for extern "Rust" fn($($args: $args,)*) -> Result {
889+
#[rust_call_abi_hack]
890+
#[allow(non_snake_case)]
891+
fn call(&self, args: ($($args,)*)) -> Result {
892+
let ($($args,)*) = args;
893+
(*self)($($args,)*)
894+
}
895+
}
896+
875897
impl<Result$(,$args)*>
876898
FnMut<($($args,)*),Result>
877899
for extern "Rust" fn($($args: $args,)*) -> Result {

src/librustc/middle/astencode.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
13321332
rbml_w.id(id);
13331333
rbml_w.tag(c::tag_table_val, |rbml_w| {
13341334
rbml_w.emit_closure_type(ecx, &unboxed_closure.closure_type);
1335+
rbml_w.emit_def_id(unboxed_closure.expr_id);
13351336
encode_unboxed_closure_kind(rbml_w, unboxed_closure.kind)
13361337
})
13371338
})
@@ -1750,6 +1751,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
17501751
dcx.tcx,
17511752
|s, a| this.convert_def_id(dcx, s, a)))
17521753
}).unwrap();
1754+
let expr_id = self.read_def_id(dcx);
17531755
let variants = [
17541756
"FnUnboxedClosureKind",
17551757
"FnMutUnboxedClosureKind",
@@ -1765,6 +1767,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
17651767
}).unwrap();
17661768
ty::UnboxedClosure {
17671769
closure_type: closure_type,
1770+
expr_id: expr_id,
17681771
kind: kind,
17691772
}
17701773
}

src/librustc/middle/borrowck/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
282282
ast_map::NodeExpr(expr) => match expr.node {
283283
ast::ExprProc(_, ref block) |
284284
ast::ExprFnBlock(_, _, ref block) |
285-
ast::ExprUnboxedFn(_, _, _, ref block) => { block.id }
285+
ast::ExprUnboxedFn(_, _, _, _, ref block) => { block.id }
286286
_ => fail!("encountered non-closure id: {}", closure_id)
287287
},
288288
_ => fail!("encountered non-expr id: {}", closure_id)

src/librustc/middle/check_loop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
4949
}
5050
ast::ExprFnBlock(_, _, ref b) |
5151
ast::ExprProc(_, ref b) |
52-
ast::ExprUnboxedFn(_, _, _, ref b) => {
52+
ast::ExprUnboxedFn(_, _, _, _, ref b) => {
5353
self.with_context(Closure, |v| v.visit_block(&**b));
5454
}
5555
ast::ExprBreak(_) => self.require_loop("break", e.span),

src/librustc/middle/liveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
961961

962962
ExprFnBlock(_, _, ref blk) |
963963
ExprProc(_, ref blk) |
964-
ExprUnboxedFn(_, _, _, ref blk) => {
964+
ExprUnboxedFn(_, _, _, _, ref blk) => {
965965
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
966966
expr_to_string(expr));
967967

src/librustc/middle/mem_categorization.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,10 +580,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
580580
}
581581
}
582582
ty::ty_unboxed_closure(closure_id, _) => {
583-
let unboxed_closures = self.typer
584-
.unboxed_closures()
585-
.borrow();
586-
let kind = unboxed_closures.get(&closure_id).kind;
583+
assert!(closure_id.krate == ast::LOCAL_CRATE);
584+
let kind = match self.typer
585+
.tcx()
586+
.map
587+
.expect_expr(closure_id.node)
588+
.node {
589+
ast::ExprUnboxedFn(_, kind, _, _, _) => {
590+
ty::UnboxedClosureKind::from_ast_kind(kind)
591+
}
592+
_ => {
593+
self.typer.tcx().sess.bug("didn't find unboxed \
594+
fn with appropriate \
595+
type in AST map")
596+
}
597+
};
587598
let onceness = match kind {
588599
ty::FnUnboxedClosureKind |
589600
ty::FnMutUnboxedClosureKind => ast::Many,

src/librustc/middle/resolve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5815,7 +5815,7 @@ impl<'a> Resolver<'a> {
58155815
Some(&**fn_decl), NoTypeParameters,
58165816
&**block);
58175817
}
5818-
ExprUnboxedFn(capture_clause, _, ref fn_decl, ref block) => {
5818+
ExprUnboxedFn(capture_clause, _, _, ref fn_decl, ref block) => {
58195819
self.capture_mode_map.borrow_mut().insert(expr.id, capture_clause);
58205820
self.resolve_function(ClosureRibKind(expr.id, block.id),
58215821
Some(&**fn_decl), NoTypeParameters,

src/librustc/middle/traits/select.rs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use std::cell::RefCell;
3232
use std::collections::hashmap::HashMap;
3333
use std::rc::Rc;
3434
use syntax::ast;
35+
use syntax::ast_util;
3536
use util::ppaux::Repr;
3637

3738
pub struct SelectionContext<'cx, 'tcx:'cx> {
@@ -543,6 +544,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
543544
* unboxed closure type.
544545
*/
545546

547+
debug!("assemble_unboxed_candidates()");
548+
546549
let closure_def_id = match ty::get(skol_obligation_self_ty).sty {
547550
ty::ty_unboxed_closure(id, _) => id,
548551
_ => { return Ok(()); }
@@ -564,22 +567,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
564567
_ => continue,
565568
};
566569

567-
// Check to see whether the argument and return types match.
568-
let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
569-
Some(closure) => closure.kind,
570-
None => {
571-
self.tcx().sess.span_bug(
572-
obligation.cause.span,
573-
format!("No entry for unboxed closure: {}",
574-
closure_def_id.repr(self.tcx())).as_slice());
575-
}
576-
};
570+
// Check to see whether the closure could implement this trait.
571+
assert!(closure_def_id.krate == ast::LOCAL_CRATE);
572+
let auxiliary_closure_id =
573+
match self.tcx().map.expect_expr(closure_def_id.node).node {
574+
ast::ExprUnboxedFn(_, _, ref ids, _, _) => {
575+
ast_util::local_def(
576+
kind.select_auxiliary_unboxed_closure_id(&**ids))
577+
}
578+
_ => {
579+
self.tcx().sess.span_bug(
580+
obligation.cause.span,
581+
"unboxed fn didn't map to an expr")
582+
}
583+
};
584+
585+
debug!("assemble_unboxed_candidates(kind={})", kind);
577586

578-
if closure_kind != kind {
579-
continue;
587+
// Check to see whether the argument and return types match.
588+
if !self.typer
589+
.unboxed_closures()
590+
.borrow()
591+
.contains_key(&auxiliary_closure_id) {
592+
// Not compatible with this trait.
593+
continue
580594
}
581595

582-
candidates.push(MatchedUnboxedClosureCandidate(closure_def_id));
596+
candidates.push(MatchedUnboxedClosureCandidate(
597+
auxiliary_closure_id));
583598
}
584599

585600
Ok(())
@@ -1067,7 +1082,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10671082
}
10681083

10691084
MatchedUnboxedClosureCandidate(closure_def_id) => {
1070-
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id));
1085+
try!(self.confirm_unboxed_closure_candidate(
1086+
obligation,
1087+
closure_def_id));
10711088
Ok(Some(VtableUnboxedClosure(closure_def_id)))
10721089
}
10731090
}
@@ -1148,11 +1165,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11481165
Ok(vtable_impl)
11491166
}
11501167

1151-
fn confirm_unboxed_closure_candidate(&mut self,
1152-
obligation: &Obligation,
1153-
closure_def_id: ast::DefId)
1154-
-> Result<(),SelectionError>
1155-
{
1168+
fn confirm_unboxed_closure_candidate(
1169+
&mut self,
1170+
obligation: &Obligation,
1171+
closure_def_id: ast::DefId)
1172+
-> Result<(),SelectionError> {
11561173
debug!("confirm_unboxed_closure_candidate({},{})",
11571174
obligation.repr(self.tcx()),
11581175
closure_def_id.repr(self.tcx()));

0 commit comments

Comments
 (0)