@@ -8,11 +8,12 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
8
8
use rustc_hir:: def_id:: LocalDefId ;
9
9
use rustc_hir:: intravisit:: { walk_inf, walk_ty, Visitor } ;
10
10
use rustc_hir:: {
11
- self as hir, Expr , ExprKind , FnRetTy , FnSig , GenericArg , GenericArgsParentheses , GenericParam , GenericParamKind ,
12
- HirId , Impl , ImplItemKind , Item , ItemKind , Pat , PatKind , Path , QPath , Ty , TyKind ,
11
+ self as hir, Expr , ExprKind , FnRetTy , FnSig , GenericArgsParentheses , GenericParam , GenericParamKind , HirId , Impl ,
12
+ ImplItemKind , Item , ItemKind , Pat , PatKind , Path , QPath , Ty , TyKind ,
13
13
} ;
14
14
use rustc_hir_analysis:: hir_ty_to_ty;
15
15
use rustc_lint:: { LateContext , LateLintPass } ;
16
+ use rustc_middle:: ty:: Ty as MiddleTy ;
16
17
use rustc_session:: impl_lint_pass;
17
18
use rustc_span:: Span ;
18
19
@@ -95,10 +96,9 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
95
96
let stack_item = if let ItemKind :: Impl ( Impl { self_ty, generics, .. } ) = item. kind
96
97
&& let TyKind :: Path ( QPath :: Resolved ( _, item_path) ) = self_ty. kind
97
98
&& let parameters = & item_path. segments . last ( ) . expect ( SEGMENTS_MSG ) . args
98
- && parameters. as_ref ( ) . map_or ( true , |params| {
99
- params. parenthesized == GenericArgsParentheses :: No
100
- && !params. args . iter ( ) . any ( |arg| matches ! ( arg, GenericArg :: Lifetime ( _) ) )
101
- } )
99
+ && parameters
100
+ . as_ref ( )
101
+ . map_or ( true , |params| params. parenthesized == GenericArgsParentheses :: No )
102
102
&& !item. span . from_expansion ( )
103
103
&& !is_from_proc_macro ( cx, item)
104
104
// expensive, should be last check
@@ -226,7 +226,12 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
226
226
} else {
227
227
hir_ty_to_ty ( cx. tcx , hir_ty)
228
228
}
229
- && same_type_and_consts ( ty, cx. tcx . type_of ( impl_id) . instantiate_identity ( ) )
229
+ && let impl_ty = cx. tcx . type_of ( impl_id) . instantiate_identity ( )
230
+ && same_type_and_consts ( ty, impl_ty)
231
+ // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that
232
+ // the lifetime parameters of `ty` are ellided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in
233
+ // which case we must still trigger the lint.
234
+ && ( has_no_lifetime ( ty) || same_lifetimes ( ty, impl_ty) )
230
235
{
231
236
span_lint ( cx, hir_ty. span ) ;
232
237
}
@@ -318,3 +323,37 @@ fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
318
323
span_lint ( cx, span) ;
319
324
}
320
325
}
326
+
327
+ /// Returns `true` if types `a` and `b` have the same lifetime parameters, otherwise returns
328
+ /// `false`.
329
+ ///
330
+ /// This function does not check that types `a` and `b` are the same types.
331
+ fn same_lifetimes < ' tcx > ( a : MiddleTy < ' tcx > , b : MiddleTy < ' tcx > ) -> bool {
332
+ use rustc_middle:: ty:: { Adt , GenericArgKind } ;
333
+ match ( & a. kind ( ) , & b. kind ( ) ) {
334
+ ( & Adt ( _, args_a) , & Adt ( _, args_b) ) => {
335
+ args_a
336
+ . iter ( )
337
+ . zip ( args_b. iter ( ) )
338
+ . all ( |( arg_a, arg_b) | match ( arg_a. unpack ( ) , arg_b. unpack ( ) ) {
339
+ // TODO: Handle inferred lifetimes
340
+ ( GenericArgKind :: Lifetime ( inner_a) , GenericArgKind :: Lifetime ( inner_b) ) => inner_a == inner_b,
341
+ ( GenericArgKind :: Type ( type_a) , GenericArgKind :: Type ( type_b) ) => same_lifetimes ( type_a, type_b) ,
342
+ _ => true ,
343
+ } )
344
+ } ,
345
+ _ => a == b,
346
+ }
347
+ }
348
+
349
+ /// Returns `true` if `ty` has no lifetime parameter, otherwise returns `false`.
350
+ fn has_no_lifetime ( ty : MiddleTy < ' _ > ) -> bool {
351
+ use rustc_middle:: ty:: { Adt , GenericArgKind } ;
352
+ match ty. kind ( ) {
353
+ & Adt ( _, args) => !args
354
+ . iter ( )
355
+ // TODO: Handle inferred lifetimes
356
+ . any ( |arg| matches ! ( arg. unpack( ) , GenericArgKind :: Lifetime ( ..) ) ) ,
357
+ _ => true ,
358
+ }
359
+ }
0 commit comments