@@ -15,7 +15,7 @@ use super::{Obligation, ObligationCause};
15
15
use super :: project;
16
16
use super :: util;
17
17
18
- use middle:: subst:: { Subst } ;
18
+ use middle:: subst:: { Subst , TypeSpace } ;
19
19
use middle:: ty:: { self , Ty } ;
20
20
use middle:: infer:: InferCtxt ;
21
21
use std:: collections:: HashSet ;
@@ -89,16 +89,28 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
89
89
return Ok ( ( ) ) ;
90
90
}
91
91
92
- // Otherwise, check that (1) all type parameters are covered.
93
- let covered_params = type_parameters_covered_by_ty ( tcx, trait_ref. self_ty ( ) ) ;
94
- let all_params = type_parameters_reachable_from_ty ( trait_ref. self_ty ( ) ) ;
95
- for & param in all_params. difference ( & covered_params) {
96
- return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
97
- }
98
-
99
- // And (2) some local type appears.
100
- if !trait_ref. self_ty ( ) . walk ( ) . any ( |t| ty_is_local_constructor ( tcx, t) ) {
101
- return Err ( OrphanCheckErr :: NoLocalInputType ) ;
92
+ // First, create an ordered iterator over all the type parameters to the trait, with the self
93
+ // type appearing first.
94
+ let input_tys = Some ( trait_ref. self_ty ( ) ) ;
95
+ let input_tys = input_tys. iter ( ) . chain ( trait_ref. substs . types . get_slice ( TypeSpace ) . iter ( ) ) ;
96
+ let mut input_tys = input_tys;
97
+
98
+ // Find the first input type that either references a type parameter OR
99
+ // some local type.
100
+ match input_tys. find ( |& & input_ty| references_local_or_type_parameter ( tcx, input_ty) ) {
101
+ Some ( & input_ty) => {
102
+ // Within this first type, check that all type parameters are covered by a local
103
+ // type constructor. Note that if there is no local type constructor, then any
104
+ // type parameter at all will be an error.
105
+ let covered_params = type_parameters_covered_by_ty ( tcx, input_ty) ;
106
+ let all_params = type_parameters_reachable_from_ty ( input_ty) ;
107
+ for & param in all_params. difference ( & covered_params) {
108
+ return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
109
+ }
110
+ }
111
+ None => {
112
+ return Err ( OrphanCheckErr :: NoLocalInputType ) ;
113
+ }
102
114
}
103
115
104
116
return Ok ( ( ) ) ;
@@ -162,13 +174,17 @@ fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
162
174
163
175
/// All type parameters reachable from `ty`
164
176
fn type_parameters_reachable_from_ty < ' tcx > ( ty : Ty < ' tcx > ) -> HashSet < Ty < ' tcx > > {
165
- ty. walk ( )
166
- . filter ( |& t| {
167
- match t. sty {
168
- // FIXME(#20590) straighten story about projection types
169
- ty:: ty_projection( ..) | ty:: ty_param( ..) => true ,
170
- _ => false ,
171
- }
172
- } )
173
- . collect ( )
177
+ ty. walk ( ) . filter ( |& t| is_type_parameter ( t) ) . collect ( )
178
+ }
179
+
180
+ fn references_local_or_type_parameter < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
181
+ ty. walk ( ) . any ( |ty| is_type_parameter ( ty) || ty_is_local_constructor ( tcx, ty) )
182
+ }
183
+
184
+ fn is_type_parameter < ' tcx > ( ty : Ty < ' tcx > ) -> bool {
185
+ match ty. sty {
186
+ // FIXME(#20590) straighten story about projection types
187
+ ty:: ty_projection( ..) | ty:: ty_param( ..) => true ,
188
+ _ => false ,
189
+ }
174
190
}
0 commit comments