]> git.lizzy.rs Git - rust.git/commitdiff
Implement the `Fn` trait for bare fn pointers in the compiler rather than doing it...
authorNiko Matsakis <niko@alum.mit.edu>
Mon, 1 Dec 2014 14:23:40 +0000 (09:23 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Thu, 4 Dec 2014 06:49:42 +0000 (01:49 -0500)
15 files changed:
src/libcore/ops.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/select.rs
src/librustc/middle/traits/util.rs
src/librustc/middle/ty_fold.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/meth.rs
src/test/compile-fail/issue-15965.rs
src/test/compile-fail/issue-18532.rs
src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs [new file with mode: 0644]
src/test/compile-fail/unboxed-closures-wrong-abi.rs [new file with mode: 0644]
src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs [new file with mode: 0644]
src/test/run-pass/unboxed-closures-extern-fn-hr.rs [new file with mode: 0644]
src/test/run-pass/unboxed-closures-extern-fn.rs

index d85481098e4ffaabfbe6d0145b5d59f5d9522e6e..4f4ec4867972eeceaa147f2a8c827f73b4c82467 100644 (file)
@@ -833,48 +833,52 @@ extern "rust-call" fn call_once(mut self, args: A) -> R {
     }
 }
 
-
-impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
-    #[allow(non_snake_case)]
-    extern "rust-call" fn call(&self, _args: ()) -> Result {
-        (*self)()
+#[cfg(stage0)]
+mod fn_impls {
+    use super::Fn;
+
+    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)
+    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)*) => (
-        impl<Result$(,$args)*>
-        Fn<($($args,)*),Result>
-        for extern "Rust" fn($($args: $args,)*) -> Result {
-            #[allow(non_snake_case)]
-            extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
-                let ($($args,)*) = args;
-                (*self)($($args,)*)
+    macro_rules! def_fn(
+        ($($args:ident)*) => (
+            impl<Result$(,$args)*>
+            Fn<($($args,)*),Result>
+            for extern "Rust" fn($($args: $args,)*) -> Result {
+                #[allow(non_snake_case)]
+                extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result {
+                    let ($($args,)*) = args;
+                    (*self)($($args,)*)
+                }
             }
-        }
+        )
     )
-)
 
-def_fn!(A0 A1)
-def_fn!(A0 A1 A2)
-def_fn!(A0 A1 A2 A3)
-def_fn!(A0 A1 A2 A3 A4)
-def_fn!(A0 A1 A2 A3 A4 A5)
-def_fn!(A0 A1 A2 A3 A4 A5 A6)
-def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
-def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
-def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
-def_fn!(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)
-def_fn!(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)
-def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
-def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
+    def_fn!(A0 A1)
+    def_fn!(A0 A1 A2)
+    def_fn!(A0 A1 A2 A3)
+    def_fn!(A0 A1 A2 A3 A4)
+    def_fn!(A0 A1 A2 A3 A4 A5)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6 A7)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9)
+    def_fn!(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)
+    def_fn!(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)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14)
+    def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15)
+}
index 34278c25cfa0b1f6ea02a7d2045a97526475da30..b8d915c06e0b7462531a26a538cab0fb95f5ae0a 100644 (file)
@@ -167,18 +167,21 @@ pub enum Vtable<'tcx, N> {
     /// Vtable identifying a particular impl.
     VtableImpl(VtableImplData<'tcx, N>),
 
-    /// Vtable automatically generated for an unboxed closure. The def
-    /// ID is the ID of the closure expression. This is a `VtableImpl`
-    /// in spirit, but the impl is generated by the compiler and does
-    /// not appear in the source.
-    VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
-
     /// Successful resolution to an obligation provided by the caller
     /// for some type parameter.
     VtableParam(VtableParamData<'tcx>),
 
     /// Successful resolution for a builtin trait.
     VtableBuiltin(VtableBuiltinData<N>),
+
+    /// Vtable automatically generated for an unboxed closure. The def
+    /// ID is the ID of the closure expression. This is a `VtableImpl`
+    /// in spirit, but the impl is generated by the compiler and does
+    /// not appear in the source.
+    VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>),
+
+    /// Same as above, but for a fn pointer type with the given signature.
+    VtableFnPointer(ty::Ty<'tcx>),
 }
 
 /// Identifies a particular impl in the source, along with a set of
@@ -322,6 +325,7 @@ impl<'tcx, N> Vtable<'tcx, N> {
     pub fn iter_nested(&self) -> Items<N> {
         match *self {
             VtableImpl(ref i) => i.iter_nested(),
+            VtableFnPointer(..) => (&[]).iter(),
             VtableUnboxedClosure(..) => (&[]).iter(),
             VtableParam(_) => (&[]).iter(),
             VtableBuiltin(ref i) => i.iter_nested(),
@@ -331,6 +335,7 @@ pub fn iter_nested(&self) -> Items<N> {
     pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<'tcx, M> {
         match *self {
             VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
+            VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
             VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()),
             VtableParam(ref p) => VtableParam((*p).clone()),
             VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)),
@@ -340,6 +345,7 @@ pub fn map_nested<M>(&self, op: |&N| -> M) -> Vtable<'tcx, M> {
     pub fn map_move_nested<M>(self, op: |N| -> M) -> Vtable<'tcx, M> {
         match self {
             VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
+            VtableFnPointer(sig) => VtableFnPointer(sig),
             VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s),
             VtableParam(p) => VtableParam(p),
             VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)),
index 71a183b475c6f370438d76c8e6e642c8a846969b..9dbcf455f4b58b91d1e6e17abda8dbfba5039cf3 100644 (file)
@@ -22,7 +22,7 @@
             OutputTypeParameterMismatch};
 use super::{Selection};
 use super::{SelectionResult};
