Skip to content

Commit 68681fc

Browse files
committed
cool beans
1 parent 00405f8 commit 68681fc

File tree

3 files changed

+95
-53
lines changed

3 files changed

+95
-53
lines changed

src/trait-bounds.md

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -44,67 +44,64 @@ certain common cases:
4444
`trait A { type B: Copy; }` is equivalent to
4545
`trait A where Self::B: Copy { type B; }`.
4646

47+
r[bound.global]
48+
49+
A bound which does not use the item's parameters or any higher-ranked lifetimes are considered global.
50+
51+
An error is emitted if a global bound cannot be satisfied in an empty environment.
52+
4753
r[bound.satisfaction]
48-
Bounds on an item must be satisfied when using the item. When type checking and
49-
borrow checking a generic item, the bounds can be used to determine that a
50-
trait is implemented for a type. For example, given `Ty: Trait`
5154

52-
* In the body of a generic function, methods from `Trait` can be called on `Ty`
53-
values. Likewise associated constants on the `Trait` can be used.
54-
* Associated types from `Trait` can be used.
55-
* Generic functions and types with a `T: Trait` bounds can be used with `Ty`
56-
being used for `T`.
55+
The bounds of an item must be satisfied when using that item.
5756

58-
```rust
59-
# type Surface = i32;
60-
trait Shape {
61-
fn draw(&self, surface: Surface);
62-
fn name() -> &'static str;
63-
}
57+
r[bound.satisfaction.impl]
6458

65-
fn draw_twice<T: Shape>(surface: Surface, sh: T) {
66-
sh.draw(surface); // Can call method because T: Shape
67-
sh.draw(surface);
68-
}
59+
- a trait bound can be satisfied by using an implementation of that trait
60+
- an impl is applicable if, after instantiating its generic parameters with inference variables
61+
- TODO: how to talk about "instantiate with infer vars"...
62+
- the self type and trait arguments are equal to the trait bound,
63+
- the where-bounds of the impl can be recursively satisfied
6964

70-
fn copy_and_draw_twice<T: Copy>(surface: Surface, sh: T) where T: Shape {
71-
let shape_copy = sh; // doesn't move sh because T: Copy
72-
draw_twice(surface, sh); // Can use generic function because T: Shape
73-
}
65+
[bound.satisfaction.impl.builtin]
7466

75-
struct Figure<S: Shape>(S, S);
67+
There exists impls which are automatically generated by the compiler.
7668

77-
fn name_figure<U: Shape>(
78-
figure: Figure<U>, // Type Figure<U> is well-formed because U: Shape
79-
) {
80-
println!(
81-
"Figure of two {}",
82-
U::name(), // Can use associated function
83-
);
84-
}
85-
```
69+
- `Sized`,`Copy`, `Clone`,...
8670

87-
r[bound.trivial]
88-
Bounds that don't use the item's parameters or [higher-ranked lifetimes] are checked when the item is defined.
89-
It is an error for such a bound to be false.
90-
91-
r[bound.special]
92-
[`Copy`], [`Clone`], and [`Sized`] bounds are also checked for certain generic types when using the item, even if the use does not provide a concrete type.
93-
It is an error to have `Copy` or `Clone` as a bound on a mutable reference, [trait object], or [slice].
94-
It is an error to have `Sized` as a bound on a trait object or slice.
95-
96-
```rust,compile_fail
97-
struct A<'a, T>
98-
where
99-
i32: Default, // Allowed, but not useful
100-
i32: Iterator, // Error: `i32` is not an iterator
101-
&'a mut T: Copy, // (at use) Error: the trait bound is not satisfied
102-
[T]: Sized, // (at use) Error: size cannot be known at compilation
103-
{
104-
f: &'a T,
105-
}
106-
struct UsesA<'a, T>(A<'a, T>);
107-
```
71+
72+
- alternative: mention this in item-kind impl
73+
74+
[bound.satisfaction.impl.builtin.trait-object]
75+
76+
Trait objects implement their trait if TODO: lookup conditions, something something project bounds make sense
77+
78+
[bound.satisfaction.bounds]
79+
80+
While inside of a generic item, trait bounds can be satisfied by using the where-bounds of the current item as the item is able to assume that its bounds are satisfied. For this, higher-ranked where-bounds can be instantiated with inference variables. The where-bound is then equated with the trait bound that needs to be satisfied.
81+
82+
[bound.satisfaction.alias-bounds]
83+
84+
- if an alias cannot be normalized in the current environment, trait bounds using this alias as a self type can be proven by using its item bounds
85+
- TODO: alias bounds from nested self-types github.com/rust-lang/rust/pull/120752
86+
87+
88+
[bound.satisfaction.candidate-preference]
89+
90+
> This is purely descriptive. Candidate preference behavior may change in future releases and must not be relied upon for correctness or soundness.
91+
92+
If there are multiple ways to satisfy a trait bound, some groups of candidate are preferred over others. In case a single group has multiple different candidates, the bound remains ambiguous. Candidate preference has the following order
93+
- builtin implementations of `Sized`
94+
- if there are any non-global where-bounds, all where-bounds
95+
- alias-bounds
96+
- impls
97+
- In case the goal trait bound does not contain any inference variables, we prefer builtin trait object impls over user-written impls. TODO: that's unsound jank
98+
- global where-bounds (only relevant if it does not hold)
99+
100+
> note: this candidate preference can result in incorrect errors and type mismatches, e.g. ...
101+
102+
[bound.satisfaction.cycles]
103+
104+
In case satisfying a bound requires recursively satisfying the same bound, we've encountered a *cycle*. TODO: terminology is iffy here .... can just drop this again
108105

109106
r[bound.trait-object]
110107
Trait and lifetime bounds are also used to name [trait objects].

src/types.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,17 @@ enum List<T> {
150150
let a: List<i32> = List::Cons(7, Box::new(List::Cons(13, Box::new(List::Nil))));
151151
```
152152

153+
## Equality of types
154+
155+
Equality and subtyping of types is generally structural. If the outermost type constructors are the same,
156+
the fields are pairwise related. The only exceptions from this rule are higher ranked types and alias types
157+
158+
higher ranked types:
159+
uwu, instantiate binder with placeholders, eq
160+
161+
aliases
162+
normalized to a rigid type, then equated as normal
163+
153164
[Array]: types/array.md
154165
[Boolean]: types/boolean.md
155166
[Closures]: types/closure.md

src/types/alias-types.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
r[type.alias]
2+
3+
- associated types
4+
- opaque types
5+
- link from "impl-trait type" to this or param
6+
7+
r[type.alias.rigid]
8+
9+
Aliases might be treated as rigid in their current environment. In this case they behave like other rigid types.
10+
11+
r[type.alias.normalization]
12+
13+
Alias types can be normalized to their underlying type.
14+
- for associated types this is the type provided by the corresponding impl
15+
- opaque types
16+
17+
r[type.alias.normalization.assoc-type]
18+
19+
Similar to how trait bounds get satisfied, associated types can be normalized via
20+
multiple different candidates
21+
22+
- impl (also builtin)
23+
- projection bound in the environment TODO: where do we talk about them
24+
- alias bound of their self type
25+
26+
candidate preference:
27+
- normalizing an alias relies on the candidate group used to prove their corresponding trait bound
28+
- if corresponding trait bound has been proven via a where-bound or an alias-bound, we do not consider impls
29+
- if there is no remaining candidate, the associated type is rigid
30+
31+
For all applicable candidates we
32+
- prefer where-bounds
33+
- then alias bounds
34+
- then impls

0 commit comments

Comments
 (0)