@@ -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
@@ -1872,74 +1873,108 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18721873 has_self : bool ,
18731874 inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
18741875 ) -> Result < LifetimeRes , ( Vec < MissingLifetime > , Vec < ElisionFnParameter > ) > {
1875- let outer_candidates =
1876- replace ( & mut self . lifetime_elision_candidates , Some ( Default :: default ( ) ) ) ;
1876+ enum Elision {
1877+ /// We have not found any candidate.
1878+ None ,
1879+ /// We have a candidate bound to `self`.
1880+ Self_ ( LifetimeRes ) ,
1881+ /// We have a candidate bound to a parameter.
1882+ Param ( LifetimeRes ) ,
1883+ /// We failed elision.
1884+ Err ,
1885+ }
18771886
1878- let mut elision_lifetime = None ;
1879- let mut lifetime_count = 0 ;
1887+ // Save elision state to reinstate it later.
1888+ let outer_candidates = self . lifetime_elision_candidates . take ( ) ;
1889+
1890+ // Result of elision.
1891+ let mut elision_lifetime = Elision :: None ;
1892+ // Information for diagnostics.
18801893 let mut parameter_info = Vec :: new ( ) ;
1894+ let mut all_candidates = Vec :: new ( ) ;
18811895
18821896 let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
18831897 for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
18841898 debug ! ( ?pat, ?ty) ;
18851899 if let Some ( pat) = pat {
18861900 self . resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
18871901 }
1902+
1903+ // Record elision candidates only for this parameter.
1904+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1905+ self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
18881906 self . visit_ty ( ty) ;
1907+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
18891908
1890- if let Some ( ref candidates) = self . lifetime_elision_candidates {
1891- let new_count = candidates. len ( ) ;
1892- let local_count = new_count - lifetime_count ;
1893- if local_count != 0 {
1909+ if let Some ( candidates) = local_candidates {
1910+ let distinct : FxHashSet < _ > = candidates. iter ( ) . map ( | ( res , _ ) | * res ) . collect ( ) ;
1911+ let lifetime_count = distinct . len ( ) ;
1912+ if lifetime_count != 0 {
18941913 parameter_info. push ( ElisionFnParameter {
18951914 index,
18961915 ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
18971916 Some ( ident)
18981917 } else {
18991918 None
19001919 } ,
1901- lifetime_count : local_count ,
1920+ lifetime_count,
19021921 span : ty. span ,
19031922 } ) ;
1923+ all_candidates. extend ( candidates. into_iter ( ) . filter_map ( |( _, candidate) | {
1924+ match candidate {
1925+ LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => {
1926+ None
1927+ }
1928+ LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1929+ }
1930+ } ) ) ;
1931+ }
1932+ let mut distinct_iter = distinct. into_iter ( ) ;
1933+ if let Some ( res) = distinct_iter. next ( ) {
1934+ match elision_lifetime {
1935+ // We are the first parameter to bind lifetimes.
1936+ Elision :: None => {
1937+ if distinct_iter. next ( ) . is_none ( ) {
1938+ // We have a single lifetime => success.
1939+ elision_lifetime = Elision :: Param ( res)
1940+ } else {
1941+ // We have have multiple lifetimes => error.
1942+ elision_lifetime = Elision :: Err ;
1943+ }
1944+ }
1945+ // We have 2 parameters that bind lifetimes => error.
1946+ Elision :: Param ( _) => elision_lifetime = Elision :: Err ,
1947+ // `self` elision takes precedence over everything else.
1948+ Elision :: Self_ ( _) | Elision :: Err => { }
1949+ }
19041950 }
1905- lifetime_count = new_count;
19061951 }
19071952
19081953 // Handle `self` specially.
19091954 if index == 0 && has_self {
19101955 let self_lifetime = self . find_lifetime_for_self ( ty) ;
19111956 if let Set1 :: One ( lifetime) = self_lifetime {
1912- elision_lifetime = Some ( lifetime ) ;
1913- self . lifetime_elision_candidates = None ;
1957+ // We found `self` elision.
1958+ elision_lifetime = Elision :: Self_ ( lifetime ) ;
19141959 } else {
1915- self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
1916- lifetime_count = 0 ;
1960+ // We do not have `self` elision: disregard the `Elision::Param` that we may
1961+ // have found.
1962+ elision_lifetime = Elision :: None ;
19171963 }
19181964 }
19191965 debug ! ( "(resolving function / closure) recorded parameter" ) ;
19201966 }
19211967
1922- let all_candidates = replace ( & mut self . lifetime_elision_candidates , outer_candidates) ;
1923- debug ! ( ?all_candidates) ;
1968+ // Reinstate elision state.
1969+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1970+ self . lifetime_elision_candidates = outer_candidates;
19241971
1925- if let Some ( res) = elision_lifetime {
1972+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
19261973 return Ok ( res) ;
19271974 }
19281975
1929- // We do not have a `self` candidate, look at the full list.
1930- let all_candidates = all_candidates. unwrap ( ) ;
1931- if let [ ( res, _) ] = & all_candidates[ ..] {
1932- Ok ( * res)
1933- } else {
1934- let all_candidates = all_candidates
1935- . into_iter ( )
1936- . filter_map ( |( _, candidate) | match candidate {
1937- LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => None ,
1938- LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1939- } )
1940- . collect ( ) ;
1941- Err ( ( all_candidates, parameter_info) )
1942- }
1976+ // We do not have a candidate.
1977+ Err ( ( all_candidates, parameter_info) )
19431978 }
19441979
19451980 /// List all the lifetimes that appear in the provided type.
0 commit comments