Skip to content

Commit 39221a0

Browse files
committed
Implement the Fn trait for bare fn pointers in the compiler rather than doing it using hard-coded impls. This means that it works also for more complex fn types involving bound regions. Fixes #19126.
1 parent 207a508 commit 39221a0

15 files changed

+442
-74
lines changed

src/libcore/ops.rs

+42-38
Original file line numberDiff line numberDiff line change
@@ -833,48 +833,52 @@ impl<F,A,R> FnOnce<A,R> for F
833833
}
834834
}
835835

836-
837-
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
838-
#[allow(non_snake_case)]
839-
extern "rust-call" fn call(&self, _args: ()) -> Result {
840-
(*self)()
836+
#[cfg(stage0)]
837+
mod fn_impls {
838+
use super::Fn;
839+
840+
impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
841+
#[allow(non_snake_case)]
842+
extern "rust-call" fn call(&self, _args: ()) -> Result {
843+
(*self)()
844+
}
841845
}
842-
}
843846

844-
impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
845-
#[allow(non_snake_case)]
846-
extern "rust-call" fn call(&self, args: (A0,)) -> Result {
847-
let (a0,) = args;
848-
(*self)(a0)
847+
impl<Result,A0> Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result {
848+
#[allow(non_snake_case)]
849+
extern "rust-call" fn call(&self, args: (A0,)) -> Result {
850+
let (a0,) = args;
851+
(*self)(a0)
852+
}
849853
}
850-
}
851854

852-
macro_rules! def_fn(
853-
($($args:ident)*) => (
854-
impl<Result$(,$args)*>
855-
Fn<($($args,)*),Result>
856-
for extern "Rust" fn($($args: $args,)*) -> Result {
857-
#[allow(non_snake_case)]
858-
extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
859-
let ($($args,)*) = args;
860-
(*self)($($args,)*)
855+
macro_rules! def_fn(
856+
($($args:ident)*) => (
857+
impl<Result$(,$args)*>
858+
Fn<($($args,)*),Result>
859+
for extern "Rust" fn($($args: $args,)*) -> Result {
860+
#[allow(non_snake_case)]
861+
extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
862+
let ($($args,)*) = args;
863+
(*self)($($args,)*)
864+
}
861865
}
862-
}
866+
)
863867
)
864-
)
865868

866-
def_fn!(A0 A1)
867-
def_fn!(A0 A1 A2)
868-
def_fn!(A0 A1 A2 A3)
869-
def_fn!(A0 A1 A2 A3 A4)
870-
def_fn!(A0 A1 A2 A3 A4 A5)
871-
def_fn!(A0 A1 A2 A3 A4 A5 A6)
872-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
873-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
874-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
875-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
876-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
877-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
878-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
879-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
880-
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
869+
def_fn!(A0 A1)
870+
def_fn!(A0 A1 A2)
871+
def_fn!(A0 A1 A2 A3)
872+
def_fn!(A0 A1 A2 A3 A4)
873+
def_fn!(A0 A1 A2 A3 A4 A5)
874+
def_fn!(A0 A1 A2 A3 A4 A5 A6)
875+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
876+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
877+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
878+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
879+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11)
880+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12)
881+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13)
882+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
883+
def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
884+
}

