@@ -33,7 +33,7 @@ use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
3333use rustc:: ty:: { ReprOptions , ToPredicate , WithConstness } ;
3434use rustc_attr:: { list_contains_name, mark_used, InlineAttr , OptimizeAttr } ;
3535use rustc_data_structures:: captures:: Captures ;
36- use rustc_data_structures:: fx:: FxHashMap ;
36+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
3737use rustc_errors:: { struct_span_err, Applicability } ;
3838use rustc_hir as hir;
3939use rustc_hir:: def:: { CtorKind , DefKind , Res } ;
@@ -369,10 +369,12 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
369369 hir:: ItemKind :: Enum ( _, generics)
370370 | hir:: ItemKind :: Struct ( _, generics)
371371 | 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 ) ;
373373 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+ }
376378 } ;
377379 let suggestions = vec ! [
378380 ( lt_sp, sugg) ,
@@ -387,7 +389,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
387389 ty:: EarlyBoundRegion {
388390 def_id: item_def_id,
389391 index: 0 ,
390- name: Symbol :: intern( "'a" ) ,
392+ name: Symbol :: intern( & lt_name ) ,
391393 } ,
392394 ) )
393395 } )
@@ -445,6 +447,43 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
445447 }
446448}
447449
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+
448487/// Returns the predicates defined on `item_def_id` of the form
449488/// `X: Foo` where `X` is the type parameter `def_id`.
450489fn type_param_predicates (
@@ -1588,7 +1627,6 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
15881627/// Returns a list of user-specified type predicates for the definition with ID `def_id`.
15891628/// N.B., this does not include any implied/inferred constraints.
15901629fn explicit_predicates_of ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> ty:: GenericPredicates < ' _ > {
1591- use rustc_data_structures:: fx:: FxHashSet ;
15921630 use rustc_hir:: * ;
15931631
15941632 debug ! ( "explicit_predicates_of(def_id={:?})" , def_id) ;
0 commit comments