@@ -30,6 +30,7 @@ use rustc_span::{BytePos, Span};
30
30
use smallvec:: { smallvec, SmallVec } ;
31
31
32
32
use rustc_span:: source_map:: { respan, Spanned } ;
33
+ use std:: assert_matches:: debug_assert_matches;
33
34
use std:: collections:: { hash_map:: Entry , BTreeSet } ;
34
35
use std:: mem:: { replace, take} ;
35
36
@@ -568,7 +569,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
568
569
/// They will be used to determine the correct lifetime for the fn return type.
569
570
/// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
570
571
/// lifetimes.
571
- lifetime_elision_candidates : Option < FxIndexMap < LifetimeRes , LifetimeElisionCandidate > > ,
572
+ lifetime_elision_candidates : Option < Vec < ( LifetimeRes , LifetimeElisionCandidate ) > > ,
572
573
573
574
/// The trait that the current context can refer to.
574
575
current_trait_ref : Option < ( Module < ' a > , TraitRef ) > ,
@@ -1802,7 +1803,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1802
1803
match res {
1803
1804
LifetimeRes :: Param { .. } | LifetimeRes :: Fresh { .. } | LifetimeRes :: Static => {
1804
1805
if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
1805
- candidates. insert ( res, candidate) ;
1806
+ candidates. push ( ( res, candidate) ) ;
1806
1807
}
1807
1808
}
1808
1809
LifetimeRes :: Infer | LifetimeRes :: Error | LifetimeRes :: ElidedAnchor { .. } => { }
@@ -1855,12 +1856,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1855
1856
has_self : bool ,
1856
1857
inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
1857
1858
) -> 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
+ }
1860
1869
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.
1863
1876
let mut parameter_info = Vec :: new ( ) ;
1877
+ let mut all_candidates = Vec :: new ( ) ;
1864
1878
1865
1879
let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
1866
1880
for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
@@ -1870,61 +1884,82 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1870
1884
this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1871
1885
}
1872
1886
} ) ;
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 ( ) ) ;
1873
1891
self . visit_ty ( ty) ;
1892
+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
1874
1893
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 {
1879
1898
parameter_info. push ( ElisionFnParameter {
1880
1899
index,
1881
1900
ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
1882
1901
Some ( ident)
1883
1902
} else {
1884
1903
None
1885
1904
} ,
1886
- lifetime_count : local_count ,
1905
+ lifetime_count,
1887
1906
span : ty. span ,
1888
1907
} ) ;
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
+ }
1889
1935
}
1890
- lifetime_count = new_count;
1891
1936
}
1892
1937
1893
1938
// Handle `self` specially.
1894
1939
if index == 0 && has_self {
1895
1940
let self_lifetime = self . find_lifetime_for_self ( ty) ;
1896
1941
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 ) ;
1899
1944
} 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 ;
1902
1948
}
1903
1949
}
1904
1950
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1905
1951
}
1906
1952
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;
1909
1956
1910
- if let Some ( res) = elision_lifetime {
1957
+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
1911
1958
return Ok ( res) ;
1912
1959
}
1913
1960
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) )
1928
1963
}
1929
1964
1930
1965
/// List all the lifetimes that appear in the provided type.
@@ -2394,7 +2429,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
2394
2429
// Do not account for the parameters we just bound for function lifetime elision.
2395
2430
if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
2396
2431
for ( _, res) in function_lifetime_rib. bindings . values ( ) {
2397
- candidates. remove ( res) ;
2432
+ candidates. retain ( | ( r , _ ) | r != res) ;
2398
2433
}
2399
2434
}
2400
2435
0 commit comments