// File: cphinton42[P]hinton-language/src/check.cpp
// Function: typecheck_function_call(Context*, unsigned int, Expr_AST*, Function_Call_AST*)
internal
bool typecheck_function_call(Context *ctx, u32 stage, Expr_AST *type, Function_Call_AST *function_call_ast)
{
    u32 new_stage = 0;
    bool add_job = false;
    
    switch(stage)
    {
        case 0: {
            function_call_ast->flags |= EXPR_FLAG_NOT_LVALUE;
            add_job = true;
        } // fall through
        case 1: {
            new_stage = 1;
            auto function = function_call_ast->function;
            if(!type_resolved(function) && add_job)
            {
                // TODO: this will need to be souped-up for overloading
                // Note: no overloading based on return type, hence the nullptr
                auto job = make_typecheck_job(nullptr, function);
                do_typecheck_job(ctx, job);
            }
            if(!type_resolved(function))
            {
                break;
            }
            add_job = true;
        } // fall through
        case 2: {
            new_stage = 2;
            Expr_AST *func_type = function_call_ast->function->resolved_type;
            Expr_AST *reduced_type;
            Status status = reduce_type(ctx, func_type, &reduced_type);
            if(status != Status::good)
            {
                break;
            }
            if(reduced_type->type != AST_Type::function_type_ast)
            {
                report_error("Expected function\n", function_call_ast->function);
                ctx->success = false;
                break;
            }
            Function_Type_AST *function_type = static_cast<Function_Type_AST*>(reduced_type);
            auto return_types = function_type->return_types;
            for(u64 i = 0; i < return_types.count; ++i)
            {
                if(!type_resolved(return_types[i]))
                {
                    goto finish;
                }
            }
            // TODO support multiple return types
            set_resolved_type(function_call_ast, return_types[0]);
            
            auto param_types = function_type->parameter_types;
            for(u64 i = 0; i < param_types.count; ++i)
            {
                if(!type_resolved(param_types[i]))
                {
                    goto finish;
                }
            }
            // TODO: varargs and named arguments
            auto args = function_call_ast->args;
            if(args.count != param_types.count)
            {
                report_error("Bad number of arguments", function_call_ast);
                ctx->success = false;
                break;
            }
            
            for(u64 i = 0; i < param_types.count; ++i)
            {
                auto job = make_typecheck_job(param_types[i], args[i]);
                do_typecheck_job(ctx, job);
            }
            new_stage = 3;
        } // fall through
    }
    finish:
    
    if(new_stage < 3)
    {
        auto job = make_typecheck_job(type, function_call_ast, new_stage);
        array_add(ctx->waiting_jobs, job);
    }
    return new_stage != stage;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl $0x0, -0x24(%rbp)
movb $0x0, -0x25(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x13c(%rbp)
testl %eax, %eax
je 0x6a65
jmp 0x6a44
movl -0x13c(%rbp), %eax
subl $0x1, %eax
je 0x6a78
jmp 0x6a51
movl -0x13c(%rbp), %eax
subl $0x2, %eax
je 0x6b05
jmp 0x6d95
movq -0x20(%rbp), %rax
movzwl 0x2(%rax), %ecx
orl $0x20, %ecx
movw %cx, 0x2(%rax)
movb $0x1, -0x25(%rbp)
movl $0x1, -0x24(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6aef
testb $0x1, -0x25(%rbp)
je 0x6aef
movq -0x30(%rbp), %rdx
leaq -0x48(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %ecx, %ecx
callq 0x4a80
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x60(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x4b40
movq -0x30(%rbp), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6b01
jmp 0x6d95
movb $0x1, -0x25(%rbp)
movl $0x2, -0x24(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x18(%rax), %rax
movq %rax, -0x68(%rbp)
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
leaq -0x70(%rbp), %rdx
callq 0x9040
movl %eax, -0x74(%rbp)
cmpl $0x0, -0x74(%rbp)
je 0x6b3b
jmp 0x6d95
movq -0x70(%rbp), %rax
cmpw $0x8, (%rax)
je 0x6b66
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rsi
leaq 0x13e34(%rip), %rdi     # 0x1a988
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x6d95
movq -0x70(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rax
movq 0x30(%rax), %rcx
movq %rcx, -0x90(%rbp)
movq 0x38(%rax), %rax
movq %rax, -0x88(%rbp)
movq $0x0, -0x98(%rbp)
movq -0x98(%rbp), %rax
cmpq -0x90(%rbp), %rax
jae 0x6bdd
movq -0x98(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x17050
movq (%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6bc7
jmp 0x6d97
jmp 0x6bc9
movq -0x98(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x98(%rbp)
jmp 0x6b93
movq -0x20(%rbp), %rax
movq %rax, -0x148(%rbp)
leaq -0x90(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x17050
movq -0x148(%rbp), %rdi
movq (%rax), %rsi
callq 0x3be0
movq -0x80(%rbp), %rax
movq 0x20(%rax), %rcx
movq %rcx, -0xa8(%rbp)
movq 0x28(%rax), %rax
movq %rax, -0xa0(%rbp)
movq $0x0, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
cmpq -0xa8(%rbp), %rax
jae 0x6c76
movq -0xb0(%rbp), %rsi
leaq -0xa8(%rbp), %rdi
callq 0x17050
movq (%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x6c60
jmp 0x6d97
jmp 0x6c62
movq -0xb0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
jmp 0x6c2c
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rcx
movq %rcx, -0xc0(%rbp)
movq 0x30(%rax), %rax
movq %rax, -0xb8(%rbp)
movq -0xc0(%rbp), %rax
cmpq -0xa8(%rbp), %rax
je 0x6cbd
movq -0x20(%rbp), %rsi
leaq 0x13cf0(%rip), %rdi     # 0x1a99b
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x6d95
movq $0x0, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpq -0xa8(%rbp), %rax
jae 0x6d8e
movq -0xc8(%rbp), %rsi
leaq -0xa8(%rbp), %rdi
callq 0x17050
movq (%rax), %rax
movq %rax, -0x150(%rbp)
movq -0xc8(%rbp), %rsi
leaq -0xc0(%rbp), %rdi
callq 0x17050
movq -0x150(%rbp), %rsi
movq (%rax), %rdx
leaq -0xe0(%rbp), %rdi
xorl %ecx, %ecx
callq 0x4a80
movq -0x8(%rbp), %rdi
movq -0xe0(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xd8(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq -0xd0(%rbp), %rax
movq %rax, -0xe8(%rbp)
leaq -0xf8(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x4b40
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0x6cc8
movl $0x3, -0x24(%rbp)
jmp 0x6d97
cmpl $0x3, -0x24(%rbp)
jae 0x6e39
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
movl -0x24(%rbp), %ecx
leaq -0x110(%rbp), %rdi
callq 0x4a80
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x110(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0x108(%rbp), %rax
movq %rax, -0x120(%rbp)
movq -0x100(%rbp), %rax
movq %rax, -0x118(%rbp)
movq 0x18e8f(%rip), %rax     # 0x1fc80
movq %rax, -0x138(%rbp)
movq 0x18e89(%rip), %rax     # 0x1fc88
movq %rax, -0x130(%rbp)
movq -0x138(%rbp), %rsi
movq -0x130(%rbp), %rdx
leaq -0x128(%rbp), %rax
movq (%rax), %rcx
movq %rcx, (%rsp)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0x17c30
movl -0x24(%rbp), %eax
cmpl -0xc(%rbp), %eax
setne %al
andb $0x1, %al
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
nopl (%rax)