From a4f7ba376eef754ea76467d5d48f81dddb83b089 Mon Sep 17 00:00:00 2001
From: Mark-Simulacrum <mark.simulacrum@gmail.com>
Date: Mon, 24 Oct 2016 18:22:59 -0600
Subject: [PATCH 1/3] Add AccumulateVec, a potentially stack-allocated vector.

AccumulateVec is generic over the Array trait, which is currently only
implemented for [T; 8].
---
 .../accumulate_vec.rs                         |  52 +++++++++
 src/librustc_data_structures/array_vec.rs     | 106 ++++++++++++++++++
 src/librustc_data_structures/lib.rs           |   5 +
 3 files changed, 163 insertions(+)
 create mode 100644 src/librustc_data_structures/accumulate_vec.rs
 create mode 100644 src/librustc_data_structures/array_vec.rs

diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs
new file mode 100644
index 0000000000000..3894db40277a1
--- /dev/null
+++ b/src/librustc_data_structures/accumulate_vec.rs
@@ -0,0 +1,52 @@
+// Copyright 2016 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.
+
+//! A vector type intended to be used for collecting from iterators onto the stack.
+//!
+//! Space for up to N elements is provided on the stack.  If more elements are collected, Vec is
+//! used to store the values on the heap. This type does not support re-allocating onto the heap,
+//! and there is no way to push more elements onto the existing storage.
+//!
+//! The N above is determined by Array's implementor, by way of an associatated constant.
+
+use std::ops::Deref;
+use std::iter::{IntoIterator, FromIterator};
+
+use array_vec::{Array, ArrayVec};
+
+#[derive(Debug)]
+pub enum AccumulateVec<A: Array> {
+    Array(ArrayVec<A>),
+    Heap(Vec<A::Element>)
+}
+
+impl<A: Array> Deref for AccumulateVec<A> {
+    type Target = [A::Element];
+    fn deref(&self) -> &Self::Target {
+        match *self {
+            AccumulateVec::Array(ref v) => &v[..],
+            AccumulateVec::Heap(ref v) => &v[..],
+        }
+    }
+}
+
+impl<A: Array> FromIterator<A::Element> for AccumulateVec<A> {
+    fn from_iter<I>(iter: I) -> AccumulateVec<A> where I: IntoIterator<Item=A::Element> {
+        let iter = iter.into_iter();
+        if iter.size_hint().1.map_or(false, |n| n <= A::LEN) {
+            let mut v = ArrayVec::new();
+            v.extend(iter);
+            AccumulateVec::Array(v)
+        } else {
+            AccumulateVec::Heap(iter.collect())
+        }
+    }
+}
+
diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs
new file mode 100644
index 0000000000000..f87426cee59ea
--- /dev/null
+++ b/src/librustc_data_structures/array_vec.rs
@@ -0,0 +1,106 @@
+// Copyright 2016 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.
+
+//! A stack-allocated vector, allowing storage of N elements on the stack.
+//!
+//! Currently, only the N = 8 case is supported (due to Array only being impl-ed for [T; 8]).
+
+use std::marker::Unsize;
+use std::iter::Extend;
+use std::ptr::drop_in_place;
+use std::ops::{Deref, DerefMut};
+use std::slice;
+use std::fmt;
+
+pub unsafe trait Array {
+    type Element;
+    type PartialStorage: Default + Unsize<[ManuallyDrop<Self::Element>]>;
+    const LEN: usize;
+}
+
+unsafe impl<T> Array for [T; 8] {
+    type Element = T;
+    type PartialStorage = [ManuallyDrop<T>; 8];
+    const LEN: usize = 8;
+}
+
+pub struct ArrayVec<A: Array> {
+    count: usize,
+    values: A::PartialStorage
+}
+
+impl<A: Array> ArrayVec<A> {
+    pub fn new() -> Self {
+        ArrayVec {
+            count: 0,
+            values: Default::default(),
+        }
+    }
+}
+
+impl<A> fmt::Debug for ArrayVec<A>
+    where A: Array,
+          A::Element: fmt::Debug {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self[..].fmt(f)
+    }
+}
+
+impl<A: Array> Deref for ArrayVec<A> {
+    type Target = [A::Element];
+    fn deref(&self) -> &Self::Target {
+        unsafe {
+            slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count)
+        }
+    }
+}
+
+impl<A: Array> DerefMut for ArrayVec<A> {
+    fn deref_mut(&mut self) -> &mut [A::Element] {
+        unsafe {
+            slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count)
+        }
+    }
+}
+
+impl<A: Array> Drop for ArrayVec<A> {
+    fn drop(&mut self) {
+        unsafe {
+            drop_in_place(&mut self[..])
+        }
+    }
+}
+
+impl<A: Array> Extend<A::Element> for ArrayVec<A> {
+    fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=A::Element> {
+        for el in iter {
+            unsafe {
+                let arr = &mut self.values as &mut [ManuallyDrop<_>];
+                arr[self.count].value = el;
+            }
+            self.count += 1;
+        }
+    }
+}
+
+// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758.
+#[allow(unions_with_drop_fields)]
+pub union ManuallyDrop<T> {
+    value: T,
+    #[allow(dead_code)]
+    empty: (),
+}
+
+impl<T> Default for ManuallyDrop<T> {
+    fn default() -> Self {
+        ManuallyDrop { empty: () }
+    }
+}
+
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 26b9f48ad04dd..143c180f823d0 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -30,6 +30,9 @@
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(fn_traits)]
+#![feature(untagged_unions)]
+#![feature(associated_consts)]
+#![feature(unsize)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
@@ -41,6 +44,8 @@ extern crate serialize as rustc_serialize; // used by deriving
 #[cfg(unix)]
 extern crate libc;
 
+pub mod array_vec;
+pub mod accumulate_vec;
 pub mod bitslice;
 pub mod blake2b;
 pub mod bitvec;

