mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
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.
This commit is contained in:
parent
31ac8a90f1
commit
3550068b53
@ -769,3 +769,37 @@ pub trait FnOnce<Args,Result> {
|
||||
fn call_once(self, args: Args) -> Result;
|
||||
}
|
||||
|
||||
macro_rules! def_fn_mut(
|
||||
($($args:ident)*) => (
|
||||
#[cfg(not(stage0))]
|
||||
impl<Result$(,$args)*>
|
||||
FnMut<($($args,)*),Result>
|
||||
for extern "Rust" fn($($args: $args,)*) -> Result {
|
||||
#[rust_call_abi_hack]
|
||||
#[allow(uppercase_variables)]
|
||||
fn call_mut(&mut self, args: ($($args,)*)) -> Result {
|
||||
let ($($args,)*) = args;
|
||||
(*self)($($args,)*)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -1541,6 +1541,13 @@ fn try_overloaded_call(fcx: &FnCtxt,
|
||||
callee_type: ty::t,
|
||||
args: &[Gc<ast::Expr>])
|
||||
-> bool {
|
||||
// Bail out if the callee is a bare function or a closure. We check those
|
||||
// manually.
|
||||
match *structure_of(fcx, callee.span, callee_type) {
|
||||
ty::ty_bare_fn(_) | ty::ty_closure(_) => return false,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Try `FnOnce`, then `FnMut`, then `Fn`.
|
||||
for &(maybe_function_trait, method_name) in [
|
||||
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
|
||||
|
@ -4045,7 +4045,8 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parse a method in a trait impl, starting with `attrs` attributes.
|
||||
pub fn parse_method(&mut self,
|
||||
already_parsed_attrs: Option<Vec<Attribute>>) -> Gc<Method> {
|
||||
already_parsed_attrs: Option<Vec<Attribute>>)
|
||||
-> Gc<Method> {
|
||||
let next_attrs = self.parse_outer_attributes();
|
||||
let attrs = match already_parsed_attrs {
|
||||
Some(mut a) => { a.push_all_move(next_attrs); a }
|
||||
@ -4083,6 +4084,11 @@ impl<'a> Parser<'a> {
|
||||
let visa = self.parse_visibility();
|
||||
let abi = if self.eat_keyword(keywords::Extern) {
|
||||
self.parse_opt_abi().unwrap_or(abi::C)
|
||||
} else if attr::contains_name(attrs.as_slice(),
|
||||
"rust_call_abi_hack") {
|
||||
// FIXME(stage0, pcwalton): Remove this awful hack after a
|
||||
// snapshot, and change to `extern "rust-call" fn`.
|
||||
abi::RustCall
|
||||
} else {
|
||||
abi::Rust
|
||||
};
|
||||
|
37
src/test/run-pass/bare-fn-implements-fn-mut.rs
Normal file
37
src/test/run-pass/bare-fn-implements-fn-mut.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
|
||||
#![feature(overloaded_calls)]
|
||||
|
||||
use std::ops::FnMut;
|
||||
|
||||
fn call_f<F:FnMut<(),()>>(mut f: F) {
|
||||
f();
|
||||
}
|
||||
|
||||
fn f() {
|
||||
println!("hello");
|
||||
}
|
||||
|
||||
fn call_g<G:FnMut<(String,String),String>>(mut g: G, x: String, y: String)
|
||||
-> String {
|
||||
g(x, y)
|
||||
}
|
||||
|
||||
fn g(x: String, y: String) -> String {
|
||||
x.append(y.as_slice())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
call_f(f);
|
||||
assert_eq!(call_g(g, "foo".to_string(), "bar".to_string()).as_slice(),
|
||||
"foobar");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user