Skip to content

Commit 8f6c879

Browse files
committed
rollup merge of rust-lang#23282: nikomatsakis/fn-trait-inheritance
The primary motivation here is to sidestep rust-lang#19032 -- for a time, I thought that we should improve coherence or otherwise extend the language, but I now think that any such changes will require more time to bake. In the meantime, inheritance amongst the fn traits is both logically correct *and* a simple solution to that obstacle. This change introduces inheritance and modifies the compiler so that it can properly generate impls for closures and fns. Things enabled by this PR (but not included in this PR): 1. An impl of `FnMut` for `&mut F` where `F : FnMut` (rust-lang#23015). 2. A better version of `Thunk` I've been calling `FnBox`. I did not include either of these in the PR because: 1. Adding the impls in 1 currently induces a coherence conflict with the pattern trait. This is interesting and merits some discussion. 2. `FnBox` deserves to be a PR of its own. The main downside to this design is (a) the need to write impls by hand; (b) the possibility of implementing `FnMut` with different semantics from `Fn`, etc. Point (a) is minor -- in particular, it does not affect normal closure usage -- and could be addressed in the future in many ways (better defaults; convenient macros; specialization; etc). Point (b) is unfortunate but "just a bug" from my POV, and certainly not unique to these traits (c.f. Copy/Clone, PartialEq/Eq, etc). (Until we lift the feature-gate on implementing the Fn traits, in any case, there is room to correct both of these if we find a nice way.) Note that I believe this change is reversible in the future if we decide on another course of action, due to the feature gate on implementing the `Fn` traits, though I do not (currently) think we should reverse it. Fixes rust-lang#18835. r? @nrc
2 parents ed81038 + 9330bae commit 8f6c879

40 files changed

+711
-261
lines changed

src/libcollectionstest/btree/set.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,21 @@ struct Counter<'a, 'b> {
4343
}
4444

4545
impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
46-
type Output = bool;
47-
4846
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
4947
assert_eq!(x, self.expected[*self.i]);
5048
*self.i += 1;
5149
true
5250
}
5351
}
5452

53+
impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
54+
type Output = bool;
55+
56+
extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
57+
self.call_mut(args)
58+
}
59+
}
60+
5561
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
5662
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
5763
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,

src/libcore/ops.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
11481148
#[lang="fn"]
11491149
#[stable(feature = "rust1", since = "1.0.0")]
11501150
#[rustc_paren_sugar]
1151+
#[cfg(stage0)]
11511152
pub trait Fn<Args> {
11521153
/// The returned type after the call operator is used.
11531154
type Output;
@@ -1156,10 +1157,21 @@ pub trait Fn<Args> {
11561157
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
11571158
}
11581159

1160+
/// A version of the call operator that takes an immutable receiver.
1161+
#[lang="fn"]
1162+
#[stable(feature = "rust1", since = "1.0.0")]
1163+
#[rustc_paren_sugar]
1164+
#[cfg(not(stage0))]
1165+
pub trait Fn<Args> : FnMut<Args> {
1166+
/// This is called when the call operator is used.
1167+
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
1168+
}
1169+
11591170
/// A version of the call operator that takes a mutable receiver.
11601171
#[lang="fn_mut"]
11611172
#[stable(feature = "rust1", since = "1.0.0")]
11621173
#[rustc_paren_sugar]
1174+
#[cfg(stage0)]
11631175
pub trait FnMut<Args> {
11641176
/// The returned type after the call operator is used.
11651177
type Output;
@@ -1168,6 +1180,16 @@ pub trait FnMut<Args> {
11681180
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
11691181
}
11701182

1183+
/// A version of the call operator that takes a mutable receiver.
1184+
#[lang="fn_mut"]
1185+
#[stable(feature = "rust1", since = "1.0.0")]
1186+
#[rustc_paren_sugar]
1187+
#[cfg(not(stage0))]
1188+
pub trait FnMut<Args> : FnOnce<Args> {
1189+
/// This is called when the call operator is used.
1190+
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
1191+
}
1192+
11711193
/// A version of the call operator that takes a by-value receiver.
11721194
#[lang="fn_once"]
11731195
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1180,6 +1202,7 @@ pub trait FnOnce<Args> {
11801202
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
11811203
}
11821204

1205+
#[cfg(stage0)]
11831206
impl<F: ?Sized, A> FnMut<A> for F
11841207
where F : Fn<A>
11851208
{
@@ -1190,6 +1213,7 @@ impl<F: ?Sized, A> FnMut<A> for F
11901213
}
11911214
}
11921215

1216+
#[cfg(stage0)]
11931217
impl<F,A> FnOnce<A> for F
11941218
where F : FnMut<A>
11951219
{

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};
@@ -541,6 +541,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
541541
#[derive(Copy, Clone)]
542542
struct BytesDeref;
543543

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

@@ -550,6 +551,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref {
550551
}
551552
}
552553

554+
#[cfg(not(stage0))]
555+
impl<'a> Fn<(&'a u8,)> for BytesDeref {
556+
#[inline]
557+
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
558+
*ptr
559+
}
560+
}
561+
562+
#[cfg(not(stage0))]
563+
impl<'a> FnMut<(&'a u8,)> for BytesDeref {
564+
#[inline]
565+
extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
566+
Fn::call(&*self, (ptr,))
567+
}
568+
}
569+
570+
#[cfg(not(stage0))]
571+
impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
572+
type Output = u8;
573+
574+
#[inline]
575+
extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
576+
Fn::call(&self, (ptr,))
577+
}
578+
}
579+
553580
/// An iterator over the substrings of a string, separated by `sep`.
554581
struct CharSplits<'a, P: Pattern<'a>> {
555582
/// 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
@@ -1069,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10691069
match self.closure_typer.closure_kind(closure_def_id) {
10701070
Some(closure_kind) => {
10711071
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
1072-
if closure_kind == kind {
1072+
if closure_kind.extends(kind) {
10731073
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
10741074
}
10751075
}
@@ -1088,10 +1088,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10881088
candidates: &mut SelectionCandidateSet<'tcx>)
10891089
-> Result<(),SelectionError<'tcx>>
10901090
{
1091-
// We provide a `Fn` impl for fn pointers. There is no need to provide
1092-
// the other traits (e.g. `FnMut`) since those are provided by blanket
1093-
// impls.
1094-
if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
1091+
// We provide impl of all fn traits for fn pointers.
1092+
if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
10951093
return Ok(());
10961094
}
10971095

src/librustc/middle/ty.rs

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

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

24902507
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)