about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/infer/glb.rs5
-rw-r--r--src/librustc/infer/lattice.rs9
-rw-r--r--src/librustc/infer/lub.rs5
-rw-r--r--src/librustc/infer/mod.rs19
-rw-r--r--src/librustc/infer/type_variable.rs25
-rw-r--r--src/librustc/traits/error_reporting.rs29
-rw-r--r--src/librustc/traits/project.rs15
-rw-r--r--src/librustc_driver/test.rs8
-rw-r--r--src/librustc_typeck/check/_match.rs16
-rw-r--r--src/librustc_typeck/check/closure.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs5
-rw-r--r--src/librustc_typeck/check/method/suggest.rs4
-rw-r--r--src/librustc_typeck/check/mod.rs56
-rw-r--r--src/librustc_typeck/check/op.rs3
-rw-r--r--src/test/compile-fail/issue-23046.rs2
-rw-r--r--src/test/compile-fail/issue-5062.rs2
-rw-r--r--src/test/compile-fail/issue-6458-2.rs2
-rw-r--r--src/test/compile-fail/issue-6458-3.rs4
-rw-r--r--src/test/compile-fail/issue-6458.rs4
-rw-r--r--src/test/compile-fail/issue-7813.rs4
-rw-r--r--src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs2
-rw-r--r--src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs4
-rw-r--r--src/test/compile-fail/unconstrained-none.rs4
-rw-r--r--src/test/compile-fail/unconstrained-ref.rs4
-rw-r--r--src/test/compile-fail/vector-no-ann.rs4
-rw-r--r--src/test/ui/codemap_tests/repair_span_std_macros.stderr4
-rw-r--r--src/test/ui/missing-items/missing-type-parameter.rs15
-rw-r--r--src/test/ui/missing-items/missing-type-parameter.stderr10
28 files changed, 191 insertions, 76 deletions
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index a5709e18808..8ccadc6b2af 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -13,6 +13,7 @@ use super::InferCtxt;
 use super::lattice::{self, LatticeDir};
 use super::Subtype;
 
+use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
@@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
         self.fields.infcx
     }
 
+    fn cause(&self) -> &ObligationCause<'tcx> {
+        &self.fields.trace.cause
+    }
+
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(&v, &a)?;
diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs
index eda78428e61..f7b26a918b3 100644
--- a/src/librustc/infer/lattice.rs
+++ b/src/librustc/infer/lattice.rs
@@ -30,7 +30,9 @@
 //! a lattice.
 
 use super::InferCtxt;
+use super::type_variable::TypeVariableOrigin;
 
+use traits::ObligationCause;
 use ty::TyVar;
 use ty::{self, Ty};
 use ty::relate::{RelateResult, TypeRelation};
@@ -38,6 +40,8 @@ use ty::relate::{RelateResult, TypeRelation};
 pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'f, 'gcx, 'tcx>;
 
+    fn cause(&self) -> &ObligationCause<'tcx>;
+
     // Relates the type `v` to `a` and `b` such that `v` represents
     // the LUB/GLB of `a` and `b` as appropriate.
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
@@ -64,14 +68,15 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
     match (&a.sty, &b.sty) {
         (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..)))
             if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
-            let v = infcx.next_diverging_ty_var();
+            let v = infcx.next_diverging_ty_var(
+                TypeVariableOrigin::LatticeVariable(this.cause().span));
             this.relate_bound(v, a, b)?;
             Ok(v)
         }
 
         (&ty::TyInfer(TyVar(..)), _) |
         (_, &ty::TyInfer(TyVar(..))) => {
-            let v = infcx.next_ty_var();
+            let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
             this.relate_bound(v, a, b)?;
             Ok(v)
         }
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index 7d352be67d3..89571dea10c 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -13,6 +13,7 @@ use super::InferCtxt;
 use super::lattice::{self, LatticeDir};
 use super::Subtype;
 
+use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
 use ty::relate::{Relate, RelateResult, TypeRelation};
 
