Skip to content

Fix pointing at arg for fulfillment errors in function calls #66700

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

Merged
merged 1 commit into from
Nov 28, 2019
Merged
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
2 changes: 1 addition & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool,
) {
debug!("report_fulfillment_errors({:?})", error);
debug!("report_fulfillment_error({:?})", error);
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
self.report_selection_error(
Expand Down
38 changes: 24 additions & 14 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3641,7 +3641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
formal_tys.clone()
};

let mut final_arg_types: Vec<(usize, Ty<'_>)> = vec![];
let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];

// Check the arguments.
// We do this in a pretty awful way: first we type-check any arguments
Expand Down Expand Up @@ -3709,7 +3709,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes);
final_arg_types.push((i, coerce_ty));
final_arg_types.push((i, checked_ty, coerce_ty));

// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
Expand Down Expand Up @@ -3756,14 +3756,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![self.tcx.types.err; len]
}

/// Given a vec of evaluated `FullfillmentError`s and an `fn` call argument expressions, we
/// walk the resolved types for each argument to see if any of the `FullfillmentError`s
/// reference a type argument. If they do, and there's only *one* argument that does, we point
/// at the corresponding argument's expression span instead of the `fn` call path span.
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
/// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
/// reference a type argument. The reason to walk also the checked type is that the coerced type
/// can be not easily comparable with predicate type (because of coercion). If the types match
/// for either checked or coerced type, and there's only *one* argument that does, we point at
/// the corresponding argument's expression span instead of the `fn` call path span.
fn point_at_arg_instead_of_call_if_possible(
&self,
errors: &mut Vec<traits::FulfillmentError<'_>>,
final_arg_types: &[(usize, Ty<'tcx>)],
final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
call_sp: Span,
args: &'tcx [hir::Expr],
) {
Expand All @@ -3773,19 +3775,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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
// `FullfillmentError`.
// `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 `FullfillmentError` references `T`.
// been `Option<T>`, but the `FulfillmentError` references `T`.
ty.walk()
.filter(|&ty| ty == predicate.skip_binder().self_ty())
.map(move |_| *i)
});
if let (Some(ref_in), None) = (referenced_in.next(), referenced_in.next()) {
})
.collect::<Vec<_>>();

// 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 thet the obligation's span to its expression's.
// 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 All @@ -3794,8 +3804,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

/// Given a vec of evaluated `FullfillmentError`s and an `fn` call expression, we walk the
/// `PathSegment`s and resolve their type parameters to see if any of the `FullfillmentError`s
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
/// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
/// were caused by them. If they were, we point at the corresponding type argument's span
/// instead of the `fn` call path span.
fn point_at_type_arg_instead_of_call_if_possible(
Expand Down
20 changes: 20 additions & 0 deletions src/test/ui/unsized/unsized-fn-param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::convert::AsRef;
use std::path::Path;

fn foo11(_bar: &dyn AsRef<Path>, _baz: &str) {}
fn foo12(_bar: &str, _baz: &dyn AsRef<Path>) {}

fn foo21(_bar: &dyn AsRef<str>, _baz: &str) {}
fn foo22(_bar: &str, _baz: &dyn AsRef<str>) {}

fn main() {
foo11("bar", &"baz"); //~ ERROR the size for values of type
foo11(&"bar", &"baz");
foo12(&"bar", "baz"); //~ ERROR the size for values of type
foo12(&"bar", &"baz");

foo21("bar", &"baz"); //~ ERROR the size for values of type
foo21(&"bar", &"baz");
foo22(&"bar", "baz"); //~ ERROR the size for values of type
foo22(&"bar", &"baz");
}
43 changes: 43 additions & 0 deletions src/test/ui/unsized/unsized-fn-param.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/unsized-fn-param.rs:11:11
|
LL | foo11("bar", &"baz");
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/unsized-fn-param.rs:13:19
|
LL | foo12(&"bar", "baz");
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/unsized-fn-param.rs:16:11
|
LL | foo21("bar", &"baz");
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required for the cast to the object type `dyn std::convert::AsRef<str>`

error[E0277]: the size for values of type `str` cannot be known at compilation time
--> $DIR/unsized-fn-param.rs:18:19
|
LL | foo22(&"bar", "baz");
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required for the cast to the object type `dyn std::convert::AsRef<str>`

error: aborting due to 4 previous errors

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