Fix pointing at arg for fulfillment errors in function calls
This commit is contained in:
parent
7d761fe046
commit
6f70803e7e
4 changed files with 88 additions and 15 deletions
|
@ -165,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
body_id: Option<hir::BodyId>,
|
body_id: Option<hir::BodyId>,
|
||||||
fallback_has_occurred: bool,
|
fallback_has_occurred: bool,
|
||||||
) {
|
) {
|
||||||
debug!("report_fulfillment_errors({:?})", error);
|
debug!("report_fulfillment_error({:?})", error);
|
||||||
match error.code {
|
match error.code {
|
||||||
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
|
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
|
||||||
self.report_selection_error(
|
self.report_selection_error(
|
||||||
|
|
|
@ -3641,7 +3641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
formal_tys.clone()
|
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.
|
// Check the arguments.
|
||||||
// We do this in a pretty awful way: first we type-check any 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
|
// We're processing function arguments so we definitely want to use
|
||||||
// two-phase borrows.
|
// two-phase borrows.
|
||||||
self.demand_coerce(&arg, checked_ty, coerce_ty, AllowTwoPhase::Yes);
|
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,
|
// 3. Relate the expected type and the formal one,
|
||||||
// if the expected type was used for the coercion.
|
// 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]
|
vec![self.tcx.types.err; len]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a vec of evaluated `FullfillmentError`s and an `fn` call argument expressions, we
|
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
|
||||||
/// walk the resolved types for each argument to see if any of the `FullfillmentError`s
|
/// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
|
||||||
/// reference a type argument. If they do, and there's only *one* argument that does, we point
|
/// reference a type argument. The reason to walk also the checked type is that the coerced type
|
||||||
/// at the corresponding argument's expression span instead of the `fn` call path span.
|
/// 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(
|
fn point_at_arg_instead_of_call_if_possible(
|
||||||
&self,
|
&self,
|
||||||
errors: &mut Vec<traits::FulfillmentError<'_>>,
|
errors: &mut Vec<traits::FulfillmentError<'_>>,
|
||||||
final_arg_types: &[(usize, Ty<'tcx>)],
|
final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
|
||||||
call_sp: Span,
|
call_sp: Span,
|
||||||
args: &'tcx [hir::Expr],
|
args: &'tcx [hir::Expr],
|
||||||
) {
|
) {
|
||||||
|
@ -3773,19 +3775,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
for error in errors {
|
for error in errors {
|
||||||
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
|
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
|
||||||
// Collect the argument position for all arguments that could have caused this
|
// Collect the argument position for all arguments that could have caused this
|
||||||
// `FullfillmentError`.
|
// `FulfillmentError`.
|
||||||
let mut referenced_in = final_arg_types.iter()
|
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)| {
|
.flat_map(|(i, ty)| {
|
||||||
let ty = self.resolve_vars_if_possible(ty);
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
// We walk the argument type because the argument's type could have
|
// 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()
|
ty.walk()
|
||||||
.filter(|&ty| ty == predicate.skip_binder().self_ty())
|
.filter(|&ty| ty == predicate.skip_binder().self_ty())
|
||||||
.map(move |_| *i)
|
.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
|
// 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.obligation.cause.span = args[ref_in].span;
|
||||||
error.points_at_arg_span = true;
|
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
|
/// 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 `FullfillmentError`s
|
/// `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
|
/// were caused by them. If they were, we point at the corresponding type argument's span
|
||||||
/// instead of the `fn` call path span.
|
/// instead of the `fn` call path span.
|
||||||
fn point_at_type_arg_instead_of_call_if_possible(
|
fn point_at_type_arg_instead_of_call_if_possible(
|
||||||
|
|
20
src/test/ui/unsized/unsized-fn-param.rs
Normal file
20
src/test/ui/unsized/unsized-fn-param.rs
Normal 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");
|
||||||
|
}
|
43
src/test/ui/unsized/unsized-fn-param.stderr
Normal file
43
src/test/ui/unsized/unsized-fn-param.stderr
Normal 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`.
|
Loading…
Add table
Add a link
Reference in a new issue