Fallout from changing fn traits to use inheritance rather than bridge

impls. This is a [breaking-change] (for gated code) in that when you
implement `Fn` (`FnMut`) you must also implement `FnOnce`. This commit
demonstrates how to fix it.
This commit is contained in:
Niko Matsakis 2015-03-11 10:08:33 -04:00
parent 37601131a0
commit 9330bae4bd
28 changed files with 218 additions and 61 deletions

View File

@ -43,8 +43,6 @@ 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;
@ -52,6 +50,14 @@ impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
}
}
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,

View File

@ -18,26 +18,36 @@ struct SFn {
}
impl Fn<(isize,)> for SFn {
type Output = isize;
extern "rust-call" fn call(&self, (z,): (isize,)) -> isize {
self.x * self.y * z
}
}
impl FnMut<(isize,)> for SFn {
extern "rust-call" fn call_mut(&mut self, args: (isize,)) -> isize { self.call(args) }
}
impl FnOnce<(isize,)> for SFn {
type Output = isize;
extern "rust-call" fn call_once(self, args: (isize,)) -> isize { self.call(args) }
}
struct SFnMut {
x: isize,
y: isize,
}
impl FnMut<(isize,)> for SFnMut {
type Output = isize;
extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize {
self.x * self.y * z
}
}
impl FnOnce<(isize,)> for SFnMut {
type Output = isize;
extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) }
}
struct SFnOnce {
x: String,
}

View File

@ -10,5 +10,6 @@
fn main() {
let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
//~^ ERROR: is not implemented for the type
//~^ ERROR E0277
//~| ERROR E0277
}

View File

@ -18,5 +18,5 @@ fn main() {
let _x: extern "C" fn() = f; // OK
is_fn(f);
//~^ ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn()
//~| ERROR the trait `core::ops::Fn<()>` is not implemented for the type `extern "C" fn()
//~| ERROR the trait `core::ops::FnOnce<()>` is not implemented for the type `extern "C" fn()
}

View File

@ -18,28 +18,21 @@
struct Foo;
impl Fn<()> for Foo {
//~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
type Output = ();
extern "rust-call" fn call(&self, args: ()) -> () {}
extern "rust-call" fn call(self, args: ()) -> () {}
}
struct Foo1;
impl Fn() for Foo1 {
impl FnOnce() for Foo1 {
//~^ ERROR associated type bindings are not allowed here
extern "rust-call" fn call(&self, args: ()) -> () {}
extern "rust-call" fn call_once(self, args: ()) -> () {}
}
struct Bar;
impl FnMut<()> for Bar {
//~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
type Output = ();
extern "rust-call" fn call_mut(&self, args: ()) -> () {}
}
struct Baz;
impl FnOnce<()> for Baz {
//~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits
type Output = ();
extern "rust-call" fn call_once(&self, args: ()) -> () {}
}

View File

@ -35,5 +35,5 @@ fn main() {
needs_fn(1);
//~^ ERROR `core::ops::Fn<(isize,)>`
//~| ERROR `core::ops::Fn<(isize,)>`
//~| ERROR `core::ops::FnOnce<(isize,)>`
}

View File

@ -17,9 +17,13 @@ fn apply<T, F>(t: T, f: F) where F: FnOnce(T) {
}
fn main() {
apply(&3, takes_mut); //~ ERROR (values differ in mutability)
apply(&3, takes_imm);
apply(&3, takes_mut);
//~^ ERROR (values differ in mutability)
//~| ERROR (values differ in mutability)
apply(&mut 3, takes_mut);
apply(&mut 3, takes_imm); //~ ERROR (values differ in mutability)
apply(&mut 3, takes_imm);
//~^ ERROR (values differ in mutability)
//~| ERROR (values differ in mutability)
}

View File

@ -16,11 +16,10 @@ struct Debuger<T> {
x: T
}
impl<T: fmt::Debug> ops::Fn<(),> for Debuger<T> {
impl<T: fmt::Debug> ops::FnOnce<(),> for Debuger<T> {
type Output = ();
fn call(&self, _args: ()) {
//~^ ERROR `call` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn
fn call_once(self, _args: ()) {
//~^ ERROR `call_once` has an incompatible type for trait: expected "rust-call" fn, found "Rust" fn
println!("{:?}", self.x);
}
}

View File

@ -13,10 +13,20 @@
struct Foo;
impl<'a, T> Fn<(&'a T,)> for Foo {
type Output = ();
extern "rust-call" fn call(&self, (_,): (T,)) {}
//~^ ERROR: has an incompatible type for trait: expected &-ptr
}
impl<'a, T> FnMut<(&'a T,)> for Foo {
extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
//~^ ERROR: has an incompatible type for trait: expected &-ptr
}
impl<'a, T> FnOnce<(&'a T,)> for Foo {
type Output = ();
extern "rust-call" fn call_once(self, (_,): (T,)) {}
//~^ ERROR: has an incompatible type for trait: expected &-ptr
}
fn main() {}

View File

