Skip to content

Commit 0e2f9b9

Browse files
committed
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.
2 parents 63c4f22 + cf753a2 commit 0e2f9b9

15 files changed

+313
-94
lines changed

src/libcore/ops.rs

+50-20
Original file line numberDiff line numberDiff line change
@@ -866,34 +866,64 @@ pub trait FnOnce<Args,Result> {
866866
extern "rust-call" fn call_once(self, args: Args) -> Result;
867867
}
868868

869-
macro_rules! def_fn_mut(
869+
impl<F,A,R> FnMut<A,R> for F
870+
where F : Fn<A,R>
871+
{
872+
extern "rust-call" fn call_mut(&mut self, args: A) -> R {
873+
self.call(args)
874+
}
875+
}
876+
877+
impl<F,A,R> FnOnce<A,R> for F
878+
where F : FnMut<A,R>
879+
{
880+
extern "rust-call" fn call_once(mut self, args: A) -> R {
881+
self.call_mut(args)
882+
}
883+
}
884+
885+
886+
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
887+
#[allow(non_snake_case)]
888+
extern "rust-call" fn call(&self, _args: ()) -> Result {
889+
(*self)()
890+
}
891+
}
892+
893+
impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
894+
#[allow(non_snake_case)]
895+
extern "rust-call" fn call(&self, args: (A0,)) -> Result {
896+
let (a0,) = args;
897+
(*self)(a0)
898+
}
899+
}
900+
901+
macro_rules! def_fn(
870902
($($args:ident)*) => (
871903
impl<Result$(,$args)*>
872-
FnMut<($($args,)*),Result>
904+
Fn<($($args,)*),Result>
873905
for extern "Rust" fn($($args: $args,)*) -> Result {
874906
#[allow(non_snake_case)]
875-
extern "rust-call" fn call_mut(&mut self, args: ($($args,)*)) -> Result {
907+
extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
876908
let ($($args,)*) = args;
877909
(*self)($($args,)*)
878910
}
879911
}
880912
)
881913
)
882914

883-
def_fn_mut!()
884-
def_fn_mut!(A0)
885-
def_fn_mut!(A0 A1)
886-
def_fn_mut!(A0 A1 A2)
887-
def_fn_mut!(A0 A1 A2 A3)
888-
def_fn_mut!(A0 A1 A2 A3 A4)
889-
def_fn_mut!(A0 A1 A2 A3 A4 A5)
890-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6)
891-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7)
892-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
893-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
894-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
895-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
896-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
897-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
898-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
899-
def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
915+
def_fn!(A0 A1)
916+
def_fn!(A0 A1 A2)
917+
def_fn!(A0 A1 A2 A3)
918+
def_fn!(A0 A1 A2 A3 A4)
919+
def_fn!(A0 A1 A2 A3 A4 A5)
920+
def_fn!(A0 A1 A2 A3 A4 A5 A6)
921+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
922+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
923+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
924+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
925+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
926+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
927+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
928+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
929+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)

src/librustc/middle/traits/coherence.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
4343
// Determine whether `impl2` can provide an implementation for those
4444
// same types.
4545
let param_env = ty::empty_parameter_environment();
46-
let mut selcx = SelectionContext::new(infcx, &param_env, infcx.tcx);
46+
let mut selcx = SelectionContext::intercrate(infcx, &param_env, infcx.tcx);
4747
let obligation = Obligation::misc(DUMMY_SP, impl1_trait_ref);
4848
debug!("impl_can_satisfy obligation={}", obligation.repr(infcx.tcx));
4949
selcx.evaluate_impl(impl2_def_id, &obligation)

src/librustc/middle/traits/select.rs

