rust/src/test/run-pass/issue-16739.rs
Alex Crichton 8f6c879d2a rollup merge of #23282: nikomatsakis/fn-trait-inheritance
The primary motivation here is to sidestep #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` (https://github.com/rust-lang/rust/issues/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 #18835.

r? @nrc
2015-03-24 14:50:44 -07:00

63 lines
1.9 KiB
Rust

// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// pretty-expanded FIXME #23616
#![allow(unknown_features)]
#![feature(box_syntax)]
#![feature(unboxed_closures, core)]
// Test that unboxing shim for calling rust-call ABI methods through a
// trait box works and does not cause an ICE.
struct Foo { foo: u32 }
impl FnMut<()> for Foo {
extern "rust-call" fn call_mut(&mut self, _: ()) -> u32 { self.foo }
}
impl FnOnce<()> for Foo {
type Output = u32;
extern "rust-call" fn call_once(mut self, _: ()) -> u32 { self.call_mut(()) }
}
/////////////////////////////////////////////////////////////////////////
impl FnMut<(u32,)> for Foo {
extern "rust-call" fn call_mut(&mut self, (x,): (u32,)) -> u32 { self.foo + x }
}
impl FnOnce<(u32,)> for Foo {
type Output = u32;
extern "rust-call" fn call_once(mut self, args: (u32,)) -> u32 { self.call_mut(args) }
}
/////////////////////////////////////////////////////////////////////////
impl FnMut<(u32,u32)> for Foo {
extern "rust-call" fn call_mut(&mut self, (x, y): (u32, u32)) -> u32 { self.foo + x + y }
}
impl FnOnce<(u32,u32)> for Foo {
type Output = u32;
extern "rust-call" fn call_once(mut self, args: (u32,u32)) -> u32 { self.call_mut(args) }
}
fn main() {
let mut f = box Foo { foo: 42 } as Box<FnMut() -> u32>;
assert_eq!(f.call_mut(()), 42);
let mut f = box Foo { foo: 40 } as Box<FnMut(u32) -> u32>;
assert_eq!(f.call_mut((2,)), 42);
let mut f = box Foo { foo: 40 } as Box<FnMut(u32, u32) -> u32>;
assert_eq!(f.call_mut((1, 1)), 42);
}