@@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
         self.fields.infcx
     }
 
+    fn cause(&self) -> &ObligationCause<'tcx> {
+        &self.fields.trace.cause
+    }
+
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(&a, &v)?;
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 72ef987aefd..9b58334e658 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -45,6 +45,7 @@ use util::nodemap::{FxHashMap, FxHashSet, NodeMap};
 use self::combine::CombineFields;
 use self::higher_ranked::HrMatchResult;
 use self::region_inference::{RegionVarBindings, RegionSnapshot};
+use self::type_variable::TypeVariableOrigin;
 use self::unify_key::ToType;
 
 mod bivariate;
@@ -114,7 +115,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     // We instantiate UnificationTable with bounds<Ty> because the
     // types that might instantiate a general type variable have an
     // order, represented by its upper and lower bounds.
-    type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
+    pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
 
     // Map from integral variable to the kind of integer it represents
     int_unification_table: RefCell<UnificationTable<ty::IntVid>>,
@@ -1054,18 +1055,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         })
     }
 
-    pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
+    pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
         self.type_variables
             .borrow_mut()
-            .new_var(diverging, None)
+            .new_var(diverging, origin, None)
     }
 
-    pub fn next_ty_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(false))
+    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_var(self.next_ty_var_id(false, origin))
     }
 
-    pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(true))
+    pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        self.tcx.mk_var(self.next_ty_var_id(true, origin))
     }
 
     pub fn next_int_var_id(&self) -> IntVid {
@@ -1118,7 +1119,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         let ty_var_id = self.type_variables
                             .borrow_mut()
-                            .new_var(false, default);
+                            .new_var(false,
+                                     TypeVariableOrigin::TypeParameterDefinition(span, def.name),
+                                     default);
 
         self.tcx.mk_var(ty_var_id)
     }
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 804765ec881..9c8419d9546 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -13,6 +13,7 @@ use self::TypeVariableValue::*;
 use self::UndoEntry::*;
 use hir::def_id::{DefId};
 use syntax::util::small_vector::SmallVector;
+use syntax::ast;
 use syntax_pos::Span;
 use ty::{self, Ty};
 
@@ -28,8 +29,24 @@ pub struct TypeVariableTable<'tcx> {
     eq_relations: ut::UnificationTable<ty::TyVid>,
 }
 
+/// Reasons to create a type inference variable
+pub enum TypeVariableOrigin {
+    MiscVariable(Span),
+    NormalizeProjectionType(Span),
+    TypeInference(Span),
+    TypeParameterDefinition(Span, ast::Name),
+    TransformedUpvar(Span),
+    SubstitutionPlaceholder(Span),
+    AutoDeref(Span),
+    AdjustmentType(Span),
+    DivergingStmt(Span),
+    DivergingBlockExpr(Span),
+    LatticeVariable(Span),
+}
+
 struct TypeVariableData<'tcx> {
     value: TypeVariableValue<'tcx>,
+    origin: TypeVariableOrigin,
     diverging: bool
 }
 
@@ -107,6 +124,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
         self.values.get(vid.index as usize).diverging
     }
 
