@@ -33,7 +33,7 @@ use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
33
33
use rustc:: ty:: { ReprOptions , ToPredicate , WithConstness } ;
34
34
use rustc_attr:: { list_contains_name, mark_used, InlineAttr , OptimizeAttr } ;
35
35
use rustc_data_structures:: captures:: Captures ;
36
- use rustc_data_structures:: fx:: FxHashMap ;
36
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
37
37
use rustc_errors:: { struct_span_err, Applicability } ;
38
38
use rustc_hir as hir;
39
39
use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
@@ -369,10 +369,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
369
369
hir:: ItemKind :: Enum ( _, generics)
370
370
| hir:: ItemKind :: Struct ( _, generics)
371
371
| hir:: ItemKind :: Union ( _, generics) => {
372
- // FIXME: look for an appropriate lt name if `'a` is already used
372
+ let lt_name = get_new_lifetime_name ( self . tcx , poly_trait_ref , generics ) ;
373
373
let ( lt_sp, sugg) = match & generics. params [ ..] {
374
- [ ] => ( generics. span , "<'a>" . to_string ( ) ) ,
375
- [ bound, ..] => ( bound. span . shrink_to_lo ( ) , "'a, " . to_string ( ) ) ,
374
+ [ ] => ( generics. span , format ! ( "<{}>" , lt_name) ) ,
375
+ [ bound, ..] => {
376
+ ( bound. span . shrink_to_lo ( ) , format ! ( "{}, " , lt_name) )
377
+ }
376
378
} ;
377
379
let suggestions = vec ! [
378
380
( lt_sp, sugg) ,
@@ -387,7 +389,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
387
389
ty:: EarlyBoundRegion {
388
390
def_id: item_def_id,
389
391
index: 0 ,
390
- name: Symbol :: intern( "'a" ) ,
392
+ name: Symbol :: intern( & lt_name ) ,
391
393
} ,
392
394
) )
393
395
} )
@@ -445,6 +447,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
445
447
}
446
448
}
447
449
450
+ /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
451
+ fn get_new_lifetime_name < ' tcx > (
452
+ tcx : TyCtxt < ' tcx > ,
453
+ poly_trait_ref : ty:: PolyTraitRef < ' tcx > ,
454
+ generics : & hir:: Generics < ' tcx > ,
455
+ ) -> String {
456
+ let existing_lifetimes = tcx
457
+ . collect_referenced_late_bound_regions ( & poly_trait_ref)
458
+ . into_iter ( )
459
+ . filter_map ( |lt| {
460
+ if let ty:: BoundRegion :: BrNamed ( _, name) = lt {
461
+ Some ( name. as_str ( ) . to_string ( ) )
462
+ } else {
463
+ None
464
+ }
465
+ } )
466
+ . chain ( generics. params . iter ( ) . filter_map ( |param| {
467
+ if let hir:: GenericParamKind :: Lifetime { .. } = & param. kind {
468
+ Some ( param. name . ident ( ) . as_str ( ) . to_string ( ) )
469
+ } else {
470
+ None
471
+ }
472
+ } ) )
473
+ . collect :: < FxHashSet < String > > ( ) ;
474
+
475
+ let a_to_z_repeat_n = |n| {
476
+ ( b'a' ..=b'z' ) . map ( move |c| {
477
+ let mut s = format ! ( "'" ) ;
478
+ s. extend ( std:: iter:: repeat ( char:: from ( c) ) . take ( n) ) ;
479
+ s
480
+ } )
481
+ } ;
482
+
483
+ // If all single char lifetime names are present, we wrap around and double the chars.
484
+ ( 1 ..) . flat_map ( a_to_z_repeat_n) . find ( |lt| !existing_lifetimes. contains ( lt. as_str ( ) ) ) . unwrap ( )
485
+ }
486
+
448
487
/// Returns the predicates defined on `item_def_id` of the form
449
488
/// `X: Foo` where `X` is the type parameter `def_id`.
450
489
fn type_param_predicates (
@@ -1588,7 +1627,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
1588
1627
/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
1589
1628
/// N.B., this does not include any implied/inferred constraints.
1590
1629
fn explicit_predicates_of ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> ty:: GenericPredicates < ' _ > {
1591
- use rustc_data_structures:: fx:: FxHashSet ;
1592
1630
use rustc_hir:: * ;
1593
1631
1594
1632
debug ! ( "explicit_predicates_of(def_id={:?})" , def_id) ;
0 commit comments