about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-12-06 07:35:21 +0000
committerbors <bors@rust-lang.org>2016-12-06 07:35:21 +0000
commitff261d3a6b5964e1e3744d055238de624afc5d76 (patch)
tree9560fef7b90152ce605f9c215e53ef94b9088b43
parentf7c93c07b8533e1d38395cc2d9d37cd2d9bec978 (diff)
parent296ec5f9b7bf5aec05ed6672d3499079d35e4594 (diff)
downloadrust-ff261d3a6b5964e1e3744d055238de624afc5d76.tar.gz
rust-ff261d3a6b5964e1e3744d055238de624afc5d76.zip
Auto merge of #38097 - Mark-Simulacrum:fn-sig-slice, r=eddyb
Refactor ty::FnSig to contain a &'tcx Slice<Ty<'tcx>>

We refactor this in order to achieve the following wins:

 - Decrease the size of `FnSig` (`Vec` + `bool`: 32, `&Slice` + `bool`: 24).
 - Potentially decrease total allocated memory due to arena-allocating `FnSig` inputs/output; since they are allocated in the type list arena, other users of type lists can reuse the same allocation for an equivalent type list.
 - Remove the last part of the type system which needs drop glue (#37965 removed the other remaining part). This makes arenas containing `FnSig` faster to drop (since we don't need to drop a Vec for each one), and makes reusing them without clearing/dropping potentially possible.

r? @eddyb
-rw-r--r--src/librustc/middle/intrinsicck.rs4
-rw-r--r--src/librustc/traits/object_safety.rs4
-rw-r--r--src/librustc/traits/select.rs14
-rw-r--r--src/librustc/traits/util.rs7
-rw-r--r--src/librustc/ty/context.rs11
-rw-r--r--src/librustc/ty/fast_reject.rs2
-rw-r--r--src/librustc/ty/flags.rs4
-rw-r--r--src/librustc/ty/relate.rs42
-rw-r--r--src/librustc/ty/structural_impls.rs24
-rw-r--r--src/librustc/ty/sty.rs23
-rw-r--r--src/librustc/ty/util.rs2
-rw-r--r--src/librustc/ty/walk.rs4
-rw-r--r--src/librustc/util/ppaux.rs4
-rw-r--r--src/librustc_driver/test.rs7
-rw-r--r--src/librustc_lint/builtin.rs4
-rw-r--r--src/librustc_lint/types.rs12
-rw-r--r--src/librustc_mir/build/expr/into.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs4
-rw-r--r--src/librustc_mir/mir_map.rs4
-rw-r--r--src/librustc_mir/transform/type_check.rs16
-rw-r--r--src/librustc_trans/abi.rs10
-rw-r--r--src/librustc_trans/base.rs6
-rw-r--r--src/librustc_trans/callee.rs26
-rw-r--r--src/librustc_trans/common.rs19
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs8
-rw-r--r--src/librustc_trans/debuginfo/mod.rs14
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs10
-rw-r--r--src/librustc_trans/declare.rs2
-rw-r--r--src/librustc_trans/intrinsic.rs21
-rw-r--r--src/librustc_trans/mir/block.rs8
-rw-r--r--src/librustc_trans/trans_item.rs24
-rw-r--r--src/librustc_typeck/astconv.rs31
-rw-r--r--src/librustc_typeck/check/callee.rs34
-rw-r--r--src/librustc_typeck/check/closure.rs19
-rw-r--r--src/librustc_typeck/check/compare_method.rs13
-rw-r--r--src/librustc_typeck/check/intrinsic.rs23
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs20
-rw-r--r--src/librustc_typeck/check/regionck.rs11
-rw-r--r--src/librustc_typeck/check/wfcheck.rs12
-rw-r--r--src/librustc_typeck/collect.rs19
-rw-r--r--src/librustc_typeck/lib.rs19
-rw-r--r--src/librustc_typeck/variance/constraints.rs4
-rw-r--r--src/librustdoc/clean/mod.rs6
44 files changed, 264 insertions, 291 deletions
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 6896c69d7db..2357549c82e 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -178,8 +178,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
                 let typ = self.infcx.tcx.tables().node_id_to_type(expr.id);
                 match typ.sty {
                     ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
-                        let from = bare_fn_ty.sig.0.inputs[0];
-                        let to = bare_fn_ty.sig.0.output;
+                        let from = bare_fn_ty.sig.skip_binder().inputs()[0];
+                        let to = bare_fn_ty.sig.skip_binder().output();
                         self.check_transmute(expr.span, from, to, expr.id);
                     }
                     _ => {
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index ceee6c236e4..0d5c9b98941 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -241,12 +241,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // The `Self` type is erased, so it should not appear in list of
         // arguments or return type apart from the receiver.
         let ref sig = self.item_type(method.def_id).fn_sig();
-        for &input_ty in &sig.0.inputs[1..] {
+        for input_ty in &sig.skip_binder().inputs()[1..] {
             if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
                 return Some(MethodViolationCode::ReferencesSelf);
             }
         }
-        if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) {
+        if self.contains_illegal_self_type_reference(trait_def_id, sig.output().skip_binder()) {
             return Some(MethodViolationCode::ReferencesSelf);
         }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c54c0bf74ef..23cfc251759 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1368,21 +1368,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::TyFnDef(.., &ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                sig: ty::Binder(ty::FnSig {
-                    inputs: _,
-                    output: _,
-                    variadic: false
-                })
+                ref sig,
             }) |
             ty::TyFnPtr(&ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                sig: ty::Binder(ty::FnSig {
-                    inputs: _,
-                    output: _,
-                    variadic: false
-                })
-            }) => {
+                ref sig
+            }) if !sig.variadic() => {
                 candidates.vec.push(FnPointerCandidate);
             }
 
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 321936fe54b..cebd8bf87d7 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -487,14 +487,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
     {
         let arguments_tuple = match tuple_arguments {
-            TupleArgumentsFlag::No => sig.0.inputs[0],
-            TupleArgumentsFlag::Yes => self.intern_tup(&sig.0.inputs[..]),
+            TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
+            TupleArgumentsFlag::Yes =>
+                self.intern_tup(sig.skip_binder().inputs()),
         };
         let trait_ref = ty::TraitRef {
             def_id: fn_trait_def_id,
             substs: self.mk_substs_trait(self_ty, &[arguments_tuple]),
         };
-        ty::Binder((trait_ref, sig.0.output))
+        ty::Binder((trait_ref, sig.skip_binder().output()))
     }
 }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 17c335fc9c7..4854a14f733 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1542,6 +1542,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn mk_fn_sig<I>(self, inputs: I, output: I::Item, variadic: bool)
