Skip to main content

rustc_trait_selection/
regions.rs

1use rustc_data_structures::fx::FxIndexSet;
2use rustc_hir::def_id::LocalDefId;
3use rustc_infer::infer::outlives::env::OutlivesEnvironment;
4use rustc_infer::infer::{
5    InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt, TypeOutlivesConstraint,
6};
7use rustc_macros::extension;
8use rustc_middle::traits::ObligationCause;
9use rustc_middle::traits::query::NoSolution;
10use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode, Unnormalized, elaborate};
11use rustc_span::{DUMMY_SP, Span};
12
13use crate::traits::ScrubbedTraitError;
14use crate::traits::outlives_bounds::InferCtxtExt;
15
16impl<'tcx> OutlivesEnvironmentBuildExt<'tcx> for OutlivesEnvironment<'tcx> {
    fn new(infcx: &InferCtxt<'tcx>, body_def_id: LocalDefId,
        param_env: ty::ParamEnv<'tcx>,
        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>) -> Self {
        Self::new_with_implied_bounds_compat(infcx, body_def_id, param_env,
            assumed_wf_tys, false)
    }
    fn new_with_implied_bounds_compat(infcx: &InferCtxt<'tcx>,
        body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>,
        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
        disable_implied_bounds_hack: bool) -> Self {
        let mut bounds = ::alloc::vec::Vec::new();
        for bound in param_env.caller_bounds() {
            if let Some(mut type_outlives) = bound.as_type_outlives_clause() {
                if infcx.next_trait_solver() {
                    match crate::solve::deeply_normalize::<_,
                                ScrubbedTraitError<'tcx>>(infcx.at(&ObligationCause::dummy(),
                                param_env), Unnormalized::new_wip(type_outlives)) {
                        Ok(new) => type_outlives = new,
                        Err(_) => {
                            infcx.dcx().delayed_bug(::alloc::__export::must_use({
                                        ::alloc::fmt::format(format_args!("could not normalize `{0}`",
                                                bound))
                                    }));
                        }
                    }
                }
                bounds.push(type_outlives);
            }
        }
        let higher_ranked_assumptions =
            infcx.take_registered_region_assumptions();
        let higher_ranked_assumptions =
            elaborate::elaborate_outlives_assumptions(infcx.tcx,
                higher_ranked_assumptions);
        OutlivesEnvironment::from_normalized_bounds(param_env, bounds,
            infcx.implied_bounds_tys(body_def_id, param_env, assumed_wf_tys,
                disable_implied_bounds_hack), higher_ranked_assumptions)
    }
}#[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)]
17impl<'tcx> OutlivesEnvironment<'tcx> {
18    fn new(
19        infcx: &InferCtxt<'tcx>,
20        body_def_id: LocalDefId,
21        param_env: ty::ParamEnv<'tcx>,
22        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
23    ) -> Self {
24        Self::new_with_implied_bounds_compat(infcx, body_def_id, param_env, assumed_wf_tys, false)
25    }
26
27    fn new_with_implied_bounds_compat(
28        infcx: &InferCtxt<'tcx>,
29        body_def_id: LocalDefId,
30        param_env: ty::ParamEnv<'tcx>,
31        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
32        disable_implied_bounds_hack: bool,
33    ) -> Self {
34        let mut bounds = vec![];
35
36        for bound in param_env.caller_bounds() {
37            if let Some(mut type_outlives) = bound.as_type_outlives_clause() {
38                if infcx.next_trait_solver() {
39                    match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
40                        infcx.at(&ObligationCause::dummy(), param_env),
41                        Unnormalized::new_wip(type_outlives),
42                    ) {
43                        Ok(new) => type_outlives = new,
44                        Err(_) => {
45                            infcx.dcx().delayed_bug(format!("could not normalize `{bound}`"));
46                        }
47                    }
48                }
49                bounds.push(type_outlives);
50            }
51        }
52
53        // FIXME(-Znext-trait-solver): Normalize these.
54        let higher_ranked_assumptions = infcx.take_registered_region_assumptions();
55        let higher_ranked_assumptions =
56            elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions);
57
58        // FIXME: This needs to be modified so that we normalize the known type
59        // outlives obligations then elaborate them into their region/type components.
60        // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
61        // if we can normalize `'a`.
62        OutlivesEnvironment::from_normalized_bounds(
63            param_env,
64            bounds,
65            infcx.implied_bounds_tys(
66                body_def_id,
67                param_env,
68                assumed_wf_tys,
69                disable_implied_bounds_hack,
70            ),
71            higher_ranked_assumptions,
72        )
73    }
74}
75
76impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
    #[doc =
    " Resolve regions, using the deep normalizer to normalize any type-outlives"]
    #[doc =
    " obligations in the process. This is in `rustc_trait_selection` because"]
    #[doc = " we need to normalize."]
    #[doc = ""]
    #[doc =
    " Prefer this method over `resolve_regions_with_normalize`, unless you are"]
    #[doc = " doing something specific for normalization."]
    #[doc = ""]
    #[doc =
    " This function assumes that all infer variables are already constrained."]
    fn resolve_regions(&self, body_def_id: LocalDefId,
        param_env: ty::ParamEnv<'tcx>,
        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>)
        -> Vec<RegionResolutionError<'tcx>> {
        self.resolve_regions_with_outlives_env(&OutlivesEnvironment::new(self,
                    body_def_id, param_env, assumed_wf_tys),
            self.tcx.def_span(body_def_id))
    }
    #[doc = " Don\'t call this directly unless you know what you\'re doing."]
    fn resolve_regions_with_outlives_env(&self,
        outlives_env: &OutlivesEnvironment<'tcx>, span: Span)
        -> Vec<RegionResolutionError<'tcx>> {
        self.resolve_regions_with_normalize(&outlives_env,
            |ty, origin|
                {
                    let ty = self.resolve_vars_if_possible(ty);
                    if self.next_trait_solver() {
                        crate::solve::deeply_normalize(self.at(&ObligationCause::dummy_with_span(origin.span()),
                                    outlives_env.param_env),
                                Unnormalized::new_wip(ty)).map_err(|_:
                                    Vec<ScrubbedTraitError<'tcx>>| NoSolution)
                    } else { Ok(ty) }
                }, span)
    }
}#[extension(pub trait InferCtxtRegionExt<'tcx>)]
77impl<'tcx> InferCtxt<'tcx> {
78    /// Resolve regions, using the deep normalizer to normalize any type-outlives
79    /// obligations in the process. This is in `rustc_trait_selection` because
80    /// we need to normalize.
81    ///
82    /// Prefer this method over `resolve_regions_with_normalize`, unless you are
83    /// doing something specific for normalization.
84    ///
85    /// This function assumes that all infer variables are already constrained.
86    fn resolve_regions(
87        &self,
88        body_def_id: LocalDefId,
89        param_env: ty::ParamEnv<'tcx>,
90        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
91    ) -> Vec<RegionResolutionError<'tcx>> {
92        self.resolve_regions_with_outlives_env(
93            &OutlivesEnvironment::new(self, body_def_id, param_env, assumed_wf_tys),
94            self.tcx.def_span(body_def_id),
95        )
96    }
97
98    /// Don't call this directly unless you know what you're doing.
99    fn resolve_regions_with_outlives_env(
100        &self,
101        outlives_env: &OutlivesEnvironment<'tcx>,
102        span: Span,
103    ) -> Vec<RegionResolutionError<'tcx>> {
104        self.resolve_regions_with_normalize(
105            &outlives_env,
106            |ty, origin| {
107                let ty = self.resolve_vars_if_possible(ty);
108
109                if self.next_trait_solver() {
110                    crate::solve::deeply_normalize(
111                        self.at(
112                            &ObligationCause::dummy_with_span(origin.span()),
113                            outlives_env.param_env,
114                        ),
115                        Unnormalized::new_wip(ty),
116                    )
117                    .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution)
118                } else {
119                    Ok(ty)
120                }
121            },
122            span,
123        )
124    }
125}
126
127/// Given a known `param_env` and a set of well formed types, can we prove that
128/// `ty` outlives `region`.
129pub fn ty_known_to_outlive<'tcx>(
130    tcx: TyCtxt<'tcx>,
131    id: LocalDefId,
132    param_env: ty::ParamEnv<'tcx>,
133    wf_tys: &FxIndexSet<Ty<'tcx>>,
134    ty: Ty<'tcx>,
135    region: ty::Region<'tcx>,
136) -> bool {
137    test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
138        infcx.register_type_outlives_constraint_inner(TypeOutlivesConstraint {
139            sub_region: region,
140            sup_type: ty,
141            origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
142        });
143    })
144}
145
146/// Given a known `param_env` and a set of well formed types, can we prove that
147/// `region_a` outlives `region_b`
148pub fn region_known_to_outlive<'tcx>(
149    tcx: TyCtxt<'tcx>,
150    id: LocalDefId,
151    param_env: ty::ParamEnv<'tcx>,
152    wf_tys: &FxIndexSet<Ty<'tcx>>,
153    region_a: ty::Region<'tcx>,
154    region_b: ty::Region<'tcx>,
155) -> bool {
156    test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
157        infcx.sub_regions(
158            SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
159            region_b,
160            region_a,
161            ty::VisibleForLeakCheck::Unreachable,
162        );
163    })
164}
165
166/// Given a known `param_env` and a set of well formed types, set up an
167/// `InferCtxt`, call the passed function (to e.g. set up region constraints
168/// to be tested), then resolve region and return errors
169pub fn test_region_obligations<'tcx>(
170    tcx: TyCtxt<'tcx>,
171    id: LocalDefId,
172    param_env: ty::ParamEnv<'tcx>,
173    wf_tys: &FxIndexSet<Ty<'tcx>>,
174    add_constraints: impl FnOnce(&InferCtxt<'tcx>),
175) -> bool {
176    // Unfortunately, we have to use a new `InferCtxt` each call, because
177    // region constraints get added and solved there and we need to test each
178    // call individually.
179    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
180
181    add_constraints(&infcx);
182
183    let errors = infcx.resolve_regions(id, param_env, wf_tys.iter().copied());
184    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/regions.rs:184",
                        "rustc_trait_selection::regions", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/regions.rs"),
                        ::tracing_core::__macro_support::Option::Some(184u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::regions"),
                        ::tracing_core::field::FieldSet::new(&["message", "errors"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("errors")
                                            as &dyn Value)),
                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&debug(&errors) as
                                            &dyn Value))])
            });
    } else { ; }
};tracing::debug!(?errors, "errors");
185
186    // If we were able to prove that the type outlives the region without
187    // an error, it must be because of the implied or explicit bounds...
188    errors.is_empty()
189}