Skip to content

librustc: Implement the unboxed closure trait hierarchy. #17543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,15 +848,15 @@ pub trait DerefMut<Sized? Result>: Deref<Result> {

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

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

macro_rules! def_fn_mut(
($($args:ident)*) => (
impl<Result$(,$args)*>
FnOnce<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
#[rust_call_abi_hack]
#[allow(non_snake_case)]
fn call_once(self, args: ($($args,)*)) -> Result {
let ($($args,)*) = args;
self($($args,)*)
}
}

impl<Result$(,$args)*>
Fn<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
#[rust_call_abi_hack]
#[allow(non_snake_case)]
fn call(&self, args: ($($args,)*)) -> Result {
let ($($args,)*) = args;
(*self)($($args,)*)
}
}

impl<Result$(,$args)*>
FnMut<($($args,)*),Result>
for extern "Rust" fn($($args: $args,)*) -> Result {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,6 +1332,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
rbml_w.id(id);
rbml_w.tag(c::tag_table_val, |rbml_w| {
rbml_w.emit_closure_type(ecx, &unboxed_closure.closure_type);
rbml_w.emit_def_id(unboxed_closure.expr_id);
encode_unboxed_closure_kind(rbml_w, unboxed_closure.kind)
})
})
Expand Down Expand Up @@ -1750,6 +1751,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
dcx.tcx,
|s, a| this.convert_def_id(dcx, s, a)))
}).unwrap();
let expr_id = self.read_def_id(dcx);
let variants = [
"FnUnboxedClosureKind",
"FnMutUnboxedClosureKind",
Expand All @@ -1765,6 +1767,7 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
}).unwrap();
ty::UnboxedClosure {
closure_type: closure_type,
expr_id: expr_id,
kind: kind,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
ast_map::NodeExpr(expr) => match expr.node {
ast::ExprProc(_, ref block) |
ast::ExprFnBlock(_, _, ref block) |
ast::ExprUnboxedFn(_, _, _, ref block) => { block.id }
ast::ExprUnboxedFn(_, _, _, _, ref block) => { block.id }
_ => fail!("encountered non-closure id: {}", closure_id)
},
_ => fail!("encountered non-expr id: {}", closure_id)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/check_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
}
ast::ExprFnBlock(_, _, ref b) |
ast::ExprProc(_, ref b) |
ast::ExprUnboxedFn(_, _, _, ref b) => {
ast::ExprUnboxedFn(_, _, _, _, ref b) => {
self.with_context(Closure, |v| v.visit_block(&**b));
}
ast::ExprBreak(_) => self.require_loop("break", e.span),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {

ExprFnBlock(_, _, ref blk) |
ExprProc(_, ref blk) |
ExprUnboxedFn(_, _, _, ref blk) => {
ExprUnboxedFn(_, _, _, _, ref blk) => {
debug!("{} is an ExprFnBlock, ExprProc, or ExprUnboxedFn",
expr_to_string(expr));

Expand Down
19 changes: 15 additions & 4 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,21 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
}
}
ty::ty_unboxed_closure(closure_id, _) => {
let unboxed_closures = self.typer
.unboxed_closures()
.borrow();
let kind = unboxed_closures.get(&closure_id).kind;
assert!(closure_id.krate == ast::LOCAL_CRATE);
let kind = match self.typer
.tcx()
.map
.expect_expr(closure_id.node)
.node {
ast::ExprUnboxedFn(_, kind, _, _, _) => {
ty::UnboxedClosureKind::from_ast_kind(kind)
}
_ => {
self.typer.tcx().sess.bug("didn't find unboxed \
fn with appropriate \
type in AST map")
}
};
let onceness = match kind {
ty::FnUnboxedClosureKind |
ty::FnMutUnboxedClosureKind => ast::Many,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5815,7 +5815,7 @@ impl<'a> Resolver<'a> {
Some(&**fn_decl), NoTypeParameters,
&**block);
}
ExprUnboxedFn(capture_clause, _, ref fn_decl, ref block) => {
ExprUnboxedFn(capture_clause, _, _, ref fn_decl, ref block) => {
self.capture_mode_map.borrow_mut().insert(expr.id, capture_clause);
self.resolve_function(ClosureRibKind(expr.id, block.id),
Some(&**fn_decl), NoTypeParameters,
Expand Down
55 changes: 36 additions & 19 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use std::cell::RefCell;
use std::collections::hashmap::HashMap;
use std::rc::Rc;
use syntax::ast;
use syntax::ast_util;
use util::ppaux::Repr;

pub struct SelectionContext<'cx, 'tcx:'cx> {
Expand Down Expand Up @@ -543,6 +544,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
* unboxed closure type.
*/

debug!("assemble_unboxed_candidates()");

let closure_def_id = match ty::get(skol_obligation_self_ty).sty {
ty::ty_unboxed_closure(id, _) => id,
_ => { return Ok(()); }
Expand All @@ -564,22 +567,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
_ => continue,
};

// Check to see whether the argument and return types match.
let closure_kind = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
Some(closure) => closure.kind,
None => {
self.tcx().sess.span_bug(
obligation.cause.span,
format!("No entry for unboxed closure: {}",
closure_def_id.repr(self.tcx())).as_slice());
}
};
// Check to see whether the closure could implement this trait.
assert!(closure_def_id.krate == ast::LOCAL_CRATE);
let auxiliary_closure_id =
match self.tcx().map.expect_expr(closure_def_id.node).node {
ast::ExprUnboxedFn(_, _, ref ids, _, _) => {
ast_util::local_def(
kind.select_auxiliary_unboxed_closure_id(&**ids))
}
_ => {
self.tcx().sess.span_bug(
obligation.cause.span,
"unboxed fn didn't map to an expr")
}
};

debug!("assemble_unboxed_candidates(kind={})", kind);

if closure_kind != kind {
continue;
// Check to see whether the argument and return types match.
if !self.typer
.unboxed_closures()
.borrow()
.contains_key(&auxiliary_closure_id) {
// Not compatible with this trait.
continue
}

candidates.push(MatchedUnboxedClosureCandidate(closure_def_id));
candidates.push(MatchedUnboxedClosureCandidate(
auxiliary_closure_id));
}

Ok(())
Expand Down Expand Up @@ -1067,7 +1082,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

MatchedUnboxedClosureCandidate(closure_def_id) => {
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id));
try!(self.confirm_unboxed_closure_candidate(
obligation,
closure_def_id));
Ok(Some(VtableUnboxedClosure(closure_def_id)))
}
}
Expand Down Expand Up @@ -1148,11 +1165,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(vtable_impl)
}

fn confirm_unboxed_closure_candidate(&mut self,
obligation: &Obligation,
closure_def_id: ast::DefId)
-> Result<(),SelectionError>
{
fn confirm_unboxed_closure_candidate(
&mut self,
obligation: &Obligation,
closure_def_id: ast::DefId)
-> Result<(),SelectionError> {
debug!("confirm_unboxed_closure_candidate({},{})",
obligation.repr(self.tcx()),
closure_def_id.repr(self.tcx()));
Expand Down
Loading