+        -> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
+        where I: Iterator,
+              I::Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>
+    {
+        inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
+            inputs_and_output: self.intern_type_list(xs),
+            variadic: variadic
+        })
+    }
+
     pub fn mk_existential_predicates<I: InternAs<[ExistentialPredicate<'tcx>],
                                      &'tcx Slice<ExistentialPredicate<'tcx>>>>(self, iter: I)
                                      -> I::Output {
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index ade6cad6866..7b4d76ad497 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -81,7 +81,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             Some(TupleSimplifiedType(tys.len()))
         }
         ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
-            Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
+            Some(FunctionSimplifiedType(f.sig.skip_binder().inputs().len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
             if can_simplify_params {
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 2bcbccb7d05..a06d3ed6cf4 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -180,8 +180,8 @@ impl FlagComputation {
     fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
         let mut computation = FlagComputation::new();
 
-        computation.add_tys(&fn_sig.0.inputs);
-        computation.add_ty(fn_sig.0.output);
+        computation.add_tys(fn_sig.skip_binder().inputs());
+        computation.add_ty(fn_sig.skip_binder().output());
 
         self.add_bound_computation(&computation);
     }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 8cb1483107f..76c26d01ac8 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -18,8 +18,10 @@ use ty::subst::{Kind, Substs};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
 use ty::error::{ExpectedFound, TypeError};
 use std::rc::Rc;
+use std::iter;
 use syntax::abi;
 use hir as ast;
+use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
 
@@ -185,32 +187,28 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
                 expected_found(relation, &a.variadic, &b.variadic)));
         }
 
-        let inputs = relate_arg_vecs(relation,
-                                     &a.inputs,
-                                     &b.inputs)?;
-        let output = relation.relate(&a.output, &b.output)?;
+        if a.inputs().len() != b.inputs().len() {
+            return Err(TypeError::ArgCount);
+        }
 
-        Ok(ty::FnSig {inputs: inputs,
-                      output: output,
-                      variadic: a.variadic})
+        let inputs_and_output = a.inputs().iter().cloned()
+            .zip(b.inputs().iter().cloned())
+            .map(|x| (x, false))
+            .chain(iter::once(((a.output(), b.output()), true)))
+            .map(|((a, b), is_output)| {
+                if is_output {
+                    relation.relate(&a, &b)
+                } else {
+                    relation.relate_with_variance(ty::Contravariant, &a, &b)
+                }
+            }).collect::<Result<AccumulateVec<[_; 8]>, _>>()?;
+        Ok(ty::FnSig {
+            inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output),
+            variadic: a.variadic
+        })
     }
 }
 
-fn relate_arg_vecs<'a, 'gcx, 'tcx, R>(relation: &mut R,
-                                      a_args: &[Ty<'tcx>],
-                                      b_args: &[Ty<'tcx>])
-                                      -> RelateResult<'tcx, Vec<Ty<'tcx>>>
-    where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
-{
-    if a_args.len() != b_args.len() {
-        return Err(TypeError::ArgCount);
-    }
-
-    a_args.iter().zip(b_args)
-          .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b))
-          .collect()
-}
-
 impl<'tcx> Relate<'tcx> for ast::Unsafety {
     fn relate<'a, 'gcx, R>(relation: &mut R,
                            a: &ast::Unsafety,
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 88de3575274..0f0478bc8cd 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -232,14 +232,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> {
 impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
     type Lifted = ty::FnSig<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
-        tcx.lift(&self.inputs[..]).and_then(|inputs| {
-            tcx.lift(&self.output).map(|output| {
-                ty::FnSig {
-                    inputs: inputs,
-                    output: output,
-                    variadic: self.variadic
-                }
-            })
+        tcx.lift(&self.inputs_and_output).map(|x| {
+            ty::FnSig {
+                inputs_and_output: x,
+                variadic: self.variadic
+            }
         })
     }
 }
@@ -589,9 +586,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::FnSig { inputs: self.inputs.fold_with(folder),
-                    output: self.output.fold_with(folder),
-                    variadic: self.variadic }
+        let inputs_and_output = self.inputs_and_output.fold_with(folder);
+        ty::FnSig {
+            inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
+            variadic: self.variadic,
+        }
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@@ -599,7 +598,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.inputs.visit_with(visitor) || self.output.visit_with(visitor)
+        self.inputs().iter().any(|i| i.visit_with(visitor)) ||
+        self.output().visit_with(visitor)
     }
 }
 
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 59f774b954c..3b7c46ef7fe 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -563,22 +563,31 @@ pub struct ClosureTy<'tcx> {
 /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
 #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
 pub struct FnSig<'tcx> {
-    pub inputs: Vec<Ty<'tcx>>,
-    pub output: Ty<'tcx>,
+    pub inputs_and_output: &'tcx Slice<Ty<'tcx>>,
     pub variadic: bool
 }
 
+impl<'tcx> FnSig<'tcx> {
+    pub fn inputs(&self) -> &[Ty<'tcx>] {
+        &self.inputs_and_output[..self.inputs_and_output.len() - 1]
+    }
+
+    pub fn output(&self) -> Ty<'tcx> {
+        self.inputs_and_output[self.inputs_and_output.len() - 1]
+    }
+}
+
 pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
 
 impl<'tcx> PolyFnSig<'tcx> {
-    pub fn inputs(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs.clone())
+    pub fn inputs(&self) -> Binder<&[Ty<'tcx>]> {
+        Binder(self.skip_binder().inputs())
     }
     pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
+        self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
     }
     pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.output.clone())
+        self.map_bound_ref(|fn_sig| fn_sig.output().clone())
     }
     pub fn variadic(&self) -> bool {
         self.skip_binder().variadic
@@ -1243,7 +1252,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     }
 
     // Type accessors for substructures of types
-    pub fn fn_args(&self) -> ty::Binder<Vec<Ty<'tcx>>> {
+    pub fn fn_args(&self) -> ty::Binder<&[Ty<'tcx>]> {
         self.fn_sig().inputs()
     }
 
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 6bb9d67db6f..e6db35cc3f5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -530,7 +530,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
                 self.hash(f.unsafety);
                 self.hash(f.abi);
                 self.hash(f.sig.variadic());
