Skip to content

Commit

Permalink
Auto merge of #87661 - FabianWolff:issue-87461, r=estebank
Browse files Browse the repository at this point in the history
Improve error reporting for closure return type mismatches

Fixes #87461.
  • Loading branch information
bors committed Aug 23, 2021
2 parents 5998c2e + d2fe289 commit 52c881f
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 22 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_typeck/src/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
35 changes: 16 additions & 19 deletions compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1106,29 +1106,26 @@ 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()) {
err.span_note(
sp,
&format!(
"return type inferred to be `{}` here",
self.resolve_vars_if_possible(expected)
),
);
}
// 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!(
"return type inferred to be `{}` here",
self.resolve_vars_if_possible(expected)
),
);
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -137,6 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
by_id: Default::default(),
}),
inh,
return_type_pre_known: true,
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,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);
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/closures/issue-87461.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/test/ui/closures/issue-87461.stderr
Original file line number Diff line number Diff line change
@@ -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`.

0 comments on commit 52c881f

Please sign in to comment.