// File: 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
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xb0(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x3da0
movq -0x10(%rbp), %rdi
callq 0x3a30
movb %al, -0xa5(%rbp)
jmp 0xd518
movb -0xa5(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0xd526
jmp 0xd528
jmp 0xd558
leaq 0xe481(%rip), %rdi      # 0x1b9b0
leaq 0xe228(%rip), %rsi      # 0x1b75e
movl $0x238, %edx            # imm = 0x238
leaq 0xe489(%rip), %rcx      # 0x1b9cb
callq 0x20d0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
jmp 0xda12
callq 0x3e00
jmp 0xd55f
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
movl -0x28(%rbp), %edi
leaq 0xe483(%rip), %rsi      # 0x1b9fd
leaq 0xd1c3(%rip), %rcx      # 0x1a744
callq 0xda30
jmp 0xd588
movq -0xb0(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x15c30
movq %rax, -0xb8(%rbp)
jmp 0xd5a5
movq -0xb8(%rbp), %rax
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
je 0xd633
movq -0x30(%rbp), %rdi
callq 0x15fe0
movb %al, -0xb9(%rbp)
jmp 0xd5c8
movb -0xb9(%rbp), %al
testb $0x1, %al
jne 0xd5d4
jmp 0xd609
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x34(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
movl -0x34(%rbp), %edi
leaq 0xe427(%rip), %rsi      # 0x1ba16
leaq 0xe430(%rip), %rcx      # 0x1ba26
callq 0xda80
jmp 0xd5fd
movl $0x1, -0x38(%rbp)
jmp 0xda00
movq -0x10(%rbp), %rcx
movq -0x30(%rbp), %rax
movl (%rcx), %ecx
movl %ecx, (%rax)
movq -0x30(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rsi
movq 0x38(%rax), %rdx
callq 0x16000
jmp 0xd62c
jmp 0xd62e
jmp 0xd6b5
movl $0x90, %edi
callq 0x15c60
movq %rax, -0xc8(%rbp)
jmp 0xd646
movq -0xc8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
movq 0x20(%rax), %rdx
movq 0x38(%rax), %rcx
callq 0x15f60
jmp 0xd664
movq -0xb0(%rbp), %rdi
movq -0xc8(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x10(%rbp), %rcx
movq -0x30(%rbp), %rax
movl (%rcx), %ecx
movl %ecx, (%rax)
movq -0x30(%rbp), %rdx
movq 0x8(%rdx), %rsi
callq 0xcdf0
jmp 0xd691
jmp 0xd6b5
movq -0xc8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
movl $0x90, %esi
callq 0x2120
jmp 0xda12
movq -0x10(%rbp), %rax
cmpq $0x0, 0x10(%rax)
je 0xd710
movq -0xb0(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
movl (%rax), %eax
movl %eax, -0x44(%rbp)
movl -0x44(%rbp), %edx
callq 0xcd30
movq %rax, -0xd0(%rbp)
jmp 0xd6e5
movq -0xd0(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x30(%rbp), %rdi
movq -0x40(%rbp), %rsi
callq 0x16050
jmp 0xd6ff
movq -0x40(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x16070
jmp 0xd70e
jmp 0xd724
movq -0x30(%rbp), %rsi
leaq 0x19365(%rip), %rdi     # 0x26a80
callq 0x15e10
jmp 0xd722
jmp 0xd724
movq -0x10(%rbp), %rax
addq $0x18, %rax
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rdi
callq 0x160d0
movq %rax, -0xd8(%rbp)
jmp 0xd742
movq -0xd8(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rdi
callq 0x160f0
movq %rax, -0xe0(%rbp)
jmp 0xd75f
movq -0xe0(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x58(%rbp), %rax
cmpq -0x60(%rbp), %rax
je 0xd843
movq -0x58(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x68(%rbp)
movq -0x30(%rbp), %rdi
addq $0x10, %rdi
movq -0x68(%rbp), %rax
movq 0x18(%rax), %rsi
callq 0x16110
movq %rax, -0xe8(%rbp)
jmp 0xd7a1
movq -0xe8(%rbp), %rax
movq %rax, -0x70(%rbp)
cmpq $0x0, -0x70(%rbp)
je 0xd7ec
movq -0x68(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x74(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
movq -0x70(%rbp), %rax
movq (%rax), %r8
movl -0x74(%rbp), %edi
leaq 0xe26d(%rip), %rsi      # 0x1ba42
leaq 0xe27a(%rip), %rcx      # 0x1ba56
leaq 0xd54a(%rip), %r9       # 0x1ad2d
callq 0xdb00
jmp 0xd7ea
jmp 0xd830
movq -0xb0(%rbp), %rsi
movq -0x68(%rbp), %rdi
callq 0x16140
movq %rax, -0xf0(%rbp)
jmp 0xd805
movq -0xf0(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
movb $0x2, 0x38(%rax)
movq -0x30(%rbp), %rdi
addq $0x10, %rdi
movq -0x70(%rbp), %rdx
movq (%rdx), %rsi
callq 0x16170
jmp 0xd82e
jmp 0xd830
jmp 0xd832
movq -0x58(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x58(%rbp)
jmp 0xd76a
movq -0x10(%rbp), %rax
addq $0x30, %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
callq 0x161f0
movq %rax, -0xf8(%rbp)
jmp 0xd861
movq -0xf8(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x80(%rbp), %rdi
callq 0x16210
movq %rax, -0x100(%rbp)
jmp 0xd881
movq -0x100(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x88(%rbp), %rax
cmpq -0x90(%rbp), %rax
je 0xd9f9
movq -0x88(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x98(%rbp)
movq -0x30(%rbp), %rdi
addq $0x40, %rdi
movq -0x98(%rbp), %rax
movq 0x18(%rax), %rsi
callq 0x16230
movq %rax, -0x108(%rbp)
jmp 0xd8d5
movq -0x108(%rbp), %rax
movq %rax, -0xa0(%rbp)
cmpq $0x0, -0xa0(%rbp)
je 0xd942
movq -0x98(%rbp), %rax
movl (%rax), %eax
movl %eax, -0xa4(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
movq -0xa0(%rbp), %rax
movq (%rax), %r8
movl -0xa4(%rbp), %edi
leaq 0xe1b4(%rip), %rcx      # 0x1bacf
movq %rsp, %rax
movq %rcx, (%rax)
leaq 0xe11a(%rip), %rsi      # 0x1ba42
leaq 0xe14b(%rip), %rcx      # 0x1ba7a
leaq 0xe169(%rip), %r9       # 0x1ba9f
callq 0xdb90
jmp 0xd93d
jmp 0xd9e0
movq -0xb0(%rbp), %rsi
movq -0x98(%rbp), %rdi
callq 0x16260
movq %rax, -0x110(%rbp)
jmp 0xd95e
movq -0x110(%rbp), %rax
movq %rax, -0xa0(%rbp)
cmpq $0x0, -0xa0(%rbp)
je 0xd978
jmp 0xd997
leaq 0xe152(%rip), %rdi      # 0x1bad1
leaq 0xddd8(%rip), %rsi      # 0x1b75e
movl $0x287, %edx            # imm = 0x287
leaq 0xe039(%rip), %rcx      # 0x1b9cb
callq 0x20d0
movq -0xa0(%rbp), %rax
cmpq $0x0, (%rax)
je 0xd9a6
jmp 0xd9c5
leaq 0xe12b(%rip), %rdi      # 0x1bad8
leaq 0xddaa(%rip), %rsi      # 0x1b75e
movl $0x288, %edx            # imm = 0x288
leaq 0xe00b(%rip), %rcx      # 0x1b9cb
callq 0x20d0
movq -0x30(%rbp), %rdi
addq $0x40, %rdi
movq -0xa0(%rbp), %rdx
movq (%rdx), %rsi
callq 0x16290
jmp 0xd9de
jmp 0xd9e0
jmp 0xd9e2
movq -0x88(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x88(%rbp)
jmp 0xd88f
movl $0x0, -0x38(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x3dd0
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
leaq -0x11(%rbp), %rdi
callq 0x3dd0
movq -0x20(%rbp), %rdi
callq 0x21c0
nopw %cs:(%rax,%rax)