-                self.hash(f.sig.inputs().skip_binder().len());
+                self.hash(f.sig.skip_binder().inputs().len());
             }
             TyDynamic(ref data, ..) => {
                 if let Some(p) = data.principal() {
diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs
index 0848dcd2c8d..3fa7a803141 100644
--- a/src/librustc/ty/walk.rs
+++ b/src/librustc/ty/walk.rs
@@ -126,6 +126,6 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
 }
 
 fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
-    stack.push(sig.0.output);
-    stack.extend(sig.0.inputs.iter().cloned().rev());
+    stack.push(sig.skip_binder().output());
+    stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
 }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index b4c87e0ce42..38b38e5b497 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -595,7 +595,7 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
 impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "fn")?;
-        fn_sig(f, &self.inputs, self.variadic, self.output)
+        fn_sig(f, self.inputs(), self.variadic, self.output())
     }
 }
 
@@ -625,7 +625,7 @@ impl fmt::Debug for ty::RegionVid {
 
 impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "({:?}; variadic: {})->{:?}", self.inputs, self.variadic, self.output)
+        write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output())
     }
 }
 
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 464e15faeaf..b7cebe31073 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -265,15 +265,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
-        let input_args = input_tys.iter().cloned().collect();
         self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: hir::Unsafety::Normal,
             abi: Abi::Rust,
