@@ -1779,53 +1779,60 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
17791779 return Some ( BuiltinCandidate { has_nested : false } ) ;
17801780 }
17811781
1782- // The next highest priority is for non-global where-bounds. However, there are
1783- // two additional rules here:
1784- // - if there are also global where-bound which may apply, we bail with ambiguity
1785- // instead of prefering the non-global where-bound. Note that if there are
1786- // only global where-bounds, they get ignored
1787- // - if there are two where-bounds which only differ in their bound vars, but are
1788- // otherwise equal, we arbitrarily prefer one of them
1782+ // Before we consider where-bounds, we have to deduplicate them here and also
1783+ // dropwhere-bounds in case the same where-bound exists without bound vars.
1784+ // This is necessary as elaborating super-trait bounds may result in duplicates.
1785+ ' search_victim: loop {
1786+ for ( i, this) in candidates. iter ( ) . enumerate ( ) {
1787+ let ParamCandidate ( this) = this. candidate else { continue } ;
1788+ for ( j, other) in candidates. iter ( ) . enumerate ( ) {
1789+ if i == j {
1790+ continue ;
1791+ }
1792+
1793+ let ParamCandidate ( other) = other. candidate else { continue } ;
1794+ if this == other {
1795+ candidates. remove ( j) ;
1796+ continue ' search_victim;
1797+ }
1798+
1799+ if this. skip_binder ( ) . trait_ref == other. skip_binder ( ) . trait_ref
1800+ && this. skip_binder ( ) . polarity == other. skip_binder ( ) . polarity
1801+ && !this. skip_binder ( ) . trait_ref . has_escaping_bound_vars ( )
1802+ {
1803+ candidates. remove ( j) ;
1804+ continue ' search_victim;
1805+ }
1806+ }
1807+ }
1808+
1809+ break ;
1810+ }
1811+
1812+ // The next highest priority is for non-global where-bounds. However, while we don't
1813+ // prefer global where-clauses here, we do bail with ambiguity when encountering both
1814+ // a global and a non-global where-clause.
17891815 //
1790- // This is fairly messy but necessary for backwards compatability, see #50825 for why
1791- // we need to handle global where-bounds like this.
1816+ // Our handling of where-bounds is generally fairly messy but necessary for backwards
1817+ // compatability, see #50825 for why we need to handle global where-bounds like this.
1818+ let is_global = |c : ty:: PolyTraitPredicate < ' tcx > | c. is_global ( ) && !c. has_bound_vars ( ) ;
17921819 let param_candidates = candidates
17931820 . iter ( )
17941821 . filter_map ( |c| if let ParamCandidate ( p) = c. candidate { Some ( p) } else { None } ) ;
1795- let is_global = |c : ty:: PolyTraitPredicate < ' tcx > | c. is_global ( ) && !c. has_bound_vars ( ) ;
1796- let mut has_non_global = false ;
1822+ let mut has_global_bounds = false ;
17971823 let mut param_candidate = None ;
17981824 for c in param_candidates {
1799- has_non_global |= !is_global ( c) ;
1800- let has_fewer_bound_vars =
1801- |this : ty:: PolyTraitPredicate < ' tcx > , other : ty:: PolyTraitPredicate < ' tcx > | {
1802- this. skip_binder ( ) . trait_ref == other. skip_binder ( ) . trait_ref
1803- && this. skip_binder ( ) . polarity == other. skip_binder ( ) . polarity
1804- && !this. skip_binder ( ) . trait_ref . has_escaping_bound_vars ( )
1805- } ;
1806- if let Some ( prev) = param_candidate. replace ( c) {
1807- if has_fewer_bound_vars ( c, prev) {
1808- // Ok, prefer `c` over the previous entry
1809- } else if has_fewer_bound_vars ( prev, c) {
1810- // Ok, keep `prev` instead of the new entry
1811- param_candidate = Some ( prev) ;
1812- } else {
1813- // Ambiguity, two potentially different where-clauses
1814- return None ;
1815- }
1825+ if is_global ( c) {
1826+ has_global_bounds = true ;
1827+ } else if param_candidate. replace ( c) . is_some ( ) {
1828+ // Ambiguity, two potentially different where-clauses
1829+ return None ;
18161830 }
18171831 }
18181832 if let Some ( predicate) = param_candidate {
1819- if is_global ( predicate) {
1820- // If we only have global where-bounds, we prefer
1821- // impls over them, otherwise we bail with ambiguity.
1822- //
1823- // This is only reachable if there's one higher-ranked
1824- // and one non-higher ranked version of a global
1825- // where-clause.
1826- if has_non_global {
1827- return None ;
1828- }
1833+ // Ambiguity, a global and a non-global where-bound.
1834+ if has_global_bounds {
1835+ return None ;
18291836 } else {
18301837 return Some ( ParamCandidate ( predicate) ) ;
18311838 }
@@ -1912,15 +1919,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
19121919 }
19131920 }
19141921
1915- // Also try ignoring all global where-bounds and check whether we end
1916- // with a unique candidate in this case.
1917- let mut not_a_global_where_bound = candidates
1918- . into_iter ( )
1919- . filter ( |c| !matches ! ( c. candidate, ParamCandidate ( p) if is_global( p) ) ) ;
1920- not_a_global_where_bound
1921- . next ( )
1922- . map ( |c| c. candidate )
1923- . filter ( |_| not_a_global_where_bound. next ( ) . is_none ( ) )
1922+ if candidates. len ( ) == 1 {
1923+ Some ( candidates. pop ( ) . unwrap ( ) . candidate )
1924+ } else {
1925+ // Also try ignoring all global where-bounds and check whether we end
1926+ // with a unique candidate in this case.
1927+ let mut not_a_global_where_bound = candidates
1928+ . into_iter ( )
1929+ . filter ( |c| !matches ! ( c. candidate, ParamCandidate ( p) if is_global( p) ) ) ;
1930+ not_a_global_where_bound
1931+ . next ( )
1932+ . map ( |c| c. candidate )
1933+ . filter ( |_| not_a_global_where_bound. next ( ) . is_none ( ) )
1934+ }
19241935 }
19251936
19261937 fn prefer_lhs_over_victim (
0 commit comments