From 680d579ff0e0c8e65e329d29b867600aa2aec478 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 28 Oct 2014 07:24:25 -0400 Subject: [PATCH] Add blanket impls to allow the various `Fn` traits to be interconverted. Fixes #18387. --- src/libcore/ops.rs | 70 +++++++++++++------ src/librustc/middle/traits/select.rs | 6 +- src/librustc/middle/typeck/check/mod.rs | 5 ++ .../unboxed-closures-fnmut-as-fn.rs | 34 +++++++++ src/test/run-pass/issue-16668.rs | 4 +- .../run-pass/unboxed-closures-extern-fn.rs | 40 +++++++++++ ...unboxed-closures-fn-as-fnmut-and-fnonce.rs | 46 ++++++++++++ .../unboxed-closures-fnmut-as-fnonce.rs | 40 +++++++++++ ...gar.rs => unboxed-closures-manual-impl.rs} | 0 .../run-pass/unboxed-closures-zero-args.rs | 2 +- 10 files changed, 221 insertions(+), 26 deletions(-) create mode 100644 src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs create mode 100644 src/test/run-pass/unboxed-closures-extern-fn.rs create mode 100644 src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs create mode 100644 src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs rename src/test/run-pass/{fn-trait-sugar.rs => unboxed-closures-manual-impl.rs} (100%) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 8d072fffb60a..ac735492be4a 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -866,13 +866,45 @@ pub trait FnOnce { extern "rust-call" fn call_once(self, args: Args) -> Result; } -macro_rules! def_fn_mut( +impl FnMut for F + where F : Fn +{ + extern "rust-call" fn call_mut(&mut self, args: A) -> R { + self.call(args) + } +} + +impl FnOnce for F + where F : FnMut +{ + extern "rust-call" fn call_once(mut self, args: A) -> R { + self.call_mut(args) + } +} + + +impl Fn<(),Result> for extern "Rust" fn() -> Result { + #[allow(non_snake_case)] + extern "rust-call" fn call(&self, _args: ()) -> Result { + (*self)() + } +} + +impl Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result { + #[allow(non_snake_case)] + extern "rust-call" fn call(&self, args: (A0,)) -> Result { + let (a0,) = args; + (*self)(a0) + } +} + +macro_rules! def_fn( ($($args:ident)*) => ( impl - FnMut<($($args,)*),Result> + Fn<($($args,)*),Result> for extern "Rust" fn($($args: $args,)*) -> Result { #[allow(non_snake_case)] - extern "rust-call" fn call_mut(&mut self, args: ($($args,)*)) -> Result { + extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result { let ($($args,)*) = args; (*self)($($args,)*) } @@ -880,20 +912,18 @@ macro_rules! def_fn_mut( ) ) -def_fn_mut!() -def_fn_mut!(A0) -def_fn_mut!(A0 A1) -def_fn_mut!(A0 A1 A2) -def_fn_mut!(A0 A1 A2 A3) -def_fn_mut!(A0 A1 A2 A3 A4) -def_fn_mut!(A0 A1 A2 A3 A4 A5) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) -def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) +def_fn!(A0 A1) +def_fn!(A0 A1 A2) +def_fn!(A0 A1 A2 A3) +def_fn!(A0 A1 A2 A3 A4) +def_fn!(A0 A1 A2 A3 A4 A5) +def_fn!(A0 A1 A2 A3 A4 A5 A6) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) +def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9a2d5b4d4dc0..01e0ec78df75 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -804,12 +804,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &candidates[i], &candidates[j])); if is_dup { - debug!("Dropping candidate #{}/#{}: {}", + debug!("Dropping candidate #{}/{}: {}", i, candidates.len(), candidates[i].repr(self.tcx())); candidates.swap_remove(i); } else { - debug!("Retaining candidate #{}/#{}", - i, candidates.len()); + debug!("Retaining candidate #{}/{}: {}", + i, candidates.len(), candidates[i].repr(self.tcx())); i += 1; } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 0e3a77ba9639..88b191b9a823 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3493,6 +3493,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind, }; + debug!("unboxed_closure for {} --> sig={} kind={}", + local_def(expr.id).repr(fcx.tcx()), + fn_ty.sig.repr(fcx.tcx()), + kind); + let unboxed_closure = ty::UnboxedClosure { closure_type: fn_ty, kind: kind, diff --git a/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs new file mode 100644 index 000000000000..20d7262432f0 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs @@ -0,0 +1,34 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that the Fn trait hierarchy rules do not permit +// Fn to be used where FnMut is implemented. + +#![feature(unboxed_closure_sugar)] +#![feature(overloaded_calls)] + +use std::ops::{Fn,FnMut,FnOnce}; + +struct S; + +impl FnMut<(int,),int> for S { + extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { + x * x + } +} + +fn call_itint>(f: &F, x: int) -> int { + f.call((x,)) +} + +fn main() { + let x = call_it(&S, 22); //~ ERROR not implemented +} + diff --git a/src/test/run-pass/issue-16668.rs b/src/test/run-pass/issue-16668.rs index 92f8030a0dc5..f36594cb4014 100644 --- a/src/test/run-pass/issue-16668.rs +++ b/src/test/run-pass/issue-16668.rs @@ -20,8 +20,8 @@ impl<'a, I, O: 'a> Parser<'a, I, O> { fn compose(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> { Parser { parse: box move |&mut: x: I| { - match self.parse.call_mut((x,)) { - Ok(r) => rhs.parse.call_mut((r,)), + match (*self.parse).call_mut((x,)) { + Ok(r) => (*rhs.parse).call_mut((r,)), Err(e) => Err(e) } } diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs new file mode 100644 index 000000000000..82d51ba1f164 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that extern fn points implement the full range of Fn traits. + +#![feature(unboxed_closure_sugar)] +#![feature(overloaded_calls)] + +use std::ops::{Fn,FnMut,FnOnce}; + +fn square(x: int) -> int { x * x } + +fn call_itint>(f: &F, x: int) -> int { + f.call((x,)) +} + +fn call_it_mutint>(f: &mut F, x: int) -> int { + f.call_mut((x,)) +} + +fn call_it_onceint>(f: F, x: int) -> int { + f.call_once((x,)) +} + +fn main() { + let x = call_it(&square, 22); + let y = call_it_mut(&mut square, 22); + let z = call_it_once(square, 22); + assert_eq!(x, square(22)); + assert_eq!(y, square(22)); + assert_eq!(z, square(22)); +} + diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs new file mode 100644 index 000000000000..90272636bc59 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that the Fn trait hierarchy rules permit +// any Fn trait to be used where Fn is implemented. + +#![feature(unboxed_closure_sugar)] +#![feature(overloaded_calls)] + +use std::ops::{Fn,FnMut,FnOnce}; + +struct S; + +impl Fn<(int,),int> for S { + extern "rust-call" fn call(&self, (x,): (int,)) -> int { + x * x + } +} + +fn call_itint>(f: &F, x: int) -> int { + f.call((x,)) +} + +fn call_it_mutint>(f: &mut F, x: int) -> int { + f.call_mut((x,)) +} + +fn call_it_onceint>(f: F, x: int) -> int { + f.call_once((x,)) +} + +fn main() { + let x = call_it(&S, 22); + let y = call_it_mut(&mut S, 22); + let z = call_it_once(S, 22); + assert_eq!(x, y); + assert_eq!(y, z); +} + diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs new file mode 100644 index 000000000000..bd01910a210a --- /dev/null +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that the Fn trait hierarchy rules permit +// FnMut or FnOnce to be used where FnMut is implemented. + +#![feature(unboxed_closure_sugar)] +#![feature(overloaded_calls)] + +use std::ops::{FnMut,FnOnce}; + +struct S; + +impl FnMut<(int,),int> for S { + extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int { + x * x + } +} + +fn call_it_mutint>(f: &mut F, x: int) -> int { + f.call_mut((x,)) +} + +fn call_it_onceint>(f: F, x: int) -> int { + f.call_once((x,)) +} + +fn main() { + let y = call_it_mut(&mut S, 22); + let z = call_it_once(S, 22); + assert_eq!(y, z); +} + diff --git a/src/test/run-pass/fn-trait-sugar.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs similarity index 100% rename from src/test/run-pass/fn-trait-sugar.rs rename to src/test/run-pass/unboxed-closures-manual-impl.rs diff --git a/src/test/run-pass/unboxed-closures-zero-args.rs b/src/test/run-pass/unboxed-closures-zero-args.rs index 6d6d81fd0ef1..f2eddd84af83 100644 --- a/src/test/run-pass/unboxed-closures-zero-args.rs +++ b/src/test/run-pass/unboxed-closures-zero-args.rs @@ -12,6 +12,6 @@ fn main() { let mut zero = |&mut:| {}; - zero.call_mut(()); + let () = zero.call_mut(()); }