// File: /workspace/github_cpp_makefile_star2_O2/baziotis[P]minijava-cpp/typecheck.cpp
// Function: DeclarationVisitor::visit(TypeDeclaration*)
void DeclarationVisitor::visit(TypeDeclaration *type_decl) {
    LOG_SCOPE;
    assert(!type_decl->is_undefined());
    print_indentation();
    debug_log(type_decl->loc, "Pass1::TypeDeclaration: ", type_decl->id, "\n");
    IdType *type = this->type_table.find(type_decl->id);
    // If it exists and it's declared (i.e. we have processed
    // a type with the same `id`), then we have redeclaration error.
    if (type) {
        if (type->is_defined()) {
            typecheck_error(type_decl->loc, "Type with id: `", type_decl->id,
                            "` has already been declared");
            return;
        } else {
            // Overwrite the location. If the type is already inserted, its
            // loc is its first usage.
            type->loc = type_decl->loc;
            type->set_sizes(type_decl->vars.len, type_decl->methods.len);
        }
    } else {
        type = new IdType(type_decl->id, type_decl->vars.len, type_decl->methods.len);
        type->loc = type_decl->loc;
        this->type_table.insert(type->id, type);
    }
    // Handle inheritance
    if (type_decl->extends) {
        IdType *parent = this->id_to_type(type_decl->extends, type_decl->loc);
        type->set_parent(parent);
        parent->add_child(type);
    } else {
        inher_roots.push(type);
    }
    for (LocalDeclaration *ld : type_decl->vars) {
        // Check redefinition in fields.
        // IMPORTANT:
        // - A field must not conflict with a field of the current class.
        // - A field can conflict with a field of the parent class and
        //   this is called shadowing. And it's correct (when we refer
        //   to the field, we refer to the most immediate in the
        //   inheritance tree).
        // - A field can't possibly conflict with a method
        //   of the current class because first we define all the fields,
        //   then all the methods (so, only a method can conflict with a field).
        // - A field can conflict with a method of a parent class, but that's
        //   NOT an error. Because it is disambiguated in what we refer to
        //   by the way we dereference.

        Field *field = type->fields.find(ld->id);
        if (field) {
            typecheck_error(ld->loc, "In class with id: `", type_decl->id,
                            "`, redefinition of field with id: `", field->id, "`");
        } else {
            field = ld->accept(this);
            field->kind = (int)LOCAL_KIND::FIELD;
            type->fields.insert(field->id, field);
        }
    }
    for (MethodDeclaration *md : type_decl->methods) {
        // Check redefinition
        // IMPORTANT:
        // - A method must not conflict with a method of the current class.
        // - A method must not conflict with a field of the current class.
        // - A method can conflict with a method of the parent class:
        //   -- If the methods have the same return type and the _same_
        //      parameters, then it's valid overriding.
        //   -- Otherwise, it's an error.
        //   We CAN'T check this in the first pass as it is possible that
        //   we have not processed the parent type yet. Note that we don't
        //   check this at the typecheck visitor but at the offset computation.
        // - A method can conflict with a field of the parent 
        //   but that's NOT an error.  Because it is disambiguated in what
        //   we refer to by the way we dereference.

        Method *method = type->methods.find(md->id);
        if (method) {
            typecheck_error(md->loc, "In class with id: `", type_decl->id,
                            "`, redefinition of method with id: `", method->id,
                            "`. Note that you can override but not overload ",
                            "a method");
        } else {
            method = md->accept(this);
            assert(method);
            assert(method->id);
            type->methods.insert(method->id, method);
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rsi, %rbx
movq %rdi, %r14
leaq 0x17(%rsp), %rdi
callq 0x3108
movq 0x10(%rbx), %rax
orq 0x8(%rbx), %rax
je 0x82e8
callq 0x312f
movl (%rbx), %edi
movq 0x8(%rbx), %rdx
leaq 0x85cd(%rip), %rsi      # 0x1068d
callq 0x8336
movq 0x8(%rbx), %rsi
leaq 0x30(%r14), %rdi
callq 0xd46e
movq %rax, %r12
testq %rax, %rax
je 0x8114
cmpl $0x0, 0x4(%r12)
movl (%rbx), %edi
je 0x814d
movq 0x8(%rbx), %rdx
leaq 0x85b7(%rip), %rsi      # 0x106a6
leaq 0x85c0(%rip), %rcx      # 0x106b6
callq 0x836b
leaq 0x17(%rsp), %rdi
callq 0x311c
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x90, %edi
callq 0xcbbc
movq %rax, %r12
movq 0x8(%rbx), %rsi
movq 0x20(%rbx), %rdx
movq 0x38(%rbx), %rcx
movq %rax, %rdi
callq 0xccca
movl (%rbx), %eax
movl %eax, (%r12)
movq 0x8(%r12), %rsi
movq %r14, %rdi
movq %r12, %rdx
callq 0x7cc2
jmp 0x8161
movl %edi, (%r12)
movq 0x20(%rbx), %rsi
movq 0x38(%rbx), %rdx
movq %r12, %rdi
callq 0xcd12
movq 0x10(%rbx), %rsi
testq %rsi, %rsi
movq %r14, 0x20(%rsp)
je 0x818b
movl (%rbx), %edx
movq %r14, %rdi
callq 0x7c52
movq %rax, 0x78(%r12)
movq %rax, %rdi
movq %r12, %rsi
callq 0xcd42
jmp 0x819a
leaq 0x128de(%rip), %rdi     # 0x1aa70
movq %r12, %rsi
callq 0xcc90
movq 0x20(%rbx), %r13
movq %rbx, 0x18(%rsp)
movq 0x28(%rbx), %rbp
movq %r12, %r15
addq $0x10, %r12
shlq $0x3, %r13
xorl %ebx, %ebx
cmpq %rbx, %r13
je 0x8218
movq (%rbp,%rbx), %r14
movq 0x18(%r14), %rsi
movq %r12, %rdi
callq 0xda72
testq %rax, %rax
je 0x81f3
movl (%r14), %edi
movq 0x18(%rsp), %rcx
movq 0x8(%rcx), %rdx
movq (%rax), %r8
leaq 0x84ed(%rip), %rsi      # 0x106d2
leaq 0x84fa(%rip), %rcx      # 0x106e6
callq 0x83bf
jmp 0x8212
movq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x84a0
movb $0x2, 0x38(%rax)
movq (%rax), %rsi
movq %r12, %rdi
movq %rax, %rdx
callq 0xcd72
addq $0x8, %rbx
jmp 0x81b4
movq 0x18(%rsp), %rbx
movq 0x38(%rbx), %r12
movq 0x40(%rbx), %r13
addq $0x40, %r15
shlq $0x3, %r12
xorl %ebp, %ebp
cmpq %rbp, %r12
je 0x80fb
movq (%r13,%rbp), %r14
movq 0x18(%r14), %rsi
movq %r15, %rdi
callq 0xdbb8
testq %rax, %rax
je 0x827f
movl (%r14), %edi
movq 0x8(%rbx), %rdx
movq (%rax), %r8
leaq 0x8500(%rip), %rax      # 0x1075f
movq %rax, (%rsp)
leaq 0x8468(%rip), %rsi      # 0x106d2
leaq 0x8499(%rip), %rcx      # 0x1070a
leaq 0x84b7(%rip), %r9       # 0x1072f
callq 0x8429
jmp 0x82a4
movq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x8604
testq %rax, %rax
je 0x82aa
movq (%rax), %rsi
testq %rsi, %rsi
je 0x82c9
movq %r15, %rdi
movq %rax, %rdx
callq 0xcdb4
addq $0x8, %rbp
jmp 0x822f
leaq 0x84b0(%rip), %rdi      # 0x10761
leaq 0x8136(%rip), %rsi      # 0x103ee
leaq 0x839c(%rip), %rcx      # 0x1065b
movl $0x287, %edx            # imm = 0x287
callq 0x20b0
leaq 0x8498(%rip), %rdi      # 0x10768
leaq 0x8117(%rip), %rsi      # 0x103ee
leaq 0x837d(%rip), %rcx      # 0x1065b
movl $0x288, %edx            # imm = 0x288
callq 0x20b0
leaq 0x8351(%rip), %rdi      # 0x10640
leaq 0x80f8(%rip), %rsi      # 0x103ee
leaq 0x835e(%rip), %rcx      # 0x1065b
movl $0x238, %edx            # imm = 0x238
callq 0x20b0
movq %rax, %rbx
movl $0x90, %esi
movq %r12, %rdi
callq 0x2100
jmp 0x8324
jmp 0x8321
jmp 0x8321
jmp 0x8321
jmp 0x8321
movq %rax, %rbx
leaq 0x17(%rsp), %rdi
callq 0x311c
movq %rbx, %rdi
callq 0x21c0