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::ty::{
10    self, CallerBoundsIterator, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, elaborate,
11};
12use rustc_span::DUMMY_SP;
13
14use crate::traits::ScrubbedTraitError;
15use crate::traits::outlives_bounds::InferCtxtExt;
16
17pub trait OutlivesEnvironmentBuildExt<'tcx> {
    fn new(infcx: &InferCtxt<'tcx>, body_def_id: LocalDefId,
    param_env: ty::ParamEnv<'tcx>,
    assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>)
    -> Self;
    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;
}
impl<'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().non_trait_clauses().iter() {
            if let Some(type_outlives) = bound.as_type_outlives_clause() {
                if true {
                    if !(!infcx.next_trait_solver() ||
                                !type_outlives.has_non_rigid_aliases()) {
                        ::core::panicking::panic("assertion failed: !infcx.next_trait_solver() || !type_outlives.has_non_rigid_aliases()")
                    };
                };
                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>)]
18impl<'tcx> OutlivesEnvironment<'tcx> {
19    fn new(
20        infcx: &InferCtxt<'tcx>,
21        body_def_id: LocalDefId,
22        param_env: ty::ParamEnv<'tcx>,
23        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
24    ) -> Self {
25        Self::new_with_implied_bounds_compat(infcx, body_def_id, param_env, assumed_wf_tys, false)
26    }
27
28    fn new_with_implied_bounds_compat(
29        infcx: &InferCtxt<'tcx>,
30        body_def_id: LocalDefId,
31        param_env: ty::ParamEnv<'tcx>,
32        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
33        disable_implied_bounds_hack: bool,
34    ) -> Self {
35        let mut bounds = vec![];
36
37        for bound in param_env.caller_bounds().non_trait_clauses().iter() {
38            if let Some(type_outlives) = bound.as_type_outlives_clause() {
39                debug_assert!(!infcx.next_trait_solver() || !type_outlives.has_non_rigid_aliases());
40                bounds.push(type_outlives);
41            }
42        }
43
44        // FIXME(-Znext-trait-solver): Normalize these.
45        let higher_ranked_assumptions = infcx.take_registered_region_assumptions();
46        let higher_ranked_assumptions =
47            elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions);
48
49        // FIXME: This needs to be modified so that we normalize the known type
50        // outlives obligations then elaborate them into their region/type components.
51        // Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
52        // if we can normalize `'a`.
53        OutlivesEnvironment::from_normalized_bounds(
54            param_env,
55            bounds,
56            infcx.implied_bounds_tys(
57                body_def_id,
58                param_env,
59                assumed_wf_tys,
60                disable_implied_bounds_hack,
61            ),
62            higher_ranked_assumptions,
63        )
64    }
65}
66
67pub trait InferCtxtRegionExt<'tcx> {
    #[doc = " Resolve regions lexically."]
    #[doc = ""]
    #[doc =
    " This function assumes that all infer variables are already constrained."]
    #[doc = ""]
    #[doc =
    " FIXME(#155345): this can probably be moved back to `rustc_infer` now that normalization is"]
    #[doc =
    " no longer required. These two extension traits won\'t be needed then."]
    fn resolve_regions(&self, body_def_id: LocalDefId,
    param_env: ty::ParamEnv<'tcx>,
    assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>)
    -> Vec<RegionResolutionError<'tcx>>;
}
impl<'tcx> InferCtxtRegionExt<'tcx> for InferCtxt<'tcx> {
    #[doc = " Resolve regions lexically."]
    #[doc = ""]
    #[doc =
    " This function assumes that all infer variables are already constrained."]
    #[doc = ""]
    #[doc =
    " FIXME(#155345): this can probably be moved back to `rustc_infer` now that normalization is"]
    #[doc =
    " no longer required. These two extension traits won\'t be needed then."]
    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))
    }
}#[extension(pub trait InferCtxtRegionExt<'tcx>)]
68impl<'tcx> InferCtxt<'tcx> {
69    /// Resolve regions lexically.
70    ///
71    /// This function assumes that all infer variables are already constrained.
72    ///
73    /// FIXME(#155345): this can probably be moved back to `rustc_infer` now that normalization is
74    /// no longer required. These two extension traits won't be needed then.
75    fn resolve_regions(
76        &self,
77        body_def_id: LocalDefId,
78        param_env: ty::ParamEnv<'tcx>,
79        assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
80    ) -> Vec<RegionResolutionError<'tcx>> {
81        self.resolve_regions_with_outlives_env(&OutlivesEnvironment::new(
82            self,
83            body_def_id,
84            param_env,
85            assumed_wf_tys,
86        ))
87    }
88}
89
90/// Given a known `param_env` and a set of well formed types, can we prove that
91/// `ty` outlives `region`.
92pub fn ty_known_to_outlive<'tcx>(
93    tcx: TyCtxt<'tcx>,
94    id: LocalDefId,
95    param_env: ty::ParamEnv<'tcx>,
96    wf_tys: &FxIndexSet<Ty<'tcx>>,
97    ty: Unnormalized<'tcx, Ty<'tcx>>,
98    region: ty::Region<'tcx>,
99) -> bool {
100    test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
101        // Types in region obligations should be normalized.
102        let ty = if infcx.next_trait_solver() {
103            let Ok(ty) = crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>(
104                infcx.at(&ObligationCause::dummy_with_span(DUMMY_SP), param_env),
105                ty,
106            ) else {
107                return Err(());
108            };
109            ty
110        } else {
111            ty.skip_norm_wip()
112        };
113
114        infcx.register_type_outlives_constraint_inner(TypeOutlivesConstraint {
115            sub_region: region,
116            sup_type: ty,
117            origin: SubregionOrigin::RelateParamBound(DUMMY_SP, ty, None),
118        });
119
120        Ok(())
121    })
122}
123
124/// Given a known `param_env` and a set of well formed types, can we prove that
125/// `region_a` outlives `region_b`
126pub fn region_known_to_outlive<'tcx>(
127    tcx: TyCtxt<'tcx>,
128    id: LocalDefId,
129    param_env: ty::ParamEnv<'tcx>,
130    wf_tys: &FxIndexSet<Ty<'tcx>>,
131    region_a: ty::Region<'tcx>,
132    region_b: ty::Region<'tcx>,
133) -> bool {
134    test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
135        infcx.sub_regions(
136            SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None),
137            region_b,
138            region_a,
139            ty::VisibleForLeakCheck::Unreachable,
140        );
141        Ok(())
142    })
143}
144
145/// Given a known `param_env` and a set of well formed types, set up an
146/// `InferCtxt`, call the passed function (to e.g. set up region constraints
147/// to be tested), then resolve region and return errors
148pub fn test_region_obligations<'tcx>(
149    tcx: TyCtxt<'tcx>,
150    id: LocalDefId,
151    param_env: ty::ParamEnv<'tcx>,
152    wf_tys: &FxIndexSet<Ty<'tcx>>,
153    add_constraints: impl FnOnce(&InferCtxt<'tcx>) -> Result<(), ()>,
154) -> bool {
155    // Unfortunately, we have to use a new `InferCtxt` each call, because
156    // region constraints get added and solved there and we need to test each
157    // call individually.
158    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
159
160    if add_constraints(&infcx).is_err() {
161        return false;
162    }
163
164    let errors = infcx.resolve_regions(id, param_env, wf_tys.iter().copied());
165    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event /rustc-dev/f5cedb83a788ea9581097abc36a2a8503a7f541c/compiler/rustc_trait_selection/src/regions.rs:165",
                        "rustc_trait_selection::regions", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("/rustc-dev/f5cedb83a788ea9581097abc36a2a8503a7f541c/compiler/rustc_trait_selection/src/regions.rs"),
                        ::tracing_core::__macro_support::Option::Some(165u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_trait_selection::regions"),
                        ::tracing_core::field::FieldSet::new(&["message",
                                        {
                                            const NAME:
                                                ::tracing::__macro_support::FieldName<{
                                                    ::tracing::__macro_support::FieldName::len("errors")
                                                }> =
                                                ::tracing::__macro_support::FieldName::new("errors");
                                            NAME.as_str()
                                        }], ::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};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("errors")
                                            as &dyn ::tracing::field::Value)),
                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&errors)
                                            as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};tracing::debug!(?errors, "errors");
166
167    // If we were able to prove that the type outlives the region without
168    // an error, it must be because of the implied or explicit bounds...
169    errors.is_empty()
170}