Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/expressions/array-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,22 @@ r[expr.array.index.array]
[Array] and [slice]-typed values can be indexed by writing a square-bracket-enclosed expression of type `usize` (the index) after them. When the array is mutable, the resulting [memory location] can be assigned to.

r[expr.array.index.trait]
For other types an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::ops::IndexMut::index_mut(&mut a, b)` in a mutable place expression context. Just as with methods, Rust will also insert dereference operations on `a` repeatedly to find an implementation.
For other types an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::ops::IndexMut::index_mut(&mut a, b)` in a mutable place expression context, except that when the index expression undergoes [temporary lifetime extension], the indexed expression `a` also has its [temporary scope] extended. Just as with methods, Rust will also insert dereference operations on `a` repeatedly to find an implementation.

```rust
// The temporary holding the result of `vec![()]` is extended to
// live to the end of the block, so `x` may be used in subsequent
// statements.
let x = &vec![()][0];
# x;
```

```rust,compile_fail,E0716
// The temporary holding the result of `vec![()]` is dropped at the
// end of the statement, so it's an error to use `y` after.
let y = &*std::ops::Index::index(&vec![()], 0); // ERROR
# y;
Comment on lines +100 to +101
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about the thinking for hiding the "use" here? My thinking is that with it hidden it could be confusing since assigning to y isn't an error, it's not until the later use. For example, it could be:

Suggested change
let y = &*std::ops::Index::index(&vec![()], 0); // ERROR
# y;
let y = &*std::ops::Index::index(&vec![()], 0);
y; // ERROR

And to contrast in the other example, it could be:

let x = &vec![()][0];
x; // OK

Is it maybe that a bare identifier statement is unusual?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just going for stylistic consistency with the examples in https://doc.rust-lang.org/nightly/reference/destructors.html#r-destructors.scope.lifetime-extension; they also hide usages and put the ok/error comments a line early, relying on the text to clarify. There's a lot more examples there, so there may be more of an argument to made for brevity. I wouldn't be opposed to making the usages explicit here (or even there too) for clarity.

```

r[expr.array.index.zero-index]
Indices are zero-based for arrays and slices.
Expand Down Expand Up @@ -127,3 +142,5 @@ The array index expression can be implemented for types other than arrays and sl
[panic]: ../panic.md
[path]: path-expr.md
[slice]: ../types/slice.md
[temporary lifetime extension]: destructors.scope.lifetime-extension
[temporary scope]: destructors.scope.temporary
17 changes: 16 additions & 1 deletion src/expressions/operator-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ r[expr.deref.safety]
Dereferencing a raw pointer requires `unsafe`.

r[expr.deref.traits]
On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` in an [immutable place expression context](../expressions.md#mutability) and `*std::ops::DerefMut::deref_mut(&mut x)` in a mutable place expression context.
On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` in an [immutable place expression context](../expressions.md#mutability) and `*std::ops::DerefMut::deref_mut(&mut x)` in a mutable place expression context, except that when `*x` undergoes [temporary lifetime extension], the dereferenced expression `x` also has its [temporary scope] extended.

```rust
# struct NoCopy;
Expand All @@ -189,6 +189,21 @@ let c = Box::new(NoCopy);
let d: NoCopy = *c;
```

```rust
// The temporary holding the result of `String::new()` is extended
// to live to the end of the block, so `x` may be used in subsequent
// statements.
let x = &*String::new();
# x;
```

```rust,compile_fail,E0716
// The temporary holding the result of `String::new()` is dropped at
// the end of the statement, so it's an error to use `y` after.
let y = &*std::ops::Deref::deref(&String::new()); // ERROR
# y;
```

r[expr.try]
## The try propagation expression

Expand Down
Loading