about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-18 00:24:05 +0000
committerbors <bors@rust-lang.org>2015-12-18 00:24:05 +0000
commit4eadabd9f8818c562446751a0ef03ea2165e7056 (patch)
tree52456c40e248d31a72bae602dc86c0054c49581e
parent48700be9cbf04d798a6f6ab65c50ab0afe86bc94 (diff)
parent7dd95799c2d31cd7b1ab573936b5ed26757fd08c (diff)
downloadrust-4eadabd9f8818c562446751a0ef03ea2165e7056.tar.gz
rust-4eadabd9f8818c562446751a0ef03ea2165e7056.zip
Auto merge of #29907 - nagisa:mir-moar-constants, r=nikomatsakis
Still will not translate references to items like `X` or `Y::V` where

```
struct X;
enum Y { V }
```

but I must go work on university things so I’m PRing what I have.

r? @nikomatsakis
-rw-r--r--src/librustc/mir/repr.rs10
-rw-r--r--src/librustc_mir/build/misc.rs1
-rw-r--r--src/librustc_mir/hair/cx/expr.rs36
-rw-r--r--src/librustc_mir/hair/cx/mod.rs8
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs6
-rw-r--r--src/librustc_mir/hair/mod.rs3
-rw-r--r--src/librustc_trans/trans/consts.rs15
-rw-r--r--src/librustc_trans/trans/meth.rs2
-rw-r--r--src/librustc_trans/trans/mir/constant.rs20
-rw-r--r--src/librustc_trans/trans/mir/did.rs160
-rw-r--r--src/librustc_trans/trans/mir/mod.rs1
-rw-r--r--src/librustc_trans/trans/mir/operand.rs10
-rw-r--r--src/test/auxiliary/mir_external_refs.rs28
-rw-r--r--src/test/run-pass/mir_refs_correct.rs218
14 files changed, 490 insertions, 28 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 049063f73a5..e83fe60f419 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -698,10 +698,20 @@ pub struct Constant<'tcx> {
     pub literal: Literal<'tcx>,
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+pub enum ItemKind {
+    Constant,
+    Function,
+    Struct,
+    Variant,
+    Method,
+}
+
 #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
 pub enum Literal<'tcx> {
     Item {
         def_id: DefId,
+        kind: ItemKind,
         substs: &'tcx Substs<'tcx>,
     },
     Value {
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index bdcb183c0ac..5d040bcb40a 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -66,6 +66,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                             -> Operand<'tcx> {
         let literal = Literal::Item {
             def_id: item_ref.def_id,
+            kind: item_ref.kind,
             substs: item_ref.substs,
         };
         self.literal_operand(span, item_ref.ty, literal)
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 08826013ebc..d1455e70165 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -480,6 +480,7 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
         kind: ExprKind::Literal {
             literal: Literal::Item {
                 def_id: callee.def_id,
+                kind: ItemKind::Method,
                 substs: callee.substs,
             },
         },
@@ -514,16 +515,39 @@ fn convert_arm<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<
 
 fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> {
     let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
-    match cx.tcx.def_map.borrow()[&expr.id].full_def() {
+    // Otherwise there may be def_map borrow conflicts
+    let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
+    match def {
         def::DefVariant(_, def_id, false) |
         def::DefStruct(def_id) |
         def::DefFn(def_id, _) |
-        def::DefConst(def_id) |
-        def::DefMethod(def_id) |
-        def::DefAssociatedConst(def_id) =>
+        def::DefMethod(def_id) => {
+            let kind = match def {
+                def::DefVariant(..) => ItemKind::Variant,
+                def::DefStruct(..) => ItemKind::Struct,
+                def::DefFn(..) => ItemKind::Function,
+                def::DefMethod(..) => ItemKind::Method,
+                _ => panic!()
+            };
             ExprKind::Literal {
-                literal: Literal::Item { def_id: def_id, substs: substs }
-            },
+                literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
+            }
+        },
+        def::DefConst(def_id) |
+        def::DefAssociatedConst(def_id) => {
+            if let Some(v) = cx.try_const_eval_literal(expr) {
+                ExprKind::Literal { literal: v }
+            } else {
+                ExprKind::Literal {
+                    literal: Literal::Item {
+                        def_id: def_id,
+                        kind: ItemKind::Constant,
+                        substs: substs
+                    }
+                }
+            }
+        }
+
 
         def::DefStatic(node_id, _) =>
             ExprKind::StaticRef {
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 8c19e620e46..d6cfd1a2c6e 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -76,6 +76,13 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
         Literal::Value { value: const_eval::eval_const_expr(self.tcx, e) }
     }
 
+    pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
+        let hint = const_eval::EvalHint::ExprTypeChecked;
+        const_eval::eval_const_expr_partial(self.tcx, e, hint, None)
+            .ok()
+            .map(|v| Literal::Value { value: v })
+    }
+
     pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
         let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
         self.cmp_method_ref(eq_def_id, "eq", ty)
@@ -132,6 +139,7 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
                         let method_ty = method_ty.ty.subst(self.tcx, &substs);
                         return ItemRef {
                             ty: method_ty,
+                            kind: ItemKind::Method,
                             def_id: method.def_id,
                             substs: self.tcx.mk_substs(substs),
                         };
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 74fef684006..c32efcd1a7d 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -97,7 +97,11 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
                                     Literal::Value { value: value }
                                 } else {
                                     let substs = self.cx.tcx.mk_substs(Substs::empty());
-                                    Literal::Item { def_id: def_id, substs: substs }
+                                    Literal::Item {
+                                        def_id: def_id,
+                                        kind: ItemKind::Constant,
+                                        substs: substs
+                                    }
                                 };
                                 PatternKind::Constant { value: literal }
                             }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 9a774ff3f57..99e6d6633f2 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -14,7 +14,7 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp};
