about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/combine.rs2
-rw-r--r--src/librustc/infer/error_reporting.rs75
-rw-r--r--src/librustc/infer/higher_ranked/mod.rs14
-rw-r--r--src/librustc/infer/mod.rs181
-rw-r--r--src/librustc/infer/sub.rs1
-rw-r--r--src/librustc/traits/coherence.rs10
-rw-r--r--src/librustc/traits/error_reporting.rs24
-rw-r--r--src/librustc/traits/fulfill.rs2
-rw-r--r--src/librustc/traits/mod.rs30
-rw-r--r--src/librustc/traits/project.rs15
-rw-r--r--src/librustc/traits/select.rs29
-rw-r--r--src/librustc/traits/specialize/mod.rs8
-rw-r--r--src/librustc/traits/structural_impls.rs46
-rw-r--r--src/librustc_driver/test.rs7
-rw-r--r--src/librustc_mir/transform/type_check.rs18
-rw-r--r--src/librustc_typeck/check/_match.rs18
-rw-r--r--src/librustc_typeck/check/coercion.rs27
-rw-r--r--src/librustc_typeck/check/compare_method.rs68
-rw-r--r--src/librustc_typeck/check/demand.rs21
-rw-r--r--src/librustc_typeck/check/dropck.rs6
-rw-r--r--src/librustc_typeck/check/intrinsic.rs6
-rw-r--r--src/librustc_typeck/check/method/confirm.rs4
-rw-r--r--src/librustc_typeck/check/method/probe.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs81
-rw-r--r--src/librustc_typeck/check/regionck.rs5
-rw-r--r--src/librustc_typeck/check/wfcheck.rs13
-rw-r--r--src/librustc_typeck/coherence/mod.rs10
-rw-r--r--src/librustc_typeck/lib.rs14
28 files changed, 389 insertions, 354 deletions
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 641273d2b76..5d33d6e6d2e 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -274,7 +274,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
     {
         let mut generalize = Generalizer {
             infcx: self.infcx,
-            span: self.trace.origin.span(),
+            span: self.trace.cause.span,
             for_vid: for_vid,
             make_region_vars: make_region_vars,
             cycle_detected: false
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index d8a7ce72f50..58caac4034e 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -80,8 +80,9 @@ use hir::print as pprust;
 use lint;
 use hir::def::Def;
 use hir::def_id::DefId;
-use infer::{self, TypeOrigin};
+use infer;
 use middle::region;
+use traits::{ObligationCause, ObligationCauseCode};
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::{Region, ReFree};
 use ty::error::TypeError;
@@ -524,10 +525,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     fn note_error_origin(&self,
                          err: &mut DiagnosticBuilder<'tcx>,
-                         origin: &TypeOrigin)
+                         cause: &ObligationCause<'tcx>)
     {
-        match origin {
-            &TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
+        match cause.code {
+            ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
                 hir::MatchSource::IfLetDesugar {..} => {
                     err.span_note(arm_span, "`if let` arm with an incompatible type");
                 }
@@ -541,7 +542,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn note_type_err(&self,
                          diag: &mut DiagnosticBuilder<'tcx>,
-                         origin: TypeOrigin,
+                         cause: &ObligationCause<'tcx>,
                          secondary_span: Option<(Span, String)>,
                          values: Option<ValuePairs<'tcx>>,
                          terr: &TypeError<'tcx>)
@@ -558,7 +559,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         };
 
-        let span = origin.span();
+        let span = cause.span;
 
         if let Some((expected, found)) = expected_found {
             let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
@@ -588,7 +589,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             diag.span_label(sp, &msg);
         }
 
-        self.note_error_origin(diag, &origin);
+        self.note_error_origin(diag, &cause);
         self.check_and_note_conflicting_crates(diag, terr, span);
         self.tcx.note_and_explain_type_err(diag, terr, span);
     }
@@ -598,17 +599,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          terr: &TypeError<'tcx>)
                                          -> DiagnosticBuilder<'tcx>
     {
-        let span = trace.origin.span();
-        let failure_str = trace.origin.as_failure_str();
-        let mut diag = match trace.origin {
-            TypeOrigin::IfExpressionWithNoElse(_) => {
+        let span = trace.cause.span;
+        let failure_str = trace.cause.as_failure_str();
+        let mut diag = match trace.cause.code {
+            ObligationCauseCode::IfExpressionWithNoElse => {
                 struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
             },
             _ => {
                 struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
             },
         };
-        self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
+        self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
         diag
     }
 
@@ -1695,18 +1696,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 if let Some((expected, found)) = self.values_str(&trace.values) {
                     // FIXME: do we want a "the" here?
                     err.span_note(
-                        trace.origin.span(),
+                        trace.cause.span,
                         &format!("...so that {} (expected {}, found {})",
-                                 trace.origin.as_requirement_str(), expected, found));
+                                 trace.cause.as_requirement_str(), expected, found));
                 } else {
                     // FIXME: this really should be handled at some earlier stage. Our
                     // handling of region checking when type errors are present is
                     // *terrible*.
 
                     err.span_note(
-                        trace.origin.span(),
+                        trace.cause.span,
                         &format!("...so that {}",
-                                 trace.origin.as_requirement_str()));
+                                 trace.cause.as_requirement_str()));
                 }
             }
             infer::Reborrow(span) => {
@@ -1961,3 +1962,45 @@ fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
                     span: syntax_pos::DUMMY_SP,
                     name: name }
 }
