Skip to content

Commit 3550068

Browse files
pcwaltonalexcrichton
authored andcommitted
librustc: Make bare functions implement the FnMut trait.
This is done entirely in the libraries for functions up to 16 arguments. A macro is used so that more arguments can be easily added if we need. Note that I had to adjust the overloaded call algorithm to not try calling the overloaded call operator if the callee is a built-in function type, to prevent loops. Closes #15448.
1 parent 31ac8a9 commit 3550068

File tree

4 files changed

+85
-1
lines changed

4 files changed

+85
-1
lines changed

src/libcore/ops.rs

+34
Original file line numberDiff line numberDiff line change
@@ -769,3 +769,37 @@ pub trait FnOnce<Args,Result> {
769769
fn call_once(self, args: Args) -> Result;
770770
}
771771

772+
macro_rules! def_fn_mut(
773+
($($args:ident)*) => (
774+
#[cfg(not(stage0))]
775+
impl<Result$(,$args)*>
776+
FnMut<($($args,)*),Result>
777+
for extern "Rust" fn($($args: $args,)*) -> Result {
778+
#[rust_call_abi_hack]
779+
#[allow(uppercase_variables)]
780+
fn call_mut(&mut self, args: ($($args,)*)) -> Result {
781+
let ($($args,)*) = args;
782+
(*self)($($args,)*)
783+
}
784+
}
785+
)
786+
)
787+
788+
def_fn_mut!()
789+
def_fn_mut!(A0)
790+
def_fn_mut!(A0 A1)
791+
def_fn_mut!(A0 A1 A2)
792+
def_fn_mut!(A0 A1 A2 A3)
793+
def_fn_mut!(A0 A1 A2 A3 A4)
794+
def_fn_mut!(A0 A1 A2 A3 A4 A5)
795+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6)
796+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7)
797+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
798+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
799+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
800+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
801+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
802+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
803+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
804+
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
805+

src/librustc/middle/typeck/check/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,13 @@ fn try_overloaded_call(fcx: &FnCtxt,
15411541
callee_type: ty::t,
15421542
args: &[Gc<ast::Expr>])
15431543
-> bool {
1544+
// Bail out if the callee is a bare function or a closure. We check those
1545+
// manually.
1546+
match *structure_of(fcx, callee.span, callee_type) {
1547+
ty::ty_bare_fn(_) | ty::ty_closure(_) => return false,
1548+
_ => {}
1549+
}
1550+
15441551
// Try `FnOnce`, then `FnMut`, then `Fn`.
15451552
for &(maybe_function_trait, method_name) in [
15461553
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),

src/libsyntax/parse/parser.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -4045,7 +4045,8 @@ impl<'a> Parser<'a> {
40454045

40464046
/// Parse a method in a trait impl, starting with `attrs` attributes.
40474047
pub fn parse_method(&mut self,
4048-
already_parsed_attrs: Option<Vec<Attribute>>) -> Gc<Method> {
4048+
already_parsed_attrs: Option<Vec<Attribute>>)
4049+
-> Gc<Method> {
40494050
let next_attrs = self.parse_outer_attributes();
40504051
let attrs = match already_parsed_attrs {
40514052
Some(mut a) => { a.push_all_move(next_attrs); a }
@@ -4083,6 +4084,11 @@ impl<'a> Parser<'a> {
40834084
let visa = self.parse_visibility();
40844085
let abi = if self.eat_keyword(keywords::Extern) {
40854086
self.parse_opt_abi().unwrap_or(abi::C)
4087+
} else if attr::contains_name(attrs.as_slice(),
4088+
"rust_call_abi_hack") {
4089+
// FIXME(stage0, pcwalton): Remove this awful hack after a
4090+
// snapshot, and change to `extern "rust-call" fn`.
4091+
abi::RustCall
40864092
} else {
40874093
abi::Rust
40884094
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(overloaded_calls)]
12+
13+
use std::ops::FnMut;
14+
15+
fn call_f<F:FnMut<(),()>>(mut f: F) {
16+
f();
17+
}
18+
19+
fn f() {
20+
println!("hello");
21+
}
22+
23+
fn call_g<G:FnMut<(String,String),String>>(mut g: G, x: String, y: String)
24+
-> String {
25+
g(x, y)
26+
}
27+
28+
fn g(x: String, y: String) -> String {
29+
x.append(y.as_slice())
30+
}
31+
32+
fn main() {
33+
call_f(f);
34+
assert_eq!(call_g(g, "foo".to_string(), "bar".to_string()).as_slice(),
35+
"foobar");
36+
}
37+

0 commit comments

Comments
 (0)