+use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind};
 use rustc::middle::def_id::DefId;
 use rustc::middle::region::CodeExtent;
 use rustc::middle::subst::Substs;
@@ -29,6 +29,7 @@ pub mod cx;
 #[derive(Clone, Debug)]
 pub struct ItemRef<'tcx> {
     pub ty: Ty<'tcx>,
+    pub kind: ItemKind,
     pub def_id: DefId,
     pub substs: &'tcx Substs<'tcx>,
 }
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 77664f19aac..4b33e50ec52 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -108,12 +108,13 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
     }
 }
 
-pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+pub fn trans_constval<'blk, 'tcx>(bcx: common::Block<'blk, 'tcx>,
                                 cv: &ConstVal,
                                 ty: Ty<'tcx>,
                                 param_substs: &'tcx Substs<'tcx>)
                                 -> ValueRef
 {
+    let ccx = bcx.ccx();
     let llty = type_of::type_of(ccx, ty);
     match *cv {
         ConstVal::Float(v) => C_floating_f64(v, llty),
@@ -123,19 +124,17 @@ pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
         ConstVal::ByteStr(ref v) => addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
         ConstVal::Struct(id) | ConstVal::Tuple(id) => {
-            let expr = ccx.tcx().map.expect_expr(id);
+            let expr = bcx.tcx().map.expect_expr(id);
             match const_expr(ccx, expr, param_substs, None, TrueConst::Yes) {
                 Ok((val, _)) => val,
                 Err(e) => panic!("const eval failure: {}", e.description()),
             }
         },
-        ConstVal::Function(_) => {
-            unimplemented!()
+        ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => {
+            let expr = bcx.tcx().map.expect_expr(id);
+            expr::trans(bcx, expr).datum.val
         },
-        ConstVal::Array(..) => {
-            unimplemented!()
-        },
-        ConstVal::Repeat(..) => {
+        ConstVal::Function(_) => {
             unimplemented!()
         },
     }
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 049773f0bec..d29ab2ee6fb 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -472,7 +472,7 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 ///
 /// In fact, all virtual calls can be thought of as normal trait calls
 /// that go through this shim function.
-fn trans_object_shim<'a, 'tcx>(
+pub fn trans_object_shim<'a, 'tcx>(
     ccx: &'a CrateContext<'a, 'tcx>,
     upcast_trait_ref: ty::PolyTraitRef<'tcx>,
     method_id: DefId,
diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs
index 9c23d330136..38fab1dbf07 100644
--- a/src/librustc_trans/trans/mir/constant.rs
+++ b/src/librustc_trans/trans/mir/constant.rs
@@ -14,7 +14,8 @@ use rustc::mir::repr as mir;
 use trans::consts;
 use trans::common::{self, Block};
 
-use super::operand::OperandRef;
+
+use super::operand::{OperandRef, OperandValue};
 use super::MirContext;
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
@@ -24,14 +25,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                           ty: Ty<'tcx>)
                           -> OperandRef<'tcx>
     {
-        use super::operand::OperandValue::{Ref, Immediate};
-
         let ccx = bcx.ccx();
-        let val = consts::trans_constval(ccx, cv, ty, bcx.fcx.param_substs);
+        let val = consts::trans_constval(bcx, cv, ty, bcx.fcx.param_substs);
         let val = if common::type_is_immediate(ccx, ty) {
-            Immediate(val)
+            OperandValue::Immediate(val)
         } else {
-            Ref(val)
+            OperandValue::Ref(val)
         };
 
         assert!(!ty.has_erasable_regions());
@@ -47,13 +46,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                           constant: &mir::Constant<'tcx>)
                           -> OperandRef<'tcx>
     {
-        let constant_ty = bcx.monomorphize(&constant.ty);
+        let ty = bcx.monomorphize(&constant.ty);
         match constant.literal {
-            mir::Literal::Item { .. } => {
-                unimplemented!()
-            }
+            mir::Literal::Item { def_id, kind, substs } =>
+                self.trans_item_ref(bcx, ty, kind, substs, def_id),
             mir::Literal::Value { ref value } => {
-                self.trans_constval(bcx, value, constant_ty)
+                self.trans_constval(bcx, value, ty)
             }
         }
     }
diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs
new file mode 100644
index 00000000000..368708d470b
--- /dev/null
+++ b/src/librustc_trans/trans/mir/did.rs
@@ -0,0 +1,160 @@
+// Copyright 2015 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.
+
+//! Code for translating references to other items (DefIds).
+
+use syntax::codemap::DUMMY_SP;
+use rustc::front::map;
+use rustc::middle::ty::{self, Ty, HasTypeFlags};
+use rustc::middle::subst::Substs;
+use rustc::middle::const_eval;
+use rustc::middle::def_id::DefId;
+use rustc::middle::subst;
+use rustc::middle::traits;
+use rustc::mir::repr::ItemKind;
+use trans::common::{Block, fulfill_obligation};
+use trans::base;
+use trans::expr;
+use trans::monomorphize;
+use trans::meth;
+use trans::inline;
+
+use super::MirContext;
+use super::operand::{OperandRef, OperandValue};
+
+impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
+    /// Translate reference to item.
+    pub fn trans_item_ref(&mut self,
+                          bcx: Block<'bcx, 'tcx>,
+                          ty: Ty<'tcx>,
+                          kind: ItemKind,
+                          substs: &'tcx Substs<'tcx>,
+                          did: DefId)
+                          -> OperandRef<'tcx> {
+        match kind {
+            ItemKind::Function |
+            ItemKind::Struct |
+            ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
+            ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
+                ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
+                ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
+            },
+            ItemKind::Constant => {
+                let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
+                let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None)
+                            .expect("def was const, but lookup_const_by_id failed");
+                // FIXME: this is falling back to translating from HIR. This is not easy to fix,
+                // because we would have somehow adapt const_eval to work on MIR rather than HIR.
+                let d = expr::trans(bcx, expr);
+                OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
+            }
+        }
+    }
+
+    /// Translates references to a function-like items.
+    ///
+    /// That includes regular functions, non-static methods, struct and enum variant constructors,
+    /// closures and possibly more.
+    ///
+    /// This is an adaptation of callee::trans_fn_ref_with_substs.
+    pub fn trans_fn_ref(&mut self,
+                        bcx: Block<'bcx, 'tcx>,
+                        ty: Ty<'tcx>,
+                        substs: &'tcx Substs<'tcx>,
+                        did: DefId)
+                        -> OperandRef<'tcx> {
+        let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
+
+        if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
+            let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None);
+            // FIXME: cast fnptr to proper type if necessary
+            OperandRef {
+                ty: fn_ty,
+                val: OperandValue::Immediate(val)
+            }
+        } else {
+            let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
+                base::get_item_val(bcx.ccx(), node_id)
+            } else {
+                base::trans_external_path(bcx.ccx(), did, ty)
+            };
+            // FIXME: cast fnptr to proper type if necessary
+            OperandRef {
+                ty: ty,
+                val: OperandValue::Immediate(val)
+            }
+        }
+    }
+
+    /// Translates references to static methods.
+    ///
+    /// This is an adaptation of meth::trans_static_method_callee
+    pub fn trans_static_method(&mut self,
+                               bcx: Block<'bcx, 'tcx>,
+                               ty: Ty<'tcx>,
+                               method_id: DefId,
+                               trait_id: DefId,
+                               substs: &'tcx Substs<'tcx>)
+                               -> OperandRef<'tcx> {
+        let ccx = bcx.ccx();
+        let tcx = bcx.tcx();
+        let mname = tcx.item_name(method_id);
+        let subst::SeparateVecsPerParamSpace {
+            types: rcvr_type,
+            selfs: rcvr_self,
+            fns: rcvr_method
+        } = substs.clone().types.split();
+        let trait_substs = Substs::erased(
+            subst::VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())
+        );
+        let trait_substs = tcx.mk_substs(trait_substs);
+        let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
+        let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+        match vtbl {
+            traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
+                assert!(!imp_substs.types.needs_infer());
+                let subst::SeparateVecsPerParamSpace {
+                    types: impl_type,
+                    selfs: impl_self,
+                    fns: _
+                } = imp_substs.types.split();
+                let callee_substs = Substs::erased(
+                    subst::VecPerParamSpace::new(impl_type, impl_self, rcvr_method)
+                );
+                let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
+                let mthsubsts = tcx.mk_substs(mth.substs);
+                self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
+            },
+            traits::VtableObject(ref data) => {
+                let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
+                OperandRef::from_rvalue_datum(
+                    meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
+                )
+            }
+            _ => {
+                tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
+            }
+        }
+   }
+}
+
+fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
+    let node_id = match tcx.map.as_local_node_id(def_id) {
+        Some(n) => n,
+        None => { return false; }
+    };
+    match tcx.map.find(node_id).expect("local item should be in ast map") {
+        map::NodeVariant(v) => {
+            v.node.data.is_tuple()
+        }
+        map::NodeStructCtor(_) => true,
+        _ => false
+    }
+}
diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs
index 27c9feaad35..0ed76ebeb43 100644
--- a/src/librustc_trans/trans/mir/mod.rs
+++ b/src/librustc_trans/trans/mir/mod.rs
@@ -192,3 +192,4 @@ mod lvalue;
 mod rvalue;
 mod operand;
 mod statement;