From 982a48575b53e05cd53f679aac2fedf6346f78c7 Mon Sep 17 00:00:00 2001
From: Mark-Simulacrum <mark.simulacrum@gmail.com>
Date: Mon, 24 Oct 2016 18:23:29 -0600
Subject: [PATCH 2/3] Utilize AccumulateVec to avoid heap allocations in
 mk_{substs, type_list, tup} calls.

---
 src/libarena/lib.rs                           |  8 +-
 src/librustc/mir/tcx.rs                       |  4 +-
 src/librustc/traits/fulfill.rs                |  4 +-
 src/librustc/traits/select.rs                 |  4 +-
 src/librustc/traits/util.rs                   |  8 +-
 src/librustc/ty/context.rs                    | 94 +++++++++++++++++--
 src/librustc/ty/mod.rs                        | 17 +++-
 src/librustc/ty/relate.rs                     | 18 +---
 src/librustc/ty/structural_impls.rs           |  5 +-
 src/librustc/ty/subst.rs                      | 47 ++--------
 src/librustc/util/ppaux.rs                    |  4 +-
 .../borrowck/mir/elaborate_drops.rs           |  2 +-
 src/librustc_driver/test.rs                   | 19 ++--
 src/librustc_lint/builtin.rs                  |  6 +-
 src/librustc_metadata/decoder.rs              |  4 +-
 src/librustc_mir/build/expr/as_rvalue.rs      |  2 +-
 src/librustc_mir/build/scope.rs               |  6 +-
 src/librustc_mir/hair/cx/mod.rs               |  4 +-
 src/librustc_trans/base.rs                    |  8 +-
 src/librustc_trans/callee.rs                  |  2 +-
 src/librustc_trans/collector.rs               |  8 +-
 src/librustc_trans/common.rs                  |  4 +-
 src/librustc_trans/glue.rs                    |  4 +-
 src/librustc_trans/mir/constant.rs            |  2 +-
 src/librustc_trans/mir/rvalue.rs              |  2 +-
 src/librustc_trans/trans_item.rs              |  2 +-
 src/librustc_typeck/astconv.rs                | 11 +--
 src/librustc_typeck/check/_match.rs           |  5 +-
 src/librustc_typeck/check/autoderef.rs        |  3 +-
 src/librustc_typeck/check/closure.rs          |  2 +-
 src/librustc_typeck/check/intrinsic.rs        |  4 +-
 src/librustc_typeck/check/method/suggest.rs   |  3 +-
 src/librustc_typeck/check/mod.rs              | 15 ++-
 src/librustc_typeck/lib.rs                    |  4 +-
 src/librustdoc/clean/mod.rs                   |  2 +-
 35 files changed, 193 insertions(+), 144 deletions(-)

diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index cfbd29571f7b2..0a06c0b2dfb76 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -157,13 +157,15 @@ impl<T> TypedArena<T> {
 
     /// Allocates a slice of objects that are copy into the `TypedArena`, returning a mutable
     /// reference to it. Will panic if passed a zero-sized types.
+    ///
+    /// Panics:
+    ///  - Zero-sized types
+    ///  - Zero-length slices
     #[inline]
     pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]
         where T: Copy {
         assert!(mem::size_of::<T>() != 0);
-        if slice.len() == 0 {
-            return unsafe { slice::from_raw_parts_mut(heap::EMPTY as *mut T, 0) };
-        }
+        assert!(slice.len() != 0);
 
         let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
         let at_least_bytes = slice.len() * mem::size_of::<T>();
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 6fe6498ff789c..8dd82b2d07924 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -163,7 +163,7 @@ impl<'tcx> Rvalue<'tcx> {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
                 let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                let ty = tcx.mk_tup(&[ty, tcx.types.bool]);
+                let ty = tcx.intern_tup(&[ty, tcx.types.bool]);
                 Some(ty)
             }
             &Rvalue::UnaryOp(_, ref operand) => {
@@ -184,7 +184,7 @@ impl<'tcx> Rvalue<'tcx> {
                     }
                     AggregateKind::Tuple => {
                         Some(tcx.mk_tup(
-                            &ops.iter().map(|op| op.ty(mir, tcx)).collect::<Vec<_>>()
+                            ops.iter().map(|op| op.ty(mir, tcx))
                         ))
                     }
                     AggregateKind::Adt(def, _, substs, _) => {
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 65860671c4c63..ded2fdc58b42b 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -11,7 +11,7 @@
 use dep_graph::DepGraph;
 use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::{Substs, Subst};
+use ty::subst::Subst;
 use rustc_data_structures::obligation_forest::{ObligationForest, Error};
 use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
 use std::marker::PhantomData;
@@ -159,7 +159,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
                 let concrete_ty = ty_scheme.ty.subst(tcx, substs);
                 let predicate = ty::TraitRef {
                     def_id: self.predicate.def_id(),
-                    substs: Substs::new_trait(tcx, concrete_ty, &[])
+                    substs: tcx.mk_substs_trait(concrete_ty, &[])
                 }.to_predicate();
 
                 let original_obligation = Obligation::new(self.cause.clone(),
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index dbaa8db3e8971..216df8b092a02 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -2599,7 +2599,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         k
                     }
                 });
-                let substs = Substs::new(tcx, params);
+                let substs = tcx.mk_substs(params);
                 for &ty in fields.split_last().unwrap().1 {
                     if ty.subst(tcx, substs).references_error() {
                         return Err(Unimplemented);
@@ -2619,7 +2619,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         k
                     }
                 });