src/librustc/middle/traits/mod.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -167,18 +167,21 @@ pub enum Vtable<'tcx, N> {
167167
/// Vtable identifying a particular impl.
168168
VtableImpl(VtableImplData<'tcx, N>),
169169

170-
/// Vtable automatically generated for an unboxed closure. The def
171-
/// ID is the ID of the closure expression. This is a `VtableImpl`
172-
/// in spirit, but the impl is generated by the compiler and does
173-
/// not appear in the source.
174-
VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
175-
176170
/// Successful resolution to an obligation provided by the caller
177171
/// for some type parameter.
178172
VtableParam(VtableParamData<'tcx>),
179173

180174
/// Successful resolution for a builtin trait.
181175
VtableBuiltin(VtableBuiltinData<N>),
176+
177+
/// Vtable automatically generated for an unboxed closure. The def
178+
/// ID is the ID of the closure expression. This is a `VtableImpl`
179+
/// in spirit, but the impl is generated by the compiler and does
180+
/// not appear in the source.
181+
VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
182+
183+
/// Same as above, but for a fn pointer type with the given signature.
184+
VtableFnPointer(ty::Ty<'tcx>),
182185
}
183186

184187
/// Identifies a particular impl in the source, along with a set of
@@ -322,6 +325,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
322325
pub fn iter_nested(&self) -> Items<N> {
323326
match *self {
324327
VtableImpl(ref i) => i.iter_nested(),
328+
VtableFnPointer(..) => (&[]).iter(),
325329
VtableUnboxedClosure(..) => (&[]).iter(),
326330
VtableParam(_) => (&[]).iter(),
327331
VtableBuiltin(ref i) => i.iter_nested(),
@@ -331,6 +335,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
331335
pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<'tcx, M> {
332336
match *self {
333337
VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
338+
VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
334339
VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
335340
VtableParam(ref p) => VtableParam((*p).clone()),
336341
VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
@@ -340,6 +345,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
340345
pub fn map_move_nested<M>(self, op: |N| -> M) -> Vtable<'tcx, M> {
341346
match self {
342347
VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
348+
VtableFnPointer(sig) => VtableFnPointer(sig),
343349
VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
344350
VtableParam(p) => VtableParam(p),
345351
VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),

src/librustc/middle/traits/select.rs

+126-17
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use super::{SelectionError, Unimplemented, Overflow,
2222
OutputTypeParameterMismatch};
2323
use super::{Selection};
2424
use super::{SelectionResult};
25-
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure};
25+
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
2626
use super::{VtableImplData, VtableParamData, VtableBuiltinData};
2727
use super::{util};
2828

@@ -36,7 +36,7 @@ use middle::ty_fold::TypeFoldable;
3636
use std::cell::RefCell;
3737
use std::collections::hash_map::HashMap;
3838
use std::rc::Rc;
39-
use syntax::ast;
39+
use syntax::{abi, ast};
4040
use util::common::ErrorReported;
4141
use util::ppaux::Repr;
4242

@@ -131,7 +131,15 @@ enum Candidate<'tcx> {
131131
BuiltinCandidate(ty::BuiltinBound),
132132
ParamCandidate(VtableParamData<'tcx>),
133133
ImplCandidate(ast::DefId),
134+
135+
/// Implementation of a `Fn`-family trait by one of the
136+
/// anonymous types generated for a `||` expression.
134137
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>),
138+
139+
/// Implementation of a `Fn`-family trait by one of the anonymous
140+
/// types generated for a fn pointer type (e.g., `fn(int)->int`)
141+
FnPointerCandidate,
142+
135143
ErrorCandidate,
136144
}
137145

@@ -917,7 +925,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
917925
None => {
918926
// For the time being, we ignore user-defined impls for builtin-bounds.
919927
// (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
920-
try!(self.assemble_unboxed_candidates(obligation, &mut candidates));
928+
try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
929+
try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
921930
try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
922931
}
923932
}
@@ -968,20 +977,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
968977
/// Note: the type parameters on an unboxed closure candidate are modeled as *output* type
969978
/// parameters and hence do not affect whether this trait is a match or not. They will be
970979
/// unified during the confirmation step.
971-
fn assemble_unboxed_candidates(&mut self,
972-
obligation: &Obligation<'tcx>,
973-
candidates: &mut CandidateSet<'tcx>)
974-
-> Result<(),SelectionError<'tcx>>
980+
fn assemble_unboxed_closure_candidates(&mut self,
981+
obligation: &Obligation<'tcx>,
982+
candidates: &mut CandidateSet<'tcx>)
983+
-> Result<(),SelectionError<'tcx>>
975984
{
976-
let tcx = self.tcx();
977-
let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() {
978-
ty::FnUnboxedClosureKind
979-
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() {
980-
ty::FnMutUnboxedClosureKind
981-
} else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() {
982-
ty::FnOnceUnboxedClosureKind
983-
} else {
984-
return Ok(()); // not a fn trait, ignore
985+
let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) {
986+
Some(k) => k,
987+
None => { return Ok(()); }
985988
};
986989

987990
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
@@ -1015,6 +1018,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
10151018
Ok(())
10161019
}
10171020

1021+
/// Implement one of the `Fn()` family for a fn pointer.
1022+
fn assemble_fn_pointer_candidates(&mut self,
1023+
obligation: &Obligation<'tcx>,
1024+
candidates: &mut CandidateSet<'tcx>)
1025+
-> Result<(),SelectionError<'tcx>>
1026+
{
1027+
// We provide a `Fn` impl for fn pointers (but not e.g. `FnMut`).
1028+
if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() {
1029+
return Ok(());
1030+
}
1031+
1032+
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
1033+
match self_ty.sty {
1034+
ty::ty_infer(..) => {
1035+
candidates.ambiguous = true; // could wind up being a fn() type
1036+
}
1037+
1038+
// provide an impl, but only for suitable `fn` pointers
1039+
ty::ty_bare_fn(ty::BareFnTy {
1040+
fn_style: ast::NormalFn,
1041+
abi: abi::Rust,
1042+
sig: ty::FnSig {
1043+
inputs: _,
1044+
output: ty::FnConverging(_),
1045+
variadic: false
1046+
}
1047+
}) => {
1048+
candidates.vec.push(FnPointerCandidate);
1049+
}
1050+
1051+
_ => { }
1052+
}
1053+
1054+
Ok(())
1055+
}
1056+
10181057
/// Search for impls that might apply to `obligation`.
10191058
fn assemble_candidates_from_impls(&mut self,
10201059
obligation: &Obligation<'tcx>,
@@ -1551,6 +1590,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15511590
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs));
15521591
Ok(VtableUnboxedClosure(closure_def_id, substs))
15531592
}
1593+
1594+
FnPointerCandidate => {
1595+
let fn_type =
1596+
try!(self.confirm_fn_pointer_candidate(obligation));
1597+
Ok(VtableFnPointer(fn_type))
1598+
}
15541599
}
15551600
}
15561601

@@ -1646,6 +1691,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16461691
nested: impl_obligations }
16471692
}
16481693

