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; }
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); }