// File: /workspace/github_cpp_makefile_star2_O1/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 $0x28, %rsp
movl %ecx, %r14d
testq %rsi, %rsi
sete %al
testq %rdx, %rdx
sete %cl
xorl %ebp, %ebp
orb %al, %cl
jne 0x6cc4
movq %rdx, %r15
movq %rdi, %rbx
leaq 0x20(%rsp), %rdx
callq 0x6b4e
testl %eax, %eax
jne 0x6cc2
leaq 0x8(%rsp), %rdx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x6b4e
testl %eax, %eax
je 0x6cd5
movl %eax, %ebp
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x20(%rsp), %r12
movzwl (%r12), %eax
cmpq $0x13, %rax
ja 0x70a2
leaq 0x94f4(%rip), %rcx      # 0x101e4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rsp), %r13
cmpw $0x8, (%r13)
jne 0x6f3d
movq 0x20(%r12), %rax
cmpq 0x20(%r13), %rax
jne 0x6fce
movq 0x30(%r12), %rax
cmpq 0x30(%r13), %rax
jne 0x704e
cmpq $0x0, 0x20(%r12)
setne %al
movb %al, 0x10(%rsp)
je 0x708f
movq 0x28(%r12), %rax
movq (%rax), %rsi
movq 0x28(%r13), %rax
movq (%rax), %rdx
movzbl %r14b, %r15d
movq %rbx, %rdi
movl %r15d, %ecx
callq 0x6c77
movl %eax, %ebp
testl %eax, %eax
jne 0x708f
movl %r15d, 0x1c(%rsp)
movl $0x1, %r15d
cmpq 0x20(%r12), %r15
setb 0x10(%rsp)
jae 0x708f
movq 0x28(%r12), %rax
movq (%rax,%r15,8), %rsi
movq 0x28(%r13), %rax
movq (%rax,%r15,8), %rdx
movq %rbx, %rdi
movl 0x1c(%rsp), %ecx
callq 0x6c77
movl %eax, %ebp
incq %r15
testl %eax, %eax
je 0x6d6e
jmp 0x708f
movq 0x8(%rsp), %rax
cmpq %rax, %r12
je 0x70a2
movl $0x2, %ebp
testb %r14b, %r14b
je 0x6cc4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9f9d(%rip), %rdi      # 0x10d7a
leaq 0xa191(%rip), %r9       # 0x10f75
jmp 0x6f6b
movq 0x8(%rsp), %rax
cmpw $0x10, (%rax)
jne 0x6edf
cmpq $0x3, 0x20(%r12)
jne 0x7146
cmpq $0x3, 0x20(%rax)
jne 0x7165
movq 0x28(%r12), %rsi
movq 0x28(%rax), %rdx
movzbl %r14b, %ecx
movq %rbx, %rdi
callq 0x6c77
jmp 0x6cc2
movq 0x8(%rsp), %rax
cmpq %rax, %r12
je 0x70a2
movl $0x2, %ebp
testb %r14b, %r14b
je 0x6cc4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9f1d(%rip), %rdi      # 0x10d7a
leaq 0xa0ff(%rip), %r9       # 0x10f63
jmp 0x6f6b
movq 0x8(%rsp), %rax
cmpw $0x11, (%rax)
jne 0x6f0e
movq 0x20(%r12), %rcx
movq 0x20(%rax), %rdx
movl %ecx, %esi
andl $0x7, %esi
movl %edx, %edi
andl $0x7, %edi
testb $0x40, %cl
je 0x6f7b
movl %edx, %r8d
andl $0x40, %r8d
je 0x6f7b
testq %rsi, %rsi
setne %dl
cmpl %esi, %edi
seta %cl
andb %dl, %cl
andb %cl, %r14b
cmpb $0x1, %r14b
jne 0x6fe0
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9ea7(%rip), %rdi      # 0x10d7a
leaq 0xa171(%rip), %r9       # 0x1104b
jmp 0x6fbe
movl $0x2, %ebp
testb %r14b, %r14b
je 0x6cc4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9e75(%rip), %rdi      # 0x10d7a
leaq 0xa07d(%rip), %r9       # 0x10f89
jmp 0x6f6b
movl $0x2, %ebp
testb %r14b, %r14b
je 0x6cc4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9e46(%rip), %rdi      # 0x10d7a
leaq 0xa0f0(%rip), %r9       # 0x1102b
jmp 0x6f6b
movl $0x2, %ebp
testb %r14b, %r14b
je 0x6cc4
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%r13), %ecx
movl 0xc(%r13), %r8d
leaq 0x9e16(%rip), %rdi      # 0x10d7a
leaq 0x9f68(%rip), %r9       # 0x10ed3
xorl %eax, %eax
callq 0x4261
movb $0x0, 0x10(%rbx)
jmp 0x6cc4
testb $0x20, %cl
je 0x6fea
movl %edx, %r8d
andl $0x20, %r8d
je 0x6fea
testq %rsi, %rsi
setne %dl
cmpl %esi, %edi
seta %cl
andb %dl, %cl
andb %cl, %r14b
cmpb $0x1, %r14b
jne 0x6fe0
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9dc3(%rip), %rdi      # 0x10d7a
leaq 0xa0a1(%rip), %r9       # 0x1105f
xorl %eax, %eax
callq 0x4261
movb $0x0, 0x10(%rbx)
jmp 0x70a2
testb %r14b, %r14b
je 0x7088
leaq 0x9f18(%rip), %r9       # 0x10ef6
jmp 0x705a
movzbl %cl, %ebp
addl %ebp, %ebp
jmp 0x6cc4
xorl %ebp, %ebp
testb %cl, %cl
jns 0x6ffe
movl %edx, %esi
andl $0x80, %esi
jne 0x6cc4
movq %rcx, %rsi
orq %rdx, %rsi
je 0x6cc4
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 0x7100
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%rax), %ecx
movl 0xc(%rax), %r8d
leaq 0x9d38(%rip), %rdi      # 0x10d7a
leaq 0xa02c(%rip), %r9       # 0x11075
jmp 0x6fbe
testb %r14b, %r14b
je 0x7088
leaq 0x9ed1(%rip), %r9       # 0x10f2b
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
movl 0x8(%r13), %ecx
movl 0xc(%r13), %r8d
leaq 0x9d07(%rip), %rdi      # 0x10d7a
xorl %r15d, %r15d
xorl %eax, %eax
callq 0x4261
movb $0x0, 0x10(%rbx)
movl $0x2, %ebp
jmp 0x7099
movl $0x2, %ebp
jmp 0x7096
cmpb $0x0, 0x10(%rsp)
je 0x70ac
xorl %r15d, %r15d
testb %r15b, %r15b
je 0x6cc4
movl $0x2, %ebp
jmp 0x6cc4
cmpq $0x0, 0x30(%r12)
sete %r15b
je 0x7099
movq %r13, 0x10(%rsp)
xorl %r13d, %r13d
movzbl %r14b, %r14d
movq 0x38(%r12), %rax
movq (%rax,%r13,8), %rsi
movq 0x10(%rsp), %rax
movq 0x38(%rax), %rax
movq (%rax,%r13,8), %rdx
movq %rbx, %rdi
movl %r14d, %ecx
callq 0x6c77
testl %eax, %eax
jne 0x70f9
incq %r13
cmpq 0x30(%r12), %r13
setae %r15b
jb 0x70c4
jmp 0x7099
xorl %r15d, %r15d
movl %eax, %ebp
jmp 0x7099
movb %cl, %bpl
jmp 0x6fe3
leaq 0x9bc1(%rip), %rdi      # 0x10cd0
leaq 0x9c84(%rip), %rsi      # 0x10d9a
leaq 0x9ead(%rip), %rcx      # 0x10fca
movl $0x7df, %edx            # imm = 0x7DF
callq 0x3080
leaq 0x9ba2(%rip), %rdi      # 0x10cd0
leaq 0x9c65(%rip), %rsi      # 0x10d9a
leaq 0x9e8e(%rip), %rcx      # 0x10fca
movl $0x7e2, %edx            # imm = 0x7E2
callq 0x3080
leaq 0x9e58(%rip), %rdi      # 0x10fa5
leaq 0x9c46(%rip), %rsi      # 0x10d9a
leaq 0x9e6f(%rip), %rcx      # 0x10fca
movl $0x779, %edx            # imm = 0x779
callq 0x3080
leaq 0x9e9a(%rip), %rdi      # 0x11006
leaq 0x9c27(%rip), %rsi      # 0x10d9a
leaq 0x9e50(%rip), %rcx      # 0x10fca
movl $0x77a, %edx            # imm = 0x77A
callq 0x3080