// File: /workspace/github_cpp_makefile_star2_O3/cphinton42[P]hinton-language/src/check.cpp
// Function: types_match(Context*, Expr_AST*, Expr_AST*, bool)
Status types_match(Context *ctx, Expr_AST *t1, Expr_AST *t2, bool report)
{
    if(!t1 || !t2)
    {
        return Status::good;
    }
    
    Expr_AST *lhs, *rhs;
    Status status = reduce_type(ctx, t1, &lhs);
    if(status != Status::good)
    {
        return status;
    }
    status = reduce_type(ctx, t2, &rhs);
    if(status != Status::good)
    {
        return status;
    }
    
    switch(lhs->type)
    {
        case AST_Type::function_type_ast: {
            if(rhs->type != AST_Type::function_type_ast)
            {
                if(report)
                {
                    report_error("Function type vs non-function type", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
            Function_Type_AST *lhs_func = static_cast<Function_Type_AST*>(lhs);
            Function_Type_AST *rhs_func = static_cast<Function_Type_AST*>(rhs);
            
            if(lhs_func->parameter_types.count != rhs_func->parameter_types.count)
            {
                if(report)
                {
                    report_error("Function types do not have same number of parameters", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
            if(lhs_func->return_types.count != rhs_func->return_types.count)
            {
                if(report)
                {
                    report_error("Function types do not have same number of return values", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
            
            for(u64 i = 0; i < lhs_func->parameter_types.count; ++i)
            {
                status = types_match(ctx, lhs_func->parameter_types[i], rhs_func->parameter_types[i], report);
                if(status != Status::good)
                {
                    return status;
                }
            }
            for(u64 i = 0; i < lhs_func->return_types.count; ++i)
            {
                status = types_match(ctx, lhs_func->return_types[i], rhs_func->return_types[i], report);
                if(status != Status::good)
                {
                    return status;
                }
            }
        } break;
        case AST_Type::enum_ast: {
            if(lhs != rhs)
            {
                if(report)
                {
                    report_error("Mismatching enums", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
        } break;
        case AST_Type::struct_ast: {
            if(lhs != rhs)
            {
                if(report)
                {
                    report_error("Mismatching structs", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
        } break;
        case AST_Type::unary_ast: {
            if(rhs->type != AST_Type::unary_ast)
            {
                if(report)
                {
                    report_error("Pointer vs non-pointer type", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
            Unary_Operator_AST *lhs_unary = static_cast<Unary_Operator_AST*>(lhs);
            Unary_Operator_AST *rhs_unary = static_cast<Unary_Operator_AST*>(rhs);
            
            // Assert since resolved_type is type_t_ast
            assert(lhs_unary->op == Unary_Operator::ref);
            assert(rhs_unary->op == Unary_Operator::ref);
            
            return types_match(ctx, lhs_unary->operand, rhs_unary->operand, report);
        } break;
        case AST_Type::primitive_ast: {
            if(rhs->type != AST_Type::primitive_ast)
            {
                if(report)
                {
                    report_error("Primitive vs non-primitive type", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
            Primitive_AST *lhs_prim_ast = static_cast<Primitive_AST*>(lhs);
            Primitive_AST *rhs_prim_ast = static_cast<Primitive_AST*>(rhs);
            
            u64 lhs_prim = lhs_prim_ast->primitive;
            u64 rhs_prim = rhs_prim_ast->primitive;
            u64 lhs_size = lhs_prim & PRIM_SIZE_MASK;
            u64 rhs_size = rhs_prim & PRIM_SIZE_MASK;
            
            if((lhs_prim & PRIM_FLOATLIKE) && (rhs_prim & PRIM_FLOATLIKE))
            {
                if(lhs_size != rhs_size && lhs_size != 0 && rhs_size != 0)
                {
                    if(rhs_size > lhs_size)
                    {
                        if(report)
                        {
                            report_error("Float size mismatch", lhs, rhs);
                            ctx->success = false;
                        }
                        return Status::bad;
                    }
                    else
                    {
                        return Status::good;
                    }
                }
                else
                {
                    return Status::good;
                }
            }
            else if((lhs_prim & PRIM_INTLIKE) && (rhs_prim & PRIM_INTLIKE))
            {
                if(lhs_size != rhs_size && lhs_size != 0 && rhs_size != 0)
                {
                    if(rhs_size > lhs_size)
                    {
                        if(report)
                        {
                            report_error("Integer size mismatch", lhs, rhs);
                            ctx->success = false;
                        }
                        return Status::bad;
                    }
                    else
                    {
                        return Status::good;
                    }
                }
                else
                {
                    return Status::good;
                }
            }
            else if((lhs_prim & PRIM_BOOLLIKE) &&
                    (rhs_prim & PRIM_BOOLLIKE))
            {
                return Status::good;
            }
            else if(lhs_prim == PRIM_VOID && rhs_prim == PRIM_VOID)
            {
                return Status::good;
            }
            else if(lhs_prim == PRIM_TYPE && rhs_prim == PRIM_TYPE)
            {
                return Status::good;
            }
            else
            {
                if(report)
                {
                    report_error("Primitive type mismatch", lhs, rhs);
                    ctx->success = false;
                }
                return Status::bad;
            }
        } break;
        
        case AST_Type::ident_ast: // TODO: this could be a type in the future
        case AST_Type::function_ast:
        case AST_Type::function_call_ast:
        case AST_Type::access_ast: // Note: would have been reduced
        case AST_Type::binary_operator_ast:
        case AST_Type::number_ast:
        case AST_Type::string_ast:
        case AST_Type::bool_ast: {
            // Not type
            assert(false);
        } break;
        case_non_exprs: {
            assert(false);
        } break;
    }
    
    return Status::bad;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movl %ecx, %r14d
testq %rsi, %rsi
sete %al
testq %rdx, %rdx
sete %cl
xorl %ebp, %ebp
orb %al, %cl
jne 0x69c4
movq %rdx, %r15
movq %rdi, %rbx
leaq 0x10(%rsp), %rdx
callq 0x684d
testl %eax, %eax
jne 0x69c2
movq %rsp, %rdx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x684d
testl %eax, %eax
je 0x69d5
movl %eax, %ebp
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x10(%rsp), %r12
movzwl (%r12), %eax
movl $0x2, %ebp
cmpq $0x13, %rax
ja 0x69c4
leaq 0x97f3(%rip), %rcx      # 0x101e4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%rsp), %r13
cmpw $0x8, (%r13)
jne 0x6c33
movq 0x20(%r12), %rcx
cmpq 0x20(%r13), %rcx
jne 0x6ca9
movq 0x30(%r12), %rax
cmpq 0x30(%r13), %rax
jne 0x6d3e
testq %rcx, %rcx
je 0x6a6c
xorl %r15d, %r15d
movzbl %r14b, %eax
movl %eax, 0xc(%rsp)
movq 0x28(%r12), %rax
movq (%rax,%r15,8), %rsi
movq 0x28(%r13), %rax
movq (%rax,%r15,8), %rdx
movq %rbx, %rdi
movl 0xc(%rsp), %ecx
callq 0x6979
testl %eax, %eax
jne 0x69c2
incq %r15
cmpq 0x20(%r12), %r15
jb 0x6a38
movq 0x30(%r12), %rax
testq %rax, %rax
je 0x69c4
xorl %r15d, %r15d
movzbl %r14b, %r14d
movq 0x38(%r12), %rax
movq (%rax,%r15,8), %rsi
movq 0x38(%r13), %rax
movq (%rax,%r15,8), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0x6979
testl %eax, %eax
jne 0x69c2
incq %r15
cmpq 0x30(%r12), %r15
jb 0x6a7c
jmp 0x69c4
movq (%rsp), %rax
cmpq %rax, %r12
sete %cl
xorb $0x1, %r14b
orb %cl, %r14b
jne 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa29c(%rip), %rdi      # 0x10d7a
leaq 0xa490(%rip), %r9       # 0x10f75
jmp 0x6d67
movq (%rsp), %rax
cmpw $0x10, (%rax)
jne 0x6bd9
cmpq $0x3, 0x20(%r12)
jne 0x6dc2
cmpq $0x3, 0x20(%rax)
jne 0x6de1
movq 0x28(%r12), %rsi
movq 0x28(%rax), %rdx
movzbl %r14b, %ecx
movq %rbx, %rdi
callq 0x6979
jmp 0x69c2
movq (%rsp), %rax
cmpq %rax, %r12
sete %cl
xorb $0x1, %r14b
orb %cl, %r14b
jne 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa222(%rip), %rdi      # 0x10d7a
leaq 0xa404(%rip), %r9       # 0x10f63
jmp 0x6d67
movq (%rsp), %rax
cmpw $0x11, (%rax)
jne 0x6c06
movq 0x20(%r12), %rcx
movq 0x20(%rax), %rdx
movl %ecx, %esi
andl $0x7, %esi
movl %edx, %edi
andl $0x7, %edi
testb $0x40, %cl
je 0x6c61
movl %edx, %r8d
andl $0x40, %r8d
je 0x6c61
testq %rsi, %rsi
setne %dl
cmpl %esi, %edi
seta %cl
andb %dl, %cl
andb %cl, %r14b
cmpb $0x1, %r14b
jne 0x6cd7
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa1ad(%rip), %rdi      # 0x10d7a
leaq 0xa477(%rip), %r9       # 0x1104b
jmp 0x6d67
testb %r14b, %r14b
je 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa180(%rip), %rdi      # 0x10d7a
leaq 0xa388(%rip), %r9       # 0x10f89
jmp 0x6d67
testb %r14b, %r14b
je 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa153(%rip), %rdi      # 0x10d7a
leaq 0xa3fd(%rip), %r9       # 0x1102b
jmp 0x6d67
testb %r14b, %r14b
je 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%r13), %ecx
movl 0xc(%r13), %r8d
leaq 0xa125(%rip), %rdi      # 0x10d7a
leaq 0xa277(%rip), %r9       # 0x10ed3
jmp 0x6d67
testb $0x20, %cl
je 0x6ce1
movl %edx, %r8d
andl $0x20, %r8d
je 0x6ce1
testq %rsi, %rsi
setne %dl
cmpl %esi, %edi
seta %cl
andb %dl, %cl
andb %cl, %r14b
cmpb $0x1, %r14b
jne 0x6cd7
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa0dd(%rip), %rdi      # 0x10d7a
leaq 0xa3bb(%rip), %r9       # 0x1105f
jmp 0x6d67
testb %r14b, %r14b
je 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%r13), %ecx
movl 0xc(%r13), %r8d
leaq 0xa0af(%rip), %rdi      # 0x10d7a
leaq 0xa224(%rip), %r9       # 0x10ef6
jmp 0x6d67
movzbl %cl, %ebp
addl %ebp, %ebp
jmp 0x69c4
xorl %ebp, %ebp
testb %cl, %cl
jns 0x6cf5
movl %edx, %esi
andl $0x80, %esi
jne 0x69c4
movq %rcx, %rsi
orq %rdx, %rsi
je 0x69c4
movl $0x100, %esi            # imm = 0x100
xorq %rsi, %rcx
xorq %rsi, %rdx
xorl %ebp, %ebp
orq %rcx, %rdx
setne %cl
andb %cl, %r14b
cmpb $0x1, %r14b
jne 0x6d7c
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0xa045(%rip), %rdi      # 0x10d7a
leaq 0xa339(%rip), %r9       # 0x11075
jmp 0x6d67
testb %r14b, %r14b
je 0x69c4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%r13), %ecx
movl 0xc(%r13), %r8d
leaq 0xa01a(%rip), %rdi      # 0x10d7a
leaq 0xa1c4(%rip), %r9       # 0x10f2b
xorl %eax, %eax
callq 0x416b
movb $0x0, 0x10(%rbx)
movl $0x2, %ebp
jmp 0x69c4
movb %cl, %bpl
jmp 0x6cda
leaq 0x9f45(%rip), %rdi      # 0x10cd0
leaq 0xa008(%rip), %rsi      # 0x10d9a
leaq 0xa231(%rip), %rcx      # 0x10fca
movl $0x7df, %edx            # imm = 0x7DF
callq 0x3080
leaq 0x9f26(%rip), %rdi      # 0x10cd0
leaq 0x9fe9(%rip), %rsi      # 0x10d9a
leaq 0xa212(%rip), %rcx      # 0x10fca
movl $0x7e2, %edx            # imm = 0x7E2
callq 0x3080
leaq 0xa1dc(%rip), %rdi      # 0x10fa5
leaq 0x9fca(%rip), %rsi      # 0x10d9a
leaq 0xa1f3(%rip), %rcx      # 0x10fca
movl $0x779, %edx            # imm = 0x779
callq 0x3080
leaq 0xa21e(%rip), %rdi      # 0x11006
leaq 0x9fab(%rip), %rsi      # 0x10d9a
leaq 0xa1d4(%rip), %rcx      # 0x10fca
movl $0x77a, %edx            # imm = 0x77A
callq 0x3080