Skip to content

Commit 4951e3a

Browse files
committed
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.
1 parent 1d82905 commit 4951e3a

File tree

10 files changed

+43
-52
lines changed

10 files changed

+43
-52
lines changed

compiler/rustc_typeck/src/check/callee.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7272
arg_exprs: &'tcx [hir::Expr<'tcx>],
7373
expected: Expectation<'tcx>,
7474
) -> Ty<'tcx> {
75-
let original_callee_ty = self.check_expr(callee_expr);
75+
let original_callee_ty = match &callee_expr.kind {
76+
hir::ExprKind::Path(hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)) => self
77+
.check_expr_with_expectation_and_args(
78+
callee_expr,
79+
Expectation::NoExpectation,
80+
arg_exprs,
81+
),
82+
_ => self.check_expr(callee_expr),
83+
};
84+
7685
let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty);
7786

7887
let mut autoderef = self.autoderef(callee_expr.span, expr_ty);

compiler/rustc_typeck/src/check/expr.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161161
&self,
162162
expr: &'tcx hir::Expr<'tcx>,
163163
expected: Expectation<'tcx>,
164+
) -> Ty<'tcx> {
165+
self.check_expr_with_expectation_and_args(expr, expected, &[])
166+
}
167+
168+
/// Same as `check_expr_with_expectation`, but allows us to pass in the arguments of a
169+
/// `ExprKind::Call` when evaluating its callee when it is an `ExprKind::Path`.
170+
pub(super) fn check_expr_with_expectation_and_args(
171+
&self,
172+
expr: &'tcx hir::Expr<'tcx>,
173+
expected: Expectation<'tcx>,
174+
args: &'tcx [hir::Expr<'tcx>],
164175
) -> Ty<'tcx> {
165176
if self.tcx().sess.verbose() {
166177
// make this code only run with -Zverbose because it is probably slow
@@ -198,7 +209,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
198209
let old_diverges = self.diverges.replace(Diverges::Maybe);
199210
let old_has_errors = self.has_errors.replace(false);
200211

201-
let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected));
212+
let ty = ensure_sufficient_stack(|| match &expr.kind {
213+
hir::ExprKind::Path(
214+
qpath @ hir::QPath::Resolved(..) | qpath @ hir::QPath::TypeRelative(..),
215+
) => self.check_expr_path(qpath, expr, args),
216+
_ => self.check_expr_kind(expr, expected),
217+
});
202218

203219
// Warn for non-block expressions with diverging children.
204220
match expr.kind {
@@ -261,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
261277
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
262278
self.check_lang_item_path(lang_item, expr)
263279
}
264-
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
280+
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
265281
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
266282
ExprKind::LlvmInlineAsm(asm) => {
267283
for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
@@ -481,10 +497,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
481497
self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
482498
}
483499

484-
fn check_expr_path(
500+
pub(crate) fn check_expr_path(
485501
&self,
486502
qpath: &'tcx hir::QPath<'tcx>,
487503
expr: &'tcx hir::Expr<'tcx>,
504+
args: &'tcx [hir::Expr<'tcx>],
488505
) -> Ty<'tcx> {
489506
let tcx = self.tcx;
490507
let (res, opt_ty, segs) =
@@ -517,16 +534,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
517534
// We just want to check sizedness, so instead of introducing
518535
// placeholder lifetimes with probing, we just replace higher lifetimes
519536
// with fresh vars.
537+
let span = args.get(i).map(|a| a.span).unwrap_or(expr.span);
520538
let input = self
521539
.replace_bound_vars_with_fresh_vars(
522-
expr.span,
540+
span,
523541
infer::LateBoundRegionConversionTime::FnCall,
524542
fn_sig.input(i),
525543
)
526544
.0;
527545
self.require_type_is_sized_deferred(
528546
input,
529-
expr.span,
547+
span,
530548
traits::SizedArgumentType(None),
531549
);
532550
}

src/test/ui/associated-types/associated-types-path-2.rs

