Skip to content
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
11 changes: 6 additions & 5 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2065,11 +2065,17 @@ impl<'tcx> CoerceMany<'tcx> {
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id);
}

let is_return_position = fcx
.tcx
.hir_get_fn_id_for_return_block(block_or_return_id)
.is_some_and(|fn_id| fn_id == fcx.tcx.local_def_id_to_hir_id(fcx.body_def_id));

// If this is due to a block, then maybe we forgot a `return`/`break`.
if due_to_block
&& let Some(expr) = expression
&& let Some(parent_fn_decl) =
fcx.tcx.hir_fn_decl_by_hir_id(fcx.tcx.local_def_id_to_hir_id(fcx.body_def_id))
&& !is_return_position
{
fcx.suggest_missing_break_or_return_expr(
&mut err,
Expand All @@ -2082,11 +2088,6 @@ impl<'tcx> CoerceMany<'tcx> {
);
}

let is_return_position = fcx
.tcx
.hir_get_fn_id_for_return_block(block_or_return_id)
.is_some_and(|fn_id| fn_id == fcx.tcx.local_def_id_to_hir_id(fcx.body_def_id));

if is_return_position
&& let Some(sp) = fcx.ret_coercion_span.get()
// If the closure has an explicit return type annotation, or if
Expand Down
32 changes: 15 additions & 17 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
pointing_at_return_type =
self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
self.suggest_missing_break_or_return_expr(
err, expr, fn_decl, expected, found, blk_id, fn_id,
);
}
pointing_at_return_type
}
Expand Down Expand Up @@ -1021,13 +1018,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::FnRetTy::Return(hir_ty) => {
if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
&& let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
&& !trait_ref
.trait_ref
.path
.segments
.last()
.and_then(|seg| seg.args)
.is_some_and(|args| !args.constraints.is_empty())
&& matches!(op_ty.origin, hir::OpaqueTyOrigin::FnReturn { .. })
{
// Use the path to get the trait name string
let trait_name = trait_ref
Expand All @@ -1054,16 +1045,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let trait_def_id = trait_ref.trait_ref.path.res.def_id();
if self.tcx.is_dyn_compatible(trait_def_id) {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)),
end_sp: hir_ty.span.shrink_to_hi(),
});

let body = self.tcx.hir_body_owned_by(fn_id);
let mut visitor = ReturnsVisitor::default();
visitor.visit_body(&body);

if !visitor.returns.is_empty() {
// Suggest boxing the return type only if there are multiple non-unit return types
if visitor.returns.len() > 1 {
err.subdiagnostic(SuggestBoxingForReturnImplTrait::ChangeReturnType {
start_sp: hir_ty.span.with_hi(hir_ty.span.lo() + BytePos(4)),
end_sp: hir_ty.span.shrink_to_hi(),
});

let starts: Vec<Span> = visitor
.returns
.iter()
Expand Down Expand Up @@ -1391,7 +1383,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Asyncness::No => ty,
};
let ty = self.normalize(expr.span, Unnormalized::new_wip(ty));
self.may_coerce(found, ty)
let can_coerce_to_prior_ret = self.ret_coercion_span.get().is_none_or(|_| {
self.ret_coercion.as_ref().is_some_and(|ret| {
let ret_ty = ret.borrow().expected_ty();
self.may_coerce(found, ret_ty)
})
});
self.may_coerce(found, ty) && can_coerce_to_prior_ret
}
hir::FnRetTy::DefaultReturn(_) if in_closure => {
self.ret_coercion.as_ref().is_some_and(|ret| {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ edition: 2024

use std::future::Future;

fn unit_return_and_async_block_type_mismatch() -> impl Future<Output = ()> {
//~^ ERROR: `()` is not a future [E0277]
if false {
return;
}
async {}
//~^ ERROR: mismatched types [E0308]
}

// should produce boxing suggestion
fn multiple_returns_same_future_output() -> impl Future<Output = ()> {
if false {
return async {};
}
async {}
//~^ ERROR: mismatched types [E0308]
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
error[E0277]: `()` is not a future
--> $DIR/return-type-mismatch-diagnostics-issue-162271.rs:5:51
|
LL | fn unit_return_and_async_block_type_mismatch() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
= help: the trait `Future` is not implemented for `()`

error[E0308]: mismatched types
--> $DIR/return-type-mismatch-diagnostics-issue-162271.rs:10:5
|
LL | fn unit_return_and_async_block_type_mismatch() -> impl Future<Output = ()> {
| ------------------------ expected a single type implementing `Future` because of return type
...
LL | return;
| ------ return type resolved to be `()`
LL | }
LL | async {}
| ^^^^^^^^ expected `()`, found `async` block
|
= note: expected unit type `()`
found `async` block `{async block@$DIR/return-type-mismatch-diagnostics-issue-162271.rs:10:5: 10:10}`

error[E0308]: mismatched types
--> $DIR/return-type-mismatch-diagnostics-issue-162271.rs:19:5
|
LL | fn multiple_returns_same_future_output() -> impl Future<Output = ()> {
| ------------------------ expected a single type implementing `Future` because of return type
LL | if false {
LL | return async {};
| --------
| |
| the expected `async` block
| return type resolved to be `{async block@$DIR/return-type-mismatch-diagnostics-issue-162271.rs:17:16: 17:21}`
LL | }
LL | async {}
| ^^^^^^^^ expected `async` block, found a different `async` block
|
= note: expected `async` block `{async block@$DIR/return-type-mismatch-diagnostics-issue-162271.rs:17:16: 17:21}`
found `async` block `{async block@$DIR/return-type-mismatch-diagnostics-issue-162271.rs:19:5: 19:10}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
help: you could change the return type to be a boxed trait object
|
LL - fn multiple_returns_same_future_output() -> impl Future<Output = ()> {
LL + fn multiple_returns_same_future_output() -> Box<dyn Future<Output = ()>> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
LL ~ return Box::new(async {});
LL | }
LL ~ Box::new(async {})
|

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/method-resolution5-deref-no-constrain.rs:20:5
|
LL | fn via_deref() -> impl Deref<Target = Foo> {
| --- expected `&Foo` because of return type
| ------------------------ expected a single type implementing `Deref` because of return type
...
LL | Box::new(Foo)
| ^^^^^^^^^^^^^ expected `&Foo`, found `Box<Foo>`
Expand Down
Loading