@@ -646,7 +646,22 @@ struct DiagnosticMetadata<'ast> {
646646}
647647
648648#[ 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 {
650665 segment_id : NodeId ,
651666 elided_lifetime_span : Span ,
652667 diagnostic : lint:: BuiltinLintDiagnostics ,
@@ -694,7 +709,7 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
694709 lifetime_uses : FxHashMap < LocalDefId , LifetimeUseSet > ,
695710
696711 /// Track which types participated in lifetime elision
697- resolved_lifetime_elisions : Vec < ResolvedNestedElisionTarget > ,
712+ resolved_lifetime_elisions : Vec < ResolvedElisionTarget > ,
698713}
699714
700715/// 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> {
17451760 LifetimeElisionCandidate :: Ignore ,
17461761 ) ;
17471762 self . resolve_anonymous_lifetime ( & lt, true ) ;
1763+
1764+ self . resolved_lifetime_elisions . push ( ResolvedElisionTarget :: TopLevel ( anchor_id) ) ;
17481765 }
17491766
17501767 #[ instrument( level = "debug" , skip( self ) ) ]
@@ -1957,16 +1974,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
19571974 }
19581975
19591976 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,
19671980 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+ ) ) ;
19701989 }
19711990 }
19721991 }
@@ -2028,22 +2047,79 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
20282047
20292048 let elision_failures =
20302049 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.
20352073
20362074 let output_resolved_lifetime_elisions =
20372075 replace ( & mut self . resolved_lifetime_elisions , outer_resolved_lifetime_elisions) ;
20382076
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 } ;
20412118
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;
20442120
20452121 self . r . lint_buffer . buffer_lint_with_diagnostic (
2046- lint:: builtin :: ELIDED_LIFETIMES_IN_PATHS ,
2122+ lint,
20472123 segment_id,
20482124 elided_lifetime_span,
20492125 "hidden lifetime parameters in types are deprecated" ,
0 commit comments