Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error reporting for closure return type mismatches #87661

Merged
merged 1 commit into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -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);
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`.