@@ -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
@@ -557,7 +558,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
557
558
/// They will be used to determine the correct lifetime for the fn return type.
558
559
/// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
559
560
/// lifetimes.
560
- lifetime_elision_candidates : Option < FxIndexMap < LifetimeRes , LifetimeElisionCandidate > > ,
561
+ lifetime_elision_candidates : Option < Vec < ( LifetimeRes , LifetimeElisionCandidate ) > > ,
561
562
562
563
/// The trait that the current context can refer to.
563
564
current_trait_ref : Option < ( Module < ' a > , TraitRef ) > ,
@@ -1819,7 +1820,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1819
1820
match res {
1820
1821
LifetimeRes :: Param { .. } | LifetimeRes :: Fresh { .. } | LifetimeRes :: Static => {
1821
1822
if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
1822
- candidates. insert ( res, candidate) ;
1823
+ candidates. push ( ( res, candidate) ) ;
1823
1824
}
1824
1825
}
1825
1826
LifetimeRes :: Infer | LifetimeRes :: Error | LifetimeRes :: ElidedAnchor { .. } => { }
@@ -1872,74 +1873,108 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1872
1873
has_self : bool ,
1873
1874
inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
1874
1875
) -> 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
+ }
1877
1886
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.
1880
1893
let mut parameter_info = Vec :: new ( ) ;
1894
+ let mut all_candidates = Vec :: new ( ) ;
1881
1895
1882
1896
let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
1883
1897
for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
1884
1898
debug ! ( ?pat, ?ty) ;
1885
1899
if let Some ( pat) = pat {
1886
1900
self . resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1887
1901
}
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 ( ) ) ;
1888
1906
self . visit_ty ( ty) ;
1907
+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
1889
1908
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 {
1894
1913
parameter_info. push ( ElisionFnParameter {
1895
1914
index,
1896
1915
ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
1897
1916
Some ( ident)
1898
1917
} else {
1899
1918
None
1900
1919
} ,
1901
- lifetime_count : local_count ,
1920
+ lifetime_count,
1902
1921
span : ty. span ,
1903
1922
} ) ;
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
+ }
1904
1950
}
1905
- lifetime_count = new_count;
1906
1951
}
1907
1952
1908
1953
// Handle `self` specially.
1909
1954
if index == 0 && has_self {
1910
1955
let self_lifetime = self . find_lifetime_for_self ( ty) ;
1911
1956
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 ) ;
1914
1959
} 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 ;
1917
1963
}
1918
1964
}
1919
1965
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1920
1966
}
1921
1967
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;
1924
1971
1925
- if let Some ( res) = elision_lifetime {
1972
+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
1926
1973
return Ok ( res) ;
1927
1974
}
1928
1975
1929
- // We do not have a `self` candidate, look at the full list.
1930
- let all_candidates = all_candidates. unwrap ( ) ;
1931
- if all_candidates. len ( ) == 1 {
1932
- Ok ( * all_candidates. first ( ) . unwrap ( ) . 0 )
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) )
1943
1978
}
1944
1979
1945
1980
/// List all the lifetimes that appear in the provided type.
@@ -2411,7 +2446,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
2411
2446
// Do not account for the parameters we just bound for function lifetime elision.
2412
2447
if let Some ( ref mut candidates) = self . lifetime_elision_candidates {
2413
2448
for ( _, res) in function_lifetime_rib. bindings . values ( ) {
2414
- candidates. remove ( res) ;
2449
+ candidates. retain ( | ( r , _ ) | r != res) ;
2415
2450
}
2416
2451
}
2417
2452
0 commit comments