@@ -981,43 +981,72 @@ impl<'a> TyLoweringContext<'a> {
981
981
982
982
fn lower_dyn_trait ( & self , bounds : & [ Interned < TypeBound > ] ) -> Ty {
983
983
let self_ty = TyKind :: BoundVar ( BoundVar :: new ( DebruijnIndex :: INNERMOST , 0 ) ) . intern ( Interner ) ;
984
+ // INVARIANT: The principal trait bound must come first. Others may be in any order but
985
+ // should be in the same order for the same set but possibly different order of bounds in
986
+ // the input.
987
+ // This invariant is used by `TyExt::dyn_trait()` and chalk.
984
988
let bounds = self . with_shifted_in ( DebruijnIndex :: ONE , |ctx| {
985
- let bounds =
986
- bounds. iter ( ) . flat_map ( |b| ctx. lower_type_bound ( b, self_ty. clone ( ) , false ) ) ;
987
-
988
- let mut auto_traits = SmallVec :: < [ _ ; 8 ] > :: new ( ) ;
989
- let mut regular_traits = SmallVec :: < [ _ ; 2 ] > :: new ( ) ;
990
- let mut other_bounds = SmallVec :: < [ _ ; 8 ] > :: new ( ) ;
991
- for bound in bounds {
992
- if let Some ( id) = bound. trait_id ( ) {
993
- if ctx. db . trait_data ( from_chalk_trait_id ( id) ) . is_auto {
994
- auto_traits. push ( bound) ;
995
- } else {
996
- regular_traits. push ( bound) ;
989
+ let mut bounds: Vec < _ > = bounds
990
+ . iter ( )
991
+ . flat_map ( |b| ctx. lower_type_bound ( b, self_ty. clone ( ) , false ) )
992
+ . collect ( ) ;
993
+
994
+ let mut multiple_regular_traits = false ;
995
+ let mut multiple_same_projection = false ;
996
+ bounds. sort_unstable_by ( |lhs, rhs| {
997
+ use std:: cmp:: Ordering ;
998
+ match ( lhs. skip_binders ( ) , rhs. skip_binders ( ) ) {
999
+ ( WhereClause :: Implemented ( lhs) , WhereClause :: Implemented ( rhs) ) => {
1000
+ let lhs_id = lhs. trait_id ;
1001
+ let lhs_is_auto = ctx. db . trait_data ( from_chalk_trait_id ( lhs_id) ) . is_auto ;
1002
+ let rhs_id = rhs. trait_id ;
1003
+ let rhs_is_auto = ctx. db . trait_data ( from_chalk_trait_id ( rhs_id) ) . is_auto ;
1004
+
1005
+ if !lhs_is_auto && !rhs_is_auto {
1006
+ multiple_regular_traits = true ;
1007
+ }
1008
+ // Note that the ordering here is important; this ensures the invariant
1009
+ // mentioned above.
1010
+ ( lhs_is_auto, lhs_id) . cmp ( & ( rhs_is_auto, rhs_id) )
997
1011
}
998
- } else {
999
- other_bounds. push ( bound) ;
1012
+ ( WhereClause :: Implemented ( _) , _) => Ordering :: Less ,
1013
+ ( _, WhereClause :: Implemented ( _) ) => Ordering :: Greater ,
1014
+ ( WhereClause :: AliasEq ( lhs) , WhereClause :: AliasEq ( rhs) ) => {
1015
+ match ( & lhs. alias , & rhs. alias ) {
1016
+ ( AliasTy :: Projection ( lhs_proj) , AliasTy :: Projection ( rhs_proj) ) => {
1017
+ // We only compare the `associated_ty_id`s. We shouldn't have
1018
+ // multiple bounds for an associated type in the correct Rust code,
1019
+ // and if we do, we error out.
1020
+ if lhs_proj. associated_ty_id == rhs_proj. associated_ty_id {
1021
+ multiple_same_projection = true ;
1022
+ }
1023
+ lhs_proj. associated_ty_id . cmp ( & rhs_proj. associated_ty_id )
1024
+ }
1025
+ // We don't produce `AliasTy::Opaque`s yet.
1026
+ _ => unreachable ! ( ) ,
1027
+ }
1028
+ }
1029
+ // We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet.
1030
+ _ => unreachable ! ( ) ,
1000
1031
}
1001
- }
1032
+ } ) ;
1002
1033
1003
- if regular_traits . len ( ) > 1 {
1034
+ if multiple_regular_traits || multiple_same_projection {
1004
1035
return None ;
1005
1036
}
1006
1037
1007
- auto_traits. sort_unstable_by_key ( |b| b. trait_id ( ) . unwrap ( ) ) ;
1008
- auto_traits. dedup ( ) ;
1038
+ // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the
1039
+ // bounds. We shouldn't have repeated elements besides auto traits at this point.
1040
+ bounds. dedup ( ) ;
1009
1041
1010
- Some ( QuantifiedWhereClauses :: from_iter (
1011
- Interner ,
1012
- regular_traits. into_iter ( ) . chain ( other_bounds) . chain ( auto_traits) ,
1013
- ) )
1042
+ Some ( QuantifiedWhereClauses :: from_iter ( Interner , bounds) )
1014
1043
} ) ;
1015
1044
1016
1045
if let Some ( bounds) = bounds {
1017
1046
let bounds = crate :: make_single_type_binders ( bounds) ;
1018
1047
TyKind :: Dyn ( DynTy { bounds, lifetime : static_lifetime ( ) } ) . intern ( Interner )
1019
1048
} else {
1020
- // FIXME: report error (additional non-auto traits)
1049
+ // FIXME: report error (additional non-auto traits or associated type rebound )
1021
1050
TyKind :: Error . intern ( Interner )
1022
1051
}
1023
1052
}
0 commit comments