Rollup of 9 pull requests
Successful merges:
- #106477 (Refine error spans for "The trait bound `T: Trait` is not satisfied" when passing literal structs/tuples)
- #107596 (Add nicer output to PGO build timer)
- #107692 (Sort Generator `print-type-sizes` according to their yield points)
- #107714 (Clarify wording on f64::round() and f32::round())
- #107720 (end entry paragraph with a period (.))
- #107724 (remove unused rustc_* imports)
- #107725 (Turn MarkdownWithToc into a struct with named fields)
- #107731 (interpret: move discriminant reading and writing to separate file)
- #107735 (Add mailmap for commits made by xes@meta.com)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
interpret: move discriminant reading and writing to separate file
This is quite different from the otherwise fairly general read and write functions in place.rs and operand.rs, and also it's nice to have these two functions close together as they are basically inverses of each other.
Clarify wording on f64::round() and f32::round()
"Round half-way cases" is a little confusing (it's a 'garden path sentence' as it's not immediately clear whether round is an adjective or verb).
Make this sentence longer and clearer.
Sort Generator `print-type-sizes` according to their yield points
Especially when trying to diagnose runaway future sizes, it might be more intuitive to sort the variants according to the control flow (aka their yield points) rather than the size of the variants.
Add nicer output to PGO build timer
This PR modifies the timer used in the PGO build script to contain nicer, hierarchical output of the individual build steps. It's not trivial to test locally, so I'll fire up a dist build right away.
r? ``@Mark-Simulacrum``
Refine error spans for "The trait bound `T: Trait` is not satisfied" when passing literal structs/tuples
This PR adds a new heuristic which refines the error span reported for "`T: Trait` is not satisfied" errors, by "drilling down" into individual fields of structs/enums/tuples to point to the "problematic" value.
Here's a self-contained example of the difference in error span:
```rs
struct Burrito<Filling> {
filling: Filling,
}
impl <Filling: Delicious> Delicious for Burrito<Filling> {}
fn eat_delicious_food<Food: Delicious>(food: Food) {}
fn will_type_error() {
eat_delicious_food(Burrito { filling: Kale });
// ^~~~~~~~~~~~~~~~~~~~~~~~~ (before) The trait bound `Kale: Delicious` is not satisfied
// ^~~~ (after) The trait bound `Kale: Delicious` is not satisfied
}
```
(kale is fine, this is just a silly food-based example)
Before this PR, the error span is identified as the entire argument to the generic function `eat_delicious_food`. However, since only `Kale` is the "problematic" part, we can point at it specifically. In particular, the primary error message itself mentions the missing `Kale: Delicious` trait bound, so it's much clearer if this part is called out explicitly.
---
The _existing_ heuristic tries to label the right function argument in `point_at_arg_if_possible`. It goes something like this:
- Look at the broken base trait `Food: Delicious` and find which generics it mentions (in this case, only `Food`)
- Look at the parameter type definitions and find which of them mention `Filling` (in this case, only `food`)
- If there is exactly one relevant parameter, label the corresponding argument with the error span, instead of the entire call
This PR extends this heuristic by further refining the resulting expression span in the new `point_at_specific_expr_if_possible` function. For each `impl` in the (broken) chain, we apply the following strategy:
The strategy to determine this span involves connecting information about our generic `impl`
with information about our (struct) type and the (struct) literal expression:
- Find the `impl` (`impl <Filling: Delicious> Delicious for Burrito<Filling>`)
that links our obligation (`Kale: Delicious`) with the parent obligation (`Burrito<Kale>: Delicious`)
- Find the "original" predicate constraint in the impl (`Filling: Delicious`) which produced our obligation.
- Find all of the generics that are mentioned in the predicate (`Filling`).
- Examine the `Self` type in the `impl`, and see which of its type argument(s) mention any of those generics.
- Examing the definition for the `Self` type, and identify (for each of its variants) if there's a unique field
which uses those generic arguments.
- If there is a unique field mentioning the "blameable" arguments, use that field for the error span.
Before we do any of this logic, we recursively call `point_at_specific_expr_if_possible` on the parent
obligation. Hence we refine the `expr` "outwards-in" and bail at the first kind of expression/impl we don't recognize.
This function returns a `Result<&Expr, &Expr>` - either way, it returns the `Expr` whose span should be
reported as an error. If it is `Ok`, then it means it refined successfull. If it is `Err`, then it may be
only a partial success - but it cannot be refined even further.
---
I added a new test file which exercises this new behavior. A few existing tests were affected, since their error spans are now different. In one case, this leads to a different code suggestion for the autofix - although the new suggestion isn't _wrong_, it is different from what used to be.
This change doesn't create any new errors or remove any existing ones, it just adjusts the spans where they're presented.
---
Some considerations: right now, this check occurs in addition to some similar logic in `adjust_fulfillment_error_for_expr_obligation` function, which tidies up various kinds of error spans (not just trait-fulfillment error). It's possible that this new code would be better integrated into that function (or another one) - but I haven't looked into this yet.
Although this code only occurs when there's a type error, it's definitely not as efficient as possible. In particular, there are definitely some cases where it degrades to quadratic performance (e.g. for a trait `impl` with 100+ generic parameters or 100 levels deep nesting of generic types). I'm not sure if these are realistic enough to worry about optimizing yet.
There's also still a lot of repetition in some of the logic, where the behavior for different types (namely, `struct` vs `enum` variant) is _similar_ but not the same.
---
I think the biggest win here is better targeting for tuples; in particular, if you're using tuples + traits to express variadic-like functions, the compiler can't tell you which part of a tuple has the wrong type, since the span will cover the entire argument. This change allows the individual field in the tuple to be highlighted, as in this example:
```
// NEW
LL | want(Wrapper { value: (3, q) });
| ---- ^ the trait `T3` is not implemented for `Q`
// OLD
LL | want(Wrapper { value: (3, q) });
| ---- ^~~~~~~~~~~~~~~~~~~~~~~~~ the trait `T3` is not implemented for `Q`
```
Especially with large tuples, the existing error spans are not very effective at quickly narrowing down the source of the problem.
Rollup of 5 pull requests
Successful merges:
- #107553 (Suggest std::ptr::null if literal 0 is given to a raw pointer function argument)
- #107580 (Recover from lifetimes with default lifetimes in generic args)
- #107669 (rustdoc: combine duplicate rules in ayu CSS)
- #107685 (Suggest adding a return type for async functions)
- #107687 (Adapt SROA MIR opt for aggregated MIR)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Adapt SROA MIR opt for aggregated MIR
The pass was broken by https://github.com/rust-lang/rust/pull/107267.
This PR extends it to replace:
```
x = Struct { 0: a, 1: b }
y = move? x
```
by assignment between locals
```
x_0 = a
x_1 = b
y_0 = move? x_0
y_1 = move? x_1
```
The improved pass runs to fixpoint, so we can flatten nested field accesses.
Suggest std::ptr::null if literal 0 is given to a raw pointer function argument
Implementation feels a little sus (we're parsing the span for a `0`) but it seems to fall in line the string-expected-found-char condition right above this check, so I think it's fine.
Feedback appreciated on help text? I think it's consistent but it does sound a little awkward maybe?
Fixes#107517
"Round half-way cases" is a little confusing (it's a 'garden path
sentence' as it's not immediately clear whether round is an adjective
or verb).
Make this sentence longer and clearer.
don't point at nonexisting code beyond EOF when warning about delims
Previously we would show this:
```
warning: unnecessary braces around block return value
--> /tmp/bad.rs:1:8
|
1 | fn a(){{{
| ^ ^
|
= note: `#[warn(unused_braces)]` on by default
help: remove these braces
|
1 - fn a(){{{
1 + fn a(){{
|
```
which is now hidden in this case.
We would create a span spanning between the pair of redundant {}s but there is only EOF instead of the `}` so we would previously point at nothing. This would cause the debug assertion ice to trigger. I would have loved to just only point at the second delim and say "you can remove that" but I'm not sure how to do that without refactoring the entire diagnostic which seems tricky. :( But given that this does not seem to regress any other tests we have, I think this edge-casey enough be acceptable.
Fixes https://github.com/rust-lang/rust/issues/107423
r? `@compiler-errors`
Especially when trying to diagnose runaway future sizes, it might be
more intuitive to sort the variants according to the control flow
(aka their yield points) rather than the size of the variants.
Less import overhead for errors
This removes huge (3+ lines) import lists found in files that had their error reporting migrated. These lists are bad for developer workflows as adding, removing, or editing a single error's name might cause a chain reaction that bloats the git diff. As the error struct names are long, the likelihood of such chain reactions is high.
Follows the suggestion by `@Nilstrieb` in the [zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/147480-t-compiler.2Fwg-diagnostics/topic/massive.20use.20statements) to replace the `use errors::{FooErr, BarErr};` with `use errors;` and then changing to `errors::FooErr` on the usage sites.
I have used sed to do most of the changes, i.e. something like:
```
sed -i -E 's/(create_err|create_feature_err|emit_err|create_note|emit_fatal|emit_warning)\(([[:alnum:]]+|[A-Z][[:alnum:]:]*)( \{|\))/\1(errors::\2\3/' path/to/file.rs
```
& then I manually fixed the errors that occured. Most manual changes were required in `compiler/rustc_parse/src/parser/expr.rs`.
r? `@compiler-errors`
emit `ConstEquate` in `TypeRelating<D>`
emitting `ConstEquate` during mir typeck is useful since it can help catch bugs in hir typeck incase our impl of `ConstEquate` is wrong.
doing this did actually catch a bug, when relating `Expr::Call` we `==` the types of all the argument consts which spuriously returns false if the type contains const projections/aliases which causes us to fall through to the `expected_found` error arm.
Generally its an ICE if the `Const`'s `Ty`s arent equal but `ConstKind::Expr` is kind of special since they are sort of like const items that are `const CALL<F: const Fn(...), const N: F>` though we dont actually explicitly represent the `F` type param explicitly in `Expr::Call` so I just made us relate the `Const`'s ty field to avoid getting ICEs from the tests I added and the following existing test:
```rust
// tests/ui/const-generics/generic_const_exprs/different-fn.rs
#![feature(generic_const_exprs)]
#![allow(incomplete_features)]
use std::mem::size_of;
use std::marker::PhantomData;
struct Foo<T>(PhantomData<T>);
fn test<T>() -> [u8; size_of::<T>()] {
[0; size_of::<Foo<T>>()]
//~^ ERROR unconstrained generic constant
//~| ERROR mismatched types
}
fn main() {
test::<u32>();
}
```
which has us relate two `ConstKind::Value` one for the fn item of `size_of::<Foo<T>>` and one for the fn item of `size_of::<T>()`, these only differ by their `Ty` and if we don't relate the `Ty` we'll end up getting an ICE from the checks that ensure the `ty` fields always match.
In theory `Expr::UnOp` has the same problem so I added a call to `relate` for the ty's, although I was unable to create a repro test.