-use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure};
+use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer};
 use super::{VtableImplData, VtableParamData, VtableBuiltinData};
 use super::{util};
 
@@ -36,7 +36,7 @@
 use std::cell::RefCell;
 use std::collections::hash_map::HashMap;
 use std::rc::Rc;
-use syntax::ast;
+use syntax::{abi, ast};
 use util::common::ErrorReported;
 use util::ppaux::Repr;
 
@@ -131,7 +131,15 @@ enum Candidate<'tcx> {
     BuiltinCandidate(ty::BuiltinBound),
     ParamCandidate(VtableParamData<'tcx>),
     ImplCandidate(ast::DefId),
+
+    /// Implementation of a `Fn`-family trait by one of the
+    /// anonymous types generated for a `||` expression.
     UnboxedClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>),
+
+    /// Implementation of a `Fn`-family trait by one of the anonymous
+    /// types generated for a fn pointer type (e.g., `fn(int)->int`)
+    FnPointerCandidate,
+
     ErrorCandidate,
 }
 
@@ -917,7 +925,8 @@ fn assemble_candidates<'o>(&mut self,
             None => {
                 // For the time being, we ignore user-defined impls for builtin-bounds.
                 // (And unboxed candidates only apply to the Fn/FnMut/etc traits.)
-                try!(self.assemble_unboxed_candidates(obligation, &mut candidates));
+                try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates));
+                try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates));
                 try!(self.assemble_candidates_from_impls(obligation, &mut candidates));
             }
         }
