@@ -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
@@ -1852,12 +1853,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18521853 has_self : bool ,
18531854 inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
18541855 ) -> Result < LifetimeRes , ( Vec < MissingLifetime > , Vec < ElisionFnParameter > ) > {
1855- let outer_candidates =
1856- replace ( & mut self . lifetime_elision_candidates , Some ( Default :: default ( ) ) ) ;
1856+ enum Elision {
1857+ /// We have not found any candidate.
1858+ None ,
1859+ /// We have a candidate bound to `self`.
1860+ Self_ ( LifetimeRes ) ,
1861+ /// We have a candidate bound to a parameter.
1862+ Param ( LifetimeRes ) ,
1863+ /// We failed elision.
1864+ Err ,
1865+ }
18571866
1858- let mut elision_lifetime = None ;
1859- let mut lifetime_count = 0 ;
1867+ // Save elision state to reinstate it later.
1868+ let outer_candidates = self . lifetime_elision_candidates . take ( ) ;
1869+
1870+ // Result of elision.
1871+ let mut elision_lifetime = Elision :: None ;
1872+ // Information for diagnostics.
18601873 let mut parameter_info = Vec :: new ( ) ;
1874+ let mut all_candidates = Vec :: new ( ) ;
18611875
18621876 let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
18631877 for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
@@ -1867,61 +1881,82 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
18671881 this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
18681882 }
18691883 } ) ;
1884+
1885+ // Record elision candidates only for this parameter.
1886+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1887+ self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
18701888 self . visit_ty ( ty) ;
1889+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
18711890
1872- if let Some ( ref candidates) = self . lifetime_elision_candidates {
1873- let new_count = candidates. len ( ) ;
1874- let local_count = new_count - lifetime_count ;
1875- if local_count != 0 {
1891+ if let Some ( candidates) = local_candidates {
1892+ let distinct : FxHashSet < _ > = candidates. iter ( ) . map ( | ( res , _ ) | * res ) . collect ( ) ;
1893+ let lifetime_count = distinct . len ( ) ;
1894+ if lifetime_count != 0 {
18761895 parameter_info. push ( ElisionFnParameter {
18771896 index,
18781897 ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
18791898 Some ( ident)
18801899 } else {
18811900 None
18821901 } ,
1883- lifetime_count : local_count ,
1902+ lifetime_count,
18841903 span : ty. span ,
18851904 } ) ;
1905+ all_candidates. extend ( candidates. into_iter ( ) . filter_map ( |( _, candidate) | {
1906+ match candidate {
1907+ LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => {
1908+ None
1909+ }
1910+ LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1911+ }
1912+ } ) ) ;
1913+ }
1914+ let mut distinct_iter = distinct. into_iter ( ) ;
1915+ if let Some ( res) = distinct_iter. next ( ) {
1916+ match elision_lifetime {
1917+ // We are the first parameter to bind lifetimes.
1918+ Elision :: None => {
1919+ if distinct_iter. next ( ) . is_none ( ) {
1920+ // We have a single lifetime => success.
1921+ elision_lifetime = Elision :: Param ( res)
1922+ } else {
1923+ // We have have multiple lifetimes => error.
1924+ elision_lifetime = Elision :: Err ;
1925+ }
1926+ }
1927+ // We have 2 parameters that bind lifetimes => error.
1928+ Elision :: Param ( _) => elision_lifetime = Elision :: Err ,
1929+ // `self` elision takes precedence over everything else.
1930+ Elision :: Self_ ( _) | Elision :: Err => { }
1931+ }
18861932 }
1887- lifetime_count = new_count;
18881933 }
18891934
18901935 // Handle `self` specially.
18911936 if index == 0 && has_self {
18921937 let self_lifetime = self . find_lifetime_for_self ( ty) ;
18931938 if let Set1 :: One ( lifetime) = self_lifetime {
1894- elision_lifetime = Some ( lifetime ) ;
1895- self . lifetime_elision_candidates = None ;
1939+ // We found `self` elision.
1940+ elision_lifetime = Elision :: Self_ ( lifetime ) ;
18961941 } else {
1897- self . lifetime_elision_candidates = Some ( Default :: default ( ) ) ;
1898- lifetime_count = 0 ;
1942+ // We do not have `self` elision: disregard the `Elision::Param` that we may
1943+ // have found.
1944+ elision_lifetime = Elision :: None ;
18991945 }
19001946 }
19011947 debug ! ( "(resolving function / closure) recorded parameter" ) ;
19021948 }
19031949
1904- let all_candidates = replace ( & mut self . lifetime_elision_candidates , outer_candidates) ;
1905- debug ! ( ?all_candidates) ;
1950+ // Reinstate elision state.
1951+ debug_assert_matches ! ( self . lifetime_elision_candidates, None ) ;
1952+ self . lifetime_elision_candidates = outer_candidates;
19061953
1907- if let Some ( res) = elision_lifetime {
1954+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
19081955 return Ok ( res) ;
19091956 }
19101957
1911- // We do not have a `self` candidate, look at the full list.
1912- let all_candidates = all_candidates. unwrap ( ) ;
1913- if let [ ( res, _) ] = & all_candidates[ ..] {
1914- Ok ( * res)
1915- } else {
1916- let all_candidates = all_candidates
1917- . into_iter ( )
1918- . filter_map ( |( _, candidate) | match candidate {
1919- LifetimeElisionCandidate :: Ignore | LifetimeElisionCandidate :: Named => None ,
1920- LifetimeElisionCandidate :: Missing ( missing) => Some ( missing) ,
1921- } )
1922- . collect ( ) ;
1923- Err ( ( all_candidates, parameter_info) )
1924- }
1958+ // We do not have a candidate.
1959+ Err ( ( all_candidates, parameter_info) )
19251960 }
19261961
19271962 /// List all the lifetimes that appear in the provided type.
0 commit comments