Skip to content

Commit 6f70803

Browse files
committed
Fix pointing at arg for fulfillment errors in function calls
1 parent 7d761fe commit 6f70803

File tree

4 files changed

+88
-15
lines changed

4 files changed

+88
-15
lines changed

src/librustc/traits/error_reporting.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
165165
body_id: Option<hir::BodyId>,
166166
fallback_has_occurred: bool,
167167
) {
168-
debug!("report_fulfillment_errors({:?})", error);
168+
debug!("report_fulfillment_error({:?})", error);
169169
match error.code {
170170
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
171171
self.report_selection_error(

src/librustc_typeck/check/mod.rs

+24-14
Original file line numberDiff line numberDiff line change
@@ -3641,7 +3641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
36413641
formal_tys.clone()
36423642
};
36433643

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

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

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

3759-
/// Given a vec of evaluated `FullfillmentError`s and an `fn` call argument expressions, we
3760-
/// walk the resolved types for each argument to see if any of the `FullfillmentError`s
3761-
/// reference a type argument. If they do, and there's only *one* argument that does, we point
3762-
/// at the corresponding argument's expression span instead of the `fn` call path span.
3759+
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
3760+
/// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
3761+
/// reference a type argument. The reason to walk also the checked type is that the coerced type
3762+
/// can be not easily comparable with predicate type (because of coercion). If the types match
3763+
/// for either checked or coerced type, and there's only *one* argument that does, we point at
3764+
/// the corresponding argument's expression span instead of the `fn` call path span.
37633765
fn point_at_arg_instead_of_call_if_possible(
37643766
&self,
37653767
errors: &mut Vec<traits::FulfillmentError<'_>>,
3766-
final_arg_types: &[(usize, Ty<'tcx>)],
3768+
final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
37673769
call_sp: Span,
37683770
args: &'tcx [hir::Expr],
37693771
) {
@@ -3773,19 +3775,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37733775
for error in errors {
37743776
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
37753777
// Collect the argument position for all arguments that could have caused this
3776-
// `FullfillmentError`.
3778+
// `FulfillmentError`.
37773779
let mut referenced_in = final_arg_types.iter()
3780+
.map(|(i, checked_ty, _)| (i, checked_ty))
3781+
.chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
37783782
.flat_map(|(i, ty)| {
37793783
let ty = self.resolve_vars_if_possible(ty);
37803784
// We walk the argument type because the argument's type could have
3781-
// been `Option<T>`, but the `FullfillmentError` references `T`.
3785+
// been `Option<T>`, but the `FulfillmentError` references `T`.
37823786
ty.walk()
37833787
.filter(|&ty| ty == predicate.skip_binder().self_ty())
37843788
.map(move |_| *i)
3785-
});
3786-
if let (Some(ref_in), None) = (referenced_in.next(), referenced_in.next()) {
3789+
})
3790+
.collect::<Vec<_>>();
3791+
3792+
// Both checked and coerced types could have matched, thus we need to remove
3793+
// duplicates.
3794+
referenced_in.dedup();
3795+
3796+
if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
37873797
// We make sure that only *one* argument matches the obligation failure
3788-
// and thet the obligation's span to its expression's.
3798+
// and we assign the obligation's span to its expression's.
37893799
error.obligation.cause.span = args[ref_in].span;
37903800
error.points_at_arg_span = true;
37913801
}
@@ -3794,8 +3804,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37943804
}
37953805
}
37963806

3797-
/// Given a vec of evaluated `FullfillmentError`s and an `fn` call expression, we walk the
3798-
/// `PathSegment`s and resolve their type parameters to see if any of the `FullfillmentError`s
3807+
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
3808+
/// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
37993809
/// were caused by them. If they were, we point at the corresponding type argument's span
38003810
/// instead of the `fn` call path span.
38013811
fn point_at_type_arg_instead_of_call_if_possible(
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use std::convert::AsRef;
2+
use std::path::Path;
3+
4+
fn foo11(_bar: &dyn AsRef<Path>, _baz: &str) {}
5+
fn foo12(_bar: &str, _baz: &dyn AsRef<Path>) {}
6+
7+
fn foo21(_bar: &dyn AsRef<str>, _baz: &str) {}
8+
fn foo22(_bar: &str, _baz: &dyn AsRef<str>) {}
9+
10+
fn main() {
11+
foo11("bar", &"baz"); //~ ERROR the size for values of type
12+
foo11(&"bar", &"baz");
13+
foo12(&"bar", "baz"); //~ ERROR the size for values of type
14+
foo12(&"bar", &"baz");
15+
16+
foo21("bar", &"baz"); //~ ERROR the size for values of type
17+
foo21(&"bar", &"baz");
18+
foo22(&"bar", "baz"); //~ ERROR the size for values of type
19+
foo22(&"bar", &"baz");
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0277]: the size for values of type `str` cannot be known at compilation time
2+
--> $DIR/unsized-fn-param.rs:11:11
3+
|
4+
LL | foo11("bar", &"baz");
5+
| ^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `std::marker::Sized` is not implemented for `str`
8+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
9+
= note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
10+
11+
error[E0277]: the size for values of type `str` cannot be known at compilation time
12+
--> $DIR/unsized-fn-param.rs:13:19
13+
|
14+
LL | foo12(&"bar", "baz");
15+
| ^^^^^ doesn't have a size known at compile-time
16+
|
17+
= help: the trait `std::marker::Sized` is not implemented for `str`
18+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
19+
= note: required for the cast to the object type `dyn std::convert::AsRef<std::path::Path>`
20+
21+
error[E0277]: the size for values of type `str` cannot be known at compilation time
22+
--> $DIR/unsized-fn-param.rs:16:11
23+
|
24+
LL | foo21("bar", &"baz");
25+
| ^^^^^ doesn't have a size known at compile-time
26+
|
27+
= help: the trait `std::marker::Sized` is not implemented for `str`
28+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
29+
= note: required for the cast to the object type `dyn std::convert::AsRef<str>`
30+
31+
error[E0277]: the size for values of type `str` cannot be known at compilation time
32+
--> $DIR/unsized-fn-param.rs:18:19
33+
|
34+
LL | foo22(&"bar", "baz");
35+
| ^^^^^ doesn't have a size known at compile-time
36+
|
37+
= help: the trait `std::marker::Sized` is not implemented for `str`
38+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
39+
= note: required for the cast to the object type `dyn std::convert::AsRef<str>`
40+
41+
error: aborting due to 4 previous errors
42+
43+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)