@@ -968,20 +977,14 @@ fn assemble_candidates_from_caller_bounds(&mut self,
     /// Note: the type parameters on an unboxed closure candidate are modeled as *output* type
     /// parameters and hence do not affect whether this trait is a match or not. They will be
     /// unified during the confirmation step.
-    fn assemble_unboxed_candidates(&mut self,
-                                   obligation: &Obligation<'tcx>,
-                                   candidates: &mut CandidateSet<'tcx>)
-                                   -> Result<(),SelectionError<'tcx>>
+    fn assemble_unboxed_closure_candidates(&mut self,
+                                           obligation: &Obligation<'tcx>,
+                                           candidates: &mut CandidateSet<'tcx>)
+                                           -> Result<(),SelectionError<'tcx>>
     {
-        let tcx = self.tcx();
-        let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() {
-            ty::FnUnboxedClosureKind
-        } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() {
-            ty::FnMutUnboxedClosureKind
-        } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() {
-            ty::FnOnceUnboxedClosureKind
-        } else {
-            return Ok(()); // not a fn trait, ignore
+        let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) {
+            Some(k) => k,
+            None => { return Ok(()); }
         };
 
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
@@ -1015,6 +1018,42 @@ fn assemble_unboxed_candidates(&mut self,
         Ok(())
     }
 
+    /// Implement one of the `Fn()` family for a fn pointer.
+    fn assemble_fn_pointer_candidates(&mut self,
+                                      obligation: &Obligation<'tcx>,
+                                      candidates: &mut CandidateSet<'tcx>)
+                                      -> Result<(),SelectionError<'tcx>>
+    {
+        // We provide a `Fn` impl for fn pointers (but not e.g. `FnMut`).
+        if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() {
+            return Ok(());
+        }
+
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        match self_ty.sty {
+            ty::ty_infer(..) => {
+                candidates.ambiguous = true; // could wind up being a fn() type
+            }
+
+            // provide an impl, but only for suitable `fn` pointers
+            ty::ty_bare_fn(ty::BareFnTy {
+                fn_style: ast::NormalFn,
+                abi: abi::Rust,
+                sig: ty::FnSig {
+                    inputs: _,
+                    output: ty::FnConverging(_),
+                    variadic: false
+                }
+            }) => {
+                candidates.vec.push(FnPointerCandidate);
+            }
+
+            _ => { }
+        }
+
+        Ok(())
+    }
+
     /// Search for impls that might apply to `obligation`.
     fn assemble_candidates_from_impls(&mut self,
                                       obligation: &Obligation<'tcx>,
@@ -1551,6 +1590,12 @@ fn confirm_candidate(&mut self,
                 try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs));
                 Ok(VtableUnboxedClosure(closure_def_id, substs))
             }
+
+            FnPointerCandidate => {
+                let fn_type =
+                    try!(self.confirm_fn_pointer_candidate(obligation));
+                Ok(VtableFnPointer(fn_type))
+            }
         }
     }
 
@@ -1646,6 +1691,51 @@ fn vtable_impl(&mut self,
                          nested: impl_obligations }
     }
 
+    fn confirm_fn_pointer_candidate(&mut self,
+                                    obligation: &Obligation<'tcx>)
+                                    -> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
+    {
+        debug!("confirm_fn_pointer_candidate({})",
+               obligation.repr(self.tcx()));
+
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        let sig = match self_ty.sty {
+            ty::ty_bare_fn(ty::BareFnTy {
+                fn_style: ast::NormalFn,
+                abi: abi::Rust,
+                ref sig
+            }) => {
+                (*sig).clone()
+            }
+            _ => {
+                self.tcx().sess.span_bug(
+                    obligation.cause.span,
+                    format!("Fn pointer candidate for inappropriate self type: {}",
+                            self_ty.repr(self.tcx())).as_slice());
+            }
+        };
+
+        let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec());
+        let output_type = sig.output.unwrap();
+        let substs =
+            Substs::new_trait(
+                vec![arguments_tuple, output_type],
+                vec![],
+                vec![],
+                self_ty);
+        let trait_ref = Rc::new(ty::TraitRef {
+            def_id: obligation.trait_ref.def_id,
+            substs: substs,
+        });
+
+        let () =
+            try!(self.confirm(obligation.cause,
+                              obligation.trait_ref.clone(),
+                              trait_ref));
+
+        Ok(self_ty)
+    }
+
     fn confirm_unboxed_closure_candidate(&mut self,
                                          obligation: &Obligation<'tcx>,
                                          closure_def_id: ast::DefId,
@@ -1964,6 +2054,22 @@ fn impl_obligations(&self,
         util::obligations_for_generics(self.tcx(), cause, recursion_depth,
                                        &bounds, &impl_substs.types)
     }
+
+    fn fn_family_trait_kind(&self,
+                            trait_def_id: ast::DefId)
+                            -> Option<ty::UnboxedClosureKind>
+    {
+        let tcx = self.tcx();
+        if Some(trait_def_id) == tcx.lang_items.fn_trait() {
+            Some(ty::FnUnboxedClosureKind)
+        } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
+            Some(ty::FnMutUnboxedClosureKind)
+        } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
+            Some(ty::FnOnceUnboxedClosureKind)
+        } else {
+            None
+        }
+    }
 }
 
 impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
