void DeclarationAnalyzer::visitTypeAlias(const TypeAliasPtr& node)
{
    if(isLazyDeclared(node))
        return;
    TypePtr type;
    SymbolScope* currentScope = symbolRegistry->getCurrentScope();

    if(currentScope->isSymbolDefined(node->getName()))
    {
        error(node, Errors::E_INVALID_REDECLARATION_1, node->getName());
        return;
    }

    //type = currentScope->getForwardDeclaration(node->getName());
    if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol && !node->getType())
    {
        //register a type place holder for protocol
        type = Type::newTypeAlias(node->getName(), nullptr, nullptr);
    }
    else
    {
        shared_ptr<TypeResolver> typeResolver(new TypeResolver(symbolRegistry, semanticAnalyzer, this, ctx, true));
        type = resolveType(node->getType(), true);
        assert(type != nullptr && "Cannot resolve type");
        //TypeBuilderPtr builder = static_pointer_cast<TypeBuilder>(type);
        //builder->setInnerType(type);
        //builder->initAlias(node->getType(), typeResolver);
    }
    validateDeclarationModifiers(node);
    declarationFinished(node->getName(), type, node);
    currentScope->addSymbol(node->getName(), type);
}
void DeclarationAnalyzer::visitTypeAlias(const TypeAliasPtr& node)
{
    SymbolScope* scope = nullptr;
    TypePtr type;
    SymbolScope* currentScope = symbolRegistry->getCurrentScope();

    //check if this type is already defined
    symbolRegistry->lookupType(node->getName(), &scope, &type);
    if(type && scope == currentScope)
    {
        //invalid redeclaration of type T
        error(node, Errors::E_INVALID_REDECLARATION_1, node->getName());
        return;
    }
    type = Type::newType(node->getName(), Type::Alias);
    if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol && !node->getType())
    {
        //register a type place holder for protocol
    }
    else
    {
        TypePtr innerType = lookupType(node->getType());
        if(innerType)
            type = innerType;
        //static_pointer_cast<TypeBuilder>(type)->setInnerType(innerType);
    }
    currentScope->addSymbol(node->getName(), type);
    validateDeclarationModifiers(node);
    declarationFinished(node->getName(), type, node);
}
Exemple #3
0
void FunctionAnalyzer::visitClass(const ClassDefPtr& node)
{
    SymbolScope* scope = symbolRegistry->getCurrentScope();
    SymbolPtr sym = scope->getForwardDeclaration(node->getIdentifier()->getName());
    TypePtr type = static_pointer_cast<Type>(sym);
    ScopeGuard guard(symbolRegistry, type->getScope());
    SCOPED_SET(ctx->currentType, type);
    semanticAnalyzer->visitImplementation(node, this, true);
}
TypePtr DeclarationAnalyzer::getOrDefineType(const std::shared_ptr<TypeDeclaration>& node)
{
    SymbolScope* currentScope = symbolRegistry->getCurrentScope();
    TypeIdentifierPtr id = node->getIdentifier();
    TypePtr type = currentScope->getForwardDeclaration(id->getName());
    if(type)
        return type;
    type = defineType(node);
    return type;
}
Exemple #5
0
/*!
    * Check if a symbol is defined. This will not use LazySymbolResolver to resolve it if it's undefined
    */
bool SymbolRegistry::isSymbolDefined(const std::wstring& name) const
{
    SymbolScope* s = currentScope;
    for(; s; s = s->parent)
    {
        if(s->isSymbolDefined(name))
            return true;
    }
    return false;
}
void DeclarationAnalyzer::visitExtension(const ExtensionDefPtr& node)
{
    if(isLazyDeclared(node))
        return;
    if(ctx->currentFunction || ctx->currentType)
    {
        error(node, Errors::E_A_MAY_ONLY_BE_DECLARED_AT_FILE_SCOPE_1, node->getIdentifier()->getName());
        return;
    }
    //if(parentNode && parentNode->getNodeType() != NodeType::Program)
    if(node->getGenericParametersDef())
    {
        error(node, Errors::E_GENERIC_ARGUMENTS_ARE_NOT_ALLOWED_ON_AN_EXTENSION);
        return;
    }
    //TypePtr type = lookupType(node->getIdentifier());
    SymbolScope* scope = symbolRegistry->getCurrentScope();
    TypePtr type = symbolRegistry->lookupType(node->getIdentifier()->getName());
    if(!type)
        type = scope->getForwardDeclaration(node->getIdentifier()->getName());
    if(!type)
    {
        error(node->getIdentifier(), Errors::E_USE_OF_UNDECLARED_TYPE_1, node->getIdentifier()->getName());
        return;
    }
    ScopeGuard guard(symbolRegistry, type->getScope());

    Type::Category category = type->getCategory();
    if(category == Type::Protocol)
    {
        error(node, Errors::E_PROTOCOL_A_CANNOT_BE_EXTENDED_1, type->getName());
        return;
    }
    if(category != Type::Struct && category != Type::Enum && category != Type::Class)
    {
        error(node, Errors::E_NON_NOMINAL_TYPE_A_CANNOT_BE_EXTENDED_1, node->getIdentifier()->getName());
        return;
    }

    TypePtr extension = Type::newExtension(type);
    symbolRegistry->getFileScope()->addExtension(extension);
    static_pointer_cast<SemanticExtensionDef>(node)->extension = extension;
    SCOPED_SET(ctx->currentType, type);
    SCOPED_SET(ctx->currentExtension, extension);
    for(const DeclarationPtr& decl : *node)
    {
        if(decl->getNodeType() == NodeType::ValueBindings)
        {
            error(node, Errors::E_EXTENSIONS_MAY_NOT_CONTAIN_STORED_PROPERTIES);
            continue;
        }
        decl->accept(this);
    }
}
Exemple #7
0
void FunctionAnalyzer::visitAccessor(const CodeBlockPtr& accessor, const ParametersNodePtr& params, const SymbolPtr& setter, int modifiers)
{
    if(!accessor)
        return;
    ScopedCodeBlockPtr codeBlock = std::static_pointer_cast<ScopedCodeBlock>(accessor);
    SymbolScope *scope = codeBlock->getScope();
    ScopeGuard scopeGuard(codeBlock.get(), this);
    (void) scopeGuard;
    if(setter)
        scope->addSymbol(setter);
    params->accept(this);
    declarationAnalyzer->prepareParameters(scope, params);

    SCOPED_SET(ctx->currentFunction, accessor->getType());

    accessor->accept(semanticAnalyzer);
}
Exemple #8
0
bool SymbolRegistry::lookupSymbol(SymbolScope* scope, const std::wstring& name, SymbolScope** container, SymbolPtr* ret, bool lazyResolve)
{
    SymbolScope* s = scope;
    for(; s; s = s->parent)
    {
        SymbolPtr symbol = s->lookup(name, lazyResolve);
        if(symbol)
        {
            if(container)
                *container = s;
            if(ret)
                *ret = symbol;
            return true;
        }
    }
    return false;
}
TypePtr DeclarationAnalyzer::defineType(const std::shared_ptr<TypeDeclaration>& node)
{
    TypeIdentifierPtr id = node->getIdentifier();

    //Analyze the type's category
    Type::Category category;
    switch(node->getNodeType())
    {
        case NodeType::Enum:
            category = Type::Enum;
            break;
        case NodeType::Class:
            category = Type::Class;
            break;
        case NodeType::Struct:
            category = Type::Struct;
            break;
        case NodeType::Protocol:
            category = Type::Protocol;
            break;
        default:
            assert(0 && "Impossible to execute here.");
    }

    //it's inside the type's scope, so need to access parent scope;

    //prepare for generic types
    GenericParametersDefPtr genericParams = node->getGenericParametersDef();

    //check if it's defined as a nested type
    if(ctx->currentType)
    {
        if(genericParams)
        {
            error(node, Errors::E_GENERIC_TYPE_A_NESTED_IN_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName());
            return nullptr;
        }
        if(ctx->currentType->isGenericType())
        {
            error(node, Errors::E_TYPE_A_NESTED_IN_GENERIC_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName());
            return nullptr;
        }
    }
    
    //register this type
    SymbolScope* currentScope = symbolRegistry->getCurrentScope();
    TypeBuilderPtr type = static_pointer_cast<TypeBuilder>(currentScope->getForwardDeclaration(id->getName()));
    S_ASSERT(type == nullptr);
    type = static_pointer_cast<TypeBuilder>(Type::newType(id->getName(), category));
    currentScope->addForwardDeclaration(type);
    TypeDeclarationPtr tnode = dynamic_pointer_cast<TypeDeclaration>(node);
    type->setReference(tnode);    
    if(tnode)
        tnode->setType(type);

    assert(type != nullptr);
    assert(type->getCategory() == category);
    //prepare for generic
    if(!type->getGenericDefinition() && node->getGenericParametersDef())
    {
        GenericParametersDefPtr genericParams = node->getGenericParametersDef();
        GenericDefinitionPtr generic = prepareGenericTypes(genericParams);
        generic->registerTo(type->getScope());
        type->setGenericDefinition(generic);
    }
    
    if(node->hasModifier(DeclarationModifiers::Final))
        type->setFlags(SymbolFlagFinal, true);
    static_pointer_cast<TypeBuilder>(type)->setModuleName(ctx->currentModule->getName());
    ctx->allTypes.push_back(type);
    
    //check inheritance clause
    {
        TypePtr parent = nullptr;
        bool first = true;

        ScopeGuard scope(symbolRegistry, type->getScope());
        SCOPED_SET(ctx->currentType, type);
        for(const TypeIdentifierPtr& parentType : node->getParents())
        {
            parentType->accept(this);
            if(first)
                declareImmediately(parentType->getName());
            TypePtr ptr = resolveType(parentType, true);
            Type::Category pcategory = ptr->getCategory();
            if(pcategory == Type::Specialized)
                pcategory = ptr->getInnerType()->getCategory();
            if(pcategory == Type::Class && category == Type::Class)
            {
                if(!first)
                {
                    //only the first type can be class type
                    error(parentType, Errors::E_SUPERCLASS_MUST_APPEAR_FIRST_IN_INHERITANCE_CLAUSE_1, toString(parentType));
                    return nullptr;
                }
                parent = ptr;
                if(parent->hasFlags(SymbolFlagFinal))
                {
                    error(parentType, Errors::E_INHERITANCE_FROM_A_FINAL_CLASS_A_1, parentType->getName());
                    return nullptr;
                }
            }
            else if(category == Type::Enum && pcategory != Type::Protocol)
            {

                if(parent)//already has a raw type
                {
                    error(parentType, Errors::E_MULTIPLE_ENUM_RAW_TYPES_A_AND_B_2, parent->toString(), ptr->toString());
                    return nullptr;
                }
                if(!first)
                {
                    error(parentType, Errors::E_RAW_TYPE_A_MUST_APPEAR_FIRST_IN_THE_ENUM_INHERITANCE_CLAUSE_1, ptr->toString());
                    return nullptr;
                }
                //check if the raw type is literal convertible
                if(!isLiteralTypeForEnum(symbolRegistry->getGlobalScope(), ptr))
                {
                    error(parentType, Errors::E_RAW_TYPE_A_IS_NOT_CONVERTIBLE_FROM_ANY_LITERAL_1, ptr->toString());
                    return nullptr;
                }
                if(!ptr->canAssignTo(symbolRegistry->getGlobalScope()->Equatable()))
                {
                    error(parentType, Errors::E_RAWREPRESENTABLE_INIT_CANNOT_BE_SYNTHESIZED_BECAUSE_RAW_TYPE_A_IS_NOT_EQUATABLE_1, ptr->toString());
                    return nullptr;
                }
                parent = ptr;
            }
            else if(pcategory == Type::Protocol)
            {
                type->addProtocol(ptr);
            }
            else
            {
                if(category == Type::Class)
                    error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_NON_CLASS_TYPE_1, toString(parentType));
                else
                    error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_TYPE_1, toString(parentType));
                return nullptr;
            }
            first = false;
        }

        type->setParentType(parent);
        if(parent && parent->getAccessLevel() == AccessLevelPublic && (node->getModifiers() & DeclarationModifiers::AccessModifiers) == 0)
            type->setAccessLevel(AccessLevelPublic);//when access level is undefined, try to inherit base's access level
        else
            type->setAccessLevel(parseAccessLevel(node->getModifiers()));
    }
    

    declarationFinished(type->getName(), type, node);
    return type;
}
void DeclarationAnalyzer::visitEnum(const EnumDefPtr& node)
{
    if(isLazyDeclared(node))
        return;
    TypeBuilderPtr type = static_pointer_cast<TypeBuilder>(getOrDefineType(node));
    ScopeGuard scope(symbolRegistry, type->getScope());
    SCOPED_SET(ctx->currentType, type);
    SCOPED_SET(ctx->currentExtension, nullptr);
    SCOPED_SET(ctx->currentFunction, nullptr);


    GlobalScope* global = symbolRegistry->getGlobalScope();
    SymbolScope* local = symbolRegistry->getCurrentScope();
    //check if it's raw value enum
    bool isRawValues = false;
    if(node->numParents() > 0)
    {
        TypePtr firstParent = lookupType(node->getParent(0));
        if(firstParent)
        {
            Type::Category  category = firstParent->getCategory();
            isRawValues = category == Type::Struct || category == Type::Enum || category == Type::Aggregate || category == Type::Class;
            if(isRawValues)
                type->setParentType(firstParent);
        }
    }

    //initialize enum's cases
    if(isRawValues)
    {
        if(!node->numCases())
        {
            error(node, Errors::E_ENUM_WITH_NO_CASES_CANNOT_DECLARE_A_RAW_TYPE);
            return;
        }
        //Add RawRepresentable protocol if it's not implemented
        if(!type->canAssignTo(global->RawRepresentable()))
        {
            makeRawRepresentable(type, global);
        }

        TypePtr rawType = type->getParentType();
        assert(rawType != nullptr);
        bool integerConvertible = rawType->canAssignTo(global->IntegerLiteralConvertible());
        for(auto c : node->getCases())
        {
            if(!c.value && !integerConvertible)
            {
                //Enum cases require explicit raw values when the raw type is not integer literal convertible
                error(node, Errors::E_ENUM_CASES_REQUIRE_EXPLICIT_RAW_VALUES_WHEN_THE_RAW_TYPE_IS_NOT_INTEGER_LITERAL_CONVERTIBLE);
                return;
            }
            if(c.value)
            {
                if(dynamic_pointer_cast<TupleType>(c.value))
                {
                    error(node, Errors::E_ENUM_WITH_RAW_TYPE_CANNOT_HAVE_CASES_WITH_ARGUMENTS);
                    return;
                }
            }
            type->addEnumCase(c.name, global->Void());
            //register it to scope
            local->addSymbol(SymbolPlaceHolderPtr(new SymbolPlaceHolder(c.name, type, SymbolPlaceHolder::R_PARAMETER, SymbolFlagReadable | SymbolFlagMember | SymbolFlagStatic | SymbolFlagInitialized)));
        }
    }
    else
    {
        //it's an associated-values enum
        for(auto c : node->getCases())
        {
            TypePtr associatedType = global->Void();
            if(c.value)
            {
                TypeNodePtr typeNode = dynamic_pointer_cast<TypeNode>(c.value);
                if(!typeNode)
                {
                    error(node, Errors::E_ENUM_CASE_CANNOT_HAVE_A_RAW_VALUE_IF_THE_ENUM_DOES_NOT_HAVE_A_RAW_TYPE);
                    return;
                }
                assert(typeNode != nullptr);
                associatedType = resolveType(typeNode, true);
            }
            type->addEnumCase(c.name, associatedType);
            if(associatedType == global->Void())
                local->addSymbol(SymbolPlaceHolderPtr(new SymbolPlaceHolder(c.name, type, SymbolPlaceHolder::R_PARAMETER, SymbolFlagReadable | SymbolFlagMember | SymbolFlagStatic | SymbolFlagInitialized)));
        }
    }
    //check member declaration of enum
    {
        SCOPED_SET(ctx->flags, (ctx->flags & (~SemanticContext::FLAG_PROCESS_IMPLEMENTATION)) | SemanticContext::FLAG_PROCESS_DECLARATION);
        for (const DeclarationPtr &decl : *node)
        {
            bool isStatic = decl->hasModifier(DeclarationModifiers::Class) || decl->hasModifier(DeclarationModifiers::Static);
            if (!isStatic && (decl->getNodeType() == NodeType::ValueBindings))
            {
                error(node, Errors::E_ENUMS_MAY_NOT_CONTAIN_STORED_PROPERTIES);
                continue;
            }
            decl->accept(this);
        }
        //add a default initializer for raw value enum
        if(isRawValues)
        {
            vector<Parameter> params = {Parameter(L"rawValue", false, type->getParentType())};
            TypePtr initType = Type::newFunction(params, global->Void(), false, nullptr);
            initType->setFlags(SymbolFlagAllocatingInit, true);
            static_pointer_cast<TypeBuilder>(initType)->setDeclaringType(type);
            initType->setFlags(SymbolFlagInit | SymbolFlagFailableInitializer | SymbolFlagMember | SymbolFlagAllocatingInit);
            FunctionSymbolPtr init(new FunctionSymbol(L"init", initType, FunctionRoleInit, nullptr));
            declarationFinished(init->getName(), init, nullptr);
        }
    }
    if(type->getParentType() != nullptr)
        verifyAccessLevel(node, type->getParentType(), DeclarationTypeEnum, ComponentTypeRawType);
    validateDeclarationModifiers(node);
    //visitImplementation(node);
}
TypePtr DeclarationAnalyzer::defineType(const std::shared_ptr<TypeDeclaration>& node)
{
    TypeIdentifierPtr id = node->getIdentifier();
    SymbolScope* scope = NULL;
    TypePtr type;

    //Analyze the type's category
    Type::Category category;
    switch(node->getNodeType())
    {
        case NodeType::Enum:
            category = Type::Enum;
            break;
        case NodeType::Class:
            category = Type::Class;
            break;
        case NodeType::Struct:
            category = Type::Struct;
            break;
        case NodeType::Protocol:
            category = Type::Protocol;
            break;
        default:
            assert(0 && "Impossible to execute here.");
    }

    //it's inside the type's scope, so need to access parent scope;
    SymbolScope* typeScope = symbolRegistry->getCurrentScope();
    SymbolScope* currentScope = typeScope->getParentScope();

    //check if this type is already defined
    symbolRegistry->lookupType(id->getName(), &scope, &type);
    if(type && scope == currentScope)
    {
        //invalid redeclaration of type T
        error(node, Errors::E_INVALID_REDECLARATION_1, id->getName());
        return nullptr;
    }
    //prepare for generic types
    GenericDefinitionPtr generic;
    GenericParametersDefPtr genericParams = node->getGenericParametersDef();

    //check if it's defined as a nested type
    if(ctx->currentType)
    {
        if(genericParams)
        {
            error(node, Errors::E_GENERIC_TYPE_A_NESTED_IN_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName());
            return nullptr;
        }
        if(ctx->currentType->isGenericType())
        {
            error(node, Errors::E_TYPE_A_NESTED_IN_GENERIC_TYPE_B_IS_NOT_ALLOWED_2, id->getName(), ctx->currentType->getName());
            return nullptr;
        }
    }

    if(genericParams)
    {
        generic = prepareGenericTypes(genericParams);
        generic->registerTo(typeScope);
    }

    //check inheritance clause
    TypePtr parent = nullptr;
    std::vector<TypePtr> protocols;
    bool first = true;

    for(const TypeIdentifierPtr& parentType : node->getParents())
    {
        parentType->accept(semanticAnalyzer);
        TypePtr ptr = this->lookupType(parentType);
        if(ptr->getCategory() == Type::Class && category == Type::Class)
        {
            if(!first)
            {
                //only the first type can be class type
                error(parentType, Errors::E_SUPERCLASS_MUST_APPEAR_FIRST_IN_INHERITANCE_CLAUSE_1, toString(parentType));
                return nullptr;
            }
            parent = ptr;
            if(parent->hasFlags(SymbolFlagFinal))
            {
                error(parentType, Errors::E_INHERITANCE_FROM_A_FINAL_CLASS_A_1, parentType->getName());
                return nullptr;
            }
        }
        else if(category == Type::Enum && ptr->getCategory() != Type::Protocol)
        {

            if(parent)//already has a raw type
            {
                error(parentType, Errors::E_MULTIPLE_ENUM_RAW_TYPES_A_AND_B_2, parent->toString(), ptr->toString());
                return nullptr;
            }
            if(!first)
            {
                error(parentType, Errors::E_RAW_TYPE_A_MUST_APPEAR_FIRST_IN_THE_ENUM_INHERITANCE_CLAUSE_1, ptr->toString());
                return nullptr;
            }
            //check if the raw type is literal convertible
            if(!isLiteralTypeForEnum(symbolRegistry->getGlobalScope(), ptr))
            {
                error(parentType, Errors::E_RAW_TYPE_A_IS_NOT_CONVERTIBLE_FROM_ANY_LITERAL_1, ptr->toString());
                return nullptr;
            }
            if(!ptr->canAssignTo(symbolRegistry->getGlobalScope()->Equatable()))
            {
                error(parentType, Errors::E_RAWREPRESENTABLE_INIT_CANNOT_BE_SYNTHESIZED_BECAUSE_RAW_TYPE_A_IS_NOT_EQUATABLE_1, ptr->toString());
                return nullptr;
            }
            parent = ptr;
        }
        else if(ptr->getCategory() == Type::Protocol)
        {
            protocols.push_back(ptr);
        }
        else
        {
            if(category == Type::Class)
                error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_NON_CLASS_TYPE_1, toString(parentType));
            else
                error(parentType, Errors::E_INHERITANCE_FROM_NONE_PROTOCOL_TYPE_1, toString(parentType));
            return nullptr;
        }
        first = false;
    }

    //register this type
    type = Type::newType(node->getIdentifier()->getName(), category, node, parent, protocols, generic);
    node->setType(type);
    if(parent && parent->getAccessLevel() == AccessLevelPublic && (node->getModifiers() & DeclarationModifiers::AccessModifiers) == 0)
        type->setAccessLevel(AccessLevelPublic);//when access level is undefined, try to inherit base's access level
    else
        type->setAccessLevel(parseAccessLevel(node->getModifiers()));
    currentScope->addSymbol(type);
    if(node->hasModifier(DeclarationModifiers::Final))
        type->setFlags(SymbolFlagFinal, true);

    declarationFinished(type->getName(), type, node);
    return type;
}
void SemanticAnalyzer::visitValueBinding(const ValueBindingPtr& node)
{
    PatternPtr name = node->getName();
    //tuple was already exploded in declaration analyzer
    if(name->getNodeType() == NodeType::Tuple)
    {
        validateTupleTypeDeclaration(node);
    }
    if (name->getNodeType() != NodeType::Identifier)
        return;
    if(node->getOwner()->isReadOnly() && !node->getInitializer() && ctx->currentType == nullptr)
    {
        error(node, Errors::E_LET_REQUIRES_INITIALIZER);
        return;
    }
    //handle type inference for temporary variable
    if(node->isTemporary() && node->getInitializer())
    {
        //temporary variable always has an initializer
        TypePtr initializerType;
        TypePtr declaredType = node->getType();

        SCOPED_SET(ctx->contextualType, declaredType);
        node->getInitializer()->accept(this);
        initializerType = node->getInitializer()->getType();
        assert(initializerType != nullptr);

        if(declaredType)
        {
            //it has both type definition and initializer, then we need to check if the initializer expression matches the type annotation
            if(!initializerType->canAssignTo(declaredType))
            {
                error(node, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initializerType->toString(), declaredType->toString());
                return;
            }
        }
        else
        {
            node->setType(initializerType);
        }
    }
    

    //add implicitly constructor for Optional
    IdentifierPtr id = static_pointer_cast<Identifier>(node->getName());
    SymbolScope* currentScope = symbolRegistry->getCurrentScope();


    TypePtr declaredType = node->getType() ? node->getType() : lookupType(node->getDeclaredType());
    SCOPED_SET(ctx->contextualType, declaredType);
    if(!declaredType && !node->getInitializer())
    {
        error(node, Errors::E_TYPE_ANNOTATION_MISSING_IN_PATTERN);
        return;
    }
    SymbolPtr sym = currentScope->lookup(id->getIdentifier());
    assert(sym != nullptr);
    SymbolPlaceHolderPtr placeholder = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym);
    assert(placeholder != nullptr);
    if(declaredType)
    {
        placeholder->setType(declaredType);
    }
    ExpressionPtr initializer = node->getInitializer();
    if(initializer)
    {
        placeholder->setFlags(SymbolFlagInitializing, true);
        ExpressionPtr initializer = transformExpression(declaredType, node->getInitializer());
        node->setInitializer(initializer);
        TypePtr actualType = initializer->getType();
        assert(actualType != nullptr);
        if(declaredType)
        {
            if(!Type::equals(actualType, declaredType) && !canConvertTo(initializer, declaredType))
            {
                error(initializer, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, actualType->toString(), declaredType->toString());
                return;
            }
        }

        if(!declaredType)
            placeholder->setType(actualType);
    }
    assert(placeholder->getType() != nullptr);
    placeholder->setFlags(SymbolFlagInitializing, false);
    //optional type always considered initialized, compiler will make it has a default value nil
    TypePtr symbolType = sym->getType();
    GlobalScope* global = symbolRegistry->getGlobalScope();
    if(initializer || global->isOptional(symbolType) || global->isImplicitlyUnwrappedOptional(symbolType))
        markInitialized(placeholder);

    if (initializer)
        placeholder->setFlags(SymbolFlagHasInitializer, true);
    if(node->isTemporary())
    {
        placeholder->setFlags(SymbolFlagTemporary, true);
        markInitialized(placeholder);
    }

    if(!node->isTemporary())
    {
        //check access control level
        DeclarationType decl = ctx->currentType ? DeclarationTypeProperty : DeclarationTypeVariable;
        declarationAnalyzer->verifyAccessLevel(node->getOwner(), placeholder->getType(), decl, ComponentTypeType);
    }
    if(ctx->currentType && ctx->currentType->getCategory() == Type::Protocol)
    {
        error(node, Errors::E_PROTOCOL_VAR_MUST_BE_COMPUTED_PROPERTY_1);
    }
}