Skip to content

Commit 48b0fd2

Browse files
authored
Rollup merge of rust-lang#66700 - VirrageS:master, r=matthewjasper
Fix pointing at arg for fulfillment errors in function calls Closes: rust-lang#66258
2 parents 8a7a9f2 + 6f70803 commit 48b0fd2

File tree

4 files changed

+88
-15
lines changed

4 files changed

+88
-15
lines changed

src/librustc/traits/error_reporting.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
166166
body_id: Option<hir::BodyId>,
167167
fallback_has_occurred: bool,
168168
) {
169-
debug!("report_fulfillment_errors({:?})", error);
169+
debug!("report_fulfillment_error({:?})", error);
170170
match error.code {
171171
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
172172
self.report_selection_error(

src/librustc_typeck/check/mod.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3748,7 +3748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37483748
formal_tys.clone()
37493749
};
37503750

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

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

38213821
// 3. Relate the expected type and the formal one,
38223822
// if the expected type was used for the coercion.
@@ -3863,14 +3863,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38633863
vec![self.tcx.types.err; len]
38643864
}
38653865

3866-
/// Given a vec of evaluated `FullfillmentError`s and an `fn` call argument expressions, we
3867-
/// walk the resolved types for each argument to see if any of the `FullfillmentError`s
3868-
/// reference a type argument. If they do, and there's only *one* argument that does, we point
3869-
/// at the corresponding argument's expression span instead of the `fn` call path span.
3866+
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
3867+
/// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
3868+
/// reference a type argument. The reason to walk also the checked type is that the coerced type
3869+
/// can be not easily comparable with predicate type (because of coercion). If the types match
3870+
/// for either checked or coerced type, and there's only *one* argument that does, we point at
3871+
/// the corresponding argument's expression span instead of the `fn` call path span.
38703872
fn point_at_arg_instead_of_call_if_possible(
38713873
&self,
38723874
errors: &mut Vec<traits::FulfillmentError<'_>>,
3873-
final_arg_types: &[(usize, Ty<'tcx>)],
3875+
final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
38743876
call_sp: Span,
38753877
args: &'tcx [hir::Expr],
38763878
) {
@@ -3880,19 +3882,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38803882
for error in errors {
38813883
if let ty::Predicate::Trait(predicate) = error.obligation.predicate {
38823884
// Collect the argument position for all arguments that could have caused this
3883-
// `FullfillmentError`.
3885+
// `FulfillmentError`.
38843886
let mut referenced_in = final_arg_types.iter()
3887+
.map(|(i, checked_ty, _)| (i, checked_ty))
3888+
.chain(final_arg_types.iter().map(|(i, _, coerced_ty)| (i, coerced_ty)))
38853889
.flat_map(|(i, ty)| {
38863890
let ty = self.resolve_vars_if_possible(ty);
38873891
// We walk the argument type because the argument's type could have
3888-
// been `Option<T>`, but the `FullfillmentError` references `T`.
3892+
// been `Option<T>`, but the `FulfillmentError` references `T`.
38893893
ty.walk()
38903894
.filter(|&ty| ty == predicate.skip_binder().self_ty())
38913895
.map(move |_| *i)
3892-
});
3893-
if let (Some(ref_in), None) = (referenced_in.next(), referenced_in.next()) {
3896+
})
3897+
.collect::<Vec<_>>();
3898+
3899+
// Both checked and coerced types could have matched, thus we need to remove
3900+
// duplicates.
3901+
referenced_in.dedup();
3902+
3903+
if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
38943904
// We make sure that only *one* argument matches the obligation failure
3895-
// and thet the obligation's span to its expression's.
3905+
// and we assign the obligation's span to its expression's.
38963906
error.obligation.cause.span = args[ref_in].span;
38973907
error.points_at_arg_span = true;
38983908
}
@@ -3901,8 +3911,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
39013911
}
39023912
}
39033913

3904-
/// Given a vec of evaluated `FullfillmentError`s and an `fn` call expression, we walk the
3905-
/// `PathSegment`s and resolve their type parameters to see if any of the `FullfillmentError`s
3914+
/// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
3915+
/// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
39063916
/// were caused by them. If they were, we point at the corresponding type argument's span
39073917
/// instead of the `fn` call path span.
39083918
fn point_at_type_arg_instead_of_call_if_possible(
Lines changed: 20 additions & 0 deletions
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+
}
Lines changed: 43 additions & 0 deletions
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)