-            sig: ty::Binder(ty::FnSig {
-                inputs: input_args,
-                output: output_ty,
-                variadic: false,
-            }),
+            sig: ty::Binder(self.infcx.tcx.mk_fn_sig(input_tys.iter().cloned(), output_ty, false)),
         }))
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index f14fa7d4fdc..ee6af643154 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1084,8 +1084,8 @@ impl LateLintPass for MutableTransmutes {
                 let typ = cx.tcx.tables().node_id_to_type(expr.id);
                 match typ.sty {
                     ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
-                        let from = bare_fn.sig.0.inputs[0];
-                        let to = bare_fn.sig.0.output;
+                        let from = bare_fn.sig.skip_binder().inputs()[0];
+                        let to = bare_fn.sig.skip_binder().output();
                         return Some((&from.sty, &to.sty));
                     }
                     _ => (),
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index bba31c8237d..6475166192a 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -603,8 +603,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
 
                 let sig = cx.erase_late_bound_regions(&bare_fn.sig);
-                if !sig.output.is_nil() {
-                    let r = self.check_type_for_ffi(cache, sig.output);
+                if !sig.output().is_nil() {
+                    let r = self.check_type_for_ffi(cache, sig.output());
                     match r {
                         FfiSafe => {}
                         _ => {
@@ -612,7 +612,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         }
                     }
                 }
-                for arg in sig.inputs {
+                for arg in sig.inputs() {
                     let r = self.check_type_for_ffi(cache, arg);
                     match r {
                         FfiSafe => {}
@@ -678,12 +678,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         let sig = self.cx.tcx.item_type(def_id).fn_sig();
         let sig = self.cx.tcx.erase_late_bound_regions(&sig);
 
-        for (&input_ty, input_hir) in sig.inputs.iter().zip(&decl.inputs) {
-            self.check_type_for_ffi_and_report_errors(input_hir.ty.span, &input_ty);
+        for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
+            self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
         }
 
         if let hir::Return(ref ret_hir) = decl.output {
-            let ret_ty = sig.output;
+            let ret_ty = sig.output();
             if !ret_ty.is_nil() {
                 self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
             }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 5a77de08070..ffd9525933b 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -208,7 +208,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let diverges = match ty.sty {
                     ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
                         // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                        f.sig.0.output.is_never()
+                        f.sig.skip_binder().output().is_never()
                     }
                     _ => false
                 };
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index e850f6c4b04..bd4724159b4 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -247,10 +247,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                     span_bug!(expr.span, "method call has late-bound regions")
                 });
 
-                assert_eq!(sig.inputs.len(), 2);
+                assert_eq!(sig.inputs().len(), 2);
 
                 let tupled_args = Expr {
-                    ty: sig.inputs[1],
+                    ty: sig.inputs()[1],
                     temp_lifetime: temp_lifetime,
                     span: expr.span,
                     kind: ExprKind::Tuple {
diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs
index 88d02d7d004..e2a516edbc8 100644
--- a/src/librustc_mir/mir_map.rs
+++ b/src/librustc_mir/mir_map.rs
@@ -238,14 +238,14 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
                 .iter()
                 .enumerate()
                 .map(|(index, arg)| {
-                    (fn_sig.inputs[index], Some(&*arg.pat))
+                    (fn_sig.inputs()[index], Some(&*arg.pat))
                 });
 
         let body = self.tcx.map.expr(body_id);
 
         let arguments = implicit_argument.into_iter().chain(explicit_arguments);
         self.cx(MirSource::Fn(id)).build(|cx| {
-            build::construct_fn(cx, id, arguments, abi, fn_sig.output, body)
+            build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
         });
 
         intravisit::walk_fn(self, fk, decl, body_id, span, id);
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 0ceed274b6d..4c86331a525 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -506,15 +506,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
         match *destination {
             Some((ref dest, _)) => {
                 let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                if let Err(terr) = self.sub_types(sig.output, dest_ty) {
+                if let Err(terr) = self.sub_types(sig.output(), dest_ty) {
                     span_mirbug!(self, term,
                                  "call dest mismatch ({:?} <- {:?}): {:?}",
-                                 dest_ty, sig.output, terr);
+                                 dest_ty, sig.output(), terr);
                 }
             },
             None => {
                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
-                if !sig.output.is_never() {
+                if !sig.output().is_never() {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             },
@@ -528,11 +528,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                          args: &[Operand<'tcx>])
     {
         debug!("check_call_inputs({:?}, {:?})", sig, args);
-        if args.len() < sig.inputs.len() ||
-           (args.len() > sig.inputs.len() && !sig.variadic) {
+        if args.len() < sig.inputs().len() ||
+           (args.len() > sig.inputs().len() && !sig.variadic) {
             span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
         }
-        for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
+        for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() {
             let op_arg_ty = op_arg.ty(mir, self.tcx());
             if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
                 span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
@@ -562,12 +562,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
 
         // box_free takes a Box as a pointer. Allow for that.
 
-        if sig.inputs.len() != 1 {
+        if sig.inputs().len() != 1 {
             span_mirbug!(self, term, "box_free should take 1 argument");
             return;
         }
 
-        let pointee_ty = match sig.inputs[0].sty {
+        let pointee_ty = match sig.inputs()[0].sty {
             ty::TyRawPtr(mt) => mt.ty,
             _ => {
                 span_mirbug!(self, term, "box_free should take a raw ptr");
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 07f53466b49..0ac853e99ee 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -367,13 +367,13 @@ impl FnType {
             Cdecl => llvm::CCallConv,
         };
 
-        let mut inputs = &sig.inputs[..];
+        let mut inputs = sig.inputs();
         let extra_args = if abi == RustCall {
             assert!(!sig.variadic && extra_args.is_empty());
 
-            match inputs[inputs.len() - 1].sty {
+            match sig.inputs().last().unwrap().sty {
                 ty::TyTuple(ref tupled_arguments) => {
-                    inputs = &inputs[..inputs.len() - 1];
+                    inputs = &sig.inputs()[0..sig.inputs().len() - 1];
                     &tupled_arguments[..]
                 }
                 _ => {
@@ -428,7 +428,7 @@ impl FnType {
             }
         };
 
-        let ret_ty = sig.output;
+        let ret_ty = sig.output();
         let mut ret = arg_of(ret_ty, true);
 
         if !type_is_fat_ptr(ccx.tcx(), ret_ty) {
@@ -569,7 +569,7 @@ impl FnType {
             };
             // Fat pointers are returned by-value.
             if !self.ret.is_ignore() {
-                if !type_is_fat_ptr(ccx.tcx(), sig.output) {
+                if !type_is_fat_ptr(ccx.tcx(), sig.output()) {
                     fixup(&mut self.ret);
                 }
             }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index a31b61e42c4..867e4dce19a 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1077,8 +1077,8 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
         let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
         let mut arg_idx = 0;
-        for (i, arg_ty) in sig.inputs.into_iter().enumerate() {
-            let lldestptr = adt::trans_field_ptr(bcx, sig.output, dest_val, Disr::from(disr), i);
+        for (i, arg_ty) in sig.inputs().iter().enumerate() {
+            let lldestptr = adt::trans_field_ptr(bcx, sig.output(), dest_val, Disr::from(disr), i);
             let arg = &fcx.fn_ty.args[arg_idx];
             arg_idx += 1;
             let b = &bcx.build();
@@ -1091,7 +1091,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 arg.store_fn_arg(b, &mut llarg_idx, lldestptr);
             }
         }
-        adt::trans_set_discr(bcx, sig.output, dest, disr);
+        adt::trans_set_discr(bcx, sig.output(), dest, disr);
     }
 
     fcx.finish(bcx, DebugLoc::None);
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index df56e27128c..7fb57dc19fc 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -38,6 +38,7 @@ use type_of;
 use Disr;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::hir;
+use std::iter;
 
 use syntax_pos::DUMMY_SP;
 
@@ -329,7 +330,11 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 
     // Make a version with the type of by-ref closure.
     let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
-    sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
+    sig.0 = tcx.mk_fn_sig(
+        iter::once(ref_closure_ty).chain(sig.0.inputs().iter().cloned()),
+        sig.0.output(),
+        sig.0.variadic
+    );
     let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: unsafety,
         abi: abi,
@@ -342,7 +347,11 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     // Make a version of the closure type with the same arguments, but
     // with argument #0 being by value.
     assert_eq!(abi, Abi::RustCall);
-    sig.0.inputs[0] = closure_ty;
+    sig.0 = tcx.mk_fn_sig(
+        iter::once(closure_ty).chain(sig.0.inputs().iter().skip(1).cloned()),
+        sig.0.output(),
+        sig.0.variadic
+    );
 
     let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
@@ -491,13 +500,12 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
         }
     };
     let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-    let tuple_input_ty = tcx.intern_tup(&sig.inputs[..]);
-    let sig = ty::FnSig {
-        inputs: vec![bare_fn_ty_maybe_ref,
-                     tuple_input_ty],
-        output: sig.output,
-        variadic: false
-    };
+    let tuple_input_ty = tcx.intern_tup(sig.inputs());
+    let sig = tcx.mk_fn_sig(
+        [bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
+        sig.output(),
+        false
+    );
     let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
     let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 29925d964da..b1d61cea39c 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -418,11 +418,11 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
         let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: hir::Unsafety::Unsafe,
             abi: Abi::C,
-            sig: ty::Binder(ty::FnSig {
-                inputs: vec![tcx.mk_mut_ptr(tcx.types.u8)],
-                output: tcx.types.never,
-                variadic: false
-            }),
+            sig: ty::Binder(tcx.mk_fn_sig(
+                iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
+                tcx.types.never,
+                false
+            )),
         }));
 
         let unwresume = ccx.eh_unwind_resume();
@@ -1091,10 +1091,11 @@ pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 ty::ClosureKind::FnOnce => ty,
             };
 
-            let sig = sig.map_bound(|sig| ty::FnSig {
-                inputs: iter::once(env_ty).chain(sig.inputs).collect(),
-                ..sig
-            });
+            let sig = sig.map_bound(|sig| tcx.mk_fn_sig(
+                iter::once(env_ty).chain(sig.inputs().iter().cloned()),
+                sig.output(),
+                sig.variadic
+            ));
             Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
         }
         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index ca76211dc4c..cda9fa46f17 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -390,16 +390,16 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 {
     let signature = cx.tcx().erase_late_bound_regions(signature);
 
-    let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
+    let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
 
     // return type
-    signature_metadata.push(match signature.output.sty {
+    signature_metadata.push(match signature.output().sty {
         ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
-        _ => type_metadata(cx, signature.output, span)
+        _ => type_metadata(cx, signature.output(), span)
     });
 
     // regular arguments
-    for &argument_type in &signature.inputs {
+    for &argument_type in signature.inputs() {
         signature_metadata.push(type_metadata(cx, argument_type, span));
     }
 
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index e023e654d51..aab70ab252a 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -308,18 +308,18 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             return create_DIArray(DIB(cx), &[]);
         }
 
-        let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
+        let mut signature = Vec::with_capacity(sig.inputs().len() + 1);
 
         // Return type -- llvm::DIBuilder wants this at index 0
-        signature.push(match sig.output.sty {
+        signature.push(match sig.output().sty {
             ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
-            _ => type_metadata(cx, sig.output, syntax_pos::DUMMY_SP)
+            _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
         });
 
         let inputs = if abi == Abi::RustCall {
-            &sig.inputs[..sig.inputs.len()-1]
+            &sig.inputs()[..sig.inputs().len() - 1]
         } else {
-            &sig.inputs[..]
+            sig.inputs()
         };
 
         // Arguments types
@@ -327,8 +327,8 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
         }
 
-        if abi == Abi::RustCall && !sig.inputs.is_empty() {
-            if let ty::TyTuple(args) = sig.inputs[sig.inputs.len() - 1].sty {
+        if abi == Abi::RustCall && !sig.inputs().is_empty() {
+            if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
                 for &argument_type in args {
                     signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
                 }
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 80e6bd7aa29..788ce32937d 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -116,8 +116,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             output.push_str("fn(");
 
             let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
-            if !sig.inputs.is_empty() {
-                for &parameter_type in &sig.inputs {
+            if !sig.inputs().is_empty() {
+                for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(cx, parameter_type, true, output);
                     output.push_str(", ");
                 }
@@ -126,7 +126,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
 
             if sig.variadic {
-                if !sig.inputs.is_empty() {
+                if !sig.inputs().is_empty() {
                     output.push_str(", ...");
                 } else {
                     output.push_str("...");
@@ -135,9 +135,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push(')');
 
-            if !sig.output.is_nil() {
+            if !sig.output().is_nil() {
                 output.push_str(" -> ");
-                push_debuginfo_type_name(cx, sig.output, true, output);
+                push_debuginfo_type_name(cx, sig.output(), true, output);
             }
         },
         ty::TyClosure(..) => {
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index eef3b9b1147..9bf023fc189 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -124,7 +124,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
     let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
 
     // FIXME(canndrew): This is_never should really be an is_uninhabited
-    if sig.output.is_never() {
+    if sig.output().is_never() {
         llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
     }
 
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 016a76a7253..577ffbad134 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -36,6 +36,7 @@ use rustc::session::Session;
 use syntax_pos::{Span, DUMMY_SP};
 
 use std::cmp::Ordering;
+use std::iter;
 
 fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
     let llvm_name = match name {
@@ -105,8 +106,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
     };
 
     let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
-    let arg_tys = sig.inputs;
-    let ret_ty = sig.output;
+    let arg_tys = sig.inputs();
+    let ret_ty = sig.output();
     let name = &*tcx.item_name(def_id).as_str();
 
     let span = match call_debug_location {
@@ -674,7 +675,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 // again to find them and extract the arguments
                 intr.inputs.iter()
                            .zip(llargs)
-                           .zip(&arg_tys)
+                           .zip(arg_tys)
                            .flat_map(|((t, llarg), ty)| modify_as_needed(bcx, t, ty, *llarg))
                            .collect()
             };
@@ -1012,11 +1013,7 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
                     trans: &mut for<'b> FnMut(Block<'b, 'tcx>))
                     -> ValueRef {
     let ccx = fcx.ccx;
-    let sig = ty::FnSig {
-        inputs: inputs,
-        output: output,
-        variadic: false,
-    };
+    let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
     let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
@@ -1051,11 +1048,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
     let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: Abi::Rust,
-        sig: ty::Binder(ty::FnSig {
-            inputs: vec![i8p],
-            output: tcx.mk_nil(),
-            variadic: false,
-        }),
+        sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)),
     }));
     let output = tcx.types.i32;
     let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
@@ -1108,7 +1101,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
 
     let tcx = bcx.tcx();
     let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
-    let arg_tys = sig.inputs;
+    let arg_tys = sig.inputs();
 
     // every intrinsic takes a SIMD vector as its first argument
     require_simd!(arg_tys[0], "input");
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 29e6f6af416..76f5f32b5dc 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -453,7 +453,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     return;
                 }
 
-                let extra_args = &args[sig.inputs.len()..];
+                let extra_args = &args[sig.inputs().len()..];
                 let extra_args = extra_args.iter().map(|op_arg| {
                     let op_ty = op_arg.ty(&self.mir, bcx.tcx());
                     bcx.monomorphize(&op_ty)
@@ -546,7 +546,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             // Make a fake operand for store_return
                             let op = OperandRef {
                                 val: Ref(dst),
-                                ty: sig.output,
+                                ty: sig.output(),
                             };
                             self.store_return(&bcx, ret_dest, fn_ty.ret, op);
                         }
@@ -584,7 +584,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             debug_loc.apply_to_bcx(ret_bcx);
                             let op = OperandRef {
                                 val: Immediate(invokeret),
-                                ty: sig.output,
+                                ty: sig.output(),
                             };
                             self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
                         });
@@ -595,7 +595,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     if let Some((_, target)) = *destination {
                         let op = OperandRef {
                             val: Immediate(llret),
-                            ty: sig.output,
+                            ty: sig.output(),
                         };
                         self.store_return(&bcx, ret_dest, fn_ty.ret, op);
                         funclet_br(self, bcx, target);
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 322c5eb6e18..214eaeb817f 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -187,11 +187,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
         assert_eq!(dg.ty(), glue::get_drop_glue_type(tcx, dg.ty()));
         let t = dg.ty();
 
-        let sig = ty::FnSig {
-            inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
-            output: tcx.mk_nil(),
-            variadic: false,
-        };
+        let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(tcx.types.i8)), tcx.mk_nil(), false);
 
         // Create a FnType for fn(*mut i8) and substitute the real type in
         // later - that prevents FnType from splitting fat pointers up.
@@ -480,14 +476,10 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
 
                 output.push_str("fn(");
 
-                let ty::FnSig {
-                    inputs: sig_inputs,
-                    output: sig_output,
-                    variadic: sig_variadic
-                } = self.tcx.erase_late_bound_regions_and_normalize(sig);
+                let sig = self.tcx.erase_late_bound_regions_and_normalize(sig);
 
-                if !sig_inputs.is_empty() {
-                    for &parameter_type in &sig_inputs {
+                if !sig.inputs().is_empty() {
+                    for &parameter_type in sig.inputs() {
                         self.push_type_name(parameter_type, output);
                         output.push_str(", ");
                     }
@@ -495,8 +487,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                     output.pop();
                 }
 
-                if sig_variadic {
-                    if !sig_inputs.is_empty() {
+                if sig.variadic {
+                    if !sig.inputs().is_empty() {
                         output.push_str(", ...");
                     } else {
                         output.push_str("...");
@@ -505,9 +497,9 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
 
                 output.push(')');
 
-                if !sig_output.is_nil() {
+                if !sig.output().is_nil() {
                     output.push_str(" -> ");
-                    self.push_type_name(sig_output, output);
+                    self.push_type_name(sig.output(), output);
                 }
             },
             ty::TyClosure(def_id, ref closure_substs) => {
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index b5531b8bb9e..d458c7c009e 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1595,7 +1595,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 // checking for here would be considered early bound
                 // anyway.)
                 let inputs = bare_fn_ty.sig.inputs();
-                let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs);
+                let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
+                    &inputs.map_bound(|i| i.to_owned()));
                 let output = bare_fn_ty.sig.output();
                 let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
                 for br in late_bound_in_ret.difference(&late_bound_in_args) {
@@ -1795,19 +1796,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::DefaultReturn(..) => self.tcx().mk_nil(),
         };
 
-        let input_tys = self_ty.into_iter().chain(arg_tys).collect();
-
-        debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys);
         debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty);
 
         self.tcx().mk_bare_fn(ty::BareFnTy {
             unsafety: unsafety,
             abi: abi,
-            sig: ty::Binder(ty::FnSig {
-                inputs: input_tys,
-                output: output_ty,
-                variadic: decl.variadic
-            }),
+            sig: ty::Binder(self.tcx().mk_fn_sig(
+                self_ty.into_iter().chain(arg_tys),
+                output_ty,
+                decl.variadic
+            )),
         })
     }
 
@@ -1849,20 +1847,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // that function type
         let rb = rscope::BindingRscope::new();
 
-        let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| {
+        let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| {
             let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
                 // no guarantee that the correct number of expected args
                 // were supplied
-                if i < e.inputs.len() {
-                    Some(e.inputs[i])
+                if i < e.inputs().len() {
+                    Some(e.inputs()[i])
                 } else {
                     None
                 }
             });
             self.ty_of_arg(&rb, a, expected_arg_ty)
-        }).collect();
+        });
 
-        let expected_ret_ty = expected_sig.map(|e| e.output);
+        let expected_ret_ty = expected_sig.as_ref().map(|e| e.output());
 
         let is_infer = match decl.output {
             hir::Return(ref output) if output.node == hir::TyInfer => true,
@@ -1879,15 +1877,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::DefaultReturn(..) => bug!(),
         };
 
-        debug!("ty_of_closure: input_tys={:?}", input_tys);
         debug!("ty_of_closure: output_ty={:?}", output_ty);
 
         ty::ClosureTy {
             unsafety: unsafety,
             abi: abi,
-            sig: ty::Binder(ty::FnSig {inputs: input_tys,
-                                       output: output_ty,
-                                       variadic: decl.variadic}),
+            sig: ty::Binder(self.tcx().mk_fn_sig(input_tys, output_ty, decl.variadic)),
         }
     }
 
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 5b17b37e279..4fba29def22 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -237,11 +237,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // This is the "default" function signature, used in case of error.
                 // In that case, we check each argument against "error" in order to
                 // set up all the node type bindings.
-                error_fn_sig = ty::Binder(ty::FnSig {
-                    inputs: self.err_args(arg_exprs.len()),
-                    output: self.tcx.types.err,
-                    variadic: false,
-                });
+                error_fn_sig = ty::Binder(self.tcx.mk_fn_sig(
+                    self.err_args(arg_exprs.len()).into_iter(),
+                    self.tcx.types.err,
+                    false,
+                ));
 
                 (&error_fn_sig, None)
             }
@@ -261,17 +261,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let expected_arg_tys =
             self.expected_types_for_fn_args(call_expr.span,
                                             expected,
-                                            fn_sig.output,
-                                            &fn_sig.inputs);
+                                            fn_sig.output(),
+                                            fn_sig.inputs());
         self.check_argument_types(call_expr.span,
-                                  &fn_sig.inputs,
+                                  fn_sig.inputs(),
                                   &expected_arg_tys[..],
                                   arg_exprs,
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments,
                                   def_span);
 
-        fn_sig.output
+        fn_sig.output()
     }
 
     fn confirm_deferred_closure_call(&self,
@@ -287,18 +287,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let expected_arg_tys = self.expected_types_for_fn_args(call_expr.span,
                                                                expected,
-                                                               fn_sig.output.clone(),
-                                                               &fn_sig.inputs);
+                                                               fn_sig.output().clone(),
+                                                               fn_sig.inputs());
 
         self.check_argument_types(call_expr.span,
-                                  &fn_sig.inputs,
+                                  fn_sig.inputs(),
                                   &expected_arg_tys,
                                   arg_exprs,
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments,
                                   None);
 
-        fn_sig.output
+        fn_sig.output()
     }
 
     fn confirm_overloaded_call(&self,
@@ -365,12 +365,12 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
 
                 debug!("attempt_resolution: method_callee={:?}", method_callee);
 
-                for (&method_arg_ty, &self_arg_ty) in
-                    method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs) {
-                    fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
+                for (method_arg_ty, self_arg_ty) in
+                    method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) {
+                    fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty);
                 }
 
-                fcx.demand_eqtype(self.call_expr.span, method_sig.output, self.fn_sig.output);
+                fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
 
                 fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
             }
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 486f8fc25bb..142a8b97111 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -15,6 +15,7 @@ use super::{check_fn, Expectation, FnCtxt};
 use astconv::AstConv;
 use rustc::ty::{self, ToPolyTraitRef, Ty};
 use std::cmp;
+use std::iter;
 use syntax::abi::Abi;
 use rustc::hir;
 
@@ -86,7 +87,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Tuple up the arguments and insert the resulting function type into
         // the `closures` table.
-        fn_ty.sig.0.inputs = vec![self.tcx.intern_tup(&fn_ty.sig.0.inputs[..])];
+        fn_ty.sig.0 = self.tcx.mk_fn_sig(
+            iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs())),
+            fn_ty.sig.skip_binder().output(),
+            fn_ty.sig.variadic()
+        );
 
         debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
                expr_def_id,
@@ -212,23 +217,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                arg_param_ty);
 
         let input_tys = match arg_param_ty.sty {
-            ty::TyTuple(tys) => tys.to_vec(),
+            ty::TyTuple(tys) => tys.into_iter(),
             _ => {
                 return None;
             }
         };
-        debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
 
         let ret_param_ty = projection.0.ty;
         let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
-        debug!("deduce_sig_from_projection: ret_param_ty {:?}",
-               ret_param_ty);
+        debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
 
-        let fn_sig = ty::FnSig {
-            inputs: input_tys,
-            output: ret_param_ty,
-            variadic: false,
-        };
+        let fn_sig = self.tcx.mk_fn_sig(input_tys.cloned(), ret_param_ty, false);
         debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
 
         Some(fn_sig)
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2602ff05bad..e85dac1a44c 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -495,8 +495,8 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                         _ => bug!("{:?} is not a MethodTraitItem", trait_m),
                     };
 
-                let impl_iter = impl_sig.inputs.iter();
-                let trait_iter = trait_sig.inputs.iter();
+                let impl_iter = impl_sig.inputs().iter();
+                let trait_iter = trait_sig.inputs().iter();
                 impl_iter.zip(trait_iter)
                          .zip(impl_m_iter)
                          .zip(trait_m_iter)
@@ -508,7 +508,8 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                          })
                          .next()
                          .unwrap_or_else(|| {
-                             if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output)
+                             if infcx.sub_types(false, &cause, impl_sig.output(),
+                                                trait_sig.output())
                                      .is_err() {
                                          (impl_m_output.span(), Some(trait_m_output.span()))
                                      } else {
@@ -681,9 +682,9 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     };
     let impl_m_fty = m_fty(impl_m);
     let trait_m_fty = m_fty(trait_m);
-    if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() {
-        let trait_number_args = trait_m_fty.sig.0.inputs.len();
-        let impl_number_args = impl_m_fty.sig.0.inputs.len();
+    let trait_number_args = trait_m_fty.sig.inputs().skip_binder().len();
+    let impl_number_args = impl_m_fty.sig.inputs().skip_binder().len();
+    if trait_number_args != impl_number_args {
         let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
         let trait_span = if let Some(trait_id) = trait_m_node_id {
             match tcx.map.expect_trait_item(trait_id).node {
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index a07573a7b9e..183a2a48ff5 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -14,7 +14,6 @@
 use intrinsics;
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Substs;
-use rustc::ty::FnSig;
 use rustc::ty::{self, Ty};
 use rustc::util::nodemap::FxHashMap;
 use {CrateCtxt, require_same_types};
@@ -26,6 +25,8 @@ use syntax_pos::Span;
 
 use rustc::hir;
 
+use std::iter;
+
 fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                    it: &hir::ForeignItem,
                                    n_tps: usize,
@@ -42,11 +43,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Unsafe,
         abi: abi,
-        sig: ty::Binder(FnSig {
-            inputs: inputs,
-            output: output,
-            variadic: false,
-        }),
+        sig: ty::Binder(tcx.mk_fn_sig(inputs.into_iter(), output, false)),
     }));
     let i_n_tps = tcx.item_generics(def_id).types.len();
     if i_n_tps != n_tps {
@@ -299,11 +296,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
                 let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
                     unsafety: hir::Unsafety::Normal,
                     abi: Abi::Rust,
-                    sig: ty::Binder(FnSig {
-                        inputs: vec![mut_u8],
-                        output: tcx.mk_nil(),
-                        variadic: false,
-                    }),
+                    sig: ty::Binder(tcx.mk_fn_sig(iter::once(mut_u8), tcx.mk_nil(), false)),
                 });
                 (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
             }
@@ -377,21 +370,21 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
 
                     let sig = tcx.item_type(def_id).fn_sig();
                     let sig = tcx.no_late_bound_regions(sig).unwrap();
-                    if intr.inputs.len() != sig.inputs.len() {
+                    if intr.inputs.len() != sig.inputs().len() {
                         span_err!(tcx.sess, it.span, E0444,
                                   "platform-specific intrinsic has invalid number of \
                                    arguments: found {}, expected {}",
-                                  sig.inputs.len(), intr.inputs.len());
+                                  sig.inputs().len(), intr.inputs.len());
                         return
                     }
-                    let input_pairs = intr.inputs.iter().zip(&sig.inputs);
+                    let input_pairs = intr.inputs.iter().zip(sig.inputs());
                     for (i, (expected_arg, arg)) in input_pairs.enumerate() {
                         match_intrinsic_type_to_type(ccx, &format!("argument {}", i + 1), it.span,
                                                      &mut structural_to_nomimal, expected_arg, arg);
                     }
                     match_intrinsic_type_to_type(ccx, "return value", it.span,
                                                  &mut structural_to_nomimal,
-                                                 &intr.output, sig.output);
+                                                 &intr.output, sig.output());
                     return
                 }
                 None => {
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 2e66f6290a0..b29eab780e0 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                     infer::FnCall,
                                                                     &fty.sig).0;
         let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
-        let transformed_self_ty = fn_sig.inputs[0];
+        let transformed_self_ty = fn_sig.inputs()[0];
         let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
                                       tcx.mk_bare_fn(ty::BareFnTy {
             sig: ty::Binder(fn_sig),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1950adf8329..1b35081d524 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -785,18 +785,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
 
     // Create the function context.  This is either derived from scratch or,
     // in the case of function expressions, based on the outer context.
-    let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
+    let mut fcx = FnCtxt::new(inherited, fn_sig.output(), body.id);
     *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
 
     fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType);
     fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty);
-    fn_sig.output = fcx.ret_ty;
+    fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty, fn_sig.variadic);
 
     {
         let mut visit = GatherLocalsVisitor { fcx: &fcx, };
 
         // Add formal parameters.
-        for (arg_ty, input) in fn_sig.inputs.iter().zip(&decl.inputs) {
+        for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
             // The type of the argument must be well-formed.
             //
             // NB -- this is now checked in wfcheck, but that
@@ -2473,14 +2473,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             match method_fn_ty.sty {
                 ty::TyFnDef(def_id, .., ref fty) => {
                     // HACK(eddyb) ignore self in the definition (see above).
-                    let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
-                                                                           fty.sig.0.output,
-                                                                           &fty.sig.0.inputs[1..]);
-
-                    self.check_argument_types(sp, &fty.sig.0.inputs[1..], &expected_arg_tys[..],
+                    let expected_arg_tys = self.expected_types_for_fn_args(
+                        sp,
+                        expected,
+                        fty.sig.0.output(),
+                        &fty.sig.0.inputs()[1..]
+                    );
+                    self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..],
                                               args_no_rcvr, fty.sig.0.variadic, tuple_arguments,
                                               self.tcx.map.span_if_local(def_id));
-                    fty.sig.0.output
+                    fty.sig.0.output()
                 }
                 _ => {
                     span_bug!(callee_expr.span, "method without bare fn type");
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index c0bf5773ed5..eb08e70d4c3 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -296,10 +296,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
         //
         // FIXME(#27579) return types should not be implied bounds
         let fn_sig_tys: Vec<_> =
-            fn_sig.inputs.iter()
-                         .cloned()
-                         .chain(Some(fn_sig.output))
-                         .collect();
+            fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
 
         let old_body_id = self.set_body_id(body_id.node_id());
         self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
@@ -940,7 +937,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     let fn_sig = method.ty.fn_sig();
                     let fn_sig = // late-bound regions should have been instantiated
                         self.tcx.no_late_bound_regions(fn_sig).unwrap();
-                    let self_ty = fn_sig.inputs[0];
+                    let self_ty = fn_sig.inputs()[0];
                     let (m, r) = match self_ty.sty {
                         ty::TyRef(r, ref m) => (m.mutbl, r),
                         _ => {
@@ -967,8 +964,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     self.type_must_outlive(infer::CallRcvr(deref_expr.span),
                                            self_ty, r_deref_expr);
                     self.type_must_outlive(infer::CallReturn(deref_expr.span),
-                                           fn_sig.output, r_deref_expr);
-                    fn_sig.output
+                                           fn_sig.output(), r_deref_expr);
+                    fn_sig.output()
                 }
                 None => derefd_ty
             };
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7870b3677d0..7f35c8efeff 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -449,15 +449,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
         let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
 
-        for &input_ty in &sig.inputs {
-            fcx.register_wf_obligation(input_ty, span, self.code.clone());
+        for input_ty in sig.inputs() {
+            fcx.register_wf_obligation(&input_ty, span, self.code.clone());
         }
-        implied_bounds.extend(sig.inputs);
+        implied_bounds.extend(sig.inputs());
 
-        fcx.register_wf_obligation(sig.output, span, self.code.clone());
+        fcx.register_wf_obligation(sig.output(), span, self.code.clone());
 
         // FIXME(#25759) return types should not be implied bounds
-        implied_bounds.push(sig.output);
+        implied_bounds.push(sig.output());
 
         self.check_where_clauses(fcx, span, predicates);
     }
@@ -487,7 +487,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
         debug!("check_method_receiver: sig={:?}", sig);
 
-        let self_arg_ty = sig.inputs[0];
+        let self_arg_ty = sig.inputs()[0];
         let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) {
             ExplicitSelf::ByValue => self_ty,
             ExplicitSelf::ByReference(region, mutbl) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 3bb7d6a77ba..fba77d17179 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -920,21 +920,12 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     let ctor_ty = match variant.ctor_kind {
         CtorKind::Fictive | CtorKind::Const => ty,
         CtorKind::Fn => {
-            let inputs: Vec<_> =
-                variant.fields
-                .iter()
-                .map(|field| tcx.item_type(field.did))
-                .collect();
-            let substs = mk_item_substs(&ccx.icx(&predicates),
-                                        ccx.tcx.map.span(ctor_id), def_id);
+            let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
+            let substs = mk_item_substs(&ccx.icx(&predicates), ccx.tcx.map.span(ctor_id), def_id);
             tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: abi::Abi::Rust,
-                sig: ty::Binder(ty::FnSig {
-                    inputs: inputs,
-                    output: ty,
-                    variadic: false
-                })
+                sig: ty::Binder(ccx.tcx.mk_fn_sig(inputs, ty, false))
             }))
         }
     };
@@ -2085,9 +2076,7 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
     ccx.tcx.mk_fn_def(def_id, substs, ccx.tcx.mk_bare_fn(ty::BareFnTy {
         abi: abi,
         unsafety: hir::Unsafety::Unsafe,
-        sig: ty::Binder(ty::FnSig {inputs: input_tys,
-                                    output: output,
-                                    variadic: decl.variadic}),
+        sig: ty::Binder(ccx.tcx.mk_fn_sig(input_tys.into_iter(), output, decl.variadic)),
     }))
 }
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index dfa66259029..50d4c3cd0c9 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -116,6 +116,7 @@ use syntax::ast;
 use syntax::abi::Abi;
 use syntax_pos::Span;
 
+use std::iter;
 use std::cell::RefCell;
 use util::nodemap::NodeMap;
 
@@ -222,11 +223,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                sig: ty::Binder(ty::FnSig {
-                    inputs: Vec::new(),
-                    output: tcx.mk_nil(),
-                    variadic: false
-                })
+                sig: ty::Binder(tcx.mk_fn_sig(iter::empty(), tcx.mk_nil(), false))
             }));
 
             require_same_types(
@@ -274,14 +271,14 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
-                sig: ty::Binder(ty::FnSig {
-                    inputs: vec![
+                sig: ty::Binder(tcx.mk_fn_sig(
+                    [
                         tcx.types.isize,
                         tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
-                    ],
-                    output: tcx.types.isize,
-                    variadic: false,
-                }),
+                    ].iter().cloned(),
+                    tcx.types.isize,
+                    false,
+                )),
             }));
 
             require_same_types(
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index ded9df25d5c..39f996ee62b 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -467,10 +467,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                                 sig: &ty::PolyFnSig<'tcx>,
                                 variance: VarianceTermPtr<'a>) {
         let contra = self.contravariant(variance);
-        for &input in &sig.0.inputs {
+        for &input in sig.0.inputs() {
             self.add_constraints_from_ty(generics, input, contra);
         }
-        self.add_constraints_from_ty(generics, sig.0.output, variance);
+        self.add_constraints_from_ty(generics, sig.0.output(), variance);
     }
 
     /// Adds constraints appropriate for a region appearing in a
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bc8472bb6b7..28ca92f5db6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1152,11 +1152,11 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
             cx.tcx.sess.cstore.fn_arg_names(did).into_iter()
         }.peekable();
         FnDecl {
-            output: Return(sig.0.output.clean(cx)),
+            output: Return(sig.skip_binder().output().clean(cx)),
             attrs: Attributes::default(),
-            variadic: sig.0.variadic,
+            variadic: sig.skip_binder().variadic,
             inputs: Arguments {
-                values: sig.0.inputs.iter().map(|t| {
+                values: sig.skip_binder().inputs().iter().map(|t| {
                     Argument {
                         type_: t.clean(cx),
                         id: ast::CRATE_NODE_ID,