13
13
use hir:: def_id:: { DefId , LOCAL_CRATE } ;
14
14
use syntax_pos:: DUMMY_SP ;
15
15
use traits:: { self , Normalized , SelectionContext , Obligation , ObligationCause , Reveal } ;
16
+ use traits:: IntercrateMode ;
16
17
use traits:: select:: IntercrateAmbiguityCause ;
17
18
use ty:: { self , Ty , TyCtxt } ;
18
19
use ty:: subst:: Subst ;
19
20
20
21
use infer:: { InferCtxt , InferOk } ;
21
22
22
- #[ derive( Copy , Clone ) ]
23
- struct InferIsLocal ( bool ) ;
23
+ #[ derive( Copy , Clone , Debug ) ]
24
+ /// Whether we do the orphan check relative to this crate or
25
+ /// to some remote crate.
26
+ enum InCrate {
27
+ Local ,
28
+ Remote
29
+ }
30
+
31
+ #[ derive( Debug , Copy , Clone ) ]
32
+ pub enum Conflict {
33
+ Upstream ,
34
+ Downstream { used_to_be_broken : bool }
35
+ }
24
36
25
37
pub struct OverlapResult < ' tcx > {
26
38
pub impl_header : ty:: ImplHeader < ' tcx > ,
@@ -31,16 +43,19 @@ pub struct OverlapResult<'tcx> {
31
43
/// `ImplHeader` with those types substituted
32
44
pub fn overlapping_impls < ' cx , ' gcx , ' tcx > ( infcx : & InferCtxt < ' cx , ' gcx , ' tcx > ,
33
45
impl1_def_id : DefId ,
34
- impl2_def_id : DefId )
46
+ impl2_def_id : DefId ,
47
+ intercrate_mode : IntercrateMode )
35
48
-> Option < OverlapResult < ' tcx > >
36
49
{
37
50
debug ! ( "impl_can_satisfy(\
38
51
impl1_def_id={:?}, \
39
- impl2_def_id={:?})",
52
+ impl2_def_id={:?},
53
+ intercrate_mode={:?})" ,
40
54
impl1_def_id,
41
- impl2_def_id) ;
55
+ impl2_def_id,
56
+ intercrate_mode) ;
42
57
43
- let selcx = & mut SelectionContext :: intercrate ( infcx) ;
58
+ let selcx = & mut SelectionContext :: intercrate ( infcx, intercrate_mode ) ;
44
59
overlap ( selcx, impl1_def_id, impl2_def_id)
45
60
}
46
61
@@ -126,32 +141,49 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
126
141
}
127
142
128
143
pub fn trait_ref_is_knowable < ' a , ' gcx , ' tcx > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
129
- trait_ref : ty:: TraitRef < ' tcx > ) -> bool
144
+ trait_ref : ty:: TraitRef < ' tcx > )
145
+ -> Option < Conflict >
130
146
{
131
147
debug ! ( "trait_ref_is_knowable(trait_ref={:?})" , trait_ref) ;
132
-
133
- // if the orphan rules pass, that means that no ancestor crate can
134
- // impl this, so it's up to us.
135
- if orphan_check_trait_ref ( tcx, trait_ref, InferIsLocal ( false ) ) . is_ok ( ) {
136
- debug ! ( "trait_ref_is_knowable: orphan check passed" ) ;
137
- return true ;
148
+ if orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Remote ) . is_ok ( ) {
149
+ // A downstream or cousin crate is allowed to implement some
150
+ // substitution of this trait-ref.
151
+
152
+ // A trait can be implementable for a trait ref by both the current
153
+ // crate and crates downstream of it. Older versions of rustc
154
+ // were not aware of this, causing incoherence (issue #43355).
155
+ let used_to_be_broken =
156
+ orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local ) . is_ok ( ) ;
157
+ if used_to_be_broken {
158
+ debug ! ( "trait_ref_is_knowable({:?}) - USED TO BE BROKEN" , trait_ref) ;
159
+ }
160
+ return Some ( Conflict :: Downstream { used_to_be_broken } ) ;
138
161
}
139
162
140
- // if the trait is not marked fundamental, then it's always possible that
141
- // an ancestor crate will impl this in the future, if they haven't
142
- // already
143
- if !trait_ref_is_local_or_fundamental ( tcx, trait_ref) {
144
- debug ! ( "trait_ref_is_knowable: trait is neither local nor fundamental" ) ;
145
- return false ;
163
+ if trait_ref_is_local_or_fundamental ( tcx, trait_ref) {
164
+ // This is a local or fundamental trait, so future-compatibility
165
+ // is no concern. We know that downstream/cousin crates are not
166
+ // allowed to implement a substitution of this trait ref, which
167
+ // means impls could only come from dependencies of this crate,
168
+ // which we already know about.
169
+ return None ;
146
170
}
147
171
148
- // find out when some downstream (or cousin) crate could impl this
149
- // trait-ref, presuming that all the parameters were instantiated
150
- // with downstream types. If not, then it could only be
151
- // implemented by an upstream crate, which means that the impl
152
- // must be visible to us, and -- since the trait is fundamental
153
- // -- we can test.
154
- orphan_check_trait_ref ( tcx, trait_ref, InferIsLocal ( true ) ) . is_err ( )
172
+ // This is a remote non-fundamental trait, so if another crate
173
+ // can be the "final owner" of a substitution of this trait-ref,
174
+ // they are allowed to implement it future-compatibly.
175
+ //
176
+ // However, if we are a final owner, then nobody else can be,
177
+ // and if we are an intermediate owner, then we don't care
178
+ // about future-compatibility, which means that we're OK if
179
+ // we are an owner.
180
+ if orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local ) . is_ok ( ) {
181
+ debug ! ( "trait_ref_is_knowable: orphan check passed" ) ;
182
+ return None ;
183
+ } else {
184
+ debug ! ( "trait_ref_is_knowable: nonlocal, nonfundamental, unowned" ) ;
185
+ return Some ( Conflict :: Upstream ) ;
186
+ }
155
187
}
156
188
157
189
pub fn trait_ref_is_local_or_fundamental < ' a , ' gcx , ' tcx > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
@@ -189,30 +221,32 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
189
221
return Ok ( ( ) ) ;
190
222
}
191
223
192
- orphan_check_trait_ref ( tcx, trait_ref, InferIsLocal ( false ) )
224
+ orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local )
193
225
}
194
226
195
227
fn orphan_check_trait_ref < ' tcx > ( tcx : TyCtxt ,
196
228
trait_ref : ty:: TraitRef < ' tcx > ,
197
- infer_is_local : InferIsLocal )
229
+ in_crate : InCrate )
198
230
-> Result < ( ) , OrphanCheckErr < ' tcx > >
199
231
{
200
- debug ! ( "orphan_check_trait_ref(trait_ref={:?}, infer_is_local={ })" ,
201
- trait_ref, infer_is_local . 0 ) ;
232
+ debug ! ( "orphan_check_trait_ref(trait_ref={:?}, in_crate={:? })" ,
233
+ trait_ref, in_crate ) ;
202
234
203
235
// First, create an ordered iterator over all the type parameters to the trait, with the self
204
236
// type appearing first.
205
237
// Find the first input type that either references a type parameter OR
206
238
// some local type.
207
239
for input_ty in trait_ref. input_types ( ) {
208
- if ty_is_local ( tcx, input_ty, infer_is_local ) {
240
+ if ty_is_local ( tcx, input_ty, in_crate ) {
209
241
debug ! ( "orphan_check_trait_ref: ty_is_local `{:?}`" , input_ty) ;
210
242
211
243
// First local input type. Check that there are no
212
244
// uncovered type parameters.
213
- let uncovered_tys = uncovered_tys ( tcx, input_ty, infer_is_local ) ;
245
+ let uncovered_tys = uncovered_tys ( tcx, input_ty, in_crate ) ;
214
246
for uncovered_ty in uncovered_tys {
215
- if let Some ( param) = uncovered_ty. walk ( ) . find ( |t| is_type_parameter ( t) ) {
247
+ if let Some ( param) = uncovered_ty. walk ( )
248
+ . find ( |t| is_possibly_remote_type ( t, in_crate) )
249
+ {
216
250
debug ! ( "orphan_check_trait_ref: uncovered type `{:?}`" , param) ;
217
251
return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
218
252
}
@@ -224,11 +258,11 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
224
258
225
259
// Otherwise, enforce invariant that there are no type
226
260
// parameters reachable.
227
- if !infer_is_local . 0 {
228
- if let Some ( param ) = input_ty . walk ( ) . find ( |t| is_type_parameter ( t ) ) {
229
- debug ! ( "orphan_check_trait_ref: uncovered type `{:?}`" , param ) ;
230
- return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
231
- }
261
+ if let Some ( param ) = input_ty . walk ( )
262
+ . find ( |t| is_possibly_remote_type ( t , in_crate ) )
263
+ {
264
+ debug ! ( "orphan_check_trait_ref: uncovered type `{:?}`" , param) ;
265
+ return Err ( OrphanCheckErr :: UncoveredTy ( param ) ) ;
232
266
}
233
267
}
234
268
@@ -237,29 +271,29 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
237
271
return Err ( OrphanCheckErr :: NoLocalInputType ) ;
238
272
}
239
273
240
- fn uncovered_tys < ' tcx > ( tcx : TyCtxt , ty : Ty < ' tcx > , infer_is_local : InferIsLocal )
274
+ fn uncovered_tys < ' tcx > ( tcx : TyCtxt , ty : Ty < ' tcx > , in_crate : InCrate )
241
275
-> Vec < Ty < ' tcx > > {
242
- if ty_is_local_constructor ( ty, infer_is_local ) {
276
+ if ty_is_local_constructor ( ty, in_crate ) {
243
277
vec ! [ ]
244
278
} else if fundamental_ty ( tcx, ty) {
245
279
ty. walk_shallow ( )
246
- . flat_map ( |t| uncovered_tys ( tcx, t, infer_is_local ) )
280
+ . flat_map ( |t| uncovered_tys ( tcx, t, in_crate ) )
247
281
. collect ( )
248
282
} else {
249
283
vec ! [ ty]
250
284
}
251
285
}
252
286
253
- fn is_type_parameter ( ty : Ty ) -> bool {
287
+ fn is_possibly_remote_type ( ty : Ty , _in_crate : InCrate ) -> bool {
254
288
match ty. sty {
255
289
ty:: TyProjection ( ..) | ty:: TyParam ( ..) => true ,
256
290
_ => false ,
257
291
}
258
292
}
259
293
260
- fn ty_is_local ( tcx : TyCtxt , ty : Ty , infer_is_local : InferIsLocal ) -> bool {
261
- ty_is_local_constructor ( ty, infer_is_local ) ||
262
- fundamental_ty ( tcx, ty) && ty. walk_shallow ( ) . any ( |t| ty_is_local ( tcx, t, infer_is_local ) )
294
+ fn ty_is_local ( tcx : TyCtxt , ty : Ty , in_crate : InCrate ) -> bool {
295
+ ty_is_local_constructor ( ty, in_crate ) ||
296
+ fundamental_ty ( tcx, ty) && ty. walk_shallow ( ) . any ( |t| ty_is_local ( tcx, t, in_crate ) )
263
297
}
264
298
265
299
fn fundamental_ty ( tcx : TyCtxt , ty : Ty ) -> bool {
@@ -273,7 +307,16 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
273
307
}
274
308
}
275
309
276
- fn ty_is_local_constructor ( ty : Ty , infer_is_local : InferIsLocal ) -> bool {
310
+ fn def_id_is_local ( def_id : DefId , in_crate : InCrate ) -> bool {
311
+ match in_crate {
312
+ // The type is local to *this* crate - it will not be
313
+ // local in any other crate.
314
+ InCrate :: Remote => false ,
315
+ InCrate :: Local => def_id. is_local ( )
316
+ }
317
+ }
318
+
319
+ fn ty_is_local_constructor ( ty : Ty , in_crate : InCrate ) -> bool {
277
320
debug ! ( "ty_is_local_constructor({:?})" , ty) ;
278
321
279
322
match ty. sty {
@@ -296,20 +339,20 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool {
296
339
false
297
340
}
298
341
299
- ty:: TyInfer ( ..) => {
300
- infer_is_local. 0
301
- }
302
-
303
- ty:: TyAdt ( def, _) => {
304
- def. did . is_local ( )
305
- }
342
+ ty:: TyInfer ( ..) => match in_crate {
343
+ InCrate :: Local => false ,
344
+ // The inference variable might be unified with a local
345
+ // type in that remote crate.
346
+ InCrate :: Remote => true ,
347
+ } ,
306
348
307
- ty:: TyForeign ( did) => {
308
- did. is_local ( )
309
- }
349
+ ty:: TyAdt ( def, _) => def_id_is_local ( def. did , in_crate) ,
350
+ ty:: TyForeign ( did) => def_id_is_local ( did, in_crate) ,
310
351
311
352
ty:: TyDynamic ( ref tt, ..) => {
312
- tt. principal ( ) . map_or ( false , |p| p. def_id ( ) . is_local ( ) )
353
+ tt. principal ( ) . map_or ( false , |p| {
354
+ def_id_is_local ( p. def_id ( ) , in_crate)
355
+ } )
313
356
}
314
357
315
358
ty:: TyError => {
0 commit comments