Skip to main content

rustc_lint/
impl_trait_overcaptures.rs

1use std::cell::LazyCell;
2use std::debug_assert_matches;
3
4use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
5use rustc_data_structures::unord::UnordSet;
6use rustc_errors::{Diagnostic, Subdiagnostic, msg};
7use rustc_hir as hir;
8use rustc_hir::def::DefKind;
9use rustc_hir::def_id::{DefId, LocalDefId};
10use rustc_infer::infer::TyCtxtInferExt;
11use rustc_infer::infer::outlives::env::OutlivesEnvironment;
12use rustc_macros::Diagnostic;
13use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
14use rustc_middle::ty::relate::{
15    Relate, RelateResult, TypeRelation, relate_args_with_variances, structurally_relate_consts,
16    structurally_relate_tys,
17};
18use rustc_middle::ty::{
19    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
20    Unnormalized,
21};
22use rustc_middle::{bug, span_bug};
23use rustc_session::lint::fcw;
24use rustc_session::{declare_lint, declare_lint_pass};
25use rustc_span::{Span, Symbol};
26use rustc_trait_selection::errors::{
27    AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion,
28};
29use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
30use rustc_trait_selection::traits::ObligationCtxt;
31
32use crate::{LateContext, LateLintPass};
33
34#[doc =
r" The `impl_trait_overcaptures` lint warns against cases where lifetime"]
#[doc = r" capture behavior will differ in edition 2024."]
#[doc = r""]
#[doc =
r" In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,"]
#[doc =
r" rather than just the lifetimes that are mentioned in the bounds of the type."]
#[doc =
r" Often these sets are equal, but if not, it means that the `impl Trait` may"]
#[doc = r" cause erroneous borrow-checker errors."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail,edition2021"]
#[doc = r" # #![deny(impl_trait_overcaptures)]"]
#[doc = r" # use std::fmt::Display;"]
#[doc = r" let mut x = vec![];"]
#[doc = r" x.push(1);"]
#[doc = r""]
#[doc = r" fn test(x: &Vec<i32>) -> impl Display {"]
#[doc = r"     x[0]"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" let element = test(&x);"]
#[doc = r" x.push(2);"]
#[doc = r#" println!("{element}");"#]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" In edition < 2024, the returned `impl Display` doesn't capture the"]
#[doc =
r" lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed"]
#[doc = r" while the `impl Display` is live."]
#[doc = r""]
#[doc =
r" To fix this, we can explicitly state that the `impl Display` doesn't"]
#[doc = r" capture any lifetimes, using `impl Display + use<>`."]
pub static IMPL_TRAIT_OVERCAPTURES: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "IMPL_TRAIT_OVERCAPTURES",
            default_level: ::rustc_lint_defs::Allow,
            desc: "`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
            is_externally_loaded: false,
            future_incompatible: Some(::rustc_lint_defs::FutureIncompatibleInfo {
                    reason: ::rustc_lint_defs::FutureIncompatibilityReason::EditionSemanticsChange(::rustc_lint_defs::EditionFcw {
                            edition: rustc_span::edition::Edition::Edition2024,
                            page_slug: "rpit-lifetime-capture",
                        }),
                    ..::rustc_lint_defs::FutureIncompatibleInfo::default_fields_for_macro()
                }),
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
35    /// The `impl_trait_overcaptures` lint warns against cases where lifetime
36    /// capture behavior will differ in edition 2024.
37    ///
38    /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,
39    /// rather than just the lifetimes that are mentioned in the bounds of the type.
40    /// Often these sets are equal, but if not, it means that the `impl Trait` may
41    /// cause erroneous borrow-checker errors.
42    ///
43    /// ### Example
44    ///
45    /// ```rust,compile_fail,edition2021
46    /// # #![deny(impl_trait_overcaptures)]
47    /// # use std::fmt::Display;
48    /// let mut x = vec![];
49    /// x.push(1);
50    ///
51    /// fn test(x: &Vec<i32>) -> impl Display {
52    ///     x[0]
53    /// }
54    ///
55    /// let element = test(&x);
56    /// x.push(2);
57    /// println!("{element}");
58    /// ```
59    ///
60    /// {{produces}}
61    ///
62    /// ### Explanation
63    ///
64    /// In edition < 2024, the returned `impl Display` doesn't capture the
65    /// lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed
66    /// while the `impl Display` is live.
67    ///
68    /// To fix this, we can explicitly state that the `impl Display` doesn't
69    /// capture any lifetimes, using `impl Display + use<>`.
70    pub IMPL_TRAIT_OVERCAPTURES,
71    Allow,
72    "`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
73    @future_incompatible = FutureIncompatibleInfo {
74        reason: fcw!(EditionSemanticsChange 2024 "rpit-lifetime-capture"),
75    };
76}
77
78#[doc =
r" The `impl_trait_redundant_captures` lint warns against cases where use of the"]
#[doc = r" precise capturing `use<...>` syntax is not needed."]
#[doc = r""]
#[doc =
r" In the 2024 edition, `impl Trait`s will capture all lifetimes in scope."]
#[doc =
r" If precise-capturing `use<...>` syntax is used, and the set of parameters"]
#[doc =
r" that are captures are *equal* to the set of parameters in scope, then"]
#[doc = r" the syntax is redundant, and can be removed."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,edition2024,compile_fail"]
#[doc = r" # #![deny(impl_trait_redundant_captures)]"]
#[doc = r" fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" To fix this, remove the `use<'a>`, since the lifetime is already captured"]
#[doc = r" since it is in scope."]
pub static IMPL_TRAIT_REDUNDANT_CAPTURES: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: "IMPL_TRAIT_REDUNDANT_CAPTURES",
            default_level: ::rustc_lint_defs::Allow,
            desc: "redundant precise-capturing `use<...>` syntax on an `impl Trait`",
            is_externally_loaded: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_lint! {
79    /// The `impl_trait_redundant_captures` lint warns against cases where use of the
80    /// precise capturing `use<...>` syntax is not needed.
81    ///
82    /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope.
83    /// If precise-capturing `use<...>` syntax is used, and the set of parameters
84    /// that are captures are *equal* to the set of parameters in scope, then
85    /// the syntax is redundant, and can be removed.
86    ///
87    /// ### Example
88    ///
89    /// ```rust,edition2024,compile_fail
90    /// # #![deny(impl_trait_redundant_captures)]
91    /// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
92    /// ```
93    ///
94    /// {{produces}}
95    ///
96    /// ### Explanation
97    ///
98    /// To fix this, remove the `use<'a>`, since the lifetime is already captured
99    /// since it is in scope.
100    pub IMPL_TRAIT_REDUNDANT_CAPTURES,
101    Allow,
102    "redundant precise-capturing `use<...>` syntax on an `impl Trait`",
103}
104
105#[doc =
r" Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes"]
#[doc = r" in edition 2024."]
pub struct ImplTraitOvercaptures;
#[automatically_derived]
impl ::core::marker::Copy for ImplTraitOvercaptures { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ImplTraitOvercaptures { }
#[automatically_derived]
impl ::core::clone::Clone for ImplTraitOvercaptures {
    #[inline]
    fn clone(&self) -> ImplTraitOvercaptures { *self }
}
impl ::rustc_lint_defs::LintPass for ImplTraitOvercaptures {
    fn name(&self) -> &'static str { "ImplTraitOvercaptures" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPL_TRAIT_OVERCAPTURES, IMPL_TRAIT_REDUNDANT_CAPTURES]))
    }
}
impl ImplTraitOvercaptures {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPL_TRAIT_OVERCAPTURES, IMPL_TRAIT_REDUNDANT_CAPTURES]))
    }
}declare_lint_pass!(
106    /// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
107    /// in edition 2024.
108    ImplTraitOvercaptures => [IMPL_TRAIT_OVERCAPTURES, IMPL_TRAIT_REDUNDANT_CAPTURES]
109);
110
111impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
112    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'tcx>) {
113        match &it.kind {
114            hir::ItemKind::Fn { .. } => check_fn(cx.tcx, it.owner_id.def_id),
115            _ => {}
116        }
117    }
118
119    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::ImplItem<'tcx>) {
120        match &it.kind {
121            hir::ImplItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
122            _ => {}
123        }
124    }
125
126    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::TraitItem<'tcx>) {
127        match &it.kind {
128            hir::TraitItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
129            _ => {}
130        }
131    }
132}
133
134#[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for ParamKind {
    #[inline]
    fn eq(&self, other: &ParamKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ParamKind::Early(__self_0, __self_1),
                    ParamKind::Early(__arg1_0, __arg1_1)) =>
                    __self_1 == __arg1_1 && __self_0 == __arg1_0,
                (ParamKind::Free(__self_0), ParamKind::Free(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ParamKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Symbol>;
        let _: ::core::cmp::AssertParamIsEq<u32>;
        let _: ::core::cmp::AssertParamIsEq<DefId>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for ParamKind {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            ParamKind::Early(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            ParamKind::Free(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            _ => {}
        }
    }
}Hash, #[automatically_derived]
impl ::core::fmt::Debug for ParamKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ParamKind::Early(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Early",
                    __self_0, &__self_1),
            ParamKind::Free(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Free",
                    &__self_0),
            ParamKind::Late => ::core::fmt::Formatter::write_str(f, "Late"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for ParamKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ParamKind {
    #[inline]
    fn clone(&self) -> ParamKind {
        let _: ::core::clone::AssertParamIsClone<Symbol>;
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<DefId>;
        *self
    }
}Clone)]
135enum ParamKind {
136    // Early-bound var.
137    Early(Symbol, u32),
138    // Late-bound var on function, not within a binder. We can capture these.
139    Free(DefId),
140    // Late-bound var in a binder. We can't capture these yet.
141    Late,
142}
143
144fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
145    let sig = tcx.fn_sig(parent_def_id).instantiate_identity().skip_norm_wip();
146
147    let mut in_scope_parameters = FxIndexMap::default();
148    // Populate the in_scope_parameters list first with all of the generics in scope
149    let mut current_def_id = Some(parent_def_id.to_def_id());
150    while let Some(def_id) = current_def_id {
151        let generics = tcx.generics_of(def_id);
152        for param in &generics.own_params {
153            in_scope_parameters.insert(param.def_id, ParamKind::Early(param.name, param.index));
154        }
155        current_def_id = generics.parent;
156    }
157
158    for bound_var in sig.bound_vars() {
159        let ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) = bound_var else {
160            ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(parent_def_id),
    format_args!("unexpected non-lifetime binder on fn sig"));span_bug!(tcx.def_span(parent_def_id), "unexpected non-lifetime binder on fn sig");
161        };
162
163        in_scope_parameters.insert(def_id, ParamKind::Free(def_id));
164    }
165
166    let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig);
167
168    // Then visit the signature to walk through all the binders (incl. the late-bound
169    // vars on the function itself, which we need to count too).
170    sig.visit_with(&mut VisitOpaqueTypes {
171        tcx,
172        parent_def_id,
173        in_scope_parameters,
174        seen: Default::default(),
175        // Lazily compute these two, since they're likely a bit expensive.
176        variances: LazyCell::new(|| {
177            let mut functional_variances = FunctionalVariances {
178                tcx,
179                variances: FxHashMap::default(),
180                ambient_variance: ty::Covariant,
181                generics: tcx.generics_of(parent_def_id),
182            };
183            functional_variances.relate(sig, sig).unwrap();
184            functional_variances.variances
185        }),
186        outlives_env: LazyCell::new(|| {
187            let typing_env = ty::TypingEnv::non_body_analysis(tcx, parent_def_id);
188            let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
189            let ocx = ObligationCtxt::new(&infcx);
190            let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
191            OutlivesEnvironment::new(&infcx, parent_def_id, param_env, assumed_wf_tys)
192        }),
193    });
194}
195
196struct VisitOpaqueTypes<'tcx, VarFn, OutlivesFn> {
197    tcx: TyCtxt<'tcx>,
198    parent_def_id: LocalDefId,
199    in_scope_parameters: FxIndexMap<DefId, ParamKind>,
200    variances: LazyCell<FxHashMap<DefId, ty::Variance>, VarFn>,
201    outlives_env: LazyCell<OutlivesEnvironment<'tcx>, OutlivesFn>,
202    seen: FxIndexSet<LocalDefId>,
203}
204
205impl<'tcx, VarFn, OutlivesFn> TypeVisitor<TyCtxt<'tcx>>
206    for VisitOpaqueTypes<'tcx, VarFn, OutlivesFn>
207where
208    VarFn: FnOnce() -> FxHashMap<DefId, ty::Variance>,
209    OutlivesFn: FnOnce() -> OutlivesEnvironment<'tcx>,
210{
211    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &ty::Binder<'tcx, T>) {
212        // When we get into a binder, we need to add its own bound vars to the scope.
213        let mut added = ::alloc::vec::Vec::new()vec![];
214        for arg in t.bound_vars() {
215            let arg: ty::BoundVariableKind<'tcx> = arg;
216            match arg {
217                ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id))
218                | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)) => {
219                    added.push(def_id);
220                    let unique = self.in_scope_parameters.insert(def_id, ParamKind::Late);
221                    match (&unique, &None) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(unique, None);
222                }
223                _ => {
224                    self.tcx.dcx().span_delayed_bug(
225                        self.tcx.def_span(self.parent_def_id),
226                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unsupported bound variable kind: {0:?}",
                arg))
    })format!("unsupported bound variable kind: {arg:?}"),
