@@ -25,14 +25,16 @@ as its direct children. Each variable's direct children would be their fields
25
25
26
26
From this view, every value in Rust has a unique * path* in the tree of ownership.
27
27
References to a value can subsequently be interpreted as a path in this tree.
28
- Of particular interest are * prefixes* : ` x ` is a prefix of ` y ` if ` x ` owns ` y `
28
+ Of particular interest are * ancestors* and * descendants* : if ` x ` owns ` y ` , then
29
+ ` x ` is an * ancestor* of ` y ` , and ` y ` is a * descendant* of ` x ` . Note that this is
30
+ an inclusive relationship: ` x ` is a descendant and ancestor of itself.
29
31
30
- However much data doesn't reside on the stack, and we must also accommodate this.
32
+ Tragically, plenty of data doesn't reside on the stack, and we must also accommodate this.
31
33
Globals and thread-locals are simple enough to model as residing at the bottom
32
34
of the stack (though we must be careful with mutable globals). Data on
33
35
the heap poses a different problem.
34
36
35
- If all Rust had on the heap was data uniquely by a pointer on the stack,
37
+ If all Rust had on the heap was data uniquely owned by a pointer on the stack,
36
38
then we can just treat that pointer as a struct that owns the value on
37
39
the heap. Box, Vec, String, and HashMap, are examples of types which uniquely
38
40
own data on the heap.
@@ -51,6 +53,10 @@ types provide exclusive access through runtime restrictions. However it is also
51
53
possible to establish unique ownership without interior mutability. For instance,
52
54
if an Rc has refcount 1, then it is safe to mutate or move its internals.
53
55
56
+ In order to correctly communicate to the type system that a variable or field of
57
+ a struct can have interior mutability, it must be wrapped in an UnsafeCell. This
58
+ does not in itself make it safe to perform interior mutability operations on that
59
+ value. You still must yourself ensure that mutual exclusion is upheld.
54
60
55
61
56
62
@@ -61,9 +67,9 @@ dereferenced. Shared references are always live unless they are literally unreac
61
67
(for instance, they reside in freed or leaked memory). Mutable references can be
62
68
reachable but * not* live through the process of * reborrowing* .
63
69
64
- A mutable reference can be reborrowed to either a shared or mutable reference.
65
- Further, the reborrow can produce exactly the same reference, or point to a
66
- path it is a prefix of . For instance, a mutable reference can be reborrowed
70
+ A mutable reference can be reborrowed to either a shared or mutable reference to
71
+ one of its descendants. A reborrowed reference will only be live again once all
72
+ reborrows derived from it expire . For instance, a mutable reference can be reborrowed
67
73
to point to a field of its referent:
68
74
69
75
``` rust
@@ -79,7 +85,7 @@ let x = &mut (1, 2);
79
85
```
80
86
81
87
It is also possible to reborrow into * multiple* mutable references, as long as
82
- they are * disjoint* : no reference is a prefix of another. Rust
88
+ they are * disjoint* : no reference is an ancestor of another. Rust
83
89
explicitly enables this to be done with disjoint struct fields, because
84
90
disjointness can be statically proven:
85
91
@@ -89,6 +95,7 @@ let x = &mut (1, 2);
89
95
// reborrow x to two disjoint subfields
90
96
let y = & mut x . 0 ;
91
97
let z = & mut x . 1 ;
98
+
92
99
// y and z are now live, but x isn't
93
100
* y = 3 ;
94
101
* z = 4 ;
@@ -105,14 +112,14 @@ To simplify things, we can model variables as a fake type of reference: *owned*
105
112
references. Owned references have much the same semantics as mutable references:
106
113
they can be re-borrowed in a mutable or shared manner, which makes them no longer
107
114
live. Live owned references have the unique property that they can be moved
108
- out of (though mutable references * can* be swapped out of). This is
115
+ out of (though mutable references * can* be swapped out of). This power is
109
116
only given to * live* owned references because moving its referent would of
110
117
course invalidate all outstanding references prematurely.
111
118
112
119
As a local lint against inappropriate mutation, only variables that are marked
113
120
as ` mut ` can be borrowed mutably.
114
121
115
- It is also interesting to note that Box behaves exactly like an owned
122
+ It is interesting to note that Box behaves exactly like an owned
116
123
reference. It can be moved out of, and Rust understands it sufficiently to
117
124
reason about its paths like a normal variable.
118
125
@@ -123,8 +130,12 @@ reason about its paths like a normal variable.
123
130
124
131
With liveness and paths defined, we can now properly define * aliasing* :
125
132
126
- ** A mutable reference is aliased if there exists another live reference to it or
127
- one of its prefixes.**
133
+ ** A mutable reference is aliased if there exists another live reference to one of
134
+ its ancestors or descendants.**
135
+
136
+ (If you prefer, you may also say the two live references alias * each other* .
137
+ This has no semantic consequences, but is probably a more useful notion when
138
+ verifying the soundness of a construct.)
128
139
129
140
That's it. Super simple right? Except for the fact that it took us two pages
130
141
to define all of the terms in that defintion. You know: Super. Simple.
0 commit comments