@@ -1972,7 +2078,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
             ErrorCandidate => format!("ErrorCandidate"),
             BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
             UnboxedClosureCandidate(c, ref s) => {
-                format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
+                format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx))
+            }
+            FnPointerCandidate => {
+                format!("FnPointerCandidate")
             }
             ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
             ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
index e8b292aac6d32a2b48b65be357abfc0a5513978f..1084807ef4a0a58dcb2350adf09c14452fac3b08 100644 (file)
@@ -302,6 +302,10 @@ fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
                         d.repr(tcx),
                         s.repr(tcx)),
 
+            super::VtableFnPointer(ref d) =>
+                format!("VtableFnPointer({})",
+                        d.repr(tcx)),
+
             super::VtableParam(ref v) =>
                 format!("VtableParam({})", v.repr(tcx)),
 
index 08dcbffc9287b6a13bf0ebf75dbd741b6af47223..de9eb42649845dd9e07be5cc218ce04c4f12c46b 100644 (file)
@@ -466,6 +466,9 @@ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::Vtable<'tcx,
             traits::VtableUnboxedClosure(d, ref s) => {
                 traits::VtableUnboxedClosure(d, s.fold_with(folder))
             }
+            traits::VtableFnPointer(ref d) => {
+                traits::VtableFnPointer(d.fold_with(folder))
+            }
             traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)),
             traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
         }
