@@ -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
@@ -1852,12 +1853,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1852
1853
has_self : bool ,
1853
1854
inputs : impl Iterator < Item = ( Option < & ' ast Pat > , & ' ast Ty ) > ,
1854
1855
) -> 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
+ }
1857
1866
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.
1860
1873
let mut parameter_info = Vec :: new ( ) ;
1874
+ let mut all_candidates = Vec :: new ( ) ;
1861
1875
1862
1876
let mut bindings = smallvec ! [ ( PatBoundCtx :: Product , Default :: default ( ) ) ] ;
1863
1877
for ( index, ( pat, ty) ) in inputs. enumerate ( ) {
@@ -1867,61 +1881,82 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
1867
1881
this. resolve_pattern ( pat, PatternSource :: FnParam , & mut bindings) ;
1868
1882
}
1869
1883
} ) ;
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 ( ) ) ;
1870
1888
self . visit_ty ( ty) ;
1889
+ let local_candidates = self . lifetime_elision_candidates . take ( ) ;
1871
1890
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 {
1876
1895
parameter_info. push ( ElisionFnParameter {
1877
1896
index,
1878
1897
ident : if let Some ( pat) = pat && let PatKind :: Ident ( _, ident, _) = pat. kind {
1879
1898
Some ( ident)
1880
1899
} else {
1881
1900
None
1882
1901
} ,
1883
- lifetime_count : local_count ,
1902
+ lifetime_count,
1884
1903
span : ty. span ,
1885
1904
} ) ;
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
+ }
1886
1932
}
1887
- lifetime_count = new_count;
1888
1933
}
1889
1934
1890
1935
// Handle `self` specially.
1891
1936
if index == 0 && has_self {
1892
1937
let self_lifetime = self . find_lifetime_for_self ( ty) ;
1893
1938
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 ) ;
1896
1941
} 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 ;
1899
1945
}
1900
1946
}
1901
1947
debug ! ( "(resolving function / closure) recorded parameter" ) ;
1902
1948
}
1903
1949
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;
1906
1953
1907
- if let Some ( res) = elision_lifetime {
1954
+ if let Elision :: Param ( res ) | Elision :: Self_ ( res) = elision_lifetime {
1908
1955
return Ok ( res) ;
1909
1956
}
1910
1957
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) )
1925
1960
}
1926
1961
1927
1962
/// List all the lifetimes that appear in the provided type.
0 commit comments