Skip to content

Comments

Rollup of stuff#21688

Closed
Manishearth wants to merge 7 commits intorust-lang:masterfrom
Manishearth:rollup
Closed

Rollup of stuff#21688
Manishearth wants to merge 7 commits intorust-lang:masterfrom
Manishearth:rollup

Conversation

@Manishearth
Copy link
Member

Homu isn't rolling up properly.

steveklabnik and others added 4 commits January 23, 2015 15:31
Spellfix for `Debug` trait documentation. Change "most all types should implement this" to "all types should implement this". Same fix for deprecated `Show` trait.
@rust-highfive
Copy link
Contributor

r? @pcwalton

(rust_highfive has picked a reviewer for you, use r? to override)

@eddyb
Copy link
Member

eddyb commented Jan 27, 2015

@bors r+ a90cc26

…ikomatsakis

 Add `CodeExtent::Remainder` variant; pre-req for new scoping/drop rules.

This new enum variant introduces finer-grain code extents, i.e. we now track that a binding lives only for a suffix of a block, and (importantly) will be dropped when it goes out of scope *before* the bindings that occurred earlier in the block.

Both of these notions are neatly captured by marking the block (and each suffix) as an enclosing scope of the next suffix beneath it.

This is work that is part of the foundation for issue rust-lang#8861.

(It actually has been seen in earlier posted pull requests, in particular rust-lang#21022; I have just factored it out into its own PR to ease my own near-future rebasing, and also get people used to the new rules.)

----

These finer grained scopes do mean that some code is newly rejected by `rustc`; for example:

```rust
let mut map : HashMap<u8, &u8> = HashMap::new();
let tmp = Box::new(2);
map.insert(43, &*tmp);
```

This will now fail to compile with a message that `*tmp` does not live long enough, because the scope of `tmp` is now strictly smaller than
that of `map`, and the use of `&u8` in map's type requires that the borrowed references are all to data that live at least as long as the map.

The usual fix for a case like this is to move the binding for `tmp` up above that of `map`; note that you can still leave the initialization in the original spot, like so:

```rust
let tmp;
let mut map : HashMap<u8, &u8> = HashMap::new();
tmp = box 2;
map.insert(43, &*tmp);
```

Similarly, one can encounter an analogous situation with `Vec`: one would need to rewrite:

```rust
let mut vec = Vec::new();
let tmp = 'c';
vec.push(&tmp);
```

as:

```rust
let tmp;
let mut vec = Vec::new();
tmp = 'c';
vec.push(&tmp);
```

----

In some corner cases, it does not suffice to reorder the bindings; in particular, when the types for both bindings need to reflect exactly the *same* code extent, and a parent/child relationship between them does not work.

In pnkfelix's experience this has arisen most often when mixing uses of cyclic data structures while also allowing a lifetime parameter `'a` to flow into a type parameter context where the type is *invariant* with respect to the type parameter. An important instance of this is `arena::TypedArena<T>`, which is invariant with respect to `T`.

(The reason that variance is relevant is this: *if* `TypedArena` were covariant with respect to its type parameter, then we could assign it
the longer lifetime when it is initialized, and then convert it to a subtype (via covariance) with a shorter lifetime when necessary.  But `TypedArena` is invariant with respect to its type parameter, and thus if `S` is a subtype of `T` (in particular, if `S` has a lifetime parameter that is shorter than that of `T`), then a `TypedArena<S>` is unrelated to `TypedArena<T>`.)

Concretely, consider code like this:

```rust
struct Node<'a> { sibling: Option<&'a Node<'a>> }
struct Context<'a> {
    // because of this field, `Context<'a>` is invariant with respect to `'a`.
    arena: &'a TypedArena<Node<'a>>,
    ...
}
fn new_ctxt<'a>(arena: &'a TypedArena<Node<'a>>) -> Context<'a> { ... }
fn use_ctxt<'a>(fcx: &'a Context<'a>) { ... }

let arena = TypedArena::new();
let ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

In these situations, if you try to introduce two bindings via two distinct `let` statements, each is (with this commit) assigned a distinct extent, and the region inference system cannot find a single region to assign to the lifetime `'a` that works for both of the bindings. So you get an error that `ctxt` does not live long enough; but moving its binding up above that of `arena` just shifts the error so now the compiler complains that `arena` does not live long enough.

 * SO: What to do? The easiest fix in this case is to ensure that the two bindings *do* get assigned the same static extent, by stuffing both
bindings into the same let statement, like so:

```rust
let (arena, ctxt): (TypedArena, Context);
arena = TypedArena::new();
ctxt = new_ctxt(&arena);

use_ctxt(&ctxt);
```

----

Due to the new code restrictions outlined above, this is a ...

[breaking-change]
@bors
Copy link
Collaborator

bors commented Jan 27, 2015

⌛ Testing commit a90cc26 with merge 4429615...

@bors
Copy link
Collaborator

bors commented Jan 27, 2015

💔 Test failed - auto-mac-64-opt

Spellfix for `Debug` trait documentation. Change "most all types should implement this" to "all types should implement this". Same fix for deprecated `Show` trait.
@eddyb
Copy link
Member

eddyb commented Jan 27, 2015

@bors r+ 9c908bb p=11

@bors
Copy link
Collaborator

bors commented Jan 27, 2015

⌛ Testing commit 9c908bb with merge 2d79c01...

@bors
Copy link
Collaborator

bors commented Jan 27, 2015

💔 Test failed - auto-mac-64-opt

@Centril Centril added the rollup A PR which is a rollup label Oct 2, 2019
lnicola pushed a commit to lnicola/rust that referenced this pull request Feb 23, 2026
…onvert-if-to-bool-then-negation

fix: correctly parenthesize inverted condition in convert_if_to_bool_…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rollup A PR which is a rollup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants