Skip to content

Commit 7064135

Browse files
Do less work on the good path
1 parent f8f4d50 commit 7064135

File tree

1 file changed

+113
-110
lines changed

1 file changed

+113
-110
lines changed

compiler/rustc_lint/src/impl_trait_overcaptures.rs

+113-110
Original file line numberDiff line numberDiff line change
@@ -264,130 +264,133 @@ where
264264
&& let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
265265
&& parent_def_id == self.parent_def_id
266266
{
267-
// Compute the set of args that are captured by the opaque...
268-
let mut captured = FxIndexSet::default();
269-
let mut captured_regions = FxIndexSet::default();
270-
let variances = self.tcx.variances_of(opaque_def_id);
271-
let mut current_def_id = Some(opaque_def_id.to_def_id());
272-
while let Some(def_id) = current_def_id {
273-
let generics = self.tcx.generics_of(def_id);
274-
for param in &generics.own_params {
275-
// A param is captured if it's invariant.
276-
if variances[param.index as usize] != ty::Invariant {
277-
continue;
278-
}
279-
280-
let arg = opaque_ty.args[param.index as usize];
281-
// We need to turn all `ty::Param`/`ConstKind::Param` and
282-
// `ReEarlyParam`/`ReBound` into def ids.
283-
captured.insert(extract_def_id_from_arg(self.tcx, generics, arg));
284-
285-
captured_regions.extend(arg.as_region());
286-
}
287-
current_def_id = generics.parent;
288-
}
289-
290-
// Compute the set of in scope params that are not captured. Get their spans,
291-
// since that's all we really care about them for emitting the diagnostic.
292-
let mut uncaptured_args: FxIndexSet<_> = self
293-
.in_scope_parameters
294-
.iter()
295-
.filter(|&(def_id, _)| !captured.contains(def_id))
296-
.collect();
297-
298-
// These are args that we know are likely fine to "overcapture", since they can be
299-
// contravariantly shortened to one of the already-captured lifetimes that they
300-
// outlive.
301-
let covariant_long_args: FxIndexSet<_> = uncaptured_args
302-
.iter()
303-
.copied()
304-
.filter(|&(def_id, kind)| {
305-
let Some(ty::Bivariant | ty::Contravariant) = self.variances.get(def_id) else {
306-
return false;
307-
};
308-
let DefKind::LifetimeParam = self.tcx.def_kind(def_id) else {
309-
return false;
310-
};
311-
let uncaptured = match *kind {
312-
ParamKind::Early(name, index) => ty::Region::new_early_param(
313-
self.tcx,
314-
ty::EarlyParamRegion { name, index },
315-
),
316-
ParamKind::Free(def_id, name) => ty::Region::new_late_param(
317-
self.tcx,
318-
self.parent_def_id.to_def_id(),
319-
ty::BoundRegionKind::BrNamed(def_id, name),
320-
),
321-
ParamKind::Late => return false,
322-
};
323-
// Does this region outlive any captured region?
324-
captured_regions.iter().any(|r| {
325-
self.outlives_env
326-
.free_region_map()
327-
.sub_free_regions(self.tcx, *r, uncaptured)
328-
})
329-
})
330-
.collect();
331-
// We don't care to warn on these args.
332-
uncaptured_args.retain(|arg| !covariant_long_args.contains(arg));
333-
334267
let opaque_span = self.tcx.def_span(opaque_def_id);
335268
let new_capture_rules =
336269
opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
337-
338-
// If we have uncaptured args, and if the opaque doesn't already have
339-
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
340270
if !new_capture_rules
341271
&& !opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..)))
342-
&& !uncaptured_args.is_empty()
343272
{
344-
let suggestion = if let Ok(snippet) =
345-
self.tcx.sess.source_map().span_to_snippet(opaque_span)
346-
&& snippet.starts_with("impl ")
347-
{
348-
let (lifetimes, others): (Vec<_>, Vec<_>) = captured
349-
.into_iter()
350-
.partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam);
351-
// Take all lifetime params first, then all others (ty/ct).
352-
let generics: Vec<_> = lifetimes
353-
.into_iter()
354-
.chain(others)
355-
.map(|def_id| self.tcx.item_name(def_id).to_string())
356-
.collect();
357-
// Make sure that we're not trying to name any APITs
358-
if generics.iter().all(|name| !name.starts_with("impl ")) {
359-
Some((
360-
format!(" + use<{}>", generics.join(", ")),
361-
opaque_span.shrink_to_hi(),
362-
))
363-
} else {
364-
None
273+
// Compute the set of args that are captured by the opaque...
274+
let mut captured = FxIndexSet::default();
275+
let mut captured_regions = FxIndexSet::default();
276+
let variances = self.tcx.variances_of(opaque_def_id);
277+
let mut current_def_id = Some(opaque_def_id.to_def_id());
278+
while let Some(def_id) = current_def_id {
279+
let generics = self.tcx.generics_of(def_id);
280+
for param in &generics.own_params {
281+
// A param is captured if it's invariant.
282+
if variances[param.index as usize] != ty::Invariant {
283+
continue;
284+
}
285+
286+
let arg = opaque_ty.args[param.index as usize];
287+
// We need to turn all `ty::Param`/`ConstKind::Param` and
288+
// `ReEarlyParam`/`ReBound` into def ids.
289+
captured.insert(extract_def_id_from_arg(self.tcx, generics, arg));
290+
291+
captured_regions.extend(arg.as_region());
365292
}
366-
} else {
367-
None
368-
};
293+
current_def_id = generics.parent;
294+
}
295+
296+
// Compute the set of in scope params that are not captured. Get their spans,
297+
// since that's all we really care about them for emitting the diagnostic.
298+
let mut uncaptured_args: FxIndexSet<_> = self
299+
.in_scope_parameters
300+
.iter()
301+
.filter(|&(def_id, _)| !captured.contains(def_id))
302+
.collect();
369303

370-
let uncaptured_spans: Vec<_> = uncaptured_args
371-
.into_iter()
372-
.map(|(def_id, _)| self.tcx.def_span(def_id))
304+
// These are args that we know are likely fine to "overcapture", since they can be
305+
// contravariantly shortened to one of the already-captured lifetimes that they
306+
// outlive.
307+
let covariant_long_args: FxIndexSet<_> = uncaptured_args
308+
.iter()
309+
.copied()
310+
.filter(|&(def_id, kind)| {
311+
let Some(ty::Bivariant | ty::Contravariant) = self.variances.get(def_id)
312+
else {
313+
return false;
314+
};
315+
let DefKind::LifetimeParam = self.tcx.def_kind(def_id) else {
316+
return false;
317+
};
318+
let uncaptured = match *kind {
319+
ParamKind::Early(name, index) => ty::Region::new_early_param(
320+
self.tcx,
321+
ty::EarlyParamRegion { name, index },
322+
),
323+
ParamKind::Free(def_id, name) => ty::Region::new_late_param(
324+
self.tcx,
325+
self.parent_def_id.to_def_id(),
326+
ty::BoundRegionKind::BrNamed(def_id, name),
327+
),
328+
ParamKind::Late => return false,
329+
};
330+
// Does this region outlive any captured region?
331+
captured_regions.iter().any(|r| {
332+
self.outlives_env
333+
.free_region_map()
334+
.sub_free_regions(self.tcx, *r, uncaptured)
335+
})
336+
})
373337
.collect();
338+
// We don't care to warn on these args.
339+
uncaptured_args.retain(|arg| !covariant_long_args.contains(arg));
340+
341+
// If we have uncaptured args, and if the opaque doesn't already have
342+
// `use<>` syntax on it, and we're < edition 2024, then warn the user.
343+
if !uncaptured_args.is_empty() {
344+
let suggestion = if let Ok(snippet) =
345+
self.tcx.sess.source_map().span_to_snippet(opaque_span)
346+
&& snippet.starts_with("impl ")
347+
{
348+
let (lifetimes, others): (Vec<_>, Vec<_>) =
349+
captured.into_iter().partition(|def_id| {
350+
self.tcx.def_kind(*def_id) == DefKind::LifetimeParam
351+
});
352+
// Take all lifetime params first, then all others (ty/ct).
353+
let generics: Vec<_> = lifetimes
354+
.into_iter()
355+
.chain(others)
356+
.map(|def_id| self.tcx.item_name(def_id).to_string())
357+
.collect();
358+
// Make sure that we're not trying to name any APITs
359+
if generics.iter().all(|name| !name.starts_with("impl ")) {
360+
Some((
361+
format!(" + use<{}>", generics.join(", ")),
362+
opaque_span.shrink_to_hi(),
363+
))
364+
} else {
365+
None
366+
}
367+
} else {
368+
None
369+
};
374370

375-
self.tcx.emit_node_span_lint(
376-
IMPL_TRAIT_OVERCAPTURES,
377-
self.tcx.local_def_id_to_hir_id(opaque_def_id),
378-
opaque_span,
379-
ImplTraitOvercapturesLint {
380-
self_ty: t,
381-
num_captured: uncaptured_spans.len(),
382-
uncaptured_spans,
383-
suggestion,
384-
},
385-
);
371+
let uncaptured_spans: Vec<_> = uncaptured_args
372+
.into_iter()
373+
.map(|(def_id, _)| self.tcx.def_span(def_id))
374+
.collect();
375+
376+
self.tcx.emit_node_span_lint(
377+
IMPL_TRAIT_OVERCAPTURES,
378+
self.tcx.local_def_id_to_hir_id(opaque_def_id),
379+
opaque_span,
380+
ImplTraitOvercapturesLint {
381+
self_ty: t,
382+
num_captured: uncaptured_spans.len(),
383+
uncaptured_spans,
384+
suggestion,
385+
},
386+
);
387+
}
386388
}
389+
387390
// Otherwise, if we are edition 2024, have `use<>` syntax, and
388391
// have no uncaptured args, then we should warn to the user that
389392
// it's redundant to capture all args explicitly.
390-
else if new_capture_rules
393+
if new_capture_rules
391394
&& let Some((captured_args, capturing_span)) =
392395
opaque.bounds.iter().find_map(|bound| match *bound {
393396
hir::GenericBound::Use(a, s) => Some((a, s)),

0 commit comments

Comments
 (0)