|
| 1 | +# Implied bounds |
| 2 | + |
| 3 | +We currently add implied region bounds to avoid explicit annotations. e.g. |
| 4 | +`fn foo<'a, T>(x: &'a T)` can freely assume that `T: 'a` holds without specifying it. |
| 5 | + |
| 6 | +There are two kinds of implied bounds: explicit and implicit. Explicit implied bounds |
| 7 | +get added to the `fn predicates_of` of the relevant item while implicit ones are |
| 8 | +handled... well... implicitly. |
| 9 | + |
| 10 | +## explicit implied bounds |
| 11 | + |
| 12 | +The explicit implied bounds are computed in [`fn inferred_outlives_of`]. Only ADTs and |
| 13 | +lazy type aliases have explicit implied bounds which are computed via a fixpoint algorithm |
| 14 | +in the [`fn inferred_outlives_crate`] query. |
| 15 | + |
| 16 | +We use [`fn insert_required_predicates_to_be_wf`] on all fields of all ADTs in the crate. |
| 17 | +This function computes the outlives bounds for each component of the field using a |
| 18 | +separate implementation. |
| 19 | + |
| 20 | +For ADTs, trait objects, and associated types the initially required predicates are |
| 21 | +computed in [`fn check_explicit_predicates`]. This simply uses `fn explicit_predicates_of` |
| 22 | +without elaborating them. |
| 23 | + |
| 24 | +Region predicates are added via [`fn insert_outlives_predicate`]. This function takes |
| 25 | +an outlives predicate, decomposes it and adds the components as explicit predicates only |
| 26 | +if the outlived region is a region parameter. [It does not add `'static` requirements][nostatic]. |
| 27 | + |
| 28 | + [`fn inferred_outlives_of`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/mod.rs#L20 |
| 29 | + [`fn inferred_outlives_crate`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/mod.rs#L83 |
| 30 | + [`fn insert_required_predicates_to_be_wf`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs#L89 |
| 31 | + [`fn check_explicit_predicates`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs#L238 |
| 32 | + [`fn insert_outlives_predicate`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/utils.rs#L15 |
| 33 | + [nostatic]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_hir_analysis/src/outlives/utils.rs#L159-L165 |
| 34 | + |
| 35 | +## implicit implied bounds |
| 36 | + |
| 37 | +As we are unable to handle implications in binders yet, we cannot simply add the outlives |
| 38 | +requirements of impls and functions as explicit predicates. |
| 39 | + |
| 40 | +### using implicit implied bounds as assumptions |
| 41 | + |
| 42 | +These bounds are not added to the `ParamEnv` of the affected item itself. For lexical |
| 43 | +region resolution they are added using [`fn OutlivesEnvironment::with_bounds`]. |
| 44 | +Similarly,during MIR borrowck we add them using |
| 45 | +[`fn UniversalRegionRelationsBuilder::add_implied_bounds`]. |
| 46 | + |
| 47 | +[We add implied bounds for the function signature and impl header in MIR borrowck][mir]. |
| 48 | +Outside of MIR borrowck we add the outlives requirements for the types returned by the |
| 49 | +[`fn assumed_wf_types`] query. |
| 50 | + |
| 51 | +The assumed outlives constraints for implicit bounds are computed using the |
| 52 | +[`fn implied_outlives_bounds`] query. This directly |
| 53 | +[extracts the required outlives bounds from `fn wf::obligations`][boundsfromty]. |
| 54 | + |
| 55 | +MIR borrowck adds the outlives constraints for both the normalized and unnormalized types, |
| 56 | +lexical region resolution [only uses the unnormalized types][notnorm]. |
| 57 | + |
| 58 | +[`fn OutlivesEnvironment::with_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_infer/src/infer/outlives/env.rs#L90-L97 |
| 59 | +[`fn UniversalRegionRelationsBuilder::add_implied_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L316 |
| 60 | +[mir]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L258-L332 |
| 61 | +[`fn assumed_wf_types`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_ty_utils/src/implied_bounds.rs#L21 |
| 62 | +[`fn implied_outlives_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_traits/src/implied_outlives_bounds.rs#L18C4-L18C27 |
| 63 | +[boundsfromty]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs#L95-L96 |
| 64 | +[notnorm]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_trait_selection/src/traits/engine.rs#L227-L250 |
| 65 | + |
| 66 | +### proving implicit implied bounds |
| 67 | + |
| 68 | +As the implicit implied bounds are not included in `fn predicates_of` we have to |
| 69 | +separately make sure they actually hold. We generally handle this by checking that |
| 70 | +all used types are well formed by emitting `WellFormed` predicates. |
| 71 | + |
| 72 | +We cannot emit `WellFormed` predicates when instantiating impls, as this would result |
| 73 | +in - currently often inductive - trait solver cycles. We also do not emit constraints |
| 74 | +involving higher ranked regions as we're lacking the implied bounds from their binder. |
| 75 | + |
| 76 | +This results in multiple unsoundnesses: |
| 77 | +- by using subtyping: [#25860] |
| 78 | +- by using super trait upcasting for a higher ranked trait bound: [#84591] |
| 79 | +- by being able to normalize a projection when using an impl while not being able |
| 80 | + to normalize it when checking the impl: [#100051] |
| 81 | + |
| 82 | +[#25860]: https://github.com/rust-lang/rust/issues/25860 |
| 83 | +[#84591]: https://github.com/rust-lang/rust/issues/84591 |
| 84 | +[#100051]: https://github.com/rust-lang/rust/issues/100051 |
0 commit comments