Skip to content
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

Change the Fn traits to use inheritance, not bridge impls #23282

Merged
merged 2 commits into from
Mar 25, 2015
Merged
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
10 changes: 8 additions & 2 deletions src/libcollectionstest/btree/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,21 @@ struct Counter<'a, 'b> {
}

impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
type Output = bool;

extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
assert_eq!(x, self.expected[*self.i]);
*self.i += 1;
true
}
}

impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
type Output = bool;

extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
self.call_mut(args)
}
}

fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,
Expand Down
24 changes: 24 additions & 0 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
#[lang="fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
#[cfg(stage0)]
pub trait Fn<Args> {
/// The returned type after the call operator is used.
type Output;
Expand All @@ -1144,10 +1145,21 @@ pub trait Fn<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

/// A version of the call operator that takes an immutable receiver.
#[lang="fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
#[cfg(not(stage0))]
pub trait Fn<Args> : FnMut<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

/// A version of the call operator that takes a mutable receiver.
#[lang="fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
#[cfg(stage0)]
pub trait FnMut<Args> {
/// The returned type after the call operator is used.
type Output;
Expand All @@ -1156,6 +1168,16 @@ pub trait FnMut<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

/// A version of the call operator that takes a mutable receiver.
#[lang="fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_paren_sugar]
#[cfg(not(stage0))]
pub trait FnMut<Args> : FnOnce<Args> {
/// This is called when the call operator is used.
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

/// A version of the call operator that takes a by-value receiver.
#[lang="fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -1168,6 +1190,7 @@ pub trait FnOnce<Args> {
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}

#[cfg(stage0)]
impl<F: ?Sized, A> FnMut<A> for F
where F : Fn<A>
{
Expand All @@ -1178,6 +1201,7 @@ impl<F: ?Sized, A> FnMut<A> for F
}
}

#[cfg(stage0)]
impl<F,A> FnOnce<A> for F
where F : FnMut<A>
{
Expand Down
29 changes: 28 additions & 1 deletion src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
use marker::Sized;
use mem;
use num::Int;
use ops::{Fn, FnMut};
use ops::{Fn, FnMut, FnOnce};
use option::Option::{self, None, Some};
use raw::{Repr, Slice};
use result::Result::{self, Ok, Err};
Expand Down Expand Up @@ -524,6 +524,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
#[derive(Copy, Clone)]
struct BytesDeref;

#[cfg(stage0)]
impl<'a> Fn<(&'a u8,)> for BytesDeref {
type Output = u8;

Expand All @@ -533,6 +534,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref {
}
}

#[cfg(not(stage0))]
impl<'a> Fn<(&'a u8,)> for BytesDeref {
#[inline]
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
*ptr
}
}

#[cfg(not(stage0))]
impl<'a> FnMut<(&'a u8,)> for BytesDeref {
#[inline]
extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
Fn::call(&*self, (ptr,))
}
}

#[cfg(not(stage0))]
impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
type Output = u8;

#[inline]
extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
Fn::call(&self, (ptr,))
}
}

/// An iterator over the substrings of a string, separated by `sep`.
struct CharSplits<'a, P: Pattern<'a>> {
/// The slice remaining to be iterated
Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>(
obligation.repr(tcx),
fn_sig.repr(tcx));

// the `Output` associated type is declared on `FnOnce`
let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();

// Note: we unwrap the binder here but re-create it below (1)
let ty::Binder((trait_ref, ret_type)) =
util::closure_trait_ref_and_return_type(tcx,
obligation.predicate.trait_ref.def_id,
fn_once_def_id,
obligation.predicate.trait_ref.self_ty(),
fn_sig,
flag);
Expand Down
8 changes: 3 additions & 5 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
match self.closure_typer.closure_kind(closure_def_id) {
Some(closure_kind) => {
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
if closure_kind == kind {
if closure_kind.extends(kind) {
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
}
}
Expand All @@ -1090,10 +1090,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates: &mut SelectionCandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
// We provide a `Fn` impl for fn pointers. There is no need to provide
// the other traits (e.g. `FnMut`) since those are provided by blanket
// impls.
if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
// We provide impl of all fn traits for fn pointers.
if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
return Ok(());
}

Expand Down
19 changes: 18 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> {
pub substs: Substs<'tcx>,
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
pub enum ClosureKind {
// Warning: Ordering is significant here! The ordering is chosen
// because the trait Fn is a subtrait of FnMut and so in turn, and
// hence we order it so that Fn < FnMut < FnOnce.
FnClosureKind,
FnMutClosureKind,
FnOnceClosureKind,
Expand All @@ -2484,6 +2487,20 @@ impl ClosureKind {
Err(err) => cx.sess.fatal(&err[..]),
}
}

/// True if this a type that impls this closure kind
/// must also implement `other`.
pub fn extends(self, other: ty::ClosureKind) -> bool {
match (self, other) {
(FnClosureKind, FnClosureKind) => true,
(FnClosureKind, FnMutClosureKind) => true,
(FnClosureKind, FnOnceClosureKind) => true,
(FnMutClosureKind, FnMutClosureKind) => true,
(FnMutClosureKind, FnOnceClosureKind) => true,
(FnOnceClosureKind, FnOnceClosureKind) => true,
_ => false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you just use self <= other instead of the big match?

}
}
}

pub trait ClosureTyper<'tcx> {
Expand Down
31 changes: 23 additions & 8 deletions src/librustc_trans/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,24 +264,36 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
/// but for the bare function type given.
pub fn trans_fn_pointer_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
closure_kind: ty::ClosureKind,
bare_fn_ty: Ty<'tcx>)
-> ValueRef
{
let _icx = push_ctxt("trans_fn_pointer_shim");
let tcx = ccx.tcx();

// Normalize the type for better caching.
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {

// If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
let is_by_ref = match closure_kind {
ty::FnClosureKind | ty::FnMutClosureKind => true,
ty::FnOnceClosureKind => false,
};
let bare_fn_ty_maybe_ref = if is_by_ref {
ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty)
} else {
bare_fn_ty
};

// Check if we already trans'd this shim.
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
Some(&llval) => { return llval; }
None => { }
}

debug!("trans_fn_pointer_shim(bare_fn_ty={})",
bare_fn_ty.repr(tcx));

// This is an impl of `Fn` trait, so receiver is `&self`.
let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty);

// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
// which is the fn pointer, and `args`, which is the arguments tuple.
let (opt_def_id, sig) =
Expand All @@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
unsafety: ast::Unsafety::Normal,
abi: synabi::RustCall,
sig: ty::Binder(ty::FnSig {
inputs: vec![bare_fn_ty_ref,
inputs: vec![bare_fn_ty_maybe_ref,
tuple_input_ty],
output: sig.output,
variadic: false
Expand Down Expand Up @@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
let mut bcx = init_function(&fcx, false, sig.output);

// the first argument (`self`) will be ptr to the the fn pointer
let llfnpointer =
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
let llfnpointer = if is_by_ref {
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32))
} else {
get_param(fcx.llfn, fcx.arg_pos(0) as u32)
};

// the remaining arguments will be the untupled values
let llargs: Vec<_> =
Expand All @@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(

finish_fn(&fcx, bcx, sig.output, DebugLoc::None);

ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);

llfn
}
Expand Down
Loading