rusty_javac/bytecode/
method_gen.rs1use 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}