Skip to content

Commit

Permalink
Rollup merge of rust-lang#40146 - bjorn3:few-infer-changes, r=pnkfelix
Browse files Browse the repository at this point in the history
Better docs of rusty parts of typeck
  • Loading branch information
Ariel Ben-Yehuda authored and alexcrichton committed Mar 10, 2017
2 parents 32a67eb + 90e94d9 commit 747ae40
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 51 deletions.
4 changes: 3 additions & 1 deletion src/librustc/infer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ course, it depends on the program.

The main case which fails today that I would like to support is:

```text
```rust
fn foo<T>(x: T, y: T) { ... }

fn bar() {
Expand All @@ -168,6 +168,8 @@ because the type variable `T` is merged with the type variable for
`X`, and thus inherits its UB/LB of `@mut int`. This leaves no
flexibility for `T` to later adjust to accommodate `@int`.

Note: `@` and `@mut` are replaced with `Rc<T>` and `Rc<RefCell<T>>` in current Rust.

### What to do when not all bounds are present

In the prior discussion we assumed that A.ub was not top and B.lb was
Expand Down
108 changes: 59 additions & 49 deletions src/librustc/infer/region_inference/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,19 @@ every expression, block, and pattern (patterns are considered to
"execute" by testing the value they are applied to and creating any
relevant bindings). So, for example:

fn foo(x: isize, y: isize) { // -+
// +------------+ // |
// | +-----+ // |
// | +-+ +-+ +-+ // |
// | | | | | | | // |
// v v v v v v v // |
let z = x + y; // |
... // |
} // -+

fn bar() { ... }
```rust
fn foo(x: isize, y: isize) { // -+
// +------------+ // |
// | +-----+ // |
// | +-+ +-+ +-+ // |
// | | | | | | | // |
// v v v v v v v // |
let z = x + y; // |
... // |
} // -+

fn bar() { ... }
```

In this example, there is a region for the fn body block as a whole,
and then a subregion for the declaration of the local variable.
Expand Down Expand Up @@ -160,28 +162,32 @@ this, we get a lot of spurious errors around nested calls, in
particular when combined with `&mut` functions. For example, a call
like this one

self.foo(self.bar())
```rust
self.foo(self.bar())
```

where both `foo` and `bar` are `&mut self` functions will always yield
an error.

Here is a more involved example (which is safe) so we can see what's
going on:

struct Foo { f: usize, g: usize }
...
fn add(p: &mut usize, v: usize) {
*p += v;
}
...
fn inc(p: &mut usize) -> usize {
*p += 1; *p
}
fn weird() {
let mut x: Box<Foo> = box Foo { ... };
'a: add(&mut (*x).f,
'b: inc(&mut (*x).f)) // (..)
}
```rust
struct Foo { f: usize, g: usize }
// ...
fn add(p: &mut usize, v: usize) {
*p += v;
}
// ...
fn inc(p: &mut usize) -> usize {
*p += 1; *p
}
fn weird() {
let mut x: Box<Foo> = box Foo { /* ... */ };
'a: add(&mut (*x).f,
'b: inc(&mut (*x).f)) // (..)
}
```

The important part is the line marked `(..)` which contains a call to
`add()`. The first argument is a mutable borrow of the field `f`. The
Expand All @@ -197,16 +203,18 @@ can see that this error is unnecessary. Let's examine the lifetimes
involved with `'a` in detail. We'll break apart all the steps involved
in a call expression:

'a: {
'a_arg1: let a_temp1: ... = add;
'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f;
'a_arg3: let a_temp3: usize = {
let b_temp1: ... = inc;
let b_temp2: &'b = &'b mut (*x).f;
'b_call: b_temp1(b_temp2)
};
'a_call: a_temp1(a_temp2, a_temp3) // (**)
}
```rust
'a: {
'a_arg1: let a_temp1: ... = add;
'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f;
'a_arg3: let a_temp3: usize = {
let b_temp1: ... = inc;
let b_temp2: &'b = &'b mut (*x).f;
'b_call: b_temp1(b_temp2)
};
'a_call: a_temp1(a_temp2, a_temp3) // (**)
}
```

Here we see that the lifetime `'a` includes a number of substatements.
In particular, there is this lifetime I've called `'a_call` that
Expand All @@ -225,19 +233,21 @@ it will not be *dereferenced* during the evaluation of the second
argument, it can still be *invalidated* by that evaluation. Consider
this similar but unsound example:

struct Foo { f: usize, g: usize }
...
fn add(p: &mut usize, v: usize) {
*p += v;
}
...
fn consume(x: Box<Foo>) -> usize {
x.f + x.g
}
fn weird() {
let mut x: Box<Foo> = box Foo { ... };
'a: add(&mut (*x).f, consume(x)) // (..)
}
```rust
struct Foo { f: usize, g: usize }
// ...
fn add(p: &mut usize, v: usize) {
*p += v;
}
// ...
fn consume(x: Box<Foo>) -> usize {
x.f + x.g
}
fn weird() {
let mut x: Box<Foo> = box Foo { ... };
'a: add(&mut (*x).f, consume(x)) // (..)
}
```

In this case, the second argument to `add` actually consumes `x`, thus
invalidating the first argument.
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/infer/region_inference/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>(
};

if output_template.is_empty() {
bug!("empty string provided as RUST_REGION_GRAPH");
panic!("empty string provided as RUST_REGION_GRAPH");
}

if output_template.contains('%') {
Expand Down

0 comments on commit 747ae40

Please sign in to comment.