Skip to content

Commit 6afe135

Browse files
Suggest adding use<> syntax
1 parent 554becc commit 6afe135

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

compiler/rustc_lint/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than pos
1515
*[other] these lifetimes are
1616
} in scope but not mentioned in the type's bounds
1717
.note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
18+
.suggestion = use the precise capturing `use<...>` syntax to make the captures explicit
1819
1920
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
2021
.note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`

compiler/rustc_lint/src/impl_trait_overcaptures.rs

+41-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
use rustc_data_structures::{fx::FxIndexSet, unord::UnordSet};
2-
use rustc_errors::LintDiagnostic;
1+
use rustc_data_structures::fx::FxIndexSet;
2+
use rustc_errors::{Applicability, LintDiagnostic};
33
use rustc_hir as hir;
44
use rustc_hir::def::DefKind;
55
use rustc_hir::def_id::{DefId, LocalDefId};
66
use rustc_hir::intravisit;
77
use rustc_middle::ty::{
88
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
99
};
10-
use rustc_span::Span;
10+
use rustc_session::lint::FutureIncompatibilityReason;
11+
use rustc_span::edition::Edition;
12+
use rustc_span::{BytePos, Span};
1113

1214
use crate::fluent_generated as fluent;
1315
use crate::{LateContext, LateLintPass};
@@ -146,7 +148,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
146148
&& opaque.precise_capturing_args.is_none()
147149
{
148150
// Compute the set of args that are captured by the opaque...
149-
let mut captured = UnordSet::default();
151+
let mut captured = FxIndexSet::default();
150152
let variances = self.tcx.variances_of(opaque_def_id);
151153
let mut current_def_id = Some(opaque_def_id.to_def_id());
152154
while let Some(def_id) = current_def_id {
@@ -172,19 +174,43 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
172174
let uncaptured_spans: Vec<_> = self
173175
.in_scope_parameters
174176
.iter()
175-
.filter(|def_id| !captured.contains(def_id))
177+
.filter(|def_id| !captured.contains(*def_id))
176178
.map(|def_id| self.tcx.def_span(def_id))
177179
.collect();
178180

179181
if !uncaptured_spans.is_empty() {
182+
let opaque_span = self.tcx.def_span(opaque_def_id);
183+
184+
let suggestion = if let Ok(snippet) =
185+
self.tcx.sess.source_map().span_to_snippet(opaque_span)
186+
&& snippet.starts_with("impl ")
187+
{
188+
let (lifetimes, others): (Vec<_>, Vec<_>) = captured
189+
.into_iter()
190+
.partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam);
191+
// Take all lifetime params first, then all others (ty/ct).
192+
let generics: Vec<_> = lifetimes
193+
.into_iter()
194+
.chain(others)
195+
.map(|def_id| self.tcx.item_name(def_id).to_string())
196+
.collect();
197+
Some((
198+
format!(" use<{}>", generics.join(", ")),
199+
opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(),
200+
))
201+
} else {
202+
None
203+
};
204+
180205
self.tcx.emit_node_lint(
181206
IMPL_TRAIT_OVERCAPTURES,
182207
self.tcx.local_def_id_to_hir_id(opaque_def_id),
183208
ImplTraitOvercapturesLint {
184-
opaque_span: self.tcx.def_span(opaque_def_id),
209+
opaque_span,
185210
self_ty: t,
186211
num_captured: uncaptured_spans.len(),
187212
uncaptured_spans,
213+
suggestion,
188214
},
189215
);
190216
}
@@ -209,6 +235,7 @@ struct ImplTraitOvercapturesLint<'tcx> {
209235
uncaptured_spans: Vec<Span>,
210236
self_ty: Ty<'tcx>,
211237
num_captured: usize,
238+
suggestion: Option<(String, Span)>,
212239
}
213240

214241
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
@@ -218,6 +245,14 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
218245
.span(self.opaque_span)
219246
.span_note(self.uncaptured_spans, fluent::lint_note)
220247
.note(fluent::lint_note2);
248+
if let Some((suggestion, span)) = self.suggestion {
249+
diag.span_suggestion(
250+
span,
251+
fluent::lint_suggestion,
252+
suggestion,
253+
Applicability::MachineApplicable,
254+
);
255+
}
221256
}
222257

223258
fn msg(&self) -> rustc_errors::DiagMessage {

0 commit comments

Comments
 (0)