@@ -1779,53 +1779,60 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
1779
1779
return Some ( BuiltinCandidate { has_nested : false } ) ;
1780
1780
}
1781
1781
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.
1789
1815
//
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 ( ) ;
1792
1819
let param_candidates = candidates
1793
1820
. iter ( )
1794
1821
. 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 ;
1797
1823
let mut param_candidate = None ;
1798
1824
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 ;
1816
1830
}
1817
1831
}
1818
1832
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 ;
1829
1836
} else {
1830
1837
return Some ( ParamCandidate ( predicate) ) ;
1831
1838
}
@@ -1912,15 +1919,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
1912
1919
}
1913
1920
}
1914
1921
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
+ }
1924
1935
}
1925
1936
1926
1937
fn prefer_lhs_over_victim (
0 commit comments