rust/compiler
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
..
rustc Add a new rustc_driver dylib to rexport rustc_driver_impl 2023-02-02 07:34:41 +01:00
rustc_abi PointeeInfo is advisory only 2023-01-31 18:49:03 +01:00
rustc_apfloat compiler: remove unnecessary imports and qualified paths 2022-12-10 18:45:34 +01:00
rustc_arena compiler: remove unnecessary imports and qualified paths 2022-12-10 18:45:34 +01:00
rustc_ast Rollup merge of #107544 - nnethercote:improve-TokenCursor, r=petrochenkov 2023-02-03 23:04:51 +05:30
rustc_ast_lowering Remove HirId -> LocalDefId map from HIR. 2023-01-28 09:55:26 +00:00
rustc_ast_passes Autoderive ExternBlockSuggestion 2023-01-19 13:52:15 +01:00
rustc_ast_pretty Rename rust_2015 => is_rust_2015 2023-02-02 08:17:13 +00:00
rustc_attr Fix uninlined_format_args for some compiler crates 2023-01-05 19:01:12 +01:00
rustc_baked_icu_data Update crate documentation of rustc_baked_icu_data crate 2022-11-18 14:46:36 -08:00
rustc_borrowck Rollup merge of #107646 - estebank:specific-span, r=compiler-errors 2023-02-04 20:29:06 +01:00
rustc_builtin_macros Don't generate unecessary &&self.field in deriving Debug 2023-02-02 22:06:23 +00:00
rustc_codegen_cranelift Auto merge of #106227 - bryangarza:ctfe-limit, r=oli-obk 2023-01-29 04:11:27 +00:00
rustc_codegen_gcc session: diagnostic migration lint on more fns 2023-01-30 17:11:35 +00:00
rustc_codegen_llvm Rollup merge of #107412 - tshepang:needless-check, r=wesleywiser 2023-01-31 23:38:51 +01:00
rustc_codegen_ssa Auto merge of #107267 - cjgillot:keep-aggregate, r=oli-obk 2023-02-04 15:17:32 +00:00
rustc_const_eval rustc_const_eval: remove huge error imports 2023-02-05 03:47:48 +01:00
rustc_data_structures Disallow impl autotrait for trait object 2023-02-03 08:33:40 -08:00
rustc_driver Remove unneeded extern crate 2023-02-02 07:47:39 +01:00
rustc_driver_impl Add a new rustc_driver dylib to rexport rustc_driver_impl 2023-02-02 07:34:41 +01:00
rustc_error_codes make unaligned_reference a hard error 2023-01-31 20:28:11 +01:00
rustc_error_messages Auto merge of #107727 - Dylan-DPC:rollup-b1yexcl, r=Dylan-DPC 2023-02-06 16:28:18 +00:00
rustc_errors Make "use latest edition" subdiagnostic translatable 2023-02-01 21:56:28 +01:00
rustc_expand rustc_expand: remove huge error imports 2023-02-05 03:47:22 +01:00
rustc_feature Auto merge of #107297 - Mark-Simulacrum:bump-bootstrap, r=pietroalbini 2023-01-31 19:24:29 +00:00
rustc_fs_util Remove useless borrows and derefs 2022-12-01 17:34:43 +00:00
rustc_graphviz Fix uninlined_format_args for some compiler crates 2023-01-05 19:01:12 +01:00
rustc_hir Rollup merge of #107125 - WaffleLapkin:expect_an_item_in_your_hir_by_the_next_morning, r=Nilstrieb 2023-01-30 17:50:08 +01:00
rustc_hir_analysis Make const/fn return params more suggestable 2023-02-03 21:37:41 +00:00
rustc_hir_pretty Use Mutability::{is_mut, is_not} 2023-01-30 12:26:26 +00:00
rustc_hir_typeck Rollup merge of #106477 - Nathan-Fenner:nathanf/refined-error-span-trait-impl, r=compiler-errors 2023-02-06 21:16:39 +01:00
rustc_incremental incremental: migrate diagnostics 2023-01-30 17:11:35 +00:00
rustc_index Fix IndexVec::drain_enumerated 2023-01-19 15:25:33 +00:00
rustc_infer Rollup merge of #106477 - Nathan-Fenner:nathanf/refined-error-span-trait-impl, r=compiler-errors 2023-02-06 21:16:39 +01:00
rustc_interface rustc_interface: remove huge error imports 2023-02-05 03:48:08 +01:00
rustc_lexer Remove double spaces after dots in comments 2023-01-17 08:09:33 +00:00
rustc_lint Auto merge of #103761 - chenyukang:yukang/fix-103320-must-use, r=compiler-errors 2023-02-06 12:57:37 +00:00
rustc_lint_defs make unaligned_reference a hard error 2023-01-31 20:28:11 +01:00
rustc_llvm llvm-wrapper: adapt for LLVM API changes 2023-02-02 10:09:48 +00:00
rustc_log Add log-backtrace option to show backtraces along with logging 2023-01-12 00:17:48 +09:00
rustc_macros Forbid #[suggestion_*(...)] on Vecs 2023-02-01 21:49:45 +01:00
rustc_metadata rustc_metadata: remove huge error imports 2023-02-05 03:47:38 +01:00
rustc_middle Rollup merge of #106477 - Nathan-Fenner:nathanf/refined-error-span-trait-impl, r=compiler-errors 2023-02-06 21:16:39 +01:00
rustc_mir_build Put a DefId in AggregateKind. 2023-02-02 23:09:51 +00:00
rustc_mir_dataflow Run SROA to fixpoint. 2023-02-05 12:08:42 +00:00
rustc_mir_transform Simplify ReplacementMap. 2023-02-05 13:41:24 +00:00
rustc_monomorphize Auto merge of #100754 - davidtwco:translation-incremental, r=compiler-errors 2023-01-31 10:20:58 +00:00
rustc_parse Rollup merge of #107580 - lenko-d:default_value_for_a_lifetime_generic_parameter_produces_confusing_diagnostic, r=compiler-errors 2023-02-06 19:54:14 +05:30
rustc_parse_format Rollup merge of #106805 - madsravn:master, r=compiler-errors 2023-02-03 06:30:23 +01:00
rustc_passes rustc_passes: remove huge error imports 2023-02-05 03:47:58 +01:00
rustc_plugin_impl
rustc_privacy Remove HirId -> LocalDefId map from HIR. 2023-01-28 09:55:26 +00:00
rustc_query_impl Don't cause a cycle when formatting query description that references a FnDef 2023-02-02 05:49:07 +00:00
rustc_query_system Support parallel compiler. 2023-02-04 15:56:50 +00:00
rustc_resolve Rename rust_2015 => is_rust_2015 2023-02-02 08:17:13 +00:00
rustc_save_analysis Review changes 2023-01-31 07:54:01 +00:00
rustc_serialize compiler: remove unnecessary imports and qualified paths 2022-12-10 18:45:34 +01:00
rustc_session rustc_session: remove huge error imports 2023-02-05 04:01:20 +01:00
rustc_smir
rustc_span Rename rust_2015 => is_rust_2015 2023-02-02 08:17:13 +00:00
rustc_symbol_mangling Introduce GeneratorWitnessMIR. 2023-01-27 18:58:44 +00:00
rustc_target Auto merge of #106925 - imWildCat:imWildCat/remove-hardcoded-ios-macbi-target-version, r=wesleywiser 2023-02-02 05:26:09 +00:00
rustc_trait_selection Rollup merge of #106477 - Nathan-Fenner:nathanf/refined-error-span-trait-impl, r=compiler-errors 2023-02-06 21:16:39 +01:00
rustc_traits Track bound types like bound regions 2023-01-30 22:18:20 +00:00
rustc_transmute Also remove #![feature(control_flow_enum)] where possible 2023-01-18 10:22:21 -08:00
rustc_ty_utils Extend -Z print-type-sizes to distinguish generator upvars and locals from "normal" ADT fields. 2023-01-31 15:59:29 -05:00
rustc_type_ir Separate witness type computation from the generator transform. 2023-01-27 19:00:26 +00:00