diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0144d51a9693f..96d42dd73b1f5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { body_id: Option, 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( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 512a49d13e7cf..9107e99331125 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>, - 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`, but the `FullfillmentError` references `T`. + // been `Option`, 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::>(); + + // 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( diff --git a/src/test/ui/unsized/unsized-fn-param.rs b/src/test/ui/unsized/unsized-fn-param.rs new file mode 100644 index 0000000000000..32efc7e17ad7e --- /dev/null +++ b/src/test/ui/unsized/unsized-fn-param.rs @@ -0,0 +1,20 @@ +use std::convert::AsRef; +use std::path::Path; + +fn foo11(_bar: &dyn AsRef, _baz: &str) {} +fn foo12(_bar: &str, _baz: &dyn AsRef) {} + +fn foo21(_bar: &dyn AsRef, _baz: &str) {} +fn foo22(_bar: &str, _baz: &dyn AsRef) {} + +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"); +} diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr new file mode 100644 index 0000000000000..ed2c2e75cbd44 --- /dev/null +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -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 + = note: required for the cast to the object type `dyn std::convert::AsRef` + +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 + = note: required for the cast to the object type `dyn std::convert::AsRef` + +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 + = note: required for the cast to the object type `dyn std::convert::AsRef` + +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 + = note: required for the cast to the object type `dyn std::convert::AsRef` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`.