-                let new_struct = tcx.mk_adt(def, Substs::new(tcx, params));
+                let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
                 let origin = TypeOrigin::Misc(obligation.cause.span);
                 let InferOk { obligations, .. } =
                     self.infcx.sub_types(false, origin, new_struct, target)
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index fa951b5efdb2b..a0792dcf4dd59 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             Ok(def_id) => {
                 Ok(ty::TraitRef {
                     def_id: def_id,
-                    substs: Substs::new_trait(self, param_ty, &[])
+                    substs: self.mk_substs_trait(param_ty, &[])
                 })
             }
             Err(e) => {
@@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         let trait_ref = ty::TraitRef {
             def_id: trait_def_id,
-            substs: Substs::new_trait(self, param_ty, ty_params)
+            substs: self.mk_substs_trait(param_ty, ty_params)
         };
         predicate_for_trait_ref(cause, trait_ref, recursion_depth)
     }
@@ -486,11 +486,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     {
         let arguments_tuple = match tuple_arguments {
             TupleArgumentsFlag::No => sig.0.inputs[0],
-            TupleArgumentsFlag::Yes => self.mk_tup(&sig.0.inputs),
+            TupleArgumentsFlag::Yes => self.intern_tup(&sig.0.inputs[..]),
         };
         let trait_ref = ty::TraitRef {
             def_id: fn_trait_def_id,
-            substs: Substs::new_trait(self, self_ty, &[arguments_tuple]),
+            substs: self.mk_substs_trait(self_ty, &[arguments_tuple]),
         };
         ty::Binder((trait_ref, sig.0.output))
     }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index d075b08f7385a..8c7a2da3be7fa 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -36,6 +36,7 @@ use ty::maps;
 use util::common::MemoizationMap;
 use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
 use util::nodemap::{FnvHashMap, FnvHashSet};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use arena::TypedArena;
 use std::borrow::Borrow;
@@ -44,6 +45,7 @@ use std::hash::{Hash, Hasher};
 use std::mem;
 use std::ops::Deref;
 use std::rc::Rc;
+use std::iter;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::parse::token::{self, keywords};
@@ -824,6 +826,9 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
 impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     type Lifted = &'tcx Substs<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
+        if self.len() == 0 {
+            return Some(Slice::empty());
+        }
         if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(&self[..]) {
             if *self as *const _ == substs as *const _ {
                 return Some(substs);
@@ -859,6 +864,9 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
     type Lifted = &'tcx Slice<Ty<'tcx>>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
                              -> Option<&'tcx Slice<Ty<'tcx>>> {
+        if self.len() == 0 {
+            return Some(Slice::empty());
+        }
         if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(&self[..]) {
             if *self as *const _ == list as *const _ {
                 return Some(list);
@@ -1212,8 +1220,8 @@ macro_rules! slice_interners {
 }
 
 slice_interners!(
-    type_list: mk_type_list(Ty),
-    substs: mk_substs(Kind)
+    type_list: _intern_type_list(Ty),
+    substs: _intern_substs(Kind)
 );
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
@@ -1318,12 +1326,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TySlice(ty))
     }
 
-    pub fn mk_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
-        self.mk_ty(TyTuple(self.mk_type_list(ts)))
+    pub fn intern_tup(self, ts: &[Ty<'tcx>]) -> Ty<'tcx> {
+        self.mk_ty(TyTuple(self.intern_type_list(ts)))
+    }
+
+    pub fn mk_tup<I: InternAs<[Ty<'tcx>], Ty<'tcx>>>(self, iter: I) -> I::Output {
+        iter.intern_with(|ts| self.mk_ty(TyTuple(self.intern_type_list(ts))))
     }
 
     pub fn mk_nil(self) -> Ty<'tcx> {
-        self.mk_tup(&[])
+        self.intern_tup(&[])
     }
 
     pub fn mk_diverging_default(self) -> Ty<'tcx> {
@@ -1369,7 +1381,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                       -> Ty<'tcx> {
         self.mk_closure_from_closure_substs(closure_id, ClosureSubsts {
             func_substs: substs,
-            upvar_tys: self.mk_type_list(tys)
+            upvar_tys: self.intern_type_list(tys)
         })
     }
 
@@ -1414,6 +1426,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.mk_ty(TyAnon(def_id, substs))
     }
 
+    pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice<Ty<'tcx>> {
+        if ts.len() == 0 {
+            Slice::empty()
+        } else {
+            self._intern_type_list(ts)
+        }
+    }
+
+    pub fn intern_substs(self, ts: &[Kind<'tcx>]) -> &'tcx Slice<Kind<'tcx>> {
+        if ts.len() == 0 {
+            Slice::empty()
+        } else {
+            self._intern_substs(ts)
+        }
+    }
+
+    pub fn mk_type_list<I: InternAs<[Ty<'tcx>],
+                        &'tcx Slice<Ty<'tcx>>>>(self, iter: I) -> I::Output {
+        iter.intern_with(|xs| self.intern_type_list(xs))
+    }
+
+    pub fn mk_substs<I: InternAs<[Kind<'tcx>],
+                     &'tcx Slice<Kind<'tcx>>>>(self, iter: I) -> I::Output {
+        iter.intern_with(|xs| self.intern_substs(xs))
+    }
+
+    pub fn mk_substs_trait(self,
+                     s: Ty<'tcx>,
+                     t: &[Ty<'tcx>])
+                    -> &'tcx Substs<'tcx>
+    {
+        self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
+    }
+
     pub fn trait_items(self, trait_did: DefId) -> Rc<Vec<ty::ImplOrTraitItem<'gcx>>> {
         self.trait_items_cache.memoize(trait_did, || {
             let def_ids = self.impl_or_trait_items(trait_did);
@@ -1432,3 +1478,39 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         })
     }
 }
+
+pub trait InternAs<T: ?Sized, R> {
+    type Output;
+    fn intern_with<F>(self, F) -> Self::Output
+        where F: FnOnce(&T) -> R;
+}
+
+impl<I, T, R, E> InternAs<[T], R> for I
+    where E: InternIteratorElement<T, R>,
+          I: Iterator<Item=E> {
+    type Output = E::Output;
+    fn intern_with<F>(self, f: F) -> Self::Output
+        where F: FnOnce(&[T]) -> R {
+        E::intern_with(self, f)
+    }
+}
+
+pub trait InternIteratorElement<T, R>: Sized {
+    type Output;
+    fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output;
+}
+
+impl<T, R> InternIteratorElement<T, R> for T {
+    type Output = R;
+    fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+        f(&iter.collect::<AccumulateVec<[_; 8]>>())
+    }
+}
+
+impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
+    type Output = Result<R, E>;
+    fn intern_with<I: Iterator<Item=Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+        Ok(f(&iter.collect::<Result<AccumulateVec<[_; 8]>, _>>()?))
+    }
+}
+
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 018f01e5913c0..53909b8143526 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -41,6 +41,7 @@ use std::ops::Deref;
 use std::rc::Rc;
 use std::slice;
 use std::vec::IntoIter;
+use std::mem;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::parse::token::{self, InternedString};
@@ -560,6 +561,14 @@ impl<'a, T> IntoIterator for &'a Slice<T> {
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice<Ty<'tcx>> {}
 
+impl<T> Slice<T> {
+    pub fn empty<'a>() -> &'a Slice<T> {
+        unsafe {
+            mem::transmute(slice::from_raw_parts(0x1 as *const T, 0))
+        }
+    }
+}
+
 /// Upvars do not get their own node-id. Instead, we use the pair of
 /// the original var id (that is, the root variable that is referenced
 /// by the upvar) and the id of the closure expression.
@@ -1797,7 +1806,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
             _ if tys.references_error() => tcx.types.err,
             0 => tcx.types.bool,
             1 => tys[0],
-            _ => tcx.mk_tup(&tys)
+            _ => tcx.intern_tup(&tys[..])
         };
 
         match self.sized_constraint.get(dep_node()) {
@@ -1873,7 +1882,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
                 };
                 let sized_predicate = Binder(TraitRef {
                     def_id: sized_trait,
-                    substs: Substs::new_trait(tcx, ty, &[])
+                    substs: tcx.mk_substs_trait(ty, &[])
                 }).to_predicate();
                 let predicates = tcx.lookup_predicates(self.did).predicates;
                 if predicates.into_iter().any(|p| p == sized_predicate) {
@@ -2124,7 +2133,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn node_id_item_substs(self, id: NodeId) -> ItemSubsts<'gcx> {
         match self.tables.borrow().item_substs.get(&id) {
             None => ItemSubsts {
-                substs: Substs::empty(self.global_tcx())
+                substs: self.global_tcx().intern_substs(&[])
             },
             Some(ts) => ts.clone(),
         }
@@ -2796,7 +2805,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // regions, so it shouldn't matter what we use for the free id
         let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
         ty::ParameterEnvironment {
-            free_substs: Substs::empty(self),
+            free_substs: self.intern_substs(&[]),
             caller_bounds: Vec::new(),
             implicit_region_bound: self.mk_region(ty::ReEmpty),
             free_id_outlive: free_id_outlive,
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 48b0b4ec9e58f..cb90e6392cf03 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -49,12 +49,6 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
         Relate::relate(self, a, b)
     }
 
-    /// Relete elements of two slices pairwise.
-    fn relate_zip<T: Relate<'tcx>>(&mut self, a: &[T], b: &[T]) -> RelateResult<'tcx, Vec<T>> {
-        assert_eq!(a.len(), b.len());
-        a.iter().zip(b).map(|(a, b)| self.relate(a, b)).collect()
-    }
-
     /// Switch variance for the purpose of relating `a` and `b`.
     fn relate_with_variance<T: Relate<'tcx>>(&mut self,
                                              variance: ty::Variance,
@@ -158,7 +152,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
         }
     });
 
