// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_types.c
// Function: typeEquivalentRecursive
static bool typeEquivalentRecursive(const Type *left, const Type *right, VisitedTypePair *firstPair)
{
    // Recursively defined types visited before (need to check first in order to break a possible circular definition)
    VisitedTypePair *pair = firstPair;
    while (pair && !(pair->left == left && pair->right == right))
        pair = pair->next;

    if (pair)
        return true;

    VisitedTypePair newPair = {left, right, firstPair};

    // Same types
    if (left == right)
        return true;

    // Identically named types
    if (left->typeIdent && right->typeIdent)
        return left->typeIdent == right->typeIdent && left->block == right->block;

    if (left->kind == right->kind)
    {
        // Pointers or weak pointers
        if (left->kind == TYPE_PTR || left->kind == TYPE_WEAKPTR)
            return typeEquivalentRecursive(left->base, right->base, &newPair);

        // Arrays
        else if (left->kind == TYPE_ARRAY)
        {
            // Number of elements
            if (left->numItems != right->numItems)
                return false;

            return typeEquivalentRecursive(left->base, right->base, &newPair);
        }

        // Dynamic arrays
        else if (left->kind == TYPE_DYNARRAY)
            return typeEquivalentRecursive(left->base, right->base, &newPair);

        // Strings
        else if (left->kind == TYPE_STR)
            return true;

        // Enumerations
        else if (typeEnum(left) || typeEnum(right))
            return false;

        // Maps
        else if (left->kind == TYPE_MAP)
        {
            // Key type
            if (!typeEquivalentRecursive(typeMapKey(left), typeMapKey(right), &newPair))
                return false;

            return typeEquivalentRecursive(left->base, right->base, &newPair);
        }

        // Structures or interfaces
        else if (left->kind == TYPE_STRUCT || left->kind == TYPE_INTERFACE || left->kind == TYPE_CLOSURE)
        {
            // Number of fields
            if (left->numItems != right->numItems)
                return false;

            // Fields
            for (int i = 0; i < left->numItems; i++)
            {
                // Name
                if (left->field[i]->hash != right->field[i]->hash || strcmp(left->field[i]->name, right->field[i]->name) != 0)
                    return false;

                // Type
                if (!typeEquivalentRecursive(left->field[i]->type, right->field[i]->type, &newPair))
                    return false;
            }
            return true;
        }

        // Functions
        else if (left->kind == TYPE_FN)
        {
            // Number of parameters
            if (left->sig.numParams != right->sig.numParams)
                return false;

            // Number of default parameters
            if (left->sig.numDefaultParams != right->sig.numDefaultParams)
                return false;

            // Method flag
            if (left->sig.isMethod != right->sig.isMethod)
                return false;

            // Parameters (skip interface method receiver)
            int iStart = left->sig.offsetFromSelf == 0 ? 0 : 1;
            for (int i = iStart; i < left->sig.numParams; i++)
            {
                // Type
                if (!typeEquivalentRecursive(left->sig.param[i]->type, right->sig.param[i]->type, &newPair))
                    return false;

                // Default value
                if (i >= left->sig.numParams - left->sig.numDefaultParams)
                    if (!typeDefaultParamEqual(&left->sig.param[i]->defaultVal, &right->sig.param[i]->defaultVal, left->sig.param[i]->type))
                        return false;
            }

            // Result type
            if (!typeEquivalentRecursive(left->sig.resultType, right->sig.resultType, &newPair))
                return false;

            return true;
        }

        // Primitive types
        else
            return true;
    }
    return false;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x28(%rbp)
xorl %eax, %eax
cmpq $0x0, -0x28(%rbp)
movb %al, -0x4d(%rbp)
je 0x222d4
movq -0x28(%rbp), %rax
movq (%rax), %rcx
xorl %eax, %eax
cmpq -0x10(%rbp), %rcx
movb %al, -0x4e(%rbp)
jne 0x222cc
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x18(%rbp), %rax
sete %al
movb %al, -0x4e(%rbp)
movb -0x4e(%rbp), %al
xorb $-0x1, %al
movb %al, -0x4d(%rbp)
movb -0x4d(%rbp), %al
testb $0x1, %al
jne 0x222dd
jmp 0x222eb
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0x2229c
cmpq $0x0, -0x28(%rbp)
je 0x222fb
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rax
cmpq -0x18(%rbp), %rax
jne 0x22326
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpq $0x0, 0x18(%rax)
je 0x22374
movq -0x18(%rbp), %rax
cmpq $0x0, 0x18(%rax)
je 0x22374
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rcx
movq -0x18(%rbp), %rdx
xorl %eax, %eax
cmpq 0x18(%rdx), %rcx
movb %al, -0x4f(%rbp)
jne 0x22367
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0x4(%rcx), %eax
sete %al
movb %al, -0x4f(%rbp)
movb -0x4f(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movl (%rax), %eax
movq -0x18(%rbp), %rcx
cmpl (%rcx), %eax
jne 0x22746
movq -0x10(%rbp), %rax
cmpl $0x10, (%rax)
je 0x22398
movq -0x10(%rbp), %rax
cmpl $0x11, (%rax)
jne 0x223bb
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x12, (%rax)
jne 0x22400
movq -0x10(%rbp), %rax
movl 0x10(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0x10(%rcx), %eax
je 0x223dd
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x13, (%rax)
jne 0x2242c
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x14, (%rax)
jne 0x2243e
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rdi
callq 0x21f60
testb $0x1, %al
jne 0x2245a
movq -0x18(%rbp), %rdi
callq 0x21f60
testb $0x1, %al
jne 0x2245a
jmp 0x22463
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x15, (%rax)
jne 0x224c2
movq -0x10(%rbp), %rdi
callq 0x24340
movq %rax, -0x58(%rbp)
movq -0x18(%rbp), %rdi
callq 0x24340
movq -0x58(%rbp), %rdi
movq %rax, %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
testb $0x1, %al
jne 0x2249f
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x16, (%rax)
je 0x224e1
movq -0x10(%rbp), %rax
cmpl $0x17, (%rax)
je 0x224e1
movq -0x10(%rbp), %rax
cmpl $0x18, (%rax)
jne 0x225cf
movq -0x10(%rbp), %rax
movl 0x10(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0x10(%rcx), %eax
je 0x224fa
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movl $0x0, -0x44(%rbp)
movl -0x44(%rbp), %eax
movq -0x10(%rbp), %rcx
cmpl 0x10(%rcx), %eax
jge 0x225c6
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x44(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x100(%rax), %eax
movq -0x18(%rbp), %rcx
movq 0x28(%rcx), %rcx
movslq -0x44(%rbp), %rdx
movq (%rcx,%rdx,8), %rcx
cmpl 0x100(%rcx), %eax
jne 0x22569
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x44(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
movq -0x18(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x44(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x3220
cmpl $0x0, %eax
je 0x22572
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x44(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x108(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x28(%rax), %rax
movslq -0x44(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x108(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
testb $0x1, %al
jne 0x225b6
movb $0x0, -0x1(%rbp)
jmp 0x2274a
jmp 0x225b8
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x22501
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
cmpl $0x1a, (%rax)
jne 0x22740
movq -0x10(%rbp), %rax
movl 0x28(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0x28(%rcx), %eax
je 0x225f5
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movl 0x2c(%rax), %eax
movq -0x18(%rbp), %rcx
cmpl 0x2c(%rcx), %eax
je 0x2260e
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movb 0x30(%rax), %al
andb $0x1, %al
movzbl %al, %eax
movq -0x18(%rbp), %rcx
movb 0x30(%rcx), %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
je 0x22634
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movq -0x10(%rbp), %rax
movl 0x34(%rax), %edx
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, %edx
cmovel %ecx, %eax
movl %eax, -0x48(%rbp)
movl -0x48(%rbp), %eax
movl %eax, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
movq -0x10(%rbp), %rcx
cmpl 0x28(%rcx), %eax
jge 0x22711
movq -0x10(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rdi
movq -0x18(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
testb $0x1, %al
jne 0x2269f
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movl -0x4c(%rbp), %eax
movq -0x10(%rbp), %rcx
movl 0x28(%rcx), %ecx
movq -0x10(%rbp), %rdx
subl 0x2c(%rdx), %ecx
cmpl %ecx, %eax
jl 0x22701
movq -0x10(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rdi
addq $0x110, %rdi            # imm = 0x110
movq -0x18(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rsi
addq $0x110, %rsi            # imm = 0x110
movq -0x10(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq 0x38(%rax,%rcx,8), %rax
movq 0x108(%rax), %rdx
callq 0x24370
testb $0x1, %al
jne 0x226ff
movb $0x0, -0x1(%rbp)
jmp 0x2274a
jmp 0x22701
jmp 0x22703
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x22651
movq -0x10(%rbp), %rax
movq 0xb8(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0xb8(%rax), %rsi
leaq -0x40(%rbp), %rdx
callq 0x22280
testb $0x1, %al
jne 0x2273a
movb $0x0, -0x1(%rbp)
jmp 0x2274a
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movb $0x1, -0x1(%rbp)
jmp 0x2274a
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x60, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)