Skip to content

Commit 52c881f

Browse files
committed
Auto merge of #87661 - FabianWolff:issue-87461, r=estebank
Improve error reporting for closure return type mismatches Fixes #87461.
2 parents 5998c2e + d2fe289 commit 52c881f

File tree

7 files changed

+89
-22
lines changed

7 files changed

+89
-22
lines changed

compiler/rustc_typeck/src/check/check.rs

+2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub(super) fn check_fn<'a, 'tcx>(
7878
fn_id: hir::HirId,
7979
body: &'tcx hir::Body<'tcx>,
8080
can_be_generator: Option<hir::Movability>,
81+
return_type_pre_known: bool,
8182
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
8283
let mut fn_sig = fn_sig;
8384

@@ -87,6 +88,7 @@ pub(super) fn check_fn<'a, 'tcx>(
8788
// in the case of closures, based on the outer context.
8889
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
8990
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
91+
fcx.return_type_pre_known = return_type_pre_known;
9092

9193
let tcx = fcx.tcx;
9294
let sess = tcx.sess;

compiler/rustc_typeck/src/check/closure.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7373

7474
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
7575

76-
let generator_types =
77-
check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;
76+
let return_type_pre_known = !liberated_sig.output().is_ty_infer();
77+
78+
let generator_types = check_fn(
79+
self,
80+
self.param_env,
81+
liberated_sig,
82+
decl,
83+
expr.hir_id,
84+
body,
85+
gen,
86+
return_type_pre_known,
87+
)
88+
.1;
7889

7990
let parent_substs = InternalSubsts::identity_for_item(
8091
self.tcx,

compiler/rustc_typeck/src/check/demand.rs

+16-19
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4040
self.suggest_missing_parentheses(err, expr);
4141
self.note_need_for_fn_pointer(err, expected, expr_ty);
4242
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
43-
self.report_closure_infered_return_type(err, expected)
43+
self.report_closure_inferred_return_type(err, expected);
4444
}
4545

4646
// Requires that the two types unify, and prints an error message if
@@ -1106,29 +1106,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11061106
}
11071107

11081108
// Report the type inferred by the return statement.
1109-
fn report_closure_infered_return_type(
1109+
fn report_closure_inferred_return_type(
11101110
&self,
11111111
err: &mut DiagnosticBuilder<'_>,
11121112
expected: Ty<'tcx>,
11131113
) {
11141114
if let Some(sp) = self.ret_coercion_span.get() {
1115-
// If the closure has an explicit return type annotation,
1116-
// then a type error may occur at the first return expression we
1117-
// see in the closure (if it conflicts with the declared
1118-
// return type). Skip adding a note in this case, since it
1119-
// would be incorrect.
1120-
if !err.span.primary_spans().iter().any(|&span| span == sp) {
1121-
let hir = self.tcx.hir();
1122-
let body_owner = hir.body_owned_by(hir.enclosing_body_owner(self.body_id));
1123-
if self.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
1124-
err.span_note(
1125-
sp,
1126-
&format!(
1127-
"return type inferred to be `{}` here",
1128-
self.resolve_vars_if_possible(expected)
1129-
),
1130-
);
1131-
}
1115+
// If the closure has an explicit return type annotation, or if
1116+
// the closure's return type has been inferred from outside
1117+
// requirements (such as an Fn* trait bound), then a type error
1118+
// may occur at the first return expression we see in the closure
1119+
// (if it conflicts with the declared return type). Skip adding a
1120+
// note in this case, since it would be incorrect.
1121+
if !self.return_type_pre_known {
1122+
err.span_note(
1123+
sp,
1124+
&format!(
1125+
"return type inferred to be `{}` here",
1126+
self.resolve_vars_if_possible(expected)
1127+
),
1128+
);
11321129
}
11331130
}
11341131
}

compiler/rustc_typeck/src/check/fn_ctxt/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ pub struct FnCtxt<'a, 'tcx> {
111111
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
112112

113113
pub(super) inh: &'a Inherited<'a, 'tcx>,
114+
115+
/// True if the function or closure's return type is known before
116+
/// entering the function/closure, i.e. if the return type is
117+
/// either given explicitly or inferred from, say, an `Fn*` trait
118+
/// bound. Used for diagnostic purposes only.
119+
pub(super) return_type_pre_known: bool,
114120
}
115121

116122
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -137,6 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
137143
by_id: Default::default(),
138144
}),
139145
inh,
146+
return_type_pre_known: true,
140147
}
141148
}
142149

compiler/rustc_typeck/src/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ fn typeck_with_fallback<'tcx>(
392392
fn_sig,
393393
);
394394

395-
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
395+
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
396396
fcx
397397
} else {
398398
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);

src/test/ui/closures/issue-87461.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Regression test for #87461.
2+
3+
// edition:2021
4+
5+
async fn func() -> Result<u16, u64> {
6+
let _ = async {
7+
Err(42u64)
8+
}.await?;
9+
10+
Ok(())
11+
//~^ ERROR: mismatched types [E0308]
12+
}
13+
14+
async fn func2() -> Result<u16, u64> {
15+
Err(42u64)?;
16+
17+
Ok(())
18+
//~^ ERROR: mismatched types [E0308]
19+
}
20+
21+
fn main() {
22+
|| -> Result<u16, u64> {
23+
if true {
24+
return Err(42u64);
25+
}
26+
Ok(())
27+
//~^ ERROR: mismatched types [E0308]
28+
};
29+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-87461.rs:10:8
3+
|
4+
LL | Ok(())
5+
| ^^ expected `u16`, found `()`
6+
7+
error[E0308]: mismatched types
8+
--> $DIR/issue-87461.rs:17:8
9+
|
10+
LL | Ok(())
11+
| ^^ expected `u16`, found `()`
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/issue-87461.rs:26:12
15+
|
16+
LL | Ok(())
17+
| ^^ expected `u16`, found `()`
18+
19+
error: aborting due to 3 previous errors
20+
21+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)