Skip to content

Commit a539558

Browse files
authored
add implied bounds doc (#1915)
* add implied bounds doc * lazy type aliases also have explicit implied bounds
1 parent 7b0ef5b commit a539558

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

Diff for: src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
- [Interactions with turbofishing](./turbofishing-and-early-late-bound.md)
121121
- [Higher-ranked trait bounds](./traits/hrtb.md)
122122
- [Caching subtleties](./traits/caching.md)
123+
- [Implied bounds](./traits/implied-bounds.md)
123124
- [Specialization](./traits/specialization.md)
124125
- [Chalk-based trait solving](./traits/chalk.md)
125126
- [Lowering to logic](./traits/lowering-to-logic.md)

Diff for: src/traits/implied-bounds.md

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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

Comments
 (0)