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); }
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; }
/*! * 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); } }
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); }
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); } }