@@ -17,15 +17,17 @@ use super::PredicateObligation;
17
17
use super :: project;
18
18
use super :: util;
19
19
20
- use middle:: subst:: { Subst , TypeSpace } ;
20
+ use middle:: subst:: { Subst , Substs , TypeSpace } ;
21
21
use middle:: ty:: { self , ToPolyTraitRef , Ty } ;
22
22
use middle:: infer:: { self , InferCtxt } ;
23
- use std:: collections:: HashSet ;
24
23
use std:: rc:: Rc ;
25
24
use syntax:: ast;
26
- use syntax:: codemap:: DUMMY_SP ;
25
+ use syntax:: codemap:: { DUMMY_SP , Span } ;
27
26
use util:: ppaux:: Repr ;
28
27
28
+ #[ derive( Copy ) ]
29
+ struct ParamIsLocal ( bool ) ;
30
+
29
31
/// True if there exist types that satisfy both of the two given impls.
30
32
pub fn overlapping_impls ( infcx : & InferCtxt ,
31
33
impl1_def_id : ast:: DefId ,
@@ -56,10 +58,16 @@ fn overlap(selcx: &mut SelectionContext,
56
58
a_def_id. repr( selcx. tcx( ) ) ,
57
59
b_def_id. repr( selcx. tcx( ) ) ) ;
58
60
59
- let ( a_trait_ref, a_obligations) = impl_trait_ref_and_oblig ( selcx, a_def_id) ;
60
- let ( b_trait_ref, b_obligations) = impl_trait_ref_and_oblig ( selcx, b_def_id) ;
61
+ let ( a_trait_ref, a_obligations) = impl_trait_ref_and_oblig ( selcx,
62
+ a_def_id,
63
+ util:: free_substs_for_impl) ;
64
+
65
+ let ( b_trait_ref, b_obligations) = impl_trait_ref_and_oblig ( selcx,
66
+ b_def_id,
67
+ util:: fresh_type_vars_for_impl) ;
61
68
62
69
debug ! ( "overlap: a_trait_ref={}" , a_trait_ref. repr( selcx. tcx( ) ) ) ;
70
+
63
71
debug ! ( "overlap: b_trait_ref={}" , b_trait_ref. repr( selcx. tcx( ) ) ) ;
64
72
65
73
// Does `a <: b` hold? If not, no overlap.
@@ -74,28 +82,68 @@ fn overlap(selcx: &mut SelectionContext,
74
82
debug ! ( "overlap: subtraitref check succeeded" ) ;
75
83
76
84
// Are any of the obligations unsatisfiable? If so, no overlap.
85
+ let tcx = selcx. tcx ( ) ;
86
+ let infcx = selcx. infcx ( ) ;
77
87
let opt_failing_obligation =
78
88
a_obligations. iter ( )
79
89
. chain ( b_obligations. iter ( ) )
90
+ . map ( |o| infcx. resolve_type_vars_if_possible ( o) )
80
91
. find ( |o| !selcx. evaluate_obligation ( o) ) ;
81
92
82
93
if let Some ( failing_obligation) = opt_failing_obligation {
83
- debug ! ( "overlap: obligation unsatisfiable {}" , failing_obligation. repr( selcx . tcx( ) ) ) ;
84
- return false ;
94
+ debug ! ( "overlap: obligation unsatisfiable {}" , failing_obligation. repr( tcx) ) ;
95
+ return false
85
96
}
86
97
87
98
true
88
99
}
89
100
101
+ pub fn trait_ref_is_knowable < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , trait_ref : & ty:: TraitRef < ' tcx > ) -> bool
102
+ {
103
+ debug ! ( "trait_ref_is_knowable(trait_ref={})" , trait_ref. repr( tcx) ) ;
104
+
105
+ // if the orphan rules pass, that means that no ancestor crate can
106
+ // impl this, so it's up to us.
107
+ if orphan_check_trait_ref ( tcx, trait_ref, ParamIsLocal ( false ) ) . is_ok ( ) {
108
+ debug ! ( "trait_ref_is_knowable: orphan check passed" ) ;
109
+ return true ;
110
+ }
111
+
112
+ // if the trait is not marked fundamental, then it's always possible that
113
+ // an ancestor crate will impl this in the future, if they haven't
114
+ // already
115
+ if
116
+ trait_ref. def_id . krate != ast:: LOCAL_CRATE &&
117
+ !ty:: has_attr ( tcx, trait_ref. def_id , "fundamental" )
118
+ {
119
+ debug ! ( "trait_ref_is_knowable: trait is neither local nor fundamental" ) ;
120
+ return false ;
121
+ }
122
+
123
+ // find out when some downstream (or cousin) crate could impl this
124
+ // trait-ref, presuming that all the parameters were instantiated
125
+ // with downstream types. If not, then it could only be
126
+ // implemented by an upstream crate, which means that the impl
127
+ // must be visible to us, and -- since the trait is fundamental
128
+ // -- we can test.
129
+ orphan_check_trait_ref ( tcx, trait_ref, ParamIsLocal ( true ) ) . is_err ( )
130
+ }
131
+
132
+ type SubstsFn = for <' a , ' tcx > fn ( infcx : & InferCtxt < ' a , ' tcx > ,
133
+ span : Span ,
134
+ impl_def_id : ast:: DefId )
135
+ -> Substs < ' tcx > ;
136
+
90
137
/// Instantiate fresh variables for all bound parameters of the impl
91
138
/// and return the impl trait ref with those variables substituted.
92
139
fn impl_trait_ref_and_oblig < ' a , ' tcx > ( selcx : & mut SelectionContext < ' a , ' tcx > ,
93
- impl_def_id : ast:: DefId )
140
+ impl_def_id : ast:: DefId ,
141
+ substs_fn : SubstsFn )
94
142
-> ( Rc < ty:: TraitRef < ' tcx > > ,
95
143
Vec < PredicateObligation < ' tcx > > )
96
144
{
97
145
let impl_substs =
98
- & util :: fresh_substs_for_impl ( selcx. infcx ( ) , DUMMY_SP , impl_def_id) ;
146
+ & substs_fn ( selcx. infcx ( ) , DUMMY_SP , impl_def_id) ;
99
147
let impl_trait_ref =
100
148
ty:: impl_trait_ref ( selcx. tcx ( ) , impl_def_id) . unwrap ( ) ;
101
149
let impl_trait_ref =
@@ -134,12 +182,12 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
134
182
impl_def_id : ast:: DefId )
135
183
-> Result < ( ) , OrphanCheckErr < ' tcx > >
136
184
{
137
- debug ! ( "impl_is_local ({})" , impl_def_id. repr( tcx) ) ;
185
+ debug ! ( "orphan_check ({})" , impl_def_id. repr( tcx) ) ;
138
186
139
187
// We only except this routine to be invoked on implementations
140
188
// of a trait, not inherent implementations.
141
189
let trait_ref = ty:: impl_trait_ref ( tcx, impl_def_id) . unwrap ( ) ;
142
- debug ! ( "trait_ref={}" , trait_ref. repr( tcx) ) ;
190
+ debug ! ( "orphan_check: trait_ref={}" , trait_ref. repr( tcx) ) ;
143
191
144
192
// If the *trait* is local to the crate, ok.
145
193
if trait_ref. def_id . krate == ast:: LOCAL_CRATE {
@@ -148,34 +196,106 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>,
148
196
return Ok ( ( ) ) ;
149
197
}
150
198
199
+ orphan_check_trait_ref ( tcx, & trait_ref, ParamIsLocal ( false ) )
200
+ }
201
+
202
+ fn orphan_check_trait_ref < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
203
+ trait_ref : & ty:: TraitRef < ' tcx > ,
204
+ param_is_local : ParamIsLocal )
205
+ -> Result < ( ) , OrphanCheckErr < ' tcx > >
206
+ {
207
+ debug ! ( "orphan_check_trait_ref(trait_ref={}, param_is_local={})" ,
208
+ trait_ref. repr( tcx) , param_is_local. 0 ) ;
209
+
151
210
// First, create an ordered iterator over all the type parameters to the trait, with the self
152
211
// type appearing first.
153
212
let input_tys = Some ( trait_ref. self_ty ( ) ) ;
154
213
let input_tys = input_tys. iter ( ) . chain ( trait_ref. substs . types . get_slice ( TypeSpace ) . iter ( ) ) ;
155
- let mut input_tys = input_tys;
156
214
157
215
// Find the first input type that either references a type parameter OR
158
216
// some local type.
159
- match input_tys. find ( |& & input_ty| references_local_or_type_parameter ( tcx, input_ty) ) {
160
- Some ( & input_ty) => {
161
- // Within this first type, check that all type parameters are covered by a local
162
- // type constructor. Note that if there is no local type constructor, then any
163
- // type parameter at all will be an error.
164
- let covered_params = type_parameters_covered_by_ty ( tcx, input_ty) ;
165
- let all_params = type_parameters_reachable_from_ty ( input_ty) ;
166
- for & param in all_params. difference ( & covered_params) {
167
- return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
217
+ for input_ty in input_tys {
218
+ if ty_is_local ( tcx, input_ty, param_is_local) {
219
+ debug ! ( "orphan_check_trait_ref: ty_is_local `{}`" , input_ty. repr( tcx) ) ;
220
+
221
+ // First local input type. Check that there are no
222
+ // uncovered type parameters.
223
+ let uncovered_tys = uncovered_tys ( tcx, input_ty, param_is_local) ;
224
+ for uncovered_ty in uncovered_tys {
225
+ if let Some ( param) = uncovered_ty. walk ( ) . find ( |t| is_type_parameter ( t) ) {
226
+ debug ! ( "orphan_check_trait_ref: uncovered type `{}`" , param. repr( tcx) ) ;
227
+ return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
228
+ }
168
229
}
230
+
231
+ // OK, found local type, all prior types upheld invariant.
232
+ return Ok ( ( ) ) ;
169
233
}
170
- None => {
171
- return Err ( OrphanCheckErr :: NoLocalInputType ) ;
234
+
235
+ // Otherwise, enforce invariant that there are no type
236
+ // parameters reachable.
237
+ if !param_is_local. 0 {
238
+ if let Some ( param) = input_ty. walk ( ) . find ( |t| is_type_parameter ( t) ) {
239
+ debug ! ( "orphan_check_trait_ref: uncovered type `{}`" , param. repr( tcx) ) ;
240
+ return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
241
+ }
172
242
}
173
243
}
174
244
175
- return Ok ( ( ) ) ;
245
+ // If we exit above loop, never found a local type.
246
+ debug ! ( "orphan_check_trait_ref: no local type" ) ;
247
+ return Err ( OrphanCheckErr :: NoLocalInputType ) ;
248
+ }
249
+
250
+ fn uncovered_tys < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
251
+ ty : Ty < ' tcx > ,
252
+ param_is_local : ParamIsLocal )
253
+ -> Vec < Ty < ' tcx > >
254
+ {
255
+ if ty_is_local_constructor ( tcx, ty, param_is_local) {
256
+ vec ! [ ]
257
+ } else if fundamental_ty ( tcx, ty) {
258
+ ty. walk_shallow ( )
259
+ . flat_map ( |t| uncovered_tys ( tcx, t, param_is_local) . into_iter ( ) )
260
+ . collect ( )
261
+ } else {
262
+ vec ! [ ty]
263
+ }
176
264
}
177
265
178
- fn ty_is_local_constructor < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
266
+ fn is_type_parameter < ' tcx > ( ty : Ty < ' tcx > ) -> bool {
267
+ match ty. sty {
268
+ // FIXME(#20590) straighten story about projection types
269
+ ty:: ty_projection( ..) | ty:: ty_param( ..) => true ,
270
+ _ => false ,
271
+ }
272
+ }
273
+
274
+ fn ty_is_local < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > , param_is_local : ParamIsLocal ) -> bool
275
+ {
276
+ ty_is_local_constructor ( tcx, ty, param_is_local) ||
277
+ fundamental_ty ( tcx, ty) && ty. walk_shallow ( ) . any ( |t| ty_is_local ( tcx, t, param_is_local) )
278
+ }
279
+
280
+ fn fundamental_ty < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool
281
+ {
282
+ match ty. sty {
283
+ ty:: ty_uniq( ..) | ty:: ty_rptr( ..) =>
284
+ true ,
285
+ ty:: ty_enum( def_id, _) | ty:: ty_struct( def_id, _) =>
286
+ ty:: has_attr ( tcx, def_id, "fundamental" ) ,
287
+ ty:: ty_trait( ref data) =>
288
+ ty:: has_attr ( tcx, data. principal_def_id ( ) , "fundamental" ) ,
289
+ _ =>
290
+ false
291
+ }
292
+ }
293
+
294
+ fn ty_is_local_constructor < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
295
+ ty : Ty < ' tcx > ,
296
+ param_is_local : ParamIsLocal )
297
+ -> bool
298
+ {
179
299
debug ! ( "ty_is_local_constructor({})" , ty. repr( tcx) ) ;
180
300
181
301
match ty. sty {
@@ -190,11 +310,15 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
190
310
ty:: ty_ptr( ..) |
191
311
ty:: ty_rptr( ..) |
192
312
ty:: ty_tup( ..) |
193
- ty:: ty_param ( ..) |
313
+ ty:: ty_infer ( ..) |
194
314
ty:: ty_projection( ..) => {
195
315
false
196
316
}
197
317
318
+ ty:: ty_param( ..) => {
319
+ param_is_local. 0
320
+ }
321
+
198
322
ty:: ty_enum( def_id, _) |
199
323
ty:: ty_struct( def_id, _) => {
200
324
def_id. krate == ast:: LOCAL_CRATE
@@ -210,7 +334,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
210
334
}
211
335
212
336
ty:: ty_closure( ..) |
213
- ty:: ty_infer( ..) |
214
337
ty:: ty_err => {
215
338
tcx. sess . bug (
216
339
& format ! ( "ty_is_local invoked on unexpected type: {}" ,
@@ -219,30 +342,4 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
219
342
}
220
343
}
221
344
222
- fn type_parameters_covered_by_ty < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
223
- ty : Ty < ' tcx > )
224
- -> HashSet < Ty < ' tcx > >
225
- {
226
- if ty_is_local_constructor ( tcx, ty) {
227
- type_parameters_reachable_from_ty ( ty)
228
- } else {
229
- ty. walk_children ( ) . flat_map ( |t| type_parameters_covered_by_ty ( tcx, t) . into_iter ( ) ) . collect ( )
230
- }
231
- }
232
-
233
- /// All type parameters reachable from `ty`
234
- fn type_parameters_reachable_from_ty < ' tcx > ( ty : Ty < ' tcx > ) -> HashSet < Ty < ' tcx > > {
235
- ty. walk ( ) . filter ( |& t| is_type_parameter ( t) ) . collect ( )
236
- }
237
-
238
- fn references_local_or_type_parameter < ' tcx > ( tcx : & ty:: ctxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
239
- ty. walk ( ) . any ( |ty| is_type_parameter ( ty) || ty_is_local_constructor ( tcx, ty) )
240
- }
241
345
242
- fn is_type_parameter < ' tcx > ( ty : Ty < ' tcx > ) -> bool {
243
- match ty. sty {
244
- // FIXME(#20590) straighten story about projection types
245
- ty:: ty_projection( ..) | ty:: ty_param( ..) => true ,
246
- _ => false ,
247
- }
248
- }
0 commit comments