From 0c03a886d3d9cb6e43207fa66d798ac5871dcbf1 Mon Sep 17 00:00:00 2001
From: Niko Matsakis <niko@alum.mit.edu>
Date: Thu, 13 Oct 2016 12:31:55 -0400
Subject: [PATCH] run compare method in old-broken-way and new-good-way

---
 src/librustc_typeck/check/compare_method.rs | 25 ++++++++++++++++-----
 src/librustc_typeck/check/mod.rs            | 15 ++++++++++++-
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index d9af317eab0..19966d3ee86 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use rustc::infer::{self, InferOk, TypeOrigin};
+use rustc::middle::free_region::FreeRegionMap;
 use rustc::ty;
 use rustc::traits::{self, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
@@ -39,8 +40,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                      impl_m_body_id: ast::NodeId,
                                      trait_m: &ty::Method<'tcx>,
                                      impl_trait_ref: &ty::TraitRef<'tcx>,
-                                     trait_item_span: Option<Span>) {
-    debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
+                                     trait_item_span: Option<Span>,
+                                     old_broken_mode: bool) {
+    debug!("compare_impl_method(impl_trait_ref={:?})",
+           impl_trait_ref);
 
     debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
            impl_trait_ref);
@@ -367,7 +370,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     item_name: impl_m.name,
                     impl_item_def_id: impl_m.def_id,
                     trait_item_def_id: trait_m.def_id,
-                    lint_id: Some(impl_m_body_id),
+                    lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
                 },
             };
 
@@ -473,8 +476,20 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
-        let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
-        fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
+        if old_broken_mode {
+            // FIXME(#18937) -- this is how the code used to
+            // work. This is buggy because the fulfillment cx creates
+            // region obligations that get overlooked.  The right
+            // thing to do is the code below. But we keep this old
+            // pass around temporarily.
+            let mut free_regions = FreeRegionMap::new();
+            free_regions.relate_free_regions_from_predicates(
+                &infcx.parameter_environment.caller_bounds);
+            infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
+        } else {
+            let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
+            fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
+        }
     });
 
     fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ef127feb042..4e0f455e362 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1028,13 +1028,26 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
                     let trait_span = tcx.map.span_if_local(ty_trait_item.def_id());
                     if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item {
+                        let err_count = tcx.sess.err_count();
                         compare_impl_method(ccx,
                                             &impl_method,
                                             impl_item.span,
                                             body.id,
                                             &trait_method,
                                             &impl_trait_ref,
-                                            trait_span);
+                                            trait_span,
+                                            true); // start with old-broken-mode
+                        if err_count == tcx.sess.err_count() {
+                            // old broken mode did not report an error. Try with the new mode.
+                            compare_impl_method(ccx,
+                                                &impl_method,
+                                                impl_item.span,
+                                                body.id,
+                                                &trait_method,
+                                                &impl_trait_ref,
+                                                trait_span,
+                                                false); // use the new mode
+                        }
                     } else {
                         let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324,
                                   "item `{}` is an associated method, \