]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/future_not_send.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / future_not_send.rs
1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::return_ty;
3 use rustc_hir::intravisit::FnKind;
4 use rustc_hir::{Body, FnDecl};
5 use rustc_infer::infer::TyCtxtInferExt;
6 use rustc_lint::{LateContext, LateLintPass};
7 use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind};
8 use rustc_session::{declare_lint_pass, declare_tool_lint};
9 use rustc_span::def_id::LocalDefId;
10 use rustc_span::{sym, Span};
11 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt;
12 use rustc_trait_selection::traits::{self, FulfillmentError};
13
14 declare_clippy_lint! {
15 /// ### What it does
16 /// This lint requires Future implementations returned from
17 /// functions and methods to implement the `Send` marker trait. It is mostly
18 /// used by library authors (public and internal) that target an audience where
19 /// multithreaded executors are likely to be used for running these Futures.
20 ///
21 /// ### Why is this bad?
22 /// A Future implementation captures some state that it
23 /// needs to eventually produce its final value. When targeting a multithreaded
24 /// executor (which is the norm on non-embedded devices) this means that this
25 /// state may need to be transported to other threads, in other words the
26 /// whole Future needs to implement the `Send` marker trait. If it does not,
27 /// then the resulting Future cannot be submitted to a thread pool in the
28 /// end user’s code.
29 ///
30 /// Especially for generic functions it can be confusing to leave the
31 /// discovery of this problem to the end user: the reported error location
32 /// will be far from its cause and can in many cases not even be fixed without
33 /// modifying the library where the offending Future implementation is
34 /// produced.
35 ///
36 /// ### Example
37 /// ```rust
38 /// async fn not_send(bytes: std::rc::Rc<[u8]>) {}
39 /// ```
40 /// Use instead:
41 /// ```rust
42 /// async fn is_send(bytes: std::sync::Arc<[u8]>) {}
43 /// ```
44 #[clippy::version = "1.44.0"]
45 pub FUTURE_NOT_SEND,
46 nursery,
47 "public Futures must be Send"
48 }
49
50 declare_lint_pass!(FutureNotSend => [FUTURE_NOT_SEND]);
51
52 impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
53 fn check_fn(
54 &mut self,
55 cx: &LateContext<'tcx>,
56 kind: FnKind<'tcx>,
57 decl: &'tcx FnDecl<'tcx>,
58 _: &'tcx Body<'tcx>,
59 _: Span,
60 fn_def_id: LocalDefId,
61 ) {
62 if let FnKind::Closure = kind {
63 return;
64 }
65 let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner());
66 if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() {
67 let preds = cx.tcx.explicit_item_bounds(def_id);
68 let mut is_future = false;
69 for &(p, _span) in preds {
70 let p = EarlyBinder(p).subst(cx.tcx, substs);
71 if let Some(trait_pred) = p.to_opt_poly_trait_pred() {
72 if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() {
73 is_future = true;
74 break;
75 }
76 }
77 }
78 if is_future {
79 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
80 let span = decl.output.span();
81 let infcx = cx.tcx.infer_ctxt().build();
82 let cause = traits::ObligationCause::misc(span, fn_def_id);
83 let send_errors = traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait);
84 if !send_errors.is_empty() {
85 span_lint_and_then(
86 cx,
87 FUTURE_NOT_SEND,
88 span,
89 "future cannot be sent between threads safely",
90 |db| {
91 for FulfillmentError { obligation, .. } in send_errors {
92 infcx
93 .err_ctxt()
94 .maybe_note_obligation_cause_for_async_await(db, &obligation);
95 if let PredicateKind::Clause(Clause::Trait(trait_pred)) =
96 obligation.predicate.kind().skip_binder()
97 {
98 db.note(&format!(
99 "`{}` doesn't implement `{}`",
100 trait_pred.self_ty(),
101 trait_pred.trait_ref.print_only_trait_path(),
102 ));
103 }
104 }
105 },
106 );
107 }
108 }
109 }
110 }
111 }