mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +00:00
Improve error reporting for closure return type mismatches
This commit is contained in:
parent
914a1e2c51
commit
d2fe289fc7
@ -78,6 +78,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
fn_id: hir::HirId,
|
||||
body: &'tcx hir::Body<'tcx>,
|
||||
can_be_generator: Option<hir::Movability>,
|
||||
return_type_pre_known: bool,
|
||||
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
|
||||
let mut fn_sig = fn_sig;
|
||||
|
||||
@ -87,6 +88,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
// in the case of closures, based on the outer context.
|
||||
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
|
||||
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
|
||||
fcx.return_type_pre_known = return_type_pre_known;
|
||||
|
||||
let tcx = fcx.tcx;
|
||||
let sess = tcx.sess;
|
||||
|
@ -73,8 +73,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
|
||||
|
||||
let generator_types =
|
||||
check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;
|
||||
let return_type_pre_known = !liberated_sig.output().is_ty_infer();
|
||||
|
||||
let generator_types = check_fn(
|
||||
self,
|
||||
self.param_env,
|
||||
liberated_sig,
|
||||
decl,
|
||||
expr.hir_id,
|
||||
body,
|
||||
gen,
|
||||
return_type_pre_known,
|
||||
)
|
||||
.1;
|
||||
|
||||
let parent_substs = InternalSubsts::identity_for_item(
|
||||
self.tcx,
|
||||
|
@ -40,7 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.suggest_missing_parentheses(err, expr);
|
||||
self.note_need_for_fn_pointer(err, expected, expr_ty);
|
||||
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
|
||||
self.report_closure_infered_return_type(err, expected)
|
||||
self.report_closure_inferred_return_type(err, expected);
|
||||
}
|
||||
|
||||
// Requires that the two types unify, and prints an error message if
|
||||
@ -1106,21 +1106,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// Report the type inferred by the return statement.
|
||||
fn report_closure_infered_return_type(
|
||||
fn report_closure_inferred_return_type(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
expected: Ty<'tcx>,
|
||||
) {
|
||||
if let Some(sp) = self.ret_coercion_span.get() {
|
||||
// If the closure has an explicit return type annotation,
|
||||
// then a type error may occur at the first return expression we
|
||||
// see in the closure (if it conflicts with the declared
|
||||
// return type). Skip adding a note in this case, since it
|
||||
// would be incorrect.
|
||||
if !err.span.primary_spans().iter().any(|&span| span == sp) {
|
||||
let hir = self.tcx.hir();
|
||||
let body_owner = hir.body_owned_by(hir.enclosing_body_owner(self.body_id));
|
||||
if self.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
|
||||
// If the closure has an explicit return type annotation, or if
|
||||
// the closure's return type has been inferred from outside
|
||||
// requirements (such as an Fn* trait bound), then a type error
|
||||
// may occur at the first return expression we see in the closure
|
||||
// (if it conflicts with the declared return type). Skip adding a
|
||||
// note in this case, since it would be incorrect.
|
||||
if !self.return_type_pre_known {
|
||||
err.span_note(
|
||||
sp,
|
||||
&format!(
|
||||
@ -1132,4 +1130,3 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,12 @@ pub struct FnCtxt<'a, 'tcx> {
|
||||
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
|
||||
|
||||
pub(super) inh: &'a Inherited<'a, 'tcx>,
|
||||
|
||||
/// True if the function or closure's return type is known before
|
||||
/// entering the function/closure, i.e. if the return type is
|
||||
/// either given explicitly or inferred from, say, an `Fn*` trait
|
||||
/// bound. Used for diagnostic purposes only.
|
||||
pub(super) return_type_pre_known: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
@ -137,6 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
by_id: Default::default(),
|
||||
}),
|
||||
inh,
|
||||
return_type_pre_known: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@ fn typeck_with_fallback<'tcx>(
|
||||
fn_sig,
|
||||
);
|
||||
|
||||
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
|
||||
let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
|
||||
fcx
|
||||
} else {
|
||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||
|
29
src/test/ui/closures/issue-87461.rs
Normal file
29
src/test/ui/closures/issue-87461.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// Regression test for #87461.
|
||||
|
||||
// edition:2021
|
||||
|
||||
async fn func() -> Result<u16, u64> {
|
||||
let _ = async {
|
||||
Err(42u64)
|
||||
}.await?;
|
||||
|
||||
Ok(())
|
||||
//~^ ERROR: mismatched types [E0308]
|
||||
}
|
||||
|
||||
async fn func2() -> Result<u16, u64> {
|
||||
Err(42u64)?;
|
||||
|
||||
Ok(())
|
||||
//~^ ERROR: mismatched types [E0308]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|| -> Result<u16, u64> {
|
||||
if true {
|
||||
return Err(42u64);
|
||||
}
|
||||
Ok(())
|
||||
//~^ ERROR: mismatched types [E0308]
|
||||
};
|
||||
}
|
21
src/test/ui/closures/issue-87461.stderr
Normal file
21
src/test/ui/closures/issue-87461.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-87461.rs:10:8
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^ expected `u16`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-87461.rs:17:8
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^ expected `u16`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-87461.rs:26:12
|
||||
|
|
||||
LL | Ok(())
|
||||
| ^^ expected `u16`, found `()`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Reference in New Issue
Block a user