@@ -30,6 +30,7 @@ use rustc_span::{BytePos, Span};
3030use smallvec:: { smallvec, SmallVec } ;
3131
3232use rustc_span:: source_map:: { respan, Spanned } ;
33+ use std:: assert_matches:: debug_assert_matches;
3334use std:: collections:: { hash_map:: Entry , BTreeSet } ;
3435use std:: mem:: { replace, take} ;
3536
@@ -568,7 +569,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
568569 /// They will be used to determine the correct lifetime for the fn return type.
569570 /// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
570571 /// lifetimes.
571- lifetime_elision_candidates : Option < FxIndexMap < LifetimeRes , LifetimeElisionCandidate > > ,
572+ lifetime_elision_candidates : Option < Vec < ( LifetimeRes , LifetimeElisionCandidate ) > > ,
572573
573574 /// The trait that the current context can refer to.
574575 current_trait_ref : Option < ( Module < ' a > , TraitRef ) > ,
@@ -1802,7 +1803,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18021803 match res {
18031804 LifetimeRes :: Param { .. } | LifetimeRes :: Fresh { .. } | LifetimeRes :: Static => {
18041805 if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
1805- candidates. insert ( res, candidate) ;
1806+ candidates. push ( ( res, candidate) ) ;
18061807 }
18071808 }
18081809 LifetimeRes :: Infer | LifetimeRes :: Error | LifetimeRes :: ElidedAnchor { .. } => { }
@@ -1855,12 +1856,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18551856 has_self : bool ,
18561857 inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
18571858 ) -> Result < LifetimeRes , ( Vec < MissingLifetime > , Vec < ElisionFnParameter > ) > {
1858- let outer_candidates =
1859- replace ( & mut self . lifetime_elision_candidates , Some ( Default :: default ( ) ) ) ;
1859+ enum Elision {
1860+ /// We have not found any candidate.
1861+ None ,
1862+ /// We have a candidate bound to `self`.
1863+ Self_ ( LifetimeRes ) ,
1864+ /// We have a candidate bound to a parameter.
1865+ Param ( LifetimeRes ) ,
1866+ /// We failed elision.
1867+ Err ,
1868+ }
18601869
1861- let mut elision_lifetime = None ;
1862- let mut lifetime_count = 0 ;
1870+ // Save elision state to reinstate it later.
1871+ let outer_candidates = self . lifetime_elision_candidates . take ( ) ;
1872+
1873+ // Result of elision.
1874+ let mut elision_lifetime = Elision :: None ;
1875+ // Information for diagnostics.
18631876 let mut parameter_info = Vec :: new ( ) ;
1877+ let mut all_candidates = Vec :: new ( ) ;
18641878
18651879 let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
18661880 for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
@@ -1870,61 +1884,82 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18701884 this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
18711885 }
18721886 } ) ;
1887+
1888+ // Record elision candidates only for this parameter.
1889+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1890+ self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
18731891 self . visit_ty ( ty) ;
1892+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
18741893
1875- if let Some ( ref candidates) = self . lifetime_elision_candidates {
1876- let new_count = candidates. len ( ) ;
1877- let local_count = new_count - lifetime_count ;
1878- if local_count != 0 {
1894+ if let Some ( candidates) = local_candidates {
1895+ let distinct : FxHashSet < _ > = candidates. iter ( ) . map ( | ( res , _ ) | * res ) . collect ( ) ;
1896+ let lifetime_count = distinct . len ( ) ;
1897+ if lifetime_count != 0 {
18791898 parameter_info. push ( ElisionFnParameter {
18801899 index,
18811900 ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
18821901 Some ( ident)
18831902 } else {
18841903 None
18851904 } ,
1886- lifetime_count : local_count ,
1905+ lifetime_count,
18871906 span : ty. span ,
18881907 } ) ;
1908+ all_candidates. extend ( candidates. into_iter ( ) . filter_map ( |( _, candidate) | {
1909+ match candidate {
1910+ LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => {
1911+ None
1912+ }
1913+ LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1914+ }
1915+ } ) ) ;
1916+ }
1917+ let mut distinct_iter = distinct. into_iter ( ) ;
1918+ if let Some ( res) = distinct_iter. next ( ) {
1919+ match elision_lifetime {
1920+ // We are the first parameter to bind lifetimes.
1921+ Elision :: None => {
1922+ if distinct_iter. next ( ) . is_none ( ) {
1923+ // We have a single lifetime => success.
1924+ elision_lifetime = Elision :: Param ( res)
1925+ } else {
1926+ // We have have multiple lifetimes => error.
1927+ elision_lifetime = Elision :: Err ;
1928+ }
1929+ }
1930+ // We have 2 parameters that bind lifetimes => error.
1931+ Elision :: Param ( _) => elision_lifetime = Elision :: Err ,
1932+ // `self` elision takes precedence over everything else.
1933+ Elision :: Self_ ( _) | Elision :: Err => { }
1934+ }
18891935 }
1890- lifetime_count = new_count;
18911936 }
18921937
18931938 // Handle `self` specially.
18941939 if index == 0 && has_self {
18951940 let self_lifetime = self . find_lifetime_for_self ( ty) ;
18961941 if let Set1 :: One ( lifetime) = self_lifetime {
1897- elision_lifetime = Some ( lifetime ) ;
1898- self . lifetime_elision_candidates = None ;
1942+ // We found `self` elision.
1943+ elision_lifetime = Elision :: Self_ ( lifetime ) ;
18991944 } else {
1900- self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
1901- lifetime_count = 0 ;
1945+ // We do not have `self` elision: disregard the `Elision::Param` that we may
1946+ // have found.
1947+ elision_lifetime = Elision :: None ;
19021948 }
19031949 }
19041950 debug ! ( "(resolving function / closure) recorded parameter" ) ;
19051951 }
19061952
1907- let all_candidates = replace ( & mut self . lifetime_elision_candidates , outer_candidates) ;
1908- debug ! ( ?all_candidates) ;
1953+ // Reinstate elision state.
1954+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1955+ self . lifetime_elision_candidates = outer_candidates;
19091956
1910- if let Some ( res) = elision_lifetime {
1957+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
19111958 return Ok ( res) ;
19121959 }
19131960
1914- // We do not have a `self` candidate, look at the full list.
1915- let all_candidates = all_candidates. unwrap ( ) ;
1916- if all_candidates. len ( ) == 1 {
1917- Ok ( * all_candidates. first ( ) . unwrap ( ) . 0 )
1918- } else {
1919- let all_candidates = all_candidates
1920- . into_iter ( )
1921- . filter_map ( |( _, candidate) | match candidate {
1922- LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => None ,
1923- LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1924- } )
1925- . collect ( ) ;
1926- Err ( ( all_candidates, parameter_info) )
1927- }
1961+ // We do not have a candidate.
1962+ Err ( ( all_candidates, parameter_info) )
19281963 }
19291964
19301965 /// List all the lifetimes that appear in the provided type.
@@ -2394,7 +2429,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
23942429 // Do not account for the parameters we just bound for function lifetime elision.
23952430 if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
23962431 for ( _, res) in function_lifetime_rib. bindings . values ( ) {
2397- candidates. remove ( res) ;
2432+ candidates. retain ( | ( r , _ ) | r != res) ;
23982433 }
23992434 }
24002435
0 commit comments