@@ -561,15 +561,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
561561 /// Returns the appropriate lifetime to use for any output lifetimes
562562 /// (if one exists) and a vector of the (pattern, number of lifetimes)
563563 /// corresponding to each input type/pattern.
564- fn find_implied_output_region ( & self ,
565- input_tys : & [ Ty < ' tcx > ] ,
566- input_pats : Vec < String > ) -> ElidedLifetime
564+ fn find_implied_output_region < F > ( & self ,
565+ input_tys : & [ Ty < ' tcx > ] ,
566+ input_pats : F ) -> ElidedLifetime
567+ where F : FnOnce ( ) -> Vec < String >
567568 {
568569 let tcx = self . tcx ( ) ;
569570 let mut lifetimes_for_params = Vec :: new ( ) ;
570571 let mut possible_implied_output_region = None ;
571572
572- for ( input_type, input_pat ) in input_tys. iter ( ) . zip ( input_pats ) {
573+ for input_type in input_tys. iter ( ) {
573574 let mut regions = FnvHashSet ( ) ;
574575 let have_bound_regions = tcx. collect_regions ( input_type, & mut regions) ;
575576
@@ -583,8 +584,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
583584 possible_implied_output_region = regions. iter ( ) . cloned ( ) . next ( ) ;
584585 }
585586
587+ // Use a placeholder for `name` because computing it can be
588+ // expensive and we don't want to do it until we know it's
589+ // necessary.
586590 lifetimes_for_params. push ( ElisionFailureInfo {
587- name : input_pat ,
591+ name : String :: new ( ) ,
588592 lifetime_count : regions. len ( ) ,
589593 have_bound_regions : have_bound_regions
590594 } ) ;
@@ -593,6 +597,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
593597 if lifetimes_for_params. iter ( ) . map ( |e| e. lifetime_count ) . sum :: < usize > ( ) == 1 {
594598 Ok ( * possible_implied_output_region. unwrap ( ) )
595599 } else {
600+ // Fill in the expensive `name` fields now that we know they're
601+ // needed.
602+ for ( info, input_pat) in lifetimes_for_params. iter_mut ( ) . zip ( input_pats ( ) ) {
603+ info. name = input_pat;
604+ }
596605 Err ( Some ( lifetimes_for_params) )
597606 }
598607 }
@@ -629,7 +638,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
629638 let inputs: Vec < _ > = data. inputs . iter ( ) . map ( |a_t| {
630639 self . ast_ty_arg_to_ty ( & binding_rscope, None , region_substs, a_t)
631640 } ) . collect ( ) ;
632- let input_params = vec ! [ String :: new( ) ; inputs. len( ) ] ;
641+ let inputs_len = inputs. len ( ) ;
642+ let input_params = || vec ! [ String :: new( ) ; inputs_len] ;
633643 let implied_output_region = self . find_implied_output_region ( & inputs, input_params) ;
634644
635645 let ( output, output_span) = match data. output {
@@ -1861,15 +1871,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
18611871 } ;
18621872 let arg_tys: Vec < Ty > =
18631873 arg_params. iter ( ) . map ( |a| self . ty_of_arg ( & rb, a, None ) ) . collect ( ) ;
1864- let arg_pats: Vec < String > =
1865- arg_params. iter ( ) . map ( |a| pprust:: pat_to_string ( & a. pat ) ) . collect ( ) ;
18661874
18671875 // Second, if there was exactly one lifetime (either a substitution or a
18681876 // reference) in the arguments, then any anonymous regions in the output
18691877 // have that lifetime.
18701878 let implied_output_region = match explicit_self_category {
18711879 ty:: ExplicitSelfCategory :: ByReference ( region, _) => Ok ( * region) ,
1872- _ => self . find_implied_output_region ( & arg_tys, arg_pats)
1880+ _ => {
1881+ // `pat_to_string` is expensive and
1882+ // `find_implied_output_region` only needs its result when
1883+ // there's an error. So we wrap it in a closure to avoid
1884+ // calling it until necessary.
1885+ let arg_pats = || {
1886+ arg_params. iter ( ) . map ( |a| pprust:: pat_to_string ( & a. pat ) ) . collect ( )
1887+ } ;
1888+ self . find_implied_output_region ( & arg_tys, arg_pats)
1889+ }
18731890 } ;
18741891
18751892 let output_ty = match decl. output {
0 commit comments