+
+impl<'tcx> ObligationCause<'tcx> {
+    fn as_failure_str(&self) -> &'static str {
+        use traits::ObligationCauseCode::*;
+        match self.code {
+            CompareImplMethodObligation { .. } => "method not compatible with trait",
+            MatchExpressionArm { source, .. } => match source {
+                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
+                _ => "match arms have incompatible types",
+            },
+            IfExpression => "if and else have incompatible types",
+            IfExpressionWithNoElse => "if may be missing an else clause",
+            EquatePredicate => "equality predicate not satisfied",
+            MainFunctionType => "main function has wrong type",
+            StartFunctionType => "start function has wrong type",
+            IntrinsicType => "intrinsic has wrong type",
+            MethodReceiver => "mismatched method receiver",
+            _ => "mismatched types",
+        }
+    }
+
+    fn as_requirement_str(&self) -> &'static str {
+        use traits::ObligationCauseCode::*;
+        match self.code {
+            CompareImplMethodObligation { .. } => "method type is compatible with trait",
+            ExprAssignable => "expression is assignable",
+            MatchExpressionArm { source, .. } => match source {
+                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
+                _ => "match arms have compatible types",
+            },
+            IfExpression => "if and else have compatible types",
+            IfExpressionWithNoElse => "if missing an else returns ()",
+            EquatePredicate => "equality where clause is satisfied",
+            MainFunctionType => "`main` function has the correct type",
+            StartFunctionType => "`start` function has the correct type",
+            IntrinsicType => "intrinsic has the correct type",
+            MethodReceiver => "method receiver has the correct type",
+            _ => "types are compatible",
+        }
+    }
+}
+
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 737ce8bdf68..08e522f5fd6 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
         // Start a snapshot so we can examine "all bindings that were
         // created as part of this type comparison".
         return self.infcx.commit_if_ok(|snapshot| {
-            let span = self.trace.origin.span();
+            let span = self.trace.cause.span;
 
             // First, we instantiate each bound region in the subtype with a fresh
             // region variable.
@@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
         // created as part of this type comparison".
         return self.infcx.commit_if_ok(|snapshot| {
             // Instantiate each bound region with a fresh region variable.
-            let span = self.trace.origin.span();
+            let span = self.trace.cause.span;
             let (a_with_fresh, a_map) =
                 self.infcx.replace_late_bound_regions_with_fresh_var(
                     span, HigherRankedType, a);
@@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
             // Generalize the regions appearing in result0 if possible
             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
-            let span = self.trace.origin.span();
+            let span = self.trace.cause.span;
             let result1 =
                 fold_regions_in(
                     self.tcx(),
@@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
             // Instantiate each bound region with a fresh region variable.
             let (a_with_fresh, a_map) =
                 self.infcx.replace_late_bound_regions_with_fresh_var(
-                    self.trace.origin.span(), HigherRankedType, a);
+                    self.trace.cause.span, HigherRankedType, a);
             let (b_with_fresh, b_map) =
                 self.infcx.replace_late_bound_regions_with_fresh_var(
-                    self.trace.origin.span(), HigherRankedType, b);
+                    self.trace.cause.span, HigherRankedType, b);
             let a_vars = var_ids(self, &a_map);
             let b_vars = var_ids(self, &b_map);
 
@@ -341,7 +341,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
 
             // Generalize the regions appearing in result0 if possible
             let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
-            let span = self.trace.origin.span();
+            let span = self.trace.cause.span;
             let result1 =
                 fold_regions_in(
                     self.tcx(),
@@ -463,7 +463,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
            ty::ReVar(r) => { r }
            _ => {
                span_bug!(
-                   fields.trace.origin.span(),
+                   fields.trace.cause.span,
                    "found non-region-vid: {:?}",
                    r);
            }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 2d4b36ec187..6ae104d7912 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -32,7 +32,7 @@ use ty::{self, Ty, TyCtxt};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use ty::relate::{Relate, RelateResult, TypeRelation};
-use traits::{self, PredicateObligations, Reveal};
+use traits::{self, ObligationCause, PredicateObligations, Reveal};
 use rustc_data_structures::unify::{self, UnificationTable};
 use std::cell::{Cell, RefCell, Ref, RefMut};
 use std::fmt;
@@ -173,89 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 /// region that each late-bound region was replaced with.
 pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, &'tcx ty::Region>;
 
-/// Why did we require that the two types be related?
-///
-/// See `error_reporting.rs` for more details
-#[derive(Clone, Copy, Debug)]
-pub enum TypeOrigin {
-    // Not yet categorized in a better way
-    Misc(Span),
-
-    // Checking that method of impl is compatible with trait
-    MethodCompatCheck(Span),
-
-    // Checking that this expression can be assigned where it needs to be
-    ExprAssignable(Span),
-
-    // Relating trait type parameters to those found in impl etc
-    RelateOutputImplTypes(Span),
-
-    // Computing common supertype in the arms of a match expression
-    MatchExpressionArm(Span, Span, hir::MatchSource),
-
-    // Computing common supertype in an if expression
-    IfExpression(Span),
-
-    // Computing common supertype of an if expression with no else counter-part
-    IfExpressionWithNoElse(Span),
-
-    // `where a == b`
-    EquatePredicate(Span),
-
-    // `main` has wrong type
-    MainFunctionType(Span),
-
-    // `start` has wrong type
-    StartFunctionType(Span),
-
-    // intrinsic has wrong type
-    IntrinsicType(Span),
-
-    // method receiver
-    MethodReceiver(Span),
-}
-
-impl TypeOrigin {
-    fn as_failure_str(&self) -> &'static str {
-        match self {
-            &TypeOrigin::Misc(_) |
-            &TypeOrigin::RelateOutputImplTypes(_) |
-            &TypeOrigin::ExprAssignable(_) => "mismatched types",
-            &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
-            &TypeOrigin::MatchExpressionArm(.., source) => match source {
-                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
-                _ => "match arms have incompatible types",
-            },
-            &TypeOrigin::IfExpression(_) => "if and else have incompatible types",
-            &TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
-            &TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
-            &TypeOrigin::MainFunctionType(_) => "main function has wrong type",
-            &TypeOrigin::StartFunctionType(_) => "start function has wrong type",
-            &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
-            &TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
-        }
-    }
-
-    fn as_requirement_str(&self) -> &'static str {
-        match self {
-            &TypeOrigin::Misc(_) => "types are compatible",
-            &TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
-            &TypeOrigin::ExprAssignable(_) => "expression is assignable",
-            &TypeOrigin::RelateOutputImplTypes(_) => {
-                "trait type parameters matches those specified on the impl"
-            }
-            &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types",
-            &TypeOrigin::IfExpression(_) => "if and else have compatible types",
-            &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
-            &TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
-            &TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
-            &TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
-            &TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
-            &TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
-        }
-    }
-}
-
 /// See `error_reporting.rs` for more details
 #[derive(Clone, Debug)]
 pub enum ValuePairs<'tcx> {
@@ -270,7 +187,7 @@ pub enum ValuePairs<'tcx> {
 /// See `error_reporting.rs` for more details.
 #[derive(Clone)]
 pub struct TypeTrace<'tcx> {
-    origin: TypeOrigin,
+    cause: ObligationCause<'tcx>,
     values: ValuePairs<'tcx>,
 }
 
@@ -1006,14 +923,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn sub_types(&self,
                      a_is_expected: bool,
-                     origin: TypeOrigin,
+                     cause: &ObligationCause<'tcx>,
                      a: Ty<'tcx>,
                      b: Ty<'tcx>)
         -> InferResult<'tcx, ()>
     {
         debug!("sub_types({:?} <: {:?})", a, b);
         self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(origin, a_is_expected, a, b);
+            let trace = TypeTrace::types(cause, a_is_expected, a, b);
             self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
@@ -1024,7 +941,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                          -> UnitResult<'tcx>
     {
         self.probe(|_| {
-            let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP);
+            let origin = &ObligationCause::dummy();
             let trace = TypeTrace::types(origin, true, a, b);
             self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| {
                 // FIXME(#32730) propagate obligations
@@ -1035,20 +952,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn eq_types(&self,
                     a_is_expected: bool,
-                    origin: TypeOrigin,
+                    cause: &ObligationCause<'tcx>,
                     a: Ty<'tcx>,
                     b: Ty<'tcx>)
         -> InferResult<'tcx, ()>
     {
         self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(origin, a_is_expected, a, b);
+            let trace = TypeTrace::types(cause, a_is_expected, a, b);
             self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
         })
     }
 
     pub fn eq_trait_refs(&self,
                           a_is_expected: bool,
-                          origin: TypeOrigin,
+                          cause: &ObligationCause<'tcx>,
                           a: ty::TraitRef<'tcx>,
                           b: ty::TraitRef<'tcx>)
         -> InferResult<'tcx, ()>
@@ -1056,7 +973,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         debug!("eq_trait_refs({:?} = {:?})", a, b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace {
-                origin: origin,
+                cause: cause.clone(),
                 values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
             };
             self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
@@ -1065,22 +982,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     pub fn eq_impl_headers(&self,
                            a_is_expected: bool,
-                           origin: TypeOrigin,
+                           cause: &ObligationCause<'tcx>,
                            a: &ty::ImplHeader<'tcx>,
                            b: &ty::ImplHeader<'tcx>)
                            -> InferResult<'tcx, ()>
     {
         debug!("eq_impl_header({:?} = {:?})", a, b);
         match (a.trait_ref, b.trait_ref) {
-            (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, origin, a_ref, b_ref),
-            (None, None) => self.eq_types(a_is_expected, origin, a.self_ty, b.self_ty),
+            (Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref),
+            (None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty),
             _ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
         }
     }
 
     pub fn sub_poly_trait_refs(&self,
                                a_is_expected: bool,
-                               origin: TypeOrigin,
+                               cause: ObligationCause<'tcx>,
                                a: ty::PolyTraitRef<'tcx>,
                                b: ty::PolyTraitRef<'tcx>)
         -> InferResult<'tcx, ()>
@@ -1088,7 +1005,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         debug!("sub_poly_trait_refs({:?} <: {:?})", a, b);
         self.commit_if_ok(|_| {
             let trace = TypeTrace {
-                origin: origin,
+                cause: cause,
                 values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
             };
             self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
@@ -1104,16 +1021,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn equality_predicate(&self,
-                              span: Span,
+                              cause: &ObligationCause<'tcx>,
                               predicate: &ty::PolyEquatePredicate<'tcx>)
         -> InferResult<'tcx, ()>
     {
         self.commit_if_ok(|snapshot| {
             let (ty::EquatePredicate(a, b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
-            let origin = TypeOrigin::EquatePredicate(span);
-            let eqty_ok = self.eq_types(false, origin, a, b)?;
-            self.leak_check(false, span, &skol_map, snapshot)?;
+            let cause_span = cause.span;
+            let eqty_ok = self.eq_types(false, cause, a, b)?;
+            self.leak_check(false, cause_span, &skol_map, snapshot)?;
             self.pop_skolemized(skol_map, snapshot);
             Ok(eqty_ok.unit())
         })
@@ -1443,26 +1360,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn report_mismatched_types(&self,
-                                   origin: TypeOrigin,
+                                   cause: &ObligationCause<'tcx>,
                                    expected: Ty<'tcx>,
                                    actual: Ty<'tcx>,
                                    err: TypeError<'tcx>) {
-        let trace = TypeTrace {
-            origin: origin,
-            values: Types(ExpectedFound {
-                expected: expected,
-                found: actual
-            })
-        };
+        let trace = TypeTrace::types(cause, true, expected, actual);
         self.report_and_explain_type_error(trace, &err).emit();
     }
 
     pub fn report_conflicting_default_types(&self,
                                             span: Span,
+                                            body_id: ast::NodeId,
                                             expected: type_variable::Default<'tcx>,
                                             actual: type_variable::Default<'tcx>) {
         let trace = TypeTrace {
-            origin: TypeOrigin::Misc(span),
+            cause: ObligationCause::misc(span, body_id),
             values: Types(ExpectedFound {
                 expected: expected.ty,
                 found: actual.ty
@@ -1507,15 +1419,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
     /// details.
     pub fn match_poly_projection_predicate(&self,
-                                           origin: TypeOrigin,
+                                           cause: ObligationCause<'tcx>,
                                            match_a: ty::PolyProjectionPredicate<'tcx>,
                                            match_b: ty::TraitRef<'tcx>)
                                            -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
     {
-        let span = origin.span();
+        let span = cause.span;
         let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
         let trace = TypeTrace {
-            origin: origin,
+            cause: cause,
             values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b))
         };
 
@@ -1664,23 +1576,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
 impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
     pub fn span(&self) -> Span {
-        self.origin.span()
+        self.cause.span
     }
 
-    pub fn types(origin: TypeOrigin,
+    pub fn types(cause: &ObligationCause<'tcx>,
                  a_is_expected: bool,
                  a: Ty<'tcx>,
                  b: Ty<'tcx>)
                  -> TypeTrace<'tcx> {
         TypeTrace {
-            origin: origin,
+            cause: cause.clone(),
             values: Types(ExpectedFound::new(a_is_expected, a, b))
         }
     }
 
     pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> {
         TypeTrace {
-            origin: TypeOrigin::Misc(syntax_pos::DUMMY_SP),
+            cause: ObligationCause::dummy(),
             values: Types(ExpectedFound {
                 expected: tcx.types.err,
                 found: tcx.types.err,
@@ -1691,26 +1603,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
 
 impl<'tcx> fmt::Debug for TypeTrace<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "TypeTrace({:?})", self.origin)
-    }
-}
-
-impl TypeOrigin {
-    pub fn span(&self) -> Span {
-        match *self {
-            TypeOrigin::MethodCompatCheck(span) => span,
-            TypeOrigin::ExprAssignable(span) => span,
-            TypeOrigin::Misc(span) => span,
-            TypeOrigin::RelateOutputImplTypes(span) => span,
-            TypeOrigin::MatchExpressionArm(match_span, ..) => match_span,
-            TypeOrigin::IfExpression(span) => span,
-            TypeOrigin::IfExpressionWithNoElse(span) => span,
-            TypeOrigin::EquatePredicate(span) => span,
-            TypeOrigin::MainFunctionType(span) => span,
-            TypeOrigin::StartFunctionType(span) => span,
-            TypeOrigin::IntrinsicType(span) => span,
-            TypeOrigin::MethodReceiver(span) => span,
-        }
+        write!(f, "TypeTrace({:?})", self.cause)
     }
 }
 
@@ -1787,16 +1680,6 @@ impl RegionVariableOrigin {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
-        self.clone()
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
-        false
-    }
-}
-
 impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
@@ -1824,12 +1707,12 @@ impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
 impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         TypeTrace {
-            origin: self.origin.fold_with(folder),
+            cause: self.cause.fold_with(folder),
             values: self.values.fold_with(folder)
         }
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.origin.visit_with(visitor) || self.values.visit_with(visitor)
+        self.cause.visit_with(visitor) || self.values.visit_with(visitor)
     }
 }
diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs
index 159de2faced..5664777772f 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc/infer/sub.rs
@@ -111,6 +111,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
                -> RelateResult<'tcx, &'tcx ty::Region> {
         debug!("{}.regions({:?}, {:?}) self.cause={:?}",
                self.tag(), a, b, self.fields.cause);
+
         // FIXME -- we have more fine-grained information available
         // from the "cause" field, we could perhaps give more tailored
         // error messages.
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index 1ccd048cedc..2e06e83f848 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -14,8 +14,8 @@ use super::{SelectionContext, Obligation, ObligationCause};
 
 use hir::def_id::{DefId, LOCAL_CRATE};
 use ty::{self, Ty, TyCtxt};
-use infer::{InferCtxt, InferOk, TypeOrigin};
-use syntax_pos::DUMMY_SP;
+
+use infer::{InferCtxt, InferOk};
 
 #[derive(Copy, Clone)]
 struct InferIsLocal(bool);
@@ -55,8 +55,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     debug!("overlap: b_impl_header={:?}", b_impl_header);
 
     // Do `a` and `b` unify? If not, no overlap.
-    match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header,
-                                                                          &b_impl_header) {
+    match selcx.infcx().eq_impl_headers(true,
+                                        &ObligationCause::dummy(),
+                                        &a_impl_header,
+                                        &b_impl_header) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty());
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 7e70fdb92e6..e0a397ad28f 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -26,7 +26,7 @@ use super::{
 
 use fmt_macros::{Parser, Piece, Position};
 use hir::def_id::DefId;
-use infer::{self, InferCtxt, TypeOrigin};
+use infer::{self, InferCtxt};
 use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
 use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::error::ExpectedFound;
@@ -100,7 +100,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         self.probe(|_| {
-            let origin = TypeOrigin::Misc(obligation.cause.span);
             let err_buf;
             let mut err = &error.err;
             let mut values = None;
@@ -121,9 +120,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     obligation.cause.clone(),
                     0
                 );
-                let origin = TypeOrigin::Misc(obligation.cause.span);
                 if let Err(error) = self.eq_types(
-                    false, origin,
+                    false, &obligation.cause,
                     data.ty, normalized.value
                 ) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound {
@@ -136,10 +134,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
 
             let mut diag = struct_span_err!(
-                self.tcx.sess, origin.span(), E0271,
+                self.tcx.sess, obligation.cause.span, E0271,
                 "type mismatch resolving `{}`", predicate
             );
-            self.note_type_err(&mut diag, origin, None, values, err);
+            self.note_type_err(&mut diag, &obligation.cause, None, values, err);
             self.note_obligation_cause(&mut diag, obligation);
             diag.emit();
         });
@@ -529,7 +527,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
                         ty::Predicate::Equate(ref predicate) => {
                             let predicate = self.resolve_type_vars_if_possible(predicate);
-                            let err = self.equality_predicate(span,
+                            let err = self.equality_predicate(&obligation.cause,
                                                               &predicate).err().unwrap();
                             struct_span_err!(self.tcx.sess, span, E0278,
                                 "the requirement `{}` is not satisfied (`{}`)",
@@ -851,7 +849,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         let tcx = self.tcx;
         match *cause_code {
-            ObligationCauseCode::MiscObligation => { }
+            ObligationCauseCode::ExprAssignable |
+            ObligationCauseCode::MatchExpressionArm { .. } |
+            ObligationCauseCode::IfExpression |
+            ObligationCauseCode::IfExpressionWithNoElse |
+            ObligationCauseCode::EquatePredicate |
+            ObligationCauseCode::MainFunctionType |
+            ObligationCauseCode::StartFunctionType |
+            ObligationCauseCode::IntrinsicType |
+            ObligationCauseCode::MethodReceiver |
+            ObligationCauseCode::MiscObligation => {
+            }
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index b4592a03bcd..535156e61e9 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -519,7 +519,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
         }
 
         ty::Predicate::Equate(ref binder) => {
-            match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
+            match selcx.infcx().equality_predicate(&obligation.cause, binder) {
                 Ok(InferOk { obligations, .. }) => {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index eba24bfd2c9..a5fdaed9712 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*;
 pub use self::Vtable::*;
 pub use self::ObligationCauseCode::*;
 
+use hir;
 use hir::def_id::DefId;
 use middle::free_region::FreeRegionMap;
 use ty::subst::Substs;
@@ -148,6 +149,35 @@ pub enum ObligationCauseCode<'tcx> {
         trait_item_def_id: DefId,
         lint_id: Option<ast::NodeId>,
     },
+
+    // Checking that this expression can be assigned where it needs to be
+    // FIXME(eddyb) #11161 is the original Expr required?
+    ExprAssignable,
+
+    // Computing common supertype in the arms of a match expression
+    MatchExpressionArm { arm_span: Span,
+                         source: hir::MatchSource },
+
+    // Computing common supertype in an if expression
+    IfExpression,
+
+    // Computing common supertype of an if expression with no else counter-part
+    IfExpressionWithNoElse,
+
+    // `where a == b`
+    EquatePredicate,
+
+    // `main` has wrong type
+    MainFunctionType,
+
+    // `start` has wrong type
+    StartFunctionType,
+
+    // intrinsic has wrong type
+    IntrinsicType,
+
+    // method receiver
+    MethodReceiver,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index f1b69feb545..6ab7a1fbfb8 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -24,7 +24,7 @@ use super::VtableImplData;
 use super::util;
 
 use hir::def_id::DefId;
-use infer::{InferOk, TypeOrigin};
+use infer::InferOk;
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::parse::token;
 use syntax::ast;
@@ -209,8 +209,7 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
            obligations);
 
     let infcx = selcx.infcx();
-    let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
-    match infcx.eq_types(true, origin, normalized_ty, obligation.predicate.ty) {
+    match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) {
         Ok(InferOk { obligations: inferred_obligations, .. }) => {
             // FIXME(#32730) once obligations are generated in inference, drop this assertion
             assert!(inferred_obligations.is_empty());
@@ -840,13 +839,12 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
                 let same_name = data.item_name() == obligation.predicate.item_name;
 
                 let is_match = same_name && infcx.probe(|_| {
-                    let origin = TypeOrigin::Misc(obligation.cause.span);
                     let data_poly_trait_ref =
                         data.to_poly_trait_ref();
                     let obligation_poly_trait_ref =
                         obligation_trait_ref.to_poly_trait_ref();
                     infcx.sub_poly_trait_refs(false,
-                                              origin,
+                                              obligation.cause.clone(),
                                               data_poly_trait_ref,
                                               obligation_poly_trait_ref)
                         // FIXME(#32730) once obligations are propagated from unification in
@@ -1153,12 +1151,11 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
 
         // select those with a relevant trait-ref
         let mut env_predicates = env_predicates.filter(|data| {
-            let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
             let data_poly_trait_ref = data.to_poly_trait_ref();
             let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
             selcx.infcx().probe(|_| {
                 selcx.infcx().sub_poly_trait_refs(false,
-                                                  origin,
+                                                  obligation.cause.clone(),
                                                   data_poly_trait_ref,
                                                   obligation_poly_trait_ref).is_ok()
             })
@@ -1265,9 +1262,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
     -> Progress<'tcx>
 {
     let infcx = selcx.infcx();
-    let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
+    let cause = obligation.cause.clone();
     let trait_ref = obligation.predicate.trait_ref;
-    match infcx.match_poly_projection_predicate(origin, poly_projection, trait_ref) {
+    match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) {
         Ok(InferOk { value: ty_match, obligations }) => {
             // FIXME(#32730) once obligations are generated in inference, drop this assertion
             assert!(obligations.is_empty());
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 6f6534cb206..6c75fb6a246 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -35,7 +35,7 @@ use super::util;
 
 use hir::def_id::DefId;
 use infer;
-use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
+use infer::{InferCtxt, InferOk, TypeFreshener};
 use ty::subst::{Kind, Subst, Substs};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use traits;
@@ -521,7 +521,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             ty::Predicate::Equate(ref p) => {
                 // does this code ever run?
-                match self.infcx.equality_predicate(obligation.cause.span, p) {
+                match self.infcx.equality_predicate(&obligation.cause, p) {
                     Ok(InferOk { obligations, .. }) => {
                         self.inferred_obligations.extend(obligations);
                         EvaluatedToOk
@@ -1247,9 +1247,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         -> bool
     {
         assert!(!skol_trait_ref.has_escaping_regions());
-        let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
+        let cause = obligation.cause.clone();
         match self.infcx.sub_poly_trait_refs(false,
-                                             origin,
+                                             cause,
                                              trait_bound.clone(),
                                              ty::Binder(skol_trait_ref.clone())) {
             Ok(InferOk { obligations, .. }) => {
@@ -2439,16 +2439,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
     /// selection of the impl. Therefore, if there is a mismatch, we
     /// report an error to the user.
     fn confirm_poly_trait_refs(&mut self,
-                               obligation_cause: ObligationCause,
+                               obligation_cause: ObligationCause<'tcx>,
                                obligation_trait_ref: ty::PolyTraitRef<'tcx>,
                                expected_trait_ref: ty::PolyTraitRef<'tcx>)
                                -> Result<(), SelectionError<'tcx>>
     {
-        let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span);
-
         let obligation_trait_ref = obligation_trait_ref.clone();
         self.infcx.sub_poly_trait_refs(false,
-                                       origin,
+                                       obligation_cause.clone(),
                                        expected_trait_ref.clone(),
                                        obligation_trait_ref.clone())
             .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
@@ -2482,9 +2480,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     builtin_bounds: data_b.builtin_bounds,
                     projection_bounds: data_a.projection_bounds.clone(),
                 });
-                let origin = TypeOrigin::Misc(obligation.cause.span);
                 let InferOk { obligations, .. } =
-                    self.infcx.sub_types(false, origin, new_trait, target)
+                    self.infcx.sub_types(false, &obligation.cause, new_trait, target)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
@@ -2553,9 +2550,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
 
             // [T; n] -> [T].
             (&ty::TyArray(a, _), &ty::TySlice(b)) => {
-                let origin = TypeOrigin::Misc(obligation.cause.span);
                 let InferOk { obligations, .. } =
-                    self.infcx.sub_types(false, origin, a, b)
+                    self.infcx.sub_types(false, &obligation.cause, a, b)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
             }
@@ -2617,9 +2613,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     }
                 });
                 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)
+                    self.infcx.sub_types(false, &obligation.cause, new_struct, target)
                     .map_err(|_| Unimplemented)?;
                 self.inferred_obligations.extend(obligations);
 
@@ -2705,10 +2700,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                impl_trait_ref,
                skol_obligation_trait_ref);
 
-        let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
         let InferOk { obligations, .. } =
             self.infcx.eq_trait_refs(false,
-                                     origin,
+                                     &obligation.cause,
                                      impl_trait_ref.value.clone(),
                                      skol_obligation_trait_ref)
             .map_err(|e| {
@@ -2780,9 +2774,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                obligation,
                poly_trait_ref);
 
-        let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
         self.infcx.sub_poly_trait_refs(false,
-                                       origin,
+                                       obligation.cause.clone(),
                                        poly_trait_ref,
                                        obligation.predicate.to_poly_trait_ref())
             .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 91c40a5cc85..870494363c8 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -22,7 +22,7 @@ use super::util::impl_trait_ref_and_oblig;
 
 use rustc_data_structures::fx::FxHashMap;
 use hir::def_id::DefId;
-use infer::{InferCtxt, InferOk, TypeOrigin};
+use infer::{InferCtxt, InferOk};
 use middle::region;
 use ty::subst::{Subst, Substs};
 use traits::{self, Reveal, ObligationCause};
@@ -223,8 +223,10 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
                                                                    target_substs);
 
     // do the impls unify? If not, no specialization.
-    match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref,
-                                                                target_trait_ref) {
+    match infcx.eq_trait_refs(true,
+                              &ObligationCause::dummy(),
+                              source_trait_ref,
+                              target_trait_ref) {
         Ok(InferOk { obligations, .. }) => {
             // FIXME(#32730) propagate obligations
             assert!(obligations.is_empty())
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index d33e8b5675f..d03ba5b0a31 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -213,6 +213,34 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                     lint_id: lint_id,
                 })
             }
+            super::ExprAssignable => {
+                Some(super::ExprAssignable)
+            }
+            super::MatchExpressionArm { arm_span, source } => {
+                Some(super::MatchExpressionArm { arm_span: arm_span,
+                                                 source: source })
+            }
+            super::IfExpression => {
+                Some(super::IfExpression)
+            }
+            super::IfExpressionWithNoElse => {
+                Some(super::IfExpressionWithNoElse)
+            }
+            super::EquatePredicate => {
+                Some(super::EquatePredicate)
+            }
+            super::MainFunctionType => {
+                Some(super::MainFunctionType)
+            }
+            super::StartFunctionType => {
+                Some(super::StartFunctionType)
+            }
+            super::IntrinsicType => {
+                Some(super::IntrinsicType)
+            }
+            super::MethodReceiver => {
+                Some(super::MethodReceiver)
+            }
         }
     }
 }
@@ -461,6 +489,15 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
 impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
+            super::ExprAssignable |
+            super::MatchExpressionArm { arm_span: _, source: _ } |
+            super::IfExpression |
+            super::IfExpressionWithNoElse |
+            super::EquatePredicate |
+            super::MainFunctionType |
+            super::StartFunctionType |
+            super::IntrinsicType |
+            super::MethodReceiver |
             super::MiscObligation |
             super::SliceOrArrayElem |
             super::TupleElem |
@@ -497,6 +534,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
+            super::ExprAssignable |
+            super::MatchExpressionArm { arm_span: _, source: _ } |
+            super::IfExpression |
+            super::IfExpressionWithNoElse |
+            super::EquatePredicate |
+            super::MainFunctionType |
+            super::StartFunctionType |
+            super::IntrinsicType |
+            super::MethodReceiver |
             super::MiscObligation |
             super::SliceOrArrayElem |
             super::TupleElem |
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 8dc21550148..782c74c8c78 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -21,9 +21,9 @@ use rustc::middle::region::CodeExtentData;
 use rustc::middle::resolve_lifetime;
 use rustc::middle::stability;
 use rustc::ty::subst::{Kind, Subst};
-use rustc::traits::Reveal;
+use rustc::traits::{ObligationCause, Reveal};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
+use rustc::infer::{self, InferOk, InferResult};
 use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::session::{self, config};
@@ -36,7 +36,6 @@ use errors::emitter::Emitter;
 use errors::{Level, DiagnosticBuilder};
 use syntax::parse::token;
 use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::DUMMY_SP;
 
 use rustc::hir;
 
@@ -245,7 +244,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-        match self.infcx.sub_types(true, TypeOrigin::Misc(DUMMY_SP), a, b) {
+        match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) {
             Ok(_) => true,
             Err(ref e) => panic!("Encountered error: {}", e),
         }
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 79bb14b7336..78912f607fa 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -306,22 +306,28 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
 pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
     fulfillment_cx: traits::FulfillmentContext<'tcx>,
-    last_span: Span
+    last_span: Span,
+    body_id: ast::NodeId,
 }
 
 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
-    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+    fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
         TypeChecker {
             infcx: infcx,
             fulfillment_cx: traits::FulfillmentContext::new(),
-            last_span: DUMMY_SP
+            last_span: DUMMY_SP,
+            body_id: body_id,
         }
     }
 
+    fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
+        traits::ObligationCause::misc(span, self.body_id)
+    }
+
     fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>)
                  -> infer::UnitResult<'tcx>
     {
-        self.infcx.sub_types(false, infer::TypeOrigin::Misc(span), sup, sub)
+        self.infcx.sub_types(false, &self.misc(span), sup, sub)
             // FIXME(#32730) propagate obligations
             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
@@ -329,7 +335,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
     fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
                 -> infer::UnitResult<'tcx>
     {
-        self.infcx.eq_types(false, infer::TypeOrigin::Misc(span), a, b)
+        self.infcx.eq_types(false, &self.misc(span), a, b)
             // FIXME(#32730) propagate obligations
             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
     }
@@ -715,7 +721,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
         }
         let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
         tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| {
-            let mut checker = TypeChecker::new(&infcx);
+            let mut checker = TypeChecker::new(&infcx, src.item_id());
             {
                 let mut verifier = TypeVerifier::new(&mut checker, mir);
                 verifier.visit_mir(mir);
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index ca630624cdb..d57a27ddc76 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -11,7 +11,8 @@
 use rustc::hir::{self, PatKind};
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
-use rustc::infer::{self, InferOk, TypeOrigin};
+use rustc::infer::{self, InferOk};
+use rustc::traits::ObligationCauseCode;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
 use check::{FnCtxt, Expectation, Diverges};
 use util::nodemap::FxHashMap;
@@ -450,14 +451,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => false
             };
 
-            let origin = if is_if_let_fallback {
-                TypeOrigin::IfExpressionWithNoElse(expr.span)
+            let cause = if is_if_let_fallback {
+                self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse)
             } else {
-                TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
+                self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
+                    arm_span: arm.body.span,
+                    source: match_src
+                })
             };
 
             let result = if is_if_let_fallback {
-                self.eq_types(true, origin, arm_ty, result_ty)
+                self.eq_types(true, &cause, arm_ty, result_ty)
                     .map(|InferOk { obligations, .. }| {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
@@ -468,7 +472,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
                 let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
+                self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
             result_ty = match result {
@@ -479,7 +483,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     } else {
                         (result_ty, arm_ty)
                     };
-                    self.report_mismatched_types(origin, expected, found, e);
+                    self.report_mismatched_types(&cause, expected, found, e);
                     self.tcx.types.err
                 }
             };
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 16493412d69..7a7ea760c03 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -63,8 +63,8 @@
 use check::FnCtxt;
 
 use rustc::hir;
-use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
-use rustc::traits::{self, ObligationCause};
+use rustc::infer::{Coercion, InferOk, TypeTrace};
+use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
@@ -78,7 +78,7 @@ use std::ops::Deref;
 
 struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
-    origin: TypeOrigin,
+    cause: ObligationCause<'tcx>,
     use_lub: bool,
     unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
 }
@@ -104,10 +104,10 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
 }
 
 impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
-    fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, origin: TypeOrigin) -> Self {
+    fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
         Coerce {
             fcx: fcx,
-            origin: origin,
+            cause: cause,
             use_lub: false,
             unsizing_obligations: RefCell::new(vec![]),
         }
@@ -115,7 +115,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
 
     fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
         self.commit_if_ok(|_| {
-            let trace = TypeTrace::types(self.origin, false, a, b);
+            let trace = TypeTrace::types(&self.cause, false, a, b);
             if self.use_lub {
                 self.lub(false, trace, &a, &b)
                     .map(|InferOk { value, obligations }| {
@@ -238,7 +238,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             _ => return self.unify_and_identity(a, b),
         };
 
-        let span = self.origin.span();
+        let span = self.cause.span;
 
         let mut first_error = None;
         let mut r_borrow_var = None;
@@ -430,7 +430,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
                 coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
 
-                let coercion = Coercion(self.origin.span());
+                let coercion = Coercion(self.cause.span);
                 let r_borrow = self.next_region_var(coercion);
                 (mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
             }
@@ -449,7 +449,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         let mut leftover_predicates = vec![];
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
-        let cause = ObligationCause::misc(self.origin.span(), self.body_id);
+        let cause = ObligationCause::misc(self.cause.span, self.body_id);
         queue.push_back(self.tcx
             .predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
 
@@ -635,7 +635,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let source = self.resolve_type_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
-        let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
+        let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
+        let mut coerce = Coerce::new(self, cause);
         self.commit_if_ok(|_| {
             let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?;
             if !adjustment.is_identity() {
@@ -655,7 +656,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// tries to unify the types, potentially inserting coercions on any of the
     /// provided expressions and returns their LUB (aka "common supertype").
     pub fn try_find_coercion_lub<'b, E, I>(&self,
-                                           origin: TypeOrigin,
+                                           cause: &ObligationCause<'tcx>,
                                            exprs: E,
                                            prev_ty: Ty<'tcx>,
                                            new: &'b hir::Expr,
@@ -669,7 +670,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let new_ty = self.resolve_type_vars_with_obligations(new_ty);
         debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
-        let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
+        let trace = TypeTrace::types(cause, true, prev_ty, new_ty);
 
         // Special-case that coercion alone cannot handle:
         // Two function item types of differing IDs or Substs.
@@ -715,7 +716,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ => {}
         }
 
-        let mut coerce = Coerce::new(self, origin);
+        let mut coerce = Coerce::new(self, cause.clone());
         coerce.use_lub = true;
 
         // First try to coerce the new expression to the type of the previous ones,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 54a0ef071ce..075567c7949 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -9,10 +9,10 @@
 // except according to those terms.
 
 use rustc::hir;
-use rustc::infer::{self, InferOk, TypeOrigin};
+use rustc::infer::{self, InferOk};
 use rustc::middle::free_region::FreeRegionMap;
 use rustc::ty;
-use rustc::traits::{self, Reveal};
+use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
@@ -95,6 +95,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let trait_to_impl_substs = impl_trait_ref.substs;
 
+    let cause = ObligationCause {
+        span: impl_m_span,
+        body_id: impl_m_body_id,
+        code: ObligationCauseCode::CompareImplMethodObligation {
+            item_name: impl_m.name,
+            impl_item_def_id: impl_m.def_id,
+            trait_item_def_id: trait_m.def_id,
+            lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
+        },
+    };
+
     // This code is best explained by example. Consider a trait:
     //
     //     trait Trait<'t,T> {
@@ -235,20 +246,9 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let traits::Normalized { value: predicate, .. } =
                 traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
 
-            let cause = traits::ObligationCause {
-                span: impl_m_span,
-                body_id: impl_m_body_id,
-                code: traits::ObligationCauseCode::CompareImplMethodObligation {
-                    item_name: impl_m.name,
-                    impl_item_def_id: impl_m.def_id,
-                    trait_item_def_id: trait_m.def_id,
-                    lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
-                },
-            };
-
             fulfillment_cx.borrow_mut().register_predicate_obligation(
                 &infcx,
-                traits::Obligation::new(cause, predicate));
+                traits::Obligation::new(cause.clone(), predicate));
         }
 
         // We now need to check that the signature of the impl method is
@@ -266,7 +266,6 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         // Compute skolemized form of impl and trait method tys.
         let tcx = infcx.tcx;
-        let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
 
         let m_fty = |method: &ty::AssociatedItem| {
             match tcx.item_type(method.def_id).sty {
@@ -315,7 +314,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
 
-        let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty)
+        let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty)
             .map(|InferOk { obligations, .. }| {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
@@ -328,22 +327,25 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
                                                                                     &terr,
-                                                                                    origin,
+                                                                                    &cause,
                                                                                     impl_m,
                                                                                     impl_sig,
                                                                                     trait_m,
                                                                                     trait_sig);
 
-            let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
+            let cause = ObligationCause {
+                span: impl_err_span,
+                ..cause.clone()
+            };
 
             let mut diag = struct_span_err!(tcx.sess,
-                                            origin.span(),
+                                            cause.span,
                                             E0053,
                                             "method `{}` has an incompatible type for trait",
                                             trait_m.name);
 
             infcx.note_type_err(&mut diag,
-                                origin,
+                                &cause,
                                 trait_err_span.map(|sp| (sp, format!("type in trait"))),
                                 Some(infer::ValuePairs::Types(ExpectedFound {
                                     expected: trait_fty,
@@ -429,7 +431,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
 fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
                                                      terr: &TypeError,
-                                                     origin: TypeOrigin,
+                                                     cause: &ObligationCause<'tcx>,
                                                      impl_m: &ty::AssociatedItem,
                                                      impl_sig: ty::FnSig<'tcx>,
                                                      trait_m: &ty::AssociatedItem,
@@ -478,9 +480,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                                    }
                                }
                            })
-                           .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+                           .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
             } else {
-                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                (cause.span, tcx.map.span_if_local(trait_m.def_id))
             }
         }
         TypeError::Sorts(ExpectedFound { .. }) => {
@@ -499,25 +501,25 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
                          .zip(impl_m_iter)
                          .zip(trait_m_iter)
                          .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
-                             match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
+                             match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
                                  Ok(_) => None,
                                  Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
                              }
                          })
                          .next()
                          .unwrap_or_else(|| {
-                             if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
+                             if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output)
                                      .is_err() {
                                          (impl_m_output.span(), Some(trait_m_output.span()))
                                      } else {
-                                         (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                                         (cause.span, tcx.map.span_if_local(trait_m.def_id))
                                      }
                          })
             } else {
-                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                (cause.span, tcx.map.span_if_local(trait_m.def_id))
             }
         }
-        _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
+        _ => (cause.span, tcx.map.span_if_local(trait_m.def_id)),
     }
 }
 
@@ -787,7 +789,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         // Compute skolemized form of impl and trait const tys.
         let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs);
         let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs);
-        let mut origin = TypeOrigin::Misc(impl_c_span);
+        let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
 
         let err = infcx.commit_if_ok(|_| {
             // There is no "body" here, so just pass dummy id.
@@ -807,7 +809,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             debug!("compare_const_impl: trait_ty={:?}", trait_ty);
 
-            infcx.sub_types(false, origin, impl_ty, trait_ty)
+            infcx.sub_types(false, &cause, impl_ty, trait_ty)
                 .map(|InferOk { obligations, .. }| {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty())
@@ -821,12 +823,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             // Locate the Span containing just the type of the offending impl
             match tcx.map.expect_impl_item(impl_c_node_id).node {
-                ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
+                ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
                 _ => bug!("{:?} is not a impl const", impl_c),
             }
 
             let mut diag = struct_span_err!(tcx.sess,
-                                            origin.span(),
+                                            cause.span,
                                             E0326,
                                             "implemented const `{}` has an incompatible type for \
                                              trait",
@@ -840,7 +842,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             };
 
             infcx.note_type_err(&mut diag,
-                                origin,
+                                &cause,
                                 Some((trait_c_span, format!("type in trait"))),
                                 Some(infer::ValuePairs::Types(ExpectedFound {
                                     expected: trait_ty,
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index d622bc7f751..8a0f1478a73 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -11,7 +11,8 @@
 
 use check::FnCtxt;
 use rustc::ty::Ty;
-use rustc::infer::{InferOk, TypeOrigin};
+use rustc::infer::{InferOk};
+use rustc::traits::ObligationCause;
 
 use syntax_pos::Span;
 use rustc::hir;
@@ -20,34 +21,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     // Requires that the two types unify, and prints an error message if
     // they don't.
     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-        let origin = TypeOrigin::Misc(sp);
-        match self.sub_types(false, origin, actual, expected) {
+        let cause = self.misc(sp);
+        match self.sub_types(false, &cause, actual, expected) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
             },
             Err(e) => {
-                self.report_mismatched_types(origin, expected, actual, e);
+                self.report_mismatched_types(&cause, expected, actual, e);
             }
         }
     }
 
     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
-        self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual);
+        self.demand_eqtype_with_origin(&self.misc(sp), expected, actual);
     }
 
     pub fn demand_eqtype_with_origin(&self,
-                                     origin: TypeOrigin,
+                                     cause: &ObligationCause<'tcx>,
                                      expected: Ty<'tcx>,
                                      actual: Ty<'tcx>)
     {
-        match self.eq_types(false, origin, actual, expected) {
+        match self.eq_types(false, cause, actual, expected) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
             },
             Err(e) => {
-                self.report_mismatched_types(origin, expected, actual, e);
+                self.report_mismatched_types(cause, expected, actual, e);
             }
         }
     }
@@ -56,9 +57,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
         let expected = self.resolve_type_vars_with_obligations(expected);
         if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
-            let origin = TypeOrigin::Misc(expr.span);
+            let cause = self.misc(expr.span);
             let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
-            self.report_mismatched_types(origin, expected, expr_ty, e);
+            self.report_mismatched_types(&cause, expected, expr_ty, e);
         }
     }
 }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 09e1f6592c1..8868d1e54f4 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -17,7 +17,7 @@ use rustc::infer::{self, InferOk};
 use middle::region;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
-use rustc::traits::{self, Reveal};
+use rustc::traits::{self, ObligationCause, Reveal};
 use util::nodemap::FxHashSet;
 
 use syntax::ast;
@@ -93,8 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
             infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
         let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
 
-        match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span),
-                             named_type, fresh_impl_self_ty) {
+        let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
+        match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index ac6343cae1c..77106b8b0c3 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -12,7 +12,7 @@
 //! intrinsics that the compiler exposes.
 
 use intrinsics;
-use rustc::infer::TypeOrigin;
+use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::subst::Substs;
 use rustc::ty::FnSig;
 use rustc::ty::{self, Ty};
@@ -63,7 +63,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             .emit();
     } else {
         require_same_types(ccx,
-                           TypeOrigin::IntrinsicType(it.span),
+                           &ObligationCause::new(it.span,
+                                                 it.id,
+                                                 ObligationCauseCode::IntrinsicType),
                            tcx.item_type(def_id),
                            fty);
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 0b6f7794e9f..f9e1db141c8 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -17,7 +17,7 @@ use rustc::traits;
 use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
 use rustc::ty::fold::TypeFoldable;
-use rustc::infer::{self, InferOk, TypeOrigin};
+use rustc::infer::{self, InferOk};
 use syntax_pos::Span;
 use rustc::hir;
 
@@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     }
 
     fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
-        match self.sub_types(false, TypeOrigin::Misc(self.span), self_ty, method_self_ty) {
+        match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 481923c2597..71696c0abea 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -17,12 +17,12 @@ use check::FnCtxt;
 use hir::def_id::DefId;
 use hir::def::Def;
 use rustc::ty::subst::{Subst, Substs};
-use rustc::traits;
+use rustc::traits::{self, ObligationCause};
 use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
-use rustc::infer::{InferOk, TypeOrigin};
+use rustc::infer::InferOk;
 use rustc::util::nodemap::FxHashSet;
 use syntax::ast;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
 use rustc::hir;
 use std::mem;
 use std::ops::Deref;
@@ -1032,7 +1032,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         self.probe(|_| {
             // First check that the self type can be related.
             match self.sub_types(false,
-                                 TypeOrigin::Misc(DUMMY_SP),
+                                 &ObligationCause::dummy(),
                                  self_ty,
                                  probe.xform_self_ty) {
                 Ok(InferOk { obligations, .. }) => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a95b3f4a973..76cd3c4a1eb 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -87,9 +87,9 @@ use hir::def::{Def, CtorKind, PathResolution};
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin,
-                   TypeOrigin, TypeTrace, type_variable};
+                   TypeTrace, type_variable};
 use rustc::ty::subst::{Kind, Subst, Substs};
-use rustc::traits::{self, Reveal};
+use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
@@ -1521,6 +1521,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    pub fn cause(&self,
+                 span: Span,
+                 code: ObligationCauseCode<'tcx>)
+                 -> ObligationCause<'tcx> {
+        ObligationCause::new(span, self.body_id, code)
+    }
+
+    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
+        self.cause(span, ObligationCauseCode::MiscObligation)
+    }
+
     /// Resolves type variables in `ty` if possible. Unlike the infcx
     /// version (resolve_type_vars_if_possible), this version will
     /// also select obligations if it seems useful, in an effort
@@ -2096,8 +2107,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 if let Some(default) = default_map.get(ty) {
                                     let default = default.clone();
                                     match self.eq_types(false,
-                                            TypeOrigin::Misc(default.origin_span),
-                                            ty, default.ty) {
+                                                        &self.misc(default.origin_span),
+                                                        ty,
+                                                        default.ty) {
                                         Ok(InferOk { obligations, .. }) => {
                                             // FIXME(#32730) propagate obligations
                                             assert!(obligations.is_empty())
@@ -2146,6 +2158,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                     self.report_conflicting_default_types(
                         first_default.origin_span,
+                        self.body_id,
                         first_default,
                         second_default)
                 }
@@ -2194,8 +2207,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         if let Some(default) = default_map.get(ty) {
                             let default = default.clone();
                             match self.eq_types(false,
-                                    TypeOrigin::Misc(default.origin_span),
-                                    ty, default.ty) {
+                                                &self.misc(default.origin_span),
+                                                ty,
+                                                default.ty) {
                                 // FIXME(#32730) propagate obligations
                                 Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
                                 Err(_) => {
@@ -2765,8 +2779,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // return type (likely containing type variables if the function
                 // is polymorphic) and the expected return type.
                 // No argument expectations are produced if unification fails.
-                let origin = TypeOrigin::Misc(call_span);
-                let ures = self.sub_types(false, origin, formal_ret, ret_ty);
+                let origin = self.misc(call_span);
+                let ures = self.sub_types(false, &origin, formal_ret, ret_ty);
                 // FIXME(#15760) can't use try! here, FromError doesn't default
                 // to identity so the resulting type is not constrained.
                 match ures {
@@ -2852,16 +2866,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.diverges.set(Diverges::Maybe);
 
         let unit = self.tcx.mk_nil();
-        let (origin, expected, found, result) =
+        let (cause, expected_ty, found_ty, result);
         if let Some(else_expr) = opt_else_expr {
             let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let else_diverges = self.diverges.get();
+            cause = self.cause(sp, ObligationCauseCode::IfExpression);
 
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
-            let origin = TypeOrigin::IfExpression(sp);
-            let result = if let Some(ref then) = then_blk.expr {
-                let res = self.try_find_coercion_lub(origin, || Some(&**then),
+            expected_ty = then_ty;
+            found_ty = else_ty;
+            result = if let Some(ref then) = then_blk.expr {
+                let res = self.try_find_coercion_lub(&cause, || Some(&**then),
                                                      then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
@@ -2876,7 +2892,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 res
             } else {
                 self.commit_if_ok(|_| {
-                    let trace = TypeTrace::types(origin, true, then_ty, else_ty);
+                    let trace = TypeTrace::types(&cause, true, then_ty, else_ty);
                     self.lub(true, trace, &then_ty, &else_ty)
                         .map(|InferOk { value, obligations }| {
                             // FIXME(#32730) propagate obligations
@@ -2888,21 +2904,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             // We won't diverge unless both branches do (or the condition does).
             self.diverges.set(cond_diverges | then_diverges & else_diverges);
-
-            (origin, then_ty, else_ty, result)
         } else {
             // If the condition is false we can't diverge.
             self.diverges.set(cond_diverges);
 
-            let origin = TypeOrigin::IfExpressionWithNoElse(sp);
-            (origin, unit, then_ty,
-             self.eq_types(true, origin, unit, then_ty)
-                 .map(|InferOk { obligations, .. }| {
-                     // FIXME(#32730) propagate obligations
-                     assert!(obligations.is_empty());
-                     unit
-                 }))
-        };
+            cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse);
+            expected_ty = unit;
+            found_ty = then_ty;
+            result = self.eq_types(true, &cause, unit, then_ty)
+                         .map(|InferOk { obligations, .. }| {
+                             // FIXME(#32730) propagate obligations
+                             assert!(obligations.is_empty());
+                             unit
+                         });
+        }
 
         match result {
             Ok(ty) => {
@@ -2913,7 +2928,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
             Err(e) => {
-                self.report_mismatched_types(origin, expected, found, e);
+                self.report_mismatched_types(&cause, expected_ty, found_ty, e);
                 self.tcx.types.err
             }
         }
@@ -3565,7 +3580,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
             } else {
                 let eq_result = self.eq_types(false,
-                                              TypeOrigin::Misc(expr.span),
+                                              &self.misc(expr.span),
                                               self.ret_ty,
                                               tcx.mk_nil())
                     // FIXME(#32730) propagate obligations
@@ -3695,20 +3710,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             for (i, e) in args.iter().enumerate() {
                 let e_ty = self.check_expr_with_hint(e, coerce_to);
-                let origin = TypeOrigin::Misc(e.span);
+                let cause = self.misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
                     self.try_coerce(e, e_ty, coerce_to)
                 } else {
                     let prev_elems = || args[..i].iter().map(|e| &**e);
-                    self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
+                    self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty)
                 };
 
                 match result {
                     Ok(ty) => unified = ty,
                     Err(e) => {
-                        self.report_mismatched_types(origin, unified, e_ty, e);
+                        self.report_mismatched_types(&cause, unified, e_ty, e);
                     }
                 }
             }
@@ -4064,9 +4079,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // We're not diverging and there's an expected type, which,
                 // in case it's not `()`, could result in an error higher-up.
                 // We have a chance to error here early and be more helpful.
-                let origin = TypeOrigin::Misc(blk.span);
-                let trace = TypeTrace::types(origin, false, ty, ety);
-                match self.sub_types(false, origin, ty, ety) {
+                let cause = self.misc(blk.span);
+                let trace = TypeTrace::types(&cause, false, ty, ety);
+                match self.sub_types(false, &cause, ty, ety) {
                     Ok(InferOk { obligations, .. }) => {
                         // FIXME(#32730) propagate obligations
                         assert!(obligations.is_empty());
@@ -4367,7 +4382,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let ty = self.tcx.item_type(impl_def_id);
 
             let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
-            match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
+            match self.sub_types(false, &self.misc(span), self_ty, impl_ty) {
                 Ok(InferOk { obligations, .. }) => {
                     // FIXME(#32730) propagate obligations
                     assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index e019c4c7614..e41c149b178 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -91,7 +91,7 @@ use middle::region::{self, CodeExtent};
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
-use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, TypeOrigin, VerifyBound};
+use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, VerifyBound};
 use hir::pat_util;
 use rustc::ty::adjustment;
 use rustc::ty::wf::ImpliedBound;
@@ -1762,7 +1762,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                            outlives);
 
                     // check whether this predicate applies to our current projection
-                    match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
+                    let cause = self.fcx.misc(span);
+                    match self.eq_types(false, &cause, ty, outlives.0) {
                         Ok(InferOk { obligations, .. }) => {
                             // FIXME(#32730) propagate obligations
                             assert!(obligations.is_empty());
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 066b3d4be08..41bea187416 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -15,8 +15,7 @@ use CrateCtxt;
 
 use hir::def_id::DefId;
 use middle::region::{CodeExtent};
-use rustc::infer::TypeOrigin;
-use rustc::traits;
+use rustc::traits::{self, ObligationCauseCode};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 
@@ -29,7 +28,7 @@ use rustc::hir;
 
 pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
     ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
-    code: traits::ObligationCauseCode<'tcx>,
+    code: ObligationCauseCode<'tcx>,
 }
 
 /// Helper type of a temporary returned by .for_item(...).
@@ -37,7 +36,7 @@ pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
 /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
 struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
-    code: traits::ObligationCauseCode<'gcx>,
+    code: ObligationCauseCode<'gcx>,
     id: ast::NodeId,
     span: Span
 }
@@ -67,7 +66,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                -> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
         CheckTypeWellFormedVisitor {
             ccx: ccx,
-            code: traits::ObligationCauseCode::MiscObligation
+            code: ObligationCauseCode::MiscObligation
         }
     }
 
@@ -515,8 +514,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
         debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
 
-        let origin = TypeOrigin::MethodReceiver(span);
-        fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty);
+        let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
+        fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty);
     }
 
     fn check_variances_for_type_defn(&self,
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 58633058264..7c860bc5aec 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -19,7 +19,7 @@ use hir::def_id::DefId;
 use middle::lang_items::UnsizeTraitLangItem;
 use rustc::ty::subst::Subst;
 use rustc::ty::{self, TyCtxt, TypeFoldable};
-use rustc::traits::{self, Reveal};
+use rustc::traits::{self, ObligationCause, Reveal};
 use rustc::ty::ParameterEnvironment;
 use rustc::ty::{Ty, TyBool, TyChar, TyError};
 use rustc::ty::{TyParam, TyRawPtr};
@@ -30,7 +30,7 @@ use rustc::ty::{TyProjection, TyAnon};
 use rustc::ty::util::CopyImplementationError;
 use middle::free_region::FreeRegionMap;
 use CrateCtxt;
-use rustc::infer::{self, InferCtxt, TypeOrigin};
+use rustc::infer::{self, InferCtxt};
 use syntax_pos::Span;
 use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
@@ -344,12 +344,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                    target);
 
             tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
-                let origin = TypeOrigin::Misc(span);
+                let cause = ObligationCause::misc(span, impl_node_id);
                 let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
                                    mt_b: ty::TypeAndMut<'gcx>,
                                    mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
                     if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
-                        infcx.report_mismatched_types(origin,
+                        infcx.report_mismatched_types(&cause,
                                                       mk_ptr(mt_b.ty),
                                                       target,
                                                       ty::error::TypeError::Mutability);
@@ -397,7 +397,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                                 }
 
                                 // Ignore fields that aren't significantly changed
-                                if let Ok(ok) = infcx.sub_types(false, origin, b, a) {
+                                if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
                                     if ok.obligations.is_empty() {
                                         return None;
                                     }
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 2c12959dbdd..76f8254cb0f 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -106,10 +106,10 @@ pub use rustc::util;
 
 use dep_graph::DepNode;
 use hir::map as hir_map;
-use rustc::infer::{InferOk, TypeOrigin};
+use rustc::infer::InferOk;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, Reveal};
+use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use session::{config, CompileResult};
 use util::common::time;
 
@@ -172,19 +172,19 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
 }
 
 fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                origin: TypeOrigin,
+                                cause: &ObligationCause<'tcx>,
                                 expected: Ty<'tcx>,
                                 actual: Ty<'tcx>)
                                 -> bool {
     ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
-        match infcx.eq_types(false, origin.clone(), expected, actual) {
+        match infcx.eq_types(false, &cause, expected, actual) {
             Ok(InferOk { obligations, .. }) => {
                 // FIXME(#32730) propagate obligations
                 assert!(obligations.is_empty());
                 true
             }
             Err(err) => {
-                infcx.report_mismatched_types(origin, expected, actual, err);
+                infcx.report_mismatched_types(cause, expected, actual, err);
                 false
             }
         }
@@ -231,7 +231,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
 
             require_same_types(
                 ccx,
-                TypeOrigin::MainFunctionType(main_span),
+                &ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
                 se_ty,
                 main_t);
         }
@@ -286,7 +286,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
 
             require_same_types(
                 ccx,
-                TypeOrigin::StartFunctionType(start_span),
+                &ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
                 se_ty,
                 start_t);
         }