void DeclarationAnalyzer::visitStruct(const StructDefPtr& node)
{
    TypePtr type = defineType(node);
    SCOPED_SET(ctx->currentType, type);
    visitDeclaration(node);
    //prepare default initializers
    this->prepareDefaultInitializers(type);
    //Type verification and typealias inference

    for(auto entry : type->getAllParents())
    {
        TypePtr parent = entry.first;
        if(parent->getCategory() != Type::Protocol || !(parent->containsAssociatedType() || parent->containsSelfType()))
            continue;
        //this parent is a protocol that contains associated type, now validate protocol's methods and infer the types out
        std::map<std::wstring, TypePtr> associatedTypes;
        //collect all defined associated types
        for(auto entry : parent->getAssociatedTypes())
        {
            TypePtr type = entry.second->unwrap();
            if(type->getCategory() != Type::Alias)
                associatedTypes.insert(make_pair(entry.first, type));
        }
        if(parent->containsSelfType())
            associatedTypes.insert(make_pair(L"Self", type));

        for(const FunctionOverloadedSymbolPtr& funcs : parent->getDeclaredFunctions())
        {
            for(const FunctionSymbolPtr& expectedFunc : *funcs)
            {
                TypePtr expectedType = expectedFunc->getType();
                assert(expectedType != nullptr);
                bool matched = false;
                //get all methods with the same name, and check their signature one by one
                vector<SymbolPtr> funcs;
                bool staticMember = expectedFunc->hasFlags(SymbolFlagStatic);
                semanticAnalyzer->getMethodsFromType(type, expectedFunc->getName(), (MemberFilter)((staticMember ? FilterStaticMember : 0) | (FilterLookupInExtension | FilterRecursive)), funcs);
                for(const SymbolPtr& func : funcs)
                {
                    TypePtr actualType = func->getType();
                    assert(actualType != nullptr);
                    if(expectedType->canSpecializeTo(actualType, associatedTypes))
                    {
                        matched = true;
                        break;
                    }
                }
                if(!matched)
                {
                    //no matched function
                    error(node, Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), parent->getName(), expectedFunc->getName());
                    return;
                }
            }
        }
        //now make types infered above visible

        for(auto entry : associatedTypes)
        {
            if(entry.first == L"Self")
                continue;
            static_pointer_cast<TypeBuilder>(type)->addMember(entry.first, entry.second);
        }
    }

    verifyProtocolConform(type);
    validateDeclarationModifiers(node);



    visitImplementation(node);
}