index 23072dee3b6b1491651af2c6d3530076845fd643..84a6b59934f6eeba475bce19067c0790f8e80b27 100644 (file)
@@ -995,9 +995,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 
     if need_invoke(bcx) {
-        debug!("invoking {} at {}", llfn, bcx.llbb);
+        debug!("invoking {} at {}", bcx.val_to_string(llfn), bcx.llbb);
         for &llarg in llargs.iter() {
-            debug!("arg: {}", llarg);
+            debug!("arg: {}", bcx.val_to_string(llarg));
         }
         let normal_bcx = bcx.fcx.new_temp_block("normal-return");
         let landing_pad = bcx.fcx.get_landing_pad();
@@ -1015,9 +1015,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                               Some(attributes));
         return (llresult, normal_bcx);
     } else {
-        debug!("calling {} at {}", llfn, bcx.llbb);
+        debug!("calling {} at {}", bcx.val_to_string(llfn), bcx.llbb);
         for &llarg in llargs.iter() {
-            debug!("arg: {}", llarg);
+            debug!("arg: {}", bcx.val_to_string(llarg));
         }
 
         match call_info {
index 50d2f885afa17f69015c0d9a42c1345d94ab17be..4bcb7b09495d90ae9773a1616ac9f0863e4ec046 100644 (file)
@@ -242,6 +242,112 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
+/// Translates an adapter that implements the `Fn` trait for a fn
+/// pointer. This is basically the equivalent of something like:
+///
+/// ```rust
+/// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int {
+///     extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int {
+///         (*self)(args.0)
+///     }
+/// }
+/// ```
+///
+/// but for the bare function type given.
+pub fn trans_fn_pointer_shim<'a, 'tcx>(
+    ccx: &'a CrateContext<'a, 'tcx>,
+    bare_fn_ty: Ty<'tcx>)
+    -> ValueRef
+{
+    let _icx = push_ctxt("trans_fn_pointer_shim");
+    let tcx = ccx.tcx();
+
+    debug!("trans_fn_pointer_shim(bare_fn_ty={})",
+           bare_fn_ty.repr(tcx));
+
+    // This is an impl of `Fn` trait, so receiver is `&self`.
+    let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, ty::ReStatic, bare_fn_ty);
+
+    // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
+    // which is the fn pointer, and `args`, which is the arguments tuple.
+    let (input_tys, output_ty) =
+        match bare_fn_ty.sty {
+            ty::ty_bare_fn(ty::BareFnTy { fn_style: ast::NormalFn,
+                                          abi: synabi::Rust,
+                                          sig: ty::FnSig { inputs: ref input_tys,
+                                                           output: output_ty,
+                                                           variadic: false }}) =>
+            {
+                (input_tys, output_ty)
+            }
+
+            _ => {
+                tcx.sess.bug(format!("trans_fn_pointer_shim invoked on invalid type: {}",
+                                           bare_fn_ty.repr(tcx)).as_slice());
+            }
+        };
+    let tuple_input_ty = ty::mk_tup(tcx, input_tys.to_vec());
+    let tuple_fn_ty = ty::mk_bare_fn(tcx,
+                                     ty::BareFnTy { fn_style: ast::NormalFn,
+                                                    abi: synabi::RustCall,
+                                                    sig: ty::FnSig {
+                                                        inputs: vec![bare_fn_ty_ref,
+                                                                     tuple_input_ty],
+                                                        output: output_ty,
+                                                        variadic: false
+                                                    }});
+    debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
+
+    //
+    let function_name =
+        link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
+                                                   "fn_pointer_shim");
+    let llfn =
+        decl_internal_rust_fn(ccx,
+                              tuple_fn_ty,
+                              function_name.as_slice());
+
+    //
+    let block_arena = TypedArena::new();
+    let empty_substs = Substs::trans_empty();
+    let fcx = new_fn_ctxt(ccx,
+                          llfn,
+                          ast::DUMMY_NODE_ID,
+                          false,
+                          output_ty,
+                          &empty_substs,
+                          None,
+                          &block_arena);
+    let mut bcx = init_function(&fcx, false, output_ty);
+
+    // the first argument (`self`) will be ptr to the the fn pointer
+    let llfnpointer =
+        Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
+
+    // the remaining arguments will be the untupled values
+    let llargs: Vec<_> =
+        input_tys.iter()
+        .enumerate()
+        .map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32))
+        .collect();
+    assert!(!fcx.needs_ret_allocas);
+
+    let dest = fcx.llretslotptr.get().map(|_|
+        expr::SaveIn(fcx.get_ret_slot(bcx, output_ty, "ret_slot"))
+    );
+
+    bcx = trans_call_inner(bcx,
+                           None,
+                           bare_fn_ty,
+                           |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
+                           ArgVals(llargs.as_slice()),
+                           dest).bcx;
+
+    finish_fn(&fcx, bcx, output_ty);
+
+    llfn
+}
+
 /// Translates the adapter that deconstructs a `Box<Trait>` object into
 /// `Trait` so that a by-value self method can be called.
 pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
index a49b7b21627f84dde3b1076da218313e2f146a62..ef431243b31e9612848f32d2f18a81d01c2da0d2 100644 (file)
@@ -368,9 +368,15 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 data: Fn(llfn),
             }
         }
-        _ => {
-            bcx.tcx().sess.bug(
-                "vtable_param left in monomorphized function's vtable substs");
+        traits::VtableFnPointer(fn_ty) => {
+            let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
+            Callee { bcx: bcx, data: Fn(llfn) }
+        }
+        traits::VtableBuiltin(..) |
+        traits::VtableParam(..) => {
+            bcx.sess().bug(
+                format!("resolved vtable bad vtable {} in trans",
+                        vtable.repr(bcx.tcx())).as_slice());
         }
     }
 }
@@ -609,6 +615,10 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
                 (vec!(llfn)).into_iter()
             }
