From 4951e3ad9ecc653bd2097c6a80e2e1c841edec66 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 14 Sep 2021 10:52:36 +0000 Subject: [PATCH] Point at argument when evaluating `Path`'s bounds When evaluating an `ExprKind::Call`, we first have to `check_expr` on it's callee. When this one is a `ExprKind::Path`, we had to evaluate the bounds introduced for its arguments, but by the time we evaluated them we no longer had access to the argument spans. Now we special case this so that we can point at the right place on unsatisfied bounds. This also allows the E0277 deduplication to kick in correctly, so we now emit fewer errors. --- compiler/rustc_typeck/src/check/callee.rs | 11 +++++++- compiler/rustc_typeck/src/check/expr.rs | 28 +++++++++++++++---- .../associated-types-path-2.rs | 2 -- .../associated-types-path-2.stderr | 18 ++---------- .../feature-gate-unsized_fn_params.stderr | 4 +-- src/test/ui/issues/issue-17651.rs | 1 - src/test/ui/issues/issue-17651.stderr | 12 +------- src/test/ui/issues/issue-30355.stderr | 4 +-- .../ui/suggestions/issue-84973-blacklist.rs | 1 - .../suggestions/issue-84973-blacklist.stderr | 14 ++-------- 10 files changed, 43 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index d10155108597..1cc06b8c2e54 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -72,7 +72,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let original_callee_ty = self.check_expr(callee_expr); + let original_callee_ty = match &callee_expr.kind { + hir::ExprKind::Path(hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)) => self + .check_expr_with_expectation_and_args( + callee_expr, + Expectation::NoExpectation, + arg_exprs, + ), + _ => self.check_expr(callee_expr), + }; + let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index f4e3c8e0d9f7..917adf0e2b9b 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -161,6 +161,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + self.check_expr_with_expectation_and_args(expr, expected, &[]) + } + + /// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a + /// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`. + pub(super) fn check_expr_with_expectation_and_args( + &self, + expr: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, + args: &'tcx [hir::Expr<'tcx>], ) -> Ty<'tcx> { if self.tcx().sess.verbose() { // make this code only run with -Zverbose because it is probably slow @@ -198,7 +209,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let old_diverges = self.diverges.replace(Diverges::Maybe); let old_has_errors = self.has_errors.replace(false); - let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected)); + let ty = ensure_sufficient_stack(|| match &expr.kind { + hir::ExprKind::Path( + qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..), + ) => self.check_expr_path(qpath, expr, args), + _ => self.check_expr_kind(expr, expected), + }); // Warn for non-block expressions with diverging children. match expr.kind { @@ -261,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), ExprKind::InlineAsm(asm) => self.check_expr_asm(asm), ExprKind::LlvmInlineAsm(asm) => { for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) { @@ -481,10 +497,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 } - fn check_expr_path( + pub(crate) fn check_expr_path( &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, + args: &'tcx [hir::Expr<'tcx>], ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = @@ -517,16 +534,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. + let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); let input = self .replace_bound_vars_with_fresh_vars( - expr.span, + span, infer::LateBoundRegionConversionTime::FnCall, fn_sig.input(i), ) .0; self.require_type_is_sized_deferred( input, - expr.span, + span, traits::SizedArgumentType(None), ); } diff --git a/src/test/ui/associated-types/associated-types-path-2.rs b/src/test/ui/associated-types/associated-types-path-2.rs index c993e1d27202..912dedfdcebb 100644 --- a/src/test/ui/associated-types/associated-types-path-2.rs +++ b/src/test/ui/associated-types/associated-types-path-2.rs @@ -28,13 +28,11 @@ pub fn f1_int_uint() { pub fn f1_uint_uint() { f1(2u32, 4u32); //~^ ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f1_uint_int() { f1(2u32, 4i32); //~^ ERROR `u32: Foo` is not satisfied - //~| ERROR `u32: Foo` is not satisfied } pub fn f2_int() { diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index da4e13fcf92d..15a5245d54d9 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -24,13 +24,7 @@ LL | pub fn f1(a: T, x: T::A) {} | ^^^ required by this bound in `f1` error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:29:5 - | -LL | f1(2u32, 4u32); - | ^^ the trait `Foo` is not implemented for `u32` - -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:35:14 + --> $DIR/associated-types-path-2.rs:34:14 | LL | f1(2u32, 4i32); | -- ^^^^ the trait `Foo` is not implemented for `u32` @@ -43,14 +37,8 @@ note: required by a bound in `f1` LL | pub fn f1(a: T, x: T::A) {} | ^^^ required by this bound in `f1` -error[E0277]: the trait bound `u32: Foo` is not satisfied - --> $DIR/associated-types-path-2.rs:35:5 - | -LL | f1(2u32, 4i32); - | ^^ the trait `Foo` is not implemented for `u32` - error[E0308]: mismatched types - --> $DIR/associated-types-path-2.rs:41:18 + --> $DIR/associated-types-path-2.rs:39:18 | LL | let _: i32 = f2(2i32); | --- ^^^^^^^^ expected `i32`, found `u32` @@ -62,7 +50,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn LL | let _: i32 = f2(2i32).try_into().unwrap(); | ++++++++++++++++++++ -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr index fbb18c8c4909..0f7520ef7f8a 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr @@ -12,10 +12,10 @@ LL | fn foo(x: &dyn Foo) { | + error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time - --> $DIR/feature-gate-unsized_fn_params.rs:24:5 + --> $DIR/feature-gate-unsized_fn_params.rs:24:9 | LL | foo(*x); - | ^^^ doesn't have a size known at compile-time + | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = note: all function arguments must have a statically known size diff --git a/src/test/ui/issues/issue-17651.rs b/src/test/ui/issues/issue-17651.rs index 08f352c11fa1..7629a5a3be1e 100644 --- a/src/test/ui/issues/issue-17651.rs +++ b/src/test/ui/issues/issue-17651.rs @@ -4,5 +4,4 @@ fn main() { (|| Box::new(*(&[0][..])))(); //~^ ERROR the size for values of type - //~| ERROR the size for values of type } diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index 2c88e22742b0..214477f6c60e 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -13,16 +13,6 @@ note: required by `Box::::new` LL | pub fn new(x: T) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time - --> $DIR/issue-17651.rs:5:9 - | -LL | (|| Box::new(*(&[0][..])))(); - | ^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[{integer}]` - = note: all function arguments must have a statically known size - = help: unsized fn params are gated as an unstable feature - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 79f5db650d9d..71bbdf5dec76 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -1,8 +1,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-30355.rs:5:6 + --> $DIR/issue-30355.rs:5:8 | LL | &X(*Y) - | ^ doesn't have a size known at compile-time + | ^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size diff --git a/src/test/ui/suggestions/issue-84973-blacklist.rs b/src/test/ui/suggestions/issue-84973-blacklist.rs index db954530b1be..6813b07a2ee6 100644 --- a/src/test/ui/suggestions/issue-84973-blacklist.rs +++ b/src/test/ui/suggestions/issue-84973-blacklist.rs @@ -21,7 +21,6 @@ fn main() { let ref_cl: &dyn Fn() -> () = &cl; f_sized(*ref_cl); //~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] - //~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] use std::rc::Rc; let rc = Rc::new(0); diff --git a/src/test/ui/suggestions/issue-84973-blacklist.stderr b/src/test/ui/suggestions/issue-84973-blacklist.stderr index 72d9f5d26a2f..ae55c96702ad 100644 --- a/src/test/ui/suggestions/issue-84973-blacklist.stderr +++ b/src/test/ui/suggestions/issue-84973-blacklist.stderr @@ -55,7 +55,7 @@ LL | fn f_sized(t: T) {} | ^ required by this bound in `f_sized` error[E0277]: `Rc<{integer}>` cannot be sent between threads safely - --> $DIR/issue-84973-blacklist.rs:28:12 + --> $DIR/issue-84973-blacklist.rs:27:12 | LL | f_send(rc); | ------ ^^ `Rc<{integer}>` cannot be sent between threads safely @@ -69,16 +69,6 @@ note: required by a bound in `f_send` LL | fn f_send(t: T) {} | ^^^^ required by this bound in `f_send` -error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time - --> $DIR/issue-84973-blacklist.rs:22:5 - | -LL | f_sized(*ref_cl); - | ^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `dyn Fn()` - = note: all function arguments must have a statically known size - = help: unsized fn params are gated as an unstable feature - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`.