-    Substs::maybe_new(tcx, params)
+    Ok(tcx.mk_substs(params)?)
 }
 
 impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
@@ -489,10 +483,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
         (&ty::TyTuple(as_), &ty::TyTuple(bs)) =>
         {
             if as_.len() == bs.len() {
-                let ts = as_.iter().zip(bs)
-                            .map(|(a, b)| relation.relate(a, b))
-                            .collect::<Result<Vec<_>, _>>()?;
-                Ok(tcx.mk_tup(&ts))
+                Ok(tcx.mk_tup(as_.iter().zip(bs).map(|(a, b)| relation.relate(a, b)))?)
             } else if !(as_.is_empty() || bs.is_empty()) {
                 Err(TypeError::TupleSize(
                     expected_found(relation, &as_.len(), &bs.len())))
@@ -544,10 +535,11 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> {
         where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
     {
         let substs = relate_substs(relation, None, a.func_substs, b.func_substs)?;
-        let upvar_tys = relation.relate_zip(&a.upvar_tys, &b.upvar_tys)?;
+        assert_eq!(a.upvar_tys.len(), b.upvar_tys.len());
         Ok(ty::ClosureSubsts {
             func_substs: substs,
-            upvar_tys: relation.tcx().mk_type_list(&upvar_tys)
+            upvar_tys: relation.tcx().mk_type_list(
+                a.upvar_tys.iter().zip(b.upvar_tys).map(|(a, b)| relation.relate(a, b)))?
         })
     }
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 0f4cff3d4875b..3165edebf1a46 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -11,6 +11,7 @@
 use infer::type_variable;
 use ty::{self, Lift, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use std::rc::Rc;
 use syntax::abi;
@@ -448,8 +449,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<Ty<'tcx>> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let tys = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
-        folder.tcx().mk_type_list(&tys)
+        let v = self.iter().map(|t| t.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
+        folder.tcx().intern_type_list(&v)
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index b0fdaa170996d..a4ceecd8c9d7b 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -16,6 +16,7 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
 
 use core::nonzero::NonZero;
 use std::fmt;
@@ -164,31 +165,6 @@ impl<'tcx> Decodable for Kind<'tcx> {
 pub type Substs<'tcx> = Slice<Kind<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
-    pub fn new<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
-                  -> &'tcx Substs<'tcx>
-    where I: IntoIterator<Item=Kind<'tcx>> {
-        tcx.mk_substs(&params.into_iter().collect::<Vec<_>>())
-    }
-
-    pub fn maybe_new<I, E>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
-                           -> Result<&'tcx Substs<'tcx>, E>
-    where I: IntoIterator<Item=Result<Kind<'tcx>, E>> {
-        Ok(Substs::new(tcx, params.into_iter().collect::<Result<Vec<_>, _>>()?))
-    }
-
-    pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                     s: Ty<'tcx>,
-                     t: &[Ty<'tcx>])
-                    -> &'tcx Substs<'tcx>
-    {
-        let t = iter::once(s).chain(t.iter().cloned());
-        Substs::new(tcx, t.map(Kind::from))
-    }
-
-    pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
-        Substs::new(tcx, iter::empty())
-    }
-
     /// Creates a Substs for generic parameter definitions,
     /// by calling closures to obtain each region and type.
     /// The closures get to observe the Substs as they're
@@ -203,10 +179,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
           FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
         let defs = tcx.lookup_generics(def_id);
         let mut substs = Vec::with_capacity(defs.count());
-
         Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
-
-        Substs::new(tcx, substs)
+        tcx.intern_substs(&substs)
     }
 
     fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
@@ -298,20 +272,20 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                        target_substs: &Substs<'tcx>)
                        -> &'tcx Substs<'tcx> {
         let defs = tcx.lookup_generics(source_ancestor);
-        Substs::new(tcx, target_substs.iter().chain(&self[defs.own_count()..]).cloned())
+        tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let params: Vec<_> = self.iter().map(|k| k.fold_with(folder)).collect();
+        let params: AccumulateVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
 
         // If folding doesn't change the substs, it's faster to avoid
         // calling `mk_substs` and instead reuse the existing substs.
         if params[..] == self[..] {
             self
         } else {
-            folder.tcx().mk_substs(&params)
+            folder.tcx().intern_substs(&params)
         }
     }
 
@@ -547,10 +521,9 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> {
                        -> ty::TraitRef<'tcx> {
         let defs = tcx.lookup_generics(trait_id);
 
-        let params = substs[..defs.own_count()].iter().cloned();
         ty::TraitRef {
             def_id: trait_id,
-            substs: Substs::new(tcx, params)
+            substs: tcx.intern_substs(&substs[..defs.own_count()])
         }
     }
 }
@@ -562,10 +535,9 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> {
         // Assert there is a Self.
         trait_ref.substs.type_at(0);
 
-        let params = trait_ref.substs[1..].iter().cloned();
         ty::ExistentialTraitRef {
             def_id: trait_ref.def_id,
-            substs: Substs::new(tcx, params)
+            substs: tcx.intern_substs(&trait_ref.substs[1..])
         }
     }
 }
@@ -582,11 +554,10 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
         assert!(!self_ty.has_escaping_regions());
 
         self.map_bound(|trait_ref| {
-            let params = trait_ref.substs.iter().cloned();
-            let params = iter::once(Kind::from(self_ty)).chain(params);
             ty::TraitRef {
                 def_id: trait_ref.def_id,
-                substs: Substs::new(tcx, params)
+                substs: tcx.mk_substs(
+                    iter::once(Kind::from(self_ty)).chain(trait_ref.substs.iter().cloned()))
             }
         })
     }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 1df0cf2d5cdf6..af92569cc350c 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use hir::def_id::DefId;