+    pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
+        &self.values.get(vid.index as usize).origin
+    }
+
     /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`.
     ///
     /// Precondition: neither `a` nor `b` are known.
@@ -173,10 +194,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
 
     pub fn new_var(&mut self,
                    diverging: bool,
-                   default: Option<Default<'tcx>>) -> ty::TyVid {
+                   origin: TypeVariableOrigin,
+                   default: Option<Default<'tcx>>,) -> ty::TyVid {
         self.eq_relations.new_key(());
         let index = self.values.push(TypeVariableData {
             value: Bounded { relations: vec![], default: default },
+            origin: origin,
             diverging: diverging
         });
         let v = ty::TyVid { index: index as u32 };
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 76a5e2764f2..0c0d0c010e2 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -27,6 +27,7 @@ use super::{
 use fmt_macros::{Parser, Piece, Position};
 use hir::def_id::DefId;
 use infer::{self, InferCtxt};
+use infer::type_variable::TypeVariableOrigin;
 use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::error::ExpectedFound;
@@ -38,7 +39,7 @@ use util::nodemap::{FxHashMap, FxHashSet};
 use std::cmp;
 use std::fmt;
 use syntax::ast;
-use syntax_pos::Span;
+use syntax_pos::{DUMMY_SP, Span};
 use errors::DiagnosticBuilder;
 
 #[derive(Debug, PartialEq, Eq, Hash)]
@@ -790,9 +791,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx }
 
             fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-                if let ty::TyParam(..) = ty.sty {
+                if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty {
                     let infcx = self.infcx;
-                    self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var())
+                    self.var_map.entry(ty).or_insert_with(||
+                        infcx.next_ty_var(
+                            TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name)))
                 } else {
                     ty.super_fold_with(self)
                 }
@@ -824,12 +827,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
 
     fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
+        let ty = self.resolve_type_vars_if_possible(&ty);
+        let name = if let ty::TyInfer(ty::TyVar(ty_vid)) = ty.sty {
+            let ty_vars = self.type_variables.borrow();
+            if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
+                    *ty_vars.var_origin(ty_vid)
+            {
+                name.to_string()
+            } else {
+                ty.to_string()
+            }
+        } else {
+            ty.to_string()
+        };
+
         let mut err = struct_span_err!(self.tcx.sess, span, E0282,
                                        "unable to infer enough type information about `{}`",
-                                       ty);
+                                       name);
         err.note("type annotations or generic parameter binding required");
-        err.span_label(span, &format!("cannot infer type for `{}`", ty));
-        err.emit()
+        err.span_label(span, &format!("cannot infer type for `{}`", name));
+        err.emit();
     }
 
     fn note_obligation_cause<T>(&self,
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 173f2a0299d..6f645b5f94d 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -25,6 +25,7 @@ use super::util;
 
 use hir::def_id::DefId;
 use infer::InferOk;
+use infer::type_variable::TypeVariableOrigin;
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::ast;
 use syntax::symbol::Symbol;
@@ -382,7 +383,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             // and a deferred predicate to resolve this when more type
             // information is available.
 
-            let ty_var = selcx.infcx().next_ty_var();
+            let tcx = selcx.infcx().tcx;
+            let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
+                i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type
+            ).map(|i| i.def_id).unwrap();
+            let ty_var = selcx.infcx().next_ty_var(
+                TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
             let projection = ty::Binder(ty::ProjectionPredicate {
                 projection_ty: projection_ty,
                 ty: ty_var
@@ -596,7 +602,12 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
     let trait_obligation = Obligation { cause: cause,
                                         recursion_depth: depth,
                                         predicate: trait_ref.to_predicate() };
-    let new_value = selcx.infcx().next_ty_var();
+    let tcx = selcx.infcx().tcx;
+    let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
+        i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type
+    ).map(|i| i.def_id).unwrap();
+    let new_value = selcx.infcx().next_ty_var(
+        TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
     Normalized {
         value: new_value,
         obligations: vec![trait_obligation]
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index b7cebe31073..2f8550e5acd 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -24,6 +24,7 @@ use rustc::ty::subst::{Kind, Subst};
 use rustc::traits::{ObligationCause, Reveal};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::infer::{self, InferOk, InferResult};
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::session::{self, config};
@@ -36,6 +37,7 @@ use errors::emitter::Emitter;
 use errors::{Level, DiagnosticBuilder};
 use syntax::feature_gate::UnstableFeatures;
 use syntax::symbol::Symbol;
+use syntax_pos::DUMMY_SP;
 
 use rustc::hir;
 
@@ -489,7 +491,7 @@ fn sub_free_bound_false_infer() {
     //! does NOT hold for any instantiation of `_#1`.
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_infer1 = env.infcx.next_ty_var();
+        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
                           env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
