Skip to content

Commit 3158dc3

Browse files
Rollup merge of rust-lang#158081 - Dnreikronos:trait_system/deferred_closure_recovery, r=nnethercote
trait-system: Recover deferred closure calls after errors fixes rust-lang#157951 this already reported the right errors, then typeck kept going and hit the deferred closure call path. that path assumed it could always find a fn trait impl after closure kind inference. with this repro, the earlier errors mean that lookup can fail, so it should recover instead of iceing. i think keeping this as recovery is the least surprising fix here. the compiler has already told the user what's wrong, so turning the later invariant into another hard failure doesn't buy much. also drops the weird e0746 help for this closure case. there's no written ret ty to edit, so suggestions like \impl f\ or \�ox<dyn box::new(f)>\ were just noise. added the next-solver ui test for the repro.
2 parents 7a39b25 + 9aaea56 commit 3158dc3

4 files changed

Lines changed: 70 additions & 6 deletions

File tree

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ use rustc_hir::{self as hir, HirId, LangItem, find_attr};
99
use rustc_hir_analysis::autoderef::Autoderef;
1010
use rustc_infer::infer::BoundRegionConversionTime;
1111
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
12+
use rustc_middle::bug;
1213
use rustc_middle::ty::adjustment::{
1314
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
1415
};
1516
use rustc_middle::ty::{self, FnSig, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, Unnormalized};
16-
use rustc_middle::{bug, span_bug};
1717
use rustc_span::def_id::LocalDefId;
1818
use rustc_span::{Ident, Span, sym};
1919
use rustc_target::spec::{AbiMap, AbiMapping};
@@ -1186,11 +1186,16 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
11861186
);
11871187
}
11881188
None => {
1189-
span_bug!(
1190-
self.call_expr.span,
1191-
"Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`",
1192-
self.closure_ty
1193-
)
1189+
let guar = fcx.tainted_by_errors().unwrap_or_else(|| {
1190+
fcx.dcx().span_delayed_bug(
1191+
self.call_expr.span,
1192+
format!(
1193+
"Expected to find a suitable `Fn`/`FnMut`/`FnOnce` implementation for `{}`",
1194+
self.closure_ty
1195+
),
1196+
)
1197+
});
1198+
fcx.write_resolution(self.call_expr.hir_id, Err(guar));
11941199
}
11951200
}
11961201
}

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,6 +2556,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
25562556
err.children.clear();
25572557

25582558
let mut span = obligation.cause.span;
2559+
let mut is_async_fn_return = false;
25592560
if let DefKind::Closure = self.tcx.def_kind(obligation.cause.body_id)
25602561
&& let parent = self.tcx.local_parent(obligation.cause.body_id)
25612562
&& let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(parent)
@@ -2571,10 +2572,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
25712572
// and
25722573
// async fn foo() -> dyn Display Box<dyn { .. }>
25732574
span = fn_sig.decl.output.span();
2575+
is_async_fn_return = true;
25742576
err.span(span);
25752577
}
25762578
let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
25772579

2580+
if !is_async_fn_return
2581+
&& let Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) =
2582+
self.tcx.hir_node_by_def_id(obligation.cause.body_id)
2583+
&& matches!(closure.fn_decl.output, hir::FnRetTy::DefaultReturn(_))
2584+
{
2585+
return true;
2586+
}
2587+
25782588
let mut visitor = ReturnsVisitor::default();
25792589
visitor.visit_body(&body);
25802590

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ compile-flags: -Znext-solver=globally
2+
//@ check-fail
3+
4+
fn main() {
5+
let f = |f: dyn Fn()| f;
6+
//~^ ERROR the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time
7+
//~| ERROR return type cannot be a trait object without pointer indirection
8+
f();
9+
//~^ ERROR this function takes 1 argument but 0 arguments were supplied
10+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time
2+
--> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:17
3+
|
4+
LL | let f = |f: dyn Fn()| f;
5+
| ^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)`
8+
= help: unsized fn params are gated as an unstable feature
9+
help: function arguments must have a statically known size, borrowed types always have a known size
10+
|
11+
LL | let f = |f: &dyn Fn()| f;
12+
| +
13+
14+
error[E0746]: return type cannot be a trait object without pointer indirection
15+
--> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:27
16+
|
17+
LL | let f = |f: dyn Fn()| f;
18+
| ^ doesn't have a size known at compile-time
19+
20+
error[E0057]: this function takes 1 argument but 0 arguments were supplied
21+
--> $DIR/deferred-closure-call-recovery-issue-157951.rs:8:5
22+
|
23+
LL | f();
24+
| ^-- argument #1 of type `(dyn Fn() + 'static)` is missing
25+
|
26+
note: closure defined here
27+
--> $DIR/deferred-closure-call-recovery-issue-157951.rs:5:13
28+
|
29+
LL | let f = |f: dyn Fn()| f;
30+
| ^^^^^^^^^^^^^
31+
help: provide the argument
32+
|
33+
LL | f(/* (dyn Fn() + 'static) */);
34+
| ++++++++++++++++++++++++++
35+
36+
error: aborting due to 3 previous errors
37+
38+
Some errors have detailed explanations: E0057, E0277, E0746.
39+
For more information about an error, try `rustc --explain E0057`.

0 commit comments

Comments
 (0)