-use ty::subst::{self, Subst, Substs};
+use ty::subst::{self, Subst};
 use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
 use ty::{TyBool, TyChar, TyAdt};
 use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
@@ -886,7 +886,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
                     // by looking up the projections associated with the def_id.
                     let item_predicates = tcx.lookup_predicates(def_id);
                     let substs = tcx.lift(&substs).unwrap_or_else(|| {
-                        Substs::empty(tcx)
+                        tcx.intern_substs(&[])
                     });
                     let bounds = item_predicates.instantiate(tcx, substs);
 
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 25986b85f7b3a..fce5553c2fee9 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -857,7 +857,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
         let unit_temp = Lvalue::Local(self.patch.new_temp(tcx.mk_nil()));
         let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
             .unwrap_or_else(|e| tcx.sess.fatal(&e));
-        let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
+        let substs = tcx.mk_substs(iter::once(Kind::from(ty)));
         let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs);
 
         self.patch.new_block(BasicBlockData {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 15be80f4ee5a5..c400610a688a0 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -20,14 +20,13 @@ use rustc::middle::region::{self, CodeExtent};
 use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, Subst};
 use rustc::traits::Reveal;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
 use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::session::{self, config};
-use std::iter;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::abi::Abi;
@@ -275,7 +274,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_pair(&self, ty1: Ty<'tcx>, ty2: Ty<'tcx>) -> Ty<'tcx> {
-        self.infcx.tcx.mk_tup(&[ty1, ty2])
+        self.infcx.tcx.intern_tup(&[ty1, ty2])
     }
 
     pub fn t_param(&self, index: u32) -> Ty<'tcx> {
@@ -679,7 +678,7 @@ fn subst_ty_renumber_bound() {
             env.t_fn(&[t_param], env.t_nil())
         };
 
-        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
+        let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
@@ -714,7 +713,7 @@ fn subst_ty_renumber_some_bounds() {
             env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
         };
 
-        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
+        let substs = env.infcx.tcx.intern_substs(&[Kind::from(t_rptr_bound1)]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = (&'a isize, fn(&'a isize))
@@ -776,7 +775,7 @@ fn subst_region_renumber_region() {
             env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
         };
 
