// File: /workspace/github_cpp_makefile_star2_O2/baziotis[P]minijava-cpp/typecheck.cpp
// Function: MainTypeCheckVisitor::visit(Method*, char const*)
void MainTypeCheckVisitor::visit(Method *method, const char *class_name) {
    LOG_SCOPE;
    debug_print("MainTypeCheck::Method %s\n", method->id);
    this->curr_method = method;

    __expr_context.method = method;

    bool is_main_method = method->id == main_method_string;

    cgen_start_method(method, class_name, is_main_method);

    if (is_main_method && type_transitively_extends_Main(this, class_name))
    {
        typecheck_error(method->loc, "In type: `", class_name,
                        "` you can't name a method `main` because "
                        "the type transitively extends `Main` class.");
    }

    for (int i = 0; i < __expr_context.nesting_level; ++i) {
      for (int j = 0; j < __expr_context.if_bufs[i].len; ++j) {
        __expr_context.if_bufs[i][j].assigned = false;
      }
      for (int j = 0; j < __expr_context.else_bufs[i].len; ++j) {
        __expr_context.else_bufs[i][j].assigned = false;
      }
    }
    __expr_context.nesting_level = 0;


    for (Statement *stmt : method->stmts) {
        stmt->accept(this);
    }
    // An undefined return expression may actually end up here.
    // Check parse.cpp
    // A null expression may also come here because of the `main()` method.
    if (!is_main_method && !method->ret_expr->is_undefined()) {
        assert(method->ret_expr);
        Type *ret_type = method->ret_expr->accept(this);
        if (ret_type->kind != TY::UNDEFINED) {
          assert(ret_type);
          assert(method->ret_type);
          llvalue_t ret_val = __expr_context.llval;
          if (!compatible_types(method->ret_type, ret_type)) {
              location_t loc_here = method->ret_expr->loc;
              typecheck_error(loc_here, "The type: `", ret_type->name(),
                              "` of the return expression does not match the ",
                              "return type: `", method->ret_type->name(),
                              "` of method: `", method->id, "`");
          } else {
              llvm_ret(ret_type, ret_val);
          }
        }
    }
    this->curr_method = NULL;

    cgen_end_method(is_main_method);

    // Free arena for objects of function lifetime
    deallocate(MEM::FUNC);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rdx, %r15
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x27(%rsp), %rdi
callq 0x3108
movq (%r14), %rsi
leaq 0x7f0e(%rip), %rdi      # 0x10927
xorl %eax, %eax
callq 0x317b
movq %r14, 0x78(%rbx)
leaq 0xff8d(%rip), %rbp      # 0x189b8
movq %r14, 0x28(%rbp)
movq (%r14), %r13
leaq 0x1000f(%rip), %rax     # 0x18a48
movq (%rax), %r12
xorl %edx, %edx
cmpq %r12, %r13
sete %dl
movq %r14, %rdi
movq %r15, %rsi
callq 0x51d0
cmpq %r12, %r13
jne 0x8a9a
leaq 0x30(%rbx), %rdi
movq %r15, %rsi
callq 0xd46e
testq %rax, %rax
je 0x8c6d
movq 0x20(%rbx), %rcx
movq 0x8(%rcx), %rcx
movq 0x78(%rax), %rax
testq %rax, %rax
je 0x8a9a
cmpq %rcx, 0x8(%rax)
jne 0x8a71
movl 0x50(%r14), %edi
leaq 0x7eb6(%rip), %rsi      # 0x10941
leaq 0x7eba(%rip), %rcx      # 0x1094c
movq %r15, %rdx
callq 0x836b
movl 0x30(%rbp), %eax
movq 0x50(%rbp), %rcx
movq 0x68(%rbp), %rdx
xorl %esi, %esi
testl %eax, %eax
cmovlel %esi, %eax
pushq $0x20
popq %rdi
cmpq %rax, %rsi
je 0x8aff
imulq $0x18, %rsi, %r8
leaq (%rcx,%r8), %r9
movq 0x8(%rcx,%r8), %r10
movq %rdi, %r11
subq $0x1, %r10
jb 0x8ad9
movq 0x10(%r9), %r15
movb $0x0, (%r15,%r11)
addq $0x28, %r11
jmp 0x8ac4
leaq (%rdx,%r8), %r9
movq 0x8(%rdx,%r8), %r8
movq %rdi, %r10
subq $0x1, %r8
jb 0x8afa
movq 0x10(%r9), %r11
movb $0x0, (%r11,%r10)
addq $0x28, %r10
jmp 0x8ae5
incq %rsi
jmp 0x8aaf
movq %r12, 0x30(%rsp)
movq %r13, %r12
andl $0x0, 0x30(%rbp)
movq 0x60(%r14), %r15
movq 0x68(%r14), %rbp
shlq $0x3, %r15
xorl %r13d, %r13d
cmpq %r13, %r15
je 0x8b33
movq (%rbp,%r13), %rdi
movq (%rdi), %rax
movq %rbx, %rsi
callq *0x18(%rax)
addq $0x8, %r13
jmp 0x8b1a
movq %r12, %r13
movq 0x30(%rsp), %r12
cmpq %r12, %r13
leaq 0xfe73(%rip), %rbp      # 0x189b8
je 0x8c39
movq 0x70(%r14), %rsi
cmpl $0x0, 0x4(%rsi)
je 0x8c39
movq %rbx, %rdi
callq 0x8d10
movq %rax, %r15
cmpl $0x0, 0x4(%rax)
je 0x8c39
movq 0x8(%r14), %rdi
testq %rdi, %rdi
je 0x8c8c
movq %r15, %rsi
callq 0x8cc8
testb %al, %al
je 0x8ba5
movups 0x8(%rbp), %xmm0
movups 0x18(%rbp), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
movq %r15, %rdi
callq 0x540f
jmp 0x8c39
movq 0x70(%r14), %rax
movl (%rax), %ebp
movq %r15, %rdi
callq 0x7572
movq %rax, %r15
movq 0x8(%r14), %rdi
callq 0x7572
movq %rax, 0x28(%rsp)
movq (%r14), %r14
incl 0x11ebb(%rip)           # 0x1aa88
movl %ebp, %edi
callq 0xc769
callq 0xc783
callq 0xc79f
leaq 0x8fec(%rip), %rdi      # 0x11bd1
callq 0xc7bb
callq 0xc7cc
callq 0xc7e8
leaq 0x7df0(%rip), %rdi      # 0x109eb
callq 0xc7bb
movq %r15, %rdi
callq 0xc7bb
leaq 0x7de8(%rip), %rdi      # 0x109f7
leaq 0x7e10(%rip), %rsi      # 0x10a26
leaq 0x7e18(%rip), %rcx      # 0x10a35
leaq 0x6dbd(%rip), %r9       # 0xf9e1
movq 0x28(%rsp), %rdx
movq %r14, %r8
callq 0xc88c
pushq $0xa
popq %rdi
callq 0x2160
xorl %edi, %edi
cmpq %r12, %r13
sete %dil
andq $0x0, 0x78(%rbx)
callq 0x5316
pushq $0x4
popq %rdi
callq 0x23f5
leaq 0x27(%rsp), %rdi
callq 0x311c
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x7f8d(%rip), %rdi      # 0x10c01
leaq 0x7773(%rip), %rsi      # 0x103ee
leaq 0x8d6f(%rip), %rcx      # 0x119f1
movl $0x30f, %edx            # imm = 0x30F
callq 0x20b0
leaq 0x7d47(%rip), %rdi      # 0x109da
leaq 0x7754(%rip), %rsi      # 0x103ee
leaq 0x7d00(%rip), %rcx      # 0x109a1
movl $0x342, %edx            # imm = 0x342
callq 0x20b0
jmp 0x8cb3
jmp 0x8cb3
jmp 0x8cb3
jmp 0x8cb3
movq %rax, %rbx
leaq 0x27(%rsp), %rdi
callq 0x311c
movq %rbx, %rdi
callq 0x21c0