Skip to content

Commit 3760113

Browse files
committed
Make the Fn traits inherit from one another and remove the bridging
impls. This requires: 1. modifying trait selection a bit so that when we synthesize impls for fn pointers and closures; 2. adding code to trans so that we can synthesize a `FnMut`/`FnOnce` impl for a `Fn` closure and so forth.
1 parent b0aad7d commit 3760113

File tree

12 files changed

+495
-202
lines changed

12 files changed

+495
-202
lines changed

src/libcore/ops.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
11361136
#[lang="fn"]
11371137
#[stable(feature = "rust1", since = "1.0.0")]
11381138
#[rustc_paren_sugar]
1139+
#[cfg(stage0)]
11391140
pub trait Fn<Args> {
11401141
/// The returned type after the call operator is used.
11411142
type Output;
@@ -1144,10 +1145,21 @@ pub trait Fn<Args> {
11441145
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
11451146
}
11461147

1148+
/// A version of the call operator that takes an immutable receiver.
1149+
#[lang="fn"]
1150+
#[stable(feature = "rust1", since = "1.0.0")]
1151+
#[rustc_paren_sugar]
1152+
#[cfg(not(stage0))]
1153+
pub trait Fn<Args> : FnMut<Args> {
1154+
/// This is called when the call operator is used.
1155+
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
1156+
}
1157+
11471158
/// A version of the call operator that takes a mutable receiver.
11481159
#[lang="fn_mut"]
11491160
#[stable(feature = "rust1", since = "1.0.0")]
11501161
#[rustc_paren_sugar]
1162+
#[cfg(stage0)]
11511163
pub trait FnMut<Args> {
11521164
/// The returned type after the call operator is used.
11531165
type Output;
@@ -1156,6 +1168,16 @@ pub trait FnMut<Args> {
11561168
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
11571169
}
11581170

1171+
/// A version of the call operator that takes a mutable receiver.
1172+
#[lang="fn_mut"]
1173+
#[stable(feature = "rust1", since = "1.0.0")]
1174+
#[rustc_paren_sugar]
1175+
#[cfg(not(stage0))]
1176+
pub trait FnMut<Args> : FnOnce<Args> {
1177+
/// This is called when the call operator is used.
1178+
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
1179+
}
1180+
11591181
/// A version of the call operator that takes a by-value receiver.
11601182
#[lang="fn_once"]
11611183
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1168,6 +1190,7 @@ pub trait FnOnce<Args> {
11681190
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
11691191
}
11701192

1193+
#[cfg(stage0)]
11711194
impl<F: ?Sized, A> FnMut<A> for F
11721195
where F : Fn<A>
11731196
{
@@ -1178,6 +1201,7 @@ impl<F: ?Sized, A> FnMut<A> for F
11781201
}
11791202
}
11801203

1204+
#[cfg(stage0)]
11811205
impl<F,A> FnOnce<A> for F
11821206
where F : FnMut<A>
11831207
{

src/libcore/str/mod.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
2929
use marker::Sized;
3030
use mem;
3131
use num::Int;
32-
use ops::{Fn, FnMut};
32+
use ops::{Fn, FnMut, FnOnce};
3333
use option::Option::{self, None, Some};
3434
use raw::{Repr, Slice};
3535
use result::Result::{self, Ok, Err};
@@ -524,6 +524,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
524524
#[derive(Copy, Clone)]
525525
struct BytesDeref;
526526

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

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

537+
#[cfg(not(stage0))]
538+
impl<'a> Fn<(&'a u8,)> for BytesDeref {
539+
#[inline]
540+
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
541+
*ptr
542+
}
543+
}
544+
545+
#[cfg(not(stage0))]
546+
impl<'a> FnMut<(&'a u8,)> for BytesDeref {
547+
#[inline]
548+
extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
549+
Fn::call(&*self, (ptr,))
550+
}
551+
}
552+
553+
#[cfg(not(stage0))]
554+
impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
555+
type Output = u8;
556+
557+
#[inline]
558+
extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
559+
Fn::call(&self, (ptr,))
560+
}
561+
}
562+
536563
/// An iterator over the substrings of a string, separated by `sep`.
537564
struct CharSplits<'a, P: Pattern<'a>> {
538565
/// The slice remaining to be iterated

src/librustc/middle/traits/project.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>(
789789
obligation.repr(tcx),
790790
fn_sig.repr(tcx));
791791

792+
// the `Output` associated type is declared on `FnOnce`
793+
let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
794+
792795
// Note: we unwrap the binder here but re-create it below (1)
793796
let ty::Binder((trait_ref, ret_type)) =
794797
util::closure_trait_ref_and_return_type(tcx,
795-
obligation.predicate.trait_ref.def_id,
798+
fn_once_def_id,
796799
obligation.predicate.trait_ref.self_ty(),
797800
fn_sig,
798801
flag);

src/librustc/middle/traits/select.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1071,7 +1071,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10711071
match self.closure_typer.closure_kind(closure_def_id) {
10721072
Some(closure_kind) => {
10731073
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
1074-
if closure_kind == kind {
1074+
if closure_kind.extends(kind) {
10751075
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
10761076
}
10771077
}
@@ -1090,10 +1090,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10901090
candidates: &mut SelectionCandidateSet<'tcx>)
10911091
-> Result<(),SelectionError<'tcx>>
10921092
{
1093-
// We provide a `Fn` impl for fn pointers. There is no need to provide
1094-
// the other traits (e.g. `FnMut`) since those are provided by blanket
1095-
// impls.
1096-
if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
1093+
// We provide impl of all fn traits for fn pointers.
1094+
if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
10971095
return Ok(());
10981096
}
10991097

src/librustc/middle/ty.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -2461,8 +2461,11 @@ pub struct ItemSubsts<'tcx> {
24612461
pub substs: Substs<'tcx>,
24622462
}
24632463

2464-
#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
2464+
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
24652465
pub enum ClosureKind {
2466+
// Warning: Ordering is significant here! The ordering is chosen
2467+
// because the trait Fn is a subtrait of FnMut and so in turn, and
2468+
// hence we order it so that Fn < FnMut < FnOnce.
24662469
FnClosureKind,
24672470
FnMutClosureKind,
24682471
FnOnceClosureKind,
@@ -2484,6 +2487,20 @@ impl ClosureKind {
24842487
Err(err) => cx.sess.fatal(&err[..]),
24852488
}
24862489
}
2490+
2491+
/// True if this a type that impls this closure kind
2492+
/// must also implement `other`.
2493+
pub fn extends(self, other: ty::ClosureKind) -> bool {
2494+
match (self, other) {
2495+
(FnClosureKind, FnClosureKind) => true,
2496+
(FnClosureKind, FnMutClosureKind) => true,
2497+
(FnClosureKind, FnOnceClosureKind) => true,
2498+
(FnMutClosureKind, FnMutClosureKind) => true,
2499+
(FnMutClosureKind, FnOnceClosureKind) => true,
2500+
(FnOnceClosureKind, FnOnceClosureKind) => true,
2501+
_ => false,
2502+
}
2503+
}
24872504
}
24882505

24892506
pub trait ClosureTyper<'tcx> {

src/librustc_trans/trans/callee.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -264,24 +264,36 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
264264
/// but for the bare function type given.
265265
pub fn trans_fn_pointer_shim<'a, 'tcx>(
266266
ccx: &'a CrateContext<'a, 'tcx>,
267+
closure_kind: ty::ClosureKind,
267268
bare_fn_ty: Ty<'tcx>)
268269
-> ValueRef
269270
{
270271
let _icx = push_ctxt("trans_fn_pointer_shim");
271272
let tcx = ccx.tcx();
272273

274+
// Normalize the type for better caching.
273275
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
274-
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
276+
277+
// If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
278+
let is_by_ref = match closure_kind {
279+
ty::FnClosureKind | ty::FnMutClosureKind => true,
280+
ty::FnOnceClosureKind => false,
281+
};
282+
let bare_fn_ty_maybe_ref = if is_by_ref {
283+
ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty)
284+
} else {
285+
bare_fn_ty
286+
};
287+
288+
// Check if we already trans'd this shim.
289+
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
275290
Some(&llval) => { return llval; }
276291
None => { }
277292
}
278293

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

282-
// This is an impl of `Fn` trait, so receiver is `&self`.
283-
let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty);
284-
285297
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
286298
// which is the fn pointer, and `args`, which is the arguments tuple.
287299
let (opt_def_id, sig) =
@@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
306318
unsafety: ast::Unsafety::Normal,
307319
abi: synabi::RustCall,
308320
sig: ty::Binder(ty::FnSig {
309-
inputs: vec![bare_fn_ty_ref,
321+
inputs: vec![bare_fn_ty_maybe_ref,
310322
tuple_input_ty],
311323
output: sig.output,
312324
variadic: false
@@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
337349
let mut bcx = init_function(&fcx, false, sig.output);
338350

339351
// the first argument (`self`) will be ptr to the the fn pointer
340-
let llfnpointer =
341-
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
352+
let llfnpointer = if is_by_ref {
353+
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32))
354+
} else {
355+
get_param(fcx.llfn, fcx.arg_pos(0) as u32)
356+
};
342357

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

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

364-
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
379+
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
365380

366381
llfn
367382
}

0 commit comments

Comments
 (0)