@@ -981,43 +981,72 @@ impl<'a> TyLoweringContext<'a> {
981981
982982 fn lower_dyn_trait ( & self , bounds : & [ Interned < TypeBound > ] ) -> Ty {
983983 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.
984988 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) )
9971011 }
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 ! ( ) ,
10001031 }
1001- }
1032+ } ) ;
10021033
1003- if regular_traits . len ( ) > 1 {
1034+ if multiple_regular_traits || multiple_same_projection {
10041035 return None ;
10051036 }
10061037
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 ( ) ;
10091041
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) )
10141043 } ) ;
10151044
10161045 if let Some ( bounds) = bounds {
10171046 let bounds = crate :: make_single_type_binders ( bounds) ;
10181047 TyKind :: Dyn ( DynTy { bounds, lifetime : static_lifetime ( ) } ) . intern ( Interner )
10191048 } else {
1020- // FIXME: report error (additional non-auto traits)
1049+ // FIXME: report error (additional non-auto traits or associated type rebound )
10211050 TyKind :: Error . intern ( Interner )
10221051 }
10231052 }
0 commit comments