From 17aff1d774b11ef68c122c995b1d2b238ff5fb04 Mon Sep 17 00:00:00 2001
From: Philipp Hansch <dev@phansch.net>
Date: Fri, 18 May 2018 22:56:25 +0200
Subject: [PATCH] Fix cargo late bound region mismatch ICE

---
 clippy_lints/src/utils/mod.rs |  6 +++++-
 tests/run-pass/ice-2774.rs    | 31 +++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
 create mode 100644 tests/run-pass/ice-2774.rs

diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 4a30b134a69..a49464b021a 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -8,7 +8,7 @@ use rustc::hir::map::Node;
 use rustc::lint::{LateContext, Level, Lint, LintContext};
 use rustc::session::Session;
 use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind};
+use rustc::ty::{self, Binder, Ty, TyCtxt, layout::{self, IntegerExt}, subst::Kind};
 use rustc_errors::{Applicability, CodeSuggestion, Substitution, SubstitutionPart};
 use std::borrow::Cow;
 use std::env;
@@ -869,10 +869,14 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: NodeId) -> Ty<'t
 }
 
 /// Check if two types are the same.
+///
+/// This discards any lifetime annotations, too.
 // FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` == `for
 // <'b> Foo<'b>` but
 // not for type parameters.
 pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    let a = cx.tcx.erase_late_bound_regions(&Binder::bind(a));
+    let b = cx.tcx.erase_late_bound_regions(&Binder::bind(b));
     cx.tcx
         .infer_ctxt()
         .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok())
diff --git a/tests/run-pass/ice-2774.rs b/tests/run-pass/ice-2774.rs
new file mode 100644
index 00000000000..c6d9bb4a276
--- /dev/null
+++ b/tests/run-pass/ice-2774.rs
@@ -0,0 +1,31 @@
+use std::collections::HashSet;
+
+// See https://github.com/rust-lang-nursery/rust-clippy/issues/2774
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Bar {
+    foo: Foo,
+}
+
+#[derive(Eq, PartialEq, Debug, Hash)]
+pub struct Foo {}
+
+#[allow(implicit_hasher)]
+// This should not cause a 'cannot relate bound region' ICE
+pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(
+        bars.iter().map(|b| &b.foo)
+    );
+}
+
+#[allow(implicit_hasher)]
+// Also this should not cause a 'cannot relate bound region' ICE
+pub fn add_barfoos_to_foos2(bars: &HashSet<&Bar>) {
+    let mut foos = HashSet::new();
+    foos.extend(
+        bars.iter().map(|b| &b.foo)
+    );
+}
+
+fn main() {}