Exemplo n.º 1
0
/*!
 *  Make the given enum type implements the protocol RawRepresentable.
 *  TODO Only one member is added for test case, add the rest members
 */
static void makeRawRepresentable(const TypeBuilderPtr& type, GlobalScope* global)
{
    type->addProtocol(global->RawRepresentable());
    //var rawValue: RawValue { get }
    TypePtr RawValue = type->getParentType();
    SymbolPlaceHolderPtr rawValue(new SymbolPlaceHolder(L"rawValue", RawValue, SymbolPlaceHolder::R_PROPERTY, SymbolFlagMember | SymbolFlagReadable));
    type->addMember(L"RawValue", RawValue);
    type->addMember(rawValue);
}
/*!
 * Check if the actual type can conform to requirement type where actual type is declared inside an owner type
 */
static bool checkTypeConform(const TypePtr& ownerType, TypePtr requirementType, const TypePtr& actualType)
{
    assert(actualType != nullptr);
    if(requirementType->getCategory() == Type::Alias)
    {
        wstring name = requirementType->getName();
        if(name == L"Self")
            requirementType = ownerType;
        else
            requirementType = ownerType->getAssociatedType(name);
        if(requirementType != nullptr)
            requirementType = requirementType->resolveAlias();
        if(requirementType == nullptr && actualType && actualType->getCategory() != Type::Alias)
        {
            //do typealias infer, the required type is not existing in owner type, we implicitly declare it as associated type
            requirementType = actualType;
            TypeBuilderPtr type = static_pointer_cast<TypeBuilder>(ownerType);
            type->addMember(name, actualType);
        }
        if(requirementType == nullptr)
            return false;
    }
    Type::Category category = requirementType->getCategory();
    if(category != actualType->getCategory())
        return false;
    switch(category)
    {
    case Type::Class:
    case Type::Struct:
    case Type::Protocol:
    case Type::Enum:
    case Type::Aggregate:
        return actualType == requirementType;
    case Type::GenericParameter:
        return actualType->getName() == requirementType->getName();
    case Type::MetaType:
        return checkTypeConform(ownerType, requirementType->getInnerType(), actualType->getInnerType());
    case Type::Tuple:
    {
        if(actualType->numElementTypes() != requirementType->numElementTypes())
            return false;
        int num = actualType->numElementTypes();
        for(int i = 0; i < num; i++)
        {
            TypePtr req = requirementType->getElementType(i);
            TypePtr act = actualType->getElementType(i);
            if(!checkTypeConform(ownerType, req, act))
                return false;
        }
        return true;
    }
    case Type::Function:
    {
        size_t num = requirementType->getParameters().size();
        if(num != actualType->getParameters().size())
            return false;
        if(!checkTypeConform(ownerType, requirementType->getReturnType(), actualType->getReturnType()))
            return false;
        auto iter = requirementType->getParameters().begin();
        auto iter2 = actualType->getParameters().begin();
        for(; iter != requirementType->getParameters().end(); iter++, iter2++)
        {
            if(iter->name != iter2->name)
                return false;
            if(iter->inout != iter2->inout)
                return false;
            TypePtr req = iter->type;
            TypePtr act = iter2->type;
            if(!checkTypeConform(ownerType, req, act))
                return false;
        }
        return true;
    }
    case Type::Specialized:
    {
        if(!Type::equals(requirementType->getInnerType(), actualType->getInnerType()))
            return false;
        GenericArgumentPtr greq = requirementType->getGenericArguments();
        GenericArgumentPtr gact = actualType->getGenericArguments();
        if(greq->size() != gact->size())
            return false;
        size_t size = greq->size();
        //TODO: check for parent generic arguments
        for(size_t i = 0; i < size; i++)
        {
            TypePtr req = greq->get(i);
            TypePtr act = gact->get(i);
            if(!checkTypeConform(ownerType, req, act))
                return false;
        }
        return true;

    }
    default:
        assert(0 && "Unsupported type category");
        return false;

    }
}
Exemplo n.º 3
0
void DeclarationAnalyzer::prepareDefaultInitializers(const TypePtr& type)
{

    /*
    Rule of initializers for class/structure:
    1) If no custom initializers, compiler will prepare one or two initializers:
        1.1) A default initializer with no arguments if all let/var fields are defined with a default value
        1.2) Skip this rule if it's a class. A default initializer with all let/var fields as initializer's parameters with the same external name,
            the order of the parameters are the exactly the same as them defined in structure
    2) Compiler will not generate initializers if there's custom initializers
    3) Convenience initializers will not be counted
     */
    SCOPED_SET(ctx->currentType, type);
    FunctionOverloadedSymbolPtr initializers = type->getDeclaredInitializer();
    int designatedInitializers = numDesignatedInitializers(initializers);
    if(designatedInitializers == 0)
    {
        bool createDefaultInit = true;
        vector<Parameter> initParams;
        if (type->getCategory() == Type::Struct)
        {
            //check all fields if they all have initializer
            for (auto sym : type->getDeclaredStoredProperties())
            {
                SymbolPlaceHolderPtr s = dynamic_pointer_cast<SymbolPlaceHolder>(sym);
                if (!s || sym->hasFlags(SymbolFlagTemporary))
                    continue;
                initParams.push_back(Parameter(sym->getName(), false, sym->getType()));
                //do not create default init if there's a variable has no initializer
                if (!s->hasFlags(SymbolFlagHasInitializer))
                    createDefaultInit = false;
            }
        }
        GlobalScope* global = symbolRegistry->getGlobalScope();
        bool initCreated = false;
        if (createDefaultInit)
        {
            //apply rule 1
            std::vector<Parameter> params;
            TypePtr initType = Type::newFunction(params, global->Void(), false);
            initType->setFlags(SymbolFlagInit, true);
            FunctionSymbolPtr initializer(new FunctionSymbol(L"init", initType, FunctionRoleInit, nullptr));
            declarationFinished(initializer->getName(), initializer, nullptr);
            initCreated = true;
        }
        if (type->getCategory() == Type::Struct && !initParams.empty())
        {
            TypePtr initType = Type::newFunction(initParams, global->Void(), false);
            initType->setFlags(SymbolFlagInit, true);
            FunctionSymbolPtr initializer(new FunctionSymbol(L"init", initType, FunctionRoleInit, nullptr));
            declarationFinished(initializer->getName(), initializer, nullptr);
            initCreated = true;
        }
        //make all stored properties initialized after the default initializer created
        if(initCreated)
        {
            for(const SymbolPtr& s : type->getDeclaredStoredProperties())
            {
                s->setFlags(SymbolFlagInitialized, true);
            }
        }

    }
    //inherit designated initializers from parent type
    if(type->getParentType() && type->getCategory() == Type::Class)
    {
        FunctionOverloadedSymbolPtr initializers = type->getDeclaredInitializer();

        TypeBuilderPtr builder = static_pointer_cast<TypeBuilder>(type);
        if(!initializers)
        {
            initializers = FunctionOverloadedSymbolPtr(new FunctionOverloadedSymbol(L"init"));
            builder->setInitializer(initializers);
        }
        TypePtr parent = type->getParentType();
        FunctionOverloadedSymbolPtr baseInitializers = parent->getDeclaredInitializer();
        if(baseInitializers)
        {
            for(const FunctionSymbolPtr& baseInitializer : *baseInitializers)
            {
                //skip convenience initializer
                if(baseInitializer->hasFlags(SymbolFlagConvenienceInit))
                    continue;
                //check if it's defined in current type
                TypePtr initType = baseInitializer->getType();
                FunctionSymbolPtr initializer = initializers->lookupByType(initType);
                if(!initializer)
                {
                    //this initializer exists in base type, but not in current type
                    //so we need to create it in current type
                    initializer = FunctionSymbolPtr(new FunctionSymbol(L"init", initType, FunctionRoleInit, nullptr));
                    //initializers->add(initializer);
                    builder->addMember(initializer);
                }
                
            }
        }
    }
}
bool DeclarationAnalyzer::verifyProtocolConform(const TypePtr& type, const TypePtr& protocol, bool supressError)
{
    for(auto entry : protocol->getDeclaredMembers())
    {
        SymbolPtr requirement = entry.second;
        if(FunctionOverloadedSymbolPtr funcs = std::dynamic_pointer_cast<FunctionOverloadedSymbol>(requirement))
        {
            //verify function
            for(auto func : *funcs)
            {
                bool success = verifyProtocolFunction(type, protocol, func, supressError);
                if(!success)
                    return false;
            }
        }
        else if(FunctionSymbolPtr func = std::dynamic_pointer_cast<FunctionSymbol>(requirement))
        {
            //verify function
            bool success = verifyProtocolFunction(type, protocol, func, supressError);
            if(!success)
                return false;
        }
        /*
         else if(requirement == Type::getPlaceHolder())
         {
         //verify inner type
         SymbolPtr sym = type->getAssociatedType(entry.first);
         if(!(std::dynamic_pointer_cast<Type>(sym)))
         {
         //Type %0 does not conform to protocol %1, unimplemented type %2
         error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_TYPE_3, type->getName(), protocol->getName(), entry.first);
         }
         }*/
        else if(TypePtr t = std::dynamic_pointer_cast<Type>(requirement))
        {
            //if type doesn't declare a type alias but the protocol has defined it with a full definition, then we will implicitly declare it
            wstring name = t->getName();
            TypePtr originalType = t->resolveAlias();
            if(type->getAssociatedType(name) == nullptr && originalType != nullptr && originalType->getCategory() != Type::Alias)
            {
                TypeBuilderPtr builder = static_pointer_cast<TypeBuilder>(type);
                builder->addMember(name, originalType);
            }
            //typealias checking is moved to second stage, when all other members verified
            continue;
        }
        else if(dynamic_pointer_cast<ComputedPropertySymbol>(requirement) || dynamic_pointer_cast<SymbolPlaceHolder>(requirement))
        {
            //verify computed properties
            SymbolPtr sym = type->getMember(entry.first);
            //ComputedPropertySymbolPtr sp = std::dynamic_pointer_cast<ComputedPropertySymbol>(sym);
            if(!sym || !checkTypeConform(type, requirement->getType(), sym->getType()))
            {
                if(!supressError)
                {
                    error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_PROPERTY_3, type->getName(), protocol->getName(), entry.first);
                }
                return false;
            }
            bool expectedSetter = requirement->hasFlags(SymbolFlagWritable);
            bool actualSetter = sym->hasFlags(SymbolFlagWritable);
            if(expectedSetter && !actualSetter)
            {
                if(!supressError)
                {
                    error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNWRITABLE_PROPERTY_3, type->getName(), protocol->getName(), entry.first);
                }
                return false;
            }
        }
    }
    //check again for associated types
    for(auto entry : protocol->getAssociatedTypes())
    {
        if(entry.second->resolveAlias() != nullptr)
            continue;
        TypePtr t = type->getAssociatedType(entry.first);
        if(t == nullptr)
        {
            //undefined type alias
            if(!supressError)
            {
                error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_2_, type->getName(), protocol->getName());
            }
            return false;
        }
    }
    return true;
}