Skip to content

Commit a73852b

Browse files
Do less work on the good path
1 parent 6cd9ab6 commit a73852b

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

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

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

0 commit comments

Comments
 (0)