Skip to content

Commit 354d48e

Browse files
Inline get_node_fn_decl into get_fn_decl, simplify/explain logic in report_return_mismatched_types
1 parent 5179676 commit 354d48e

9 files changed

+117
-119
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

+10-23
Original file line numberDiff line numberDiff line change
@@ -1994,39 +1994,26 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
19941994
}
19951995
};
19961996

1997+
// If this is due to an explicit `return`, suggest adding a return type.
19971998
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
19981999
&& !due_to_block
19992000
{
20002001
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
20012002
}
20022003

2003-
let mut parent_id = fcx.tcx.hir().get_parent_item(block_or_return_id).def_id;
2004-
let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
2005-
// When suggesting return, we need to account for closures and async blocks, not just items.
2006-
// FIXME: fix get_fn_decl to be async block aware, use get_fn_decl results above
2007-
for (_, node) in fcx.tcx.hir().parent_iter(block_or_return_id) {
2008-
match node {
2009-
hir::Node::Expr(&hir::Expr {
2010-
kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
2011-
..
2012-
}) => {
2013-
parent_item = node;
2014-
parent_id = *def_id;
2015-
break;
2016-
}
2017-
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
2018-
_ => {}
2019-
}
2020-
}
2021-
2022-
if let Some(expr) = expression
2023-
&& let Some(fn_decl) = parent_item.fn_decl()
2024-
&& due_to_block
2004+
// If this is due to a block, then maybe we forgot a `return`/`break`.
2005+
if due_to_block
2006+
&& let Some(expr) = expression
2007+
&& let Some((parent_fn_decl, parent_id)) = fcx
2008+
.tcx
2009+
.hir()
2010+
.parent_iter(block_or_return_id)
2011+
.find_map(|(_, node)| Some((node.fn_decl()?, node.associated_body()?.0)))
20252012
{
20262013
fcx.suggest_missing_break_or_return_expr(
20272014
&mut err,
20282015
expr,
2029-
fn_decl,
2016+
parent_fn_decl,
20302017
expected,
20312018
found,
20322019
block_or_return_id,

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+67-75
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
3333
use rustc_session::lint;
3434
use rustc_span::def_id::LocalDefId;
3535
use rustc_span::hygiene::DesugaringKind;
36-
use rustc_span::symbol::{kw, sym, Ident};
36+
use rustc_span::symbol::{kw, sym};
3737
use rustc_span::Span;
3838
use rustc_target::abi::FieldIdx;
3939
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -910,76 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
910910
)
911911
}
912912

