auto merge of #18388 : nikomatsakis/rust/fn-trait-hierarchy, r=acrichto
Add blanket impls to allow the various `Fn` traits to be interconverted. Fixes #18387.
This commit is contained in:
commit
0e2f9b9485
15 changed files with 313 additions and 94 deletions
|
@ -866,13 +866,45 @@ pub trait FnOnce<Args,Result> {
|
||||||
extern "rust-call" fn call_once(self, args: Args) -> Result;
|
extern "rust-call" fn call_once(self, args: Args) -> Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! def_fn_mut(
|
impl<F,A,R> FnMut<A,R> for F
|
||||||
|
where F : Fn<A,R>
|
||||||
|
{
|
||||||
|
extern "rust-call" fn call_mut(&mut self, args: A) -> R {
|
||||||
|
self.call(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F,A,R> FnOnce<A,R> for F
|
||||||
|
where F : FnMut<A,R>
|
||||||
|
{
|
||||||
|
extern "rust-call" fn call_once(mut self, args: A) -> R {
|
||||||
|
self.call_mut(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
extern "rust-call" fn call(&self, _args: ()) -> Result {
|
||||||
|
(*self)()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Result,A0> 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)*) => (
|
($($args:ident)*) => (
|
||||||
impl<Result$(,$args)*>
|
impl<Result$(,$args)*>
|
||||||
FnMut<($($args,)*),Result>
|
Fn<($($args,)*),Result>
|
||||||
for extern "Rust" fn($($args: $args,)*) -> Result {
|
for extern "Rust" fn($($args: $args,)*) -> Result {
|
||||||
#[allow(non_snake_case)]
|
#[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;
|
let ($($args,)*) = args;
|
||||||
(*self)($($args,)*)
|
(*self)($($args,)*)
|
||||||
}
|
}
|
||||||
|
@ -880,20 +912,18 @@ macro_rules! def_fn_mut(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def_fn_mut!()
|
def_fn!(A0 A1)
|
||||||
def_fn_mut!(A0)
|
def_fn!(A0 A1 A2)
|
||||||
def_fn_mut!(A0 A1)
|
def_fn!(A0 A1 A2 A3)
|
||||||
def_fn_mut!(A0 A1 A2)
|
def_fn!(A0 A1 A2 A3 A4)
|
||||||
def_fn_mut!(A0 A1 A2 A3)
|
def_fn!(A0 A1 A2 A3 A4 A5)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4 A5)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
|
||||||
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
|
def_fn!(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)
|
def_fn!(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)
|
def_fn!(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)
|
def_fn!(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)
|
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
|
||||||
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)
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
||||||
// Determine whether `impl2` can provide an implementation for those
|
// Determine whether `impl2` can provide an implementation for those
|
||||||
// same types.
|
// same types.
|
||||||
let param_env = ty::empty_parameter_environment();
|
let param_env = ty::empty_parameter_environment();
|
||||||
let mut selcx = SelectionContext::new(infcx, ¶m_env, infcx.tcx);
|
let mut selcx = SelectionContext::intercrate(infcx, ¶m_env, infcx.tcx);
|
||||||
let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
|
let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
|
||||||
debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
|
debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
|
||||||
selcx.evaluate_impl(impl2_def_id, &obligation)
|
selcx.evaluate_impl(impl2_def_id, &obligation)
|
||||||
|
|
|
@ -45,6 +45,22 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
|
||||||
/// which is important for checking for trait bounds that
|
/// which is important for checking for trait bounds that
|
||||||
/// recursively require themselves.
|
/// recursively require themselves.
|
||||||
skolemizer: TypeSkolemizer<'cx, 'tcx>,
|
skolemizer: TypeSkolemizer<'cx, 'tcx>,
|
||||||
|
|
||||||
|
/// If true, indicates that the evaluation should be conservative
|
||||||
|
/// and consider the possibility of types outside this crate.
|
||||||
|
/// This comes up primarily when resolving ambiguity. Imagine
|
||||||
|
/// there is some trait reference `$0 : Bar` where `$0` is an
|
||||||
|
/// inference variable. If `intercrate` is true, then we can never
|
||||||
|
/// say for sure that this reference is not implemented, even if
|
||||||
|
/// there are *no impls at all for `Bar`*, because `$0` could be
|
||||||
|
/// bound to some type that in a downstream crate that implements
|
||||||
|
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
|
||||||
|
/// though, we set this to false, because we are only interested
|
||||||
|
/// in types that the user could actually have written --- in
|
||||||
|
/// other words, we consider `$0 : Bar` to be unimplemented if
|
||||||
|
/// there is no type that the user could *actually name* that
|
||||||
|
/// would satisfy it. This avoids crippling inference, basically.
|
||||||
|
intercrate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A stack that walks back up the stack frame.
|
// A stack that walks back up the stack frame.
|
||||||
|
@ -142,6 +158,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
param_env: param_env,
|
param_env: param_env,
|
||||||
typer: typer,
|
typer: typer,
|
||||||
skolemizer: infcx.skolemizer(),
|
skolemizer: infcx.skolemizer(),
|
||||||
|
intercrate: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
|
||||||
|
param_env: &'cx ty::ParameterEnvironment,
|
||||||
|
typer: &'cx Typer<'tcx>)
|
||||||
|
-> SelectionContext<'cx, 'tcx> {
|
||||||
|
SelectionContext {
|
||||||
|
infcx: infcx,
|
||||||
|
param_env: param_env,
|
||||||
|
typer: typer,
|
||||||
|
skolemizer: infcx.skolemizer(),
|
||||||
|
intercrate: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,44 +244,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// The result is "true" if the obligation *may* hold and "false" if
|
// The result is "true" if the obligation *may* hold and "false" if
|
||||||
// we can be sure it does not.
|
// we can be sure it does not.
|
||||||
|
|
||||||
pub fn evaluate_obligation_intercrate(&mut self,
|
pub fn evaluate_obligation(&mut self,
|
||||||
obligation: &Obligation)
|
obligation: &Obligation)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
* Evaluates whether the obligation `obligation` can be
|
* Evaluates whether the obligation `obligation` can be
|
||||||
* satisfied (by any means). This "intercrate" version allows
|
* satisfied (by any means).
|
||||||
* for the possibility that unbound type variables may be
|
|
||||||
* instantiated with types from another crate. This is
|
|
||||||
* important for coherence. In practice this means that
|
|
||||||
* unbound type variables must always be considered ambiguous.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
debug!("evaluate_obligation_intercrate({})",
|
debug!("evaluate_obligation({})",
|
||||||
obligation.repr(self.tcx()));
|
obligation.repr(self.tcx()));
|
||||||
|
|
||||||
let stack = self.push_stack(None, obligation);
|
let stack = self.push_stack(None, obligation);
|
||||||
self.evaluate_stack_intercrate(&stack).may_apply()
|
self.evaluate_stack(&stack).may_apply()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn evaluate_obligation_intracrate(&mut self,
|
|
||||||
obligation: &Obligation)
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
/*!
|
|
||||||
* Evaluates whether the obligation `obligation` can be
|
|
||||||
* satisfied (by any means). This "intracrate" version does
|
|
||||||
* not allow for the possibility that unbound type variables
|
|
||||||
* may be instantiated with types from another crate; hence,
|
|
||||||
* if there are unbound inputs but no crates locally visible,
|
|
||||||
* it considers the result to be unimplemented.
|
|
||||||
*/
|
|
||||||
|
|
||||||
debug!("evaluate_obligation_intracrate({})",
|
|
||||||
obligation.repr(self.tcx()));
|
|
||||||
|
|
||||||
let stack = self.push_stack(None, obligation);
|
|
||||||
self.evaluate_stack_intracrate(&stack).may_apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_builtin_bound_recursively(&mut self,
|
fn evaluate_builtin_bound_recursively(&mut self,
|
||||||
|
@ -288,46 +294,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
|
|
||||||
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
|
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
|
||||||
|
|
||||||
// FIXME(#17901) -- Intercrate vs intracrate resolution is a
|
let result = self.evaluate_stack(&stack);
|
||||||
// tricky question here. For coherence, we want
|
|
||||||
// intercrate. Also, there was a nasty cycle around impls like
|
|
||||||
// `impl<T:Eq> Eq for Vec<T>` (which would wind up checking
|
|
||||||
// whether `$0:Eq`, where $0 was the value substituted for
|
|
||||||
// `T`, which could then be checked against the very same
|
|
||||||
// impl). This problem is avoided by the stricter rules around
|
|
||||||
// unbound type variables by intercrate. I suspect that in the
|
|
||||||
// latter case a more fine-grained rule would suffice (i.e.,
|
|
||||||
// consider it ambiguous if even 1 impl matches, no need to
|
|
||||||
// figure out which one, but call it unimplemented if 0 impls
|
|
||||||
// match).
|
|
||||||
let result = self.evaluate_stack_intercrate(&stack);
|
|
||||||
|
|
||||||
debug!("result: {}", result);
|
debug!("result: {}", result);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_stack_intercrate(&mut self,
|
fn evaluate_stack(&mut self,
|
||||||
stack: &ObligationStack)
|
stack: &ObligationStack)
|
||||||
-> EvaluationResult
|
-> EvaluationResult
|
||||||
{
|
{
|
||||||
// Whenever any of the types are unbound, there can always be
|
// In intercrate mode, whenever any of the types are unbound,
|
||||||
// an impl. Even if there are no impls in this crate, perhaps
|
// there can always be an impl. Even if there are no impls in
|
||||||
// the type would be unified with something from another crate
|
// this crate, perhaps the type would be unified with
|
||||||
// that does provide an impl.
|
// something from another crate that does provide an impl.
|
||||||
|
//
|
||||||
|
// In intracrate mode, we must still be conservative. The reason is
|
||||||
|
// that we want to avoid cycles. Imagine an impl like:
|
||||||
|
//
|
||||||
|
// impl<T:Eq> Eq for Vec<T>
|
||||||
|
//
|
||||||
|
// and a trait reference like `$0 : Eq` where `$0` is an
|
||||||
|
// unbound variable. When we evaluate this trait-reference, we
|
||||||
|
// will unify `$0` with `Vec<$1>` (for some fresh variable
|
||||||
|
// `$1`), on the condition that `$1 : Eq`. We will then wind
|
||||||
|
// up with many candidates (since that are other `Eq` impls
|
||||||
|
// that apply) and try to winnow things down. This results in
|
||||||
|
// a recurssive evaluation that `$1 : Eq` -- as you can
|
||||||
|
// imagine, this is just where we started. To avoid that, we
|
||||||
|
// check for unbound variables and return an ambiguous (hence possible)
|
||||||
|
// match if we've seen this trait before.
|
||||||
|
//
|
||||||
|
// This suffices to allow chains like `FnMut` implemented in
|
||||||
|
// terms of `Fn` etc, but we could probably make this more
|
||||||
|
// precise still.
|
||||||
let input_types = stack.skol_trait_ref.input_types();
|
let input_types = stack.skol_trait_ref.input_types();
|
||||||
if input_types.iter().any(|&t| ty::type_is_skolemized(t)) {
|
let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t));
|
||||||
debug!("evaluate_stack_intercrate({}) --> unbound argument, must be ambiguous",
|
if
|
||||||
|
unbound_input_types &&
|
||||||
|
(self.intercrate ||
|
||||||
|
stack.iter().skip(1).any(
|
||||||
|
|prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id))
|
||||||
|
{
|
||||||
|
debug!("evaluate_stack_intracrate({}) --> unbound argument, recursion --> ambiguous",
|
||||||
stack.skol_trait_ref.repr(self.tcx()));
|
stack.skol_trait_ref.repr(self.tcx()));
|
||||||
return EvaluatedToAmbig;
|
return EvaluatedToAmbig;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.evaluate_stack_intracrate(stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn evaluate_stack_intracrate(&mut self,
|
|
||||||
stack: &ObligationStack)
|
|
||||||
-> EvaluationResult
|
|
||||||
{
|
|
||||||
// If there is any previous entry on the stack that precisely
|
// If there is any previous entry on the stack that precisely
|
||||||
// matches this obligation, then we can assume that the
|
// matches this obligation, then we can assume that the
|
||||||
// obligation is satisfied for now (still all other conditions
|
// obligation is satisfied for now (still all other conditions
|
||||||
|
@ -592,7 +605,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
Err(_) => { return Err(()); }
|
Err(_) => { return Err(()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.evaluate_obligation_intracrate(obligation) {
|
if self.evaluate_obligation(obligation) {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
|
@ -804,12 +817,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
&candidates[i],
|
&candidates[i],
|
||||||
&candidates[j]));
|
&candidates[j]));
|
||||||
if is_dup {
|
if is_dup {
|
||||||
debug!("Dropping candidate #{}/#{}: {}",
|
debug!("Dropping candidate #{}/{}: {}",
|
||||||
i, candidates.len(), candidates[i].repr(self.tcx()));
|
i, candidates.len(), candidates[i].repr(self.tcx()));
|
||||||
candidates.swap_remove(i);
|
candidates.swap_remove(i);
|
||||||
} else {
|
} else {
|
||||||
debug!("Retaining candidate #{}/#{}",
|
debug!("Retaining candidate #{}/{}: {}",
|
||||||
i, candidates.len());
|
i, candidates.len(), candidates[i].repr(self.tcx()));
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -828,7 +841,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// be the case that you could still satisfy the obligation
|
// be the case that you could still satisfy the obligation
|
||||||
// from another crate by instantiating the type variables with
|
// from another crate by instantiating the type variables with
|
||||||
// a type from another crate that does have an impl. This case
|
// a type from another crate that does have an impl. This case
|
||||||
// is checked for in `evaluate_obligation` (and hence users
|
// is checked for in `evaluate_stack` (and hence users
|
||||||
// who might care about this case, like coherence, should use
|
// who might care about this case, like coherence, should use
|
||||||
// that function).
|
// that function).
|
||||||
if candidates.len() == 0 {
|
if candidates.len() == 0 {
|
||||||
|
@ -849,6 +862,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// global cache. We want the cache that is specific to this
|
// global cache. We want the cache that is specific to this
|
||||||
// scope whenever where clauses might affect the result.
|
// scope whenever where clauses might affect the result.
|
||||||
|
|
||||||
|
// Avoid using the master cache during coherence and just rely
|
||||||
|
// on the local cache. This effectively disables caching
|
||||||
|
// during coherence. It is really just a simplification to
|
||||||
|
// avoid us having to fear that coherence results "pollute"
|
||||||
|
// the master cache. Since coherence executes pretty quickly,
|
||||||
|
// it's not worth going to more trouble to increase the
|
||||||
|
// hit-rate I don't think.
|
||||||
|
if self.intercrate {
|
||||||
|
return &self.param_env.selection_cache;
|
||||||
|
}
|
||||||
|
|
||||||
// If the trait refers to any parameters in scope, then use
|
// If the trait refers to any parameters in scope, then use
|
||||||
// the cache of the param-environment.
|
// the cache of the param-environment.
|
||||||
if
|
if
|
||||||
|
|
|
@ -235,7 +235,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(
|
||||||
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
|
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
|
||||||
&fcx.inh.param_env,
|
&fcx.inh.param_env,
|
||||||
fcx);
|
fcx);
|
||||||
if !selcx.evaluate_obligation_intracrate(&obligation) {
|
if !selcx.evaluate_obligation(&obligation) {
|
||||||
debug!("--> Cannot match obligation");
|
debug!("--> Cannot match obligation");
|
||||||
return None; // Cannot be matched, no such method resolution is possible.
|
return None; // Cannot be matched, no such method resolution is possible.
|
||||||
}
|
}
|
||||||
|
|
|
@ -2147,11 +2147,11 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try `FnOnce`, then `FnMut`, then `Fn`.
|
// Try the options that are least restrictive on the caller first.
|
||||||
for &(maybe_function_trait, method_name) in [
|
for &(maybe_function_trait, method_name) in [
|
||||||
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
|
(fcx.tcx().lang_items.fn_trait(), token::intern("call")),
|
||||||
(fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
|
(fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
|
||||||
(fcx.tcx().lang_items.fn_trait(), token::intern("call"))
|
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
|
||||||
].iter() {
|
].iter() {
|
||||||
let function_trait = match maybe_function_trait {
|
let function_trait = match maybe_function_trait {
|
||||||
None => continue,
|
None => continue,
|
||||||
|
@ -3493,6 +3493,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||||
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
|
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 {
|
let unboxed_closure = ty::UnboxedClosure {
|
||||||
closure_type: fn_ty,
|
closure_type: fn_ty,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
|
|
34
src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs
Normal file
34
src/test/compile-fail/unboxed-closures-fnmut-as-fn.rs
Normal file
|
@ -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 <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.
|
||||||
|
|
||||||
|
// 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_it<F:Fn(int)->int>(f: &F, x: int) -> int {
|
||||||
|
f.call((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = call_it(&S, 22); //~ ERROR not implemented
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut_ = |&mut: x| x;
|
let mut_ = |&mut: x| x;
|
||||||
mut_.call_once((0i, )); //~ ERROR type `closure` does not implement
|
mut_.call((0i, )); //~ ERROR type `closure` does not implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ fn call_it<F:FnMut<(int,int),int>>(y: int, mut f: F) -> int {
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
|
let f = |&mut: x: uint, y: int| -> int { (x as int) + y };
|
||||||
let z = call_it(3, f); //~ ERROR type mismatch
|
let z = call_it(3, f); //~ ERROR not implemented
|
||||||
println!("{}", z);
|
println!("{}", z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
#![feature(lang_items, overloaded_calls, unboxed_closures)]
|
#![feature(lang_items, overloaded_calls, unboxed_closures)]
|
||||||
|
|
||||||
fn c<F:FnOnce(int, int) -> int>(f: F) -> int {
|
fn c<F:Fn(int, int) -> int>(f: F) -> int {
|
||||||
f(5, 6)
|
f(5, 6)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let z: int = 7;
|
let z: int = 7;
|
||||||
assert_eq!(c(|&: x: int, y| x + y + z), 10);
|
assert_eq!(c(|&mut: x: int, y| x + y + z), 10);
|
||||||
//~^ ERROR not implemented
|
//~^ ERROR not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ impl<'a, I, O: 'a> Parser<'a, I, O> {
|
||||||
fn compose<K: 'a>(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> {
|
fn compose<K: 'a>(mut self, mut rhs: Parser<'a, O, K>) -> Parser<'a, I, K> {
|
||||||
Parser {
|
Parser {
|
||||||
parse: box move |&mut: x: I| {
|
parse: box move |&mut: x: I| {
|
||||||
match self.parse.call_mut((x,)) {
|
match (*self.parse).call_mut((x,)) {
|
||||||
Ok(r) => rhs.parse.call_mut((r,)),
|
Ok(r) => (*rhs.parse).call_mut((r,)),
|
||||||
Err(e) => Err(e)
|
Err(e) => Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
40
src/test/run-pass/unboxed-closures-extern-fn.rs
Normal file
40
src/test/run-pass/unboxed-closures-extern-fn.rs
Normal file
|
@ -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 <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.
|
||||||
|
|
||||||
|
// 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_it<F:Fn(int)->int>(f: &F, x: int) -> int {
|
||||||
|
f.call((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
|
||||||
|
f.call_mut((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it_once<F:FnOnce(int)->int>(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));
|
||||||
|
}
|
||||||
|
|
46
src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs
Normal file
46
src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs
Normal file
|
@ -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 <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.
|
||||||
|
|
||||||
|
// 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_it<F:Fn(int)->int>(f: &F, x: int) -> int {
|
||||||
|
f.call((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
|
||||||
|
f.call_mut((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it_once<F:FnOnce(int)->int>(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);
|
||||||
|
}
|
||||||
|
|
40
src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs
Normal file
40
src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs
Normal file
|
@ -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 <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.
|
||||||
|
|
||||||
|
// 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_mut<F:FnMut(int)->int>(f: &mut F, x: int) -> int {
|
||||||
|
f.call_mut((x,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_it_once<F:FnOnce(int)->int>(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);
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut zero = |&mut:| {};
|
let mut zero = |&mut:| {};
|
||||||
zero.call_mut(());
|
let () = zero.call_mut(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue