Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix pointing at arg when cause is outside of call #66933

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 37 additions & 28 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3880,36 +3880,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<T>`, but the `FulfillmentError` references `T`.
ty.walk()
.filter(|&ty| ty == predicate.skip_binder().self_ty())
.map(move |_| *i)
})
.collect::<Vec<_>>();
// 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<T>`, but the `FulfillmentError` references `T`.
ty.walk()
.filter(|&ty| ty == predicate.skip_binder().self_ty())
.map(move |_| *i)
})
.collect::<Vec<_>>();

// 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;
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/issues/issue-66923-show-error-for-correct-call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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<f64>> = vec![];

let x1: &[f64] = &v;
let x2: Vec<f64> = x1.into_iter().collect();
//~^ ERROR a value of type
fft.push(x2);

let x3 = x1.into_iter().collect::<Vec<f64>>();
//~^ ERROR a value of type
fft.push(x3);
}
19 changes: 19 additions & 0 deletions src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0277]: a value of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
--> $DIR/issue-66923-show-error-for-correct-call.rs:8:39
|
LL | let x2: Vec<f64> = x1.into_iter().collect();
| ^^^^^^^ value of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
|
= help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`

error[E0277]: a value of type `std::vec::Vec<f64>` cannot be built from an iterator over elements of type `&f64`
--> $DIR/issue-66923-show-error-for-correct-call.rs:12:29
|
LL | let x3 = x1.into_iter().collect::<Vec<f64>>();
| ^^^^^^^ value of type `std::vec::Vec<f64>` cannot be built from `std::iter::Iterator<Item=&f64>`
|
= help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec<f64>`

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.