Tweaks, but somethign is wrong.

pull/4/head
Edd Barrett 8 years ago
parent 87b4ca44fa
commit c5c93f2d4c

@ -214,20 +214,15 @@ to the compiler. However it does mean that several programs that are totally
correct with respect to Rust's *true* semantics are rejected because lifetimes correct with respect to Rust's *true* semantics are rejected because lifetimes
are too dumb. are too dumb.
# Unifying Lifetimes # A More Involved Example.
XXX: is unification a good term to be using?
Often the Rust compiler must prove that two references with different lifetimes
are compatible. We call this *unification* of lifetimes.
Consider the following program: Consider the following program:
```rust,ignore ```rust,ignore
fn main() { fn main() {
let s1 = String::from("short"); let s1 = String::from("short");
let s2 = String::from("a long long long string"); let s2r = &String::from("a long long long string");
println!("{}", shortest(&s1, &s2)); println!("{}", shortest(&s1, s2r));
} }
fn shortest<'k>(x: &'k str, y: &'k str) -> &'k str { fn shortest<'k>(x: &'k str, y: &'k str) -> &'k str {
@ -241,18 +236,17 @@ fn shortest<'k>(x: &'k str, y: &'k str) -> &'k str {
The idea is that `shortest()` returns a reference to the shorter of the two The idea is that `shortest()` returns a reference to the shorter of the two
strings referenced by its arguments, but *without* allocating a new string. strings referenced by its arguments, but *without* allocating a new string.
Let's de-sugar main so we can see the implicit lifetimes: Let's de-sugar `main()` so we can see the implicit lifetimes:
```rust,ignore ```rust,ignore
fn main() { fn main() {
'a { 'a {
let s1 = String::from("short"); let s1 = String::from("short");
'b { b' {
let s2 = String::from("a long long long string"); let s2r: &'b = &'b String::from("a long long long string");
'c { 'c {
// Like before, an anonymous scope introduced since &s1 doesn't // Annonymous scope for the borrow of s1
// need to last as long as s1 itself, and similarly for s2. println!("{}", shortest(&'c s1, s2r));
println!("{}", shortest(&'b s1, &'a s2));
} }
} }
} }
@ -260,8 +254,8 @@ fn main() {
``` ```
Now we see that the references passed as arguments to `shortest()`, i.e. `&s1` Now we see that the references passed as arguments to `shortest()`, i.e. `&s1`
and `&s2`, actually have different lifetimes, `&'a` and `&'b`, since their and `&s2`, actually have different lifetimes (`&'b` and `&'c` respectively), since the borrows occur in different scopes.
referents are defined in different scopes. However, the signature of However, the signature of
`shortest()` requires that these two references (and also the returned `shortest()` requires that these two references (and also the returned
reference, which has lifetime `'c`) have the same lifetime. So how does the reference, which has lifetime `'c`) have the same lifetime. So how does the
compiler make sure this is the case? compiler make sure this is the case?
@ -269,32 +263,51 @@ compiler make sure this is the case?
At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of At the call-site of `shortest()`, the compiler must try to *convert* the lifetimes of
the references marked `&'a` in the signature of `shortest()` the references marked `&'a` in the signature of `shortest()`
into a single compatible lifetime. This new lifetime must be shorter than, or equally as into a single compatible lifetime. This new lifetime must be shorter than, or equally as
long as, all three of the original reference lifetimes involved. Therefore a reference `&'o` can be long as, all three of the original reference lifetimes involved. In other words, we must convert to the shortest of the three lifetimes to `&'c`. Conversion from a reference `&'o` can be converted to to `&'p` if `'o` lives at least as long as `'p`, therefore:
converted to to `&'p` if `'o` lives at least as long as `'p`.
In our example:
* `&'b` outlives `'c`, so `&'b` can be converted to `&'c`. * `The first argument &'c s1` already has lifetime `&'c`, so we don't have to do anything here.
* `&'a` outlives `'c`, so `&'a` can be converted to `&'c`. * `&'b` outlives `&'c`, so we can convert `s2r: &'b` to `s2r: &'c`.
* The returned reference has lifetime `&'c` already. * The returned reference has lifetime `&'c` already.
So these references are unified in `&'c`, therefore the lifetime constraints After conversion, the call-site satisfies the signature of `shorter()`, we have
imposed by `shortest()` are consistent, and the compiler accepts the program. proven the lifetimes in this program to be consistent, and therefore the
compiler accepts the program.
Now consider a slight variation on `main()` like this: Now consider a slight variation on `main()` like this:
```rust,ignore ```rust,ignore
fn main() { fn main() {
let a = String::from("short"); let s1 = String::from("short");
{ let res;
let c: &str; let s2 = String::from("a long long long string");
let b = String::from("a long long long string"); res = shortest(&s1, &s2);
c = min(&a, &b); println!("{}", res);
}
```
De-sugared it looks like this:
```rust,ignore
fn main() {
'a {
let s1 = String::from("short");
'b {
let res: &'b str;
'c {
let s2 = String::from("a long long long string");
'd {
// Annonymous scope for the borrows of s1 and s2
// Assigning to the outer scope causes s1 and s2 to have 'b
res: &'b = shortest(&'d s1, &'d s2);
println!("{}", res);
}
}
}
} }
} }
``` ```
XXX Desugar. XXX: Something is wrong. The above program does not compile, so we should be
able to show that the lifetimes are inconsistent. To do so we would to be have
XXX Explain why it doesn't work. to show that we can't convert `&'b` to `&'d`, but since `&'b` outlives `&'d`,
we can. Hrmm.

Loading…
Cancel
Save