1694+
fn confirm_fn_pointer_candidate(&mut self,
1695+
obligation: &Obligation<'tcx>)
1696+
-> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
1697+
{
1698+
debug!("confirm_fn_pointer_candidate({})",
1699+
obligation.repr(self.tcx()));
1700+
1701+
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
1702+
let sig = match self_ty.sty {
1703+
ty::ty_bare_fn(ty::BareFnTy {
1704+
fn_style: ast::NormalFn,
1705+
abi: abi::Rust,
1706+
ref sig
1707+
}) => {
1708+
(*sig).clone()
1709+
}
1710+
_ => {
1711+
self.tcx().sess.span_bug(
1712+
obligation.cause.span,
1713+
format!("Fn pointer candidate for inappropriate self type: {}",
1714+
self_ty.repr(self.tcx())).as_slice());
1715+
}
1716+
};
1717+
1718+
let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec());
1719+
let output_type = sig.output.unwrap();
1720+
let substs =
1721+
Substs::new_trait(
1722+
vec![arguments_tuple, output_type],
1723+
vec![],
1724+
vec![],
1725+
self_ty);
1726+
let trait_ref = Rc::new(ty::TraitRef {
1727+
def_id: obligation.trait_ref.def_id,
1728+
substs: substs,
1729+
});
1730+
1731+
let () =
1732+
try!(self.confirm(obligation.cause,
1733+
obligation.trait_ref.clone(),
1734+
trait_ref));
1735+
1736+
Ok(self_ty)
1737+
}
1738+
16491739
fn confirm_unboxed_closure_candidate(&mut self,
16501740
obligation: &Obligation<'tcx>,
16511741
closure_def_id: ast::DefId,
@@ -1964,6 +2054,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
19642054
util::obligations_for_generics(self.tcx(), cause, recursion_depth,
19652055
&bounds, &impl_substs.types)
19662056
}
2057+
2058+
fn fn_family_trait_kind(&self,
2059+
trait_def_id: ast::DefId)
2060+
-> Option<ty::UnboxedClosureKind>
2061+
{
2062+
let tcx = self.tcx();
2063+
if Some(trait_def_id) == tcx.lang_items.fn_trait() {
2064+
Some(ty::FnUnboxedClosureKind)
2065+
} else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
2066+
Some(ty::FnMutUnboxedClosureKind)
2067+
} else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
2068+
Some(ty::FnOnceUnboxedClosureKind)
2069+
} else {
2070+
None
2071+
}
2072+
}
19672073
}
19682074

19692075
impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
@@ -1972,7 +2078,10 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
19722078
ErrorCandidate => format!("ErrorCandidate"),
19732079
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
19742080
UnboxedClosureCandidate(c, ref s) => {
1975-
format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
2081+
format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx))
2082+
}
2083+
FnPointerCandidate => {
2084+
format!("FnPointerCandidate")
19762085
}
19772086
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
19782087
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),

src/librustc/middle/traits/util.rs

+4
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,10 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
302302
d.repr(tcx),
303303
s.repr(tcx)),
304304

305+
super::VtableFnPointer(ref d) =>
306+
format!("VtableFnPointer({})",
307+
d.repr(tcx)),
308+
305309
super::VtableParam(ref v) =>
306310
format!("VtableParam({})", v.repr(tcx)),
307311

src/librustc/middle/ty_fold.rs

+3
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N>
466466
traits::VtableUnboxedClosure(d, ref s) => {
467467
traits::VtableUnboxedClosure(d, s.fold_with(folder))
468468
}
469+
traits::VtableFnPointer(ref d) => {
470+
traits::VtableFnPointer(d.fold_with(folder))
471+
}
469472
traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
470473
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
471474
}

0 commit comments

Comments
 (0)