+mod did;
diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs
index 106c1d05ab7..3a3087b4788 100644
--- a/src/librustc_trans/trans/mir/operand.rs
+++ b/src/librustc_trans/trans/mir/operand.rs
@@ -76,6 +76,16 @@ impl<'tcx> OperandRef<'tcx> {
             }
         }
     }
+
+    pub fn from_rvalue_datum(datum: datum::Datum<'tcx, datum::Rvalue>) -> OperandRef {
+        OperandRef {
+            ty: datum.ty,
+            val: match datum.kind.mode {
+                datum::RvalueMode::ByRef => OperandValue::Ref(datum.val),
+                datum::RvalueMode::ByValue => OperandValue::Immediate(datum.val),
+            }
+        }
+    }
 }
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
diff --git a/src/test/auxiliary/mir_external_refs.rs b/src/test/auxiliary/mir_external_refs.rs
new file mode 100644
index 00000000000..4cad98004d7
--- /dev/null
+++ b/src/test/auxiliary/mir_external_refs.rs
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+
+pub struct S(pub u8);
+
+impl S {
+    pub fn hey() -> u8 { 24 }
+}
+
+pub trait X {
+    fn hoy(&self) -> u8 { 25 }
+}
+
+impl X for S {}
+
+pub enum E {
+    U(u8)
+}
+
+pub fn regular_fn() -> u8 { 12 }
diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs
new file mode 100644
index 00000000000..2da1a758709
--- /dev/null
+++ b/src/test/run-pass/mir_refs_correct.rs
@@ -0,0 +1,218 @@
+// Copyright 2015 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(rustc_attrs)]
+// aux-build:mir_external_refs.rs
+
+
+extern crate mir_external_refs as ext;
+
+struct S(u8);
+
+impl S {
+    fn hey() -> u8 { 42 }
+    fn hey2(&self) -> u8 { 44 }
+}
+
+trait X {
+    fn hoy(&self) -> u8 { 43 }
+    fn hoy2() -> u8 { 45 }
+}
+
+trait F<U> {
+    fn f(self, other: U) -> u64;
+}
+
+impl F<u32> for u32 {
+    fn f(self, other: u32) -> u64 { self as u64 + other as u64 }
+}
+
+impl F<u64> for u32 {
+    fn f(self, other: u64) -> u64 { self as u64 - other }
+}
+
+impl F<u64> for u64 {
+    fn f(self, other: u64) -> u64 { self * other }
+}
+
+impl F<u32> for u64 {
+    fn f(self, other: u32) -> u64 { self ^ other as u64 }
+}
+
+trait T<I, O> {
+    fn staticmeth(i: I, o: O) -> (I, O) { (i, o) }
+}
+
+impl<I, O> T<I, O> for O {}
+
+impl X for S {}
+
+enum E {
+    U(u8)
+}
+
+const C: u8 = 84;
+const C2: [u8; 5] = [42; 5];
+const C3: [u8; 3] = [42, 41, 40];
+
+fn regular() -> u8 {
+    21
+}
+
+fn parametric<T>(u: T) -> T {
+    u
+}
+
+#[rustc_mir]
+fn t1() -> fn()->u8 {
+    regular
+}
+
+#[rustc_mir]
+fn t2() -> fn(u8)->E {
+    E::U
+}
+
+#[rustc_mir]
+fn t3() -> fn(u8)->S {
+    S
+}
+
+#[rustc_mir]
+fn t4() -> fn()->u8 {
+    S::hey
+}
+
+#[rustc_mir]
+fn t5() -> fn(&S)-> u8 {
+    <S as X>::hoy
+}
+
+
+#[rustc_mir]
+fn t6() -> fn()->u8{
+    ext::regular_fn
+}
+
+#[rustc_mir]
+fn t7() -> fn(u8)->ext::E {
+    ext::E::U
+}
+
+#[rustc_mir]
+fn t8() -> fn(u8)->ext::S {
+    ext::S
+}
+
+#[rustc_mir]
+fn t9() -> fn()->u8 {
+    ext::S::hey
+}
+
+#[rustc_mir]
+fn t10() -> fn(&ext::S)->u8 {
+    <ext::S as ext::X>::hoy
+}
+
+#[rustc_mir]
+fn t11() -> fn(u8)->u8 {
+    parametric
+}
+
+#[rustc_mir]
+fn t12() -> u8 {
+    C
+}
+
+#[rustc_mir]
+fn t13() -> [u8; 5] {
+    C2
+}
+
+#[rustc_mir]
+fn t13_2() -> [u8; 3] {
+    C3
+}
+
+#[rustc_mir]
+fn t14() -> fn()-> u8 {
+    <S as X>::hoy2
+}
+
+#[rustc_mir]
+fn t15() -> fn(&S)-> u8 {
+    S::hey2
+}
+
+#[rustc_mir]
+fn t16() -> fn(u32, u32)->u64 {
+    F::f
+}
+
+#[rustc_mir]
+fn t17() -> fn(u32, u64)->u64 {
+    F::f
+}
+
+#[rustc_mir]
+fn t18() -> fn(u64, u64)->u64 {
+    F::f
+}
+
+#[rustc_mir]
+fn t19() -> fn(u64, u32)->u64 {
+    F::f
+}
+
+#[rustc_mir]
+fn t20() -> fn(u64, u32)->(u64, u32) {
+    <u32 as T<_, _>>::staticmeth
+}
+
+fn main(){
+    unsafe {
+        assert_eq!(t1()(), regular());
+
+        assert!(::std::mem::transmute::<_, *mut ()>(t2()) ==
+                ::std::mem::transmute::<_, *mut ()>(E::U));
+        assert!(::std::mem::transmute::<_, *mut ()>(t3()) ==
+                ::std::mem::transmute::<_, *mut ()>(S));
+
+        assert_eq!(t4()(), S::hey());
+        let s = S(42);
+        assert_eq!(t5()(&s), <S as X>::hoy(&s));
+
+
+        assert_eq!(t6()(), ext::regular_fn());
+        assert!(::std::mem::transmute::<_, *mut ()>(t7()) ==
+                ::std::mem::transmute::<_, *mut ()>(ext::E::U));
+        assert!(::std::mem::transmute::<_, *mut ()>(t8()) ==
+                ::std::mem::transmute::<_, *mut ()>(ext::S));
+
+        assert_eq!(t9()(), ext::S::hey());
+        let sext = ext::S(6);
+        assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext));
+
+        let p = parametric::<u8>;
+        assert!(::std::mem::transmute::<_, *mut ()>(t11()) ==
+                ::std::mem::transmute::<_, *mut ()>(p));
+
+        assert_eq!(t12(), C);
+        assert_eq!(t13(), C2);
+        assert_eq!(t13_2(), C3);
+
+        assert_eq!(t14()(), <S as X>::hoy2());
+        assert_eq!(t15()(&s), S::hey2(&s));
+        assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32));
+        assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64));
+        assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
+        assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
+        assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
+    }
+}