bool Type::isKindOf(const TypePtr &protocolOrBase) const { assert(protocolOrBase != nullptr); if(protocolOrBase->getCategory() != Class && protocolOrBase->getCategory() != Protocol) return false; auto iter = parents.find(protocolOrBase); return iter != parents.end(); }
USE_SWALLOW_NS FunctionSymbol::FunctionSymbol(const std::wstring& name, const TypePtr& functionType, const CodeBlockPtr& definition) :name(name), type(functionType), definition(definition) { assert(functionType); assert(functionType->getCategory() == Type::Function); }
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); } }
bool Type::canAssignTo(const TypePtr &type) const { if(type == nullptr) return false; TypePtr self = this->self(); if(equals(self, type)) return true; if(type->getCategory() == Protocol || type->getCategory() == Class) { if(this->category == Type::Specialized) self = innerType; if(self->parents.find(type) != parents.end()) { return true; } return false; } /* if(type->getCategory() != category) return false; if(category == Tuple) { //In tuple type, each element type must can be assigned to corresponding element type in given argument if(elementTypes.size() != type->elementTypes.size()) return false; auto iter1 = elementTypes.begin(); auto iter2 = type->elementTypes.begin(); for(; iter1 != elementTypes.end(); iter1++, iter2++) { if(!(*iter1)->canAssignTo(*iter2)) { return false; } } } */ return equals(self, type); }
void SemanticAnalyzer::checkTupleDefinition(const TuplePtr& tuple, const ExpressionPtr& initializer) { //this is a tuple definition, the corresponding declared type must be a tuple type TypeNodePtr declaredType = tuple->getDeclaredType(); TypePtr type = lookupType(declaredType); if(!type) { error(tuple, Errors::E_USE_OF_UNDECLARED_TYPE_1, toString(declaredType)); return; } if(!(type->getCategory() == Type::Tuple)) { //tuple definition must have a tuple type definition error(tuple, Errors::E_TUPLE_PATTERN_MUST_MATCH_TUPLE_TYPE_1, toString(declaredType)); return; } if(tuple->numElements() != type->numElementTypes()) { //tuple pattern has the wrong length for tuple type '%' error(tuple, Errors::E_TUPLE_PATTERN_MUST_MATCH_TUPLE_TYPE_1, toString(declaredType)); return; } //check if initializer has the same type with the declared type if(initializer) { TypePtr valueType = evaluateType(initializer); if(valueType && !Type::equals(valueType, type)) { //tuple pattern has the wrong length for tuple type '%' //tuple types '%0' and '%1' have a different number of elements (%2 vs. %3) wstring expectedType = type->toString(); wstring got = toString(valueType->numElementTypes()); wstring expected = toString(type->numElementTypes()); error(initializer, Errors::E_TUPLE_TYPES_HAVE_A_DIFFERENT_NUMBER_OF_ELEMENT_4, toString(declaredType), expectedType, got, expected); return; } } for(const PatternPtr& p : *tuple) { NodeType nodeType = p->getNodeType(); if(nodeType != NodeType::Identifier) { } } }
TEST(TestEnumeration, Declaration) { SEMANTIC_ANALYZE(L"enum CompassPoint { \n" L"case North\n" L"case South\n" L"case East\n" L"case West\n" L"}"); dumpCompilerResults(compilerResults); ASSERT_EQ(0, compilerResults.numResults()); TypePtr CompassPoint; ASSERT_NOT_NULL(CompassPoint = dynamic_pointer_cast<Type>(scope->lookup(L"CompassPoint"))); ASSERT_EQ(Type::Enum, CompassPoint->getCategory()); }
/*! * Verify if the specified type conform to the given protocol */ bool DeclarationAnalyzer::verifyProtocolConform(const TypePtr& type, bool supressError) { if(type->getCategory() == Type::Protocol) return true;//do not perform protocol conform on protocol type int idx = 0; TypeBuilderPtr type2 = static_pointer_cast<TypeBuilder>(type); vector<int>& protocolFlags = type2->getProtocolFlags(); for(const TypePtr& protocol : type->getProtocols()) { //TODO check if the protocol is checked if(protocolFlags[idx] == 0) { bool success = verifyProtocolConform(type, protocol, supressError); if(success) { //TODO: mark the protocol is checked protocolFlags[idx] = 1; } } idx++; } return true; }
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); }
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); } } } } }
/*! * 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; } }
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; }
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 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); }
void SemanticAnalyzer::validateTupleTypeDeclaration(const PatternPtr& name, const TypePtr& declType, const TypePtr& initType) { switch(name->getNodeType()) { case NodeType::Identifier: { if(initType && declType && !initType->canAssignTo(declType)) { error(name, Errors::E_CANNOT_CONVERT_EXPRESSION_TYPE_2, initType->toString(), declType->toString()); } break; } case NodeType::TypedPattern: { TypedPatternPtr pat = static_pointer_cast<TypedPattern>(name); assert(pat->getDeclaredType()); TypePtr nameType = lookupType(pat->getDeclaredType()); assert(nameType != nullptr); if(declType && !Type::equals(nameType, declType)) { error(name, Errors::E_TYPE_ANNOTATION_DOES_NOT_MATCH_CONTEXTUAL_TYPE_A_1, declType->toString()); abort(); return; } break; } case NodeType::Tuple: { TuplePtr tuple = static_pointer_cast<Tuple>(name); if(declType) { if((declType->getCategory() != Type::Tuple) || (tuple->numElements() != declType->numElementTypes())) { error(name, Errors::E_TYPE_ANNOTATION_DOES_NOT_MATCH_CONTEXTUAL_TYPE_A_1, declType->toString()); abort(); return; } } int elements = tuple->numElements(); for(int i = 0; i < elements; i++) { PatternPtr element = tuple->getElement(i); TypePtr elementDecl = declType ? declType->getElementType(i) : nullptr; TypePtr elementInit = initType ? initType->getElementType(i) : nullptr; validateTupleTypeDeclaration(element, elementDecl, elementInit); } break; } case NodeType::ValueBindingPattern: break; case NodeType::EnumCasePattern: { break; } case NodeType::TypeCase: case NodeType::TypeCheck: default: error(name, Errors::E_EXPECT_TUPLE_OR_IDENTIFIER); break; } }