913-
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
914-
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
915-
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
916-
/// for example, where most of the type checking actually happens within a nested closure,
917-
/// but we often want access to the parent function's signature.
918-
///
919-
/// Otherwise, return false.
920-
pub(in super::super) fn get_node_fn_decl(
921-
&self,
922-
node: Node<'tcx>,
923-
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
924-
match node {
925-
Node::Item(&hir::Item {
926-
ident,
927-
kind: hir::ItemKind::Fn(ref sig, ..),
928-
owner_id,
929-
..
930-
}) => {
931-
// This is less than ideal, it will not suggest a return type span on any
932-
// method called `main`, regardless of whether it is actually the entry point,
933-
// but it will still present it as the reason for the expected type.
934-
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
935-
}
936-
Node::TraitItem(&hir::TraitItem {
937-
ident,
938-
kind: hir::TraitItemKind::Fn(ref sig, ..),
939-
owner_id,
940-
..
941-
}) => Some((owner_id.def_id, &sig.decl, ident, true)),
942-
Node::ImplItem(&hir::ImplItem {
943-
ident,
944-
kind: hir::ImplItemKind::Fn(ref sig, ..),
945-
owner_id,
946-
..
947-
}) => Some((owner_id.def_id, &sig.decl, ident, false)),
948-
Node::Expr(&hir::Expr {
949-
hir_id,
950-
kind:
951-
hir::ExprKind::Closure(hir::Closure {
952-
kind: hir::ClosureKind::Coroutine(..), ..
953-
}),
954-
..
955-
}) => {
956-
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
957-
Node::Item(&hir::Item {
958-
ident,
959-
kind: hir::ItemKind::Fn(ref sig, ..),
960-
owner_id,
961-
..
962-
}) => (ident, sig, owner_id),
963-
Node::TraitItem(&hir::TraitItem {
964-
ident,
965-
kind: hir::TraitItemKind::Fn(ref sig, ..),
966-
owner_id,
967-
..
968-
}) => (ident, sig, owner_id),
969-
Node::ImplItem(&hir::ImplItem {
970-
ident,
971-
kind: hir::ImplItemKind::Fn(ref sig, ..),
972-
owner_id,
973-
..
974-
}) => (ident, sig, owner_id),
975-
_ => return None,
976-
};
977-
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
978-
}
979-
_ => None,
980-
}
981-
}
982-
983913
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
984914
/// suggestion can be made, `None` otherwise.
985915
pub fn get_fn_decl(
@@ -988,10 +918,72 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
988918
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
989919
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
990920
// `while` before reaching it, as block tail returns are not available in them.
991-
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|blk_id| {
992-
let parent = self.tcx.hir_node(blk_id);
993-
self.get_node_fn_decl(parent)
994-
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
921+
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
922+
match self.tcx.hir_node(item_id) {
923+
Node::Item(&hir::Item {
924+
ident,
925+
kind: hir::ItemKind::Fn(ref sig, ..),
926+
owner_id,
927+
..
928+
}) => {
929+
// This is less than ideal, it will not suggest a return type span on any
930+
// method called `main`, regardless of whether it is actually the entry point,
931+
// but it will still present it as the reason for the expected type.
932+
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
933+
}
934+
Node::TraitItem(&hir::TraitItem {
935+
kind: hir::TraitItemKind::Fn(ref sig, ..),
936+
owner_id,
937+
..
938+
}) => Some((owner_id.def_id, sig.decl, true)),
939+
// FIXME: Suggestable if this is not a trait implementation
940+
Node::ImplItem(&hir::ImplItem {
941+
kind: hir::ImplItemKind::Fn(ref sig, ..),
942+
owner_id,
943+
..
944+
}) => Some((owner_id.def_id, sig.decl, false)),
945+
Node::Expr(&hir::Expr {
946+
hir_id,
947+
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
948+
..
949+
}) => {
950+
match kind {
951+
hir::ClosureKind::CoroutineClosure(_) => {
952+
// FIXME(async_closures): Implement this.
953+
return None;
954+
}
955+
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
956+
_,
957+
hir::CoroutineSource::Fn,
958+
)) => {
959+
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
960+
Node::Item(&hir::Item {
961+
ident,
962+
kind: hir::ItemKind::Fn(ref sig, ..),
963+
owner_id,
964+
..
965+
}) => (ident, sig, owner_id),
966+
Node::TraitItem(&hir::TraitItem {
967+
ident,
968+
kind: hir::TraitItemKind::Fn(ref sig, ..),
969+
owner_id,
970+
..
971+
}) => (ident, sig, owner_id),
972+
Node::ImplItem(&hir::ImplItem {
973+
ident,
974+
kind: hir::ImplItemKind::Fn(ref sig, ..),
975+
owner_id,
976+
..
977+
}) => (ident, sig, owner_id),
978+
_ => return None,
979+
};
980+
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
981+
}
982+
_ => Some((def_id, fn_decl, true)),
983+
}
984+
}
985+
_ => None,
986+
}
995987
})
996988
}
997989

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+7
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
799799
can_suggest: bool,
800800
fn_id: LocalDefId,
801801
) -> bool {
802+
// Can't suggest `->` on a block-like coroutine
803+
if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
804+
self.tcx.coroutine_kind(fn_id)
805+
{
806+
return false;
807+
}
808+
802809
let found =
803810
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
804811
// Only suggest changing the return type for methods that

tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ LL | | }
1111
error[E0308]: mismatched types
1212
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9
1313
|
14+
LL | call(|| -> Option<()> {
15+
| ---------- expected `Option<()>` because of return type
16+
...
1417
LL | true
1518
| ^^^^ expected `Option<()>`, found `bool`
1619
|

tests/ui/closures/closure-return-type-mismatch.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ LL | return "test";
1313
error[E0308]: mismatched types
1414
--> $DIR/closure-return-type-mismatch.rs:12:20
1515
|
16+
LL | || -> bool {
17+
| ---- expected `bool` because of return type
18+
LL | if false {
1619
LL | return "hello"
1720
| ^^^^^^^ expected `bool`, found `&str`
1821

tests/ui/impl-trait/issue-99914.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/issue-99914.rs:9:27
33
|
44
LL | t.and_then(|t| -> _ { bar(t) });
5-
| ^^^^^^ expected `Result<_, Error>`, found future
5+
| - ^^^^^^ expected `Result<_, Error>`, found future
6+
| |
7+
| expected `Result<_, Error>` because of return type
68
|
79
help: try wrapping the expression in `Ok`
810
|

tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
fn main() -> Result<(), ()> {
55
a(|| {
6+
//~^ HELP: try adding a return type
67
b()
78
//~^ ERROR: mismatched types [E0308]
89
//~| NOTE: expected `()`, found `i32`

tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
error[E0308]: mismatched types
2-
--> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
2+
--> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
33
|
44
LL | b()
5-
| ^^^- help: consider using a semicolon here: `;`
6-
| |
7-
| expected `()`, found `i32`
5+
| ^^^ expected `()`, found `i32`
6+
|
7+
help: consider using a semicolon here
8+
|
9+
LL | b();
10+
| +
11+
help: try adding a return type
12+
|
13+
LL | a(|| -> i32 {
14+
| ++++++
815

916
error[E0308]: mismatched types
10-
--> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
17+
--> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
1118
|
1219
LL | / if true {
1320
LL | |

tests/ui/typeck/issue-81943.stderr

+11-15
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,32 @@ error[E0308]: mismatched types
22
--> $DIR/issue-81943.rs:7:9
33
|
44
LL | f(|x| lib::d!(x));
5-
| ^^^^^^^^^^ expected `()`, found `i32`
5+
| -^^^^^^^^^^ expected `()`, found `i32`
6+
| |
7+
| help: try adding a return type: `-> i32`
68
|
79
= note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
810

911
error[E0308]: mismatched types
1012
--> $DIR/issue-81943.rs:8:28
1113
|
1214
LL | f(|x| match x { tmp => { g(tmp) } });
13-
| -------------------^^^^^^----
14-
| | |
15-
| | expected `()`, found `i32`
16-
| expected this to be `()`
15+
| ^^^^^^ expected `()`, found `i32`
1716
|
1817
help: consider using a semicolon here
1918
|
2019
LL | f(|x| match x { tmp => { g(tmp); } });
2120
| +
22-
help: consider using a semicolon here
21+
help: try adding a return type
2322
|
24-
LL | f(|x| match x { tmp => { g(tmp) } };);
25-
| +
23+
LL | f(|x| -> i32 match x { tmp => { g(tmp) } });
24+
| ++++++
2625

2726
error[E0308]: mismatched types
2827
--> $DIR/issue-81943.rs:10:38
2928
|
3029
LL | ($e:expr) => { match $e { x => { g(x) } } }
31-
| ------------------^^^^----
32-
| | |
33-
| | expected `()`, found `i32`
34-
| expected this to be `()`
30+
| ^^^^ expected `()`, found `i32`
3531
LL | }
3632
LL | f(|x| d!(x));
3733
| ----- in this macro invocation
@@ -41,10 +37,10 @@ help: consider using a semicolon here
4137
|
4238
LL | ($e:expr) => { match $e { x => { g(x); } } }
4339
| +
44-
help: consider using a semicolon here
40+
help: try adding a return type
4541
|
46-
LL | ($e:expr) => { match $e { x => { g(x) } }; }
47-
| +
42+
LL | f(|x| -> i32 d!(x));
43+
| ++++++
4844

4945
error: aborting due to 3 previous errors
5046

0 commit comments

Comments
 (0)