1
Fork 0

Fix pointing at arg for fulfillment errors in function calls

This commit is contained in:
Janusz Marcinkiewicz 2019-11-24 14:31:19 +01:00
parent 7d761fe046
commit 6f70803e7e
4 changed files with 88 additions and 15 deletions

View file

@ -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(

View file

@ -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
@ -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.
@ -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],
) {
@ -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;
}
@ -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(

View file

@ -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");
}

View file

@ -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`.