@@ -14,10 +14,10 @@ use super::SelectionContext;
1414use super :: { Obligation , ObligationCause } ;
1515use super :: util;
1616
17- use middle:: subst;
1817use middle:: subst:: Subst ;
1918use middle:: ty:: { mod, Ty } ;
2019use middle:: infer:: InferCtxt ;
20+ use std:: collections:: HashSet ;
2121use std:: rc:: Rc ;
2222use syntax:: ast;
2323use syntax:: codemap:: DUMMY_SP ;
@@ -52,9 +52,21 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
5252 selcx. evaluate_impl ( impl2_def_id, & obligation)
5353}
5454
55- pub fn impl_is_local ( tcx : & ty:: ctxt ,
56- impl_def_id : ast:: DefId )
57- -> bool
55+ #[ allow( missing_copy_implementations) ]
56+ pub enum OrphanCheckErr {
57+ NoLocalInputType ,
58+ UncoveredTypeParameter ( ty:: ParamTy ) ,
59+ }
60+
61+ /// Checks the coherence orphan rules. `impl_def_id` should be the
62+ /// def-id of a trait impl. To pass, either the trait must be local, or else
63+ /// two conditions must be satisfied:
64+ ///
65+ /// 1. At least one of the input types must involve a local type.
66+ /// 2. All type parameters must be covered by a local type.
67+ pub fn orphan_check ( tcx : & ty:: ctxt ,
68+ impl_def_id : ast:: DefId )
69+ -> Result < ( ) , OrphanCheckErr >
5870{
5971 debug ! ( "impl_is_local({})" , impl_def_id. repr( tcx) ) ;
6072
@@ -63,99 +75,74 @@ pub fn impl_is_local(tcx: &ty::ctxt,
6375 let trait_ref = ty:: impl_trait_ref ( tcx, impl_def_id) . unwrap ( ) ;
6476 debug ! ( "trait_ref={}" , trait_ref. repr( tcx) ) ;
6577
66- // If the trait is local to the crate, ok.
78+ // If the * trait* is local to the crate, ok.
6779 if trait_ref. def_id . krate == ast:: LOCAL_CRATE {
6880 debug ! ( "trait {} is local to current crate" ,
6981 trait_ref. def_id. repr( tcx) ) ;
70- return true ;
82+ return Ok ( ( ) ) ;
7183 }
7284
73- // Otherwise, at least one of the input types must be local to the
74- // crate.
75- trait_ref. input_types ( ) . iter ( ) . any ( |& t| ty_is_local ( tcx, t) )
85+ // Check condition 1: at least one type must be local.
86+ if !trait_ref. input_types ( ) . iter ( ) . any ( |& t| ty_reaches_local ( tcx, t) ) {
87+ return Err ( OrphanCheckErr :: NoLocalInputType ) ;
88+ }
89+
90+ // Check condition 2: type parameters must be "covered" by a local type.
91+ let covered_params: HashSet < _ > =
92+ trait_ref. input_types ( ) . iter ( )
93+ . flat_map ( |& t| type_parameters_covered_by_ty ( tcx, t) . into_iter ( ) )
94+ . collect ( ) ;
95+ let all_params: HashSet < _ > =
96+ trait_ref. input_types ( ) . iter ( )
97+ . flat_map ( |& t| type_parameters_reachable_from_ty ( t) . into_iter ( ) )
98+ . collect ( ) ;
99+ for & param in all_params. difference ( & covered_params) {
100+ return Err ( OrphanCheckErr :: UncoveredTypeParameter ( param) ) ;
101+ }
102+
103+ return Ok ( ( ) ) ;
104+ }
105+
106+ fn ty_reaches_local < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
107+ ty. walk ( ) . any ( |t| ty_is_local_constructor ( tcx, t) )
76108}
77109
78- pub fn ty_is_local < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
79- debug ! ( "ty_is_local ({})" , ty. repr( tcx) ) ;
110+ fn ty_is_local_constructor < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
111+ debug ! ( "ty_is_local_constructor ({})" , ty. repr( tcx) ) ;
80112
81113 match ty. sty {
82114 ty:: ty_bool |
83115 ty:: ty_char |
84116 ty:: ty_int( ..) |
85117 ty:: ty_uint( ..) |
86118 ty:: ty_float( ..) |
87- ty:: ty_str( ..) => {
88- false
89- }
90-
91- ty:: ty_unboxed_closure( ..) => {
92- // This routine is invoked on types specified by users as
93- // part of an impl and hence an unboxed closure type
94- // cannot appear.
95- tcx. sess . bug ( "ty_is_local applied to unboxed closure type" )
96- }
97-
119+ ty:: ty_str( ..) |
98120 ty:: ty_bare_fn( ..) |
99- ty:: ty_closure( ..) => {
121+ ty:: ty_closure( ..) |
122+ ty:: ty_vec( ..) |
123+ ty:: ty_ptr( ..) |
124+ ty:: ty_rptr( ..) |
125+ ty:: ty_tup( ..) |
126+ ty:: ty_param( ..) |
127+ ty:: ty_projection( ..) => {
100128 false
101129 }
102130
103- ty:: ty_uniq( t) => {
104- let krate = tcx. lang_items . owned_box ( ) . map ( |d| d. krate ) ;
105- krate == Some ( ast:: LOCAL_CRATE ) || ty_is_local ( tcx, t)
106- }
107-
108- ty:: ty_vec( t, _) |
109- ty:: ty_ptr( ty:: mt { ty : t, .. } ) |
110- ty:: ty_rptr( _, ty:: mt { ty : t, .. } ) => {
111- ty_is_local ( tcx, t)
112- }
113-
114- ty:: ty_tup( ref ts) => {
115- ts. iter ( ) . any ( |& t| ty_is_local ( tcx, t) )
131+ ty:: ty_enum( def_id, _) |
132+ ty:: ty_struct( def_id, _) => {
133+ def_id. krate == ast:: LOCAL_CRATE
116134 }
117135
118- ty:: ty_enum( def_id, ref substs) |
119- ty:: ty_struct( def_id, ref substs) => {
120- def_id. krate == ast:: LOCAL_CRATE || {
121- let variances = ty:: item_variances ( tcx, def_id) ;
122- subst:: ParamSpace :: all ( ) . iter ( ) . any ( |& space| {
123- substs. types . get_slice ( space) . iter ( ) . enumerate ( ) . any (
124- |( i, & t) | {
125- match * variances. types . get ( space, i) {
126- ty:: Bivariant => {
127- // If Foo<T> is bivariant with respect to
128- // T, then it doesn't matter whether T is
129- // local or not, because `Foo<U>` for any
130- // U will be a subtype of T.
131- false
132- }
133- ty:: Contravariant |
134- ty:: Covariant |
135- ty:: Invariant => {
136- ty_is_local ( tcx, t)
137- }
138- }
139- } )
140- } )
141- }
136+ ty:: ty_uniq( _) => { // treat ~T like Box<T>
137+ let krate = tcx. lang_items . owned_box ( ) . map ( |d| d. krate ) ;
138+ krate == Some ( ast:: LOCAL_CRATE )
142139 }
143140
144141 ty:: ty_trait( ref tt) => {
145142 tt. principal_def_id ( ) . krate == ast:: LOCAL_CRATE
146143 }
147144
148- // Type parameters may be bound to types that are not local to
149- // the crate.
150- ty:: ty_param( ..) => {
151- false
152- }
153-
154- // Associated types could be anything, I guess.
155- ty:: ty_projection( ..) => {
156- false
157- }
158-
145+ ty:: ty_unboxed_closure( ..) |
159146 ty:: ty_infer( ..) |
160147 ty:: ty_open( ..) |
161148 ty:: ty_err => {
@@ -165,3 +152,27 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
165152 }
166153 }
167154}
155+
156+ fn type_parameters_covered_by_ty < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
157+ ty : Ty < ' tcx > )
158+ -> HashSet < ty:: ParamTy >
159+ {
160+ if ty_is_local_constructor ( tcx, ty) {
161+ type_parameters_reachable_from_ty ( ty)
162+ } else {
163+ ty. walk_children ( ) . flat_map ( |t| type_parameters_covered_by_ty ( tcx, t) . into_iter ( ) ) . collect ( )
164+ }
165+ }
166+
167+ /// All type parameters reachable from `ty`
168+ fn type_parameters_reachable_from_ty < ' tcx > ( ty : Ty < ' tcx > ) -> HashSet < ty:: ParamTy > {
169+ ty. walk ( )
170+ . filter_map ( |t| {
171+ match t. sty {
172+ ty:: ty_param( ref param_ty) => Some ( param_ty. clone ( ) ) ,
173+ _ => None ,
174+ }
175+ } )
176+ . collect ( )
177+ }
178+
0 commit comments