rust/tests/ui/traits
Matthias Krüger 800221b5b8
Rollup merge of #106477 - Nathan-Fenner:nathanf/refined-error-span-trait-impl, r=compiler-errors
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.
2023-02-06 21:16:39 +01:00
..
alias Add regression test for #60755 2023-01-27 19:46:56 +09:00
associated_type_bound Tweak E0597 2023-01-15 19:46:20 +00:00
auxiliary
bound Only point at impl self ty in WF if trait predicate shares self ty 2023-01-12 22:25:30 +00:00
default-method
inductive-overflow
inheritance
negative-impls Point at specific field in struct literal when trait fulfillment fails 2023-01-23 13:37:58 -08:00
new-solver Trait upcasting support in new solver 2023-01-30 19:11:01 +00:00
object
reservation-impl
solver-cycles
suggest-deferences
trait-upcasting Reintroduce multiple_supertrait_upcastable lint 2023-01-28 15:08:07 +00:00
vtable Tweak E0597 2023-01-15 19:46:20 +00:00
wf-object
alignment-gep-tup-like-1.rs
anon_trait_static_method_exe.rs
anon-static-method.rs
as-struct-constructor.rs
as-struct-constructor.stderr
assignability-trait.rs
assoc-type-in-superbad.rs
assoc-type-in-superbad.stderr
assoc-type-in-supertrait.rs
astconv-cycle-between-and-type.rs
augmented-assignments-trait.rs
bad-method-typaram-kind.rs
bad-method-typaram-kind.stderr
bad-sized.rs
bad-sized.stderr
bug-7183-generics.rs
bug-7295.rs
cache-issue-18209.rs
cache-reached-depth-ice.rs
cache-reached-depth-ice.stderr
coercion-generic-bad.rs
coercion-generic-bad.stderr
coercion-generic-regions.rs
coercion-generic-regions.stderr Tweak E0597 2023-01-15 19:46:20 +00:00
coercion-generic.rs
coercion.rs
composition-trivial.rs
conditional-dispatch.rs
conditional-model-fn.rs
conservative_impl_trait.rs
copy-guessing.rs
copy-impl-cannot-normalize.rs
copy-impl-cannot-normalize.stderr Delay normalization bugs instead of reporting them 2023-01-13 23:19:36 +00:00
copy-is-not-modulo-regions.not_static.stderr Rebase and move UI tests 2023-01-13 23:06:29 +00:00
copy-is-not-modulo-regions.rs Rebase and move UI tests 2023-01-13 23:06:29 +00:00
copy-requires-self-wf.rs Rebase and move UI tests 2023-01-13 23:06:29 +00:00
cycle-cache-err-60010.rs
cycle-cache-err-60010.stderr
cycle-generic-bound.rs
cycle-type-trait.rs
do-not-mention-type-params-by-name-in-suggestion-issue-96292.rs
do-not-mention-type-params-by-name-in-suggestion-issue-96292.stderr
duplicate-methods.rs
duplicate-methods.stderr
dyn-trait.rs
early-vtbl-resolution.rs
elaborate-type-region.rs
false-ambiguity-where-clause-builtin-bound.rs
fmt-pointer-trait.rs
fn-trait-cast-diagnostic.rs Add note when FnPtr vs. FnDef impl trait 2023-01-14 10:37:56 +00:00
fn-trait-cast-diagnostic.stderr Add note when FnPtr vs. FnDef impl trait 2023-01-14 10:37:56 +00:00
generic.rs
ignore-err-impls.rs Filter impl and where-clause candidates that reference errors 2023-01-11 20:03:29 +00:00
ignore-err-impls.stderr Render missing generics suggestion verbosely 2023-01-12 22:04:30 +00:00
impl_trait_as_trait_return_position.rs
impl-1.rs
impl-1.stderr
impl-2.rs
impl-bounds-checking.rs
impl-bounds-checking.stderr Point at impl self type for impl wf obligations 2023-01-12 20:44:47 +00:00
impl-can-not-have-untraitful-items.rs
impl-can-not-have-untraitful-items.stderr
impl-different-num-params.rs
impl-different-num-params.stderr
impl-evaluation-order.rs
impl-for-module.rs
impl-for-module.stderr
impl-implicit-trait.rs
impl-inherent-prefer-over-trait.rs
impl-method-mismatch.rs
impl-method-mismatch.stderr
impl-object-overlap-issue-23853.rs
impl-of-supertrait-has-wrong-lifetime-parameters.rs
impl-of-supertrait-has-wrong-lifetime-parameters.stderr Point at impl self type for impl wf obligations 2023-01-12 20:44:47 +00:00
impl.rs
infer-from-object-issue-26952.rs
inherent-method-order.rs
invalid_operator_trait.rs
invalid_operator_trait.stderr
issue-3683.rs
issue-3973.rs
issue-3973.stderr
issue-4107.rs
issue-6128.rs
issue-6334.rs
issue-7013.rs
issue-7013.stderr
issue-8153.rs
issue-8153.stderr
issue-9394-inherited-calls.rs
issue-18400.rs
issue-18400.stderr
issue-18412.rs
issue-20692.rs
issue-20692.stderr
issue-22019.rs
issue-22110.rs
issue-22655.rs
issue-23003-overflow.rs
issue-23003.rs
issue-23825.rs
issue-24010.rs
issue-26339.rs
issue-28576.rs
issue-28576.stderr
issue-32963.rs
issue-32963.stderr
issue-33140-hack-boundaries.rs
issue-33140-hack-boundaries.stderr
issue-33140.rs
issue-33140.stderr
issue-35869.rs
issue-35869.stderr
issue-38033.rs
issue-38404.rs
issue-38404.stderr
issue-38604.rs
issue-38604.stderr
issue-43132.rs
issue-43784-supertrait.rs
issue-43784-supertrait.stderr Keep obligation chain when elaborating obligations 2023-01-13 18:20:23 +00:00
issue-50480.rs Delay normalization bugs instead of reporting them 2023-01-13 23:19:36 +00:00
issue-50480.stderr Delay normalization bugs instead of reporting them 2023-01-13 23:19:36 +00:00
issue-52893.rs
issue-52893.stderr Modify primary span label for E0308 2023-01-30 20:12:19 +00:00
issue-56202.rs
issue-56488.rs
issue-59029-1.rs
issue-59029-1.stderr
issue-59029-2.rs
issue-65284-suggest-generic-trait-bound.rs
issue-65284-suggest-generic-trait-bound.stderr
issue-65673.rs
issue-65673.stderr
issue-68295.rs
issue-68295.stderr Modify primary span label for E0308 2023-01-30 20:12:19 +00:00
issue-70944.rs
issue-71036.rs
issue-71036.stderr
issue-71136.rs
issue-71136.stderr
issue-72410.rs
issue-72410.stderr
issue-72455.rs
issue-75627.rs
issue-75627.stderr Render missing generics suggestion verbosely 2023-01-12 22:04:30 +00:00
issue-77982.rs
issue-77982.stderr
issue-78372.rs
issue-78372.stderr Render missing generics suggestion verbosely 2023-01-12 22:04:30 +00:00
issue-78632.rs
issue-79458.rs
issue-79458.stderr
issue-82830.rs
issue-83538-tainted-cache-after-cycle.rs
issue-83538-tainted-cache-after-cycle.stderr
issue-84399-bad-fresh-caching.rs
issue-85360-eval-obligation-ice.rs
issue-85360-eval-obligation-ice.stderr
issue-85735.rs
issue-85735.stderr
issue-87558.rs
issue-87558.stderr
issue-89119.rs
issue-90195-2.rs
issue-90195.rs
issue-90662-projection-caching.rs
issue-91594.rs
issue-91594.stderr Point at HIR types when impl trait ref doesn't normalize 2023-01-12 20:44:47 +00:00
issue-91949-hangs-on-recursion.rs
issue-91949-hangs-on-recursion.stderr
issue-92292.rs
issue-95311.rs
issue-95898.rs
issue-95898.stderr
issue-96664.rs
issue-96665.rs
issue-97576.rs
issue-97576.stderr
issue-97695-double-trivial-bound.rs
issue-99875.rs
issue-99875.stderr Add note when FnPtr vs. FnDef impl trait 2023-01-14 10:37:56 +00:00
issue-102989.rs
issue-102989.stderr
issue-104322.rs
issue-106072.rs fix: misleading add dyn to derive macro suggestion 2023-01-14 12:14:06 +00:00
issue-106072.stderr fix: misleading add dyn to derive macro suggestion 2023-01-14 12:14:06 +00:00
item-inside-macro.rs
item-privacy.rs
item-privacy.stderr When suggesting writing a fully qualified path probe for appropriate types 2023-01-11 21:30:10 +00:00
kindck-owned-contains-1.rs
map-types.rs
map-types.stderr
matching-lifetimes.rs
matching-lifetimes.stderr
method-private.rs
method-private.stderr
monad.rs
monomorphized-callees-with-ty-params-3314.rs
multidispatch1.rs
multidispatch2.rs
multidispatch-bad.rs
multidispatch-bad.stderr
multidispatch-conditional-impl-not-considered.rs
multidispatch-convert-ambig-dest.rs
multidispatch-convert-ambig-dest.stderr
multidispatch-infer-convert-target.rs
mutual-recursion-issue-75860.rs
mutual-recursion-issue-75860.stderr
no_send-struct.rs
no_send-struct.stderr
no-fallback-multiple-impls.rs
no-fallback-multiple-impls.stderr
normalize-supertrait.rs
not-suggest-non-existing-fully-qualified-path.rs
not-suggest-non-existing-fully-qualified-path.stderr
object-does-not-impl-trait.rs
object-does-not-impl-trait.stderr
object-one-type-two-traits.rs
objects-owned-object-borrowed-method-headerless.rs
operator-overloading-issue-52025.rs
overlap-not-permitted-for-builtin-trait.rs
overlap-not-permitted-for-builtin-trait.stderr
overlap-permitted-for-marker-traits.rs
param-without-lifetime-constraint.rs
param-without-lifetime-constraint.stderr
parameterized-with-bounds.rs
pointee-deduction.rs
pointee-tail-is-generic-errors.rs
pointee-tail-is-generic-errors.stderr
pointee-tail-is-generic.rs
principal-less-objects.rs
privacy.rs
project-modulo-regions.rs
project-modulo-regions.with_clause.stderr
project-modulo-regions.without_clause.stderr
region-pointer-simple.rs
resolution-in-overloaded-op.rs
resolution-in-overloaded-op.stderr
safety-fn-body.mir.stderr
safety-fn-body.rs
safety-fn-body.thir.stderr
safety-inherent-impl.rs
safety-inherent-impl.stderr
safety-ok-cc.rs
safety-ok.rs
safety-trait-impl-cc.rs
safety-trait-impl-cc.stderr
safety-trait-impl.rs
safety-trait-impl.stderr
self-without-lifetime-constraint.rs
self-without-lifetime-constraint.stderr
static-method-generic-inference.rs
static-method-generic-inference.stderr
static-method-overwriting.rs
static-outlives-a-where-clause.rs
staticness-mismatch.rs
staticness-mismatch.stderr
suggest-fully-qualified-closure.rs
suggest-fully-qualified-closure.stderr
suggest-fully-qualified-path-with-adjustment.rs
suggest-fully-qualified-path-with-adjustment.stderr
suggest-fully-qualified-path-without-adjustment.rs
suggest-fully-qualified-path-without-adjustment.stderr
suggest-where-clause.rs
suggest-where-clause.stderr
superdefault-generics.rs
syntax-polarity.rs
syntax-trait-polarity.rs
syntax-trait-polarity.stderr
test-2.rs
test-2.stderr
test.rs
test.stderr
to-str.rs
track-obligations.rs Add tests 2023-01-13 18:20:24 +00:00
track-obligations.stderr Add tests 2023-01-13 18:20:24 +00:00
trait-or-new-type-instead.rs
trait-or-new-type-instead.stderr
typeclasses-eq-example-static.rs
typeclasses-eq-example.rs
ufcs-object.rs
unspecified-self-in-trait-ref.rs
unspecified-self-in-trait-ref.stderr
use-before-def.rs
vtable-res-trait-param.rs
vtable-res-trait-param.stderr
where-clause-vs-impl.rs
with-bounds-default.rs
with-dst.rs