@@ -20,16 +20,17 @@ use ty::subst::Subst;
20
20
use infer:: { InferCtxt , InferOk } ;
21
21
22
22
#[ derive( Copy , Clone , Debug ) ]
23
- enum InferIsLocal {
24
- BrokenYes ,
25
- Yes ,
26
- No
23
+ /// Whether we do the orphan check relative to this crate or
24
+ /// to some remote crate.
25
+ enum InCrate {
26
+ Local ,
27
+ Remote
27
28
}
28
29
29
30
#[ derive( Debug , Copy , Clone ) ]
30
31
pub enum Conflict {
31
32
Upstream ,
32
- Downstream
33
+ Downstream { used_to_be_broken : bool }
33
34
}
34
35
35
36
pub struct OverlapResult < ' tcx > {
@@ -136,21 +137,23 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
136
137
}
137
138
138
139
pub fn trait_ref_is_knowable < ' a , ' gcx , ' tcx > ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
139
- trait_ref : ty:: TraitRef < ' tcx > ,
140
- broken : bool )
140
+ trait_ref : ty:: TraitRef < ' tcx > )
141
141
-> Option < Conflict >
142
142
{
143
- debug ! ( "trait_ref_is_knowable(trait_ref={:?}, broken={:?})" , trait_ref, broken) ;
144
- let mode = if broken {
145
- InferIsLocal :: BrokenYes
146
- } else {
147
- InferIsLocal :: Yes
148
- } ;
149
- if orphan_check_trait_ref ( tcx, trait_ref, mode) . is_ok ( ) {
143
+ debug ! ( "trait_ref_is_knowable(trait_ref={:?})" , trait_ref) ;
144
+ if orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Remote ) . is_ok ( ) {
150
145
// A downstream or cousin crate is allowed to implement some
151
146
// substitution of this trait-ref.
152
- debug ! ( "trait_ref_is_knowable: downstream crate might implement" ) ;
153
- return Some ( Conflict :: Downstream ) ;
147
+
148
+ // A trait can be implementable for a trait ref by both the current
149
+ // crate and crates downstream of it. Older versions of rustc
150
+ // were not aware of this, causing incoherence (issue #43355).
151
+ let used_to_be_broken =
152
+ orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local ) . is_ok ( ) ;
153
+ if used_to_be_broken {
154
+ debug ! ( "trait_ref_is_knowable({:?}) - USED TO BE BROKEN" , trait_ref) ;
155
+ }
156
+ return Some ( Conflict :: Downstream { used_to_be_broken } ) ;
154
157
}
155
158
156
159
if trait_ref_is_local_or_fundamental ( tcx, trait_ref) {
@@ -161,6 +164,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
161
164
// which we already know about.
162
165
return None ;
163
166
}
167
+
164
168
// This is a remote non-fundamental trait, so if another crate
165
169
// can be the "final owner" of a substitution of this trait-ref,
166
170
// they are allowed to implement it future-compatibly.
@@ -169,7 +173,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
169
173
// and if we are an intermediate owner, then we don't care
170
174
// about future-compatibility, which means that we're OK if
171
175
// we are an owner.
172
- if orphan_check_trait_ref ( tcx, trait_ref, InferIsLocal :: No ) . is_ok ( ) {
176
+ if orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local ) . is_ok ( ) {
173
177
debug ! ( "trait_ref_is_knowable: orphan check passed" ) ;
174
178
return None ;
175
179
} else {
@@ -213,31 +217,31 @@ pub fn orphan_check<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
213
217
return Ok ( ( ) ) ;
214
218
}
215
219
216
- orphan_check_trait_ref ( tcx, trait_ref, InferIsLocal :: No )
220
+ orphan_check_trait_ref ( tcx, trait_ref, InCrate :: Local )
217
221
}
218
222
219
223
fn orphan_check_trait_ref < ' tcx > ( tcx : TyCtxt ,
220
224
trait_ref : ty:: TraitRef < ' tcx > ,
221
- infer_is_local : InferIsLocal )
225
+ in_crate : InCrate )
222
226
-> Result < ( ) , OrphanCheckErr < ' tcx > >
223
227
{
224
- debug ! ( "orphan_check_trait_ref(trait_ref={:?}, infer_is_local ={:?})" ,
225
- trait_ref, infer_is_local ) ;
228
+ debug ! ( "orphan_check_trait_ref(trait_ref={:?}, in_crate ={:?})" ,
229
+ trait_ref, in_crate ) ;
226
230
227
231
// First, create an ordered iterator over all the type parameters to the trait, with the self
228
232
// type appearing first.
229
233
// Find the first input type that either references a type parameter OR
230
234
// some local type.
231
235
for input_ty in trait_ref. input_types ( ) {
232
- if ty_is_local ( tcx, input_ty, infer_is_local ) {
236
+ if ty_is_local ( tcx, input_ty, in_crate ) {
233
237
debug ! ( "orphan_check_trait_ref: ty_is_local `{:?}`" , input_ty) ;
234
238
235
239
// First local input type. Check that there are no
236
240
// uncovered type parameters.
237
- let uncovered_tys = uncovered_tys ( tcx, input_ty, infer_is_local ) ;
241
+ let uncovered_tys = uncovered_tys ( tcx, input_ty, in_crate ) ;
238
242
for uncovered_ty in uncovered_tys {
239
243
if let Some ( param) = uncovered_ty. walk ( )
240
- . find ( |t| is_possibly_remote_type ( t, infer_is_local ) )
244
+ . find ( |t| is_possibly_remote_type ( t, in_crate ) )
241
245
{
242
246
debug ! ( "orphan_check_trait_ref: uncovered type `{:?}`" , param) ;
243
247
return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
@@ -251,7 +255,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
251
255
// Otherwise, enforce invariant that there are no type
252
256
// parameters reachable.
253
257
if let Some ( param) = input_ty. walk ( )
254
- . find ( |t| is_possibly_remote_type ( t, infer_is_local ) )
258
+ . find ( |t| is_possibly_remote_type ( t, in_crate ) )
255
259
{
256
260
debug ! ( "orphan_check_trait_ref: uncovered type `{:?}`" , param) ;
257
261
return Err ( OrphanCheckErr :: UncoveredTy ( param) ) ;
@@ -263,29 +267,29 @@ fn orphan_check_trait_ref<'tcx>(tcx: TyCtxt,
263
267
return Err ( OrphanCheckErr :: NoLocalInputType ) ;
264
268
}
265
269
266
- fn uncovered_tys < ' tcx > ( tcx : TyCtxt , ty : Ty < ' tcx > , infer_is_local : InferIsLocal )
270
+ fn uncovered_tys < ' tcx > ( tcx : TyCtxt , ty : Ty < ' tcx > , in_crate : InCrate )
267
271
-> Vec < Ty < ' tcx > > {
268
- if ty_is_local_constructor ( ty, infer_is_local ) {
272
+ if ty_is_local_constructor ( ty, in_crate ) {
269
273
vec ! [ ]
270
274
} else if fundamental_ty ( tcx, ty) {
271
275
ty. walk_shallow ( )
272
- . flat_map ( |t| uncovered_tys ( tcx, t, infer_is_local ) )
276
+ . flat_map ( |t| uncovered_tys ( tcx, t, in_crate ) )
273
277
. collect ( )
274
278
} else {
275
279
vec ! [ ty]
276
280
}
277
281
}
278
282
279
- fn is_possibly_remote_type ( ty : Ty , _infer_is_local : InferIsLocal ) -> bool {
283
+ fn is_possibly_remote_type ( ty : Ty , _in_crate : InCrate ) -> bool {
280
284
match ty. sty {
281
285
ty:: TyProjection ( ..) | ty:: TyParam ( ..) => true ,
282
286
_ => false ,
283
287
}
284
288
}
285
289
286
- fn ty_is_local ( tcx : TyCtxt , ty : Ty , infer_is_local : InferIsLocal ) -> bool {
287
- ty_is_local_constructor ( ty, infer_is_local ) ||
288
- fundamental_ty ( tcx, ty) && ty. walk_shallow ( ) . any ( |t| ty_is_local ( tcx, t, infer_is_local ) )
290
+ fn ty_is_local ( tcx : TyCtxt , ty : Ty , in_crate : InCrate ) -> bool {
291
+ ty_is_local_constructor ( ty, in_crate ) ||
292
+ fundamental_ty ( tcx, ty) && ty. walk_shallow ( ) . any ( |t| ty_is_local ( tcx, t, in_crate ) )
289
293
}
290
294
291
295
fn fundamental_ty ( tcx : TyCtxt , ty : Ty ) -> bool {
@@ -299,15 +303,16 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool {
299
303
}
300
304
}
301
305
302
- fn def_id_is_local ( def_id : DefId , infer_is_local : InferIsLocal ) -> bool {
303
- match infer_is_local {
304
- InferIsLocal :: Yes => false ,
305
- InferIsLocal :: No |
306
- InferIsLocal :: BrokenYes => def_id. is_local ( )
306
+ fn def_id_is_local ( def_id : DefId , in_crate : InCrate ) -> bool {
307
+ match in_crate {
308
+ // The type is local to *this* crate - it will not be
309
+ // local in any other crate.
310
+ InCrate :: Remote => false ,
311
+ InCrate :: Local => def_id. is_local ( )
307
312
}
308
313
}
309
314
310
- fn ty_is_local_constructor ( ty : Ty , infer_is_local : InferIsLocal ) -> bool {
315
+ fn ty_is_local_constructor ( ty : Ty , in_crate : InCrate ) -> bool {
311
316
debug ! ( "ty_is_local_constructor({:?})" , ty) ;
312
317
313
318
match ty. sty {
@@ -330,18 +335,19 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal) -> bool {
330
335
false
331
336
}
332
337
333
- ty:: TyInfer ( ..) => match infer_is_local {
334
- InferIsLocal :: No => false ,
335
- InferIsLocal :: Yes |
336
- InferIsLocal :: BrokenYes => true
338
+ ty:: TyInfer ( ..) => match in_crate {
339
+ InCrate :: Local => false ,
340
+ // The inference variable might be unified with a local
341
+ // type in that remote crate.
342
+ InCrate :: Remote => true ,
337
343
} ,
338
344
339
- ty:: TyAdt ( def, _) => def_id_is_local ( def. did , infer_is_local ) ,
340
- ty:: TyForeign ( did) => def_id_is_local ( did, infer_is_local ) ,
345
+ ty:: TyAdt ( def, _) => def_id_is_local ( def. did , in_crate ) ,
346
+ ty:: TyForeign ( did) => def_id_is_local ( did, in_crate ) ,
341
347
342
348
ty:: TyDynamic ( ref tt, ..) => {
343
349
tt. principal ( ) . map_or ( false , |p| {
344
- def_id_is_local ( p. def_id ( ) , infer_is_local )
350
+ def_id_is_local ( p. def_id ( ) , in_crate )
345
351
} )
346
352
}
347
353
0 commit comments