-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,11 @@ pub fn f1_int_uint() {
2828
pub fn f1_uint_uint() {
2929
f1(2u32, 4u32);
3030
//~^ ERROR `u32: Foo` is not satisfied
31-
//~| ERROR `u32: Foo` is not satisfied
3231
}
3332

3433
pub fn f1_uint_int() {
3534
f1(2u32, 4i32);
3635
//~^ ERROR `u32: Foo` is not satisfied
37-
//~| ERROR `u32: Foo` is not satisfied
3836
}
3937

4038
pub fn f2_int() {

src/test/ui/associated-types/associated-types-path-2.stderr

+3-15
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
2424
| ^^^ required by this bound in `f1`
2525

2626
error[E0277]: the trait bound `u32: Foo` is not satisfied
27-
--> $DIR/associated-types-path-2.rs:29:5
28-
|
29-
LL | f1(2u32, 4u32);
30-
| ^^ the trait `Foo` is not implemented for `u32`
31-
32-
error[E0277]: the trait bound `u32: Foo` is not satisfied
33-
--> $DIR/associated-types-path-2.rs:35:14
27+
--> $DIR/associated-types-path-2.rs:34:14
3428
|
3529
LL | f1(2u32, 4i32);
3630
| -- ^^^^ the trait `Foo` is not implemented for `u32`
@@ -43,14 +37,8 @@ note: required by a bound in `f1`
4337
LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
4438
| ^^^ required by this bound in `f1`
4539

46-
error[E0277]: the trait bound `u32: Foo` is not satisfied
47-
--> $DIR/associated-types-path-2.rs:35:5
48-
|
49-
LL | f1(2u32, 4i32);
50-
| ^^ the trait `Foo` is not implemented for `u32`
51-
5240
error[E0308]: mismatched types
53-
--> $DIR/associated-types-path-2.rs:41:18
41+
--> $DIR/associated-types-path-2.rs:39:18
5442
|
5543
LL | let _: i32 = f2(2i32);
5644
| --- ^^^^^^^^ expected `i32`, found `u32`
@@ -62,7 +50,7 @@ help: you can convert a `u32` to an `i32` and panic if the converted value doesn
6250
LL | let _: i32 = f2(2i32).try_into().unwrap();
6351
| ++++++++++++++++++++
6452

65-
error: aborting due to 6 previous errors
53+
error: aborting due to 4 previous errors
6654

6755
Some errors have detailed explanations: E0277, E0308.
6856
For more information about an error, try `rustc --explain E0277`.

src/test/ui/feature-gates/feature-gate-unsized_fn_params.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ LL | fn foo(x: &dyn Foo) {
1212
| +
1313

1414
error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known at compilation time
15-
--> $DIR/feature-gate-unsized_fn_params.rs:24:5
15+
--> $DIR/feature-gate-unsized_fn_params.rs:24:9
1616
|
1717
LL | foo(*x);
18-
| ^^^ doesn't have a size known at compile-time
18+
| ^^ doesn't have a size known at compile-time
1919
|
2020
= help: the trait `Sized` is not implemented for `(dyn Foo + 'static)`
2121
= note: all function arguments must have a statically known size

src/test/ui/issues/issue-17651.rs

-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@
44
fn main() {
55
(|| Box::new(*(&[0][..])))();
66
//~^ ERROR the size for values of type
7-
//~| ERROR the size for values of type
87
}

src/test/ui/issues/issue-17651.stderr

+1-11
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,6 @@ note: required by `Box::<T>::new`
1313
LL | pub fn new(x: T) -> Self {
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^
1515

16-
error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
17-
--> $DIR/issue-17651.rs:5:9
18-
|
19-
LL | (|| Box::new(*(&[0][..])))();
20-
| ^^^^^^^^ doesn't have a size known at compile-time
21-
|
22-
= help: the trait `Sized` is not implemented for `[{integer}]`
23-
= note: all function arguments must have a statically known size
24-
= help: unsized fn params are gated as an unstable feature
25-
26-
error: aborting due to 2 previous errors
16+
error: aborting due to previous error
2717

2818
For more information about this error, try `rustc --explain E0277`.

src/test/ui/issues/issue-30355.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
2-
--> $DIR/issue-30355.rs:5:6
2+
--> $DIR/issue-30355.rs:5:8
33
|
44
LL | &X(*Y)
5-
| ^ doesn't have a size known at compile-time
5+
| ^^ doesn't have a size known at compile-time
66
|
77
= help: the trait `Sized` is not implemented for `[u8]`
88
= note: all function arguments must have a statically known size

src/test/ui/suggestions/issue-84973-blacklist.rs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ fn main() {
2121
let ref_cl: &dyn Fn() -> () = &cl;
2222
f_sized(*ref_cl);
2323
//~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277]
24-
//~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277]
2524

2625
use std::rc::Rc;
2726
let rc = Rc::new(0);

src/test/ui/suggestions/issue-84973-blacklist.stderr

+2-12
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ LL | fn f_sized<T: Sized>(t: T) {}
5555
| ^ required by this bound in `f_sized`
5656

5757
error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
58-
--> $DIR/issue-84973-blacklist.rs:28:12
58+
--> $DIR/issue-84973-blacklist.rs:27:12
5959
|
6060
LL | f_send(rc);
6161
| ------ ^^ `Rc<{integer}>` cannot be sent between threads safely
@@ -69,16 +69,6 @@ note: required by a bound in `f_send`
6969
LL | fn f_send<T: Send>(t: T) {}
7070
| ^^^^ required by this bound in `f_send`
7171

72-
error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time
73-
--> $DIR/issue-84973-blacklist.rs:22:5
74-
|
75-
LL | f_sized(*ref_cl);
76-
| ^^^^^^^ doesn't have a size known at compile-time
77-
|
78-
= help: the trait `Sized` is not implemented for `dyn Fn()`
79-
= note: all function arguments must have a statically known size
80-
= help: unsized fn params are gated as an unstable feature
81-
82-
error: aborting due to 6 previous errors
72+
error: aborting due to 5 previous errors
8373

8474
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)