@@ -646,7 +646,22 @@ struct DiagnosticMetadata<'ast> {
646
646
}
647
647
648
648
#[ derive( Debug ) ]
649
- struct ResolvedNestedElisionTarget {
649
+ enum ResolvedElisionTarget {
650
+ TopLevel ( NodeId ) ,
651
+ Nested ( NestedResolvedElisionTarget ) ,
652
+ }
653
+
654
+ impl ResolvedElisionTarget {
655
+ fn node_id ( & self ) -> NodeId {
656
+ match * self {
657
+ Self :: TopLevel ( n) => n,
658
+ Self :: Nested ( NestedResolvedElisionTarget { segment_id, .. } ) => segment_id,
659
+ }
660
+ }
661
+ }
662
+
663
+ #[ derive( Debug ) ]
664
+ struct NestedResolvedElisionTarget {
650
665
segment_id : NodeId ,
651
666
elided_lifetime_span : Span ,
652
667
diagnostic : lint:: BuiltinLintDiagnostics ,
@@ -694,7 +709,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
694
709
lifetime_uses : FxHashMap < LocalDefId , LifetimeUseSet > ,
695
710
696
711
/// Track which types participated in lifetime elision
697
- resolved_lifetime_elisions : Vec < ResolvedNestedElisionTarget > ,
712
+ resolved_lifetime_elisions : Vec < ResolvedElisionTarget > ,
698
713
}
699
714
700
715
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
@@ -1745,6 +1760,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
1745
1760
LifetimeElisionCandidate :: Ignore ,
1746
1761
) ;
1747
1762
self . resolve_anonymous_lifetime ( & lt, true ) ;
1763
+
1764
+ self . resolved_lifetime_elisions . push ( ResolvedElisionTarget :: TopLevel ( anchor_id) ) ;
1748
1765
}
1749
1766
1750
1767
#[ instrument( level = "debug" , skip( self ) ) ]
@@ -1957,16 +1974,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
1957
1974
}
1958
1975
1959
1976
if should_lint {
1960
- self . resolved_lifetime_elisions . push ( ResolvedNestedElisionTarget {
1961
- segment_id,
1962
- elided_lifetime_span,
1963
- diagnostic : lint:: BuiltinLintDiagnostics :: ElidedLifetimesInPaths (
1964
- expected_lifetimes,
1965
- path_span,
1966
- !segment. has_generic_args ,
1977
+ self . resolved_lifetime_elisions . push ( ResolvedElisionTarget :: Nested (
1978
+ NestedResolvedElisionTarget {
1979
+ segment_id,
1967
1980
elided_lifetime_span,
1968
- ) ,
1969
- } ) ;
1981
+ diagnostic : lint:: BuiltinLintDiagnostics :: ElidedLifetimesInPaths (
1982
+ expected_lifetimes,
1983
+ path_span,
1984
+ !segment. has_generic_args ,
1985
+ elided_lifetime_span,
1986
+ ) ,
1987
+ } ,
1988
+ ) ) ;
1970
1989
}
1971
1990
}
1972
1991
}
@@ -2028,22 +2047,79 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
2028
2047
2029
2048
let elision_failures =
2030
2049
replace ( & mut self . diagnostic_metadata . current_elision_failures , outer_failures) ;
2031
- if !elision_failures. is_empty ( ) {
2032
- let Err ( failure_info) = elision_lifetime else { bug ! ( ) } ;
2033
- self . report_missing_lifetime_specifiers ( elision_failures, Some ( failure_info) ) ;
2034
- }
2050
+
2051
+ let elision_lifetime = match ( elision_failures. is_empty ( ) , elision_lifetime) {
2052
+ ( true , Ok ( lifetime) ) => Some ( lifetime) ,
2053
+
2054
+ ( true , Err ( e) ) => None ,
2055
+
2056
+ ( false , Ok ( _) ) => bug ! ( ) ,
2057
+
2058
+ ( false , Err ( failure_info) ) => {
2059
+ self . report_missing_lifetime_specifiers ( elision_failures, Some ( failure_info) ) ;
2060
+ None
2061
+ }
2062
+ } ;
2063
+
2064
+ // We've recorded all elisions that occurred in the params and
2065
+ // outputs, categorized by top-level or nested.
2066
+ //
2067
+ // Our primary lint case is when an output lifetime is tied to
2068
+ // an input lifetime. In that case, we want to warn about any
2069
+ // parameters that had a nested elision.
2070
+ //
2071
+ // The secondary case is for nested elisions that are not part
2072
+ // of the tied lifetime relationship.
2035
2073
2036
2074
let output_resolved_lifetime_elisions =
2037
2075
replace ( & mut self . resolved_lifetime_elisions , outer_resolved_lifetime_elisions) ;
2038
2076
2039
- let resolved_lifetime_elisions =
2040
- param_resolved_lifetime_elisions. into_iter ( ) . chain ( output_resolved_lifetime_elisions) ;
2077
+ match ( output_resolved_lifetime_elisions. is_empty ( ) , elision_lifetime) {
2078
+ ( true , _) | ( _, None ) => {
2079
+ // Treat all parameters as untied
2080
+ self . report_elided_lifetimes_in_paths (
2081
+ param_resolved_lifetime_elisions,
2082
+ lint:: builtin:: ELIDED_LIFETIMES_IN_PATHS_UNTIED ,
2083
+ ) ;
2084
+ }
2085
+ ( false , Some ( elision_lifetime) ) => {
2086
+ let ( primary, secondary) : ( Vec < _ > , Vec < _ > ) =
2087
+ param_resolved_lifetime_elisions. into_iter ( ) . partition ( |re| {
2088
+ let lvl1 = & self . r . lifetimes_res_map [ & re. node_id ( ) ] ;
2089
+ let lvl2 = match lvl1 {
2090
+ LifetimeRes :: ElidedAnchor { start, .. } => {
2091
+ & self . r . lifetimes_res_map [ & start]
2092
+ }
2093
+ o => o,
2094
+ } ;
2095
+
2096
+ lvl2 == & elision_lifetime
2097
+ } ) ;
2098
+
2099
+ self . report_elided_lifetimes_in_paths (
2100
+ primary. into_iter ( ) . chain ( output_resolved_lifetime_elisions) ,
2101
+ lint:: builtin:: ELIDED_LIFETIMES_IN_PATHS_TIED ,
2102
+ ) ;
2103
+ self . report_elided_lifetimes_in_paths (
2104
+ secondary,
2105
+ lint:: builtin:: ELIDED_LIFETIMES_IN_PATHS_UNTIED ,
2106
+ ) ;
2107
+ }
2108
+ }
2109
+ }
2110
+
2111
+ fn report_elided_lifetimes_in_paths (
2112
+ & mut self ,
2113
+ resolved_elisions : impl IntoIterator < Item = ResolvedElisionTarget > ,
2114
+ lint : & ' static lint:: Lint ,
2115
+ ) {
2116
+ for re in resolved_elisions {
2117
+ let ResolvedElisionTarget :: Nested ( d) = re else { continue } ;
2041
2118
2042
- for re in resolved_lifetime_elisions {
2043
- let ResolvedNestedElisionTarget { segment_id, elided_lifetime_span, diagnostic } = re;
2119
+ let NestedResolvedElisionTarget { segment_id, elided_lifetime_span, diagnostic } = d;
2044
2120
2045
2121
self . r . lint_buffer . buffer_lint_with_diagnostic (
2046
- lint:: builtin :: ELIDED_LIFETIMES_IN_PATHS ,
2122
+ lint,
2047
2123
segment_id,
2048
2124
elided_lifetime_span,
2049
2125
"hidden lifetime parameters in types are deprecated" ,
0 commit comments