| Age | Commit message (Collapse) | Author | Lines |
|
Allow storing `format_args!()` in variable
Fixes https://github.com/rust-lang/rust/issues/92698
Tracking issue for super let: https://github.com/rust-lang/rust/issues/139076
Tracking issue for format_args: https://github.com/rust-lang/rust/issues/99012
This change allows:
```rust
let name = "world";
let f = format_args!("hello {name}!"); // New: Store format_args!() for later!
println!("{f}");
```
This will need an FCP.
This implementation makes use of `super let`, which is unstable and might not exist in the future in its current form. However, it is entirely reasonable to assume future Rust will always have _a_ way of expressing temporary lifetimes like this, since the (stable) `pin!()` macro needs this too. (This was also the motivation for merging https://github.com/rust-lang/rust/pull/139114.)
(This is a second version of https://github.com/rust-lang/rust/pull/139135)
|
|
r=lcnr,traviscross
Stabilize `feature(generic_arg_infer)`
Fixes rust-lang/rust#85077
r? lcnr
cc ````@rust-lang/project-const-generics````
|
|
This uses `super let` to allow
let f = format_args!("Hello {}", world);
println!("{f}");
to work.
|
|
Require generic params for const generic params
I think that was just an oversight when the support for them was added
r? `@BoxyUwU` or `@camelid`
fixes rust-lang/rust#137188
fixes rust-lang/rust#138166
fixes rust-lang/rust#138240
fixes rust-lang/rust#138266
fixes rust-lang/rust#138359
|
|
|
|
r=oli-obk
assert more in release in `rustc_ast_lowering`
My understanding of the compiler's architecture is that in the `ast_lowering` crate, we are constructing the HIR as a one-time thing per crate. This is after tokenizing, parsing, resolution, expansion, possible reparsing, reresolution, reexpansion, and so on. In other words, there are many reasons that perf-focused PRs spend a lot of time touching `rustc_parse`, `rustc_expand`, `rustc_ast`, and then `rustc_hir` and "onwards", but `ast_lowering` is a little bit of an odd duck.
In this crate, we have a number of debug assertions. Some are clearly expensive checks that seem like they are prohibitive to run in actual optimized compiler builds, but then there are a number that are simple asserts on integer equalities, `is_empty`, or the like. I believe we should do some of them even in release builds, because the correctness gain is worth the performance cost: almost zero.
|
|
lint on duplicates during attribute parsing
To do this we stuff them in the diagnostic context to be emitted after
hir is constructed
|
|
|
|
|
|
|
|
Replace some `Option<Span>` with `Span` and use DUMMY_SP instead of None
Turns out many locations actually have a span available that we could use, so I used it
|
|
|
|
|
|
`UsePath` contains a `SmallVec<[Res; 3]>`. This holds up to three `Res`
results, one per namespace (type, value, or macro). `lower_import_res`
takes a `PerNS<Option<Res<NodeId>>>` result and lowers it into the
`SmallVec`. This is pretty weird. The input `PerNS` makes it clear which
`Res` belongs to which namespace, but the `SmallVec` throws that
information away.
And code that operates on the `SmallVec` tends to use iteration (or even
just grabbing the first entry!) without knowing which namespace the
`Res` belongs to. Even weirder! Also, `SmallVec` is an overly flexible
type to use here, because it can contain any number of elements (even
though it's optimized for 3 in this case).
This commit changes `UsePath` so it also contains a
`PerNS<Option<Res<HirId>>>`. This type preserves more information and is
more self-documenting. The commit also changes a lot of the use sites to
access the result for a particular namespace. E.g. if you're looking up
a trait, it will be in the `Res` for the type namespace if it's present;
it's silly to look in the `Res` for the value namespace or macro
namespace. Overall I find the new code much easier to understand.
However, some use sites still iterate. These now use `present_items`
because that filters out the `None` results.
Also, `redundant_pub_crate.rs` gets a bigger change. A
`UseKind:ListStem` item gets no `Res` results, which means the old `all`
call in `is_not_macro_export` would succeed (because `all` succeeds on
an empty iterator) and the `ListStem` would be ignored. This is what we
want, but was more by luck than design. The new code detects `ListStem`
explicitly. The commit generalizes the name of that function
accordingly.
Finally, the commit also removes the `use_path` arena, because
`PerNS<Option<Res>>` impls `Copy` (unlike `SmallVec`) and it can be
allocated in the arena shared by all `Copy` types.
|
|
|
|
Stage0 bootstrap update
This PR [follows the release process](https://forge.rust-lang.org/release/process.html#master-bootstrap-update-tuesday) to update the stage0 compiler.
The only thing of note is https://github.com/rust-lang/rust/commit/58651d1b316e268fac2100c3ae37bb502a36b8ba, which was flagged by clippy as a correctness fix. I think allowing that lint in our case makes sense, but it's worth to have a second pair of eyes on it.
r? `@Mark-Simulacrum`
|
|
|
|
|
|
Remove global `next_disambiguator` state and handle it with a `DisambiguatorState` type
This removes `Definitions.next_disambiguator` as it doesn't guarantee deterministic def paths when `create_def` is called in parallel. Instead a new `DisambiguatorState` type is passed as a mutable reference to `create_def` to help create unique def paths. `create_def` calls with distinct `DisambiguatorState` instances must ensure that that the def paths are unique without its help.
Anon associated types did rely on this global state for uniqueness and are changed to use (method they're defined in + their position in the method return type) as the `DefPathData` to ensure uniqueness. This also means that the method they're defined in appears in error messages, which is nicer.
`DefPathData::NestedStatic` is added to use for nested data inside statics instead of reusing `DefPathData::AnonConst` to avoid conflicts with those.
cc `@oli-obk`
|
|
Improve `Lifetime::suggestion`
r? ``@lcnr``
|
|
`Path<>` needs to be distinguished from `Path<T>`. This commit does
that, improving some error messages.
|
|
|
|
`DisambiguatorState` type
|
|
|
|
Rollup of 8 pull requests
Successful merges:
- #137653 (Deprecate the unstable `concat_idents!`)
- #138957 (Update the index of Option to make the summary more comprehensive)
- #140006 (ensure compiler existance of tools on the dist step)
- #140143 (Move `sys::pal::os::Env` into `sys::env`)
- #140202 (Make #![feature(let_chains)] bootstrap conditional in compiler/)
- #140236 (norm nested aliases before evaluating the parent goal)
- #140257 (Some drive-by housecleaning in `rustc_borrowck`)
- #140278 (Don't use item name to look up associated item from trait item)
r? `@ghost`
`@rustbot` modify labels: rollup
|
|
Make #![feature(let_chains)] bootstrap conditional in compiler/
Let chains have been stabilized recently in #132833, so we can remove the gating from our uses in the compiler (as the compiler uses edition 2024).
|
|
`DelimArgs` tweaks
r? `@petrochenkov`
|
|
An upcoming lint will want to be able to know if a lifetime is
hidden (e.g. `&u8`, `ContainsLifetime`) or anonymous: (e.g. `&'_ u8`,
`ContainsLifetime<'_>`). It will also want to know if the lifetime is
related to a reference (`&u8`) or a path (`ContainsLifetime`).
|
|
|
|
|
|
Rename `LifetimeName` as `LifetimeKind`.
It's a much better name, more consistent with how we name such things.
Also rename `Lifetime::res` as `Lifetime::kind` to match. I suspect this field used to have the type `LifetimeRes` and then the type was changed but the field name remained the same.
r? ``@BoxyUwU``
|
|
It's a much better name, more consistent with how we name such things.
Also rename `Lifetime::res` as `Lifetime::kind` to match. I suspect this
field used to have the type `LifetimeRes` and then the type was changed
but the field name remained the same.
|
|
These were low value even before #137978 resulted in empty names being
used much less. (Why check for non-emptiness in these three places?
There are thousands of places in the compiler you could check.)
|
|
nnethercote:rm-Nonterminal-and-TokenKind-Interpolated, r=petrochenkov
Remove `Nonterminal` and `TokenKind::Interpolated`
A third attempt at this; the first attempt was #96724 and the second was #114647.
r? `@ghost`
|
|
r=compiler-errors
Allow parenthesis around inferred array lengths
In #135272 it was noticed that we weren't handling `Vec<(((((_)))))>` correctly under the new desugaring for `generic_arg_infer`, this had to be fixed in order to not regress stable code for types that should continue working. This has the side effect of *also* allowing the following to work:
```rust
#![feature(generic_arg_infer)]
struct Bar<const N: usize>;
fn main() {
let a: Bar<((_))> = Bar::<10>;
}
```
However I did not make the same change for array lengths resulting in the following not compiling:
```rust
#![feature(generic_arg_infer)]
fn main() {
let a: [u8; (((_)))] = [2; 2];
let a: [u8; 2] = [2; (((((_)))))];
}
```
This is rather inconsistent as parenthesis around `_` *are* supported for const args to non-arrays, and type args. This PR fixes this allowing the above example to compile. No stable impact.
r? compiler-errors
|
|
|
|
It bugs me when variables of type `Ident` are called `name`. It leads to
silly things like `name.name`. `Ident` variables should be called
`ident`, and `name` should be used for variables of type `Symbol`.
This commit improves things by by doing `s/name/ident/` on a bunch of
`Ident` variables. Not all of them, but a decent chunk.
|
|
Implement `super let`
Tracking issue: https://github.com/rust-lang/rust/issues/139076
This implements `super let` as proposed in #139080, based on the following two equivalence rules.
1. For all expressions `$expr` in any context, these are equivalent:
- `& $expr`
- `{ super let a = & $expr; a }`
2. And, additionally, these are equivalent in any context when `$expr` is a temporary (aka rvalue):
- `& $expr`
- `{ super let a = $expr; & a }`
So far, this experiment has a few interesting results:
## Interesting result 1
In this snippet:
```rust
super let a = f(&temp());
```
I originally expected temporary `temp()` would be dropped at the end of the statement (`;`), just like in a regular `let`, because `temp()` is not subject to temporary lifetime extension.
However, it turns out that that would break the fundamental equivalence rules.
For example, in
```rust
g(&f(&temp()));
```
the temporary `temp()` will be dropped at the `;`.
The first equivalence rule tells us this must be equivalent:
```rust
g({ super let a = &f(&temp()); a });
```
But that means that `temp()` must live until the last `;` (after `g()`), not just the first `;` (after `f()`).
While this was somewhat surprising to me at first, it does match the exact behavior we need for `pin!()`: The following _should work_. (See also https://github.com/rust-lang/rust/issues/138718)
```rust
g(pin!(f(&mut temp())));
```
Here, `temp()` lives until the end of the statement. This makes sense from the perspective of the user, as no other `;` or `{}` are visible. Whether `pin!()` uses a `{}` block internally or not should be irrelevant.
This means that _nothing_ in a `super let` statement will be dropped at the end of that super let statement. It does not even need its own scope.
This raises questions that are useful for later on:
- Will this make temporaries live _too long_ in cases where `super let` is used not in a hidden block in a macro, but as a visible statement in code like the following?
```rust
let writer = {
super let file = File::create(&format!("/home/{user}/test"));
Writer::new(&file)
};
```
- Is a `let` statement in a block still the right syntax for this? Considering it has _no_ scope of its own, maybe neither a block nor a statement should be involved
This leads me to think that instead of `{ super let $pat = $init; $expr }`, we might want to consider something like `let $pat = $init in $expr` or `$expr where $pat = $init`. Although there are also issues with these, as it isn't obvious anymore if `$init` should be subject to temporary lifetime extension. (Do we want both `let _ = _ in ..` and `super let _ = _ in ..`?)
## Interesting result 2
What about `super let x;` without initializer?
```rust
let a = {
super let x;
x = temp();
&x
};
```
This works fine with the implementation in this PR: `x` is extended to live as long as `a`.
While it matches my expectations, a somewhat interesting thing to realize is that these are _not_ equivalent:
- `super let x = $expr;`
- `super let x; x = $expr;`
In the first case, all temporaries in $expr will live at least as long as (the result of) the surrounding block.
In the second case, temporaries will be dropped at the end of the assignment statement. (Because the assignment statement itself "is not `super`".)
This difference in behavior might be confusing, but it _might_ be useful.
One might want to extend the lifetime of a variable without extending all the temporaries in the initializer expression.
On the other hand, that can also be expressed as:
- `let x = $expr; super let x = x;` (w/o temporary lifetime extension), or
- `super let x = { $expr };` (w/ temporary lifetime extension)
So, this raises these questions:
- Do we want to accept `super let x;` without initializer at all?
- Does it make sense for statements other than let statements to be "super"? An expression statement also drops temporaries at its `;`, so now that we discovered that `super let` basically disables that `;` (see interesting result 1), is there a use to having other statements without their own scope? (I don't think that's ever useful?)
## Interesting result 3
This works now:
```rust
super let Some(x) = a.get(i) else { return };
```
I didn't put in any special cases for `super let else`. This is just the behavior that 'naturally' falls out when implementing `super let` without thinking of the `let else` case.
- Should `super let else` work?
## Interesting result 4
This 'works':
```rust
fn main() {
super let a = 123;
}
```
I didn't put in any special cases for `super let` at function scope. I had expected the code to cause an ICE or other weird failure when used at function body scope, because there's no way to let the variable live as long as the result of the function.
This raises the question:
- Does this mean that this behavior is the natural/expected behavior when `super let` is used at function scope? Or is this just a quirk and should we explicitly disallow `super let` in a function body? (Probably the latter.)
---
The questions above do not need an answer to land this PR. These questions should be considered when redesigning/rfc'ing/stabilizing the feature.
|
|
Add new `PatKind::Missing` variants
To avoid some ugly uses of `kw::Empty` when handling "missing" patterns, e.g. in bare fn tys. Helps with #137978. Details in the individual commits.
r? ``@oli-obk``
|
|
|
|
These are no longer needed now that `Nonterminal` is gone.
|
|
They are no longer needed.
This does slightly worsen the error message for a single test, but that
test contains code that is so badly broken that I'm not worried about
it.
|
|
`hir::Lifetime::ident` currently sometimes uses `kw::Empty` for elided
lifetimes and sometimes uses `kw::UnderscoreLifetime`, and the
distinction is used when creating some error suggestions, e.g. in
`Lifetime::suggestion` and `ImplicitLifetimeFinder::visit_ty`. I found
this *really* confusing, and it took me a while to understand what was
going on.
This commit replaces all uses of `kw::Empty` in `hir::Lifetime::ident`
with `kw::UnderscoreLifetime`. It adds a new field
`hir::Lifetime::is_path_anon` that mostly replaces the old
empty/underscore distinction and makes things much clearer.
Some other notable changes:
- Adds a big comment to `Lifetime` talking about permissable field
values.
- Adds some assertions in `new_named_lifetime` about what ident values
are permissible for the different `LifetimeRes` values.
- Adds a `Lifetime::new` constructor that does some checking to make
sure the `is_elided` and `is_anonymous` states are valid.
- `add_static_impl_trait_suggestion` now looks at `Lifetime::res`
instead of the ident when creating the suggestion. This is the one
case where `is_path_anon` doesn't replace the old empty/underscore
distinction.
- A couple of minor pretty-printing improvements.
|
|
Thanks to the introduction of `PatKind::Missing`.
|
|
"Missing" patterns are possible in bare fn types (`fn f(u32)`) and
similar places. Currently these are represented in the AST with
`ast::PatKind::Ident` with no `by_ref`, no `mut`, an empty ident, and no
sub-pattern. This flows through to `{hir,thir}::PatKind::Binding` for
HIR and THIR.
This is a bit nasty. It's very non-obvious, and easy to forget to check
for the exceptional empty identifier case.
This commit adds a new variant, `PatKind::Missing`, to do it properly.
The process I followed:
- Add a `Missing` variant to `{ast,hir,thir}::PatKind`.
- Chang `parse_param_general` to produce `ast::PatKind::Missing`
instead of `ast::PatKind::Missing`.
- Look through `kw::Empty` occurrences to find functions where an
existing empty ident check needs replacing with a `PatKind::Missing`
check: `print_param`, `check_trait_item`, `is_named_param`.
- Add a `PatKind::Missing => unreachable!(),` arm to every exhaustive
match identified by the compiler.
- Find which arms are actually reachable by running the test suite,
changing them to something appropriate, usually by looking at what
would happen to a `PatKind::Ident`/`PatKind::Binding` with no ref, no
`mut`, an empty ident, and no subpattern.
Quite a few of the `unreachable!()` arms were never reached. This makes
sense because `PatKind::Missing` can't happen in every pattern, only
in places like bare fn tys and trait fn decls.
I also tried an alternative approach: modifying `ast::Param::pat` to
hold an `Option<P<Pat>>` instead of a `P<Pat>`, but that quickly turned
into a very large and painful change. Adding `PatKind::Missing` is much
easier.
|
|
Ensure `define_opaque` attrs are accounted for in HIR hash
Fixes #138948
r? oli-obk
|
|
r=oli-obk,traviscross
Stabilize `#![feature(precise_capturing_in_traits)]`
# Precise capturing (`+ use<>` bounds) in traits - Stabilization Report
Fixes https://github.com/rust-lang/rust/issues/130044.
## Stabilization summary
This report proposes the stabilization of `use<>` precise capturing bounds in return-position impl traits in traits (RPITITs). This completes a missing part of [RFC 3617 "Precise capturing"].
Precise capturing in traits was not ready for stabilization when the first subset was proposed for stabilization (namely, RPITs on free and inherent functions - https://github.com/rust-lang/rust/pull/127672) since this feature has a slightly different implementation, and it hadn't yet been implemented or tested at the time. It is now complete, and the type system implications of this stabilization are detailed below.
## Motivation
Currently, RPITITs capture all in-scope lifetimes, according to the decision made in the ["lifetime capture rules 2024" RFC](https://rust-lang.github.io/rfcs/3498-lifetime-capture-rules-2024.html#return-position-impl-trait-in-trait-rpitit). However, traits can be designed such that some lifetimes in arguments may not want to be captured. There is currently no way to express this.
## Major design decisions since the RFC
No major decisions were made. This is simply an extension to the RFC that was understood as a follow-up from the original stabilization.
## What is stabilized?
Users may write `+ use<'a, T>` bounds on their RPITITs. This conceptually modifies the desugaring of the RPITIT to omit the lifetimes that we would copy over from the method. For example,
```rust
trait Foo {
fn method<'a>(&'a self) -> impl Sized;
// ... desugars to something like:
type RPITIT_1<'a>: Sized;
fn method_desugared<'a>(&'a self) -> Self::RPITIT_1<'a>;
// ... whereas with precise capturing ...
fn precise<'a>(&'a self) -> impl Sized + use<Self>;
// ... desugars to something like:
type RPITIT_2: Sized;
fn precise_desugared<'a>(&'a self) -> Self::RPITIT_2;
}
```
And thus the GAT doesn't name `'a`. In the compiler internals, it's not implemented exactly like this, but not in a way that users should expect to be able to observe.
#### Limitations on what generics must be captured
Currently, we require that all generics from the trait (including the `Self`) type are captured. This is because the generics from the trait are required to be *invariant* in order to do associated type normalization.
And like regular precise capturing bounds, all type and const generics in scope must be captured.
Thus, only the in-scope method lifetimes may be relaxed with this syntax today.
## What isn't stabilized? (a.k.a. potential future work)
See section above. Relaxing the requirement to capture all type and const generics in scope may be relaxed when https://github.com/rust-lang/rust/issues/130043 is implemented, however it currently interacts with some underexplored corners of the type system (e.g. unconstrained type bivariance) so I don't expect it to come soon after.
## Implementation summary
This functionality is implemented analogously to the way that *opaque type* precise capturing works.
Namely, we currently use *variance* to model the capturedness of lifetimes. However, since RPITITs are anonymous GATs instead of opaque types, we instead modify the type relation of GATs to consider variances for RPITITs (along with opaque types which it has done since https://github.com/rust-lang/rust/pull/103491).
https://github.com/rust-lang/rust/blob/30f168ef811aec63124eac677e14699baa9395bd/compiler/rustc_middle/src/ty/util.rs#L954-L976
https://github.com/rust-lang/rust/blob/30f168ef811aec63124eac677e14699baa9395bd/compiler/rustc_type_ir/src/relate.rs#L240-L244
Using variance to model capturedness is an implementation detail, and in the future it would be desirable if opaques and RPITITs simply did not include the uncaptured lifetimes in their generics. This can be changed in a forwards-compatible way, and almost certainly would not be observable by users (at least not negatively, since it may indeed fix some bugs along the way).
## Tests
* Test that the lifetime isn't actually captured: `tests/ui/impl-trait/precise-capturing/rpitit.rs` and `tests/ui/impl-trait/precise-capturing/rpitit-outlives.rs` and `tests/ui/impl-trait/precise-capturing/rpitit-outlives-2.rs`.
* Technical test for variance computation: `tests/ui/impl-trait/in-trait/variance.rs`.
* Test that you must capture all trait generics: `tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs`.
* Test that you cannot capture more than what the trait specifies: `tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs` and `tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs`.
* Undercapturing (refinement) lint: `tests/ui/impl-trait/in-trait/refine-captures.rs`.
### What other unstable features may be exposed by this feature?
I don't believe that this exposes any new unstable features indirectly.
## Remaining bugs and open issues
Not aware of any open issues or bugs.
## Tooling support
Rustfmt: :white_check_mark: Supports formatting `+ use<>` everywhere.
Clippy: :white_check_mark: No support needed, unless specific clippy lints are impl'd to care for precise capturing itself.
Rustdoc: :white_check_mark: Rendering `+ use<>` precise capturing bounds is supported.
Rust-analyzer: :white_check_mark: Parser support, and then lifetime support isn't needed https://github.com/rust-lang/rust/pull/138128#issuecomment-2705292494 (previous: ~~:question: There is parser support, but I am unsure of rust-analyzer's level of support for RPITITs in general.~~)
## History
Tracking issue: https://github.com/rust-lang/rust/issues/130044
* https://github.com/rust-lang/rust/pull/131033
* https://github.com/rust-lang/rust/pull/132795
* https://github.com/rust-lang/rust/pull/136554
|
|
|
|
Visitors track whether an assoc item is in a trait impl or an inherent impl
`AssocCtxt::Impl` now contains an `of_trait` field. This allows ast lowering and nameres to not have to track whether we're in a trait impl or an inherent impl.
|
|
|