@@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst;
14
14
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
15
15
use rustc_span:: symbol:: sym;
16
16
use rustc_span:: DUMMY_SP ;
17
+ use std:: iter;
17
18
18
19
/// Whether we do the orphan check relative to this crate or
19
20
/// to some remote crate.
@@ -378,19 +379,25 @@ fn orphan_check_trait_ref<'tcx>(
378
379
ty : Ty < ' tcx > ,
379
380
in_crate : InCrate ,
380
381
) -> Vec < Ty < ' tcx > > {
381
- if fundamental_ty ( ty) && ty_is_non_local ( ty, in_crate) . is_some ( ) {
382
- ty. walk_shallow ( ) . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) ) . collect ( )
383
- } else {
384
- vec ! [ ty]
382
+ // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
383
+ // or maybe if this should be calling `ty_is_non_local_constructor`.
384
+ if ty_is_non_local ( tcx, ty, in_crate) . is_some ( ) {
385
+ if let Some ( inner_tys) = fundamental_ty_inner_tys ( tcx, ty) {
386
+ return inner_tys
387
+ . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) )
388
+ . collect ( ) ;
389
+ }
385
390
}
391
+
392
+ vec ! [ ty]
386
393
}
387
394
388
395
let mut non_local_spans = vec ! [ ] ;
389
396
for ( i, input_ty) in
390
397
trait_ref. input_types ( ) . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) ) . enumerate ( )
391
398
{
392
399
debug ! ( "orphan_check_trait_ref: check ty `{:?}`" , input_ty) ;
393
- let non_local_tys = ty_is_non_local ( input_ty, in_crate) ;
400
+ let non_local_tys = ty_is_non_local ( tcx , input_ty, in_crate) ;
394
401
if non_local_tys. is_none ( ) {
395
402
debug ! ( "orphan_check_trait_ref: ty_is_local `{:?}`" , input_ty) ;
396
403
return Ok ( ( ) ) ;
@@ -416,30 +423,53 @@ fn orphan_check_trait_ref<'tcx>(
416
423
Err ( OrphanCheckErr :: NonLocalInputType ( non_local_spans) )
417
424
}
418
425
419
- fn ty_is_non_local < ' t > ( ty : Ty < ' t > , in_crate : InCrate ) -> Option < Vec < Ty < ' t > > > {
426
+ fn ty_is_non_local ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , in_crate : InCrate ) -> Option < Vec < Ty < ' tcx > > > {
420
427
match ty_is_non_local_constructor ( ty, in_crate) {
421
428
Some ( ty) => {
422
- if !fundamental_ty ( ty) {
423
- Some ( vec ! [ ty] )
424
- } else {
425
- let tys: Vec < _ > = ty
426
- . walk_shallow ( )
427
- . filter_map ( |t| ty_is_non_local ( t, in_crate) )
428
- . flat_map ( |i| i)
429
+ if let Some ( inner_tys) = fundamental_ty_inner_tys ( tcx, ty) {
430
+ let tys: Vec < _ > = inner_tys
431
+ . filter_map ( |ty| ty_is_non_local ( tcx, ty, in_crate) )
432
+ . flatten ( )
429
433
. collect ( ) ;
430
434
if tys. is_empty ( ) { None } else { Some ( tys) }
435
+ } else {
436
+ Some ( vec ! [ ty] )
431
437
}
432
438
}
433
439
None => None ,
434
440
}
435
441
}
436
442
437
- fn fundamental_ty ( ty : Ty < ' _ > ) -> bool {
438
- match ty. kind {
439
- ty:: Ref ( ..) => true ,
440
- ty:: Adt ( def, _) => def. is_fundamental ( ) ,
441
- _ => false ,
442
- }
443
+ /// For `#[fundamental]` ADTs and `&T` / `&mut T`, returns `Some` with the
444
+ /// type parameters of the ADT, or `T`, respectively. For non-fundamental
445
+ /// types, returns `None`.
446
+ fn fundamental_ty_inner_tys (
447
+ tcx : TyCtxt < ' tcx > ,
448
+ ty : Ty < ' tcx > ,
449
+ ) -> Option < impl Iterator < Item = Ty < ' tcx > > > {
450
+ let ( first_ty, rest_tys) = match ty. kind {
451
+ ty:: Ref ( _, ty, _) => ( ty, ty:: subst:: InternalSubsts :: empty ( ) . types ( ) ) ,
452
+ ty:: Adt ( def, substs) if def. is_fundamental ( ) => {
453
+ let mut types = substs. types ( ) ;
454
+
455
+ // FIXME(eddyb) actually validate `#[fundamental]` up-front.
456
+ match types. next ( ) {
457
+ None => {
458
+ tcx. sess . span_err (
459
+ tcx. def_span ( def. did ) ,
460
+ "`#[fundamental]` requires at least one type parameter" ,
461
+ ) ;
462
+
463
+ return None ;
464
+ }
465
+
466
+ Some ( first_ty) => ( first_ty, types) ,
467
+ }
468
+ }
469
+ _ => return None ,
470
+ } ;
471
+
472
+ Some ( iter:: once ( first_ty) . chain ( rest_tys) )
443
473
}
444
474
445
475
fn def_id_is_local ( def_id : DefId , in_crate : InCrate ) -> bool {
@@ -451,6 +481,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool {
451
481
}
452
482
}
453
483
484
+ // FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
454
485
fn ty_is_non_local_constructor ( ty : Ty < ' _ > , in_crate : InCrate ) -> Option < Ty < ' _ > > {
455
486
debug ! ( "ty_is_non_local_constructor({:?})" , ty) ;
456
487
0 commit comments