-        let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(re_bound1)));
+        let substs = env.infcx.tcx.intern_substs(&[Kind::from(re_bound1)]);
         let t_substituted = t_source.subst(env.infcx.tcx, substs);
 
         // t_expected = fn(&'a isize)
@@ -803,8 +802,8 @@ fn walk_ty() {
         let tcx = env.infcx.tcx;
         let int_ty = tcx.types.isize;
         let uint_ty = tcx.types.usize;
-        let tup1_ty = tcx.mk_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
-        let tup2_ty = tcx.mk_tup(&[tup1_ty, tup1_ty, uint_ty]);
+        let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
+        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
         let uniq_ty = tcx.mk_box(tup2_ty);
         let walked: Vec<_> = uniq_ty.walk().collect();
         assert_eq!(walked,
@@ -819,8 +818,8 @@ fn walk_ty_skip_subtree() {
         let tcx = env.infcx.tcx;
         let int_ty = tcx.types.isize;
         let uint_ty = tcx.types.usize;
-        let tup1_ty = tcx.mk_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
-        let tup2_ty = tcx.mk_tup(&[tup1_ty, tup1_ty, uint_ty]);
+        let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty]);
+        let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty]);
         let uniq_ty = tcx.mk_box(tup2_ty);
 
         // types we expect to see (in order), plus a boolean saying
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 3428ec8d4c960..3d6dd5dedf5ba 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -503,21 +503,21 @@ impl LateLintPass for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx)))
+                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemUnion(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx)))
+                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx)))
+                (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             _ => return,
         };
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index e18fd58144398..7aa0ed1d1ab85 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -374,7 +374,7 @@ impl<'a, 'tcx> SpecializedDecoder<ty::GenericPredicates<'tcx>> for DecodeContext
 
 impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> {
-        Ok(self.tcx().mk_substs(&Vec::decode(self)?))
+        Ok(self.tcx().mk_substs((0..self.read_usize()?).map(|_| Decodable::decode(self)))?)
     }
 }
 
@@ -386,7 +386,7 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx>
 
 impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<Ty<'tcx>>> for DecodeContext<'a, 'tcx> {
     fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice<Ty<'tcx>>, Self::Error> {
-        Ok(self.tcx().mk_type_list(&Vec::decode(self)?))
+        Ok(self.tcx().mk_type_list((0..self.read_usize()?).map(|_| Decodable::decode(self)))?)
     }
 }
 
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index d30af8b82555c..dcb301cab00c8 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -257,7 +257,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         let source_info = self.source_info(span);
         let bool_ty = self.hir.bool_ty();
         if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() {
-            let result_tup = self.hir.tcx().mk_tup(&[ty, bool_ty]);
+            let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]);
             let result_value = self.temp(result_tup);
 
             self.cfg.push_assign(block, source_info,
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index 01cce3c7dd794..e5d4ea8af50a2 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -89,15 +89,13 @@ should go to.
 use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
 use rustc::middle::region::{CodeExtent, CodeExtentData};
 use rustc::middle::lang_items;
-use rustc::ty::subst::{Kind, Substs, Subst};
+use rustc::ty::subst::{Kind, Subst};
 use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::repr::*;
 use syntax_pos::Span;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::fnv::FnvHashMap;
 
-use std::iter;
-
 pub struct Scope<'tcx> {
     /// the scope-id within the scope_auxiliary
     id: ScopeId,
@@ -800,7 +798,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                               -> TerminatorKind<'tcx> {
     let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
                        .unwrap_or_else(|e| tcx.sess.fatal(&e));
-    let substs = Substs::new(tcx, iter::once(Kind::from(data.item_ty)));
+    let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
     TerminatorKind::Call {
         func: Operand::Constant(Constant {
             span: data.span,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 8dd33ad2f9c7a..9fe3addea4127 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -27,7 +27,7 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::FnKind;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::infer::InferCtxt;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::Subst;
 use rustc::ty::{self, Ty, TyCtxt};
 use syntax::parse::token;
 use rustc::hir;
@@ -146,7 +146,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                         params: &[Ty<'tcx>])
                         -> (Ty<'tcx>, Literal<'tcx>) {
         let method_name = token::intern(method_name);
-        let substs = Substs::new_trait(self.tcx, self_ty, params);
+        let substs = self.tcx.mk_substs_trait(self_ty, params);
         for trait_item in self.tcx.trait_items(trait_def_id).iter() {
             match *trait_item {
                 ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 02aa7c069f9b3..d4d4f883e7b85 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -214,7 +214,7 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Allocate space:
     let def_id = require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem);
-    let r = Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
+    let r = Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[]))
         .call(bcx, debug_loc, &[size, align], None);
 
     Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
@@ -405,7 +405,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
                                              -> CustomCoerceUnsized {
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(),
-        substs: Substs::new_trait(scx.tcx(), source_ty, &[target_ty])
+        substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty])
     });
 
     match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
@@ -848,7 +848,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                 common::validate_substs(instance.substs);
                 (instance.substs, Some(instance.def))
             }
-            None => (Substs::empty(ccx.tcx()), None)
+            None => (ccx.tcx().intern_substs(&[]), None)
         };
 
         let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
@@ -1211,7 +1211,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
                     Ok(id) => id,
                     Err(s) => ccx.sess().fatal(&s)
                 };
-                let empty_substs = Substs::empty(ccx.tcx());
+                let empty_substs = ccx.tcx().intern_substs(&[]);
                 let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
                 let args = {
                     let opaque_rust_main =
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 5c7ab77648e5e..cdd3e919e61c0 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -327,7 +327,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
         }
     };
     let sig = tcx.erase_late_bound_regions_and_normalize(sig);
