Skip to main content

rusty_javac/bytecode/
method_gen.rs

1use crate::bytecode::codegen::CodegenCtx;
2use crate::bytecode::expr_gen::push_default_value;
3use crate::bytecode::local_var::return_opcode;
4use crate::classfile::MethodWriter;
5use crate::hir::*;
6use crate::ty::Ty;
7
8pub fn gen_method_body(mw: &mut MethodWriter, ctx: &mut CodegenCtx, body: &Body, block: &Block) {
9    for stmt_id in &block.stmts {
10        crate::bytecode::stmt_gen::gen_stmt(mw, ctx, body, *stmt_id);
11    }
12    if !block_definitely_exits(body, block) {
13        emit_default_return(mw, &ctx.return_ty);
14    }
15}
16
17fn block_definitely_exits(body: &Body, block: &Block) -> bool {
18    block
19        .stmts
20        .last()
21        .map(|stmt| stmt_definitely_exits(body, *stmt))
22        .unwrap_or(false)
23}
24
25fn stmt_definitely_exits(body: &Body, stmt_id: StmtId) -> bool {
26    match &body.stmts[stmt_id] {
27        Stmt::Return(_) | Stmt::Throw(_) => true,
28        Stmt::Block(block) => block_definitely_exits(body, block),
29        Stmt::If {
30            then_branch,
31            else_branch: Some(else_branch),
32            ..
33        } => stmt_definitely_exits(body, *then_branch) && stmt_definitely_exits(body, *else_branch),
34        Stmt::Try(try_stmt) => {
35            if try_stmt
36                .finally
37                .as_ref()
38                .is_some_and(|finally| block_definitely_exits(body, finally))
39            {
40                return true;
41            }
42            block_definitely_exits(body, &try_stmt.body)
43                && try_stmt
44                    .catches
45                    .iter()
46                    .all(|catch| block_definitely_exits(body, &catch.body))
47        }
48        Stmt::Labeled { body: stmt, .. } => stmt_definitely_exits(body, *stmt),
49        _ => false,
50    }
51}
52
53fn emit_default_return(mw: &mut MethodWriter, ty: &Ty) {
54    push_default_value(mw, ty);
55    mw.visit_insn(return_opcode(ty));
56}