Skip to content

Commit 802599c

Browse files
committed
Auto merge of #714 - scalexm:wf-ty, r=jackh726
Update "implied bounds" rules for types to match #206 The rules were changed in #206, but the book was not updated.
2 parents a029ba5 + 467c6ee commit 802599c

File tree

2 files changed

+21
-24
lines changed

2 files changed

+21
-24
lines changed

book/src/clauses/implied_bounds.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ Notice that we are now also requiring `Implemented(Self: Trait)` for
405405
traversing all the implied bounds transitively. This does not change anything
406406
when checking whether impls are legal, because since we assume
407407
that the where clauses hold inside the impl, we know that the corresponding
408-
trait reference do hold. Thanks to this setup, you can see that we indeed
408+
trait reference does hold. Thanks to this setup, you can see that we indeed
409409
require to prove the set of all bounds transitively implied by the where
410410
clauses.
411411

@@ -462,41 +462,38 @@ are effectively visiting all the transitive implied bounds, and only these.
462462

463463
## Implied bounds on types
464464

465-
We mainly talked about implied bounds for traits because this was the most
466-
subtle regarding implementation. Implied bounds on types are simpler,
467-
especially because if we assume that a type is well-formed, we don't use that
468-
fact to deduce that other types are well-formed, we only use it to deduce
469-
that e.g. some trait bounds hold.
465+
We mainly talked about implied bounds for traits, but implied bounds on types
466+
are very similar. Suppose we have the following definition:
470467

471-
For types, we just use rules like these ones:
472468
```rust,ignore
473469
struct Type<...> where WC1, ..., WCn {
474470
...
475471
}
476472
```
477473

474+
To prove that `Type<...>` is well-formed, we would need to prove a goal of the
475+
form `WellFormed(Type<...>).`. The `WellFormed(Type<...>)` predicate is defined
476+
by the rule:
477+
478478
```text
479479
forall<...> {
480-
WellFormed(Type<...>) :- WC1, ..., WCn.
480+
WellFormed(Type<...>) :- WellFormed(WC1), ..., WellFormed(WCn).
481481
}
482+
```
483+
484+
Conversely, if we know a type is well-formed from our environment (for example
485+
because it appears as an argument of one of our functions), we can have implied
486+
bounds thanks to the below set of rules:
482487

488+
```text
483489
forall<...> {
484490
FromEnv(WC1) :- FromEnv(Type<...>).
485491
...
486492
FromEnv(WCn) :- FromEnv(Type<...>).
487493
}
488494
```
489-
We can see that we have this asymmetry between well-formedness check,
490-
which only verifies that the direct superbounds hold, and implied bounds which
491-
gives access to all bounds transitively implied by the where clauses. In that
492-
case this is ok because as we said, we don't use `FromEnv(Type<...>)` to deduce
493-
other `FromEnv(OtherType<...>)` things, nor do we use `FromEnv(Type: Trait)` to
494-
deduce `FromEnv(OtherType<...>)` things. So in that sense type definitions are
495-
"less recursive" than traits, and we saw in a previous subsection that
496-
it was the combination of asymmetry and recursive trait / impls that led to
497-
unsoundness. As such, the `WellFormed(Type<...>)` predicate does not need
498-
to be co-inductive.
499495

500-
This asymmetry optimization is useful because in a real Rust program, we have
501-
to check the well-formedness of types very often (e.g. for each type which
502-
appears in the body of a function).
496+
Looking at the above rules, we see that we can never encounter a chain of
497+
deductions of the form `WellFormed(Type<...>) :- ... :- WellFormed(Type<...>)`.
498+
So in contrast with traits, the `WellFormed(Type<...>)` predicate does not need
499+
to be co-inductive.

book/src/clauses/lowering_rules.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,12 @@ we produce the following rule:
204204
```text
205205
// Rule WellFormed-Type
206206
forall<P1..Pn> {
207-
WellFormed(Type<P1..Pn>) :- WC
207+
WellFormed(Type<P1..Pn>) :- WellFormed(WC)
208208
}
209209
```
210210

211-
Note that we use `struct` for defining a type, but this should be understood
212-
as a general type definition (it could be e.g. a generic `enum`).
211+
Note that we use `struct` to define a type, but this should be understood as a
212+
general type definition (it could be e.g. a generic `enum`).
213213

214214
Conversely, we define rules which say that if we assume that a type is
215215
well-formed, we can also assume that its where clauses hold. That is,

0 commit comments

Comments
 (0)