From 4cc7ef5d93994eae7dab744767f6ac2804544b0f Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Sun, 1 Dec 2019 13:39:01 +0100 Subject: [PATCH 1/2] Fix pointing at arg when cause is outside of call --- src/librustc_typeck/check/mod.rs | 65 +++++++++++++++------------ src/test/ui/issues/issue-66923.rs | 13 ++++++ src/test/ui/issues/issue-66923.stderr | 19 ++++++++ 3 files changed, 69 insertions(+), 28 deletions(-) create mode 100644 src/test/ui/issues/issue-66923.rs create mode 100644 src/test/ui/issues/issue-66923.stderr diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a4a4a50bf273..7f8621902f2a1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3876,36 +3876,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_sp: Span, args: &'tcx [hir::Expr], ) { - if !call_sp.desugaring_kind().is_some() { - // We *do not* do this for desugared call spans to keep good diagnostics when involving - // the `?` operator. - for error in errors { - if let ty::Predicate::Trait(predicate) = error.obligation.predicate { - // Collect the argument position for all arguments that could have caused this - // `FulfillmentError`. - let mut referenced_in = final_arg_types.iter() - .map(|(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty))) - .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(ty); - // We walk the argument type because the argument's type could have - // been `Option`, but the `FulfillmentError` references `T`. - ty.walk() - .filter(|&ty| ty == predicate.skip_binder().self_ty()) - .map(move |_| *i) - }) - .collect::>(); + // We *do not* do this for desugared call spans to keep good diagnostics when involving + // the `?` operator. + if call_sp.desugaring_kind().is_some() { + return + } + + for error in errors { + // Only if the cause is somewhere inside the expression we want try to point at arg. + // Otherwise, it means that the cause is somewhere else and we should not change + // anything because we can break the correct span. + if !call_sp.contains(error.obligation.cause.span) { + continue + } + + if let ty::Predicate::Trait(predicate) = error.obligation.predicate { + // Collect the argument position for all arguments that could have caused this + // `FulfillmentError`. + let mut referenced_in = final_arg_types.iter() + .map(|(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty))) + .flat_map(|(i, ty)| { + let ty = self.resolve_vars_if_possible(ty); + // We walk the argument type because the argument's type could have + // been `Option`, but the `FulfillmentError` references `T`. + ty.walk() + .filter(|&ty| ty == predicate.skip_binder().self_ty()) + .map(move |_| *i) + }) + .collect::>(); - // Both checked and coerced types could have matched, thus we need to remove - // duplicates. - referenced_in.dedup(); + // Both checked and coerced types could have matched, thus we need to remove + // duplicates. + referenced_in.dedup(); - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { - // We make sure that only *one* argument matches the obligation failure - // and we assign the obligation's span to its expression's. - error.obligation.cause.span = args[ref_in].span; - error.points_at_arg_span = true; - } + if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + // We make sure that only *one* argument matches the obligation failure + // and we assign the obligation's span to its expression's. + error.obligation.cause.span = args[ref_in].span; + error.points_at_arg_span = true; } } } diff --git a/src/test/ui/issues/issue-66923.rs b/src/test/ui/issues/issue-66923.rs new file mode 100644 index 0000000000000..a452e6384a3d4 --- /dev/null +++ b/src/test/ui/issues/issue-66923.rs @@ -0,0 +1,13 @@ +fn main() { + let v = vec![1_f64, 2.2_f64]; + let mut fft: Vec> = vec![]; + + let x1: &[f64] = &v; + let x2: Vec = x1.into_iter().collect(); + //~^ ERROR a collection of type + fft.push(x2); + + let x3 = x1.into_iter().collect::>(); + //~^ ERROR a collection of type + fft.push(x3); +} diff --git a/src/test/ui/issues/issue-66923.stderr b/src/test/ui/issues/issue-66923.stderr new file mode 100644 index 0000000000000..a2eec7caee507 --- /dev/null +++ b/src/test/ui/issues/issue-66923.stderr @@ -0,0 +1,19 @@ +error[E0277]: a collection of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` + --> $DIR/issue-66923.rs:6:39 + | +LL | let x2: Vec = x1.into_iter().collect(); + | ^^^^^^^ a collection of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | + = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + +error[E0277]: a collection of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` + --> $DIR/issue-66923.rs:10:29 + | +LL | let x3 = x1.into_iter().collect::>(); + | ^^^^^^^ a collection of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | + = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 0abb988793d8477a4cb783e5b3d9410d0c3e7493 Mon Sep 17 00:00:00 2001 From: Janusz Marcinkiewicz Date: Tue, 3 Dec 2019 08:20:17 +0100 Subject: [PATCH 2/2] Rename tests and add short test description --- ...ue-66923.rs => issue-66923-show-error-for-correct-call.rs} | 2 ++ ....stderr => issue-66923-show-error-for-correct-call.stderr} | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) rename src/test/ui/issues/{issue-66923.rs => issue-66923-show-error-for-correct-call.rs} (77%) rename src/test/ui/issues/{issue-66923.stderr => issue-66923-show-error-for-correct-call.stderr} (88%) diff --git a/src/test/ui/issues/issue-66923.rs b/src/test/ui/issues/issue-66923-show-error-for-correct-call.rs similarity index 77% rename from src/test/ui/issues/issue-66923.rs rename to src/test/ui/issues/issue-66923-show-error-for-correct-call.rs index a452e6384a3d4..8a1c18ed1de19 100644 --- a/src/test/ui/issues/issue-66923.rs +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.rs @@ -1,3 +1,5 @@ +// This test checks that errors are showed for lines with `collect` rather than `push` method. + fn main() { let v = vec![1_f64, 2.2_f64]; let mut fft: Vec> = vec![]; diff --git a/src/test/ui/issues/issue-66923.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr similarity index 88% rename from src/test/ui/issues/issue-66923.stderr rename to src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr index a2eec7caee507..fbddd5a56f0ba 100644 --- a/src/test/ui/issues/issue-66923.stderr +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr @@ -1,5 +1,5 @@ error[E0277]: a collection of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` - --> $DIR/issue-66923.rs:6:39 + --> $DIR/issue-66923-show-error-for-correct-call.rs:8:39 | LL | let x2: Vec = x1.into_iter().collect(); | ^^^^^^^ a collection of type `std::vec::Vec` cannot be built from `std::iter::Iterator` @@ -7,7 +7,7 @@ LL | let x2: Vec = x1.into_iter().collect(); = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` error[E0277]: a collection of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` - --> $DIR/issue-66923.rs:10:29 + --> $DIR/issue-66923-show-error-for-correct-call.rs:12:29 | LL | let x3 = x1.into_iter().collect::>(); | ^^^^^^^ a collection of type `std::vec::Vec` cannot be built from `std::iter::Iterator`