227                    );
228                }
229            }
230        }
231
232        t.super_visit_with(self);
233
234        // And remove them. The `shift_remove` should be `O(1)` since we're popping
235        // them off from the end.
236        for arg in added.into_iter().rev() {
237            self.in_scope_parameters.shift_remove(&arg);
238        }
239    }
240
241    fn visit_ty(&mut self, t: Ty<'tcx>) {
242        if !t.has_aliases() {
243            return;
244        }
245
246        if let ty::Alias(ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) = *t.kind()
247            && self.tcx.is_impl_trait_in_trait(def_id)
248        {
249            // visit the opaque of the RPITIT
250            self.tcx.type_of(def_id).instantiate(self.tcx, args).skip_norm_wip().visit_with(self)
251        } else if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args: opaque_ty_args, .. }) = *t.kind()
252            && let Some(opaque_def_id) = def_id.as_local()
253            // Don't recurse infinitely on an opaque
254            && self.seen.insert(opaque_def_id)
255            // If it's owned by this function
256            && let opaque =
257                self.tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty()
258            // We want to recurse into RPITs and async fns, even though the latter
259            // doesn't overcapture on its own, it may mention additional RPITs
260            // in its bounds.
261            && let hir::OpaqueTyOrigin::FnReturn { parent, .. }
262                | hir::OpaqueTyOrigin::AsyncFn { parent, .. } = opaque.origin
263            && parent == self.parent_def_id
264        {
265            let opaque_span = self.tcx.def_span(opaque_def_id);
266            let new_capture_rules = opaque_span.at_least_rust_2024();
267            if !new_capture_rules
268                && !opaque.bounds.iter().any(|bound| #[allow(non_exhaustive_omitted_patterns)] match bound {
    hir::GenericBound::Use(..) => true,
    _ => false,
}matches!(bound, hir::GenericBound::Use(..)))
269            {
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.
294                let mut uncaptured_args: FxIndexSet<_> = self
295                    .in_scope_parameters
296                    .iter()
297                    .filter(|&(def_id, _)| !captured.contains(def_id))
298                    .collect();
299                // Remove the set of lifetimes that are in-scope that outlive some other captured
300                // lifetime and are contravariant (i.e. covariant in argument position).
301                uncaptured_args.retain(|&(def_id, kind)| {
302                    let Some(ty::Bivariant | ty::Contravariant) = self.variances.get(def_id) else {
303                        // Keep all covariant/invariant args. Also if variance is `None`,
304                        // then that means it's either not a lifetime, or it didn't show up
305                        // anywhere in the signature.
306                        return true;
307                    };
308                    // We only computed variance of lifetimes...
309                    if true {
    {
        match self.tcx.def_kind(*def_id) {
            DefKind::LifetimeParam => {}
            ref left_val => {
                ::core::panicking::assert_matches_failed(left_val,
                    "DefKind::LifetimeParam", ::core::option::Option::None);
            }
        }
    };
};debug_assert_matches!(self.tcx.def_kind(*def_id), DefKind::LifetimeParam);
310                    let uncaptured = match *kind {
311                        ParamKind::Early(name, index) => ty::Region::new_early_param(
312                            self.tcx,
313                            ty::EarlyParamRegion { name, index },
314                        ),
315                        ParamKind::Free(def_id) => ty::Region::new_late_param(
316                            self.tcx,
317                            self.parent_def_id.to_def_id(),
318                            ty::LateParamRegionKind::Named(def_id),
319                        ),
320                        // Totally ignore late bound args from binders.
321                        ParamKind::Late => return true,
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
331                // If we have uncaptured args, and if the opaque doesn't already have
332                // `use<>` syntax on it, and we're < edition 2024, then warn the user.
333                if !uncaptured_args.is_empty() {
334                    let suggestion = impl_trait_overcapture_suggestion(
335                        self.tcx,
336                        opaque_def_id,
337                        self.parent_def_id,
338                        captured,
339                    );
340
341                    let uncaptured_spans: Vec<_> = uncaptured_args
342                        .into_iter()
343                        .map(|(&def_id, _)| self.tcx.def_span(def_id))
344                        .collect();
345
346                    self.tcx.emit_node_span_lint(
347                        IMPL_TRAIT_OVERCAPTURES,
348                        self.tcx.local_def_id_to_hir_id(opaque_def_id),
349                        opaque_span,
350                        ImplTraitOvercapturesLint {
351                            self_ty: t,
352                            num_captured: uncaptured_spans.len(),
353                            uncaptured_spans,
354                            suggestion,
355                        },
356                    );
357                }
358            }
359
360            // Otherwise, if we are edition 2024, have `use<>` syntax, and
361            // have no uncaptured args, then we should warn to the user that
362            // it's redundant to capture all args explicitly.
363            if new_capture_rules
364                && let Some((captured_args, capturing_span)) =
365                    opaque.bounds.iter().find_map(|bound| match *bound {
366                        hir::GenericBound::Use(a, s) => Some((a, s)),
367                        _ => None,
368                    })
369            {
370                let mut explicitly_captured = UnordSet::default();
371                for arg in captured_args {
372                    match self.tcx.named_bound_var(arg.hir_id()) {
373                        Some(
374                            ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
375                        ) => {
376                            if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy
377                            {
378                                let def_id = self
379                                    .tcx
380                                    .map_opaque_lifetime_to_parent_lifetime(def_id)
381                                    .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id())
382                                    .expect("variable should have been duplicated from parent");
383
384                                explicitly_captured.insert(def_id);
385                            } else {
386                                explicitly_captured.insert(def_id.to_def_id());
387                            }
388                        }
389                        _ => {
390                            self.tcx.dcx().span_delayed_bug(
391                                self.tcx.hir_span(arg.hir_id()),
392                                "no valid for captured arg",
393                            );
394                        }
395                    }
396                }
397
398                if self
399                    .in_scope_parameters
400                    .iter()
401                    .all(|(def_id, _)| explicitly_captured.contains(def_id))
402                {
403                    self.tcx.emit_node_span_lint(
404                        IMPL_TRAIT_REDUNDANT_CAPTURES,
405                        self.tcx.local_def_id_to_hir_id(opaque_def_id),
406                        opaque_span,
407                        ImplTraitRedundantCapturesLint { capturing_span },
408                    );
409                }
410            }
411
412            // Walk into the bounds of the opaque, too, since we want to get nested opaques
413            // in this lint as well. Interestingly, one place that I expect this lint to fire
414            // is for `impl for<'a> Bound<Out = impl Other>`, since `impl Other` will begin
415            // to capture `'a` in e2024 (even though late-bound vars in opaques are not allowed).
416            for clause in self
417                .tcx
418                .item_bounds(def_id)
419                .iter_instantiated(self.tcx, opaque_ty_args)
420                .map(Unnormalized::skip_norm_wip)
421            {
422                clause.visit_with(self)
423            }
424        }
425
426        t.super_visit_with(self);
427    }
428}
429
430struct ImplTraitOvercapturesLint<'tcx> {
431    uncaptured_spans: Vec<Span>,
432    self_ty: Ty<'tcx>,
433    num_captured: usize,
434    suggestion: Option<AddPreciseCapturingForOvercapture>,
435}
436
437impl<'a> Diagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
438    fn into_diag(
439        self,
440        dcx: rustc_errors::DiagCtxtHandle<'a>,
441        level: rustc_errors::Level,
442    ) -> rustc_errors::Diag<'a, ()> {
443        let mut diag = rustc_errors::Diag::new(
444            dcx,
445            level,
446            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024"))msg!("`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024"),
447        );
448        diag.arg("self_ty", self.self_ty.to_string())
449            .arg("num_captured", self.num_captured)
450            .span_note(
451                self.uncaptured_spans,
452                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("specifically, {$num_captured ->\n                        [one] this lifetime is\n                        *[other] these lifetimes are\n                    } in scope but not mentioned in the type's bounds"))msg!(
453                    "specifically, {$num_captured ->
454                        [one] this lifetime is
455                        *[other] these lifetimes are
456                    } in scope but not mentioned in the type's bounds"
457                ),
458            )
459            .note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("all lifetimes in scope will be captured by `impl Trait`s in edition 2024"))msg!("all lifetimes in scope will be captured by `impl Trait`s in edition 2024"));
460        if let Some(suggestion) = self.suggestion {
461            suggestion.add_to_diag(&mut diag);
462        }
463        diag
464    }
465}
466
467#[derive(const _: () =
    {
        impl<'_sess, G> rustc_errors::Diagnostic<'_sess, G> for
            ImplTraitRedundantCapturesLint where
            G: rustc_errors::EmissionGuarantee {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess, G> {
                match self {
                    ImplTraitRedundantCapturesLint { capturing_span: __binding_0
                        } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("all possible in-scope parameters are already captured, so `use<...>` syntax is redundant")));
                        let __code_3 =
                            [::alloc::__export::must_use({
                                                ::alloc::fmt::format(format_args!(""))
                                            })].into_iter();
                        ;
                        diag.span_suggestions_with_style(__binding_0,
                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("remove the `use<...>` syntax")),
                            __code_3, rustc_errors::Applicability::MachineApplicable,
                            rustc_errors::SuggestionStyle::ShowCode);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
468#[diag("all possible in-scope parameters are already captured, so `use<...>` syntax is redundant")]
469struct ImplTraitRedundantCapturesLint {
470    #[suggestion("remove the `use<...>` syntax", code = "", applicability = "machine-applicable")]
471    capturing_span: Span,
472}
473
474fn extract_def_id_from_arg<'tcx>(
475    tcx: TyCtxt<'tcx>,
476    generics: &'tcx ty::Generics,
477    arg: ty::GenericArg<'tcx>,
478) -> DefId {
479    match arg.kind() {
480        ty::GenericArgKind::Lifetime(re) => match re.kind() {
481            ty::ReEarlyParam(ebr) => generics.region_param(ebr, tcx).def_id,
482            ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. })
483            | ty::ReLateParam(ty::LateParamRegion {
484                scope: _,
485                kind: ty::LateParamRegionKind::Named(def_id),
486            }) => def_id,
487            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
488        },
489        ty::GenericArgKind::Type(ty) => {
490            let ty::Param(param_ty) = *ty.kind() else {
491                ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
492            };
493            generics.type_param(param_ty, tcx).def_id
494        }
495        ty::GenericArgKind::Const(ct) => {
496            let ty::ConstKind::Param(param_ct) = ct.kind() else {
497                ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"));bug!();
498            };
499            generics.const_param(param_ct, tcx).def_id
500        }
501    }
502}
503
504/// Computes the variances of regions that appear in the type, but considering
505/// late-bound regions too, which don't have their variance computed usually.
506///
507/// Like generalization, this is a unary operation implemented on top of the binary
508/// relation infrastructure, mostly because it's much easier to have the relation
509/// track the variance for you, rather than having to do it yourself.
510struct FunctionalVariances<'tcx> {
511    tcx: TyCtxt<'tcx>,
512    variances: FxHashMap<DefId, ty::Variance>,
513    ambient_variance: ty::Variance,
514    generics: &'tcx ty::Generics,
515}
516
517impl<'tcx> TypeRelation<TyCtxt<'tcx>> for FunctionalVariances<'tcx> {
518    fn cx(&self) -> TyCtxt<'tcx> {
519        self.tcx
520    }
521
522    fn relate_ty_args(
523        &mut self,
524        a_ty: Ty<'tcx>,
525        _: Ty<'tcx>,
526        def_id: DefId,
527        a_args: ty::GenericArgsRef<'tcx>,
528        b_args: ty::GenericArgsRef<'tcx>,
529        _: impl FnOnce(ty::GenericArgsRef<'tcx>) -> Ty<'tcx>,
530    ) -> RelateResult<'tcx, Ty<'tcx>> {
531        let variances = self.cx().variances_of(def_id);
532        relate_args_with_variances(self, variances, a_args, b_args)?;
533        Ok(a_ty)
534    }
535
536    fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
537        &mut self,
538        variance: ty::Variance,
539        _: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
540        a: T,
541        b: T,
542    ) -> RelateResult<'tcx, T> {
543        let old_variance = self.ambient_variance;
544        self.ambient_variance = self.ambient_variance.xform(variance);
545        self.relate(a, b).unwrap();
546        self.ambient_variance = old_variance;
547        Ok(a)
548    }
549
550    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
551        structurally_relate_tys(self, a, b).unwrap();
552        Ok(a)
553    }
554
555    fn regions(
556        &mut self,
557        a: ty::Region<'tcx>,
558        _: ty::Region<'tcx>,
559    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
560        let def_id = match a.kind() {
561            ty::ReEarlyParam(ebr) => self.generics.region_param(ebr, self.tcx).def_id,
562            ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. })
563            | ty::ReLateParam(ty::LateParamRegion {
564                scope: _,
565                kind: ty::LateParamRegionKind::Named(def_id),
566            }) => def_id,
567            _ => {
568                return Ok(a);
569            }
570        };
571
572        if let Some(variance) = self.variances.get_mut(&def_id) {
573            *variance = unify(*variance, self.ambient_variance);
574        } else {
575            self.variances.insert(def_id, self.ambient_variance);
576        }
577
578        Ok(a)
579    }
580
581    fn consts(
582        &mut self,
583        a: ty::Const<'tcx>,
584        b: ty::Const<'tcx>,
585    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
586        structurally_relate_consts(self, a, b).unwrap();
587        Ok(a)
588    }
589
590    fn binders<T>(
591        &mut self,
592        a: ty::Binder<'tcx, T>,
593        b: ty::Binder<'tcx, T>,
594    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
595    where
596        T: Relate<TyCtxt<'tcx>>,
597    {
598        self.relate(a.skip_binder(), b.skip_binder()).unwrap();
599        Ok(a)
600    }
601}
602
603/// What is the variance that satisfies the two variances?
604fn unify(a: ty::Variance, b: ty::Variance) -> ty::Variance {
605    match (a, b) {
606        // Bivariance is lattice bottom.
607        (ty::Bivariant, other) | (other, ty::Bivariant) => other,
608        // Invariant is lattice top.
609        (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant,
610        // If type is required to be covariant and contravariant, then it's invariant.
611        (ty::Contravariant, ty::Covariant) | (ty::Covariant, ty::Contravariant) => ty::Invariant,
612        // Otherwise, co + co = co, contra + contra = contra.
613        (ty::Contravariant, ty::Contravariant) => ty::Contravariant,
614        (ty::Covariant, ty::Covariant) => ty::Covariant,
615    }
616}