Skip to content

Commit

Permalink
Add some commenting
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed May 14, 2024
1 parent d57e57c commit 554becc
Showing 1 changed file with 23 additions and 4 deletions.
27 changes: 23 additions & 4 deletions compiler/rustc_lint/src/impl_trait_overcaptures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ declare_lint! {
}

declare_lint_pass!(
/// Lint for use of `async fn` in the definition of a publicly-reachable
/// trait.
/// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
/// in edition 2024.
ImplTraitOvercaptures => [IMPL_TRAIT_OVERCAPTURES]
);

Expand All @@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
}
}
DefKind::Fn => {
// All freee functions need to check for overcaptures.
// All free functions need to check for overcaptures.
}
DefKind::Closure => return,
kind => {
Expand All @@ -64,6 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
let sig = cx.tcx.fn_sig(parent_def_id).instantiate_identity();

let mut in_scope_parameters = FxIndexSet::default();
// Populate the in_scope_parameters list first with all of the generics in scope
let mut current_def_id = Some(parent_def_id.to_def_id());
while let Some(def_id) = current_def_id {
let generics = cx.tcx.generics_of(def_id);
Expand All @@ -73,6 +74,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
current_def_id = generics.parent;
}

// Then visit the signature to walk through all the binders (incl. the late-bound
// vars on the function itself, which we need to count too).
sig.visit_with(&mut VisitOpaqueTypes {
tcx: cx.tcx,
parent_def_id,
Expand All @@ -94,6 +97,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
&mut self,
t: &ty::Binder<'tcx, T>,
) -> Self::Result {
// When we get into a binder, we need to add its own bound vars to the scope.
let mut added = vec![];
for arg in t.bound_vars() {
let arg: ty::BoundVariableKind = arg;
Expand All @@ -117,6 +121,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {

t.super_visit_with(self);

// And remove them. The `shift_remove` should be `O(1)` since we're popping
// them off from the end.
for arg in added.into_iter().rev() {
self.in_scope_parameters.shift_remove(&arg);
}
Expand All @@ -129,22 +135,29 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {

if let ty::Alias(ty::Opaque, opaque_ty) = *t.kind()
&& let Some(opaque_def_id) = opaque_ty.def_id.as_local()
// Don't recurse infinitely on an opaque
&& self.seen.insert(opaque_def_id)
// If it's owned by this function
&& let opaque =
self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty()
&& let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
&& parent_def_id == self.parent_def_id
// And if the opaque doesn't already have `use<>` syntax on it...
&& opaque.precise_capturing_args.is_none()
{
// Compute the set of args that are captured by the opaque...
let mut captured = UnordSet::default();
let variances = self.tcx.variances_of(opaque_def_id);
let mut current_def_id = Some(opaque_def_id.to_def_id());
while let Some(def_id) = current_def_id {
let generics = self.tcx.generics_of(def_id);
for param in &generics.params {
for param in &generics.own_params {
// A param is captured if it's invariant.
if variances[param.index as usize] != ty::Invariant {
continue;
}
// We need to turn all `ty::Param`/`ConstKind::Param` and
// `ReEarlyParam`/`ReBound` into def ids.
captured.insert(extract_def_id_from_arg(
self.tcx,
generics,
Expand All @@ -154,6 +167,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
current_def_id = generics.parent;
}

// Compute the set of in scope params that are not captured. Get their spans,
// since that's all we really care about them for emitting the diagnostic.
let uncaptured_spans: Vec<_> = self
.in_scope_parameters
.iter()
Expand All @@ -174,6 +189,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
);
}

// Walk into the bounds of the opaque, too, since we want to get nested opaques
// in this lint as well. Interestingly, one place that I expect this lint to fire
// is for `impl for<'a> Bound<Out = impl Other>`, since `impl Other` will begin
// to capture `'a` in e2024 (even though late-bound vars in opaques are not allowed).
for clause in
self.tcx.item_bounds(opaque_ty.def_id).iter_instantiated(self.tcx, opaque_ty.args)
{
Expand Down

0 comments on commit 554becc

Please sign in to comment.