//===--- ModuleFile.cpp - Loading a serialized module -----------*- c++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "ModuleFile.h" #include "ModuleFormat.h" #include "swift/AST/AST.h" #include "swift/Basic/STLExtras.h" #include "swift/Serialization/BCReadingExtras.h" #include "llvm/Support/MemoryBuffer.h" #include using namespace swift; using namespace swift::serialization; static constexpr const auto AF_DontPopBlockAtEnd = llvm::BitstreamCursor::AF_DontPopBlockAtEnd; /// Declares a member \c type that is a std::function compatible with the given /// callable type. /// /// \tparam T A callable type, such as a lambda. template struct as_function : public as_function {}; template struct as_function { using type = std::function; }; /// Returns a std::function that can call a void-returning, single-argument /// lambda without copying it. template static typename as_function::type makeStackLambda(const L &theLambda) { return std::cref(theLambda); } static ModuleStatus validateControlBlock(llvm::BitstreamCursor &cursor, llvm::SmallVectorImpl &scratch) { // The control block is malformed until we've at least read a major version // number. ModuleStatus result = ModuleStatus::Malformed; auto next = cursor.advance(); while (next.Kind != llvm::BitstreamEntry::EndBlock) { if (next.Kind == llvm::BitstreamEntry::Error) return ModuleStatus::Malformed; if (next.Kind == llvm::BitstreamEntry::SubBlock) { // Unknown metadata sub-block, possibly for use by a future version of the // module format. if (cursor.SkipBlock()) return ModuleStatus::Malformed; next = cursor.advance(); continue; } scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case control_block::METADATA: { uint16_t versionMajor = scratch[0]; if (versionMajor > VERSION_MAJOR) return ModuleStatus::FormatTooNew; result = ModuleStatus::Valid; break; } default: // Unknown metadata record, possibly for use by a future version of the // module format. break; } next = cursor.advance(); } return result; } /// Translate from the serialization DefaultArgumentKind enumerators, which are /// guaranteed to be stable, to the AST ones. static Optional getActualDefaultArgKind(uint8_t raw) { switch (static_cast(raw)) { case serialization::DefaultArgumentKind::None: return swift::DefaultArgumentKind::None; case serialization::DefaultArgumentKind::Normal: return swift::DefaultArgumentKind::Normal; case serialization::DefaultArgumentKind::Column: return swift::DefaultArgumentKind::Column; case serialization::DefaultArgumentKind::File: return swift::DefaultArgumentKind::File; case serialization::DefaultArgumentKind::Line: return swift::DefaultArgumentKind::Line; } return Nothing; } Pattern *ModuleFile::maybeReadPattern() { using namespace decls_block; SmallVector scratch; auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (next.Kind != llvm::BitstreamEntry::Record) return nullptr; unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch); switch (kind) { case decls_block::PAREN_PATTERN: { Pattern *subPattern = maybeReadPattern(); assert(subPattern); auto result = new (ModuleContext->Ctx) ParenPattern(SourceLoc(), subPattern, SourceLoc()); result->setType(subPattern->getType()); return result; } case decls_block::TUPLE_PATTERN: { TypeID tupleTypeID; unsigned count; bool hasVararg; TuplePatternLayout::readRecord(scratch, tupleTypeID, count, hasVararg); SmallVector elements; for ( ; count > 0; --count) { scratch.clear(); next = DeclTypeCursor.advance(); assert(next.Kind == llvm::BitstreamEntry::Record); kind = DeclTypeCursor.readRecord(next.ID, scratch); assert(kind == decls_block::TUPLE_PATTERN_ELT); // FIXME: Add something for this record or remove it. uint8_t rawDefaultArg; TuplePatternEltLayout::readRecord(scratch, rawDefaultArg); Pattern *subPattern = maybeReadPattern(); assert(subPattern); // Decode the default argument kind. // FIXME: Default argument expression, if available. swift::DefaultArgumentKind defaultArgKind = swift::DefaultArgumentKind::None; if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg)) defaultArgKind = *defaultArg; elements.push_back(TuplePatternElt(subPattern, nullptr, defaultArgKind)); } auto result = TuplePattern::create(ModuleContext->Ctx, SourceLoc(), elements, SourceLoc(), hasVararg, SourceLoc()); { BCOffsetRAII restoreOffset(DeclTypeCursor); result->setType(getType(tupleTypeID)); } return result; } case decls_block::NAMED_PATTERN: { DeclID varID; NamedPatternLayout::readRecord(scratch, varID); BCOffsetRAII restoreOffset(DeclTypeCursor); auto var = cast(getDecl(varID)); auto result = new (ModuleContext->Ctx) NamedPattern(var); if (var->hasType()) result->setType(var->getType()); return result; } case decls_block::ANY_PATTERN: { TypeID typeID; AnyPatternLayout::readRecord(scratch, typeID); auto result = new (ModuleContext->Ctx) AnyPattern(SourceLoc()); { BCOffsetRAII restoreOffset(DeclTypeCursor); result->setType(getType(typeID)); } return result; } case decls_block::TYPED_PATTERN: { TypeID typeID; TypedPatternLayout::readRecord(scratch, typeID); Pattern *subPattern = maybeReadPattern(); assert(subPattern); TypeLoc typeInfo = TypeLoc::withoutLoc(getType(typeID)); auto result = new (ModuleContext->Ctx) TypedPattern(subPattern, typeInfo); { BCOffsetRAII restoreOffset(DeclTypeCursor); result->setType(typeInfo.getType()); } return result; } default: return nullptr; } } Optional> ModuleFile::maybeReadConformance() { using namespace decls_block; BCOffsetRAII lastRecordOffset(DeclTypeCursor); SmallVector scratch; auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (next.Kind != llvm::BitstreamEntry::Record) return Nothing; unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch); if (kind != PROTOCOL_CONFORMANCE && kind != NO_CONFORMANCE) return Nothing; lastRecordOffset.reset(); if (kind == NO_CONFORMANCE) { DeclID protoID; NoConformanceLayout::readRecord(scratch, protoID); return std::make_pair(cast(getDecl(protoID)), nullptr); } DeclID protoID; unsigned valueCount, typeCount, inheritedCount, defaultedCount; ArrayRef rawIDs; ProtocolConformanceLayout::readRecord(scratch, protoID, valueCount, typeCount, inheritedCount, defaultedCount, rawIDs); ProtocolConformance *conformance = ModuleContext->Ctx.Allocate(1); while (inheritedCount--) { auto inherited = maybeReadConformance(); assert(inherited.hasValue()); conformance->InheritedMapping.insert(inherited.getValue()); } // Reset the offset RAII to the end of the trailing records. lastRecordOffset.reset(); ArrayRef::iterator rawIDIter = rawIDs.begin(); while (valueCount--) { auto first = cast(getDecl(*rawIDIter++)); auto second = cast(getDecl(*rawIDIter++)); conformance->Mapping.insert(std::make_pair(first, second)); } while (typeCount--) { auto first = getType(*rawIDIter++)->castTo(); auto second = getType(*rawIDIter++); conformance->TypeMapping.insert(std::make_pair(first, second)); } while (defaultedCount--) { auto decl = cast(getDecl(*rawIDIter++)); conformance->DefaultedDefinitions.insert(decl); } auto proto = cast(getDecl(protoID)); return std::make_pair(proto, conformance); } GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) { using namespace decls_block; assert(DC && "need a context for the decls in the list"); BCOffsetRAII lastRecordOffset(DeclTypeCursor); SmallVector scratch; StringRef blobData; auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (next.Kind != llvm::BitstreamEntry::Record) return nullptr; unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch, &blobData); if (kind != GENERIC_PARAM_LIST) return nullptr; ArrayRef rawArchetypeIDs; GenericParamListLayout::readRecord(scratch, rawArchetypeIDs); SmallVector archetypes; { BCOffsetRAII restoreOffset(DeclTypeCursor); for (TypeID next : rawArchetypeIDs) archetypes.push_back(getType(next)->castTo()); } SmallVector params; SmallVector requirements; while (true) { lastRecordOffset.reset(); bool shouldContinue = true; auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); switch (recordID) { case GENERIC_PARAM: { DeclID paramDeclID; GenericParamLayout::readRecord(scratch, paramDeclID); { BCOffsetRAII restoreInnerOffset(DeclTypeCursor); auto typeAlias = cast(getDecl(paramDeclID, DC)); params.push_back(GenericParam(typeAlias)); } break; } case GENERIC_REQUIREMENT: { uint8_t rawKind; ArrayRef rawTypeIDs; GenericRequirementLayout::readRecord(scratch, rawKind, rawTypeIDs); switch (rawKind) { case GenericRequirementKind::Conformance: { assert(rawTypeIDs.size() == 2); TypeLoc subject, constraint; { BCOffsetRAII restoreInnerOffset(DeclTypeCursor); subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0])); constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1])); } requirements.push_back(Requirement::getConformance(subject, SourceLoc(), constraint)); break; } case GenericRequirementKind::SameType: { assert(rawTypeIDs.size() == 2); TypeLoc first, second; { BCOffsetRAII restoreInnerOffset(DeclTypeCursor); first = TypeLoc::withoutLoc(getType(rawTypeIDs[0])); second = TypeLoc::withoutLoc(getType(rawTypeIDs[1])); } requirements.push_back(Requirement::getSameType(first, SourceLoc(), second)); break; } default: // Unknown requirement kind. Drop the requirement and continue, but log // an error so that we don't actually try to generate code. error(); } break; } default: // This record is not part of the GenericParamList. shouldContinue = false; break; } if (!shouldContinue) break; } auto paramList = GenericParamList::create(ModuleContext->Ctx, SourceLoc(), params, SourceLoc(), requirements, SourceLoc()); paramList->setAllArchetypes(ModuleContext->Ctx.AllocateCopy(archetypes)); paramList->setOuterParameters(DC->getGenericParamsOfContext()); return paramList; } MutableArrayRef ModuleFile::getTypes(ArrayRef rawTypeIDs, Type *classType) { ASTContext &ctx = ModuleContext->Ctx; auto result = MutableArrayRef(ctx.Allocate(rawTypeIDs.size()), rawTypeIDs.size()); if (classType) *classType = nullptr; TypeLoc *nextType = result.data(); for (TypeID rawID : rawTypeIDs) { auto type = getType(rawID); if (classType && type->getClassOrBoundGenericClass()) { assert(!*classType && "already found a class type"); *classType = type; } new (nextType) auto(TypeLoc::withoutLoc(type)); ++nextType; } return result; } Optional> ModuleFile::readMembers() { using namespace decls_block; auto entry = DeclTypeCursor.advance(); if (entry.Kind != llvm::BitstreamEntry::Record) return Nothing; SmallVector memberIDBuffer; unsigned kind = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer); assert(kind == DECL_CONTEXT); ArrayRef rawMemberIDs; decls_block::DeclContextLayout::readRecord(memberIDBuffer, rawMemberIDs); if (rawMemberIDs.empty()) return MutableArrayRef(); ASTContext &ctx = ModuleContext->Ctx; MutableArrayRef members(ctx.Allocate(rawMemberIDs.size()), rawMemberIDs.size()); auto nextMember = members.begin(); for (DeclID rawID : rawMemberIDs) { *nextMember = getDecl(rawID); assert(*nextMember && "unable to deserialize next member"); ++nextMember; } return members; } Identifier ModuleFile::getIdentifier(IdentifierID IID) { if (IID == 0) return Identifier(); assert(IID <= Identifiers.size() && "invalid identifier ID"); auto identRecord = Identifiers[IID-1]; if (identRecord.Offset == 0) return identRecord.Ident; assert(!IdentifierData.empty() && "no identifier data in module"); StringRef rawStrPtr = IdentifierData.substr(identRecord.Offset); size_t terminatorOffset = rawStrPtr.find('\0'); assert(terminatorOffset != StringRef::npos && "unterminated identifier string data"); return ModuleContext->Ctx.getIdentifier(rawStrPtr.slice(0, terminatorOffset)); } DeclContext *ModuleFile::getDeclContext(DeclID DID) { if (DID == 0) return ModuleContext; Decl *D = getDecl(DID); if (auto ND = dyn_cast(D)) return ND; if (auto ED = dyn_cast(D)) return ED; if (auto CD = dyn_cast(D)) return CD; if (auto DD = dyn_cast(D)) return DD; if (auto FD = dyn_cast(D)) return FD->getBody(); llvm_unreachable("unknown DeclContext kind"); } /// Returns the appropriate module for the given name. /// /// An empty name represents the builtin module. All other names are looked up /// in the ASTContext. static Module *getModule(ASTContext &ctx, Identifier name) { if (name.empty()) return ctx.TheBuiltinModule; // FIXME: provide a real source location. return ctx.getModule(std::make_pair(name, SourceLoc()), false); } /// Translate from the Serialization assocativity enum values to the AST /// strongly-typed enum. /// /// The former is guaranteed to be stable, but may not reflect this version of /// the AST. static Optional getActualAssociativity(uint8_t assoc) { switch (assoc) { case serialization::Associativity::LeftAssociative: return swift::Associativity::Left; case serialization::Associativity::RightAssociative: return swift::Associativity::Right; case serialization::Associativity::NonAssociative: return swift::Associativity::None; default: return Nothing; } } Decl *ModuleFile::getDecl(DeclID DID, Optional ForcedContext, Optional> DidRecord) { if (DID == 0) return nullptr; assert(DID <= Decls.size() && "invalid decl ID"); auto &declOrOffset = Decls[DID-1]; if (declOrOffset.isComplete()) { if (DidRecord) (*DidRecord)(declOrOffset); return declOrOffset; } DeclTypeCursor.JumpToBit(declOrOffset); auto entry = DeclTypeCursor.advance(); if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize decls represented by sub-blocks. error(); return nullptr; } ASTContext &ctx = ModuleContext->Ctx; SmallVector scratch; StringRef blobData; unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); switch (recordID) { case decls_block::TYPE_ALIAS_DECL: { IdentifierID nameID; DeclID contextID; TypeID underlyingTypeID; bool isGeneric; bool isImplicit; ArrayRef inheritedIDs; decls_block::TypeAliasLayout::readRecord(scratch, nameID, contextID, underlyingTypeID, isGeneric, isImplicit, inheritedIDs); auto inherited = MutableArrayRef(ctx.Allocate(inheritedIDs.size()), inheritedIDs.size()); TypeLoc underlyingType; DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = ForcedContext ? *ForcedContext : getDeclContext(contextID); if (declOrOffset.isComplete()) break; TypeLoc *nextInheritedType = inherited.data(); for (TypeID TID : inheritedIDs) { auto type = getType(TID); new (nextInheritedType) TypeLoc(TypeLoc::withoutLoc(type)); ++nextInheritedType; } underlyingType = TypeLoc::withoutLoc(getType(underlyingTypeID)); } auto alias = new (ctx) TypeAliasDecl(SourceLoc(), getIdentifier(nameID), SourceLoc(), underlyingType, DC, inherited); declOrOffset = alias; if (isImplicit) alias->setImplicit(); if (isGeneric) alias->setGenericParameter(); SmallVector protoBuf; SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) { protoBuf.push_back(conformance.getValue().first); conformanceBuf.push_back(conformance.getValue().second); } alias->setProtocols(ctx.AllocateCopy(protoBuf)); alias->setConformances(ctx.AllocateCopy(conformanceBuf)); break; } case decls_block::STRUCT_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; ArrayRef inheritedIDs; decls_block::StructLayout::readRecord(scratch, nameID, contextID, isImplicit, inheritedIDs); MutableArrayRef inherited; DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; inherited = getTypes(inheritedIDs); } auto genericParams = maybeReadGenericParams(DC); auto theStruct = new (ctx) StructDecl(SourceLoc(), getIdentifier(nameID), SourceLoc(), inherited, genericParams, DC); declOrOffset = theStruct; if (DidRecord) { (*DidRecord)(theStruct); DidRecord.reset(); } if (isImplicit) theStruct->setImplicit(); if (genericParams) for (auto &genericParam : *theStruct->getGenericParams()) genericParam.getAsTypeParam()->setDeclContext(theStruct); SmallVector protoBuf; SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) { protoBuf.push_back(conformance.getValue().first); conformanceBuf.push_back(conformance.getValue().second); } theStruct->setProtocols(ctx.AllocateCopy(protoBuf)); theStruct->setConformances(ctx.AllocateCopy(conformanceBuf)); auto members = readMembers(); assert(members.hasValue() && "could not read struct members"); theStruct->setMembers(members.getValue(), SourceRange()); break; } case decls_block::CONSTRUCTOR_DECL: { DeclID parentID; bool isImplicit; TypeID signatureID; DeclID implicitThisID; decls_block::ConstructorLayout::readRecord(scratch, parentID, isImplicit, signatureID, implicitThisID); VarDecl *thisDecl; DeclContext *parent; { BCOffsetRAII restoreOffset(DeclTypeCursor); parent = getDeclContext(parentID); if (declOrOffset.isComplete()) break; thisDecl = cast(getDecl(implicitThisID, nullptr)); } auto genericParams = maybeReadGenericParams(parent); auto ctor = new (ctx) ConstructorDecl(ctx.getIdentifier("constructor"), SourceLoc(), /*args=*/nullptr, thisDecl, genericParams, parent); declOrOffset = ctor; thisDecl->setDeclContext(ctor); Pattern *args = maybeReadPattern(); assert(args && "missing arguments for constructor"); ctor->setArguments(args); // This must be set after recording the constructor in the map. // A polymorphic constructor type needs to refer to the constructor to get // its generic parameters. ctor->setType(getType(signatureID)); if (isImplicit) ctor->setImplicit(); if (genericParams) for (auto &genericParam : *ctor->getGenericParams()) genericParam.getAsTypeParam()->setDeclContext(ctor); break; } case decls_block::VAR_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; TypeID typeID; DeclID getterID, setterID; DeclID overriddenID; decls_block::VarLayout::readRecord(scratch, nameID, contextID, isImplicit, typeID, getterID, setterID, overriddenID); auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID); auto var = new (ctx) VarDecl(SourceLoc(), getIdentifier(nameID), getType(typeID), DC); declOrOffset = var; if (getterID || setterID) { var->setProperty(ctx, SourceLoc(), cast_or_null(getDecl(getterID)), cast_or_null(getDecl(setterID)), SourceLoc()); } if (isImplicit) var->setImplicit(); var->setOverriddenDecl(cast_or_null(getDecl(overriddenID))); break; } case decls_block::FUNC_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; bool isClassMethod; bool isAssignmentOrConversion; TypeID signatureID; DeclID associatedDeclID; DeclID overriddenID; decls_block::FuncLayout::readRecord(scratch, nameID, contextID, isImplicit, isClassMethod, isAssignmentOrConversion, signatureID, associatedDeclID, overriddenID); DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; } // Read generic params before reading the type, because the type may // reference generic parameters, and we want them to have a dummy // DeclContext for now. GenericParamList *genericParams = maybeReadGenericParams(DC); auto fn = new (ctx) FuncDecl(SourceLoc(), SourceLoc(), getIdentifier(nameID), SourceLoc(), genericParams, /*type=*/nullptr, /*body=*/nullptr, DC); declOrOffset = fn; AnyFunctionType *signature; { BCOffsetRAII restoreOffset(DeclTypeCursor); signature = getType(signatureID)->castTo(); // This must be set after recording the constructor in the map. // A polymorphic constructor type needs to refer to the constructor to get // its generic parameters. fn->setType(signature); } SmallVector patternBuf; while (Pattern *pattern = maybeReadPattern()) patternBuf.push_back(pattern); assert(!patternBuf.empty()); size_t patternCount = patternBuf.size() / 2; assert(patternCount * 2 == patternBuf.size() && "two sets of patterns don't match up"); ArrayRef patterns(patternBuf); ArrayRef argPatterns = patterns.slice(0, patternCount); ArrayRef bodyPatterns = patterns.slice(patternCount); auto body = FuncExpr::create(ctx, SourceLoc(), argPatterns, bodyPatterns, TypeLoc::withoutLoc(signature->getResult()), DC); fn->setBody(body); if (genericParams) for (auto &genericParam : *fn->getGenericParams()) genericParam.getAsTypeParam()->setDeclContext(body); fn->setOverriddenDecl(cast_or_null(getDecl(overriddenID))); fn->setStatic(isClassMethod); if (isImplicit) fn->setImplicit(); if (!blobData.empty()) fn->getMutableAttrs().AsmName = ctx.AllocateCopy(blobData); if (isAssignmentOrConversion) { if (fn->isOperator()) fn->getMutableAttrs().Assignment = true; else fn->getMutableAttrs().Conversion = true; } if (Decl *associated = getDecl(associatedDeclID)) { if (auto op = dyn_cast(associated)) { fn->setOperatorDecl(op); DeclAttributes &attrs = fn->getMutableAttrs(); if (isa(op)) attrs.ExplicitPrefix = true; else if (isa(op)) attrs.ExplicitPostfix = true; // Note that an explicit [infix] is not required. } // Otherwise, unknown associated decl kind. } break; } case decls_block::PATTERN_BINDING_DECL: { DeclID contextID; bool isImplicit; decls_block::PatternBindingLayout::readRecord(scratch, contextID, isImplicit); Pattern *pattern = maybeReadPattern(); assert(pattern); auto binding = new (ctx) PatternBindingDecl(SourceLoc(), pattern, /*init=*/nullptr, getDeclContext(contextID)); declOrOffset = binding; if (isImplicit) binding->setImplicit(); break; } case decls_block::PROTOCOL_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; ArrayRef inheritedIDs; decls_block::ProtocolLayout::readRecord(scratch, nameID, contextID, isImplicit, inheritedIDs); DeclContext *DC; MutableArrayRef inherited; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; inherited = getTypes(inheritedIDs); } auto proto = new (ctx) ProtocolDecl(DC, SourceLoc(), SourceLoc(), getIdentifier(nameID), inherited); declOrOffset = proto; if (DidRecord) { (*DidRecord)(proto); DidRecord.reset(); } if (isImplicit) proto->setImplicit(); auto members = readMembers(); assert(members.hasValue() && "could not read struct members"); proto->setMembers(members.getValue(), SourceRange()); break; } case decls_block::PREFIX_OPERATOR_DECL: { IdentifierID nameID; DeclID contextID; decls_block::PrefixOperatorLayout::readRecord(scratch, nameID, contextID); declOrOffset = new (ctx) PrefixOperatorDecl(getDeclContext(contextID), SourceLoc(), SourceLoc(), getIdentifier(nameID), SourceLoc(), SourceLoc(), SourceLoc()); break; } case decls_block::POSTFIX_OPERATOR_DECL: { IdentifierID nameID; DeclID contextID; decls_block::PostfixOperatorLayout::readRecord(scratch, nameID, contextID); declOrOffset = new (ctx) PostfixOperatorDecl(getDeclContext(contextID), SourceLoc(), SourceLoc(), getIdentifier(nameID), SourceLoc(), SourceLoc(), SourceLoc()); break; } case decls_block::INFIX_OPERATOR_DECL: { IdentifierID nameID; DeclID contextID; uint8_t rawAssociativity; unsigned precedence; decls_block::InfixOperatorLayout::readRecord(scratch, nameID, contextID, rawAssociativity, precedence); auto associativity = getActualAssociativity(rawAssociativity); if (!associativity.hasValue()) { error(); return nullptr; } InfixData infixData(precedence, associativity.getValue()); declOrOffset = new (ctx) InfixOperatorDecl(getDeclContext(contextID), SourceLoc(), SourceLoc(), getIdentifier(nameID), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), SourceLoc(), infixData); break; } case decls_block::CLASS_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; ArrayRef inheritedIDs; decls_block::ClassLayout::readRecord(scratch, nameID, contextID, isImplicit, inheritedIDs); MutableArrayRef inherited; Type baseClassTy; DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; inherited = getTypes(inheritedIDs, &baseClassTy); } auto genericParams = maybeReadGenericParams(DC); auto theClass = new (ctx) ClassDecl(SourceLoc(), getIdentifier(nameID), SourceLoc(), inherited, genericParams, DC); declOrOffset = theClass; if (DidRecord) { (*DidRecord)(theClass); DidRecord.reset(); } if (isImplicit) theClass->setImplicit(); if (baseClassTy) theClass->setBaseClassLoc(TypeLoc::withoutLoc(baseClassTy)); if (genericParams) for (auto &genericParam : *theClass->getGenericParams()) genericParam.getAsTypeParam()->setDeclContext(theClass); SmallVector protoBuf; SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) { protoBuf.push_back(conformance.getValue().first); conformanceBuf.push_back(conformance.getValue().second); } theClass->setProtocols(ctx.AllocateCopy(protoBuf)); theClass->setConformances(ctx.AllocateCopy(conformanceBuf)); auto members = readMembers(); assert(members.hasValue() && "could not read class members"); theClass->setMembers(members.getValue(), SourceRange()); break; } case decls_block::ONEOF_DECL: { IdentifierID nameID; DeclID contextID; bool isImplicit; ArrayRef inheritedIDs; decls_block::OneOfLayout::readRecord(scratch, nameID, contextID, isImplicit, inheritedIDs); MutableArrayRef inherited; DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; inherited = getTypes(inheritedIDs); } auto genericParams = maybeReadGenericParams(DC); // FIXME Preserve the isEnum bit. auto oneOf = new (ctx) OneOfDecl(SourceLoc(), /*isEnum*/ false, getIdentifier(nameID), SourceLoc(), inherited, genericParams, DC); declOrOffset = oneOf; if (DidRecord) { (*DidRecord)(oneOf); DidRecord.reset(); } if (isImplicit) oneOf->setImplicit(); if (genericParams) for (auto &genericParam : *oneOf->getGenericParams()) genericParam.getAsTypeParam()->setDeclContext(oneOf); SmallVector protoBuf; SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) { protoBuf.push_back(conformance.getValue().first); conformanceBuf.push_back(conformance.getValue().second); } oneOf->setProtocols(ctx.AllocateCopy(protoBuf)); oneOf->setConformances(ctx.AllocateCopy(conformanceBuf)); auto members = readMembers(); assert(members.hasValue() && "could not read oneof members"); oneOf->setMembers(members.getValue(), SourceRange()); break; } case decls_block::ONEOF_ELEMENT_DECL: { IdentifierID nameID; DeclID contextID; TypeID argTypeID, resTypeID, ctorTypeID; bool isImplicit; decls_block::OneOfElementLayout::readRecord(scratch, nameID, contextID, argTypeID, resTypeID, ctorTypeID, isImplicit); DeclContext *DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; auto argTy = getType(argTypeID); auto resTy = getType(resTypeID); auto elem = new (ctx) OneOfElementDecl(SourceLoc(), SourceLoc(), getIdentifier(nameID), TypeLoc::withoutLoc(argTy), SourceLoc(), TypeLoc::withoutLoc(resTy), DC); declOrOffset = elem; elem->setType(getType(ctorTypeID)); if (isImplicit) elem->setImplicit(); break; } case decls_block::SUBSCRIPT_DECL: { DeclID contextID; bool isImplicit; TypeID declTypeID, elemTypeID; DeclID getterID, setterID; DeclID overriddenID; decls_block::SubscriptLayout::readRecord(scratch, contextID, isImplicit, declTypeID, elemTypeID, getterID, setterID, overriddenID); DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; } Pattern *indices = maybeReadPattern(); assert(indices); auto elemTy = TypeLoc::withoutLoc(getType(elemTypeID)); auto getter = cast_or_null(getDecl(getterID)); auto setter = cast_or_null(getDecl(setterID)); auto subscript = new (ctx) SubscriptDecl(ctx.getIdentifier("__subscript"), SourceLoc(), indices, SourceLoc(), elemTy, SourceRange(), getter, setter, DC); declOrOffset = subscript; subscript->setType(getType(declTypeID)); if (isImplicit) subscript->setImplicit(); auto overriddenDecl = cast_or_null(getDecl(overriddenID)); subscript->setOverriddenDecl(overriddenDecl); break; } case decls_block::EXTENSION_DECL: { TypeID baseID; DeclID contextID; bool isImplicit; ArrayRef inheritedIDs; decls_block::ExtensionLayout::readRecord(scratch, baseID, contextID, isImplicit, inheritedIDs); TypeLoc baseTy; MutableArrayRef inherited; DeclContext *DC; { BCOffsetRAII restoreOffset(DeclTypeCursor); DC = getDeclContext(contextID); if (declOrOffset.isComplete()) break; baseTy = TypeLoc::withoutLoc(getType(baseID)); inherited = getTypes(inheritedIDs); } auto extension = new (ctx) ExtensionDecl(SourceLoc(), baseTy, inherited, DC); declOrOffset = extension; if (isImplicit) extension->setImplicit(); SmallVector protoBuf; SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) { protoBuf.push_back(conformance.getValue().first); conformanceBuf.push_back(conformance.getValue().second); } extension->setProtocols(ctx.AllocateCopy(protoBuf)); extension->setConformances(ctx.AllocateCopy(conformanceBuf)); auto members = readMembers(); assert(members.hasValue() && "could not read extension members"); extension->setMembers(members.getValue(), SourceRange()); baseTy.getType()->getAnyNominal()->addExtension(extension); break; } case decls_block::DESTRUCTOR_DECL: { DeclID parentID; bool isImplicit; TypeID signatureID; DeclID implicitThisID; decls_block::DestructorLayout::readRecord(scratch, parentID, isImplicit, signatureID, implicitThisID); DeclContext *parent = getDeclContext(parentID); if (declOrOffset.isComplete()) break; auto thisDecl = cast(getDecl(implicitThisID, nullptr)); auto dtor = new (ctx) DestructorDecl(ctx.getIdentifier("destructor"), SourceLoc(), thisDecl, parent); declOrOffset = dtor; thisDecl->setDeclContext(dtor); dtor->setType(getType(signatureID)); if (isImplicit) dtor->setImplicit(); break; } case decls_block::XREF: { uint8_t kind; TypeID expectedTypeID; bool isWithinExtension; ArrayRef rawAccessPath; decls_block::XRefLayout::readRecord(scratch, kind, expectedTypeID, isWithinExtension, rawAccessPath); // First, find the module this reference is referring to. Identifier moduleName = getIdentifier(rawAccessPath.front()); rawAccessPath = rawAccessPath.slice(1); Module *M = getModule(ctx, moduleName); assert(M && "missing dependency"); switch (kind) { case XRefKind::SwiftValue: case XRefKind::SwiftGenericParameter: { // Start by looking up the top-level decl in the module. Module *baseModule = M; if (isWithinExtension) { baseModule = getModule(ctx, getIdentifier(rawAccessPath.front())); rawAccessPath = rawAccessPath.slice(1); } SmallVector values; baseModule->lookupValue(Module::AccessPathTy(), getIdentifier(rawAccessPath.front()), NLKind::QualifiedLookup, values); rawAccessPath = rawAccessPath.slice(1); // Then, follow the chain of nested ValueDecls until we run out of // identifiers in the access path. SmallVector baseValues; for (IdentifierID nextID : rawAccessPath) { baseValues.swap(values); values.clear(); for (auto base : baseValues) { if (auto nominal = dyn_cast(base)) { Identifier memberName = getIdentifier(nextID); auto members = nominal->lookupDirect(memberName); values.append(members.begin(), members.end()); } } } // If we have a type to validate against, filter out any ValueDecls that // don't match that type. CanType expectedTy; if (kind == XRefKind::SwiftValue) if (Type maybeExpectedTy = getType(expectedTypeID)) expectedTy = maybeExpectedTy->getCanonicalType(); ValueDecl *result = nullptr; for (auto value : values) { if (value->getModuleContext() != M) continue; if (expectedTy && value->getType()->getCanonicalType() != expectedTy) continue; if (!result || result == value) { result = value; continue; } // It's an error if more than one value has the same type. // FIXME: Functions and constructors can overload based on parameter // names. error(); return nullptr; } // It's an error if lookup doesn't actually find anything -- that means // the module's out of date. if (!result) { error(); return nullptr; } if (kind == XRefKind::SwiftGenericParameter) { GenericParamList *paramList = nullptr; if (auto nominal = dyn_cast(result)) paramList = nominal->getGenericParams(); else if (auto fn = dyn_cast(result)) paramList = fn->getGenericParams(); else if (auto ctor = dyn_cast(result)) paramList = ctor->getGenericParams(); if (!paramList) { error(); return nullptr; } if (expectedTypeID >= paramList->size()) { error(); return nullptr; } result = paramList->getParams()[expectedTypeID].getDecl(); assert(result); } declOrOffset = result; break; } case XRefKind::SwiftOperator: { assert(rawAccessPath.size() == 1 && "can't import operators not at module scope"); Identifier opName = getIdentifier(rawAccessPath.back()); switch (expectedTypeID) { case OperatorKind::Infix: { auto op = M->lookupInfixOperator(opName); declOrOffset = op.hasValue() ? op.getValue() : nullptr; break; } case OperatorKind::Prefix: { auto op = M->lookupPrefixOperator(opName); declOrOffset = op.hasValue() ? op.getValue() : nullptr; break; } case OperatorKind::Postfix: { auto op = M->lookupPostfixOperator(opName); declOrOffset = op.hasValue() ? op.getValue() : nullptr; break; } default: // Unknown operator kind. error(); return nullptr; } break; } default: // Unknown cross-reference kind. error(); return nullptr; } break; } default: // We don't know how to deserialize this kind of decl. error(); return nullptr; } if (DidRecord) (*DidRecord)(declOrOffset); return declOrOffset; } /// Translate from the Serialization calling convention enum values to the AST /// strongly-typed enum. /// /// The former is guaranteed to be stable, but may not reflect this version of /// the AST. static Optional getActualCC(uint8_t cc) { switch (cc) { #define CASE(THE_CC) \ case serialization::AbstractCC::THE_CC: \ return swift::AbstractCC::THE_CC; CASE(C) CASE(ObjCMethod) CASE(Freestanding) CASE(Method) #undef CASE default: return Nothing; } } /// Translate from the serialization Ownership enumerators, which are /// guaranteed to be stable, to the AST ones. static Optional getActualOwnership(serialization::Ownership raw) { switch (raw) { case serialization::Ownership::Strong: return swift::Ownership::Strong; case serialization::Ownership::Unowned: return swift::Ownership::Unowned; case serialization::Ownership::Weak: return swift::Ownership::Weak; } return Nothing; } Type ModuleFile::getType(TypeID TID) { if (TID == 0) return Type(); assert(TID <= Types.size() && "invalid decl ID"); auto &typeOrOffset = Types[TID-1]; if (typeOrOffset.isComplete()) return typeOrOffset; DeclTypeCursor.JumpToBit(typeOrOffset); auto entry = DeclTypeCursor.advance(); if (entry.Kind != llvm::BitstreamEntry::Record) { // We don't know how to serialize types represented by sub-blocks. error(); return nullptr; } ASTContext &ctx = ModuleContext->Ctx; SmallVector scratch; StringRef blobData; unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); switch (recordID) { case decls_block::NAME_ALIAS_TYPE: { DeclID underlyingID; decls_block::NameAliasTypeLayout::readRecord(scratch, underlyingID); auto alias = dyn_cast_or_null(getDecl(underlyingID)); if (!alias) { error(); return nullptr; } typeOrOffset = alias->getDeclaredType(); break; } case decls_block::NOMINAL_TYPE: { DeclID declID; TypeID parentID; decls_block::NominalTypeLayout::readRecord(scratch, declID, parentID); Type parentTy = getType(parentID); // Record the type as soon as possible. Members of a nominal type often // try to refer back to the type. getDecl(declID, Nothing, makeStackLambda([&](Decl *D) { auto nominal = cast(D); typeOrOffset = NominalType::get(nominal, parentTy, ctx); })); assert(typeOrOffset.isComplete()); break; } case decls_block::PAREN_TYPE: { TypeID underlyingID; decls_block::ParenTypeLayout::readRecord(scratch, underlyingID); typeOrOffset = ParenType::get(ctx, getType(underlyingID)); break; } case decls_block::TUPLE_TYPE: { // The tuple record itself is empty. Read all trailing elements. SmallVector elements; while (true) { auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); if (recordID != decls_block::TUPLE_TYPE_ELT) break; IdentifierID nameID; TypeID typeID; bool isVararg; decls_block::TupleTypeEltLayout::readRecord(scratch, nameID, typeID, isVararg); { BCOffsetRAII restoreOffset(DeclTypeCursor); elements.push_back({getType(typeID), getIdentifier(nameID), /*initializer=*/nullptr, isVararg}); } } typeOrOffset = TupleType::get(elements, ctx); break; } case decls_block::FUNCTION_TYPE: { TypeID inputID; TypeID resultID; uint8_t rawCallingConvention; bool autoClosure; bool thin; bool blockCompatible; decls_block::FunctionTypeLayout::readRecord(scratch, inputID, resultID, rawCallingConvention, autoClosure, thin, blockCompatible); auto callingConvention = getActualCC(rawCallingConvention); if (!callingConvention.hasValue()) { error(); return nullptr; } typeOrOffset = FunctionType::get(getType(inputID), getType(resultID), autoClosure, blockCompatible, thin, callingConvention.getValue(), ctx); break; } case decls_block::METATYPE_TYPE: { TypeID instanceID; decls_block::MetaTypeTypeLayout::readRecord(scratch, instanceID); typeOrOffset = MetaTypeType::get(getType(instanceID), ctx); break; } case decls_block::LVALUE_TYPE: { TypeID objectTypeID; bool isImplicit, isNonSettable; decls_block::LValueTypeLayout::readRecord(scratch, objectTypeID, isImplicit, isNonSettable); LValueType::Qual quals; if (isImplicit) quals |= LValueType::Qual::Implicit; if (isNonSettable) quals |= LValueType::Qual::NonSettable; typeOrOffset = LValueType::get(getType(objectTypeID), quals, ctx); break; } case decls_block::REFERENCE_STORAGE_TYPE: { uint8_t rawOwnership; TypeID referentTypeID; decls_block::ReferenceStorageTypeLayout::readRecord(scratch, rawOwnership, referentTypeID); auto ownership = getActualOwnership((serialization::Ownership) rawOwnership); if (!ownership.hasValue()) { error(); break; } typeOrOffset = ReferenceStorageType::get(getType(referentTypeID), ownership.getValue(), ctx); break; } case decls_block::ARCHETYPE_TYPE: { IdentifierID nameID; bool isPrimary; TypeID parentOrIndex; TypeID superclassID; ArrayRef rawConformanceIDs; decls_block::ArchetypeTypeLayout::readRecord(scratch, nameID, isPrimary, parentOrIndex, superclassID, rawConformanceIDs); ArchetypeType *parent = nullptr; Type superclass; Optional index; SmallVector conformances; { BCOffsetRAII restoreOffset(DeclTypeCursor); if (isPrimary) index = parentOrIndex; else parent = getType(parentOrIndex)->castTo(); superclass = getType(superclassID); for (DeclID protoID : rawConformanceIDs) conformances.push_back(cast(getDecl(protoID))); } // See if we triggered deserialization through our conformances. if (typeOrOffset.isComplete()) break; auto archetype = ArchetypeType::getNew(ctx, parent, getIdentifier(nameID), conformances, superclass, index); typeOrOffset = archetype; auto entry = DeclTypeCursor.advance(); if (entry.Kind != llvm::BitstreamEntry::Record) { error(); break; } scratch.clear(); unsigned kind = DeclTypeCursor.readRecord(entry.ID, scratch); if (kind != decls_block::ARCHETYPE_NESTED_TYPE_NAMES) { error(); break; } ArrayRef rawNameIDs; decls_block::ArchetypeNestedTypeNamesLayout::readRecord(scratch, rawNameIDs); entry = DeclTypeCursor.advance(); if (entry.Kind != llvm::BitstreamEntry::Record) { error(); break; } SmallVector scratch2; kind = DeclTypeCursor.readRecord(entry.ID, scratch2); if (kind != decls_block::ARCHETYPE_NESTED_TYPES) { error(); break; } ArrayRef rawTypeIDs; decls_block::ArchetypeNestedTypesLayout::readRecord(scratch2, rawTypeIDs); SmallVector, 4> nestedTypes; for_each(rawNameIDs, rawTypeIDs, [&](IdentifierID nameID, TypeID nestedID) { auto nestedTy = getType(nestedID)->castTo(); nestedTypes.push_back(std::make_pair(getIdentifier(nameID), nestedTy)); }); archetype->setNestedTypes(ctx, nestedTypes); break; } case decls_block::PROTOCOL_COMPOSITION_TYPE: { ArrayRef rawProtocolIDs; decls_block::ProtocolCompositionTypeLayout::readRecord(scratch, rawProtocolIDs); SmallVector protocols; for (TypeID protoID : rawProtocolIDs) protocols.push_back(getType(protoID)); typeOrOffset = ProtocolCompositionType::get(ctx, protocols); break; } case decls_block::SUBSTITUTED_TYPE: { TypeID originalID, replacementID; decls_block::SubstitutedTypeLayout::readRecord(scratch, originalID, replacementID); typeOrOffset = SubstitutedType::get(getType(originalID), getType(replacementID), ctx); break; } case decls_block::BOUND_GENERIC_TYPE: { DeclID declID; TypeID parentID; ArrayRef rawArgumentIDs; decls_block::BoundGenericTypeLayout::readRecord(scratch, declID, parentID, rawArgumentIDs); SmallVector genericArgs; for (TypeID type : rawArgumentIDs) genericArgs.push_back(getType(type)); auto boundTy = BoundGenericType::get(cast(getDecl(declID)), getType(parentID), genericArgs); typeOrOffset = boundTy; // BoundGenericTypes get uniqued in the ASTContext, so it's possible this // type already has its substitutions. In that case, ignore the module's. if (boundTy->hasSubstitutions()) break; SmallVector substitutions; while (true) { auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd); if (entry.Kind != llvm::BitstreamEntry::Record) break; scratch.clear(); unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData); if (recordID != decls_block::BOUND_GENERIC_SUBSTITUTION) break; TypeID archetypeID, replacementID; decls_block::BoundGenericSubstitutionLayout::readRecord(scratch, archetypeID, replacementID); SmallVector conformanceBuf; while (auto conformance = maybeReadConformance()) conformanceBuf.push_back(conformance.getValue().second); { BCOffsetRAII restoreOffset(DeclTypeCursor); substitutions.push_back({getType(archetypeID)->castTo(), getType(replacementID), ctx.AllocateCopy(conformanceBuf)}); } } boundTy->setSubstitutions(ctx.AllocateCopy(substitutions)); break; } case decls_block::POLYMORPHIC_FUNCTION_TYPE: { TypeID inputID; TypeID resultID; DeclID genericContextID; uint8_t rawCallingConvention; bool thin; decls_block::PolymorphicFunctionTypeLayout::readRecord(scratch, inputID, resultID, genericContextID, rawCallingConvention, thin); auto callingConvention = getActualCC(rawCallingConvention); if (!callingConvention.hasValue()) { error(); return nullptr; } Decl *genericContext = getDecl(genericContextID); assert(genericContext && "loading PolymorphicFunctionType before its decl"); GenericParamList *paramList = nullptr; switch (genericContext->getKind()) { case DeclKind::Constructor: paramList = cast(genericContext)->getGenericParams(); break; case DeclKind::Func: paramList = cast(genericContext)->getGenericParams(); break; case DeclKind::Class: case DeclKind::Struct: case DeclKind::OneOf: paramList = cast(genericContext)->getGenericParams(); break; default: break; } assert(paramList && "missing generic params for polymorphic function"); typeOrOffset = PolymorphicFunctionType::get(getType(inputID), getType(resultID), paramList, thin, callingConvention.getValue(), ctx); break; } case decls_block::ARRAY_SLICE_TYPE: { TypeID baseID, implID; decls_block::ArraySliceTypeLayout::readRecord(scratch, baseID, implID); auto sliceTy = ArraySliceType::get(getType(baseID), ctx); typeOrOffset = sliceTy; // Slice types are uniqued by the ASTContext, so they may already have // type information. If so, ignore the information in the module. if (!sliceTy->hasImplementationType()) sliceTy->setImplementationType(getType(implID)); break; } case decls_block::ARRAY_TYPE: { TypeID baseID; uint64_t size; decls_block::ArrayTypeLayout::readRecord(scratch, baseID, size); typeOrOffset = ArrayType::get(getType(baseID), size, ctx); break; } case decls_block::UNBOUND_GENERIC_TYPE: { DeclID genericID; TypeID parentID; decls_block::UnboundGenericTypeLayout::readRecord(scratch, genericID, parentID); auto genericDecl = cast(getDecl(genericID)); typeOrOffset = UnboundGenericType::get(genericDecl, getType(parentID), ctx); break; } default: // We don't know how to deserialize this kind of type. error(); return nullptr; } return typeOrOffset; } ModuleFile::ModuleFile(llvm::OwningPtr &&input) : ModuleContext(nullptr), InputFile(std::move(input)), InputReader(reinterpret_cast(InputFile->getBufferStart()), reinterpret_cast(InputFile->getBufferEnd())), Status(ModuleStatus::Valid) { llvm::BitstreamCursor cursor{InputReader}; for (unsigned char byte : SIGNATURE) { if (cursor.AtEndOfStream() || cursor.Read(8) != byte) return error(); } // Future-proofing: make sure we validate the control block before we try to // read any other blocks. bool hasValidControlBlock = false; SmallVector scratch; auto topLevelEntry = cursor.advance(); while (topLevelEntry.Kind == llvm::BitstreamEntry::SubBlock) { switch (topLevelEntry.ID) { case llvm::bitc::BLOCKINFO_BLOCK_ID: if (cursor.ReadBlockInfoBlock()) return error(); break; case CONTROL_BLOCK_ID: { cursor.EnterSubBlock(CONTROL_BLOCK_ID); ModuleStatus err = validateControlBlock(cursor, scratch); if (err != ModuleStatus::Valid) return error(err); hasValidControlBlock = true; break; } case INPUT_BLOCK_ID: { if (!hasValidControlBlock) return error(); cursor.EnterSubBlock(INPUT_BLOCK_ID); auto next = cursor.advance(); while (next.Kind == llvm::BitstreamEntry::Record) { scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case input_block::SOURCE_FILE: assert(scratch.empty()); SourcePaths.push_back(blobData); break; case input_block::IMPORTED_MODULE: assert(scratch.empty()); Dependencies.push_back(blobData); break; default: // Unknown input kind, possibly for use by a future version of the // module format. // FIXME: Should we warn about this? break; } next = cursor.advance(); } if (next.Kind != llvm::BitstreamEntry::EndBlock) return error(); break; } case DECLS_AND_TYPES_BLOCK_ID: { if (!hasValidControlBlock) return error(); // The decls-and-types block is lazily loaded. Save the cursor and load // any abbrev records at the start of the block. DeclTypeCursor = cursor; DeclTypeCursor.EnterSubBlock(DECLS_AND_TYPES_BLOCK_ID); if (DeclTypeCursor.advance().Kind == llvm::BitstreamEntry::Error) return error(); // With the main cursor, skip over the block and continue. if (cursor.SkipBlock()) return error(); break; } case IDENTIFIER_DATA_BLOCK_ID: { if (!hasValidControlBlock) return error(); cursor.EnterSubBlock(IDENTIFIER_DATA_BLOCK_ID); auto next = cursor.advanceSkippingSubblocks(); while (next.Kind == llvm::BitstreamEntry::Record) { scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case identifier_block::IDENTIFIER_DATA: assert(scratch.empty()); IdentifierData = blobData; break; default: // Unknown identifier data, which this version of the compiler won't // use. break; } next = cursor.advanceSkippingSubblocks(); } if (next.Kind != llvm::BitstreamEntry::EndBlock) return error(); break; } case INDEX_BLOCK_ID: { if (!hasValidControlBlock) return error(); cursor.EnterSubBlock(INDEX_BLOCK_ID); auto next = cursor.advanceSkippingSubblocks(); while (next.Kind == llvm::BitstreamEntry::Record) { scratch.clear(); StringRef blobData; unsigned kind = cursor.readRecord(next.ID, scratch, &blobData); switch (kind) { case index_block::DECL_OFFSETS: assert(blobData.empty()); Decls.assign(scratch.begin(), scratch.end()); break; case index_block::TYPE_OFFSETS: assert(blobData.empty()); Types.assign(scratch.begin(), scratch.end()); break; case index_block::IDENTIFIER_OFFSETS: assert(blobData.empty()); Identifiers.assign(scratch.begin(), scratch.end()); break; case index_block::TOP_LEVEL_DECLS: assert(blobData.empty()); RawTopLevelIDs.assign(scratch.begin(), scratch.end()); break; case index_block::OPERATORS: assert(blobData.empty()); RawOperatorIDs.assign(scratch.begin(), scratch.end()); break; default: // Unknown index kind, which this version of the compiler won't use. break; } next = cursor.advanceSkippingSubblocks(); } if (next.Kind != llvm::BitstreamEntry::EndBlock) return error(); break; } case FALL_BACK_TO_TRANSLATION_UNIT_ID: // This is a bring-up hack and will eventually go away. Status = ModuleStatus::FallBackToTranslationUnit; break; default: // Unknown top-level block, possibly for use by a future version of the // module format. if (cursor.SkipBlock()) return error(); break; } topLevelEntry = cursor.advance(AF_DontPopBlockAtEnd); } if (topLevelEntry.Kind != llvm::BitstreamEntry::EndBlock) return error(); } bool ModuleFile::associateWithModule(Module *module) { assert(!ModuleContext && "already associated with an AST module"); assert(Status == ModuleStatus::Valid && "invalid module file"); ASTContext &ctx = module->Ctx; bool missingDependency = false; for (auto &dependency : Dependencies) { assert(!dependency.Mod && "already loaded?"); Identifier ID = ctx.getIdentifier(dependency.Name); // FIXME: Provide a proper source location. dependency.Mod = ctx.getModule(std::make_pair(ID, SourceLoc()), false); if (!dependency.Mod) missingDependency = true; } if (missingDependency) { error(ModuleStatus::MissingDependency); return false; } ModuleContext = module; // FIXME: The only reason we're deserializing eagerly is to force extensions // to load, which they shouldn't yet anyway. buildTopLevelDeclMap(); return Status == ModuleStatus::Valid; } void ModuleFile::buildTopLevelDeclMap() { // FIXME: be more lazy about deserialization by encoding this some other way. for (DeclID ID : RawTopLevelIDs) { // FIXME: Right now ExtensionDecls are in here as well. if (auto value = dyn_cast(getDecl(ID))) TopLevelDecls[value->getName()].push_back(value); } RawTopLevelIDs.clear(); } void ModuleFile::lookupValue(Identifier name, SmallVectorImpl &results) { auto iter = TopLevelDecls.find(name); if (iter == TopLevelDecls.end()) return; results.append(iter->second.begin(), iter->second.end()); } OperatorKind getOperatorKind(DeclKind kind) { switch (kind) { case DeclKind::PrefixOperator: return Prefix; case DeclKind::PostfixOperator: return Postfix; case DeclKind::InfixOperator: return Infix; default: llvm_unreachable("unknown operator fixity"); } } OperatorDecl *ModuleFile::lookupOperator(Identifier name, DeclKind fixity) { if (!RawOperatorIDs.empty()) { for (DeclID ID : RawOperatorIDs) { auto op = cast(getDecl(ID)); OperatorKey key(op->getName(), getOperatorKind(op->getKind())); Operators[key] = op; } RawOperatorIDs = {}; } return Operators.lookup(OperatorKey(name, getOperatorKind(fixity))); }