From 64bc975d27f86aaa1d3d94921c9c042477b4e88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 6 Dec 2022 12:08:17 -0800 Subject: [PATCH] Mention only assoc types changes --- .../src/traits/error_reporting/suggestions.rs | 96 +++++++++++++------ src/test/ui/issues/issue-34334.stderr | 6 +- ...e-66923-show-error-for-correct-call.stderr | 4 +- .../iterators/invalid-iterator-chain.stderr | 38 ++++---- 4 files changed, 92 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 8bfa405cbea..2f9b8c21071 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2865,11 +2865,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - let span = expr.span; - let mut multi_span: MultiSpan = match expr.kind { - hir::ExprKind::MethodCall(_, _, _, span) => span.into(), - _ => span.into(), - }; + let mut primary_spans = vec![]; + let mut span_labels = vec![]; // FIXME: visit the ty to see if there's any closure involved, and if there is, // check whether its evaluated return type is the same as the one corresponding @@ -2897,12 +2894,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } let point_at_chain = |expr: &hir::Expr<'_>| { + let mut assocs = vec![]; + // We still want to point at the different methods even if there hasn't + // been a change of assoc type. + let mut call_spans = vec![]; let mut expr = expr; let mut prev_ty = self.resolve_vars_if_possible( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()), ); - let outer_ty = prev_ty; - let mut assoc_seen = 0; while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { @@ -2910,12 +2909,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // vec![1, 2, 3].iter().map(mapper).sum() // ^^^^^^ ^^^^^^^^^^^ expr = rcvr_expr; + let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); + call_spans.push(span); let ocx = ObligationCtxt::new_in_snapshot(self.infcx); for diff in &type_diffs { let Sorts(expected_found) = diff else { continue; }; let ty::Projection(proj) = expected_found.expected.kind() else { continue; }; - assoc_seen += 1; let origin = TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, @@ -2963,23 +2963,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if ocx.select_where_possible().is_empty() { // `ty_var` now holds the type that `Item` is for `ExprTy`. let assoc = self.tcx.def_path_str(proj.item_def_id); - multi_span.push_span_label( - span, - &format!( - "associated type `{assoc}` is `{}` here", - self.resolve_vars_if_possible(ty_var), - ), - ); + let ty_var = self.resolve_vars_if_possible(ty_var); + assocs_in_this_method.push(Some((span, (assoc, ty_var)))); } else { // `` didn't select, so likely we've // reached the end of the iterator chain, like the originating // `Vec<_>`. - multi_span.push_span_label( - span, - format!("this call has type `{prev_ty}`"), - ); + // Keep the space consistent for later zipping. + assocs_in_this_method.push(None); } } + assocs.push(assocs_in_this_method); prev_ty = self.resolve_vars_if_possible( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(tcx.ty_error()), ); @@ -2992,17 +2986,65 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Point at the root expression // vec![1, 2, 3].iter().map(mapper).sum() // ^^^^^^^^^^^^^ - multi_span.push_span_label( - expr.span, - format!("this expression has type `{ty}`"), - ); + span_labels + .push((expr.span, format!("this expression has type `{ty}`"))); }; - if assoc_seen > 0 { - // Only show this if it is not a "trivial" expression (not a method - // chain) and there are associated types to talk about. + // Only show this if it is not a "trivial" expression (not a method + // chain) and there are associated types to talk about. + let mut assocs = assocs.into_iter().peekable(); + while let Some(assocs_in_method) = assocs.next() { + let Some(prev_assoc_in_method) = assocs.peek() else { + for entry in assocs_in_method { + let Some((span, (assoc, ty))) = entry else { continue; }; + primary_spans.push(span); + span_labels.push(( + span, + format!("associated type `{assoc}` is `{ty}` here"), + )); + } + break; + }; + for (entry, prev_entry) in + assocs_in_method.into_iter().zip(prev_assoc_in_method.into_iter()) + { + match (entry, prev_entry) { + (Some((span, (assoc, ty))), Some((_, (_, prev_ty)))) => { + if ty != *prev_ty { + primary_spans.push(span); + span_labels.push(( + span, + format!("associated type `{assoc}` changed to `{ty}` here"), + )); + } + } + (Some((span, (assoc, ty))), None) => { + span_labels.push(( + span, + format!("associated type `{assoc}` is `{ty}` here"), + )); + } + (None, Some(_)) | (None, None) => {} + } + } + } + for span in call_spans { + if span_labels.iter().find(|(s, _)| *s == span).is_none() { + // Ensure we are showing the entire chain, even if the assoc types + // haven't changed. + span_labels.push((span, String::new())); + } + } + if !primary_spans.is_empty() { + let mut multi_span: MultiSpan = primary_spans.into(); + for (span, label) in span_labels { + multi_span.push_span_label(span, label); + } err.span_note( multi_span, - format!("the expression is of type `{outer_ty}`"), + format!( + "the method call chain might not have had the expected \ + associated types", + ), ); } }; diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 5e84dcdef30..eca961633dc 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -22,11 +22,11 @@ LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_rece | = help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>` = help: the trait `FromIterator` is implemented for `Vec` -note: the expression is of type `Map, [closure@$DIR/issue-34334.rs:5:47: 5:82]>` - --> $DIR/issue-34334.rs:5:43 +note: the method call chain might not have had the expected associated types + --> $DIR/issue-34334.rs:5:36 | LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - | -- ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here + | -- ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `()` here | | | | | associated type `std::iter::Iterator::Item` is `&(_, _, _)` here | this expression has type `Vec<(_, _, _)>` diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr index 5ee287b1b15..7f97b5bfcbe 100644 --- a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr @@ -8,7 +8,7 @@ LL | let x2: Vec = x1.into_iter().collect(); | = help: the trait `FromIterator<&f64>` is not implemented for `Vec` = help: the trait `FromIterator` is implemented for `Vec` -note: the expression is of type `std::slice::Iter<'_, f64>` +note: the method call chain might not have had the expected associated types --> $DIR/issue-66923-show-error-for-correct-call.rs:8:27 | LL | let x2: Vec = x1.into_iter().collect(); @@ -31,7 +31,7 @@ LL | let x3 = x1.into_iter().collect::>(); | = help: the trait `FromIterator<&f64>` is not implemented for `Vec` = help: the trait `FromIterator` is implemented for `Vec` -note: the expression is of type `std::slice::Iter<'_, f64>` +note: the method call chain might not have had the expected associated types --> $DIR/issue-66923-show-error-for-correct-call.rs:12:17 | LL | let x3 = x1.into_iter().collect::>(); diff --git a/src/test/ui/iterators/invalid-iterator-chain.stderr b/src/test/ui/iterators/invalid-iterator-chain.stderr index 0b3e0653864..57be01a2442 100644 --- a/src/test/ui/iterators/invalid-iterator-chain.stderr +++ b/src/test/ui/iterators/invalid-iterator-chain.stderr @@ -9,20 +9,18 @@ LL | println!("{}", scores.sum::()); = help: the following other types implement trait `Sum`: > -note: the expression is of type `Map, [closure@$DIR/invalid-iterator-chain.rs:4:14: 4:22]>` - --> $DIR/invalid-iterator-chain.rs:7:20 +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain.rs:3:10 | LL | let scores = vec![(0, 0)] | ------------ this expression has type `Vec<({integer}, {integer})>` LL | .iter() - | ------ associated type `std::iter::Iterator::Item` is `&({integer}, {integer})` here + | ^^^^^^ associated type `std::iter::Iterator::Item` is `&({integer}, {integer})` here LL | .map(|(a, b)| { - | __________- + | __________^ LL | | a + b; LL | | }); - | |__________- associated type `std::iter::Iterator::Item` is `()` here -LL | println!("{}", scores.sum::()); - | ^^^^^^ + | |__________^ associated type `std::iter::Iterator::Item` changed to `()` here note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | @@ -46,25 +44,25 @@ LL | .sum::(), = help: the following other types implement trait `Sum`: > -note: the expression is of type `Map, [closure@$DIR/invalid-iterator-chain.rs:12:18: 12:21]>, [closure@$DIR/invalid-iterator-chain.rs:13:18: 13:21]>, [closure@$DIR/invalid-iterator-chain.rs:14:18: 14:21]>, [closure@$DIR/invalid-iterator-chain.rs:15:21: 15:24]>, [closure@$DIR/invalid-iterator-chain.rs:16:18: 16:21]>, [closure@$DIR/invalid-iterator-chain.rs:17:18: 17:21]>` - --> $DIR/invalid-iterator-chain.rs:17:14 +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain.rs:11:14 | LL | vec![0, 1] | ---------- this expression has type `Vec<{integer}>` LL | .iter() - | ------ associated type `std::iter::Iterator::Item` is `&{integer}` here + | ^^^^^^ associated type `std::iter::Iterator::Item` is `&{integer}` here LL | .map(|x| x * 2) - | -------------- associated type `std::iter::Iterator::Item` is `{integer}` here + | ^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `{integer}` here LL | .map(|x| x as f64) - | ----------------- associated type `std::iter::Iterator::Item` is `f64` here + | ^^^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `f64` here LL | .map(|x| x as i64) - | ----------------- associated type `std::iter::Iterator::Item` is `i64` here + | ^^^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `i64` here LL | .filter(|x| *x > 0) - | ------------------ associated type `std::iter::Iterator::Item` is `i64` here + | ------------------ LL | .map(|x| { x + 1 }) - | ------------------ associated type `std::iter::Iterator::Item` is `i64` here + | ------------------ LL | .map(|x| { x; }) - | ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here + | ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `()` here note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | @@ -82,11 +80,11 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); = help: the following other types implement trait `Sum`: > -note: the expression is of type `Map, [closure@$DIR/invalid-iterator-chain.rs:20:42: 20:45]>` - --> $DIR/invalid-iterator-chain.rs:20:38 +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain.rs:20:31 | LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::()); - | ---------- ------ ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` is `()` here + | ---------- ^^^^^^ ^^^^^^^^^^^^^^^ associated type `std::iter::Iterator::Item` changed to `()` here | | | | | associated type `std::iter::Iterator::Item` is `&{integer}` here | this expression has type `Vec<{integer}>` @@ -107,7 +105,7 @@ LL | println!("{}", vec![(), ()].iter().sum::()); = help: the following other types implement trait `Sum`: > -note: the expression is of type `std::slice::Iter<'_, ()>` +note: the method call chain might not have had the expected associated types --> $DIR/invalid-iterator-chain.rs:21:33 | LL | println!("{}", vec![(), ()].iter().sum::());