-    let tuple_input_ty = tcx.mk_tup(&sig.inputs);
+    let tuple_input_ty = tcx.intern_tup(&sig.inputs[..]);
     let sig = ty::FnSig {
         inputs: vec![bare_fn_ty_maybe_ref,
                      tuple_input_ty],
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 8112bb8e65c5b..8a7919d01f5fc 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             create_fn_trans_item(scx,
                                  exchange_free_fn_def_id,
                                  fn_substs,
-                                 Substs::empty(scx.tcx()));
+                                 scx.tcx().intern_substs(&[]));
 
         output.push(exchange_free_fn_trans_item);
     }
@@ -752,7 +752,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                    .drop_trait()
                                    .unwrap();
 
-        let self_type_substs = Substs::new_trait(scx.tcx(), ty, &[]);
+        let self_type_substs = scx.tcx().mk_substs_trait(ty, &[]);
 
         let trait_ref = ty::TraitRef {
             def_id: drop_trait_def_id,
@@ -768,7 +768,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             let trans_item = create_fn_trans_item(scx,
                                                   destructor_did,
                                                   substs,
-                                                  Substs::empty(scx.tcx()));
+                                                  scx.tcx().intern_substs(&[]));
             output.push(trans_item);
         }
 
@@ -1035,7 +1035,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
 
     if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
         let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty);
-        let param_substs = Substs::empty(scx.tcx());
+        let param_substs = scx.tcx().intern_substs(&[]);
 
         // Walk all methods of the trait, including those of its supertraits
         let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 6ae5fc1657aa7..9158c06d6a168 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -376,7 +376,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
         let tcx = ccx.tcx();
         match tcx.lang_items.eh_personality() {
             Some(def_id) if !base::wants_msvc_seh(ccx.sess()) => {
-                Callee::def(ccx, def_id, Substs::empty(tcx)).reify(ccx)
+                Callee::def(ccx, def_id, tcx.intern_substs(&[])).reify(ccx)
             }
             _ => {
                 if let Some(llpersonality) = ccx.eh_personality().get() {
@@ -403,7 +403,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
         let tcx = ccx.tcx();
         assert!(ccx.sess().target.target.options.custom_unwind_resume);
         if let Some(def_id) = tcx.lang_items.eh_unwind_resume() {
-            return Callee::def(ccx, def_id, Substs::empty(tcx));
+            return Callee::def(ccx, def_id, tcx.intern_substs(&[]));
         }
 
         let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 64d959d29080c..648dd9f3e3aea 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -48,7 +48,7 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
     let args = [PointerCast(bcx, v, Type::i8p(bcx.ccx())), size, align];
-    Callee::def(bcx.ccx(), def_id, Substs::empty(bcx.tcx()))
+    Callee::def(bcx.ccx(), def_id, bcx.tcx().intern_substs(&[]))
         .call(bcx, debug_loc, &args, None).bcx
 }
 
@@ -292,7 +292,7 @@ fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     let trait_ref = ty::Binder(ty::TraitRef {
         def_id: tcx.lang_items.drop_trait().unwrap(),
-        substs: Substs::new_trait(tcx, t, &[])
+        substs: tcx.mk_substs_trait(t, &[])
     });
     let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
         traits::VtableImpl(data) => data,
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index baa306069f168..3e7d8acf610c2 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -773,7 +773,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 let rhs = self.const_operand(rhs, span)?;
                 let ty = lhs.ty;
                 let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
-                let binop_ty = tcx.mk_tup(&[val_ty, tcx.types.bool]);
+                let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool]);
                 let (lhs, rhs) = (lhs.llval, rhs.llval);
                 assert!(!ty.is_fp());
 
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 5ffaadf972a63..b6172fa2a907d 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -430,7 +430,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                                              lhs.immediate(), rhs.immediate(),
                                                              lhs.ty);
                 let val_ty = op.ty(bcx.tcx(), lhs.ty, rhs.ty);
-                let operand_ty = bcx.tcx().mk_tup(&[val_ty, bcx.tcx().types.bool]);
+                let operand_ty = bcx.tcx().intern_tup(&[val_ty, bcx.tcx().types.bool]);
                 let operand = OperandRef {
                     val: result,
                     ty: operand_ty
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 6c317eb994849..8930387c046e2 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -310,7 +310,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
             },
             TransItem::Static(node_id) => {
                 let def_id = hir_map.local_def_id(node_id);
-                let instance = Instance::new(def_id, Substs::empty(tcx));
+                let instance = Instance::new(def_id, tcx.intern_substs(&[]));
                 to_string_internal(tcx, "static ", instance)
             },
         };
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0c4e6324b8911..2a601475fcd76 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -635,9 +635,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     {
         let anon_scope = rscope.anon_type_scope();
         let binding_rscope = MaybeWithAnonTypes::new(BindingRscope::new(), anon_scope);
-        let inputs: Vec<_> = data.inputs.iter().map(|a_t| {
+        let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
             self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
-        }).collect();
+        }));
         let inputs_len = inputs.len();
         let input_params = || vec![String::new(); inputs_len];
         let implied_output_region = self.find_implied_output_region(&inputs, input_params);
@@ -660,7 +660,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             span: output_span
         };
 
-        (self.tcx().mk_tup(&inputs), output_binding)
+        (self.tcx().mk_ty(ty::TyTuple(inputs)), output_binding)
     }
 
     pub fn instantiate_poly_trait_ref(&self,
@@ -1661,10 +1661,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 tcx.types.never
             },
             hir::TyTup(ref fields) => {
-                let flds = fields.iter()
-                                 .map(|t| self.ast_ty_to_ty(rscope, &t))
-                                 .collect::<Vec<_>>();
-                tcx.mk_tup(&flds)
+                tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(rscope, &t)))
             }
             hir::TyBareFn(ref bf) => {
                 require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index f7e590871fc5e..d3fef0711b246 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -168,8 +168,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 let max_len = cmp::max(expected_len, elements.len());
 
-                let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect();
-                let pat_ty = tcx.mk_tup(&element_tys);
+                let element_tys_iter = (0..max_len).map(|_| self.next_ty_var());
+                let element_tys = tcx.mk_type_list(element_tys_iter);
+                let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys));
                 self.demand_eqtype(pat.span, expected, pat_ty);
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index 8127bcf825643..900c22a8176ed 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -16,7 +16,6 @@ use rustc::traits;
 use rustc::ty::{self, Ty, TraitRef};
 use rustc::ty::{ToPredicate, TypeFoldable};
 use rustc::ty::{MethodCall, MethodCallee};
