-With the lock mechanism established, we can now look at the core of the proposal: Validating the contract described by a type.
-This is done by a new MIR statement, `Validate`, which takes two arguments: An *operation* (which we will discuss shortly), and a list of `(Lvalue, Ty)` pairs defining which lvalues is supposed to be validated at which type.
-Crucially, this is a non-erased type -- all the lifetime information must be present.
-
-The most important validation operation is *acquire validation*.
-As the name indicates, this is about acquiring the appropriate locks.
-It also otherwise makes sure that values are valid at the given type, e.g., references have to be non-NULL and aligned.
-
-The core of acquire validation is an operation with a signature roughly like this:
-{% highlight rust %}
-fn acquire_validate(lval: Lvalue, ty: Ty, mutbl: Mutability, lft: Option<Lifetime>)
-{% endhighlight %}
-Why are mutability and lifetime showing up here?
-The reason is that reference types have a "transitive" effect down the type hierarchy: `&T` makes everything reachable through this reference read-only, even if `T` involves `&mut`.
-Similarly, in case of nested references, it is the *outermost* reference that defines the lifetime for which access through this pointer is granted.
-(The compiler makes sure that inner references always have longer lifetimes than outer references.)
-
-`acquire_validate` recursively traverses the type hierarchy.
-When it encounters a primitive type like `i32`, it acquires a lock of `size_of::<ty>` many locations starting at `lval` for lifetime `lft` -- this will be a write or read lock depending on whether `mutbl` says this data is mutable or not.[^2]
-In other words, memory is locked "at the leaves" of the type structure, rather than locking immediately when we see a reference type.
-We will come back later to why this is necessary.
-Validation also makes sure that the value stored in memory is valid at the given type.
-For a `u32`, this just amounts to checking that the memory is properly initialized.
-
-[^2]: For simplicity, we pretend lvalues are just locations in memory. Actually, lvalues can also refer to variables not in memory (like non-addressable stack locals), but these do not need to be locked. Furthermore, lvalues for unsized types carry the additional information stored in a fat pointer, i.e., a length (for slices) or a vtable (for trait objects); this is handled appropriately when validating the respective types.
-
-For compound types like tuples, `struct` or `enum`, validation proceeds recursively on the fields.
-In particular, the enum discriminant is checked to be in-range (in particular, this empty enums always invalid).
-However, because the recursive validation will only lock memory that's actually covered by a field, we also have to acquire the appropriate lock for padding bytes and the enum discriminant here.
-
-Finally, at a reference type, two things happen.
-First, the reference itself is stored in memory somewhere; this memory has to be locked just like the validation of `i32` locks the memory used to store the integer.
-The reference is also checked to be non-NULL and properly aligned for the type it points to.
-Furthermore, validation proceeds recursively after *dereferencing* the reference.
-Crucially, the `mutbl` and `lft` for this recursive call are taking the reference type into account:
-If `lft` was `None` and this reference's lifetime ends within the function (i.e., there is a corresponding `EndRegion` somewhere), it is now set to the reference's lifetime.
-If `mutbl` was mutable, it becomes immutable when following a shared reference.
-
-There are two other validation operations besides acquire validation: release validation, and suspend validation.
-These serve to release the appropriate locks before handing references to foreign code, and to handle the operation of taking a reference.
-(Bear with me for just a little longer, we will see examples of this soon.)
-Suspend validation takes an additional parameter, namely the lifetime for which locks are to be suspended.
-Both operations recursively follow the type just like acquire validation, and for all memory they visit, they release/suspend *write* locks.
-Read locks are not touched, which corresponds to the fact that shared references are `Copy` and hence never "given up":
-Shared references always remain usable until their lifetime expires, at which point the read lock is released automatically.
-
-Validation statements are emitted during MIR construction in the following places:
-- At the beginning of the function, we perform acquire validation of the arguments.
-- When taking a reference, we suspend the referee for the reference lifetime and acquire the referent.
-- When calling another function, we release the arguments and acquire the return value.
-
-### 2.3 Examples
-
-After all this rather dry theory, let us look at some examples demonstrating how validation works, and how it enables optimizations.