+            traits::VtableFnPointer(bare_fn_ty) => {
+                let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)];
+                llfn.into_iter()
+            }
             traits::VtableParam(..) => {
                 bcx.sess().bug(
                     format!("resolved vtable for {} to bad vtable {} in trans",
index 856cd1b0f3f26c3397da7a98ced7b8a668c7cf3a..935e67706589ef75f1bda27d3336776aef45d998 100644 (file)
@@ -11,8 +11,6 @@
 fn main() {
     return
         { return () } //~ ERROR the type of this value must be known in this context
-    () //~^ ERROR the type of this value must be known in this context
-//~^^ ERROR notation; the first type parameter for the function trait is neither a tuple nor unit
-//~^^^ ERROR overloaded calls are experimental
+    ()
     ;
 }
index 943d326182f89e30cfdba190256e2aeef1069990..9cf922ae99002cece4c190e728b073e601c0a9be 100644 (file)
@@ -17,6 +17,4 @@
 fn main() {
     (return)((),());
     //~^ ERROR the type of this value must be known
-    //~^^ ERROR the type of this value must be known
-    //~^^^ ERROR cannot use call notation
 }
diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs
new file mode 100644 (file)
index 0000000..a82689b
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+// Tests that unsafe extern fn pointers do not implement any Fn traits.
+
+#![feature(unboxed_closures)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+unsafe fn square(x: &int) -> int { (*x) * (*x) }
+
+fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
+
+fn main() {
+    let x = call_it(&square, 22); //~ ERROR not implemented
+    let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+    let z = call_it_once(square, 22); //~ ERROR not implemented
+}
+
diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs
new file mode 100644 (file)
index 0000000..920e919
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+// Tests that unsafe extern fn pointers do not implement any Fn traits.
+
+#![feature(unboxed_closures)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+extern "C" fn square(x: &int) -> int { (*x) * (*x) }
+
+fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
+
+fn main() {
+    let x = call_it(&square, 22); //~ ERROR not implemented
+    let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+    let z = call_it_once(square, 22); //~ ERROR not implemented
+}
+
diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs
new file mode 100644 (file)
index 0000000..a7a7b1c
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+// Tests that unsafe extern fn pointers do not implement any Fn traits.
+
+#![feature(unboxed_closures)]
+
+use std::ops::{Fn,FnMut,FnOnce};
+
+unsafe fn square(x: int) -> int { x * x }
+// note: argument type here is `int`, not `&int`
+
+fn call_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: F, _: int) -> int { 0 }
+
+fn main() {
+    let x = call_it(&square, 22); //~ ERROR not implemented
+    let y = call_it_mut(&mut square, 22); //~ ERROR not implemented
+    let z = call_it_once(square, 22); //~ ERROR not implemented
+}
+
diff --git a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs
new file mode 100644 (file)
index 0000000..df753f0
--- /dev/null
@@ -0,0 +1,45 @@
+// 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 higher-ranked extern fn pointers implement the full range of Fn traits.
+
+#![feature(unboxed_closures)]
+
+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)(&x)
+}
+
+fn call_it_boxed(f: &Fn(&int) -> int, x: int) -> int {
+    f.call((&x,))
+}
+
+fn call_it_mut<F:FnMut(&int)->int>(f: &mut F, x: int) -> int {
+    (*f)(&x)
+}
+
+fn call_it_once<F:FnOnce(&int)->int>(f: F, x: int) -> int {
+    f(&x)
+}
+
+fn main() {
+    let x = call_it(&square, 22);
+    let x1 = call_it_boxed(&square, 22);
+    let y = call_it_mut(&mut square, 22);
+    let z = call_it_once(square, 22);
+    assert_eq!(x, square(&22));
+    assert_eq!(x1, square(&22));
+    assert_eq!(y, square(&22));
+    assert_eq!(z, square(&22));
+}
+
index 2628bd90eef0e1756ea2f26ac7aa7e81f2a66be1..58657c2b71880dbcbdea73719ad698847e056e58 100644 (file)
@@ -8,7 +8,7 @@
 // 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.
+// Checks that extern fn pointers implement the full range of Fn traits.
 
 #![feature(unboxed_closures)]
 #![feature(unboxed_closures)]