@@ -15,7 +15,7 @@ use super::{Obligation, ObligationCause};
1515use super :: project;
1616use super :: util;
1717
18- use middle:: subst:: { Subst } ;
18+ use middle:: subst:: { Subst , TypeSpace } ;
1919use middle:: ty:: { self , Ty } ;
2020use middle:: infer:: InferCtxt ;
2121use std:: collections:: HashSet ;
@@ -89,16 +89,28 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
8989 return Ok ( ( ) ) ;
9090 }
9191
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+ }
102114 }
103115
104116 return Ok ( ( ) ) ;
@@ -162,13 +174,17 @@ fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
162174
163175/// All type parameters reachable from `ty`
164176fn 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+ }
174190}
0 commit comments