@@ -14,6 +14,7 @@ use rustc_middle::ty::subst::Subst;
1414use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1515use rustc_span:: symbol:: sym;
1616use rustc_span:: DUMMY_SP ;
17+ use std:: iter;
1718
1819/// Whether we do the orphan check relative to this crate or
1920/// to some remote crate.
@@ -378,19 +379,25 @@ fn orphan_check_trait_ref<'tcx>(
378379 ty : Ty < ' tcx > ,
379380 in_crate : InCrate ,
380381 ) -> 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+ }
385390 }
391+
392+ vec ! [ ty]
386393 }
387394
388395 let mut non_local_spans = vec ! [ ] ;
389396 for ( i, input_ty) in
390397 trait_ref. input_types ( ) . flat_map ( |ty| uncover_fundamental_ty ( tcx, ty, in_crate) ) . enumerate ( )
391398 {
392399 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) ;
394401 if non_local_tys. is_none ( ) {
395402 debug ! ( "orphan_check_trait_ref: ty_is_local `{:?}`" , input_ty) ;
396403 return Ok ( ( ) ) ;
@@ -416,30 +423,53 @@ fn orphan_check_trait_ref<'tcx>(
416423 Err ( OrphanCheckErr :: NonLocalInputType ( non_local_spans) )
417424}
418425
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 > > > {
420427 match ty_is_non_local_constructor ( ty, in_crate) {
421428 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 ( )
429433 . collect ( ) ;
430434 if tys. is_empty ( ) { None } else { Some ( tys) }
435+ } else {
436+ Some ( vec ! [ ty] )
431437 }
432438 }
433439 None => None ,
434440 }
435441}
436442
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) )
443473}
444474
445475fn 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 {
451481 }
452482}
453483
484+ // FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
454485fn ty_is_non_local_constructor ( ty : Ty < ' _ > , in_crate : InCrate ) -> Option < Ty < ' _ > > {
455486 debug ! ( "ty_is_non_local_constructor({:?})" , ty) ;
456487
0 commit comments