+86-62
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,22 @@ pub struct SelectionContext<'cx, 'tcx:'cx> {
4545
/// which is important for checking for trait bounds that
4646
/// recursively require themselves.
4747
skolemizer: TypeSkolemizer<'cx, 'tcx>,
48+
49+
/// If true, indicates that the evaluation should be conservative
50+
/// and consider the possibility of types outside this crate.
51+
/// This comes up primarily when resolving ambiguity. Imagine
52+
/// there is some trait reference `$0 : Bar` where `$0` is an
53+
/// inference variable. If `intercrate` is true, then we can never
54+
/// say for sure that this reference is not implemented, even if
55+
/// there are *no impls at all for `Bar`*, because `$0` could be
56+
/// bound to some type that in a downstream crate that implements
57+
/// `Bar`. This is the suitable mode for coherence. Elsewhere,
58+
/// though, we set this to false, because we are only interested
59+
/// in types that the user could actually have written --- in
60+
/// other words, we consider `$0 : Bar` to be unimplemented if
61+
/// there is no type that the user could *actually name* that
62+
/// would satisfy it. This avoids crippling inference, basically.
63+
intercrate: bool,
4864
}
4965

5066
// A stack that walks back up the stack frame.
@@ -142,6 +158,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
142158
param_env: param_env,
143159
typer: typer,
144160
skolemizer: infcx.skolemizer(),
161+
intercrate: false,
162+
}
163+
}
164+
165+
pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>,
166+
param_env: &'cx ty::ParameterEnvironment,
167+
typer: &'cx Typer<'tcx>)
168+
-> SelectionContext<'cx, 'tcx> {
169+
SelectionContext {
170+
infcx: infcx,
171+
param_env: param_env,
172+
typer: typer,
173+
skolemizer: infcx.skolemizer(),
174+
intercrate: true,
145175
}
146176
}
147177

@@ -214,44 +244,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
214244
// The result is "true" if the obligation *may* hold and "false" if
215245
// we can be sure it does not.
216246

