From 67da0ff2967b477a84bb60759a95fa6d733c7a61 Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Sat, 30 Oct 2021 14:14:28 -0500
Subject: [PATCH 1/3] Deduplicate projection sub-obligations

---
 compiler/rustc_trait_selection/src/traits/project.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index db8a6d9620495..574dd5fc8f48d 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -20,6 +20,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use crate::traits::error_reporting::InferCtxtExt as _;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
@@ -944,6 +945,11 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 Normalized { value: projected_ty, obligations: projected_obligations }
             };
 
+            let mut deduped: FxHashSet<_> = Default::default();
+            result
+                .obligations
+                .drain_filter(|sub_obligation| !deduped.insert(sub_obligation.clone()));
+
             let mut canonical =
                 SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
             result.obligations.drain_filter(|projected_obligation| {

From 851f2b2f969131442fc6290580d7c3632a3a24ae Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Sat, 30 Oct 2021 18:53:00 -0500
Subject: [PATCH 2/3] Use SsoHashSet

---
 compiler/rustc_trait_selection/src/traits/project.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 574dd5fc8f48d..8c26ff529773f 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -20,7 +20,7 @@ use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
 use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
 use crate::traits::error_reporting::InferCtxtExt as _;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sso::SsoHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::DefId;
@@ -945,7 +945,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 Normalized { value: projected_ty, obligations: projected_obligations }
             };
 
-            let mut deduped: FxHashSet<_> = Default::default();
+            let mut deduped: SsoHashSet<_> = Default::default();
             result
                 .obligations
                 .drain_filter(|sub_obligation| !deduped.insert(sub_obligation.clone()));

From 39d44e72ca2ef82ea294f64e7ef3db23b4fdfd04 Mon Sep 17 00:00:00 2001
From: Aaron Hill <aa1ronham@gmail.com>
Date: Sun, 31 Oct 2021 16:14:16 -0500
Subject: [PATCH 3/3] Combine drain_filter calls

---
 compiler/rustc_trait_selection/src/traits/project.rs | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8c26ff529773f..bf274dad4f09a 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -946,13 +946,13 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             };
 
             let mut deduped: SsoHashSet<_> = Default::default();
-            result
-                .obligations
-                .drain_filter(|sub_obligation| !deduped.insert(sub_obligation.clone()));
-
             let mut canonical =
                 SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
+
             result.obligations.drain_filter(|projected_obligation| {
+                if !deduped.insert(projected_obligation.clone()) {
+                    return true;
+                }
                 // If any global obligations always apply, considering regions, then we don't
                 // need to include them. The `is_global` check rules out inference variables,
                 // so there's no need for the caller of `opt_normalize_projection_type`