-use rustc::ty::subst::Substs;
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::hir;
 
@@ -106,7 +105,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
                 Some(f) => f,
                 None => return None,
             },
-            substs: Substs::new_trait(tcx, self.cur_ty, &[]),
+            substs: tcx.mk_substs_trait(self.cur_ty, &[]),
         };
 
         let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 7b05cd1d48328..d478f1092bd87 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -88,7 +88,7 @@ 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.mk_tup(&fn_ty.sig.0.inputs)];
+        fn_ty.sig.0.inputs = vec![self.tcx.intern_tup(&fn_ty.sig.0.inputs[..])];
 
         debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
                expr_def_id,
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 7171b33a3af39..cbe3893fbf67a 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -89,7 +89,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
             "cxchg" | "cxchgweak" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)),
                                               param(ccx, 0),
                                               param(ccx, 0)),
-                                      tcx.mk_tup(&[param(ccx, 0), tcx.types.bool])),
+                                      tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
             "load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))),
                        param(ccx, 0)),
             "store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)),
@@ -274,7 +274,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
 
             "add_with_overflow" | "sub_with_overflow"  | "mul_with_overflow" =>
                 (1, vec!(param(ccx, 0), param(ccx, 0)),
-                tcx.mk_tup(&[param(ccx, 0), tcx.types.bool])),
+                tcx.intern_tup(&[param(ccx, 0), tcx.types.bool])),
 
             "unchecked_div" | "unchecked_rem" =>
                 (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index e93f990b81071..32bf839a4ed4e 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -19,7 +19,6 @@ use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
 use hir::def::Def;
 use hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::lang_items::FnOnceTraitLangItem;
-use rustc::ty::subst::Substs;
 use rustc::traits::{Obligation, SelectionContext};
 use util::nodemap::FnvHashSet;
 
@@ -55,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 self.autoderef(span, ty).any(|(ty, _)| {
                     self.probe(|_| {
-                        let fn_once_substs = Substs::new_trait(tcx, ty, &[self.next_ty_var()]);
+                        let fn_once_substs = tcx.mk_substs_trait(ty, &[self.next_ty_var()]);
                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
                         let poly_trait_ref = trait_ref.to_poly_trait_ref();
                         let obligation =
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index af5a1d7b71383..915c46891c657 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2380,7 +2380,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             let err_inputs = match tuple_arguments {
                 DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.mk_tup(&err_inputs)],
+                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
             };
 
             self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
@@ -3718,9 +3718,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => None
                 }
             });
-            let mut err_field = false;
 
-            let elt_ts = elts.iter().enumerate().map(|(i, e)| {
+            let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| {
                 let t = match flds {
                     Some(ref fs) if i < fs.len() => {
                         let ety = fs[i];
@@ -3731,13 +3730,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.check_expr_with_expectation(&e, NoExpectation)
                     }
                 };
-                err_field = err_field || t.references_error();
                 t
-            }).collect::<Vec<_>>();
-            if err_field {
+            });
+            let tuple = tcx.mk_tup(elt_ts_iter);
+            if tuple.references_error() {
                 tcx.types.err
             } else {
-                tcx.mk_tup(&elt_ts)
+                tuple
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
@@ -4193,7 +4192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let ty = self.normalize_associated_types_in(span, &ty);
                 self.write_ty(node_id, ty);
                 self.write_substs(node_id, ty::ItemSubsts {
-                    substs: Substs::empty(self.tcx)
+                    substs: self.tcx.intern_substs(&[])
                 });
                 return ty;
             }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index cb9b162cabe11..7752690e534bc 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -233,7 +233,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 _ => ()
             }
             let main_def_id = tcx.map.local_def_id(main_id);
-            let substs = Substs::empty(tcx);
+            let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(main_def_id, substs,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
@@ -285,7 +285,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
             }
 
             let start_def_id = ccx.tcx.map.local_def_id(start_id);
-            let substs = Substs::empty(tcx);
+            let substs = tcx.intern_substs(&[]);
             let se_ty = tcx.mk_fn_def(start_def_id, substs,
                                       tcx.mk_bare_fn(ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index eb6115e937315..265b66b01ea52 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -670,7 +670,7 @@ impl Clean<TyParamBound> for ty::BuiltinBound {
             Some(tcx) => tcx,
             None => return RegionBound(Lifetime::statik())
         };
-        let empty = Substs::empty(tcx);
+        let empty = tcx.intern_substs(&[]);
         let (did, path) = match *self {
             ty::BoundSend =>
                 (tcx.lang_items.send_trait().unwrap(),

From 989eba79a33187de03d8cdadb4994bb6b52200b0 Mon Sep 17 00:00:00 2001
From: Mark-Simulacrum <mark.simulacrum@gmail.com>
Date: Mon, 24 Oct 2016 18:24:24 -0600
Subject: [PATCH 3/3] Add size hint to Result's FromIterator implementation.

---
 src/libcore/result.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 96845259299be..78230b608044b 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -1008,6 +1008,11 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
                     None => None,
                 }
             }
+
+            fn size_hint(&self) -> (usize, Option<usize>) {
+                let (_min, max) = self.iter.size_hint();
+                (0, max)
+            }
         }
 
         let mut adapter = Adapter { iter: iter.into_iter(), err: None };