@@ -508,7 +510,7 @@ fn lub_free_bound_infer() {
 
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         env.create_simple_region_hierarchy();
-        let t_infer1 = env.infcx.next_ty_var();
+        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(1, 1);
         env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
@@ -628,7 +630,7 @@ fn glb_bound_free() {
 fn glb_bound_free_infer() {
     test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let t_rptr_bound1 = env.t_rptr_late_bound(1);
-        let t_infer1 = env.infcx.next_ty_var();
+        let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
 
         // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
         // which should yield for<'b> fn(&'b isize) -> isize
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 15f383c5787..624201eaab6 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -12,6 +12,7 @@ use rustc::hir::{self, PatKind};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::infer;
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::traits::ObligationCauseCode;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
 use check::{FnCtxt, Expectation, Diverges};
@@ -162,7 +163,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 let max_len = cmp::max(expected_len, elements.len());
 
-                let element_tys_iter = (0..max_len).map(|_| self.next_ty_var());
+                let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(
+                    // FIXME: MiscVariable for now, obtaining the span and name information
+                    //       from all tuple elements isn't trivial.
+                    TypeVariableOrigin::TypeInference(pat.span)));
                 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);
@@ -172,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 pat_ty
             }
             PatKind::Box(ref inner) => {
-                let inner_ty = self.next_ty_var();
+                let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
                 let uniq_ty = tcx.mk_box(inner_ty);
 
                 if self.check_dereferencable(pat.span, expected, &inner) {
@@ -203,7 +207,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             (expected, mt.ty)
                         }
                         _ => {
-                            let inner_ty = self.next_ty_var();
+                            let inner_ty = self.next_ty_var(
+                                TypeVariableOrigin::TypeInference(inner.span));
                             let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
                             let region = self.next_region_var(infer::PatternRegion(pat.span));
                             let rptr_ty = tcx.mk_ref(region, mt);
@@ -379,7 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
             // `check_pat` for some details.
-            discrim_ty = self.next_ty_var();
+            discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
             self.check_expr_has_type(discrim, discrim_ty);
         };
         let discrim_diverges = self.diverges.get();
@@ -407,7 +412,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // of execution reach it, we will panic, so bottom is an appropriate
         // type in that case)
         let expected = expected.adjust_for_branches(self);
-        let mut result_ty = self.next_diverging_ty_var();
+        let mut result_ty = self.next_diverging_ty_var(
+            TypeVariableOrigin::DivergingBlockExpr(expr.span));
         let mut all_arms_diverge = Diverges::WarnedAlways;
         let coerce_first = match expected {
             // We don't coerce to `()` so that if the match expression is a
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 142a8b97111..1d81ed7d359 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -13,6 +13,7 @@
 use super::{check_fn, Expectation, FnCtxt};
 
 use astconv::AstConv;
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::ty::{self, ToPolyTraitRef, Ty};
 use std::cmp;
 use std::iter;
@@ -66,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let closure_type = self.tcx.mk_closure(expr_def_id,
             self.parameter_environment.free_substs.extend_to(self.tcx, expr_def_id,
                 |_, _| span_bug!(expr.span, "closure has region param"),
-                |_, _| self.infcx.next_ty_var()
+                |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
             )
         );
 
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index b0787d75c9c..5cb0804b1bc 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -20,6 +20,7 @@ use rustc::infer::InferOk;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
 use syntax::ast;
 use syntax_pos::Span;
@@ -1225,7 +1226,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         let substs = Substs::for_item(self.tcx,
                                       impl_def_id,
                                       |_, _| self.tcx.mk_region(ty::ReErased),
-                                      |_, _| self.next_ty_var());
+                                      |_, _| self.next_ty_var(
+                                        TypeVariableOrigin::SubstitutionPlaceholder(
+                                            self.tcx.def_span(impl_def_id))));
 
         (impl_ty, substs)
     }
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 7cfefefc0d9..86bfede87b3 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -28,6 +28,7 @@ use syntax_pos::Span;
 
 use rustc::hir::print as pprust;
 use rustc::hir;
