slice: Remove some uses of unsafe in first/last chunk methods
Remove unsafe `split_at_unchecked` and `split_at_mut_unchecked` in some slice `split_first_chunk`/`split_last_chunk` methods.
Replace those calls with the safe `split_at` and `split_at_checked` where applicable.
Add codegen tests to check for no panics when calculating the last chunk index using `checked_sub` and `split_at`.
Better viewed with whitespace disabled in diff view
---
The unchecked calls are mostly manual implementations of the safe methods, but with the safety condition negated from `mid <= len` to `len < mid`.
```rust
if self.len() < N {
None
} else {
// SAFETY: We manually verified the bounds of the split.
let (first, tail) = unsafe { self.split_at_unchecked(N) };
// Or for the last_chunk methods
let (init, last) = unsafe { self.split_at_unchecked(self.len() - N) };
```
Unsafe is still needed for the pointer array casts. Their safety comments are unmodified.
Experimental feature gate for `super let`
This adds an experimental feature gate, `#![feature(super_let)]`, for the `super let` experiment.
Tracking issue: https://github.com/rust-lang/rust/issues/139076
Liaison: ``@nikomatsakis``
## Description
There's a rough (inaccurate) description here: https://blog.m-ou.se/super-let/
In short, `super let` allows you to define something that lives long enough to be borrowed by the tail expression of the block. For example:
```rust
let a = {
super let b = temp();
&b
};
```
Here, `b` is extended to live as long as `a`, similar to how in `let a = &temp();`, the temporary will be extended to live as long as `a`.
## Properties
During the temporary lifetimes work we did last year, we explored the properties of "super let" and concluded that the fundamental property should be that these two are always equivalent in any context:
1. `& $expr`
2. `{ super let a = & $expr; a }`
And, additionally, that these are equivalent in any context when `$expr` is a temporary (aka rvalue):
1. `& $expr`
2. `{ super let a = $expr; & a }`
This makes it possible to give a name to a temporary without affecting how temporary lifetimes work, such that a macro can transparently use a block in its expansion, without that having any effect on the outside.
## Implementing pin!() correctly
With `super let`, we can properly implement the `pin!()` macro without hacks: ✨
```rust
pub macro pin($value:expr $(,)?) {
{
super let mut pinned = $value;
unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }
}
}
```
This is important, as there is currently no way to express it without hacks in Rust 2021 and before (see [hacky definition](2a06022951/library/core/src/pin.rs (L1947))), and no way to express it at all in Rust 2024 (see [issue](https://github.com/rust-lang/rust/issues/138718)).
## Fixing format_args!()
This will also allow us to express `format_args!()` in a way where one can assign the result to a variable, fixing a [long standing issue](https://github.com/rust-lang/rust/issues/92698):
```rust
let f = format_args!("Hello {name}!"); // error today, but accepted in the future! (after separate FCP)
```
## Experiment
The precise definition of `super let`, what happens for `super let x;` (without initializer), and whether to accept `super let _ = _ else { .. }` are still open questions, to be answered by the experiment.
Furthermore, once we have a more complete understanding of the feature, we might be able to come up with a better syntax. (Which could be just a different keywords, or an entirely different way of naming temporaries that doesn't involve a block and a (super) let statement.)
The File is unwrapped to a Handle into an AnonPipe, and then that AnonPipe was unwrapped to a Handle into another AnonPipe. The second operation is entirely redundant.
Misc query tweaks
Remove some redundant work around `cache_on_disk` and `ensure_ok`, since `Result<(), ErrorGuaranteed>` queries don't need to cache or recompute their "value" if they are only used for their result.
In the AST, currently we use `BinOpKind` within `ExprKind::AssignOp` and
`AssocOp::AssignOp`, even though this allows some nonsensical
combinations. E.g. there is no `&&=` operator. Likewise for HIR and
THIR.
This commit introduces `AssignOpKind` which only includes the ten
assignable operators, and uses it in `ExprKind::AssignOp` and
`AssocOp::AssignOp`. (And does similar things for `hir::ExprKind` and
`thir::ExprKind`.) This avoids the possibility of nonsensical
combinations, as seen by the removal of the `bug!` case in
`lang_item_for_binop`.
The commit is mostly plumbing, including:
- Adds an `impl From<AssignOpKind> for BinOpKind` (AST) and `impl
From<AssignOp> for BinOp` (MIR/THIR).
- `BinOpCategory` can now be created from both `BinOpKind` and
`AssignOpKind`.
- Replaces the `IsAssign` type with `Op`, which has more information and
a few methods.
- `suggest_swapping_lhs_and_rhs`: moves the condition to the call site,
it's easier that way.
- `check_expr_inner`: had to factor out some code into a separate
method.
I'm on the fence about whether avoiding the nonsensical combinations is
worth the extra code.
First, move the `lang_item_for_op` call from the top of
`lookup_op_method`'s body to its callsites. It makes those callsites a
little more verbose, but also means `lookup_op_method` no longer cares
whether it's handling a binop or unop. This lets us remove `Op` and
split `lang_item_for_op` into `lang_item_for_{bin,un}op`, which is a
little simpler.
This change is a prerequisite for adding the `ast::AssignOpKind` type in
a subsequent commit.
With this, almost the entire file is fully typechecked,
the only exception being the Element.contains(EventTarget) pattern
that is used several times, those are annotated with
@ts-expect-error
Rollup of 6 pull requests
Successful merges:
- #138992 (literal pattern lowering: use the pattern's type instead of the literal's in `const_to_pat`)
- #139211 (interpret: add a version of run_for_validation for &self)
- #139235 (`AstValidator` tweaks)
- #139237 (Add a dep kind for use of the anon node with zero dependencies)
- #139260 (Add dianqk to codegen reviewers)
- #139264 (Fix two incorrect turbofish suggestions)
r? `@ghost`
`@rustbot` modify labels: rollup
changes:
* Add type signature
* Add null checks
* getHelpButton and getSettingsButton are only called once,
which should marginally improve performance due to less queries.
unfortunatly 2 @ts-expect-error was needed,
as typescript is unaware the EventTarget is likely an Element.
Fix two incorrect turbofish suggestions
This fixes#121901
This is my contribution to Rust, and my first contribution to a language parser that I didn't write myself.
I am a bit outside my depth here, so any constructive criticism is appreciated.
Add a dep kind for use of the anon node with zero dependencies
This adds a dep kind for use of the anon node with zero dependencies instead of making use of the null node. I don't think this matters, but it is nicer than random null nodes in the dep graph.
`AstValidator` tweaks
When I read through `AstValidator` there were several things that tripped me up, and made the code harder to understand than I would have liked. This PR addresses them. Best reviewed one commit at a time.
r? ``@davidtwco``
literal pattern lowering: use the pattern's type instead of the literal's in `const_to_pat`
This has two purposes:
- First, it enables removing the `treat_byte_string_as_slice` fields from `TypeckResults` and `ConstToPat`. A byte string pattern's type will be `&[u8]` when matching on a slice reference, so `const_to_pat` will lower it to a slice ref pattern. I believe this is tested by `tests/ui/match/pattern-deref-miscompile.rs`.
- Second, it will simplify the implementation of byte string literals in deref patterns. If byte string patterns can be given the type `[u8; N]` or `[u8]` during HIR typeck, then nothing needs to be changed in `const_to_pat` in order to lower the patterns `deref!(b"..."): Vec<u8>` and `deref!(b"..."): Box<[u8; 3]>`.
Implementation-wise, this uses `lit_to_const` to make a const with the pattern's type and the literal's valtree; that feels to me like the best way to make sure that the valtree representations of the pattern type and literal are the same. Though it may necessitate later changes to `lit_to_const` to accommodate giving byte string literal patterns non-reference types—would that be reasonable?
This unfortunately doesn't work for the `string_deref_patterns` feature (since that gives string literal patterns the `String` type), so I added a workaround for that. However, once `deref_patterns` supports string literals, it may be able to replace `string_deref_patterns`; the special case for `String` can removed at that point.
r? ``@oli-obk``