@ -18,13 +18,18 @@ struct S {
}
impl FnMut<(isize,)> for S {
type Output = isize;
extern "rust-call" fn call_mut(&mut self, (z,): (isize,)) -> isize {
self.x * self.y * z
}
}
impl FnOnce<(isize,)> for S {
type Output = isize;
extern "rust-call" fn call_once(mut self, (z,): (isize,)) -> isize {
self.call_mut((z,))
}
}
fn main() {
let mut s = S {
x: 3,

View File

@ -18,12 +18,16 @@ struct S {
}
impl FnMut<isize> for S {
type Output = isize;
extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
self.x + self.y + z
}
}
impl FnOnce<isize> for S {
type Output = isize;
extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
}
fn main() {
let mut s = S {
x: 1,

View File

@ -19,13 +19,17 @@ use std::ops::{Fn,FnMut,FnOnce};
struct S;
impl FnMut<(isize,)> for S {
type Output = isize;
extern "rust-call" fn call_mut(&mut self, (x,): (isize,)) -> isize {
x * x
}
}
impl FnOnce<(isize,)> for S {
type Output = isize;
extern "rust-call" fn call_once(mut self, args: (isize,)) -> isize { self.call_mut(args) }
}
fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize {
f.call((x,))
}
@ -33,5 +37,4 @@ fn call_it<F:Fn(isize)->isize>(f: &F, x: isize) -> isize {
fn main() {
let x = call_it(&S, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}

View File

@ -28,14 +28,19 @@ impl<F,A,R> YCombinator<F,A,R> {
}
impl<A,R,F : FnMut(&mut FnMut(A) -> R, A) -> R> FnMut<(A,)> for YCombinator<F,A,R> {
type Output = R;
extern "rust-call" fn call_mut(&mut self, (arg,): (A,)) -> R {
(self.func)(self, arg)
//~^ ERROR cannot borrow `*self` as mutable more than once at a time
}
}
impl<A,R,F : FnMut(&mut FnMut(A) -> R, A) -> R> FnOnce<(A,)> for YCombinator<F,A,R> {
type Output = R;
extern "rust-call" fn call_once(mut self, args: (A,)) -> R {
self.call_mut(args)
}
}
fn main() {
let mut counter = 0;
let factorial = |recur: &mut FnMut(u32) -> u32, arg: u32| -> u32 {

View File

@ -27,11 +27,15 @@ fn a() {
}
fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }

View File

@ -27,11 +27,15 @@ fn a() {
}
fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }

View File

@ -28,11 +28,15 @@ fn a() {
}
fn b() {
let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
let y = call_it_mut(&mut square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn c() {
let z = call_it_once(square, 22); //~ ERROR not implemented
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }

View File

@ -14,7 +14,6 @@ use std::ops::Fn;
struct Foo<T>(T);
impl<T: Copy> Fn<()> for Foo<T> {
type Output = T;
extern "rust-call" fn call(&self, _: ()) -> T {
match *self {
Foo(t) => t
@ -22,6 +21,20 @@ impl<T: Copy> Fn<()> for Foo<T> {
}
}
impl<T: Copy> FnMut<()> for Foo<T> {
extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
self.call(())
}
}
impl<T: Copy> FnOnce<()> for Foo<T> {
type Output = T;
extern "rust-call" fn call_once(self, _: ()) -> T {
self.call(())
}
}
fn main() {
let t: u8 = 1;
println!("{}", Foo(t)());

View File

@ -15,10 +15,18 @@ trait Foo { fn dummy(&self) { }}
struct Bar;
impl<'a> std::ops::Fn<(&'a (Foo+'a),)> for Bar {
type Output = ();
extern "rust-call" fn call(&self, _: (&'a Foo,)) {}
}
impl<'a> std::ops::FnMut<(&'a (Foo+'a),)> for Bar {
extern "rust-call" fn call_mut(&mut self, a: (&'a Foo,)) { self.call(a) }
}
impl<'a> std::ops::FnOnce<(&'a (Foo+'a),)> for Bar {
type Output = ();
extern "rust-call" fn call_once(self, a: (&'a Foo,)) { self.call(a) }
}
struct Baz;
impl Foo for Baz {}

View File

@ -34,9 +34,21 @@ impl Alloy {
}
impl<'b> Fn<(&'b mut (Response+'b),)> for SendFile {
extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {}
}
impl<'b> FnMut<(&'b mut (Response+'b),)> for SendFile {
extern "rust-call" fn call_mut(&mut self, (_res,): (&'b mut (Response+'b),)) {
self.call((_res,))
}
}
impl<'b> FnOnce<(&'b mut (Response+'b),)> for SendFile {
type Output = ();
extern "rust-call" fn call(&self, (_res,): (&'b mut (Response+'b),)) {}
extern "rust-call" fn call_once(self, (_res,): (&'b mut (Response+'b),)) {
self.call((_res,))
}
}
impl<Rq: Request, Rs: Response> Ingot<Rq, Rs> for HelloWorld {

View File

@ -18,20 +18,36 @@
struct Foo { foo: u32 }
impl FnMut<()> for Foo {
type Output = u32;
extern "rust-call" fn call_mut(&mut self, _: ()) -> u32 { self.foo }
}
impl FnMut<(u32,)> for 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 FnMut<(u32,u32)> for Foo {
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);

View File

@ -14,9 +14,17 @@
struct Foo;
impl<'a> Fn<(&'a (),)> for Foo {
type Output = ();
extern "rust-call" fn call(&self, (_,): (&(),)) {}
}
impl<'a> FnMut<(&'a (),)> for Foo {
extern "rust-call" fn call_mut(&mut self, (_,): (&(),)) {}
}
impl<'a> FnOnce<(&'a (),)> for Foo {
type Output = ();
extern "rust-call" fn call_once(self, (_,): (&(),)) {}
}
fn main() {}

View File

@ -19,13 +19,20 @@ use std::ops::Add;
struct G<A>(PhantomData<A>);
impl<'a, A: Add<i32, Output=i32>> Fn<(A,)> for G<A> {
type Output = i32;
extern "rust-call" fn call(&self, (arg,): (A,)) -> i32 {
arg.add(1)
}
}
impl<'a, A: Add<i32, Output=i32>> FnMut<(A,)> for G<A> {
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> i32 { self.call(args) }
}
impl<'a, A: Add<i32, Output=i32>> FnOnce<(A,)> for G<A> {
type Output = i32;
extern "rust-call" fn call_once(self, args: (A,)) -> i32 { self.call(args) }
}
fn main() {
// ICE trigger
(G(PhantomData))(1);

View File

@ -18,24 +18,38 @@ struct S1 {
}
impl FnMut<(i32,)> for S1 {
type Output = i32;
extern "rust-call" fn call_mut(&mut self, (z,): (i32,)) -> i32 {
self.x * self.y * z
}
}
impl FnOnce<(i32,)> for S1 {
type Output = i32;
extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 {
self.call_mut(args)
}
}
struct S2 {
x: i32,
y: i32,
}
impl Fn<(i32,)> for S2 {
type Output = i32;
extern "rust-call" fn call(&self, (z,): (i32,)) -> i32 {
self.x * self.y * z
}
}
impl FnMut<(i32,)> for S2 {
extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) }
}
impl FnOnce<(i32,)> for S2 {
type Output = i32;
extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) }
}
struct S3 {
x: i32,
y: i32,

View File

@ -18,12 +18,16 @@ struct S {
}
impl FnMut<()> for S {
type Output = i32;
extern "rust-call" fn call_mut(&mut self, (): ()) -> i32 {
self.x * self.y
}
}
impl FnOnce<()> for S {
type Output = i32;
extern "rust-call" fn call_once(mut self, args: ()) -> i32 { self.call_mut(args) }
}
fn main() {
let mut s = S {
x: 3,

View File

@ -19,12 +19,20 @@ use std::ops::{Fn,FnMut,FnOnce};
struct S;
impl Fn<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call(&self, (x,): (i32,)) -> i32 {
x * x
}
}
impl FnMut<(i32,)> for S {
extern "rust-call" fn call_mut(&mut self, args: (i32,)) -> i32 { self.call(args) }
}
impl FnOnce<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call_once(self, args: (i32,)) -> i32 { self.call(args) }
}
fn call_it<F:Fn(i32)->i32>(f: &F, x: i32) -> i32 {
f(x)
}

View File

@ -19,13 +19,17 @@ use std::ops::{FnMut,FnOnce};
struct S;
impl FnMut<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 {
x * x
}
}
impl FnOnce<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) }
}
fn call_it_mut<F:FnMut(i32)->i32>(f: &mut F, x: i32) -> i32 {
f(x)
}

View File

@ -30,13 +30,20 @@ impl<F,A,R> YCombinator<F,A,R> {
}
impl<A,R,F : Fn(&Fn(A) -> R, A) -> R> Fn<(A,)> for YCombinator<F,A,R> {
type Output = R;
extern "rust-call" fn call(&self, (arg,): (A,)) -> R {
(self.func)(self, arg)
}
}
impl<A,R,F : Fn(&Fn(A) -> R, A) -> R> FnMut<(A,)> for YCombinator<F,A,R> {
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> R { self.call(args) }
}
impl<A,R,F : Fn(&Fn(A) -> R, A) -> R> FnOnce<(A,)> for YCombinator<F,A,R> {
type Output = R;
extern "rust-call" fn call_once(self, args: (A,)) -> R { self.call(args) }
}
fn main() {
let factorial = |recur: &Fn(u32) -> u32, arg: u32| -> u32 {
if arg == 0 {1} else {arg * recur(arg-1)}

View File

@ -15,13 +15,17 @@ use std::ops::FnMut;
struct S;
impl FnMut<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call_mut(&mut self, (x,): (i32,)) -> i32 {
x * x
}
}
impl FnOnce<(i32,)> for S {
type Output = i32;
extern "rust-call" fn call_once(mut self, args: (i32,)) -> i32 { self.call_mut(args) }
}
fn call_it<F:FnMut(i32)->i32>(mut f: F, x: i32) -> i32 {
f(x) + 3
}