+use rustc::infer::type_variable::TypeVariableOrigin;
 
 use std::cell;
 use std::cmp::Ordering;
@@ -53,7 +54,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 self.autoderef(span, ty).any(|(ty, _)| {
                     self.probe(|_| {
-                        let fn_once_substs = tcx.mk_substs_trait(ty, &[self.next_ty_var()]);
+                        let fn_once_substs = tcx.mk_substs_trait(ty,
+                            &[self.next_ty_var(TypeVariableOrigin::MiscVariable(span))]);
                         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 9c8d7caefe5..58dff935a16 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -85,8 +85,8 @@ use dep_graph::DepNode;
 use fmt_macros::{Parser, Piece, Position};
 use hir::def::{Def, CtorKind};
 use hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin,
-                   TypeTrace, type_variable};
+use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace};
+use rustc::infer::type_variable::{self, TypeVariableOrigin};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
@@ -117,7 +117,7 @@ use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, InternedString, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{self, BytePos, Span};
+use syntax_pos::{self, BytePos, Span, DUMMY_SP};
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -683,11 +683,11 @@ struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 }
 
 impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> {
-    fn assign(&mut self, _span: Span, nid: ast::NodeId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
+    fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
         match ty_opt {
             None => {
                 // infer the variable's type
-                let var_ty = self.fcx.next_ty_var();
+                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
                 self.fcx.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
@@ -1444,8 +1444,8 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
         Ok(r)
     }
 
-    fn ty_infer(&self, _span: Span) -> Ty<'tcx> {
-        self.next_ty_var()
+    fn ty_infer(&self, span: Span) -> Ty<'tcx> {
+        self.next_ty_var(TypeVariableOrigin::TypeInference(span))
     }
 
     fn ty_infer_for_def(&self,
@@ -1751,13 +1751,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
                     return ty_var;
                 }
-                let ty_var = self.next_ty_var();
+                let span = self.tcx.def_span(def_id);
+                let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
                 self.anon_types.borrow_mut().insert(def_id, ty_var);
 
                 let item_predicates = self.tcx.item_predicates(def_id);
                 let bounds = item_predicates.instantiate(self.tcx, substs);
 
-                let span = self.tcx.def_span(def_id);
                 for predicate in bounds.predicates {
                     // Change the predicate to refer to the type variable,
                     // which will be the concrete type, instead of the TyAnon.
@@ -2204,7 +2204,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let conflicting_default =
                         self.find_conflicting_default(&unbound_tyvars, &default_map, conflict)
                             .unwrap_or(type_variable::Default {
-                                ty: self.next_ty_var(),
+                                ty: self.next_ty_var(
+                                    TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)),
                                 origin_span: syntax_pos::DUMMY_SP,
                                 // what do I put here?
                                 def_id: self.tcx.map.local_def_id(ast::CRATE_NODE_ID)
@@ -2398,7 +2399,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                unsize,
                index_ty);
 
-        let input_ty = self.next_ty_var();
+        let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span));
 
         // First, try built-in indexing.
         match (adjusted_ty.builtin_index(), &index_ty.sty) {
@@ -3486,8 +3487,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Add adjustments to !-expressions
         if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
-                let adj_ty = self.next_diverging_ty_var();
+            if let Some(hir::map::NodeExpr(node_expr)) = self.tcx.map.find(expr.id) {
+                let adj_ty = self.next_diverging_ty_var(
+                    TypeVariableOrigin::AdjustmentType(node_expr.span));
                 self.write_adjustment(expr.id, adjustment::Adjustment {
                     kind: adjustment::Adjust::NeverToAny,
                     target: adj_ty
@@ -3781,7 +3783,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
           }
           hir::ExprLoop(ref body, _, _) => {
-            let unified = self.next_ty_var();
+            let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(body.span));
             let coerce_to = expected.only_has_type(self).unwrap_or(unified);
             let ctxt = LoopCtxt {
                 unified: unified,
@@ -3860,7 +3862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
 
-            let mut unified = self.next_ty_var();
+            let mut unified = self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span));
             let coerce_to = uty.unwrap_or(unified);
 
             for (i, e) in args.iter().enumerate() {
@@ -3905,7 +3907,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     (uty, uty)
                 }
                 None => {
-                    let t: Ty = self.next_ty_var();
+                    let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span));
                     let element_ty = self.check_expr_has_type(&element, t);
                     (element_ty, t)
                 }
@@ -4154,31 +4156,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.diverges.set(Diverges::Maybe);
         self.has_errors.set(false);
 
-        let node_id = match stmt.node {
+        let (node_id, span) = match stmt.node {
             hir::StmtDecl(ref decl, id) => {
-                match decl.node {
+                let span = match decl.node {
                     hir::DeclLocal(ref l) => {
                         self.check_decl_local(&l);
+                        l.span
                     }
-                    hir::DeclItem(_) => {/* ignore for now */ }
-                }
-                id
+                    hir::DeclItem(_) => {/* ignore for now */
+                        DUMMY_SP
+                    }
+                };
+                (id, span)
             }
             hir::StmtExpr(ref expr, id) => {
                 // Check with expected type of ()
                 self.check_expr_has_type(&expr, self.tcx.mk_nil());
-                id
+                (id, expr.span)
             }
             hir::StmtSemi(ref expr, id) => {
                 self.check_expr(&expr);
-                id
+                (id, expr.span)
             }
         };
 
         if self.has_errors.get() {
             self.write_error(node_id);
         } else if self.diverges.get().always() {
-            self.write_ty(node_id, self.next_diverging_ty_var());
+            self.write_ty(node_id, self.next_diverging_ty_var(
+                TypeVariableOrigin::DivergingStmt(span)));
         } else {
             self.write_nil(node_id);
         }
@@ -4224,7 +4230,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
 
-            ty = self.next_diverging_ty_var();
+            ty = self.next_diverging_ty_var(TypeVariableOrigin::DivergingBlockExpr(blk.span));
         } else if let ExpectHasType(ety) = expected {
             if let Some(ref e) = blk.expr {
                 // Coerce the tail expression to the right type.
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index adb8c6be42b..d1a9b8ef85a 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -13,6 +13,7 @@
 use super::FnCtxt;
 use hir::def_id::DefId;
 use rustc::ty::{Ty, TypeFoldable, PreferMutLvalue};
+use rustc::infer::type_variable::TypeVariableOrigin;
 use syntax::ast;
 use syntax::symbol::Symbol;
 use rustc::hir;
@@ -179,7 +180,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // using this variable as the expected type, which sometimes lets
         // us do better coercions than we would be able to do otherwise,
         // particularly for things like `String + &String`.
-        let rhs_ty_var = self.next_ty_var();
+        let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
 
         let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
                                                     Symbol::intern(name), trait_def_id,
diff --git a/src/test/compile-fail/issue-23046.rs b/src/test/compile-fail/issue-23046.rs
index dba9c32f9b4..c274665530f 100644
--- a/src/test/compile-fail/issue-23046.rs
+++ b/src/test/compile-fail/issue-23046.rs
@@ -25,6 +25,6 @@ pub fn let_<'var, VAR, F: for<'v: 'var> Fn(Expr<'v, VAR>) -> Expr<'v, VAR>>
 
 fn main() {
     let ex = |x| {
-        let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `_`
+        let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `VAR`
             let_(add(x, x), |x|x)})};
 }
diff --git a/src/test/compile-fail/issue-5062.rs b/src/test/compile-fail/issue-5062.rs
index f5aa4fadbed..cf78d6d8c0a 100644
--- a/src/test/compile-fail/issue-5062.rs
+++ b/src/test/compile-fail/issue-5062.rs
@@ -9,4 +9,4 @@
 // except according to those terms.
 
 fn main() { format!("{:?}", None); }
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
+    //~^ ERROR unable to infer enough type information about `T` [E0282]
diff --git a/src/test/compile-fail/issue-6458-2.rs b/src/test/compile-fail/issue-6458-2.rs
index 71f28054579..3816896d43d 100644
--- a/src/test/compile-fail/issue-6458-2.rs
+++ b/src/test/compile-fail/issue-6458-2.rs
@@ -11,5 +11,5 @@
 fn main() {
     // Unconstrained type:
     format!("{:?}", None);
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
+    //~^ ERROR unable to infer enough type information about `T` [E0282]
 }
diff --git a/src/test/compile-fail/issue-6458-3.rs b/src/test/compile-fail/issue-6458-3.rs
index e397805565b..8029522f5d3 100644
--- a/src/test/compile-fail/issue-6458-3.rs
+++ b/src/test/compile-fail/issue-6458-3.rs
@@ -12,7 +12,7 @@ use std::mem;
 
 fn main() {
     mem::transmute(0);
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
-    //~| NOTE cannot infer type for `_`
+    //~^ ERROR unable to infer enough type information about `U` [E0282]
+    //~| NOTE cannot infer type for `U`
     //~| NOTE type annotations or generic parameter binding
 }
diff --git a/src/test/compile-fail/issue-6458.rs b/src/test/compile-fail/issue-6458.rs
index a64522a0e5b..f8354ddbf12 100644
--- a/src/test/compile-fail/issue-6458.rs
+++ b/src/test/compile-fail/issue-6458.rs
@@ -17,8 +17,8 @@ pub fn foo<State>(_: TypeWithState<State>) {}
 
 pub fn bar() {
    foo(TypeWithState(marker::PhantomData));
-   //~^ ERROR unable to infer enough type information about `_` [E0282]
-   //~| NOTE cannot infer type for `_`
+   //~^ ERROR unable to infer enough type information about `State` [E0282]
+   //~| NOTE cannot infer type for `State`
    //~| NOTE type annotations or generic parameter binding
 }
 
diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs
index e3cb1d0c7da..e37a8816423 100644
--- a/src/test/compile-fail/issue-7813.rs
+++ b/src/test/compile-fail/issue-7813.rs
@@ -10,7 +10,7 @@
 
 fn main() {
     let v = &[];
-    let it = v.iter(); //~ ERROR unable to infer enough type information about `_` [E0282]
-                       //~| NOTE cannot infer type for `_`
+    let it = v.iter(); //~ ERROR unable to infer enough type information about `T` [E0282]
+                       //~| NOTE cannot infer type for `T`
                        //~| NOTE type annotations or generic parameter binding
 }
diff --git a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs
index 4f86909765e..1cf41f95a2d 100644
--- a/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs
+++ b/src/test/compile-fail/method-ambig-one-trait-unknown-int-type.rs
@@ -32,7 +32,7 @@ impl foo for Vec<isize> {
 fn m1() {
     // we couldn't infer the type of the vector just based on calling foo()...
     let mut x = Vec::new();
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
+    //~^ ERROR unable to infer enough type information about `T` [E0282]
     x.foo();
 }
 
diff --git a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs
index e6545063dbd..ed2ffa995e5 100644
--- a/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs
+++ b/src/test/compile-fail/traits-multidispatch-convert-ambig-dest.rs
@@ -34,8 +34,8 @@ where T : Convert<U>
 
 fn a() {
     test(22, std::default::Default::default());
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
-    //~| NOTE cannot infer type for `_`
+    //~^ ERROR unable to infer enough type information about `U` [E0282]
+    //~| NOTE cannot infer type for `U`
     //~| NOTE type annotations or generic parameter binding
 }
 
diff --git a/src/test/compile-fail/unconstrained-none.rs b/src/test/compile-fail/unconstrained-none.rs
index 380cdd266cd..88080bc70ca 100644
--- a/src/test/compile-fail/unconstrained-none.rs
+++ b/src/test/compile-fail/unconstrained-none.rs
@@ -11,7 +11,7 @@
 // Issue #5062
 
 fn main() {
-    None; //~ ERROR unable to infer enough type information about `_` [E0282]
-          //~| NOTE cannot infer type for `_`
+    None; //~ ERROR unable to infer enough type information about `T` [E0282]
+          //~| NOTE cannot infer type for `T`
           //~| NOTE type annotations or generic parameter binding
 }
diff --git a/src/test/compile-fail/unconstrained-ref.rs b/src/test/compile-fail/unconstrained-ref.rs
index ba94bf613d2..12278549215 100644
--- a/src/test/compile-fail/unconstrained-ref.rs
+++ b/src/test/compile-fail/unconstrained-ref.rs
@@ -13,7 +13,7 @@ struct S<'a, T:'a> {
 }
 
 fn main() {
-    S { o: &None }; //~ ERROR unable to infer enough type information about `_` [E0282]
-                    //~| NOTE cannot infer type for `_`
+    S { o: &None }; //~ ERROR unable to infer enough type information about `T` [E0282]
+                    //~| NOTE cannot infer type for `T`
                     //~| NOTE type annotations or generic parameter binding
 }
diff --git a/src/test/compile-fail/vector-no-ann.rs b/src/test/compile-fail/vector-no-ann.rs
index 25709f35246..d559caf77a1 100644
--- a/src/test/compile-fail/vector-no-ann.rs
+++ b/src/test/compile-fail/vector-no-ann.rs
@@ -11,7 +11,7 @@
 
 fn main() {
     let _foo = Vec::new();
-    //~^ ERROR unable to infer enough type information about `_` [E0282]
-    //~| NOTE cannot infer type for `_`
+    //~^ ERROR unable to infer enough type information about `T` [E0282]
+    //~| NOTE cannot infer type for `T`
     //~| NOTE type annotations or generic parameter binding
 }
diff --git a/src/test/ui/codemap_tests/repair_span_std_macros.stderr b/src/test/ui/codemap_tests/repair_span_std_macros.stderr
index 73a1c5bae85..7e0d778a3b2 100644
--- a/src/test/ui/codemap_tests/repair_span_std_macros.stderr
+++ b/src/test/ui/codemap_tests/repair_span_std_macros.stderr
@@ -1,8 +1,8 @@
-error[E0282]: unable to infer enough type information about `_`
+error[E0282]: unable to infer enough type information about `T`
   --> $DIR/repair_span_std_macros.rs:12:13
    |
 12 |     let x = vec![];
-   |             ^^^^^^ cannot infer type for `_`
+   |             ^^^^^^ cannot infer type for `T`
    |
    = note: type annotations or generic parameter binding required
    = note: this error originates in a macro outside of the current crate
diff --git a/src/test/ui/missing-items/missing-type-parameter.rs b/src/test/ui/missing-items/missing-type-parameter.rs
new file mode 100644
index 00000000000..3671abd6624
--- /dev/null
+++ b/src/test/ui/missing-items/missing-type-parameter.rs
@@ -0,0 +1,15 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo<X>() { }
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/missing-items/missing-type-parameter.stderr b/src/test/ui/missing-items/missing-type-parameter.stderr
new file mode 100644
index 00000000000..2d007af4980
--- /dev/null
+++ b/src/test/ui/missing-items/missing-type-parameter.stderr
@@ -0,0 +1,10 @@
+error[E0282]: unable to infer enough type information about `X`
+  --> $DIR/missing-type-parameter.rs:14:5
+   |
+14 |     foo();
+   |     ^^^ cannot infer type for `X`
+   |
+   = note: type annotations or generic parameter binding required
+
+error: aborting due to previous error
+