Skip to content

Commit d91858b

Browse files
authored
Rollup merge of rust-lang#109248 - compiler-errors:get_fn_decl-aaa, r=WaffleLapkin
Pass the right HIR back from `get_fn_decl` Fixes rust-lang#109232 Makes sure that the `fn_id: HirId` that we pass to `suggest_missing_return_type` matches up with the `fn_decl: hir::FnDecl` that we pass to it, so the late-bound vars that we fetch from the former match up with the types in the latter... This HIR suggestion code really needs a big refactor. I've tried to do it in the past (a couple of attempts), but it's a super tangled mess. It really shouldn't be passing around things like `hir::Node` and just deal with `LocalDefId`s everywhere... Anyways, I'd rather fix this ICE, now.
2 parents 2a3c0e3 + 08c9132 commit d91858b

File tree

8 files changed

+75
-36
lines changed

8 files changed

+75
-36
lines changed

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
299299
{
300300
// check that the `if` expr without `else` is the fn body's expr
301301
if expr.span == sp {
302-
return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
302+
return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| {
303303
let span = fn_decl.output.span();
304304
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
305305
Some((span, format!("expected `{snippet}` because of this return type")))

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,20 +1722,21 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
17221722
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
17231723
}
17241724
}
1725-
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
1725+
fcx.get_node_fn_decl(parent)
1726+
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
17261727
} else {
17271728
fcx.get_fn_decl(parent_id)
17281729
};
17291730

1730-
if let Some((fn_decl, can_suggest)) = fn_decl {
1731+
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
17311732
if blk_id.is_none() {
17321733
pointing_at_return_type |= fcx.suggest_missing_return_type(
17331734
&mut err,
17341735
&fn_decl,
17351736
expected,
17361737
found,
17371738
can_suggest,
1738-
fcx.tcx.hir().get_parent_item(id).into(),
1739+
fn_id,
17391740
);
17401741
}
17411742
if !pointing_at_return_type {
@@ -1746,17 +1747,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
17461747
let parent_id = fcx.tcx.hir().get_parent_item(id);
17471748
let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
17481749

1749-
if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
1750+
if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
17501751
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
17511752
{
17521753
fcx.suggest_missing_break_or_return_expr(
1753-
&mut err,
1754-
expr,
1755-
fn_decl,
1756-
expected,
1757-
found,
1758-
id,
1759-
parent_id.into(),
1754+
&mut err, expr, fn_decl, expected, found, id, fn_id,
17601755
);
17611756
}
17621757

@@ -1882,7 +1877,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
18821877
}
18831878

18841879
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
1885-
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
1880+
if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
18861881
&& let hir::FnRetTy::Return(ty) = fn_decl.output
18871882
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
18881883
&& let ty::Dynamic(..) = ty.kind()

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
788788
self.ret_coercion_span.set(Some(expr.span));
789789
}
790790
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
791-
if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
791+
if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
792792
coercion.coerce_forced_unit(
793793
self,
794794
&cause,

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -898,51 +898,74 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
898898
)
899899
}
900900

901-
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
901+
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
902+
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
903+
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
904+
/// for example, where most of the type checking actually happens within a nested closure,
905+
/// but we often want access to the parent function's signature.
906+
///
907+
/// Otherwise, return false.
902908
pub(in super::super) fn get_node_fn_decl(
903909
&self,
904910
node: Node<'tcx>,
905-
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
911+
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
906912
match node {
907-
Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
913+
Node::Item(&hir::Item {
914+
ident,
915+
kind: hir::ItemKind::Fn(ref sig, ..),
916+
owner_id,
917+
..
918+
}) => {
908919
// This is less than ideal, it will not suggest a return type span on any
909920
// method called `main`, regardless of whether it is actually the entry point,
910921
// but it will still present it as the reason for the expected type.
911-
Some((&sig.decl, ident, ident.name != sym::main))
922+
Some((
923+
hir::HirId::make_owner(owner_id.def_id),
924+
&sig.decl,
925+
ident,
926+
ident.name != sym::main,
927+
))
912928
}
913929
Node::TraitItem(&hir::TraitItem {
914930
ident,
915931
kind: hir::TraitItemKind::Fn(ref sig, ..),
932+
owner_id,
916933
..
917-
}) => Some((&sig.decl, ident, true)),
934+
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
918935
Node::ImplItem(&hir::ImplItem {
919936
ident,
920937
kind: hir::ImplItemKind::Fn(ref sig, ..),
938+
owner_id,
921939
..
922-
}) => Some((&sig.decl, ident, false)),
923-
Node::Expr(&hir::Expr {
924-
hir_id,
925-
kind: hir::ExprKind::Closure(..),
926-
..
927-
}) if let Some(Node::Item(&hir::Item {
940+
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
941+
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
942+
if let Some(Node::Item(&hir::Item {
943+
ident,
944+
kind: hir::ItemKind::Fn(ref sig, ..),
945+
owner_id,
946+
..
947+
})) = self.tcx.hir().find_parent(hir_id) => Some((
948+
hir::HirId::make_owner(owner_id.def_id),
949+
&sig.decl,
928950
ident,
929-
kind: hir::ItemKind::Fn(ref sig, ..),
930-
..
931-
})) = self.tcx.hir().find_parent(hir_id) => {
932-
Some((&sig.decl, ident, ident.name != sym::main))
933-
},
951+
ident.name != sym::main,
952+
)),
934953
_ => None,
935954
}
936955
}
937956

938-
/// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
957+
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
939958
/// suggestion can be made, `None` otherwise.
940-
pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
959+
pub fn get_fn_decl(
960+
&self,
961+
blk_id: hir::HirId,
962+
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
941963
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
942964
// `while` before reaching it, as block tail returns are not available in them.
943965
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
944966
let parent = self.tcx.hir().get(blk_id);
945-
self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
967+
self.get_node_fn_decl(parent)
968+
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
946969
})
947970
}
948971

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16691669
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
16701670
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
16711671
let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
1672-
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
1672+
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
16731673
}
16741674

16751675
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6464
let expr = expr.peel_drop_temps();
6565
self.suggest_missing_semicolon(err, expr, expected, false);
6666
let mut pointing_at_return_type = false;
67-
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
68-
let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
67+
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
6968
pointing_at_return_type = self.suggest_missing_return_type(
7069
err,
7170
&fn_decl,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// edition: 2021
2+
3+
// Make sure we don't ICE when suggesting a return type
4+
// for an async fn that has late-bound vars...
5+
6+
async fn ice(_: &i32) {
7+
true
8+
//~^ ERROR mismatched types
9+
}
10+
11+
fn main() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/suggest-ret-on-async-w-late.rs:7:5
3+
|
4+
LL | async fn ice(_: &i32) {
5+
| - help: try adding a return type: `-> bool`
6+
LL | true
7+
| ^^^^ expected `()`, found `bool`
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)