// File: cphinton42[P]hinton-language/src/check.cpp
// Function: typecheck_assign(Context*, unsigned int, Assign_AST*)
internal
bool typecheck_assign(Context *ctx, u32 stage, Assign_AST *assign_ast)
{
    u32 new_stage = 0;
    bool add_job = false;
    
    switch(stage)
    {
        case 0: {
            add_job = true;
        } // fall through
        case 1: {
            new_stage = 1;
            if(!type_resolved(assign_ast->lhs) && add_job)
            {
                auto job = make_typecheck_job(nullptr, assign_ast->lhs);
                do_typecheck_job(ctx, job);
            }
            if(!type_resolved(assign_ast->lhs))
            {
                break;
            }
            add_job = true;
        } // fall through
        case 2: {
            new_stage = 2;
            u16 lvalue_flags = assign_ast->lhs->flags & EXPR_FLAG_LVALUE_MASK;
            if(lvalue_flags == 0)
            {
                break;
            }
            else if(lvalue_flags == EXPR_FLAG_NOT_LVALUE)
            {
                report_error("LHS of assignment must be an lvalue", assign_ast);
                ctx->success = false;
                break;
            }
            else
            {
                assert(lvalue_flags == EXPR_FLAG_LVALUE);
            }
            add_job = true;
        } // fall through
        case 3: {
            new_stage = 3;
            
            switch(assign_ast->assign_type)
            {
                case Assign_Operator::equal: {
                    if(!type_resolved(assign_ast->rhs) && add_job)
                    {
                        auto job = make_typecheck_job(assign_ast->lhs->resolved_type, assign_ast->rhs);
                        do_typecheck_job(ctx, job);
                    }
                    if(!type_resolved(assign_ast->rhs))
                    {
                        goto finish;
                    }
                } break;
                
                // TODO:
                case Assign_Operator::mul_eq:
                case Assign_Operator::add_eq:
                case Assign_Operator::sub_eq:
                case Assign_Operator::div_eq: {
                    report_error("*=, +=, -=, /= currently unsupported by the typechecking system", assign_ast);
                    ctx->success = false;
                } break;
            }
            
            new_stage = 4;
        } // fall through
    }
    finish:
    
    if(new_stage < 4)
    {
        auto job = make_typecheck_job(nullptr, assign_ast, new_stage);
        array_add(ctx->waiting_jobs, job);
    }
    return new_stage != stage;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xf0, %rsp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movb $0x0, -0x1d(%rbp)
movl -0xc(%rbp), %eax
movq %rax, -0xd0(%rbp)
subq $0x3, %rax
ja 0x5b51
movq -0xd0(%rbp), %rax
leaq 0x1375d(%rip), %rcx     # 0x190b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, -0x1d(%rbp)
movl $0x1, -0x1c(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x59d3
testb $0x1, -0x1d(%rbp)
je 0x59d3
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdx
leaq -0x38(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %ecx, %ecx
callq 0x4a80
movq -0x8(%rbp), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x50(%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 -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x59e9
jmp 0x5b51
movb $0x1, -0x1d(%rbp)
movl $0x2, -0x1c(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movzwl 0x2(%rax), %eax
andl $0x30, %eax
movw %ax, -0x52(%rbp)
movzwl -0x52(%rbp), %eax
cmpl $0x0, %eax
jne 0x5a15
jmp 0x5b51
movzwl -0x52(%rbp), %eax
cmpl $0x20, %eax
jne 0x5a3b
movq -0x18(%rbp), %rsi
leaq 0x14e1c(%rip), %rdi     # 0x1a845
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
jmp 0x5b51
movzwl -0x52(%rbp), %eax
cmpl $0x10, %eax
jne 0x5a46
jmp 0x5a65
leaq 0x14e1c(%rip), %rdi     # 0x1a869
leaq 0x14498(%rip), %rsi     # 0x19eec
movl $0x150, %edx            # imm = 0x150
leaq 0x14e2a(%rip), %rcx     # 0x1a88a
callq 0x3080
jmp 0x5a67
jmp 0x5a69
movb $0x1, -0x1d(%rbp)
movl $0x3, -0x1c(%rbp)
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0xd8(%rbp)
testq %rax, %rax
je 0x5aa3
jmp 0x5a8a
movq -0xd8(%rbp), %rax
decq %rax
subq $0x4, %rax
jb 0x5b32
jmp 0x5b4a
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x5b1d
testb $0x1, -0x1d(%rbp)
je 0x5b1d
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movq 0x18(%rax), %rsi
movq -0x18(%rbp), %rax
movq 0x20(%rax), %rdx
leaq -0x70(%rbp), %rdi
xorl %ecx, %ecx
callq 0x4a80
movq -0x8(%rbp), %rdi
movq -0x70(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x78(%rbp)
leaq -0x88(%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 -0x18(%rbp), %rax
movq 0x20(%rax), %rdi
callq 0x5600
testb $0x1, %al
jne 0x5b30
jmp 0x5b53
jmp 0x5b4a
movq -0x18(%rbp), %rsi
leaq 0x14d81(%rip), %rdi     # 0x1a8be
callq 0x4950
movq -0x8(%rbp), %rax
movb $0x0, 0x10(%rax)
movl $0x4, -0x1c(%rbp)
jmp 0x5b53
cmpl $0x4, -0x1c(%rbp)
jae 0x5bf5
movq -0x18(%rbp), %rdx
movl -0x1c(%rbp), %ecx
leaq -0xa0(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x4a80
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0xa0(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq 0x1a0d3(%rip), %rax     # 0x1fc80
movq %rax, -0xc8(%rbp)
movq 0x1a0cd(%rip), %rax     # 0x1fc88
movq %rax, -0xc0(%rbp)
movq -0xc8(%rbp), %rsi
movq -0xc0(%rbp), %rdx
leaq -0xb8(%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 -0x1c(%rbp), %eax
cmpl -0xc(%rbp), %eax
setne %al
andb $0x1, %al
addq $0xf0, %rsp
popq %rbp
retq
nopl (%rax)