217-
pub fn evaluate_obligation_intercrate(&mut self,
218-
obligation: &Obligation)
219-
-> bool
247+
pub fn evaluate_obligation(&mut self,
248+
obligation: &Obligation)
249+
-> bool
220250
{
221251
/*!
222252
* Evaluates whether the obligation `obligation` can be
223-
* satisfied (by any means). This "intercrate" version allows
224-
* for the possibility that unbound type variables may be
225-
* instantiated with types from another crate. This is
226-
* important for coherence. In practice this means that
227-
* unbound type variables must always be considered ambiguous.
253+
* satisfied (by any means).
228254
*/
229255

230-
debug!("evaluate_obligation_intercrate({})",
256+
debug!("evaluate_obligation({})",
231257
obligation.repr(self.tcx()));
232258

233259
let stack = self.push_stack(None, obligation);
234-
self.evaluate_stack_intercrate(&stack).may_apply()
235-
}
236-
237-
pub fn evaluate_obligation_intracrate(&mut self,
238-
obligation: &Obligation)
239-
-> bool
240-
{
241-
/*!
242-
* Evaluates whether the obligation `obligation` can be
243-
* satisfied (by any means). This "intracrate" version does
244-
* not allow for the possibility that unbound type variables
245-
* may be instantiated with types from another crate; hence,
246-
* if there are unbound inputs but no crates locally visible,
247-
* it considers the result to be unimplemented.
248-
*/
249-
250-
debug!("evaluate_obligation_intracrate({})",
251-
obligation.repr(self.tcx()));
252-
253-
let stack = self.push_stack(None, obligation);
254-
self.evaluate_stack_intracrate(&stack).may_apply()
260+
self.evaluate_stack(&stack).may_apply()
255261
}
256262

257263
fn evaluate_builtin_bound_recursively(&mut self,
@@ -288,46 +294,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
288294

289295
let stack = self.push_stack(previous_stack.map(|x| x), obligation);
290296

291-
// FIXME(#17901) -- Intercrate vs intracrate resolution is a
292-
// tricky question here. For coherence, we want
293-
// intercrate. Also, there was a nasty cycle around impls like
294-
// `impl<T:Eq> Eq for Vec<T>` (which would wind up checking
295-
// whether `$0:Eq`, where $0 was the value substituted for
296-
// `T`, which could then be checked against the very same
297-
// impl). This problem is avoided by the stricter rules around
298-
// unbound type variables by intercrate. I suspect that in the
299-
// latter case a more fine-grained rule would suffice (i.e.,
300-
// consider it ambiguous if even 1 impl matches, no need to
301-
// figure out which one, but call it unimplemented if 0 impls
302-
// match).
303-
let result = self.evaluate_stack_intercrate(&stack);
297+
let result = self.evaluate_stack(&stack);
304298

305299
debug!("result: {}", result);
306300
result
307301
}
308302

309-
fn evaluate_stack_intercrate(&mut self,
303+
fn evaluate_stack(&mut self,
310304
stack: &ObligationStack)
311305
-> EvaluationResult
312306
{
313-
// Whenever any of the types are unbound, there can always be
314-
// an impl. Even if there are no impls in this crate, perhaps
315-
// the type would be unified with something from another crate
316-
// that does provide an impl.
307+
// In intercrate mode, whenever any of the types are unbound,
308+
// there can always be an impl. Even if there are no impls in
309+
// this crate, perhaps the type would be unified with
310+
// something from another crate that does provide an impl.
311+
//
312+
// In intracrate mode, we must still be conservative. The reason is
313+
// that we want to avoid cycles. Imagine an impl like:
314+
//
315+
// impl<T:Eq> Eq for Vec<T>
316+
//
317+
// and a trait reference like `$0 : Eq` where `$0` is an
318+
// unbound variable. When we evaluate this trait-reference, we
319+
// will unify `$0` with `Vec<$1>` (for some fresh variable
320+
// `$1`), on the condition that `$1 : Eq`. We will then wind
321+
// up with many candidates (since that are other `Eq` impls
322+
// that apply) and try to winnow things down. This results in
323+
// a recurssive evaluation that `$1 : Eq` -- as you can
324+
// imagine, this is just where we started. To avoid that, we
325+
// check for unbound variables and return an ambiguous (hence possible)
326+
// match if we've seen this trait before.
327+
//
328+
// This suffices to allow chains like `FnMut` implemented in
329+
// terms of `Fn` etc, but we could probably make this more
330+
// precise still.
317331
let input_types = stack.skol_trait_ref.input_types();
318-
if input_types.iter().any(|&t| ty::type_is_skolemized(t)) {
319-
debug!("evaluate_stack_intercrate({}) --> unbound argument, must be ambiguous",
332+
let unbound_input_types = input_types.iter().any(|&t| ty::type_is_skolemized(t));
333+
if
334+
unbound_input_types &&
335+
(self.intercrate ||
336+
stack.iter().skip(1).any(
337+
|prev| stack.skol_trait_ref.def_id == prev.skol_trait_ref.def_id))
338+
{
339+
debug!("evaluate_stack_intracrate({}) --> unbound argument, recursion --> ambiguous",
320340
stack.skol_trait_ref.repr(self.tcx()));
321341
return EvaluatedToAmbig;
322342
}
323343

324-
self.evaluate_stack_intracrate(stack)
325-
}
326-
327-
fn evaluate_stack_intracrate(&mut self,
328-
stack: &ObligationStack)
329-
-> EvaluationResult
330-
{
331344
// If there is any previous entry on the stack that precisely
332345
// matches this obligation, then we can assume that the
333346
// obligation is satisfied for now (still all other conditions
@@ -592,7 +605,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
592605
Err(_) => { return Err(()); }
593606
}
594607

595-
if self.evaluate_obligation_intracrate(obligation) {
608+
if self.evaluate_obligation(obligation) {
596609
Ok(())
597610
} else {
598611
Err(())
@@ -804,12 +817,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
804817
&candidates[i],
805818
&candidates[j]));
806819
if is_dup {
807-
debug!("Dropping candidate #{}/#{}: {}",
820+
debug!("Dropping candidate #{}/{}: {}",
808821
i, candidates.len(), candidates[i].repr(self.tcx()));
809822
candidates.swap_remove(i);
810823
} else {
811-
debug!("Retaining candidate #{}/#{}",
812-
i, candidates.len());
824+
debug!("Retaining candidate #{}/{}: {}",
825+
i, candidates.len(), candidates[i].repr(self.tcx()));
813826
i += 1;
814827
}
815828
}
@@ -828,7 +841,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
828841
// be the case that you could still satisfy the obligation
829842
// from another crate by instantiating the type variables with
830843
// a type from another crate that does have an impl. This case
831-
// is checked for in `evaluate_obligation` (and hence users
844+
// is checked for in `evaluate_stack` (and hence users
832845
// who might care about this case, like coherence, should use
833846
// that function).
834847
if candidates.len() == 0 {
@@ -849,6 +862,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
849862
// global cache. We want the cache that is specific to this
850863
// scope whenever where clauses might affect the result.
851864

865+
// Avoid using the master cache during coherence and just rely
866+
// on the local cache. This effectively disables caching
867+
// during coherence. It is really just a simplification to
868+
// avoid us having to fear that coherence results "pollute"
869+
// the master cache. Since coherence executes pretty quickly,
870+
// it's not worth going to more trouble to increase the
871+
// hit-rate I don't think.
872+
if self.intercrate {
873+
return &self.param_env.selection_cache;
874+
}
875+
852876
// If the trait refers to any parameters in scope, then use
853877
// the cache of the param-environment.
854878
if

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(
235235
let mut selcx = traits::SelectionContext::new(fcx.infcx(),
236236
&fcx.inh.param_env,
237237
fcx);
238-
if !selcx.evaluate_obligation_intracrate(&obligation) {
238+
if !selcx.evaluate_obligation(&obligation) {
239239
debug!("--> Cannot match obligation");
240240
return None; // Cannot be matched, no such method resolution is possible.
241241
}

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

+8-3
Original file line numberDiff line numberDiff line change
@@ -2147,11 +2147,11 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt,
21472147
_ => {}
21482148
}
21492149

2150-
// Try `FnOnce`, then `FnMut`, then `Fn`.
2150+
// Try the options that are least restrictive on the caller first.
21512151
for &(maybe_function_trait, method_name) in [
2152-
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
2152+
(fcx.tcx().lang_items.fn_trait(), token::intern("call")),
21532153
(fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
2154-
(fcx.tcx().lang_items.fn_trait(), token::intern("call"))
2154+
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
21552155
].iter() {
21562156
let function_trait = match maybe_function_trait {
21572157
None => continue,
@@ -3493,6 +3493,11 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
34933493
ast::FnOnceUnboxedClosureKind => ty::FnOnceUnboxedClosureKind,
34943494
};
34953495

3496+
debug!("unboxed_closure for {} --> sig={} kind={}",
3497+
local_def(expr.id).repr(fcx.tcx()),
3498+
fn_ty.sig.repr(fcx.tcx()),
3499+
kind);
3500+
34963501
let unboxed_closure = ty::UnboxedClosure {
34973502
closure_type: fn_ty,
34983503
kind: kind,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
// Checks that the Fn trait hierarchy rules do not permit
12+
// Fn to be used where FnMut is implemented.
13+
14+
#![feature(unboxed_closure_sugar)]
15+
#![feature(overloaded_calls)]
16+
17+
use std::ops::{Fn,FnMut,FnOnce};
18+
19+
struct S;
20+
21+
impl FnMut<(int,),int> for S {
22+
extern "rust-call" fn call_mut(&mut self, (x,): (int,)) -> int {
23+
x * x
24+
}
25+
}
26+
27+
fn call_it<F:Fn(int)->int>(f: &F, x: int) -> int {
28+
f.call((x,))
29+
}
30+
31+
fn main() {
32+
let x = call_it(&S, 22); //~ ERROR not implemented
33+
}
34+

0 commit comments

Comments
 (0)