`-Zhigher-ranked-assumptions`: Consider WF of coroutine witness when proving outlives assumptions
### TL;DR
This PR introduces an unstable flag `-Zhigher-ranked-assumptions` which tests out a new algorithm for dealing with some of the higher-ranked outlives problems that come from auto trait bounds on coroutines. See:
* rust-lang/rust#110338
While it doesn't fix all of the issues, it certainly fixed many of them, so I'd like to get this landed so people can test the flag on their own code.
### Background
Consider, for example:
```rust
use std::future::Future;
trait Client {
type Connecting<'a>: Future + Send
where
Self: 'a;
fn connect(&self) -> Self::Connecting<'_>;
}
fn call_connect<C>(c: C) -> impl Future + Send
where
C: Client + Send + Sync,
{
async move { c.connect().await }
}
```
Due to the fact that we erase the lifetimes in a coroutine, we can think of the interior type of the async block as something like: `exists<'r, 's> { C, &'r C, C::Connecting<'s> }`. The first field is the `c` we capture, the second is the auto-ref that we perform on the call to `.connect()`, and the third is the resulting future we're awaiting at the first and only await point. Note that every region is uniquified differently in the interior types.
For the async block to be `Send`, we must prove that both of the interior types are `Send`. First, we have an `exists<'r, 's>` binder, which needs to be instantiated universally since we treat the regions in this binder as *unknown*[^exist]. This gives us two types: `{ &'!r C, C::Connecting<'!s> }`. Proving `&'!r C: Send` is easy due to a [`Send`](https://doc.rust-lang.org/nightly/std/marker/trait.Send.html#impl-Send-for-%26T) impl for references.
Proving `C::Connecting<'!s>: Send` can only be done via the item bound, which then requires `C: '!s` to hold (due to the `where Self: 'a` on the associated type definition). Unfortunately, we don't know that `C: '!s` since we stripped away any relationship between the interior type and the param `C`. This leads to a bogus borrow checker error today!
### Approach
Coroutine interiors are well-formed by virtue of them being borrow-checked, as long as their callers are invoking their parent functions in a well-formed way, then substitutions should also be well-formed. Therefore, in our example above, we should be able to deduce the assumption that `C: '!s` holds from the well-formedness of the interior type `C::Connecting<'!s>`.
This PR introduces the notion of *coroutine assumptions*, which are the outlives assumptions that we can assume hold due to the well-formedness of a coroutine's interior types. These are computed alongside the coroutine types in the `CoroutineWitnessTypes` struct. When we instantiate the binder when proving an auto trait for a coroutine, we instantiate the `CoroutineWitnessTypes` and stash these newly instantiated assumptions in the region storage in the `InferCtxt`. Later on in lexical region resolution or MIR borrowck, we use these registered assumptions to discharge any placeholder outlives obligations that we would otherwise not be able to prove.
### How well does it work?
I've added a ton of tests of different reported situations that users have shared on issues like rust-lang/rust#110338, and an (anecdotally) large number of those examples end up working straight out of the box! Some limitations are described below.
### How badly does it not work?
The behavior today is quite rudimentary, since we currently discharge the placeholder assumptions pretty early in region resolution. This manifests itself as some limitations on the code that we accept.
For example, `tests/ui/async-await/higher-ranked-auto-trait-11.rs` continues to fail. In that test, we must prove that a placeholder is equal to a universal for a param-env candidate to hold when proving an auto trait, e.g. `'!1 = 'a` is required to prove `T: Trait<'!1>` in a param-env that has `T: Trait<'a>`. Unfortunately, at that point in the MIR body, we only know that the placeholder is equal to some body-local existential NLL var `'?2`, which only gets equated to the universal `'a` when being stored into the return local later on in MIR borrowck.
This could be fixed by integrating these assumptions into the type outlives machinery in a more first-class way, and delaying things to the end of MIR typeck when we know the full relationship between existential and universal NLL vars. Doing this integration today is quite difficult today.
`tests/ui/async-await/higher-ranked-auto-trait-11.rs` fails because we don't compute the full transitive outlives relations between placeholders. In that test, we have in our region assumptions that some `'!1 = '!2` and `'!2 = '!3`, but we must prove `'!1 = '!3`.
This can be fixed by computing the set of coroutine outlives assumptions in a more transitive way, or as I mentioned above, integrating these assumptions into the type outlives machinery in a more first-class way, since it's already responsible for the transitive outlives assumptions of universals.
### Moving forward
I'm still quite happy with this implementation, and I'd like to land it for testing. I may work on overhauling both the way we compute these coroutine assumptions and also how we deal with the assumptions during (lexical/nll) region checking. But for now, I'd like to give users a chance to try out this new `-Zhigher-ranked-assumptions` flag to uncover more shortcomings.
[^exist]: Instantiating this binder with infer regions would be incomplete, since we'd be asking for *some* instantiation of the interior types, not proving something for *all* instantiations of the interior types.
Unify `CoroutineWitness` sooner in typeck, and stall coroutine obligations based off of `TypingEnv`
* Stall coroutine obligations based off of `TypingMode` in the old solver.
* Eagerly assign `TyKind::CoroutineWitness` to the witness arg of coroutines during typeck, rather than deferring them to the end of typeck.
r? lcnr
This is part of https://github.com/rust-lang/rust/issues/143017.
Rollup of 11 pull requests
Successful merges:
- rust-lang/rust#143326 (Remove deprecated `Error::description` impl from `c_str::FromBytesWithNulError`)
- rust-lang/rust#143431 (Use relative visibility when noting sealed trait to reduce false positive)
- rust-lang/rust#143550 (resolve: Use interior mutability for extern module map)
- rust-lang/rust#143631 (update to literal-escaper-0.0.5)
- rust-lang/rust#143793 (Opaque type collection: Guard against endlessly recursing free alias types)
- rust-lang/rust#143880 (tests: Test line debuginfo for linebreaked function parameters)
- rust-lang/rust#143914 (Reword mismatched-lifetime-syntaxes text based on feedback)
- rust-lang/rust#143926 (Remove deprecated fields in bootstrap)
- rust-lang/rust#143955 (Make frame spans appear on a separate trace line)
- rust-lang/rust#143975 (type_id_eq: check that the hash fully matches the type)
- rust-lang/rust#143984 (Fix ice for feature-gated `cfg` attributes applied to the crate)
r? `@ghost`
`@rustbot` modify labels: rollup
Fix ice for feature-gated `cfg` attributes applied to the crate
This PR fixes two fixes:
1. When a feature gated option of the `cfg` attribute is applied to the crate, an ICE would occur because features are not yet available at that stage. This is fixed by ignoring the feature gate at that point, the attribute will later be re-checked (this was already done) when the feature gate is available. Fixes https://github.com/rust-lang/rust/issues/143977
2. Errors and lints on the `cfg` attribute applied to the crate would be produced twice, because of the re-checking. This is fixed by not producing any errors and lints during the first run.
The added regression test checks both problems.
r? ``@jdonszelmann``
type_id_eq: check that the hash fully matches the type
The previous logic wouldn't always detect when the hash mismatches the provenance. Fix that by adding a new helper, `read_type_id`, that reads a single type ID while fully checking it for validity and consistency.
r? ``@oli-obk``
Reword mismatched-lifetime-syntaxes text based on feedback
Key changes include:
- Removal of the word "syntax" from the lint message. More accurately, it could have been something like "syntax group" or "syntax category", but avoiding it completely is easier.
- The primary lint message now reflects exactly which mismatch is occurring, instead of trying to be general. A new `help` line is general across the mismatch kinds.
- Suggestions have been reduced to be more minimal, no longer also changing non-idiomatic but unrelated aspects.
- Suggestion text no longer mentions changes when those changes don't occur in that specific suggestion.
r? ``@jieyouxu``
Opaque type collection: Guard against endlessly recursing free alias types
See test description for technical details.
Fixes https://github.com/rust-lang/rust/issues/131994.
r? oli-obk (sry, your queue is large, so no rush & feel free to reassign)
Use relative visibility when noting sealed trait to reduce false positive
Fixesrust-lang/rust#143392
I used relative visibility instead of just determining if it's public or not.
r? compiler
Only inherit local hash for paths
`DefPathHash`, as the counterpart of `DefId` that is stable across compiler invocations, is comprised of 2 parts. The first one is the `StableCrateId`, stable form of `CrateNum`. The second is 64 complementary bits to identify the crate-local definition.
The current implementation always hashes the full 128 bits when (1) trying to create a new child `DefPathHash` or (2) hashing a `CrateNum` or a `LocalDefId`. But we only need half that information: `LocalDefId` means that the `StableCrateId` is always the current crate's ; `CrateNum` means that we do not care about the local part.
As stable hashing is very hot in the query system, in particular hashing definitions, this is a big deal.
We still want the local part to change when the `StableCrateId` changes, to make incr-compilation errors less painful, ie. increase the likelihood that if will magically disappear by changing some code.
This PR sprinkles some `#[inline]` attributes on small functions that appeared in profiles.
trait_sel: `MetaSized` always holds temporarily
As a temporary measure while a proper fix for `tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs` is implemented, make `MetaSized` obligations always hold. In effect, temporarily reverting the `sized_hierarchy` feature. This is a small change that can be backported.
cc rust-lang/rust#143992
r? ```@lcnr```
Dont collect assoc ty item bounds from trait where clause for host effect predicates
For background, we uplift `where Self::Assoc: Trait` bounds in a trait's where clauses into *item bounds* on `type Assoc;`. This is because before we *had* syntactical item bounds, users would express their item bounds like so.
Let's opt out of doing this same behavior for `HostEffect` predicates like `where Self::Assoc: [const] Trait`. I left a comment in the code:
```rust
// FIXME(const_trait_impl): We *could* uplift the
// `where Self::Assoc: [const] Trait` bounds from the parent trait
// here too, but we'd need to split `const_conditions` into two
// queries (like we do for `trait_explicit_predicates_and_bounds`)
// since we need to also filter the predicates *out* of the const
// conditions or they lead to cycles in the trait solver when
// utilizing these bounds. For now, let's do nothing.
```
As an aside, this was an ICE that was only triggerable when building libraries and not binaries because we never were calling `tcx.ensure_ok().explicit_implied_const_bounds(def_id);` on associated types like we should have been. I adjusted the calls to `ensure_ok` to make sure this happens, so we catch bugs like this in the future more easily.
As another aside, I fixed the bound uplifting logic for *always const* predicates, since those act like normal clauses and have no notion of conditional constness.
r? ```@oli-obk``` ```@fee1-dead``` or anyone really
Fixesrust-lang/rust#133275
Linting public reexport of private dependencies
Part of public/private dependencies rust-lang/rust#44663
Partially addresses rust-lang/rust#71043
I'm adding a warning for reexports of private dependencies into `rustc_resolve`. I get that this should not be a warning, but should instead be a lint to be controlled by the feature gate, but I did not figure out how exactly to do that at that point. I tried doing the same thing as is done in `rustc_privacy`, but the linting system is not ready yet as far as I understand the error I got, so I made a warning for now instead. Some guidance on how to emit lints with `dcx` would be appreciated.
This also sets the `std_detect` crate as a public dependency of `std` because some macros are reexported from there. I did not check closer, but the other option may be to allow the specific reexports instead.
Added error for invalid char cast
fixesrust-lang/rust#143597
not really sure if I did it right, but according to cast-char test -- it is right, also this code gave me false positive result
```
for _ in 0..(256 as u8) {}
```
so this is why I added this check `if lit_val <= 0xFF`
Also I believe that error message could be improved, but I'm not sure how exactly
cc ```@hkBst```
r? compiler
Implement unstable trait impl
This PR allows marking impls of stable trait with stable type as unstable.
## Approach
In std/core, an impl can be marked as unstable by annotating it with ``#[unstable_feature_bound(feat_name)]``. This will add a ``ClauseKind::Unstable_Feature(feat_name)`` to the list of predicates in ``predicates_of`` .
When an unstable impl's function is called, we will first iterate through all the goals in ``param_env`` to check if there is any ``ClauseKind::UnstableFeature(feat_name)`` in ``param_env``.
The existence of ``ClauseKind::Unstable_Feature(feat_name)`` in ``param_env`` means an``#[unstable_feature_bound(feat_name)]`` is present at the call site of the function, so we allow the check to succeed in this case.
If ``ClauseKind::UnstableFeature(feat_name)`` does not exist in ``param_env``, we will still allow the check to succeed for either of the cases below:
1. The feature is enabled through ``#[feature(feat_name)]`` outside of std / core.
2. We are in codegen because we may be monomorphizing a body from an upstream crate which had an unstable feature enabled that the downstream crate do not.
For the rest of the case, it will fail with ambiguity.
## Limitation
In this PR, we do not support:
1. using items that need ``#[unstable_feature_bound]`` within stable APIs
2. annotate main function with ``#[unstable_feature_bound]``
3. annotate ``#[unstable_feature_bound]`` on items other than free function and impl
## Acknowledgement
The design and mentoring are done by `@BoxyUwU`
There are many places that join path segments with `::` to produce a
string. A lot of these use `join("::")`. Many in rustdoc use
`join_with_double_colon`, and a few use `.joined("..")`. One in Clippy
uses `itertools::join`. A couple of them look for `kw::PathRoot` in the
first segment, which can be important.
This commit introduces `rustc_ast::join_path_{syms,ident}` to do the
joining for everyone. `rustc_ast` is as good a location for these as
any, being the earliest-running of the several crates with a `Path`
type. Two functions are needed because `Ident` printing is more complex
than simple `Symbol` printing.
The commit also removes `join_with_double_colon`, and
`estimate_item_path_byte_length` with it.
There are still a handful of places that join strings with "::" that are
unchanged. They are not that important: some of them are in tests, and
some of them first split a path around "::" and then rejoin with "::".
This fixes one test case where `{{root}}` shows up in an error message.
Constify `Index` traits
tracking issue: rust-lang/rust#143775
the `SliceIndex` trait cannot be implemented by users as it is sealed. While it would be useful for the `get` method on slices, it seems weird to have a feature gate for that that isn't also gating index syntax at the same time, so I put them under the same feature gate.
r? ```````@fee1-dead```````
rustdoc-json: Structured attributes
Implements and closesrust-lang/rust#141358.
This has 2 primary benefits.
1. For rustdoc-json consumers, they no longer need to parse strings of attributes, but it's there in a structured and normalized way. CC ```@obi1kenobi```
2. For rustc conributors, the output of HIR pretty printing is no longer a versioned thing in the output. People can work on rust-lang/rust#131229 without needing to bump `FORMAT_VERSION`. CC ```@jdonszelmann``` ```@JonathanBrouwer.```
(Over time, as the attribute refractor continues, I expect we'll add new things to `rustdoc_json_types::Attribute`. But this can be done separately to the rustc changes).
Todo before being mergable:
- [x] Update test assertions.
- [x] Fix modeling of `#[repr]`.
- [ ] ~~Add tests of `#[doc(hidden)]` in `Item::attrs` (probably in a seperate PR).~~ I'm gonna punt this to a future PR
- [x] Documentation.
As a temporary measure while a proper fix for
`tests/ui/sized-hierarchy/incomplete-inference-issue-143992.rs`
is implemented, make `MetaSized` obligations always hold. In effect,
temporarily reverting the `sized_hierarchy` feature. This is a small
change that can be backported.
Implements https://www.github.com/rust-lang/rust/issues/141358.
This has 2 primary benefits:
1. For rustdoc-json consumers, they no longer need to parse strings of
attributes, but it's there in a structured and normalized way.
2. For rustc contributors, the output of HIR pretty printing is no
longer a versioned thing in the output. People can work on
https://github.com/rust-lang/rust/issues/131229 without needing to
bump `FORMAT_VERSION`.
(Over time, as the attribute refractor continues, I expect we'll add new
things to `rustdoc_json_types::Attribute`. But this can be done
separately to the rustc changes).
`std::vec`: Add UB check for `set_len`, `from_raw_parts_in`, and etc.
Closesrust-lang/rust#143813
I noticed that `from_parts_in` do the similar things like `from_raw_parts_in`, so I add the UB check in the last commit. If it is not appropriate, I will remove it.
And I fix a typo in the first commit.
r? `@scottmcm`
update `cfg_select!` documentation
tracking issue: https://github.com/rust-lang/rust/issues/115585
After rust-lang/rust#143461, and with an eye on a soon(ish) stabilization, I think the docs need some work.
The existing text read more like a motivation for the feature existing to me, so I've tried to now be a bit more descriptive. Still, suggestions are very welcome.
I also added a test for an empty `select! {}` because it's just the sort of thing that might break.
r? ``@traviscross``
Preserve constness in trait objects up to hir ty lowering
r? ``@compiler-errors``
While we don't support `dyn const Trait`, we can at least also inform the user that `const Trait` is only legal for `#[const_trait] trait Trait {}`
Adjust `run_make_support::symbols` helpers
Massage the `symbols` helpers to fill out {match all, match any} x {substring match, exact match}:
| | Substring match | Exact match |
|-----------|----------------------------------------|-------------------------------|
| Match any | `object_contains_any_symbol_substring` | `object_contains_any_symbol` |
| Match all | `object_contains_all_symbol_substring` | `object_contains_all_symbols` |
As I'd like to use `object_contains_all_symbols` for rust-lang/rust#143669.
As part of this:
- Rename `any_symbol_contains` to `object_contains_any_symbol_substring` for accuracy, as `any_symbol_contains` is actually "contains any matching substring".
- Remove `with_symbol_iter`.
Noticed while working on https://github.com/rust-lang/rust/pull/143669.
r? ``@ChrisDenton`` (or compiler)