about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLzu Tao <taolzu@gmail.com>2024-07-17 11:30:29 +0700
committerLzu Tao <taolzu@gmail.com>2024-07-26 00:27:40 +0700
commit0bc9f003a3fdf2d860647a22768297aaa07611e4 (patch)
tree16d01f13dd5fc01aa797d8f822922f274b8ab58d
parente53182a2b492613ce3988c1c893330d53e9caed1 (diff)
downloadrust-0bc9f003a3fdf2d860647a22768297aaa07611e4.tar.gz
rust-0bc9f003a3fdf2d860647a22768297aaa07611e4.zip
Check for 'static lifetime in return type
-rw-r--r--clippy_lints/src/eta_reduction.rs21
-rw-r--r--tests/ui/eta.fixed4
-rw-r--r--tests/ui/eta.stderr14
3 files changed, 21 insertions, 18 deletions
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index d03ae101823..5a7226d590c 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -9,8 +9,7 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, RegionKind, Ty, TypeVisitableExt,
-    TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -176,6 +175,17 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                     }
                 },
             };
+            if let Some(outer) = outer_receiver
+                && ty_has_static(sig.output())
+                && let generic_args = typeck.node_args(outer.hir_id)
+                // HACK: Given a closure in `T.method(|| f())`, where `fn f() -> U where U: 'static`, `T.method(f)`
+                // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
+                // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
+                // So we have a hack like this.
+                && generic_args.len() > 0
+            {
+                return;
+            }
             if check_sig(closure_sig, sig)
                 && let generic_args = typeck.node_args(callee.hir_id)
                 // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
@@ -275,7 +285,7 @@ fn check_sig<'tcx>(closure_sig: FnSig<'tcx>, call_sig: FnSig<'tcx>) -> bool {
 /// This is needed because rustc is unable to late bind early-bound regions in a function signature.
 fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
     fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
-        matches!(from_region.kind(), RegionKind::ReBound(..)) && !matches!(to_region.kind(), RegionKind::ReBound(..))
+        from_region.is_bound() && !to_region.is_bound()
     }
 
     fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
@@ -328,3 +338,8 @@ fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'
         .zip(to_sig.inputs_and_output)
         .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
+
+fn ty_has_static(ty: Ty<'_>) -> bool {
+    ty.walk()
+        .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if re.is_static()))
+}
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
index 5323425de47..ca422ee29c1 100644
--- a/tests/ui/eta.fixed
+++ b/tests/ui/eta.fixed
@@ -492,9 +492,9 @@ mod issue_13073 {
     pub fn foo() {
         // shouldn't lint
         let bind: Option<String> = None;
-        let _field = bind.as_deref().or_else(get_default).unwrap();
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
         let bind: Option<&'static str> = None;
-        let _field = bind.as_deref().or_else(get_default).unwrap();
+        let _field = bind.as_deref().or_else(|| get_default()).unwrap();
         // should lint
         let _field = bind.or_else(get_default).unwrap();
     }
diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr
index d35c37af37c..5540261fc57 100644
--- a/tests/ui/eta.stderr
+++ b/tests/ui/eta.stderr
@@ -203,22 +203,10 @@ LL |         let x = Box::new(|| None.map(|x| f(x)));
    |                                      ^^^^^^^^ help: replace the closure with the function itself: `f`
 
 error: redundant closure
-  --> tests/ui/eta.rs:495:46
-   |
-LL |         let _field = bind.as_deref().or_else(|| get_default()).unwrap();
-   |                                              ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
-
-error: redundant closure
-  --> tests/ui/eta.rs:497:46
-   |
-LL |         let _field = bind.as_deref().or_else(|| get_default()).unwrap();
-   |                                              ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
-
-error: redundant closure
   --> tests/ui/eta.rs:499:35
    |
 LL |         let _field = bind.or_else(|| get_default()).unwrap();
    |                                   ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
 
-error: aborting due to 36 previous errors
+error: aborting due to 34 previous errors