mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Proof-of-concept for the above. This shouldn't be common---renames are far more likely, and those we can track---but occurs when the swift_wrapper attribute (the implementation of NS_STRING_ENUM) is active in Swift 4 but not in Swift 3. Note that this only checks the canonical interface type of the declaration, because the non-canonical type may contain references to the declaration's generic parameters.
4569 lines
152 KiB
C++
4569 lines
152 KiB
C++
//===--- Deserialization.cpp - Loading a serialized AST -------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DeserializationErrors.h"
|
|
#include "swift/Serialization/ModuleFile.h"
|
|
#include "swift/Serialization/ModuleFormat.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/DiagnosticsSema.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/ClangImporter/ClangImporter.h"
|
|
#include "swift/Parse/Parser.h"
|
|
#include "swift/Serialization/BCReadingExtras.h"
|
|
#include "swift/Serialization/SerializedModuleLoader.h"
|
|
#include "swift/Basic/Defer.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#define DEBUG_TYPE "Serialization"
|
|
|
|
STATISTIC(NumDeclsLoaded, "# of decls deserialized");
|
|
STATISTIC(NumMemberListsLoaded,
|
|
"# of nominals/extensions whose members were loaded");
|
|
STATISTIC(NumNestedTypeShortcuts,
|
|
"# of same-module nested types resolved without lookup");
|
|
|
|
using namespace swift;
|
|
using namespace swift::serialization;
|
|
using llvm::Expected;
|
|
|
|
StringRef swift::getNameOfModule(const ModuleFile *MF) {
|
|
return MF->Name;
|
|
}
|
|
|
|
namespace {
|
|
struct IDAndKind {
|
|
const Decl *D;
|
|
DeclID ID;
|
|
};
|
|
|
|
static raw_ostream &operator<<(raw_ostream &os, IDAndKind &&pair) {
|
|
return os << Decl::getKindName(pair.D->getKind())
|
|
<< "Decl #" << pair.ID;
|
|
}
|
|
|
|
class PrettyDeclDeserialization : public llvm::PrettyStackTraceEntry {
|
|
const ModuleFile *MF;
|
|
const ModuleFile::Serialized<Decl*> &DeclOrOffset;
|
|
DeclID ID;
|
|
decls_block::RecordKind Kind;
|
|
public:
|
|
PrettyDeclDeserialization(ModuleFile *module,
|
|
const ModuleFile::Serialized<Decl*> &declOrOffset,
|
|
DeclID DID, decls_block::RecordKind kind)
|
|
: MF(module), DeclOrOffset(declOrOffset), ID(DID), Kind(kind) {
|
|
}
|
|
|
|
static const char *getRecordKindString(decls_block::RecordKind Kind) {
|
|
switch (Kind) {
|
|
#define RECORD(Id) case decls_block::Id: return #Id;
|
|
#include "swift/Serialization/DeclTypeRecordNodes.def"
|
|
}
|
|
|
|
llvm_unreachable("Unhandled RecordKind in switch.");
|
|
}
|
|
|
|
void print(raw_ostream &os) const override {
|
|
if (!DeclOrOffset.isComplete()) {
|
|
os << "While deserializing decl #" << ID << " ("
|
|
<< getRecordKindString(Kind) << ")";
|
|
} else {
|
|
os << "While deserializing ";
|
|
|
|
if (auto VD = dyn_cast<ValueDecl>(DeclOrOffset.get())) {
|
|
os << "'" << VD->getName() << "' (" << IDAndKind{VD, ID} << ")";
|
|
} else if (auto ED = dyn_cast<ExtensionDecl>(DeclOrOffset.get())) {
|
|
os << "extension of '" << ED->getExtendedType() << "' ("
|
|
<< IDAndKind{ED, ID} << ")";
|
|
} else {
|
|
os << IDAndKind{DeclOrOffset.get(), ID};
|
|
}
|
|
}
|
|
os << " in '" << getNameOfModule(MF) << "'\n";
|
|
}
|
|
};
|
|
|
|
class PrettyXRefTrace :
|
|
public llvm::PrettyStackTraceEntry,
|
|
public XRefTracePath {
|
|
public:
|
|
explicit PrettyXRefTrace(ModuleDecl &M) : XRefTracePath(M) {}
|
|
|
|
void print(raw_ostream &os) const override {
|
|
XRefTracePath::print(os, "\t");
|
|
}
|
|
};
|
|
|
|
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
|
|
const char *Action;
|
|
const ModuleFile *MF;
|
|
public:
|
|
explicit PrettyStackTraceModuleFile(const char *action, ModuleFile *module)
|
|
: Action(action), MF(module) {}
|
|
|
|
void print(raw_ostream &os) const override {
|
|
os << Action << " \'" << getNameOfModule(MF) << "'\n";
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
const char DeclDeserializationError::ID = '\0';
|
|
void DeclDeserializationError::anchor() {}
|
|
const char XRefError::ID = '\0';
|
|
void XRefError::anchor() {}
|
|
const char OverrideError::ID = '\0';
|
|
void OverrideError::anchor() {}
|
|
const char TypeError::ID = '\0';
|
|
void TypeError::anchor() {}
|
|
|
|
LLVM_NODISCARD
|
|
static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
|
|
std::unique_ptr<llvm::ErrorInfoBase> result;
|
|
llvm::handleAllErrors(std::move(error),
|
|
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
|
|
result = std::move(info);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
|
|
/// Skips a single record in the bitstream.
|
|
///
|
|
/// Returns true if the next entry is a record of type \p recordKind.
|
|
/// Destroys the stream position if the next entry is not a record.
|
|
static void skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
|
|
auto next = cursor.advance(AF_DontPopBlockAtEnd);
|
|
assert(next.Kind == llvm::BitstreamEntry::Record);
|
|
|
|
#if NDEBUG
|
|
cursor.skipRecord(next.ID);
|
|
#else
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
unsigned kind = cursor.readRecord(next.ID, scratch, &blobData);
|
|
assert(kind == recordKind);
|
|
#endif
|
|
}
|
|
|
|
void ModuleFile::fatal(llvm::Error error) {
|
|
if (FileContext) {
|
|
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Name);
|
|
|
|
if (!CompatibilityVersion.empty()) {
|
|
SmallString<16> buffer;
|
|
llvm::raw_svector_ostream out(buffer);
|
|
out << getContext().LangOpts.EffectiveLanguageVersion;
|
|
if (out.str() != CompatibilityVersion) {
|
|
getContext().Diags.diagnose(
|
|
SourceLoc(), diag::serialization_compatibility_version_mismatch,
|
|
out.str(), Name, CompatibilityVersion);
|
|
}
|
|
}
|
|
}
|
|
|
|
logAllUnhandledErrors(std::move(error), llvm::errs(),
|
|
"\n*** DESERIALIZATION FAILURE (please include this "
|
|
"section in any bug report) ***\n");
|
|
abort();
|
|
}
|
|
|
|
ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
|
|
assert(FileContext && "cannot delay actions before associating with a file");
|
|
ModuleDecl *associatedModule = getAssociatedModule();
|
|
|
|
// Check for the common case.
|
|
if (associatedModule->getFiles().size() == 1)
|
|
return *this;
|
|
|
|
for (FileUnit *file : associatedModule->getFiles())
|
|
if (auto *serialized = dyn_cast<SerializedASTFile>(file))
|
|
return serialized->File;
|
|
|
|
llvm_unreachable("should always have FileContext in the list of files");
|
|
}
|
|
|
|
void ModuleFile::finishPendingActions() {
|
|
assert(&getModuleFileForDelayedActions() == this &&
|
|
"wrong module used for delayed actions");
|
|
while (!DelayedGenericEnvironments.empty()) {
|
|
// Force completion of the last generic environment.
|
|
auto genericEnvDC = DelayedGenericEnvironments.back();
|
|
DelayedGenericEnvironments.pop_back();
|
|
(void)genericEnvDC->getGenericEnvironmentOfContext();
|
|
}
|
|
}
|
|
|
|
/// Translate from the serialization DefaultArgumentKind enumerators, which are
|
|
/// guaranteed to be stable, to the AST ones.
|
|
static Optional<swift::DefaultArgumentKind>
|
|
getActualDefaultArgKind(uint8_t raw) {
|
|
switch (static_cast<serialization::DefaultArgumentKind>(raw)) {
|
|
case serialization::DefaultArgumentKind::None:
|
|
return swift::DefaultArgumentKind::None;
|
|
case serialization::DefaultArgumentKind::Normal:
|
|
return swift::DefaultArgumentKind::Normal;
|
|
case serialization::DefaultArgumentKind::Inherited:
|
|
return swift::DefaultArgumentKind::Inherited;
|
|
case serialization::DefaultArgumentKind::Column:
|
|
return swift::DefaultArgumentKind::Column;
|
|
case serialization::DefaultArgumentKind::File:
|
|
return swift::DefaultArgumentKind::File;
|
|
case serialization::DefaultArgumentKind::Line:
|
|
return swift::DefaultArgumentKind::Line;
|
|
case serialization::DefaultArgumentKind::Function:
|
|
return swift::DefaultArgumentKind::Function;
|
|
case serialization::DefaultArgumentKind::DSOHandle:
|
|
return swift::DefaultArgumentKind::DSOHandle;
|
|
case serialization::DefaultArgumentKind::Nil:
|
|
return swift::DefaultArgumentKind::Nil;
|
|
case serialization::DefaultArgumentKind::EmptyArray:
|
|
return swift::DefaultArgumentKind::EmptyArray;
|
|
case serialization::DefaultArgumentKind::EmptyDictionary:
|
|
return swift::DefaultArgumentKind::EmptyDictionary;
|
|
}
|
|
return None;
|
|
}
|
|
|
|
ParameterList *ModuleFile::readParameterList() {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<uint64_t, 8> scratch;
|
|
auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch);
|
|
assert(recordID == PARAMETERLIST);
|
|
(void) recordID;
|
|
unsigned numParams;
|
|
decls_block::ParameterListLayout::readRecord(scratch, numParams);
|
|
|
|
SmallVector<ParamDecl*, 8> params;
|
|
for (unsigned i = 0; i != numParams; ++i) {
|
|
scratch.clear();
|
|
auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch);
|
|
assert(recordID == PARAMETERLIST_ELT);
|
|
(void) recordID;
|
|
|
|
DeclID paramID;
|
|
bool isVariadic;
|
|
uint8_t rawDefaultArg;
|
|
decls_block::ParameterListEltLayout::readRecord(scratch, paramID,
|
|
isVariadic, rawDefaultArg);
|
|
|
|
|
|
auto decl = cast<ParamDecl>(getDecl(paramID));
|
|
decl->setVariadic(isVariadic);
|
|
|
|
// Decode the default argument kind.
|
|
// FIXME: Default argument expression, if available.
|
|
if (auto defaultArg = getActualDefaultArgKind(rawDefaultArg))
|
|
decl->setDefaultArgumentKind(*defaultArg);
|
|
params.push_back(decl);
|
|
}
|
|
|
|
return ParameterList::create(getContext(), params);
|
|
}
|
|
|
|
Expected<Pattern *> ModuleFile::readPattern(DeclContext *owningDC) {
|
|
// Currently, the only case in which this function can fail (return an error)
|
|
// is when reading a pattern for a single variable declaration.
|
|
|
|
using namespace decls_block;
|
|
|
|
auto readPatternUnchecked = [this](DeclContext *owningDC) -> Pattern * {
|
|
Expected<Pattern *> deserialized = readPattern(owningDC);
|
|
if (!deserialized) {
|
|
fatal(deserialized.takeError());
|
|
}
|
|
assert(deserialized.get());
|
|
return deserialized.get();
|
|
};
|
|
|
|
SmallVector<uint64_t, 8> scratch;
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
if (next.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
/// Local function to record the type of this pattern.
|
|
auto recordPatternType = [&](Pattern *pattern, Type type) {
|
|
if (type->hasTypeParameter())
|
|
pattern->setDelayedInterfaceType(type, owningDC);
|
|
else
|
|
pattern->setType(type);
|
|
};
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(next.ID, scratch);
|
|
switch (kind) {
|
|
case decls_block::PAREN_PATTERN: {
|
|
bool isImplicit;
|
|
ParenPatternLayout::readRecord(scratch, isImplicit);
|
|
|
|
Pattern *subPattern = readPatternUnchecked(owningDC);
|
|
|
|
auto result = new (getContext()) ParenPattern(SourceLoc(),
|
|
subPattern,
|
|
SourceLoc(),
|
|
isImplicit);
|
|
|
|
if (Type interfaceType = subPattern->getDelayedInterfaceType())
|
|
result->setDelayedInterfaceType(ParenType::get(getContext(),
|
|
interfaceType), owningDC);
|
|
else
|
|
result->setType(ParenType::get(getContext(), subPattern->getType()));
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
case decls_block::TUPLE_PATTERN: {
|
|
TypeID tupleTypeID;
|
|
unsigned count;
|
|
bool isImplicit;
|
|
|
|
TuplePatternLayout::readRecord(scratch, tupleTypeID, count, isImplicit);
|
|
|
|
SmallVector<TuplePatternElt, 8> 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.
|
|
IdentifierID labelID;
|
|
TuplePatternEltLayout::readRecord(scratch, labelID);
|
|
Identifier label = getIdentifier(labelID);
|
|
|
|
Pattern *subPattern = readPatternUnchecked(owningDC);
|
|
elements.push_back(TuplePatternElt(label, SourceLoc(), subPattern));
|
|
}
|
|
|
|
auto result = TuplePattern::create(getContext(), SourceLoc(),
|
|
elements, SourceLoc(), isImplicit);
|
|
recordPatternType(result, getType(tupleTypeID));
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
case decls_block::NAMED_PATTERN: {
|
|
DeclID varID;
|
|
TypeID typeID;
|
|
bool isImplicit;
|
|
NamedPatternLayout::readRecord(scratch, varID, typeID, isImplicit);
|
|
|
|
auto deserialized = getDeclChecked(varID);
|
|
if (!deserialized) {
|
|
// Pass through the error. It's too bad that it affects the whole pattern,
|
|
// but that's what we get.
|
|
return deserialized.takeError();
|
|
}
|
|
|
|
auto var = cast<VarDecl>(deserialized.get());
|
|
auto result = new (getContext()) NamedPattern(var, isImplicit);
|
|
recordPatternType(result, getType(typeID));
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
case decls_block::ANY_PATTERN: {
|
|
TypeID typeID;
|
|
bool isImplicit;
|
|
|
|
AnyPatternLayout::readRecord(scratch, typeID, isImplicit);
|
|
auto result = new (getContext()) AnyPattern(SourceLoc(), isImplicit);
|
|
recordPatternType(result, getType(typeID));
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
case decls_block::TYPED_PATTERN: {
|
|
TypeID typeID;
|
|
bool isImplicit;
|
|
TypedPatternLayout::readRecord(scratch, typeID, isImplicit);
|
|
|
|
Expected<Pattern *> subPattern = readPattern(owningDC);
|
|
if (!subPattern) {
|
|
// Pass through any errors.
|
|
return subPattern;
|
|
}
|
|
|
|
auto result = new (getContext()) TypedPattern(subPattern.get(), TypeLoc(),
|
|
isImplicit);
|
|
recordPatternType(result, getType(typeID));
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
case decls_block::VAR_PATTERN: {
|
|
bool isImplicit, isLet;
|
|
VarPatternLayout::readRecord(scratch, isLet, isImplicit);
|
|
|
|
Pattern *subPattern = readPatternUnchecked(owningDC);
|
|
|
|
auto result = new (getContext()) VarPattern(SourceLoc(), isLet, subPattern,
|
|
isImplicit);
|
|
if (Type interfaceType = subPattern->getDelayedInterfaceType())
|
|
result->setDelayedInterfaceType(interfaceType, owningDC);
|
|
else
|
|
result->setType(subPattern->getType());
|
|
restoreOffset.reset();
|
|
return result;
|
|
}
|
|
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
SILLayout *ModuleFile::readSILLayout(llvm::BitstreamCursor &Cursor) {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<uint64_t, 16> scratch;
|
|
|
|
auto next = Cursor.advance(AF_DontPopBlockAtEnd);
|
|
assert(next.Kind == llvm::BitstreamEntry::Record);
|
|
|
|
unsigned kind = Cursor.readRecord(next.ID, scratch);
|
|
switch (kind) {
|
|
case decls_block::SIL_LAYOUT: {
|
|
unsigned numFields;
|
|
ArrayRef<uint64_t> types;
|
|
decls_block::SILLayoutLayout::readRecord(scratch, numFields, types);
|
|
|
|
SmallVector<SILField, 4> fields;
|
|
for (auto fieldInfo : types.slice(0, numFields)) {
|
|
bool isMutable = fieldInfo & 0x80000000U;
|
|
auto typeId = fieldInfo & 0x7FFFFFFFU;
|
|
fields.push_back(
|
|
SILField(getType(typeId)->getCanonicalType(),
|
|
isMutable));
|
|
}
|
|
|
|
SmallVector<GenericTypeParamType*, 4> genericParams;
|
|
for (auto typeId : types.slice(numFields)) {
|
|
auto type = getType(typeId)->castTo<GenericTypeParamType>();
|
|
genericParams.push_back(type);
|
|
}
|
|
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
CanGenericSignature sig;
|
|
if (!genericParams.empty() || !requirements.empty()) {
|
|
sig = GenericSignature::get(genericParams, requirements)
|
|
->getCanonicalSignature();
|
|
}
|
|
return SILLayout::get(getContext(), sig, fields);
|
|
}
|
|
default:
|
|
error();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
ProtocolConformanceRef ModuleFile::readConformance(
|
|
llvm::BitstreamCursor &Cursor,
|
|
GenericEnvironment *genericEnv) {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<uint64_t, 16> scratch;
|
|
|
|
auto next = Cursor.advance(AF_DontPopBlockAtEnd);
|
|
assert(next.Kind == llvm::BitstreamEntry::Record);
|
|
|
|
unsigned kind = Cursor.readRecord(next.ID, scratch);
|
|
switch (kind) {
|
|
case ABSTRACT_PROTOCOL_CONFORMANCE: {
|
|
DeclID protoID;
|
|
AbstractProtocolConformanceLayout::readRecord(scratch, protoID);
|
|
auto proto = cast<ProtocolDecl>(getDecl(protoID));
|
|
return ProtocolConformanceRef(proto);
|
|
}
|
|
|
|
case SPECIALIZED_PROTOCOL_CONFORMANCE: {
|
|
TypeID conformingTypeID;
|
|
unsigned numSubstitutions;
|
|
SpecializedProtocolConformanceLayout::readRecord(scratch, conformingTypeID,
|
|
numSubstitutions);
|
|
|
|
ASTContext &ctx = getContext();
|
|
Type conformingType = getType(conformingTypeID);
|
|
if (genericEnv) {
|
|
conformingType = genericEnv->mapTypeIntoContext(conformingType);
|
|
}
|
|
|
|
PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
|
|
"reading specialized conformance for",
|
|
conformingType);
|
|
|
|
// Read the substitutions.
|
|
SmallVector<Substitution, 4> substitutions;
|
|
while (numSubstitutions--) {
|
|
auto sub = maybeReadSubstitution(Cursor, genericEnv);
|
|
assert(sub.hasValue() && "Missing substitution?");
|
|
substitutions.push_back(*sub);
|
|
}
|
|
|
|
ProtocolConformanceRef genericConformance =
|
|
readConformance(Cursor, genericEnv);
|
|
PrettyStackTraceDecl traceTo("... to", genericConformance.getRequirement());
|
|
|
|
assert(genericConformance.isConcrete() && "Abstract generic conformance?");
|
|
auto conformance =
|
|
ctx.getSpecializedConformance(conformingType,
|
|
genericConformance.getConcrete(),
|
|
substitutions);
|
|
return ProtocolConformanceRef(conformance);
|
|
}
|
|
|
|
case INHERITED_PROTOCOL_CONFORMANCE: {
|
|
TypeID conformingTypeID;
|
|
InheritedProtocolConformanceLayout::readRecord(scratch, conformingTypeID);
|
|
|
|
ASTContext &ctx = getContext();
|
|
Type conformingType = getType(conformingTypeID);
|
|
if (genericEnv) {
|
|
conformingType = genericEnv->mapTypeIntoContext(conformingType);
|
|
}
|
|
|
|
PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
|
|
"reading inherited conformance for",
|
|
conformingType);
|
|
|
|
ProtocolConformanceRef inheritedConformance =
|
|
readConformance(Cursor, genericEnv);
|
|
PrettyStackTraceDecl traceTo("... to",
|
|
inheritedConformance.getRequirement());
|
|
|
|
assert(inheritedConformance.isConcrete() &&
|
|
"Abstract inherited conformance?");
|
|
auto conformance =
|
|
ctx.getInheritedConformance(conformingType,
|
|
inheritedConformance.getConcrete());
|
|
return ProtocolConformanceRef(conformance);
|
|
}
|
|
|
|
case NORMAL_PROTOCOL_CONFORMANCE_ID: {
|
|
NormalConformanceID conformanceID;
|
|
NormalProtocolConformanceIdLayout::readRecord(scratch, conformanceID);
|
|
return ProtocolConformanceRef(readNormalConformance(conformanceID));
|
|
}
|
|
|
|
case PROTOCOL_CONFORMANCE_XREF: {
|
|
DeclID protoID;
|
|
DeclID nominalID;
|
|
ModuleID moduleID;
|
|
ProtocolConformanceXrefLayout::readRecord(scratch, protoID, nominalID,
|
|
moduleID);
|
|
|
|
auto nominal = cast<NominalTypeDecl>(getDecl(nominalID));
|
|
PrettyStackTraceDecl trace("cross-referencing conformance for", nominal);
|
|
auto proto = cast<ProtocolDecl>(getDecl(protoID));
|
|
PrettyStackTraceDecl traceTo("... to", proto);
|
|
auto module = getModule(moduleID);
|
|
|
|
SmallVector<ProtocolConformance *, 2> conformances;
|
|
nominal->lookupConformance(module, proto, conformances);
|
|
PrettyStackTraceModuleFile traceMsg(
|
|
"If you're seeing a crash here, check that your SDK and dependencies "
|
|
"are at least as new as the versions used to build", this);
|
|
// This would normally be an assertion but it's more useful to print the
|
|
// PrettyStackTrace here even in no-asserts builds.
|
|
if (conformances.empty())
|
|
abort();
|
|
return ProtocolConformanceRef(conformances.front());
|
|
}
|
|
|
|
// Not a protocol conformance.
|
|
default:
|
|
error();
|
|
ProtocolConformance *conformance = nullptr;
|
|
return ProtocolConformanceRef(conformance); // FIXME: this will assert
|
|
}
|
|
}
|
|
|
|
NormalProtocolConformance *ModuleFile::readNormalConformance(
|
|
NormalConformanceID conformanceID) {
|
|
auto &conformanceEntry = NormalConformances[conformanceID-1];
|
|
if (conformanceEntry.isComplete()) {
|
|
return conformanceEntry.get();
|
|
}
|
|
|
|
using namespace decls_block;
|
|
|
|
// Find the conformance record.
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(conformanceEntry);
|
|
auto entry = DeclTypeCursor.advance();
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
DeclID protoID;
|
|
DeclContextID contextID;
|
|
unsigned valueCount, typeCount;
|
|
ArrayRef<uint64_t> rawIDs;
|
|
SmallVector<uint64_t, 16> scratch;
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(entry.ID, scratch);
|
|
if (kind != NORMAL_PROTOCOL_CONFORMANCE) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
NormalProtocolConformanceLayout::readRecord(scratch, protoID,
|
|
contextID, valueCount,
|
|
typeCount,
|
|
rawIDs);
|
|
|
|
ASTContext &ctx = getContext();
|
|
DeclContext *dc = getDeclContext(contextID);
|
|
Type conformingType = dc->getDeclaredTypeInContext();
|
|
PrettyStackTraceType trace(ctx, "reading conformance for", conformingType);
|
|
|
|
auto proto = cast<ProtocolDecl>(getDecl(protoID));
|
|
PrettyStackTraceDecl traceTo("... to", proto);
|
|
|
|
auto conformance = ctx.getConformance(conformingType, proto, SourceLoc(), dc,
|
|
ProtocolConformanceState::Incomplete);
|
|
|
|
// Record this conformance.
|
|
if (conformanceEntry.isComplete())
|
|
return conformance;
|
|
|
|
uint64_t offset = conformanceEntry;
|
|
conformanceEntry = conformance;
|
|
|
|
dc->getAsNominalTypeOrNominalTypeExtensionContext()
|
|
->registerProtocolConformance(conformance);
|
|
|
|
// Read requirement signature conformances.
|
|
SmallVector<ProtocolConformanceRef, 4> reqConformances;
|
|
for (auto req : proto->getRequirementSignature()->getRequirements()) {
|
|
if (req.getKind() == RequirementKind::Conformance) {
|
|
auto reqConformance = readConformance(DeclTypeCursor);
|
|
reqConformances.push_back(reqConformance);
|
|
}
|
|
}
|
|
conformance->setSignatureConformances(reqConformances);
|
|
|
|
// If the conformance is complete, we're done.
|
|
if (conformance->isComplete())
|
|
return conformance;
|
|
|
|
conformance->setState(ProtocolConformanceState::Complete);
|
|
conformance->setLazyLoader(this, offset);
|
|
return conformance;
|
|
}
|
|
|
|
Optional<Substitution>
|
|
ModuleFile::maybeReadSubstitution(llvm::BitstreamCursor &cursor,
|
|
GenericEnvironment *genericEnv) {
|
|
BCOffsetRAII lastRecordOffset(cursor);
|
|
|
|
auto entry = cursor.advance(AF_DontPopBlockAtEnd);
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
return None;
|
|
|
|
StringRef blobData;
|
|
SmallVector<uint64_t, 2> scratch;
|
|
unsigned recordID = cursor.readRecord(entry.ID, scratch, &blobData);
|
|
if (recordID != decls_block::BOUND_GENERIC_SUBSTITUTION)
|
|
return None;
|
|
|
|
TypeID replacementID;
|
|
unsigned numConformances;
|
|
decls_block::BoundGenericSubstitutionLayout::readRecord(scratch,
|
|
replacementID,
|
|
numConformances);
|
|
|
|
auto replacementTy = getType(replacementID);
|
|
if (genericEnv) {
|
|
replacementTy = genericEnv->mapTypeIntoContext(replacementTy);
|
|
}
|
|
|
|
SmallVector<ProtocolConformanceRef, 4> conformanceBuf;
|
|
while (numConformances--) {
|
|
conformanceBuf.push_back(readConformance(cursor));
|
|
}
|
|
|
|
lastRecordOffset.reset();
|
|
return Substitution{replacementTy,
|
|
getContext().AllocateCopy(conformanceBuf)};
|
|
}
|
|
|
|
GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC,
|
|
GenericParamList *outerParams) {
|
|
using namespace decls_block;
|
|
|
|
assert(DC && "need a context for the decls in the list");
|
|
|
|
BCOffsetRAII lastRecordOffset(DeclTypeCursor);
|
|
SmallVector<uint64_t, 8> 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;
|
|
|
|
SmallVector<GenericTypeParamDecl *, 8> params;
|
|
|
|
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);
|
|
auto genericParam = cast<GenericTypeParamDecl>(getDecl(paramDeclID, DC));
|
|
// FIXME: There are unfortunate inconsistencies in the treatment of
|
|
// generic param decls. Currently the first request for context wins
|
|
// because we don't want to change context on-the-fly.
|
|
// Here are typical scenarios:
|
|
// (1) AST reads decl, get's scope.
|
|
// Later, readSILFunction tries to force module scope.
|
|
// (2) readSILFunction forces module scope.
|
|
// Later, readVTable requests an enclosing scope.
|
|
// ...other combinations are possible, but as long as AST lookups
|
|
// precede SIL linkage, we should be ok.
|
|
assert((genericParam->getDeclContext()->isModuleScopeContext() ||
|
|
DC->isModuleScopeContext() ||
|
|
genericParam->getDeclContext() == DC) &&
|
|
"Mismatched decl context for generic types.");
|
|
params.push_back(genericParam);
|
|
break;
|
|
}
|
|
default:
|
|
// This record is not part of the GenericParamList.
|
|
shouldContinue = false;
|
|
break;
|
|
}
|
|
|
|
if (!shouldContinue)
|
|
break;
|
|
}
|
|
|
|
auto paramList = GenericParamList::create(getContext(), SourceLoc(),
|
|
params, SourceLoc(), { },
|
|
SourceLoc());
|
|
paramList->setOuterParameters(outerParams ? outerParams :
|
|
DC->getGenericParamsOfContext());
|
|
|
|
return paramList;
|
|
}
|
|
|
|
void ModuleFile::readGenericRequirements(
|
|
SmallVectorImpl<Requirement> &requirements,
|
|
llvm::BitstreamCursor &Cursor) {
|
|
using namespace decls_block;
|
|
|
|
BCOffsetRAII lastRecordOffset(Cursor);
|
|
SmallVector<uint64_t, 8> scratch;
|
|
StringRef blobData;
|
|
|
|
while (true) {
|
|
lastRecordOffset.reset();
|
|
bool shouldContinue = true;
|
|
|
|
auto entry = Cursor.advance(AF_DontPopBlockAtEnd);
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
break;
|
|
|
|
scratch.clear();
|
|
unsigned recordID = Cursor.readRecord(entry.ID, scratch, &blobData);
|
|
switch (recordID) {
|
|
case GENERIC_REQUIREMENT: {
|
|
uint8_t rawKind;
|
|
uint64_t rawTypeIDs[2];
|
|
GenericRequirementLayout::readRecord(scratch, rawKind,
|
|
rawTypeIDs[0], rawTypeIDs[1]);
|
|
|
|
switch (rawKind) {
|
|
case GenericRequirementKind::Conformance: {
|
|
auto subject = getType(rawTypeIDs[0]);
|
|
auto constraint = getType(rawTypeIDs[1]);
|
|
|
|
requirements.push_back(Requirement(RequirementKind::Conformance,
|
|
subject, constraint));
|
|
break;
|
|
}
|
|
case GenericRequirementKind::Superclass: {
|
|
auto subject = getType(rawTypeIDs[0]);
|
|
auto constraint = getType(rawTypeIDs[1]);
|
|
|
|
requirements.push_back(Requirement(RequirementKind::Superclass,
|
|
subject, constraint));
|
|
break;
|
|
}
|
|
case GenericRequirementKind::SameType: {
|
|
auto first = getType(rawTypeIDs[0]);
|
|
auto second = getType(rawTypeIDs[1]);
|
|
|
|
requirements.push_back(Requirement(RequirementKind::SameType,
|
|
first, 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;
|
|
}
|
|
case LAYOUT_REQUIREMENT: {
|
|
uint8_t rawKind;
|
|
uint64_t rawTypeID;
|
|
uint32_t size;
|
|
uint32_t alignment;
|
|
LayoutRequirementLayout::readRecord(scratch, rawKind, rawTypeID,
|
|
size, alignment);
|
|
|
|
auto first = getType(rawTypeID);
|
|
LayoutConstraint layout;
|
|
LayoutConstraintKind kind = LayoutConstraintKind::UnknownLayout;
|
|
switch (rawKind) {
|
|
default: {
|
|
// Unknown layout requirement kind.
|
|
error();
|
|
break;
|
|
}
|
|
case LayoutRequirementKind::NativeRefCountedObject:
|
|
kind = LayoutConstraintKind::NativeRefCountedObject;
|
|
break;
|
|
case LayoutRequirementKind::RefCountedObject:
|
|
kind = LayoutConstraintKind::RefCountedObject;
|
|
break;
|
|
case LayoutRequirementKind::Trivial:
|
|
kind = LayoutConstraintKind::Trivial;
|
|
break;
|
|
case LayoutRequirementKind::TrivialOfExactSize:
|
|
kind = LayoutConstraintKind::TrivialOfExactSize;
|
|
break;
|
|
case LayoutRequirementKind::TrivialOfAtMostSize:
|
|
kind = LayoutConstraintKind::TrivialOfAtMostSize;
|
|
break;
|
|
case LayoutRequirementKind::Class:
|
|
kind = LayoutConstraintKind::Class;
|
|
break;
|
|
case LayoutRequirementKind::NativeClass:
|
|
kind = LayoutConstraintKind::NativeClass;
|
|
break;
|
|
case LayoutRequirementKind::UnknownLayout:
|
|
kind = LayoutConstraintKind::UnknownLayout;
|
|
break;
|
|
}
|
|
|
|
ASTContext &ctx = getContext();
|
|
if (kind != LayoutConstraintKind::TrivialOfAtMostSize &&
|
|
kind != LayoutConstraintKind::TrivialOfExactSize)
|
|
layout = LayoutConstraint::getLayoutConstraint(kind, ctx);
|
|
else
|
|
layout =
|
|
LayoutConstraint::getLayoutConstraint(kind, size, alignment, ctx);
|
|
|
|
requirements.push_back(
|
|
Requirement(RequirementKind::Layout, first, layout));
|
|
break;
|
|
}
|
|
default:
|
|
// This record is not part of the GenericParamList.
|
|
shouldContinue = false;
|
|
break;
|
|
}
|
|
|
|
if (!shouldContinue)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ModuleFile::configureGenericEnvironment(
|
|
GenericContext *genericDecl,
|
|
serialization::GenericEnvironmentID envID) {
|
|
if (envID == 0) return;
|
|
|
|
auto sigOrEnv = getGenericSignatureOrEnvironment(envID);
|
|
|
|
// If we just have a generic signature, set up lazy generic environment
|
|
// creation.
|
|
if (auto genericSig = sigOrEnv.dyn_cast<GenericSignature *>()) {
|
|
genericDecl->setLazyGenericEnvironment(this, genericSig, envID);
|
|
ModuleFile &delayedActionFile = getModuleFileForDelayedActions();
|
|
delayedActionFile.DelayedGenericEnvironments.push_back(genericDecl);
|
|
return;
|
|
}
|
|
|
|
// If we have a full generic environment, it's because it happened to be
|
|
// deserialized already. Record it directly.
|
|
if (auto genericEnv = sigOrEnv.dyn_cast<GenericEnvironment *>()) {
|
|
genericDecl->setGenericEnvironment(genericEnv);
|
|
return;
|
|
}
|
|
}
|
|
|
|
llvm::PointerUnion<GenericSignature *, GenericEnvironment *>
|
|
ModuleFile::getGenericSignatureOrEnvironment(
|
|
serialization::GenericEnvironmentID ID,
|
|
bool wantEnvironment) {
|
|
// The empty result with the type the caller expects.
|
|
llvm::PointerUnion<GenericSignature *, GenericEnvironment *> result;
|
|
if (wantEnvironment)
|
|
result = static_cast<GenericEnvironment *>(nullptr);
|
|
|
|
// Zero is a sentinel for having no generic environment.
|
|
if (ID == 0) return result;
|
|
|
|
assert(ID <= GenericEnvironments.size() && "invalid GenericEnvironment ID");
|
|
auto &envOrOffset = GenericEnvironments[ID-1];
|
|
|
|
// If we've already deserialized this generic environment, return it.
|
|
if (envOrOffset.isComplete()) {
|
|
return envOrOffset.get();
|
|
}
|
|
|
|
// Read the generic environment.
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(envOrOffset);
|
|
DeserializingEntityRAII deserializingEntity(*this);
|
|
|
|
SmallVector<GenericTypeParamType *, 4> paramTypes;
|
|
{
|
|
using namespace decls_block;
|
|
|
|
StringRef blobData;
|
|
SmallVector<uint64_t, 8> scratch;
|
|
|
|
// we only want to be tracking the offset for this part of the function,
|
|
// since loading the generic signature (a) may read the record we reject,
|
|
// and (b) shouldn't have its progress erased. (That function also does its
|
|
// own internal tracking.)
|
|
BCOffsetRAII lastRecordOffset(DeclTypeCursor);
|
|
|
|
auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
return result;
|
|
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
switch (recordID) {
|
|
case GENERIC_ENVIRONMENT: {
|
|
lastRecordOffset.reset();
|
|
|
|
ArrayRef<uint64_t> rawParamIDs;
|
|
GenericEnvironmentLayout::readRecord(scratch, rawParamIDs);
|
|
|
|
for (unsigned i = 0, n = rawParamIDs.size(); i != n; ++i) {
|
|
auto paramTy = getType(rawParamIDs[i])->castTo<GenericTypeParamType>();
|
|
paramTypes.push_back(paramTy);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SIL_GENERIC_ENVIRONMENT: {
|
|
ArrayRef<uint64_t> rawParamIDs;
|
|
SILGenericEnvironmentLayout::readRecord(scratch, rawParamIDs);
|
|
lastRecordOffset.reset();
|
|
|
|
if (rawParamIDs.size() % 2 != 0) {
|
|
error();
|
|
return result;
|
|
}
|
|
|
|
for (unsigned i = 0, n = rawParamIDs.size(); i != n; i += 2) {
|
|
Identifier name = getIdentifier(rawParamIDs[i]);
|
|
auto paramTy = getType(rawParamIDs[i+1])->castTo<GenericTypeParamType>();
|
|
|
|
if (!name.empty()) {
|
|
auto paramDecl =
|
|
createDecl<GenericTypeParamDecl>(getAssociatedModule(),
|
|
name,
|
|
SourceLoc(),
|
|
paramTy->getDepth(),
|
|
paramTy->getIndex());
|
|
paramTy = paramDecl->getDeclaredInterfaceType()
|
|
->castTo<GenericTypeParamType>();
|
|
}
|
|
|
|
paramTypes.push_back(paramTy);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
error();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// If there are no parameters, the environment is empty.
|
|
if (paramTypes.empty()) {
|
|
if (wantEnvironment)
|
|
envOrOffset = nullptr;
|
|
|
|
return result;
|
|
}
|
|
|
|
// Read the generic requirements.
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
// Construct the generic signature from the loaded parameters and
|
|
// requirements.
|
|
auto signature = GenericSignature::get(paramTypes, requirements);
|
|
|
|
// If we only want the signature, return it now.
|
|
if (!wantEnvironment) return signature;
|
|
|
|
// If we've already deserialized this generic environment, return it.
|
|
if (envOrOffset.isComplete()) {
|
|
return envOrOffset.get();
|
|
}
|
|
|
|
// Form the generic environment. Record it now so that deserialization of
|
|
// the archetypes in the environment can refer to this environment.
|
|
auto genericEnv = signature->createGenericEnvironment(*getAssociatedModule());
|
|
envOrOffset = genericEnv;
|
|
|
|
return genericEnv;
|
|
}
|
|
|
|
GenericEnvironment *ModuleFile::getGenericEnvironment(
|
|
serialization::GenericEnvironmentID ID) {
|
|
return getGenericSignatureOrEnvironment(ID, /*wantEnvironment=*/true)
|
|
.get<GenericEnvironment *>();
|
|
;
|
|
}
|
|
|
|
bool ModuleFile::readDefaultWitnessTable(ProtocolDecl *proto) {
|
|
using namespace decls_block;
|
|
|
|
auto entry = DeclTypeCursor.advance();
|
|
if (entry.Kind != llvm::BitstreamEntry::Record)
|
|
return true;
|
|
|
|
SmallVector<uint64_t, 16> witnessIDBuffer;
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(entry.ID, witnessIDBuffer);
|
|
assert(kind == DEFAULT_WITNESS_TABLE);
|
|
(void)kind;
|
|
|
|
ArrayRef<uint64_t> rawWitnessIDs;
|
|
decls_block::DefaultWitnessTableLayout::readRecord(
|
|
witnessIDBuffer, rawWitnessIDs);
|
|
|
|
if (rawWitnessIDs.empty())
|
|
return false;
|
|
|
|
unsigned e = rawWitnessIDs.size();
|
|
assert(e % 2 == 0 && "malformed default witness table");
|
|
(void) e;
|
|
|
|
for (unsigned i = 0, e = rawWitnessIDs.size(); i < e; i += 2) {
|
|
ValueDecl *requirement = cast<ValueDecl>(getDecl(rawWitnessIDs[i]));
|
|
assert(requirement && "unable to deserialize next requirement");
|
|
ValueDecl *witness = cast<ValueDecl>(getDecl(rawWitnessIDs[i + 1]));
|
|
assert(witness && "unable to deserialize next witness");
|
|
assert(requirement->getDeclContext() == proto);
|
|
|
|
proto->setDefaultWitness(requirement, witness);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static Optional<swift::CtorInitializerKind>
|
|
getActualCtorInitializerKind(uint8_t raw) {
|
|
switch (serialization::CtorInitializerKind(raw)) {
|
|
#define CASE(NAME) \
|
|
case serialization::CtorInitializerKind::NAME: \
|
|
return swift::CtorInitializerKind::NAME;
|
|
CASE(Designated)
|
|
CASE(Convenience)
|
|
CASE(Factory)
|
|
CASE(ConvenienceFactory)
|
|
#undef CASE
|
|
}
|
|
return None;
|
|
}
|
|
|
|
/// Remove values from \p values that don't match the expected type or module.
|
|
///
|
|
/// Any of \p expectedTy, \p expectedModule, or \p expectedGenericSig can be
|
|
/// omitted, in which case any type or module is accepted. Values imported
|
|
/// from Clang can also appear in any module.
|
|
static void filterValues(Type expectedTy, ModuleDecl *expectedModule,
|
|
CanGenericSignature expectedGenericSig, bool isType,
|
|
bool inProtocolExt, bool isStatic,
|
|
Optional<swift::CtorInitializerKind> ctorInit,
|
|
SmallVectorImpl<ValueDecl *> &values) {
|
|
CanType canTy;
|
|
if (expectedTy)
|
|
canTy = expectedTy->getCanonicalType();
|
|
|
|
auto newEnd = std::remove_if(values.begin(), values.end(),
|
|
[=](ValueDecl *value) {
|
|
if (isType != isa<TypeDecl>(value))
|
|
return true;
|
|
if (!value->hasInterfaceType())
|
|
return true;
|
|
if (canTy && value->getInterfaceType()->getCanonicalType() != canTy)
|
|
return true;
|
|
if (value->isStatic() != isStatic)
|
|
return true;
|
|
// FIXME: Should be able to move a value from an extension in a derived
|
|
// module to the original definition in a base module.
|
|
if (expectedModule && !value->hasClangNode() &&
|
|
value->getModuleContext() != expectedModule)
|
|
return true;
|
|
|
|
// If we're expecting a member within a constrained extension with a
|
|
// particular generic signature, match that signature.
|
|
if (expectedGenericSig &&
|
|
value->getDeclContext()->getGenericSignatureOfContext()
|
|
->getCanonicalSignature() != expectedGenericSig)
|
|
return true;
|
|
|
|
// If we don't expect a specific generic signature, ignore anything from a
|
|
// constrained extension.
|
|
if (!expectedGenericSig &&
|
|
isa<ExtensionDecl>(value->getDeclContext()) &&
|
|
cast<ExtensionDecl>(value->getDeclContext())->isConstrainedExtension())
|
|
return true;
|
|
|
|
// If we're looking at members of a protocol or protocol extension,
|
|
// filter by whether we expect to find something in a protocol extension or
|
|
// not. This lets us distinguish between a protocol member and a protocol
|
|
// extension member that have the same type.
|
|
if (value->getDeclContext()->getAsProtocolOrProtocolExtensionContext() &&
|
|
(bool)value->getDeclContext()->getAsProtocolExtensionContext()
|
|
!= inProtocolExt)
|
|
return true;
|
|
|
|
// If we're expecting an initializer with a specific kind, and this is not
|
|
// an initializer with that kind, remove it.
|
|
if (ctorInit) {
|
|
if (!isa<ConstructorDecl>(value) ||
|
|
cast<ConstructorDecl>(value)->getInitKind() != *ctorInit)
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
values.erase(newEnd, values.end());
|
|
}
|
|
|
|
Expected<Decl *>
|
|
ModuleFile::resolveCrossReference(ModuleDecl *baseModule, uint32_t pathLen) {
|
|
using namespace decls_block;
|
|
assert(baseModule && "missing dependency");
|
|
PrettyXRefTrace pathTrace(*baseModule);
|
|
|
|
auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
SmallVector<ValueDecl *, 8> values;
|
|
SmallVector<uint64_t, 8> scratch;
|
|
StringRef blobData;
|
|
|
|
// Read the first path piece. This one is special because lookup is performed
|
|
// against the base module, rather than against the previous link in the path.
|
|
// In particular, operator path pieces represent actual operators here, but
|
|
// filters on operator functions when they appear later on.
|
|
scratch.clear();
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
|
|
&blobData);
|
|
switch (recordID) {
|
|
case XREF_TYPE_PATH_PIECE:
|
|
case XREF_VALUE_PATH_PIECE: {
|
|
IdentifierID IID;
|
|
TypeID TID = 0;
|
|
bool isType = (recordID == XREF_TYPE_PATH_PIECE);
|
|
bool inProtocolExt = false;
|
|
bool isStatic = false;
|
|
if (isType)
|
|
XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
|
|
else
|
|
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
|
|
isStatic);
|
|
|
|
Identifier name = getIdentifier(IID);
|
|
pathTrace.addValue(name);
|
|
|
|
Type filterTy = getType(TID);
|
|
if (!isType)
|
|
pathTrace.addType(filterTy);
|
|
|
|
baseModule->lookupQualified(ModuleType::get(baseModule), name,
|
|
NL_QualifiedDefault | NL_KnownNoDependency,
|
|
/*typeResolver=*/nullptr, values);
|
|
filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt, isStatic,
|
|
None, values);
|
|
break;
|
|
}
|
|
|
|
case XREF_EXTENSION_PATH_PIECE:
|
|
llvm_unreachable("can only extend a nominal");
|
|
|
|
case XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE: {
|
|
IdentifierID IID;
|
|
uint8_t rawOpKind;
|
|
XRefOperatorOrAccessorPathPieceLayout::readRecord(scratch, IID, rawOpKind);
|
|
|
|
Identifier opName = getIdentifier(IID);
|
|
pathTrace.addOperator(opName);
|
|
|
|
switch (rawOpKind) {
|
|
case OperatorKind::Infix:
|
|
return baseModule->lookupInfixOperator(opName);
|
|
case OperatorKind::Prefix:
|
|
return baseModule->lookupPrefixOperator(opName);
|
|
case OperatorKind::Postfix:
|
|
return baseModule->lookupPostfixOperator(opName);
|
|
case OperatorKind::PrecedenceGroup:
|
|
return baseModule->lookupPrecedenceGroup(opName);
|
|
default:
|
|
// Unknown operator kind.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
case XREF_GENERIC_PARAM_PATH_PIECE:
|
|
case XREF_INITIALIZER_PATH_PIECE:
|
|
llvm_unreachable("only in a nominal or function");
|
|
|
|
default:
|
|
// Unknown xref kind.
|
|
pathTrace.addUnknown(recordID);
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (values.empty()) {
|
|
return llvm::make_error<XRefError>("top-level value not found", pathTrace);
|
|
}
|
|
|
|
// Filters for values discovered in the remaining path pieces.
|
|
ModuleDecl *M = nullptr;
|
|
CanGenericSignature genericSig = nullptr;
|
|
|
|
// For remaining path pieces, filter or drill down into the results we have.
|
|
while (--pathLen) {
|
|
auto entry = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
scratch.clear();
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
|
|
&blobData);
|
|
switch (recordID) {
|
|
case XREF_TYPE_PATH_PIECE: {
|
|
if (values.size() == 1) {
|
|
ModuleDecl *module = values.front()->getModuleContext();
|
|
if (module == this->getAssociatedModule()) {
|
|
// Fast path for nested types in the same module.
|
|
IdentifierID IID;
|
|
bool onlyInNominal = false;
|
|
XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
|
|
Identifier memberName = getIdentifier(IID);
|
|
pathTrace.addValue(memberName);
|
|
|
|
llvm::PrettyStackTraceString message{
|
|
"If you're seeing a crash here, try passing "
|
|
"-Xfrontend -disable-serialization-nested-type-lookup-table"};
|
|
|
|
TypeDecl *nestedType = nullptr;
|
|
if (onlyInNominal) {
|
|
// Only look in the file containing the type itself.
|
|
const DeclContext *dc = values.front()->getDeclContext();
|
|
auto *serializedFile =
|
|
dyn_cast<SerializedASTFile>(dc->getModuleScopeContext());
|
|
if (serializedFile) {
|
|
nestedType =
|
|
serializedFile->File.lookupNestedType(memberName,
|
|
values.front());
|
|
}
|
|
} else {
|
|
// Fault in extensions, then ask every serialized AST in the module.
|
|
(void)cast<NominalTypeDecl>(values.front())->getExtensions();
|
|
for (FileUnit *file : module->getFiles()) {
|
|
if (file == getFile())
|
|
continue;
|
|
auto *serializedFile = dyn_cast<SerializedASTFile>(file);
|
|
if (!serializedFile)
|
|
continue;
|
|
nestedType =
|
|
serializedFile->File.lookupNestedType(memberName,
|
|
values.front());
|
|
if (nestedType)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (nestedType) {
|
|
values.clear();
|
|
values.push_back(nestedType);
|
|
++NumNestedTypeShortcuts;
|
|
break;
|
|
}
|
|
|
|
pathTrace.removeLast();
|
|
}
|
|
}
|
|
LLVM_FALLTHROUGH;
|
|
}
|
|
case XREF_VALUE_PATH_PIECE:
|
|
case XREF_INITIALIZER_PATH_PIECE: {
|
|
TypeID TID = 0;
|
|
Identifier memberName;
|
|
Optional<swift::CtorInitializerKind> ctorInit;
|
|
bool isType = false;
|
|
bool inProtocolExt = false;
|
|
bool isStatic = false;
|
|
switch (recordID) {
|
|
case XREF_TYPE_PATH_PIECE: {
|
|
IdentifierID IID;
|
|
XRefTypePathPieceLayout::readRecord(scratch, IID, inProtocolExt);
|
|
memberName = getIdentifier(IID);
|
|
isType = true;
|
|
break;
|
|
}
|
|
|
|
case XREF_VALUE_PATH_PIECE: {
|
|
IdentifierID IID;
|
|
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
|
|
isStatic);
|
|
memberName = getIdentifier(IID);
|
|
break;
|
|
}
|
|
|
|
case XREF_INITIALIZER_PATH_PIECE: {
|
|
uint8_t kind;
|
|
XRefInitializerPathPieceLayout::readRecord(scratch, TID, inProtocolExt,
|
|
kind);
|
|
memberName = getContext().Id_init;
|
|
ctorInit = getActualCtorInitializerKind(kind);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
llvm_unreachable("Unhandled path piece");
|
|
}
|
|
|
|
pathTrace.addValue(memberName);
|
|
|
|
Type filterTy = getType(TID);
|
|
if (!isType)
|
|
pathTrace.addType(filterTy);
|
|
|
|
if (values.size() != 1) {
|
|
return llvm::make_error<XRefError>("multiple matching base values",
|
|
pathTrace);
|
|
}
|
|
|
|
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
|
|
values.clear();
|
|
|
|
if (!nominal) {
|
|
return llvm::make_error<XRefError>("base is not a nominal type",
|
|
pathTrace);
|
|
}
|
|
|
|
auto members = nominal->lookupDirect(memberName);
|
|
values.append(members.begin(), members.end());
|
|
filterValues(filterTy, M, genericSig, isType, inProtocolExt, isStatic,
|
|
ctorInit, values);
|
|
break;
|
|
}
|
|
|
|
case XREF_EXTENSION_PATH_PIECE: {
|
|
ModuleID ownerID;
|
|
ArrayRef<uint64_t> genericParamIDs;
|
|
XRefExtensionPathPieceLayout::readRecord(scratch, ownerID,
|
|
genericParamIDs);
|
|
M = getModule(ownerID);
|
|
pathTrace.addExtension(M);
|
|
|
|
// Read the generic signature, if we have one.
|
|
if (!genericParamIDs.empty()) {
|
|
SmallVector<GenericTypeParamType *, 4> params;
|
|
SmallVector<Requirement, 5> requirements;
|
|
for (TypeID paramID : genericParamIDs) {
|
|
params.push_back(getType(paramID)->castTo<GenericTypeParamType>());
|
|
}
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
genericSig = GenericSignature::getCanonical(params, requirements);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
case XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE: {
|
|
uint8_t rawKind;
|
|
XRefOperatorOrAccessorPathPieceLayout::readRecord(scratch, None,
|
|
rawKind);
|
|
|
|
if (values.size() == 1) {
|
|
if (auto storage = dyn_cast<AbstractStorageDecl>(values.front())) {
|
|
pathTrace.addAccessor(rawKind);
|
|
switch (rawKind) {
|
|
case Getter:
|
|
values.front() = storage->getGetter();
|
|
break;
|
|
case Setter:
|
|
values.front() = storage->getSetter();
|
|
break;
|
|
case MaterializeForSet:
|
|
values.front() = storage->getMaterializeForSetFunc();
|
|
break;
|
|
case Addressor:
|
|
values.front() = storage->getAddressor();
|
|
break;
|
|
case MutableAddressor:
|
|
values.front() = storage->getMutableAddressor();
|
|
break;
|
|
case WillSet:
|
|
case DidSet:
|
|
llvm_unreachable("invalid XREF accessor kind");
|
|
default:
|
|
// Unknown accessor kind.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
pathTrace.addOperatorFilter(rawKind);
|
|
|
|
auto newEnd = std::remove_if(values.begin(), values.end(),
|
|
[=](ValueDecl *value) {
|
|
auto fn = dyn_cast<FuncDecl>(value);
|
|
if (!fn)
|
|
return true;
|
|
if (!fn->getOperatorDecl())
|
|
return true;
|
|
if (getStableFixity(fn->getOperatorDecl()->getKind()) != rawKind)
|
|
return true;
|
|
return false;
|
|
});
|
|
values.erase(newEnd, values.end());
|
|
break;
|
|
}
|
|
|
|
case XREF_GENERIC_PARAM_PATH_PIECE: {
|
|
if (values.size() != 1) {
|
|
return llvm::make_error<XRefError>("multiple matching base values",
|
|
pathTrace);
|
|
}
|
|
|
|
uint32_t paramIndex;
|
|
XRefGenericParamPathPieceLayout::readRecord(scratch, paramIndex);
|
|
|
|
pathTrace.addGenericParam(paramIndex);
|
|
|
|
ValueDecl *base = values.front();
|
|
GenericParamList *paramList = nullptr;
|
|
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(base)) {
|
|
if (genericSig) {
|
|
// Find an extension in the requested module that has the
|
|
// correct generic signature.
|
|
for (auto ext : nominal->getExtensions()) {
|
|
if (ext->getModuleContext() == M &&
|
|
ext->getGenericSignature()->getCanonicalSignature()
|
|
== genericSig) {
|
|
paramList = ext->getGenericParams();
|
|
break;
|
|
}
|
|
}
|
|
assert(paramList && "Couldn't find constrained extension");
|
|
} else {
|
|
// Simple case: use the nominal type's generic parameters.
|
|
paramList = nominal->getGenericParams();
|
|
}
|
|
} else if (auto alias = dyn_cast<TypeAliasDecl>(base)) {
|
|
paramList = alias->getGenericParams();
|
|
} else if (auto fn = dyn_cast<AbstractFunctionDecl>(base))
|
|
paramList = fn->getGenericParams();
|
|
|
|
if (!paramList) {
|
|
return llvm::make_error<XRefError>(
|
|
"cross-reference to generic param for non-generic type",
|
|
pathTrace);
|
|
}
|
|
if (paramIndex >= paramList->size()) {
|
|
return llvm::make_error<XRefError>(
|
|
"generic argument index out of bounds",
|
|
pathTrace);
|
|
}
|
|
|
|
values.clear();
|
|
values.push_back(paramList->getParams()[paramIndex]);
|
|
assert(values.back());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Unknown xref path piece.
|
|
pathTrace.addUnknown(recordID);
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
Optional<PrettyStackTraceModuleFile> traceMsg;
|
|
if (M != getAssociatedModule()) {
|
|
traceMsg.emplace("If you're seeing a crash here, check that your SDK "
|
|
"and dependencies match the versions used to build",
|
|
this);
|
|
}
|
|
|
|
if (values.empty()) {
|
|
return llvm::make_error<XRefError>("result not found", pathTrace);
|
|
}
|
|
|
|
// Reset the module filter.
|
|
M = nullptr;
|
|
genericSig = nullptr;
|
|
}
|
|
|
|
// Make sure we /used/ the last module filter we got.
|
|
// This catches the case where the last path piece we saw was an Extension
|
|
// path piece, which is not a valid way to end a path. (Cross-references to
|
|
// extensions are not allowed because they cannot be uniquely named.)
|
|
if (M) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
// When all is said and done, we should have a single value here to return.
|
|
if (values.size() != 1) {
|
|
return llvm::make_error<llvm::StringError>(
|
|
"result is ambiguous",
|
|
std::error_code(EINVAL, std::generic_category()));
|
|
}
|
|
|
|
return values.front();
|
|
}
|
|
|
|
Identifier ModuleFile::getIdentifier(IdentifierID IID) {
|
|
if (IID == 0)
|
|
return Identifier();
|
|
|
|
size_t rawID = IID - NUM_SPECIAL_MODULES;
|
|
assert(rawID < Identifiers.size() && "invalid identifier ID");
|
|
auto identRecord = Identifiers[rawID];
|
|
|
|
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 getContext().getIdentifier(rawStrPtr.slice(0, terminatorOffset));
|
|
}
|
|
|
|
DeclContext *ModuleFile::getLocalDeclContext(DeclContextID DCID) {
|
|
assert(DCID != 0 && "invalid local DeclContext ID 0");
|
|
auto &declContextOrOffset = LocalDeclContexts[DCID-1];
|
|
|
|
if (declContextOrOffset.isComplete())
|
|
return declContextOrOffset;
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(declContextOrOffset);
|
|
auto entry = DeclTypeCursor.advance();
|
|
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
ASTContext &ctx = getContext();
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
|
|
&blobData);
|
|
switch(recordID) {
|
|
case decls_block::ABSTRACT_CLOSURE_EXPR_CONTEXT: {
|
|
TypeID closureTypeID;
|
|
unsigned discriminator = 0;
|
|
bool implicit = false;
|
|
DeclContextID parentID;
|
|
|
|
decls_block::AbstractClosureExprLayout::readRecord(scratch,
|
|
closureTypeID,
|
|
implicit,
|
|
discriminator,
|
|
parentID);
|
|
DeclContext *parent = getDeclContext(parentID);
|
|
auto type = getType(closureTypeID);
|
|
|
|
declContextOrOffset = new (ctx)
|
|
SerializedAbstractClosureExpr(type, implicit, discriminator, parent);
|
|
break;
|
|
}
|
|
|
|
case decls_block::TOP_LEVEL_CODE_DECL_CONTEXT: {
|
|
DeclContextID parentID;
|
|
decls_block::TopLevelCodeDeclContextLayout::readRecord(scratch,
|
|
parentID);
|
|
DeclContext *parent = getDeclContext(parentID);
|
|
|
|
declContextOrOffset = new (ctx) SerializedTopLevelCodeDeclContext(parent);
|
|
break;
|
|
}
|
|
|
|
case decls_block::PATTERN_BINDING_INITIALIZER_CONTEXT: {
|
|
DeclID bindingID;
|
|
uint32_t bindingIndex;
|
|
decls_block::PatternBindingInitializerLayout::readRecord(scratch,
|
|
bindingID,
|
|
bindingIndex);
|
|
auto decl = getDecl(bindingID);
|
|
PatternBindingDecl *binding = cast<PatternBindingDecl>(decl);
|
|
|
|
if (!declContextOrOffset.isComplete())
|
|
declContextOrOffset = new (ctx)
|
|
SerializedPatternBindingInitializer(binding, bindingIndex);
|
|
break;
|
|
}
|
|
|
|
case decls_block::DEFAULT_ARGUMENT_INITIALIZER_CONTEXT: {
|
|
DeclContextID parentID;
|
|
unsigned index = 0;
|
|
decls_block::DefaultArgumentInitializerLayout::readRecord(scratch,
|
|
parentID,
|
|
index);
|
|
DeclContext *parent = getDeclContext(parentID);
|
|
|
|
declContextOrOffset = new (ctx)
|
|
SerializedDefaultArgumentInitializer(index, parent);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
llvm_unreachable("Unknown record ID found when reading local DeclContext.");
|
|
}
|
|
return declContextOrOffset;
|
|
}
|
|
|
|
DeclContext *ModuleFile::getDeclContext(DeclContextID DCID) {
|
|
if (DCID == 0)
|
|
return FileContext;
|
|
|
|
assert(DCID <= DeclContexts.size() && "invalid DeclContext ID");
|
|
auto &declContextOrOffset = DeclContexts[DCID-1];
|
|
|
|
if (declContextOrOffset.isComplete())
|
|
return declContextOrOffset;
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(declContextOrOffset);
|
|
auto entry = DeclTypeCursor.advance();
|
|
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
|
|
if (recordID != decls_block::DECL_CONTEXT)
|
|
llvm_unreachable("Expected a DECL_CONTEXT record");
|
|
|
|
DeclContextID declOrDeclContextId;
|
|
bool isDecl;
|
|
|
|
decls_block::DeclContextLayout::readRecord(scratch, declOrDeclContextId,
|
|
isDecl);
|
|
|
|
if (!isDecl)
|
|
return getLocalDeclContext(declOrDeclContextId);
|
|
|
|
auto D = getDecl(declOrDeclContextId);
|
|
|
|
if (auto ND = dyn_cast<NominalTypeDecl>(D)) {
|
|
declContextOrOffset = ND;
|
|
} else if (auto ED = dyn_cast<ExtensionDecl>(D)) {
|
|
declContextOrOffset = ED;
|
|
} else if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
|
|
declContextOrOffset = AFD;
|
|
} else if (auto SD = dyn_cast<SubscriptDecl>(D)) {
|
|
declContextOrOffset = SD;
|
|
} else if (auto TAD = dyn_cast<TypeAliasDecl>(D)) {
|
|
declContextOrOffset = TAD;
|
|
} else {
|
|
llvm_unreachable("Unknown Decl : DeclContext kind");
|
|
}
|
|
|
|
return declContextOrOffset;
|
|
}
|
|
|
|
ModuleDecl *ModuleFile::getModule(ModuleID MID) {
|
|
if (MID < NUM_SPECIAL_MODULES) {
|
|
switch (static_cast<SpecialModuleID>(static_cast<uint8_t>(MID))) {
|
|
case BUILTIN_MODULE_ID:
|
|
return getContext().TheBuiltinModule;
|
|
case CURRENT_MODULE_ID:
|
|
return FileContext->getParentModule();
|
|
case OBJC_HEADER_MODULE_ID: {
|
|
auto clangImporter =
|
|
static_cast<ClangImporter *>(getContext().getClangModuleLoader());
|
|
return clangImporter->getImportedHeaderModule();
|
|
}
|
|
case NUM_SPECIAL_MODULES:
|
|
llvm_unreachable("implementation detail only");
|
|
}
|
|
}
|
|
return getModule(getIdentifier(MID));
|
|
}
|
|
|
|
ModuleDecl *ModuleFile::getModule(ArrayRef<Identifier> name) {
|
|
if (name.empty() || name.front().empty())
|
|
return getContext().TheBuiltinModule;
|
|
|
|
// FIXME: duplicated from NameBinder::getModule
|
|
if (name.size() == 1 &&
|
|
name.front() == FileContext->getParentModule()->getName()) {
|
|
if (!ShadowedModule) {
|
|
auto importer = getContext().getClangModuleLoader();
|
|
assert(importer && "no way to import shadowed module");
|
|
ShadowedModule = importer->loadModule(SourceLoc(),
|
|
{ { name.front(), SourceLoc() } });
|
|
}
|
|
|
|
return ShadowedModule;
|
|
}
|
|
|
|
SmallVector<ImportDecl::AccessPathElement, 4> importPath;
|
|
for (auto pathElem : name)
|
|
importPath.push_back({ pathElem, SourceLoc() });
|
|
return getContext().getModule(importPath);
|
|
}
|
|
|
|
|
|
/// Translate from the Serialization associativity 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<swift::Associativity> 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 None;
|
|
}
|
|
}
|
|
|
|
static Optional<swift::StaticSpellingKind>
|
|
getActualStaticSpellingKind(uint8_t raw) {
|
|
switch (serialization::StaticSpellingKind(raw)) {
|
|
case serialization::StaticSpellingKind::None:
|
|
return swift::StaticSpellingKind::None;
|
|
case serialization::StaticSpellingKind::KeywordStatic:
|
|
return swift::StaticSpellingKind::KeywordStatic;
|
|
case serialization::StaticSpellingKind::KeywordClass:
|
|
return swift::StaticSpellingKind::KeywordClass;
|
|
}
|
|
return None;
|
|
}
|
|
|
|
static bool isDeclAttrRecord(unsigned ID) {
|
|
using namespace decls_block;
|
|
switch (ID) {
|
|
#define DECL_ATTR(NAME, CLASS, ...) case CLASS##_DECL_ATTR: return true;
|
|
#include "swift/Serialization/DeclTypeRecordNodes.def"
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
static Optional<swift::Accessibility>
|
|
getActualAccessibility(uint8_t raw) {
|
|
switch (serialization::AccessibilityKind(raw)) {
|
|
#define CASE(NAME) \
|
|
case serialization::AccessibilityKind::NAME: \
|
|
return Accessibility::NAME;
|
|
CASE(Private)
|
|
CASE(FilePrivate)
|
|
CASE(Internal)
|
|
CASE(Public)
|
|
CASE(Open)
|
|
#undef CASE
|
|
}
|
|
return None;
|
|
}
|
|
|
|
static Optional<swift::OptionalTypeKind>
|
|
getActualOptionalTypeKind(uint8_t raw) {
|
|
switch (serialization::OptionalTypeKind(raw)) {
|
|
case serialization::OptionalTypeKind::None:
|
|
return OTK_None;
|
|
case serialization::OptionalTypeKind::Optional:
|
|
return OTK_Optional;
|
|
case serialization::OptionalTypeKind::ImplicitlyUnwrappedOptional:
|
|
return OTK_ImplicitlyUnwrappedOptional;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
static Optional<swift::AddressorKind>
|
|
getActualAddressorKind(uint8_t raw) {
|
|
switch (serialization::AddressorKind(raw)) {
|
|
case serialization::AddressorKind::NotAddressor:
|
|
return swift::AddressorKind::NotAddressor;
|
|
case serialization::AddressorKind::Unsafe:
|
|
return swift::AddressorKind::Unsafe;
|
|
case serialization::AddressorKind::Owning:
|
|
return swift::AddressorKind::Owning;
|
|
case serialization::AddressorKind::NativeOwning:
|
|
return swift::AddressorKind::NativeOwning;
|
|
case serialization::AddressorKind::NativePinning:
|
|
return swift::AddressorKind::NativePinning;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
void ModuleFile::configureStorage(AbstractStorageDecl *decl,
|
|
unsigned rawStorageKind,
|
|
serialization::DeclID getter,
|
|
serialization::DeclID setter,
|
|
serialization::DeclID materializeForSet,
|
|
serialization::DeclID addressor,
|
|
serialization::DeclID mutableAddressor,
|
|
serialization::DeclID willSet,
|
|
serialization::DeclID didSet) {
|
|
// We currently don't serialize these locations.
|
|
SourceLoc beginLoc, endLoc;
|
|
|
|
auto makeAddressed = [&] {
|
|
decl->makeAddressed(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(addressor)),
|
|
cast_or_null<FuncDecl>(getDecl(mutableAddressor)),
|
|
endLoc);
|
|
};
|
|
|
|
auto addTrivialAccessors = [&] {
|
|
decl->addTrivialAccessors(
|
|
cast_or_null<FuncDecl>(getDecl(getter)),
|
|
cast_or_null<FuncDecl>(getDecl(setter)),
|
|
cast_or_null<FuncDecl>(getDecl(materializeForSet)));
|
|
};
|
|
|
|
auto setObservingAccessors = [&] {
|
|
decl->setObservingAccessors(
|
|
cast_or_null<FuncDecl>(getDecl(getter)),
|
|
cast_or_null<FuncDecl>(getDecl(setter)),
|
|
cast_or_null<FuncDecl>(getDecl(materializeForSet)));
|
|
};
|
|
|
|
switch ((StorageKind) rawStorageKind) {
|
|
case StorageKind::Stored:
|
|
return;
|
|
|
|
case StorageKind::StoredWithTrivialAccessors:
|
|
addTrivialAccessors();
|
|
return;
|
|
|
|
case StorageKind::StoredWithObservers:
|
|
decl->makeStoredWithObservers(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(willSet)),
|
|
cast_or_null<FuncDecl>(getDecl(didSet)),
|
|
endLoc);
|
|
setObservingAccessors();
|
|
return;
|
|
|
|
case StorageKind::InheritedWithObservers:
|
|
decl->makeInheritedWithObservers(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(willSet)),
|
|
cast_or_null<FuncDecl>(getDecl(didSet)),
|
|
endLoc);
|
|
setObservingAccessors();
|
|
return;
|
|
|
|
case StorageKind::Addressed:
|
|
makeAddressed();
|
|
return;
|
|
|
|
case StorageKind::AddressedWithTrivialAccessors:
|
|
makeAddressed();
|
|
addTrivialAccessors();
|
|
return;
|
|
|
|
case StorageKind::AddressedWithObservers:
|
|
decl->makeAddressedWithObservers(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(addressor)),
|
|
cast_or_null<FuncDecl>(getDecl(mutableAddressor)),
|
|
cast_or_null<FuncDecl>(getDecl(willSet)),
|
|
cast_or_null<FuncDecl>(getDecl(didSet)),
|
|
endLoc);
|
|
setObservingAccessors();
|
|
return;
|
|
|
|
case StorageKind::Computed:
|
|
decl->makeComputed(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(getter)),
|
|
cast_or_null<FuncDecl>(getDecl(setter)),
|
|
cast_or_null<FuncDecl>(getDecl(materializeForSet)),
|
|
endLoc);
|
|
return;
|
|
|
|
case StorageKind::ComputedWithMutableAddress:
|
|
decl->makeComputedWithMutableAddress(beginLoc,
|
|
cast_or_null<FuncDecl>(getDecl(getter)),
|
|
cast_or_null<FuncDecl>(getDecl(setter)),
|
|
cast_or_null<FuncDecl>(getDecl(materializeForSet)),
|
|
cast_or_null<FuncDecl>(getDecl(mutableAddressor)),
|
|
endLoc);
|
|
return;
|
|
}
|
|
llvm_unreachable("bad storage kind");
|
|
}
|
|
|
|
template <typename T, typename ...Args>
|
|
T *ModuleFile::createDecl(Args &&... args) {
|
|
// Note that this method is not used for all decl kinds.
|
|
static_assert(std::is_base_of<Decl, T>::value, "not a Decl");
|
|
T *result = new (getContext()) T(std::forward<Args>(args)...);
|
|
result->setEarlyAttrValidation(true);
|
|
return result;
|
|
}
|
|
|
|
static const uint64_t lazyConformanceContextDataPositionMask = 0xFFFFFFFFFFFF;
|
|
|
|
/// Decode the context data for lazily-loaded conformances.
|
|
static std::pair<uint64_t, uint64_t> decodeLazyConformanceContextData(
|
|
uint64_t contextData) {
|
|
return std::make_pair(contextData >> 48,
|
|
contextData & lazyConformanceContextDataPositionMask);
|
|
}
|
|
|
|
/// Encode the context data for lazily-loaded conformances.
|
|
static uint64_t encodeLazyConformanceContextData(uint64_t numProtocols,
|
|
uint64_t bitPosition) {
|
|
assert(numProtocols < 0xFFFF);
|
|
assert(bitPosition < lazyConformanceContextDataPositionMask);
|
|
return (numProtocols << 48) | bitPosition;
|
|
}
|
|
|
|
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|
Expected<Decl *> deserialized = getDeclChecked(DID, ForcedContext);
|
|
if (!deserialized) {
|
|
fatal(deserialized.takeError());
|
|
}
|
|
return deserialized.get();
|
|
}
|
|
|
|
Expected<Decl *>
|
|
ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
|
if (DID == 0)
|
|
return nullptr;
|
|
|
|
assert(DID <= Decls.size() && "invalid decl ID");
|
|
auto &declOrOffset = Decls[DID-1];
|
|
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
++NumDeclsLoaded;
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
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 = getContext();
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
|
|
// Read the attributes (if any).
|
|
DeclAttribute *DAttrs = nullptr;
|
|
DeclAttribute **AttrsNext = &DAttrs;
|
|
auto AddAttribute = [&](DeclAttribute *Attr) {
|
|
// Advance the linked list.
|
|
*AttrsNext = Attr;
|
|
AttrsNext = Attr->getMutableNext();
|
|
};
|
|
unsigned recordID;
|
|
|
|
class PrivateDiscriminatorRAII {
|
|
ModuleFile &moduleFile;
|
|
Serialized<Decl *> &declOrOffset;
|
|
|
|
public:
|
|
Identifier discriminator;
|
|
|
|
PrivateDiscriminatorRAII(ModuleFile &moduleFile,
|
|
Serialized<Decl *> &declOrOffset)
|
|
: moduleFile(moduleFile), declOrOffset(declOrOffset) {}
|
|
|
|
~PrivateDiscriminatorRAII() {
|
|
if (!discriminator.empty() && declOrOffset.isComplete())
|
|
if (auto value = dyn_cast_or_null<ValueDecl>(declOrOffset.get()))
|
|
moduleFile.PrivateDiscriminatorsByValue[value] = discriminator;
|
|
}
|
|
};
|
|
|
|
class LocalDiscriminatorRAII {
|
|
Serialized<Decl *> &declOrOffset;
|
|
|
|
public:
|
|
unsigned discriminator;
|
|
|
|
LocalDiscriminatorRAII(Serialized<Decl *> &declOrOffset)
|
|
: declOrOffset(declOrOffset), discriminator(0) {}
|
|
|
|
~LocalDiscriminatorRAII() {
|
|
if (discriminator != 0 && declOrOffset.isComplete())
|
|
if (auto value = dyn_cast<ValueDecl>(declOrOffset.get()))
|
|
value->setLocalDiscriminator(discriminator);
|
|
}
|
|
};
|
|
|
|
PrivateDiscriminatorRAII privateDiscriminatorRAII{*this, declOrOffset};
|
|
LocalDiscriminatorRAII localDiscriminatorRAII(declOrOffset);
|
|
DeserializingEntityRAII deserializingEntity(*this);
|
|
|
|
// Local function that handles the "inherited" list for a type.
|
|
auto handleInherited
|
|
= [&](TypeDecl *nominal, ArrayRef<uint64_t> rawInheritedIDs) {
|
|
auto inheritedTypes = ctx.Allocate<TypeLoc>(rawInheritedIDs.size());
|
|
for_each(inheritedTypes, rawInheritedIDs,
|
|
[this](TypeLoc &tl, uint64_t rawID) {
|
|
tl = TypeLoc::withoutLoc(getType(rawID));
|
|
});
|
|
nominal->setInherited(inheritedTypes);
|
|
nominal->setCheckedInheritanceClause();
|
|
};
|
|
|
|
while (true) {
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
// We don't know how to serialize decls represented by sub-blocks.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
|
|
if (isDeclAttrRecord(recordID)) {
|
|
DeclAttribute *Attr = nullptr;
|
|
switch (recordID) {
|
|
case decls_block::SILGenName_DECL_ATTR: {
|
|
bool isImplicit;
|
|
serialization::decls_block::SILGenNameDeclAttrLayout::readRecord(
|
|
scratch, isImplicit);
|
|
Attr = new (ctx) SILGenNameAttr(blobData, isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::CDecl_DECL_ATTR: {
|
|
bool isImplicit;
|
|
serialization::decls_block::CDeclDeclAttrLayout::readRecord(
|
|
scratch, isImplicit);
|
|
Attr = new (ctx) CDeclAttr(blobData, isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Alignment_DECL_ATTR: {
|
|
bool isImplicit;
|
|
unsigned alignment;
|
|
serialization::decls_block::AlignmentDeclAttrLayout::readRecord(
|
|
scratch, isImplicit, alignment);
|
|
Attr = new (ctx) AlignmentAttr(alignment, SourceLoc(), SourceRange(),
|
|
isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::SwiftNativeObjCRuntimeBase_DECL_ATTR: {
|
|
bool isImplicit;
|
|
IdentifierID nameID;
|
|
serialization::decls_block::SwiftNativeObjCRuntimeBaseDeclAttrLayout
|
|
::readRecord(scratch, isImplicit, nameID);
|
|
|
|
auto name = getIdentifier(nameID);
|
|
Attr = new (ctx) SwiftNativeObjCRuntimeBaseAttr(name, SourceLoc(),
|
|
SourceRange(),
|
|
isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Semantics_DECL_ATTR: {
|
|
bool isImplicit;
|
|
serialization::decls_block::SemanticsDeclAttrLayout::readRecord(
|
|
scratch, isImplicit);
|
|
Attr = new (ctx) SemanticsAttr(blobData, isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Inline_DECL_ATTR: {
|
|
unsigned kind;
|
|
serialization::decls_block::InlineDeclAttrLayout::readRecord(
|
|
scratch, kind);
|
|
Attr = new (ctx) InlineAttr((InlineKind)kind);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Effects_DECL_ATTR: {
|
|
unsigned kind;
|
|
serialization::decls_block::EffectsDeclAttrLayout::readRecord(scratch,
|
|
kind);
|
|
Attr = new (ctx) EffectsAttr((EffectsKind)kind);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Available_DECL_ATTR: {
|
|
#define LIST_VER_TUPLE_PIECES(X)\
|
|
X##_Major, X##_Minor, X##_Subminor, X##_HasMinor, X##_HasSubminor
|
|
#define DEF_VER_TUPLE_PIECES(X) unsigned LIST_VER_TUPLE_PIECES(X)
|
|
#define DECODE_VER_TUPLE(X)\
|
|
if (X##_HasMinor) {\
|
|
if (X##_HasSubminor)\
|
|
X = clang::VersionTuple(X##_Major, X##_Minor, X##_Subminor);\
|
|
else\
|
|
X = clang::VersionTuple(X##_Major, X##_Minor);\
|
|
}\
|
|
else X = clang::VersionTuple(X##_Major);
|
|
|
|
bool isImplicit;
|
|
bool isUnavailable;
|
|
bool isDeprecated;
|
|
DEF_VER_TUPLE_PIECES(Introduced);
|
|
DEF_VER_TUPLE_PIECES(Deprecated);
|
|
DEF_VER_TUPLE_PIECES(Obsoleted);
|
|
unsigned platform, messageSize, renameSize;
|
|
// Decode the record, pulling the version tuple information.
|
|
serialization::decls_block::AvailableDeclAttrLayout::readRecord(
|
|
scratch, isImplicit, isUnavailable, isDeprecated,
|
|
LIST_VER_TUPLE_PIECES(Introduced),
|
|
LIST_VER_TUPLE_PIECES(Deprecated),
|
|
LIST_VER_TUPLE_PIECES(Obsoleted),
|
|
platform, messageSize, renameSize);
|
|
|
|
StringRef message = blobData.substr(0, messageSize);
|
|
blobData = blobData.substr(messageSize);
|
|
StringRef rename = blobData.substr(0, renameSize);
|
|
clang::VersionTuple Introduced, Deprecated, Obsoleted;
|
|
DECODE_VER_TUPLE(Introduced)
|
|
DECODE_VER_TUPLE(Deprecated)
|
|
DECODE_VER_TUPLE(Obsoleted)
|
|
|
|
PlatformAgnosticAvailabilityKind platformAgnostic;
|
|
if (isUnavailable)
|
|
platformAgnostic = PlatformAgnosticAvailabilityKind::Unavailable;
|
|
else if (isDeprecated)
|
|
platformAgnostic = PlatformAgnosticAvailabilityKind::Deprecated;
|
|
else if (((PlatformKind)platform) == PlatformKind::none &&
|
|
(!Introduced.empty() ||
|
|
!Deprecated.empty() ||
|
|
!Obsoleted.empty()))
|
|
platformAgnostic =
|
|
PlatformAgnosticAvailabilityKind::SwiftVersionSpecific;
|
|
else
|
|
platformAgnostic = PlatformAgnosticAvailabilityKind::None;
|
|
|
|
Attr = new (ctx) AvailableAttr(
|
|
SourceLoc(), SourceRange(),
|
|
(PlatformKind)platform, message, rename,
|
|
Introduced, SourceRange(),
|
|
Deprecated, SourceRange(),
|
|
Obsoleted, SourceRange(),
|
|
platformAgnostic, isImplicit);
|
|
break;
|
|
|
|
#undef DEF_VER_TUPLE_PIECES
|
|
#undef LIST_VER_TUPLE_PIECES
|
|
#undef DECODE_VER_TUPLE
|
|
}
|
|
|
|
case decls_block::AutoClosure_DECL_ATTR: {
|
|
bool isImplicit;
|
|
bool isEscaping;
|
|
serialization::decls_block::AutoClosureDeclAttrLayout::readRecord(
|
|
scratch, isImplicit, isEscaping);
|
|
Attr = new (ctx) AutoClosureAttr(SourceLoc(), SourceRange(),
|
|
isEscaping, isImplicit);
|
|
break;
|
|
}
|
|
|
|
case decls_block::ObjC_DECL_ATTR: {
|
|
bool isImplicit;
|
|
bool isImplicitName;
|
|
bool isSwift3Inferred;
|
|
uint64_t numArgs;
|
|
ArrayRef<uint64_t> rawPieceIDs;
|
|
serialization::decls_block::ObjCDeclAttrLayout::readRecord(
|
|
scratch, isImplicit, isSwift3Inferred, isImplicitName, numArgs,
|
|
rawPieceIDs);
|
|
|
|
SmallVector<Identifier, 4> pieces;
|
|
for (auto pieceID : rawPieceIDs)
|
|
pieces.push_back(getIdentifier(pieceID));
|
|
|
|
if (numArgs == 0)
|
|
Attr = ObjCAttr::create(ctx, None, isImplicitName);
|
|
else
|
|
Attr = ObjCAttr::create(ctx, ObjCSelector(ctx, numArgs-1, pieces),
|
|
isImplicitName);
|
|
Attr->setImplicit(isImplicit);
|
|
cast<ObjCAttr>(Attr)->setSwift3Inferred(isSwift3Inferred);
|
|
break;
|
|
}
|
|
|
|
case decls_block::Specialize_DECL_ATTR: {
|
|
unsigned exported;
|
|
SpecializeAttr::SpecializationKind specializationKind;
|
|
unsigned specializationKindVal;
|
|
SmallVector<Requirement, 8> requirements;
|
|
|
|
serialization::decls_block::SpecializeDeclAttrLayout::readRecord(
|
|
scratch, exported, specializationKindVal);
|
|
|
|
specializationKind = specializationKindVal
|
|
? SpecializeAttr::SpecializationKind::Partial
|
|
: SpecializeAttr::SpecializationKind::Full;
|
|
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
Attr = SpecializeAttr::create(ctx, SourceLoc(), SourceRange(),
|
|
requirements, exported != 0,
|
|
specializationKind);
|
|
break;
|
|
}
|
|
|
|
#define SIMPLE_DECL_ATTR(NAME, CLASS, ...) \
|
|
case decls_block::CLASS##_DECL_ATTR: { \
|
|
bool isImplicit; \
|
|
serialization::decls_block::CLASS##DeclAttrLayout::readRecord( \
|
|
scratch, isImplicit); \
|
|
Attr = new (ctx) CLASS##Attr(isImplicit); \
|
|
break; \
|
|
}
|
|
#include "swift/AST/Attr.def"
|
|
|
|
default:
|
|
// We don't know how to deserialize this kind of attribute.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (!Attr)
|
|
return nullptr;
|
|
|
|
AddAttribute(Attr);
|
|
|
|
} else if (recordID == decls_block::PRIVATE_DISCRIMINATOR) {
|
|
IdentifierID discriminatorID;
|
|
decls_block::PrivateDiscriminatorLayout::readRecord(scratch,
|
|
discriminatorID);
|
|
privateDiscriminatorRAII.discriminator = getIdentifier(discriminatorID);
|
|
|
|
} else if (recordID == decls_block::LOCAL_DISCRIMINATOR) {
|
|
unsigned discriminator;
|
|
decls_block::LocalDiscriminatorLayout::readRecord(scratch, discriminator);
|
|
localDiscriminatorRAII.discriminator = discriminator;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
// Advance bitstream cursor to the next record.
|
|
entry = DeclTypeCursor.advance();
|
|
|
|
// Prepare to read the next record.
|
|
scratch.clear();
|
|
}
|
|
|
|
PrettyDeclDeserialization stackTraceEntry(
|
|
this, declOrOffset, DID, static_cast<decls_block::RecordKind>(recordID));
|
|
|
|
switch (recordID) {
|
|
case decls_block::TYPE_ALIAS_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
TypeID underlyingTypeID, interfaceTypeID;
|
|
bool isImplicit;
|
|
GenericEnvironmentID genericEnvID;
|
|
uint8_t rawAccessLevel;
|
|
|
|
decls_block::TypeAliasLayout::readRecord(scratch, nameID, contextID,
|
|
underlyingTypeID, interfaceTypeID,
|
|
isImplicit, genericEnvID,
|
|
rawAccessLevel);
|
|
|
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
|
|
|
auto genericParams = maybeReadGenericParams(DC);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto alias = createDecl<TypeAliasDecl>(SourceLoc(), SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc(), genericParams, DC);
|
|
declOrOffset = alias;
|
|
|
|
configureGenericEnvironment(alias, genericEnvID);
|
|
|
|
alias->setUnderlyingType(getType(underlyingTypeID));
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
alias->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (isImplicit)
|
|
alias->setImplicit();
|
|
|
|
alias->setCheckedInheritanceClause();
|
|
break;
|
|
}
|
|
|
|
case decls_block::GENERIC_TYPE_PARAM_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
unsigned depth;
|
|
unsigned index;
|
|
|
|
decls_block::GenericTypeParamDeclLayout::readRecord(scratch, nameID,
|
|
contextID,
|
|
isImplicit,
|
|
depth,
|
|
index);
|
|
|
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
|
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto genericParam = createDecl<GenericTypeParamDecl>(DC,
|
|
getIdentifier(nameID),
|
|
SourceLoc(),
|
|
depth,
|
|
index);
|
|
declOrOffset = genericParam;
|
|
|
|
if (isImplicit)
|
|
genericParam->setImplicit();
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::ASSOCIATED_TYPE_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
TypeID defaultDefinitionID;
|
|
bool isImplicit;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
|
|
decls_block::AssociatedTypeDeclLayout::readRecord(scratch, nameID,
|
|
contextID,
|
|
defaultDefinitionID,
|
|
isImplicit,
|
|
rawInheritedIDs);
|
|
|
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
// The where-clause information is pushed up into the protocol
|
|
// (specifically, into its requirement signature) and
|
|
// serialized/deserialized there, so the actual Decl doesn't need to store
|
|
// it.
|
|
TrailingWhereClause *trailingWhere = nullptr;
|
|
auto assocType = createDecl<AssociatedTypeDecl>(
|
|
DC, SourceLoc(), getIdentifier(nameID), SourceLoc(), trailingWhere,
|
|
this, defaultDefinitionID);
|
|
declOrOffset = assocType;
|
|
|
|
assocType->computeType();
|
|
|
|
assert(!assocType->getDeclaredInterfaceType()->hasError() &&
|
|
"erroneous associated type");
|
|
|
|
Accessibility parentAccess = cast<ProtocolDecl>(DC)->getFormalAccess();
|
|
assocType->setAccessibility(std::max(parentAccess,Accessibility::Internal));
|
|
if (isImplicit)
|
|
assocType->setImplicit();
|
|
|
|
auto inherited = ctx.Allocate<TypeLoc>(rawInheritedIDs.size());
|
|
for_each(inherited, rawInheritedIDs, [this](TypeLoc &loc, uint64_t rawID) {
|
|
loc.setType(getType(rawID));
|
|
});
|
|
assocType->setInherited(inherited);
|
|
|
|
assocType->setCheckedInheritanceClause();
|
|
break;
|
|
}
|
|
|
|
case decls_block::STRUCT_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
GenericEnvironmentID genericEnvID;
|
|
uint8_t rawAccessLevel;
|
|
unsigned numConformances;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
|
|
decls_block::StructLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, genericEnvID,
|
|
rawAccessLevel,
|
|
numConformances,
|
|
rawInheritedIDs);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto genericParams = maybeReadGenericParams(DC);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto theStruct = createDecl<StructDecl>(SourceLoc(), getIdentifier(nameID),
|
|
SourceLoc(), None, genericParams,
|
|
DC);
|
|
declOrOffset = theStruct;
|
|
|
|
// Read the generic environment.
|
|
configureGenericEnvironment(theStruct, genericEnvID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
theStruct->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (isImplicit)
|
|
theStruct->setImplicit();
|
|
|
|
theStruct->computeType();
|
|
|
|
handleInherited(theStruct, rawInheritedIDs);
|
|
|
|
theStruct->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
|
|
skipRecord(DeclTypeCursor, decls_block::MEMBERS);
|
|
theStruct->setConformanceLoader(
|
|
this,
|
|
encodeLazyConformanceContextData(numConformances,
|
|
DeclTypeCursor.GetCurrentBitNo()));
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::CONSTRUCTOR_DECL: {
|
|
DeclContextID contextID;
|
|
uint8_t rawFailability;
|
|
bool isImplicit, isObjC, hasStubImplementation, throws;
|
|
GenericEnvironmentID genericEnvID;
|
|
uint8_t storedInitKind, rawAccessLevel;
|
|
TypeID interfaceID, canonicalTypeID;
|
|
DeclID overriddenID;
|
|
ArrayRef<uint64_t> argNameIDs;
|
|
|
|
decls_block::ConstructorLayout::readRecord(scratch, contextID,
|
|
rawFailability, isImplicit,
|
|
isObjC, hasStubImplementation,
|
|
throws, storedInitKind,
|
|
genericEnvID, interfaceID,
|
|
canonicalTypeID, overriddenID,
|
|
rawAccessLevel, argNameIDs);
|
|
|
|
// Resolve the name ids.
|
|
SmallVector<Identifier, 2> argNames;
|
|
for (auto argNameID : argNameIDs)
|
|
argNames.push_back(getIdentifier(argNameID));
|
|
DeclName name(ctx, ctx.Id_init, argNames);
|
|
|
|
Optional<swift::CtorInitializerKind> initKind =
|
|
getActualCtorInitializerKind(storedInitKind);
|
|
|
|
auto overridden = getDeclChecked(overriddenID);
|
|
if (!overridden) {
|
|
llvm::consumeError(overridden.takeError());
|
|
auto kind = OverrideError::Normal;
|
|
if (initKind == CtorInitializerKind::Designated)
|
|
kind = OverrideError::DesignatedInitializer;
|
|
return llvm::make_error<OverrideError>(name, kind);
|
|
}
|
|
|
|
auto parent = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto *genericParams = maybeReadGenericParams(parent);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
OptionalTypeKind failability = OTK_None;
|
|
if (auto actualFailability = getActualOptionalTypeKind(rawFailability))
|
|
failability = *actualFailability;
|
|
|
|
auto ctor =
|
|
createDecl<ConstructorDecl>(name, SourceLoc(),
|
|
failability, /*FailabilityLoc=*/SourceLoc(),
|
|
/*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(),
|
|
/*BodyParams=*/nullptr, nullptr,
|
|
genericParams, parent);
|
|
declOrOffset = ctor;
|
|
|
|
configureGenericEnvironment(ctor, genericEnvID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
ctor->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
auto *bodyParams0 = readParameterList();
|
|
bodyParams0->get(0)->setImplicit(); // self is implicit.
|
|
|
|
auto *bodyParams1 = readParameterList();
|
|
assert(bodyParams0 && bodyParams1 && "missing parameters for constructor");
|
|
ctor->setParameterLists(bodyParams0->get(0), bodyParams1);
|
|
|
|
auto interfaceType = getType(interfaceID);
|
|
ctor->setInterfaceType(interfaceType);
|
|
|
|
// Set the initializer interface type of the constructor.
|
|
auto allocType = ctor->getInterfaceType();
|
|
auto selfTy = ctor->computeInterfaceSelfType(/*isInitializingCtor=*/true);
|
|
if (auto polyFn = allocType->getAs<GenericFunctionType>()) {
|
|
ctor->setInitializerInterfaceType(
|
|
GenericFunctionType::get(polyFn->getGenericSignature(),
|
|
selfTy, polyFn->getResult(),
|
|
polyFn->getExtInfo()));
|
|
} else {
|
|
auto fn = allocType->castTo<FunctionType>();
|
|
ctor->setInitializerInterfaceType(FunctionType::get(selfTy,
|
|
fn->getResult(),
|
|
fn->getExtInfo()));
|
|
}
|
|
|
|
if (auto errorConvention = maybeReadForeignErrorConvention())
|
|
ctor->setForeignErrorConvention(*errorConvention);
|
|
|
|
if (isImplicit)
|
|
ctor->setImplicit();
|
|
if (hasStubImplementation)
|
|
ctor->setStubImplementation(true);
|
|
if (initKind.hasValue())
|
|
ctor->setInitKind(initKind.getValue());
|
|
if (auto overriddenCtor = cast_or_null<ConstructorDecl>(overridden.get()))
|
|
ctor->setOverriddenDecl(overriddenCtor);
|
|
break;
|
|
}
|
|
|
|
case decls_block::VAR_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit, isObjC, isStatic, isLet, hasNonPatternBindingInit;
|
|
uint8_t storageKind, rawAccessLevel, rawSetterAccessLevel;
|
|
TypeID interfaceTypeID, canonicalTypeID;
|
|
DeclID getterID, setterID, materializeForSetID, willSetID, didSetID;
|
|
DeclID addressorID, mutableAddressorID, overriddenID;
|
|
|
|
decls_block::VarLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, isObjC, isStatic, isLet,
|
|
hasNonPatternBindingInit, storageKind,
|
|
interfaceTypeID, canonicalTypeID,
|
|
getterID, setterID, materializeForSetID,
|
|
addressorID, mutableAddressorID,
|
|
willSetID, didSetID, overriddenID,
|
|
rawAccessLevel, rawSetterAccessLevel);
|
|
|
|
Identifier name = getIdentifier(nameID);
|
|
|
|
Expected<Decl *> overridden = getDeclChecked(overriddenID);
|
|
if (!overridden) {
|
|
llvm::consumeError(overridden.takeError());
|
|
return llvm::make_error<OverrideError>(name);
|
|
}
|
|
|
|
auto canonicalType = getTypeChecked(canonicalTypeID);
|
|
if (!canonicalType)
|
|
return llvm::make_error<TypeError>(name, takeErrorInfo(canonicalType.takeError()));
|
|
|
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto var = createDecl<VarDecl>(/*IsStatic*/isStatic, /*IsLet*/isLet,
|
|
/*IsCaptureList*/false, SourceLoc(), name,
|
|
Type(), DC);
|
|
var->setHasNonPatternBindingInit(hasNonPatternBindingInit);
|
|
declOrOffset = var;
|
|
|
|
Type interfaceType = getType(interfaceTypeID);
|
|
var->setInterfaceType(interfaceType);
|
|
|
|
if (auto referenceStorage = interfaceType->getAs<ReferenceStorageType>())
|
|
AddAttribute(new (ctx) OwnershipAttr(referenceStorage->getOwnership()));
|
|
|
|
configureStorage(var, storageKind, getterID, setterID, materializeForSetID,
|
|
addressorID, mutableAddressorID, willSetID, didSetID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
var->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (var->isSettable(nullptr)) {
|
|
if (auto setterAccess = getActualAccessibility(rawSetterAccessLevel)) {
|
|
var->setSetterAccessibility(*setterAccess);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (isImplicit)
|
|
var->setImplicit();
|
|
|
|
if (auto overriddenVar = cast_or_null<VarDecl>(overridden.get())) {
|
|
var->setOverriddenDecl(overriddenVar);
|
|
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::PARAM_DECL: {
|
|
IdentifierID argNameID, paramNameID;
|
|
DeclContextID contextID;
|
|
bool isLet;
|
|
TypeID interfaceTypeID;
|
|
|
|
decls_block::ParamLayout::readRecord(scratch, argNameID, paramNameID,
|
|
contextID, isLet, interfaceTypeID);
|
|
|
|
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto param = createDecl<ParamDecl>(isLet, SourceLoc(), SourceLoc(),
|
|
getIdentifier(argNameID), SourceLoc(),
|
|
getIdentifier(paramNameID), Type(), DC);
|
|
|
|
declOrOffset = param;
|
|
|
|
auto paramTy = getType(interfaceTypeID);
|
|
if (paramTy->hasError()) {
|
|
// FIXME: This should never happen, because we don't serialize
|
|
// error types.
|
|
DC->dumpContext();
|
|
paramTy->dump();
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
param->setInterfaceType(paramTy);
|
|
break;
|
|
}
|
|
|
|
case decls_block::FUNC_DECL: {
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
bool isStatic;
|
|
uint8_t rawStaticSpelling, rawAccessLevel, rawAddressorKind;
|
|
bool isObjC, isMutating, hasDynamicSelf, throws;
|
|
unsigned numParamPatterns;
|
|
GenericEnvironmentID genericEnvID;
|
|
TypeID interfaceTypeID, canonicalTypeID;
|
|
DeclID associatedDeclID;
|
|
DeclID overriddenID;
|
|
DeclID accessorStorageDeclID;
|
|
bool hasCompoundName;
|
|
ArrayRef<uint64_t> nameIDs;
|
|
|
|
decls_block::FuncLayout::readRecord(scratch, contextID, isImplicit,
|
|
isStatic, rawStaticSpelling, isObjC,
|
|
isMutating, hasDynamicSelf, throws,
|
|
numParamPatterns, genericEnvID,
|
|
interfaceTypeID, canonicalTypeID,
|
|
associatedDeclID, overriddenID,
|
|
accessorStorageDeclID, hasCompoundName,
|
|
rawAddressorKind, rawAccessLevel,
|
|
nameIDs);
|
|
|
|
// Resolve the name ids.
|
|
SmallVector<Identifier, 2> names;
|
|
for (auto nameID : nameIDs)
|
|
names.push_back(getIdentifier(nameID));
|
|
|
|
DeclName name;
|
|
if (!names.empty()) {
|
|
if (hasCompoundName)
|
|
name = DeclName(ctx, names[0],
|
|
llvm::makeArrayRef(names.begin() + 1, names.end()));
|
|
else
|
|
name = DeclName(names[0]);
|
|
}
|
|
|
|
Expected<Decl *> overridden = getDeclChecked(overriddenID);
|
|
if (!overridden) {
|
|
llvm::consumeError(overridden.takeError());
|
|
return llvm::make_error<OverrideError>(name);
|
|
}
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
// 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 staticSpelling = getActualStaticSpellingKind(rawStaticSpelling);
|
|
if (!staticSpelling.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto fn = FuncDecl::createDeserialized(
|
|
ctx, /*StaticLoc=*/SourceLoc(), staticSpelling.getValue(),
|
|
/*FuncLoc=*/SourceLoc(), name, /*NameLoc=*/SourceLoc(),
|
|
/*Throws=*/throws, /*ThrowsLoc=*/SourceLoc(),
|
|
/*AccessorKeywordLoc=*/SourceLoc(), genericParams,
|
|
numParamPatterns, DC);
|
|
fn->setEarlyAttrValidation();
|
|
declOrOffset = fn;
|
|
|
|
configureGenericEnvironment(fn, genericEnvID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
fn->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (auto addressorKind = getActualAddressorKind(rawAddressorKind)) {
|
|
if (*addressorKind != AddressorKind::NotAddressor)
|
|
fn->setAddressorKind(*addressorKind);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (Decl *associated = getDecl(associatedDeclID)) {
|
|
if (auto op = dyn_cast<OperatorDecl>(associated)) {
|
|
fn->setOperatorDecl(op);
|
|
|
|
if (isa<PrefixOperatorDecl>(op))
|
|
fn->getAttrs().add(new (ctx) PrefixAttr(/*implicit*/false));
|
|
else if (isa<PostfixOperatorDecl>(op))
|
|
fn->getAttrs().add(new (ctx) PostfixAttr(/*implicit*/false));
|
|
// Note that an explicit 'infix' is not required.
|
|
}
|
|
// Otherwise, unknown associated decl kind.
|
|
}
|
|
|
|
// Set the interface type.
|
|
auto interfaceType = getType(interfaceTypeID);
|
|
fn->setInterfaceType(interfaceType);
|
|
|
|
SmallVector<ParameterList*, 2> paramLists;
|
|
for (unsigned i = 0, e = numParamPatterns; i != e; ++i)
|
|
paramLists.push_back(readParameterList());
|
|
|
|
// If the first parameter list is (self), mark it implicit.
|
|
if (numParamPatterns && DC->isTypeContext())
|
|
paramLists[0]->get(0)->setImplicit();
|
|
|
|
fn->setDeserializedSignature(paramLists, TypeLoc());
|
|
|
|
if (auto errorConvention = maybeReadForeignErrorConvention())
|
|
fn->setForeignErrorConvention(*errorConvention);
|
|
|
|
if (auto overriddenFunc = cast_or_null<FuncDecl>(overridden.get())) {
|
|
fn->setOverriddenDecl(overriddenFunc);
|
|
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
|
|
}
|
|
|
|
fn->setStatic(isStatic);
|
|
if (isImplicit)
|
|
fn->setImplicit();
|
|
fn->setMutating(isMutating);
|
|
fn->setDynamicSelf(hasDynamicSelf);
|
|
|
|
// If we are an accessor on a var or subscript, make sure it is deserialized
|
|
// too.
|
|
getDecl(accessorStorageDeclID);
|
|
break;
|
|
}
|
|
|
|
case decls_block::PATTERN_BINDING_DECL: {
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
bool isStatic;
|
|
uint8_t RawStaticSpelling;
|
|
unsigned numPatterns;
|
|
ArrayRef<uint64_t> initContextIDs;
|
|
|
|
decls_block::PatternBindingLayout::readRecord(scratch, contextID,
|
|
isImplicit,
|
|
isStatic,
|
|
RawStaticSpelling,
|
|
numPatterns,
|
|
initContextIDs);
|
|
auto StaticSpelling = getActualStaticSpellingKind(RawStaticSpelling);
|
|
if (!StaticSpelling.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
auto dc = getDeclContext(contextID);
|
|
|
|
SmallVector<std::pair<Pattern *, DeclContextID>, 4> patterns;
|
|
for (unsigned i = 0; i != numPatterns; ++i) {
|
|
auto pattern = readPattern(dc);
|
|
if (!pattern) {
|
|
// Silently drop the pattern...
|
|
llvm::consumeError(pattern.takeError());
|
|
// ...but continue to read any further patterns we're expecting.
|
|
continue;
|
|
}
|
|
|
|
patterns.emplace_back(pattern.get(), DeclContextID());
|
|
if (!initContextIDs.empty())
|
|
patterns.back().second = initContextIDs[i];
|
|
}
|
|
|
|
auto binding =
|
|
PatternBindingDecl::createDeserialized(ctx, SourceLoc(),
|
|
StaticSpelling.getValue(),
|
|
SourceLoc(), patterns.size(), dc);
|
|
binding->setEarlyAttrValidation(true);
|
|
declOrOffset = binding;
|
|
|
|
binding->setStatic(isStatic);
|
|
|
|
if (isImplicit)
|
|
binding->setImplicit();
|
|
|
|
for (unsigned i = 0; i != patterns.size(); ++i) {
|
|
DeclContext *initContext = getDeclContext(patterns[i].second);
|
|
binding->setPattern(i, patterns[i].first, initContext);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::PROTOCOL_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit, isClassBounded, isObjC;
|
|
GenericEnvironmentID genericEnvID;
|
|
uint8_t rawAccessLevel;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
|
|
decls_block::ProtocolLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, isClassBounded, isObjC,
|
|
genericEnvID, rawAccessLevel,
|
|
rawInheritedIDs);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto proto = createDecl<ProtocolDecl>(DC, SourceLoc(), SourceLoc(),
|
|
getIdentifier(nameID), None,
|
|
/*TrailingWhere=*/nullptr);
|
|
declOrOffset = proto;
|
|
|
|
proto->setRequiresClass(isClassBounded);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
proto->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
auto genericParams = maybeReadGenericParams(DC);
|
|
assert(genericParams && "protocol with no generic parameters?");
|
|
proto->setGenericParams(genericParams);
|
|
|
|
handleInherited(proto, rawInheritedIDs);
|
|
|
|
configureGenericEnvironment(proto, genericEnvID);
|
|
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
if (isImplicit)
|
|
proto->setImplicit();
|
|
proto->computeType();
|
|
|
|
auto signature = GenericSignature::get(
|
|
{ proto->getProtocolSelfType() }, requirements);
|
|
proto->setRequirementSignature(signature);
|
|
|
|
proto->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
|
|
proto->setCircularityCheck(CircularityCheck::Checked);
|
|
break;
|
|
}
|
|
|
|
case decls_block::PREFIX_OPERATOR_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
|
|
decls_block::PrefixOperatorLayout::readRecord(scratch, nameID,
|
|
contextID);
|
|
auto DC = getDeclContext(contextID);
|
|
declOrOffset = createDecl<PrefixOperatorDecl>(DC, SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc());
|
|
break;
|
|
}
|
|
|
|
case decls_block::POSTFIX_OPERATOR_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
|
|
decls_block::PostfixOperatorLayout::readRecord(scratch, nameID,
|
|
contextID);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
declOrOffset = createDecl<PostfixOperatorDecl>(DC, SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc());
|
|
break;
|
|
}
|
|
|
|
case decls_block::INFIX_OPERATOR_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
DeclID precedenceGroupID;
|
|
|
|
decls_block::InfixOperatorLayout::readRecord(scratch, nameID, contextID,
|
|
precedenceGroupID);
|
|
|
|
PrecedenceGroupDecl *precedenceGroup = nullptr;
|
|
Identifier precedenceGroupName;
|
|
if (precedenceGroupID) {
|
|
precedenceGroup =
|
|
dyn_cast_or_null<PrecedenceGroupDecl>(getDecl(precedenceGroupID));
|
|
if (precedenceGroup) {
|
|
precedenceGroupName = precedenceGroup->getName();
|
|
}
|
|
}
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
|
|
auto result = createDecl<InfixOperatorDecl>(DC, SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc(), SourceLoc(),
|
|
precedenceGroupName,
|
|
SourceLoc());
|
|
result->setPrecedenceGroup(precedenceGroup);
|
|
|
|
declOrOffset = result;
|
|
break;
|
|
}
|
|
|
|
case decls_block::PRECEDENCE_GROUP_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
uint8_t rawAssociativity;
|
|
bool assignment;
|
|
unsigned numHigherThan;
|
|
ArrayRef<uint64_t> rawRelations;
|
|
|
|
decls_block::PrecedenceGroupLayout::readRecord(scratch, nameID, contextID,
|
|
rawAssociativity,
|
|
assignment, numHigherThan,
|
|
rawRelations);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
|
|
auto associativity = getActualAssociativity(rawAssociativity);
|
|
if (!associativity.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (numHigherThan > rawRelations.size()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
SmallVector<PrecedenceGroupDecl::Relation, 4> higherThan;
|
|
for (auto relID : rawRelations.slice(0, numHigherThan)) {
|
|
PrecedenceGroupDecl *rel = nullptr;
|
|
if (relID)
|
|
rel = dyn_cast_or_null<PrecedenceGroupDecl>(getDecl(relID));
|
|
if (!rel) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
higherThan.push_back({SourceLoc(), rel->getName(), rel});
|
|
}
|
|
|
|
SmallVector<PrecedenceGroupDecl::Relation, 4> lowerThan;
|
|
for (auto relID : rawRelations.slice(numHigherThan)) {
|
|
PrecedenceGroupDecl *rel = nullptr;
|
|
if (relID)
|
|
rel = dyn_cast_or_null<PrecedenceGroupDecl>(getDecl(relID));
|
|
if (!rel) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
lowerThan.push_back({SourceLoc(), rel->getName(), rel});
|
|
}
|
|
|
|
declOrOffset = PrecedenceGroupDecl::create(DC, SourceLoc(), SourceLoc(),
|
|
getIdentifier(nameID),
|
|
SourceLoc(),
|
|
SourceLoc(), SourceLoc(),
|
|
*associativity,
|
|
SourceLoc(), SourceLoc(),
|
|
assignment,
|
|
SourceLoc(), higherThan,
|
|
SourceLoc(), lowerThan,
|
|
SourceLoc());
|
|
break;
|
|
}
|
|
|
|
case decls_block::CLASS_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit, isObjC, requiresStoredPropertyInits;
|
|
GenericEnvironmentID genericEnvID;
|
|
TypeID superclassID;
|
|
uint8_t rawAccessLevel;
|
|
unsigned numConformances;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
decls_block::ClassLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, isObjC,
|
|
requiresStoredPropertyInits,
|
|
genericEnvID, superclassID,
|
|
rawAccessLevel, numConformances,
|
|
rawInheritedIDs);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto genericParams = maybeReadGenericParams(DC);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto theClass = createDecl<ClassDecl>(SourceLoc(), getIdentifier(nameID),
|
|
SourceLoc(), None, genericParams, DC);
|
|
declOrOffset = theClass;
|
|
|
|
configureGenericEnvironment(theClass, genericEnvID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
theClass->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
theClass->setAddedImplicitInitializers();
|
|
if (isImplicit)
|
|
theClass->setImplicit();
|
|
theClass->setSuperclass(getType(superclassID));
|
|
if (requiresStoredPropertyInits)
|
|
theClass->setRequiresStoredPropertyInits(true);
|
|
|
|
theClass->computeType();
|
|
|
|
handleInherited(theClass, rawInheritedIDs);
|
|
|
|
theClass->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
|
|
theClass->setHasDestructor();
|
|
skipRecord(DeclTypeCursor, decls_block::MEMBERS);
|
|
theClass->setConformanceLoader(
|
|
this,
|
|
encodeLazyConformanceContextData(numConformances,
|
|
DeclTypeCursor.GetCurrentBitNo()));
|
|
|
|
theClass->setCircularityCheck(CircularityCheck::Checked);
|
|
break;
|
|
}
|
|
|
|
case decls_block::ENUM_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
GenericEnvironmentID genericEnvID;
|
|
TypeID rawTypeID;
|
|
uint8_t rawAccessLevel;
|
|
unsigned numConformances;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
|
|
decls_block::EnumLayout::readRecord(scratch, nameID, contextID,
|
|
isImplicit, genericEnvID, rawTypeID,
|
|
rawAccessLevel,
|
|
numConformances, rawInheritedIDs);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto genericParams = maybeReadGenericParams(DC);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto theEnum = createDecl<EnumDecl>(SourceLoc(), getIdentifier(nameID),
|
|
SourceLoc(), None, genericParams, DC);
|
|
|
|
declOrOffset = theEnum;
|
|
|
|
configureGenericEnvironment(theEnum, genericEnvID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
theEnum->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (isImplicit)
|
|
theEnum->setImplicit();
|
|
theEnum->setRawType(getType(rawTypeID));
|
|
|
|
theEnum->computeType();
|
|
|
|
handleInherited(theEnum, rawInheritedIDs);
|
|
|
|
theEnum->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
|
|
skipRecord(DeclTypeCursor, decls_block::MEMBERS);
|
|
theEnum->setConformanceLoader(
|
|
this,
|
|
encodeLazyConformanceContextData(numConformances,
|
|
DeclTypeCursor.GetCurrentBitNo()));
|
|
break;
|
|
}
|
|
|
|
case decls_block::ENUM_ELEMENT_DECL: {
|
|
IdentifierID nameID;
|
|
DeclContextID contextID;
|
|
TypeID interfaceTypeID;
|
|
bool hasArgumentType;
|
|
bool isImplicit; bool isNegative;
|
|
unsigned rawValueKindID;
|
|
|
|
decls_block::EnumElementLayout::readRecord(scratch, nameID,
|
|
contextID,
|
|
interfaceTypeID,
|
|
hasArgumentType,
|
|
isImplicit, rawValueKindID,
|
|
isNegative);
|
|
|
|
DeclContext *DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto elem = createDecl<EnumElementDecl>(SourceLoc(),
|
|
getIdentifier(nameID),
|
|
TypeLoc(),
|
|
hasArgumentType,
|
|
SourceLoc(),
|
|
nullptr,
|
|
DC);
|
|
declOrOffset = elem;
|
|
|
|
// Deserialize the literal raw value, if any.
|
|
switch ((EnumElementRawValueKind)rawValueKindID) {
|
|
case EnumElementRawValueKind::None:
|
|
break;
|
|
case EnumElementRawValueKind::IntegerLiteral: {
|
|
auto literalText = getContext().AllocateCopy(blobData);
|
|
auto literal = new (getContext()) IntegerLiteralExpr(literalText,
|
|
SourceLoc(),
|
|
/*implicit*/ true);
|
|
if (isNegative)
|
|
literal->setNegative(SourceLoc());
|
|
elem->setRawValueExpr(literal);
|
|
}
|
|
}
|
|
|
|
auto interfaceType = getType(interfaceTypeID);
|
|
elem->setInterfaceType(interfaceType);
|
|
|
|
if (isImplicit)
|
|
elem->setImplicit();
|
|
elem->setAccessibility(std::max(cast<EnumDecl>(DC)->getFormalAccess(),
|
|
Accessibility::Internal));
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::SUBSCRIPT_DECL: {
|
|
DeclContextID contextID;
|
|
bool isImplicit, isObjC;
|
|
GenericEnvironmentID genericEnvID;
|
|
TypeID interfaceTypeID, canonicalTypeID;
|
|
DeclID getterID, setterID, materializeForSetID;
|
|
DeclID addressorID, mutableAddressorID, willSetID, didSetID;
|
|
DeclID overriddenID;
|
|
uint8_t rawAccessLevel, rawSetterAccessLevel;
|
|
uint8_t rawStorageKind;
|
|
ArrayRef<uint64_t> argNameIDs;
|
|
|
|
decls_block::SubscriptLayout::readRecord(scratch, contextID,
|
|
isImplicit, isObjC, rawStorageKind,
|
|
genericEnvID,
|
|
interfaceTypeID, canonicalTypeID,
|
|
getterID, setterID,
|
|
materializeForSetID,
|
|
addressorID, mutableAddressorID,
|
|
willSetID, didSetID,
|
|
overriddenID, rawAccessLevel,
|
|
rawSetterAccessLevel,
|
|
argNameIDs);
|
|
// Resolve the name ids.
|
|
SmallVector<Identifier, 2> argNames;
|
|
for (auto argNameID : argNameIDs)
|
|
argNames.push_back(getIdentifier(argNameID));
|
|
DeclName name(ctx, ctx.Id_subscript, argNames);
|
|
|
|
Expected<Decl *> overridden = getDeclChecked(overriddenID);
|
|
if (!overridden) {
|
|
llvm::consumeError(overridden.takeError());
|
|
return llvm::make_error<OverrideError>(name);
|
|
}
|
|
|
|
auto parent = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto *genericParams = maybeReadGenericParams(parent);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto subscript = createDecl<SubscriptDecl>(name, SourceLoc(), nullptr,
|
|
SourceLoc(), TypeLoc(),
|
|
parent, genericParams);
|
|
declOrOffset = subscript;
|
|
|
|
configureGenericEnvironment(subscript, genericEnvID);
|
|
|
|
subscript->setIndices(readParameterList());
|
|
|
|
configureStorage(subscript, rawStorageKind,
|
|
getterID, setterID, materializeForSetID,
|
|
addressorID, mutableAddressorID, willSetID, didSetID);
|
|
|
|
if (auto accessLevel = getActualAccessibility(rawAccessLevel)) {
|
|
subscript->setAccessibility(*accessLevel);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
if (subscript->isSettable()) {
|
|
if (auto setterAccess = getActualAccessibility(rawSetterAccessLevel)) {
|
|
subscript->setSetterAccessibility(*setterAccess);
|
|
} else {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
auto interfaceType = getType(interfaceTypeID);
|
|
subscript->setInterfaceType(interfaceType);
|
|
|
|
if (isImplicit)
|
|
subscript->setImplicit();
|
|
if (auto overriddenSub = cast_or_null<SubscriptDecl>(overridden.get())) {
|
|
subscript->setOverriddenDecl(overriddenSub);
|
|
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case decls_block::EXTENSION_DECL: {
|
|
TypeID baseID;
|
|
DeclContextID contextID;
|
|
bool isImplicit;
|
|
GenericEnvironmentID genericEnvID;
|
|
unsigned numConformances;
|
|
ArrayRef<uint64_t> rawInheritedIDs;
|
|
|
|
decls_block::ExtensionLayout::readRecord(scratch, baseID, contextID,
|
|
isImplicit, genericEnvID,
|
|
numConformances, rawInheritedIDs);
|
|
|
|
auto DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto extension = ExtensionDecl::create(ctx, SourceLoc(), TypeLoc(), { },
|
|
DC, nullptr);
|
|
extension->setEarlyAttrValidation();
|
|
declOrOffset = extension;
|
|
|
|
// Generic parameter lists are written from outermost to innermost.
|
|
// Keep reading until we run out of generic parameter lists.
|
|
GenericParamList *outerParams = nullptr;
|
|
while (auto *genericParams = maybeReadGenericParams(DC, outerParams))
|
|
outerParams = genericParams;
|
|
extension->setGenericParams(outerParams);
|
|
|
|
configureGenericEnvironment(extension, genericEnvID);
|
|
|
|
auto baseTy = getType(baseID);
|
|
auto nominal = baseTy->getAnyNominal();
|
|
extension->getExtendedTypeLoc().setType(baseTy);
|
|
|
|
if (isImplicit)
|
|
extension->setImplicit();
|
|
|
|
auto inheritedTypes = ctx.Allocate<TypeLoc>(rawInheritedIDs.size());
|
|
for_each(inheritedTypes, rawInheritedIDs,
|
|
[this](TypeLoc &tl, uint64_t rawID) {
|
|
tl = TypeLoc::withoutLoc(getType(rawID));
|
|
});
|
|
extension->setInherited(inheritedTypes);
|
|
extension->setCheckedInheritanceClause();
|
|
|
|
extension->setMemberLoader(this, DeclTypeCursor.GetCurrentBitNo());
|
|
skipRecord(DeclTypeCursor, decls_block::MEMBERS);
|
|
extension->setConformanceLoader(
|
|
this,
|
|
encodeLazyConformanceContextData(numConformances,
|
|
DeclTypeCursor.GetCurrentBitNo()));
|
|
|
|
nominal->addExtension(extension);
|
|
|
|
#ifndef NDEBUG
|
|
if (outerParams) {
|
|
unsigned paramCount = 0;
|
|
for (auto *paramList = outerParams;
|
|
paramList != nullptr;
|
|
paramList = paramList->getOuterParameters()) {
|
|
paramCount += paramList->size();
|
|
}
|
|
assert(paramCount ==
|
|
extension->getGenericSignature()->getGenericParams().size());
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::DESTRUCTOR_DECL: {
|
|
DeclContextID contextID;
|
|
bool isImplicit, isObjC;
|
|
GenericEnvironmentID genericEnvID;
|
|
TypeID interfaceID;
|
|
|
|
decls_block::DestructorLayout::readRecord(scratch, contextID,
|
|
isImplicit, isObjC,
|
|
genericEnvID,
|
|
interfaceID);
|
|
|
|
DeclContext *DC = getDeclContext(contextID);
|
|
if (declOrOffset.isComplete())
|
|
return declOrOffset;
|
|
|
|
auto dtor = createDecl<DestructorDecl>(ctx.Id_deinit, SourceLoc(),
|
|
/*selfpat*/nullptr, DC);
|
|
declOrOffset = dtor;
|
|
|
|
configureGenericEnvironment(dtor, genericEnvID);
|
|
|
|
dtor->setAccessibility(std::max(cast<ClassDecl>(DC)->getFormalAccess(),
|
|
Accessibility::Internal));
|
|
auto *selfParams = readParameterList();
|
|
selfParams->get(0)->setImplicit(); // self is implicit.
|
|
|
|
assert(selfParams && "Didn't get self pattern?");
|
|
dtor->setSelfDecl(selfParams->get(0));
|
|
|
|
auto interfaceType = getType(interfaceID);
|
|
dtor->setInterfaceType(interfaceType);
|
|
|
|
if (isImplicit)
|
|
dtor->setImplicit();
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::XREF: {
|
|
assert(DAttrs == nullptr);
|
|
ModuleID baseModuleID;
|
|
uint32_t pathLen;
|
|
decls_block::XRefLayout::readRecord(scratch, baseModuleID, pathLen);
|
|
auto resolved = resolveCrossReference(getModule(baseModuleID), pathLen);
|
|
if (!resolved)
|
|
return resolved;
|
|
declOrOffset = resolved.get();
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// We don't know how to deserialize this kind of decl.
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
// Record the attributes.
|
|
if (DAttrs)
|
|
declOrOffset.get()->getAttrs().setRawAttributeChain(DAttrs);
|
|
|
|
auto decl = declOrOffset.get();
|
|
decl->setValidationStarted();
|
|
return decl;
|
|
}
|
|
|
|
/// Translate from the Serialization function type repr 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<swift::FunctionType::Representation>
|
|
getActualFunctionTypeRepresentation(uint8_t rep) {
|
|
switch (rep) {
|
|
#define CASE(THE_CC) \
|
|
case (uint8_t)serialization::FunctionTypeRepresentation::THE_CC: \
|
|
return swift::FunctionType::Representation::THE_CC;
|
|
CASE(Swift)
|
|
CASE(Block)
|
|
CASE(Thin)
|
|
CASE(CFunctionPointer)
|
|
#undef CASE
|
|
default:
|
|
return None;
|
|
}
|
|
}
|
|
|
|
/// Translate from the Serialization function type repr 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<swift::SILFunctionType::Representation>
|
|
getActualSILFunctionTypeRepresentation(uint8_t rep) {
|
|
switch (rep) {
|
|
#define CASE(THE_CC) \
|
|
case (uint8_t)serialization::SILFunctionTypeRepresentation::THE_CC: \
|
|
return swift::SILFunctionType::Representation::THE_CC;
|
|
CASE(Thick)
|
|
CASE(Block)
|
|
CASE(Thin)
|
|
CASE(CFunctionPointer)
|
|
CASE(Method)
|
|
CASE(ObjCMethod)
|
|
CASE(WitnessMethod)
|
|
#undef CASE
|
|
default:
|
|
return None;
|
|
}
|
|
}
|
|
|
|
/// Translate from the serialization Ownership enumerators, which are
|
|
/// guaranteed to be stable, to the AST ones.
|
|
static
|
|
Optional<swift::Ownership> getActualOwnership(serialization::Ownership raw) {
|
|
switch (raw) {
|
|
case serialization::Ownership::Strong: return swift::Ownership::Strong;
|
|
case serialization::Ownership::Unmanaged:return swift::Ownership::Unmanaged;
|
|
case serialization::Ownership::Unowned: return swift::Ownership::Unowned;
|
|
case serialization::Ownership::Weak: return swift::Ownership::Weak;
|
|
}
|
|
return None;
|
|
}
|
|
|
|
/// Translate from the serialization ParameterConvention enumerators,
|
|
/// which are guaranteed to be stable, to the AST ones.
|
|
static
|
|
Optional<swift::ParameterConvention> getActualParameterConvention(uint8_t raw) {
|
|
switch (serialization::ParameterConvention(raw)) {
|
|
#define CASE(ID) \
|
|
case serialization::ParameterConvention::ID: \
|
|
return swift::ParameterConvention::ID;
|
|
CASE(Indirect_In)
|
|
CASE(Indirect_Inout)
|
|
CASE(Indirect_InoutAliasable)
|
|
CASE(Indirect_In_Guaranteed)
|
|
CASE(Direct_Owned)
|
|
CASE(Direct_Unowned)
|
|
CASE(Direct_Guaranteed)
|
|
#undef CASE
|
|
}
|
|
return None;
|
|
}
|
|
|
|
/// Translate from the serialization ResultConvention enumerators,
|
|
/// which are guaranteed to be stable, to the AST ones.
|
|
static
|
|
Optional<swift::ResultConvention> getActualResultConvention(uint8_t raw) {
|
|
switch (serialization::ResultConvention(raw)) {
|
|
#define CASE(ID) \
|
|
case serialization::ResultConvention::ID: return swift::ResultConvention::ID;
|
|
CASE(Indirect)
|
|
CASE(Owned)
|
|
CASE(Unowned)
|
|
CASE(UnownedInnerPointer)
|
|
CASE(Autoreleased)
|
|
#undef CASE
|
|
}
|
|
return None;
|
|
}
|
|
|
|
Type ModuleFile::getType(TypeID TID) {
|
|
Expected<Type> deserialized = getTypeChecked(TID);
|
|
if (!deserialized) {
|
|
fatal(deserialized.takeError());
|
|
}
|
|
return deserialized.get();
|
|
}
|
|
|
|
Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
|
|
if (TID == 0)
|
|
return Type();
|
|
|
|
assert(TID <= Types.size() && "invalid type ID");
|
|
auto &typeOrOffset = Types[TID-1];
|
|
|
|
if (typeOrOffset.isComplete())
|
|
return typeOrOffset;
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
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 = getContext();
|
|
|
|
SmallVector<uint64_t, 64> scratch;
|
|
StringRef blobData;
|
|
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch, &blobData);
|
|
|
|
switch (recordID) {
|
|
case decls_block::NAME_ALIAS_TYPE: {
|
|
DeclID underlyingID;
|
|
TypeID canonicalTypeID;
|
|
decls_block::NameAliasTypeLayout::readRecord(scratch, underlyingID,
|
|
canonicalTypeID);
|
|
auto aliasOrError = getDeclChecked(underlyingID);
|
|
if (!aliasOrError)
|
|
return aliasOrError.takeError();
|
|
auto alias = dyn_cast<TypeAliasDecl>(aliasOrError.get());
|
|
|
|
if (ctx.LangOpts.EnableDeserializationRecovery) {
|
|
Expected<Type> expectedType = getTypeChecked(canonicalTypeID);
|
|
if (!expectedType)
|
|
return expectedType.takeError();
|
|
if (expectedType.get()) {
|
|
if (!alias ||
|
|
!alias->getDeclaredInterfaceType()->isEqual(expectedType.get())) {
|
|
// Fall back to the canonical type.
|
|
typeOrOffset = expectedType.get();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Look through compatibility aliases that are now unavailable.
|
|
if (alias->getAttrs().isUnavailable(ctx) &&
|
|
alias->isCompatibilityAlias()) {
|
|
typeOrOffset = alias->getUnderlyingTypeLoc().getType();
|
|
break;
|
|
}
|
|
|
|
typeOrOffset = alias->getDeclaredInterfaceType();
|
|
break;
|
|
}
|
|
|
|
case decls_block::NOMINAL_TYPE: {
|
|
DeclID declID;
|
|
TypeID parentID;
|
|
decls_block::NominalTypeLayout::readRecord(scratch, declID, parentID);
|
|
|
|
Expected<Type> parentTy = getTypeChecked(parentID);
|
|
if (!parentTy)
|
|
return parentTy.takeError();
|
|
|
|
auto nominalOrError = getDeclChecked(declID);
|
|
if (!nominalOrError)
|
|
return nominalOrError.takeError();
|
|
|
|
auto nominal = dyn_cast<NominalTypeDecl>(nominalOrError.get());
|
|
if (!nominal) {
|
|
XRefTracePath tinyTrace{*nominalOrError.get()->getModuleContext()};
|
|
tinyTrace.addValue(cast<ValueDecl>(nominalOrError.get())->getName());
|
|
return llvm::make_error<XRefError>("declaration is not a nominal type",
|
|
tinyTrace);
|
|
}
|
|
typeOrOffset = NominalType::get(nominal, parentTy.get(), ctx);
|
|
|
|
assert(typeOrOffset.isComplete());
|
|
break;
|
|
}
|
|
|
|
case decls_block::PAREN_TYPE: {
|
|
TypeID underlyingID;
|
|
bool isVariadic, isAutoClosure, isEscaping;
|
|
decls_block::ParenTypeLayout::readRecord(scratch, underlyingID, isVariadic,
|
|
isAutoClosure, isEscaping);
|
|
typeOrOffset = ParenType::get(
|
|
ctx, getType(underlyingID),
|
|
ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping));
|
|
break;
|
|
}
|
|
|
|
case decls_block::TUPLE_TYPE: {
|
|
// The tuple record itself is empty. Read all trailing elements.
|
|
SmallVector<TupleTypeElt, 8> 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 isVariadic, isAutoClosure, isEscaping;
|
|
decls_block::TupleTypeEltLayout::readRecord(
|
|
scratch, nameID, typeID, isVariadic, isAutoClosure, isEscaping);
|
|
|
|
elements.emplace_back(
|
|
getType(typeID), getIdentifier(nameID),
|
|
ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping));
|
|
}
|
|
|
|
typeOrOffset = TupleType::get(elements, ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::FUNCTION_TYPE: {
|
|
TypeID inputID;
|
|
TypeID resultID;
|
|
uint8_t rawRepresentation;
|
|
bool autoClosure, noescape, throws;
|
|
|
|
decls_block::FunctionTypeLayout::readRecord(scratch, inputID, resultID,
|
|
rawRepresentation,
|
|
autoClosure,
|
|
noescape,
|
|
throws);
|
|
auto representation = getActualFunctionTypeRepresentation(rawRepresentation);
|
|
if (!representation.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
auto Info = FunctionType::ExtInfo(*representation,
|
|
autoClosure, noescape,
|
|
throws);
|
|
|
|
typeOrOffset = FunctionType::get(getType(inputID), getType(resultID),
|
|
Info);
|
|
break;
|
|
}
|
|
|
|
case decls_block::EXISTENTIAL_METATYPE_TYPE: {
|
|
TypeID instanceID;
|
|
uint8_t repr;
|
|
decls_block::ExistentialMetatypeTypeLayout::readRecord(scratch,
|
|
instanceID, repr);
|
|
|
|
switch (repr) {
|
|
case serialization::MetatypeRepresentation::MR_None:
|
|
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID));
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_Thin:
|
|
error();
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_Thick:
|
|
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID),
|
|
MetatypeRepresentation::Thick);
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_ObjC:
|
|
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID),
|
|
MetatypeRepresentation::ObjC);
|
|
break;
|
|
|
|
default:
|
|
error();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case decls_block::METATYPE_TYPE: {
|
|
TypeID instanceID;
|
|
uint8_t repr;
|
|
decls_block::MetatypeTypeLayout::readRecord(scratch, instanceID, repr);
|
|
|
|
switch (repr) {
|
|
case serialization::MetatypeRepresentation::MR_None:
|
|
typeOrOffset = MetatypeType::get(getType(instanceID));
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_Thin:
|
|
typeOrOffset = MetatypeType::get(getType(instanceID),
|
|
MetatypeRepresentation::Thin);
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_Thick:
|
|
typeOrOffset = MetatypeType::get(getType(instanceID),
|
|
MetatypeRepresentation::Thick);
|
|
break;
|
|
|
|
case serialization::MetatypeRepresentation::MR_ObjC:
|
|
typeOrOffset = MetatypeType::get(getType(instanceID),
|
|
MetatypeRepresentation::ObjC);
|
|
break;
|
|
|
|
default:
|
|
error();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case decls_block::DYNAMIC_SELF_TYPE: {
|
|
TypeID selfID;
|
|
decls_block::DynamicSelfTypeLayout::readRecord(scratch, selfID);
|
|
typeOrOffset = DynamicSelfType::get(getType(selfID), ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::LVALUE_TYPE: {
|
|
TypeID objectTypeID;
|
|
decls_block::LValueTypeLayout::readRecord(scratch, objectTypeID);
|
|
typeOrOffset = LValueType::get(getType(objectTypeID));
|
|
break;
|
|
}
|
|
case decls_block::INOUT_TYPE: {
|
|
TypeID objectTypeID;
|
|
decls_block::LValueTypeLayout::readRecord(scratch, objectTypeID);
|
|
typeOrOffset = InOutType::get(getType(objectTypeID));
|
|
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: {
|
|
GenericEnvironmentID envID;
|
|
TypeID interfaceTypeID;
|
|
|
|
decls_block::ArchetypeTypeLayout::readRecord(scratch, envID,
|
|
interfaceTypeID);
|
|
|
|
auto env = getGenericEnvironment(envID);
|
|
if (!env) {
|
|
error();
|
|
break;
|
|
}
|
|
|
|
Type interfaceType = getType(interfaceTypeID);
|
|
Type contextType = env->mapTypeIntoContext(interfaceType);
|
|
typeOrOffset = contextType;
|
|
|
|
if (contextType->hasError()) {
|
|
error();
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case decls_block::OPENED_EXISTENTIAL_TYPE: {
|
|
TypeID existentialID;
|
|
|
|
decls_block::OpenedExistentialTypeLayout::readRecord(scratch,
|
|
existentialID);
|
|
|
|
typeOrOffset = ArchetypeType::getOpened(getType(existentialID));
|
|
break;
|
|
}
|
|
|
|
case decls_block::GENERIC_TYPE_PARAM_TYPE: {
|
|
DeclID declIDOrDepth;
|
|
unsigned indexPlusOne;
|
|
|
|
decls_block::GenericTypeParamTypeLayout::readRecord(scratch, declIDOrDepth,
|
|
indexPlusOne);
|
|
|
|
if (indexPlusOne == 0) {
|
|
auto genericParam
|
|
= dyn_cast_or_null<GenericTypeParamDecl>(getDecl(declIDOrDepth));
|
|
|
|
if (!genericParam) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
// See if we triggered deserialization through our conformances.
|
|
if (typeOrOffset.isComplete())
|
|
break;
|
|
|
|
typeOrOffset = genericParam->getDeclaredInterfaceType();
|
|
break;
|
|
}
|
|
|
|
typeOrOffset = GenericTypeParamType::get(declIDOrDepth,indexPlusOne-1,ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::PROTOCOL_COMPOSITION_TYPE: {
|
|
bool hasExplicitAnyObject;
|
|
ArrayRef<uint64_t> rawProtocolIDs;
|
|
|
|
decls_block::ProtocolCompositionTypeLayout::readRecord(scratch,
|
|
hasExplicitAnyObject,
|
|
rawProtocolIDs);
|
|
SmallVector<Type, 4> protocols;
|
|
for (TypeID protoID : rawProtocolIDs)
|
|
protocols.push_back(getType(protoID));
|
|
|
|
typeOrOffset = ProtocolCompositionType::get(ctx, protocols,
|
|
hasExplicitAnyObject);
|
|
break;
|
|
}
|
|
|
|
case decls_block::DEPENDENT_MEMBER_TYPE: {
|
|
TypeID baseID;
|
|
DeclID assocTypeID;
|
|
|
|
decls_block::DependentMemberTypeLayout::readRecord(scratch, baseID,
|
|
assocTypeID);
|
|
typeOrOffset = DependentMemberType::get(
|
|
getType(baseID),
|
|
cast<AssociatedTypeDecl>(getDecl(assocTypeID)));
|
|
break;
|
|
}
|
|
|
|
case decls_block::BOUND_GENERIC_TYPE: {
|
|
DeclID declID;
|
|
TypeID parentID;
|
|
ArrayRef<uint64_t> rawArgumentIDs;
|
|
|
|
decls_block::BoundGenericTypeLayout::readRecord(scratch, declID, parentID,
|
|
rawArgumentIDs);
|
|
|
|
auto nominal = cast<NominalTypeDecl>(getDecl(declID));
|
|
auto parentTy = getType(parentID);
|
|
|
|
SmallVector<Type, 8> genericArgs;
|
|
for (TypeID type : rawArgumentIDs)
|
|
genericArgs.push_back(getType(type));
|
|
|
|
auto boundTy = BoundGenericType::get(nominal, parentTy, genericArgs);
|
|
typeOrOffset = boundTy;
|
|
break;
|
|
}
|
|
|
|
case decls_block::GENERIC_FUNCTION_TYPE: {
|
|
TypeID inputID;
|
|
TypeID resultID;
|
|
uint8_t rawRep;
|
|
bool throws = false;
|
|
ArrayRef<uint64_t> genericParamIDs;
|
|
|
|
decls_block::GenericFunctionTypeLayout::readRecord(scratch,
|
|
inputID,
|
|
resultID,
|
|
rawRep,
|
|
throws,
|
|
genericParamIDs);
|
|
auto rep = getActualFunctionTypeRepresentation(rawRep);
|
|
if (!rep.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
// Read the generic parameters.
|
|
SmallVector<GenericTypeParamType *, 4> genericParams;
|
|
for (auto paramID : genericParamIDs) {
|
|
auto param = dyn_cast_or_null<GenericTypeParamType>(
|
|
getType(paramID).getPointer());
|
|
if (!param) {
|
|
error();
|
|
break;
|
|
}
|
|
|
|
genericParams.push_back(param);
|
|
}
|
|
|
|
// Read the generic requirements.
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
auto info = GenericFunctionType::ExtInfo(*rep, throws);
|
|
|
|
auto sig = GenericSignature::get(genericParams, requirements);
|
|
typeOrOffset = GenericFunctionType::get(sig,
|
|
getType(inputID),
|
|
getType(resultID),
|
|
info);
|
|
break;
|
|
}
|
|
|
|
case decls_block::SIL_BLOCK_STORAGE_TYPE: {
|
|
TypeID captureID;
|
|
|
|
decls_block::SILBlockStorageTypeLayout::readRecord(scratch, captureID);
|
|
typeOrOffset = SILBlockStorageType::get(getType(captureID)
|
|
->getCanonicalType());
|
|
break;
|
|
}
|
|
|
|
case decls_block::SIL_BOX_TYPE: {
|
|
SILLayoutID layoutID;
|
|
|
|
decls_block::SILBoxTypeLayout::readRecord(scratch, layoutID);
|
|
|
|
// Get the layout.
|
|
auto getLayout = [&]() -> SILLayout * {
|
|
assert(layoutID > 0 && layoutID <= SILLayouts.size()
|
|
&& "invalid layout ID");
|
|
|
|
auto &layoutOrOffset = SILLayouts[layoutID - 1];
|
|
if (layoutOrOffset.isComplete()) {
|
|
return layoutOrOffset;
|
|
}
|
|
|
|
BCOffsetRAII saveOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(layoutOrOffset);
|
|
auto layout = readSILLayout(DeclTypeCursor);
|
|
if (!layout) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
layoutOrOffset = layout;
|
|
return layout;
|
|
};
|
|
|
|
auto layout = getLayout();
|
|
if (!layout)
|
|
return nullptr;
|
|
|
|
SmallVector<Substitution, 4> genericArgs;
|
|
if (auto sig = layout->getGenericSignature()) {
|
|
for (unsigned i : range(sig->getSubstitutionListSize())) {
|
|
(void)i;
|
|
auto sub = maybeReadSubstitution(DeclTypeCursor);
|
|
if (!sub) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
genericArgs.push_back(
|
|
Substitution(sub->getReplacement()->getCanonicalType(),
|
|
sub->getConformances()));
|
|
}
|
|
}
|
|
|
|
typeOrOffset = SILBoxType::get(getContext(), layout, genericArgs);
|
|
break;
|
|
}
|
|
|
|
case decls_block::SIL_FUNCTION_TYPE: {
|
|
uint8_t rawCalleeConvention;
|
|
uint8_t rawRepresentation;
|
|
bool pseudogeneric = false;
|
|
bool hasErrorResult;
|
|
unsigned numParams;
|
|
unsigned numResults;
|
|
ArrayRef<uint64_t> variableData;
|
|
|
|
decls_block::SILFunctionTypeLayout::readRecord(scratch,
|
|
rawCalleeConvention,
|
|
rawRepresentation,
|
|
pseudogeneric,
|
|
hasErrorResult,
|
|
numParams,
|
|
numResults,
|
|
variableData);
|
|
|
|
// Process the ExtInfo.
|
|
auto representation
|
|
= getActualSILFunctionTypeRepresentation(rawRepresentation);
|
|
if (!representation.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
SILFunctionType::ExtInfo extInfo(*representation, pseudogeneric);
|
|
|
|
// Process the callee convention.
|
|
auto calleeConvention = getActualParameterConvention(rawCalleeConvention);
|
|
if (!calleeConvention.hasValue()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
auto processParameter = [&](TypeID typeID, uint64_t rawConvention)
|
|
-> Optional<SILParameterInfo> {
|
|
auto convention = getActualParameterConvention(rawConvention);
|
|
auto type = getType(typeID);
|
|
if (!convention || !type) return None;
|
|
return SILParameterInfo(type->getCanonicalType(), *convention);
|
|
};
|
|
|
|
auto processResult = [&](TypeID typeID, uint64_t rawConvention)
|
|
-> Optional<SILResultInfo> {
|
|
auto convention = getActualResultConvention(rawConvention);
|
|
auto type = getType(typeID);
|
|
if (!convention || !type) return None;
|
|
return SILResultInfo(type->getCanonicalType(), *convention);
|
|
};
|
|
|
|
// Bounds check. FIXME: overflow
|
|
if (2 * numParams + 2 * numResults + 2 * unsigned(hasErrorResult)
|
|
> variableData.size()) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
|
|
unsigned nextVariableDataIndex = 0;
|
|
|
|
// Process the parameters.
|
|
SmallVector<SILParameterInfo, 8> allParams;
|
|
allParams.reserve(numParams);
|
|
for (unsigned i = 0; i != numParams; ++i) {
|
|
auto typeID = variableData[nextVariableDataIndex++];
|
|
auto rawConvention = variableData[nextVariableDataIndex++];
|
|
auto param = processParameter(typeID, rawConvention);
|
|
if (!param) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
allParams.push_back(*param);
|
|
}
|
|
|
|
// Process the results.
|
|
SmallVector<SILResultInfo, 8> allResults;
|
|
allParams.reserve(numResults);
|
|
for (unsigned i = 0; i != numResults; ++i) {
|
|
auto typeID = variableData[nextVariableDataIndex++];
|
|
auto rawConvention = variableData[nextVariableDataIndex++];
|
|
auto result = processResult(typeID, rawConvention);
|
|
if (!result) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
allResults.push_back(*result);
|
|
}
|
|
|
|
// Process the error result.
|
|
Optional<SILResultInfo> errorResult;
|
|
if (hasErrorResult) {
|
|
auto typeID = variableData[nextVariableDataIndex++];
|
|
auto rawConvention = variableData[nextVariableDataIndex++];
|
|
errorResult = processResult(typeID, rawConvention);
|
|
if (!errorResult) {
|
|
error();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Process the generic signature parameters.
|
|
SmallVector<GenericTypeParamType *, 8> genericParamTypes;
|
|
for (auto id : variableData.slice(nextVariableDataIndex)) {
|
|
genericParamTypes.push_back(
|
|
cast<GenericTypeParamType>(getType(id)->getCanonicalType()));
|
|
}
|
|
|
|
// Read the generic requirements, if any.
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
GenericSignature *genericSig = nullptr;
|
|
if (!genericParamTypes.empty() || !requirements.empty())
|
|
genericSig = GenericSignature::get(genericParamTypes, requirements,
|
|
/*isKnownCanonical=*/true);
|
|
|
|
typeOrOffset = SILFunctionType::get(genericSig, extInfo,
|
|
calleeConvention.getValue(),
|
|
allParams, allResults, errorResult,
|
|
ctx);
|
|
break;
|
|
}
|
|
|
|
case decls_block::ARRAY_SLICE_TYPE: {
|
|
TypeID baseID;
|
|
decls_block::ArraySliceTypeLayout::readRecord(scratch, baseID);
|
|
|
|
auto sliceTy = ArraySliceType::get(getType(baseID));
|
|
typeOrOffset = sliceTy;
|
|
break;
|
|
}
|
|
|
|
case decls_block::DICTIONARY_TYPE: {
|
|
TypeID keyID, valueID;
|
|
decls_block::DictionaryTypeLayout::readRecord(scratch, keyID, valueID);
|
|
|
|
auto dictTy = DictionaryType::get(getType(keyID), getType(valueID));
|
|
typeOrOffset = dictTy;
|
|
break;
|
|
}
|
|
|
|
case decls_block::OPTIONAL_TYPE: {
|
|
TypeID baseID;
|
|
decls_block::OptionalTypeLayout::readRecord(scratch, baseID);
|
|
|
|
auto optionalTy = OptionalType::get(getType(baseID));
|
|
typeOrOffset = optionalTy;
|
|
break;
|
|
}
|
|
|
|
case decls_block::UNCHECKED_OPTIONAL_TYPE: {
|
|
TypeID baseID;
|
|
decls_block::ImplicitlyUnwrappedOptionalTypeLayout::readRecord(scratch, baseID);
|
|
|
|
auto optionalTy = ImplicitlyUnwrappedOptionalType::get(getType(baseID));
|
|
typeOrOffset = optionalTy;
|
|
break;
|
|
}
|
|
|
|
case decls_block::UNBOUND_GENERIC_TYPE: {
|
|
DeclID genericID;
|
|
TypeID parentID;
|
|
decls_block::UnboundGenericTypeLayout::readRecord(scratch,
|
|
genericID, parentID);
|
|
|
|
auto genericDecl = cast<GenericTypeDecl>(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;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
PrettyStackTraceType trace(ctx, "deserializing", typeOrOffset.get());
|
|
if (typeOrOffset.get()->hasError()) {
|
|
typeOrOffset.get()->dump();
|
|
llvm_unreachable("deserialization produced an invalid type "
|
|
"(rdar://problem/30382791)");
|
|
}
|
|
#endif
|
|
|
|
// Invoke the callback on the deserialized type.
|
|
DeserializedTypeCallback(typeOrOffset);
|
|
|
|
return typeOrOffset;
|
|
}
|
|
|
|
void ModuleFile::loadAllMembers(Decl *container, uint64_t contextData) {
|
|
PrettyStackTraceDecl trace("loading members for", container);
|
|
++NumMemberListsLoaded;
|
|
|
|
IterableDeclContext *IDC;
|
|
if (auto *nominal = dyn_cast<NominalTypeDecl>(container))
|
|
IDC = nominal;
|
|
else
|
|
IDC = cast<ExtensionDecl>(container);
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(contextData);
|
|
auto entry = DeclTypeCursor.advance();
|
|
if (entry.Kind != llvm::BitstreamEntry::Record) {
|
|
error();
|
|
return;
|
|
}
|
|
|
|
SmallVector<uint64_t, 16> memberIDBuffer;
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(entry.ID, memberIDBuffer);
|
|
assert(kind == decls_block::MEMBERS);
|
|
(void)kind;
|
|
|
|
ArrayRef<uint64_t> rawMemberIDs;
|
|
decls_block::MembersLayout::readRecord(memberIDBuffer, rawMemberIDs);
|
|
|
|
if (rawMemberIDs.empty())
|
|
return;
|
|
|
|
SmallVector<Decl *, 16> members;
|
|
members.reserve(rawMemberIDs.size());
|
|
for (DeclID rawID : rawMemberIDs) {
|
|
Expected<Decl *> next = getDeclChecked(rawID);
|
|
if (!next) {
|
|
if (!getContext().LangOpts.EnableDeserializationRecovery)
|
|
fatal(next.takeError());
|
|
|
|
// Drop the member if it had a problem.
|
|
if (auto *containingClass = dyn_cast<ClassDecl>(container)) {
|
|
auto handleMissingDesignatedInit =
|
|
[containingClass](const DeclDeserializationError &error) {
|
|
if (error.getKind() != OverrideError::DesignatedInitializer)
|
|
return;
|
|
containingClass->setHasMissingDesignatedInitializers();
|
|
};
|
|
llvm::handleAllErrors(next.takeError(), handleMissingDesignatedInit);
|
|
} else {
|
|
llvm::consumeError(next.takeError());
|
|
}
|
|
continue;
|
|
}
|
|
assert(next.get() && "unchecked error deserializing next member");
|
|
members.push_back(next.get());
|
|
}
|
|
|
|
for (auto member : members)
|
|
IDC->addMember(member);
|
|
|
|
if (auto *proto = dyn_cast<ProtocolDecl>(container)) {
|
|
PrettyStackTraceDecl trace("reading default witness table for", proto);
|
|
bool Err = readDefaultWitnessTable(proto);
|
|
assert(!Err && "unable to read default witness table");
|
|
(void)Err;
|
|
}
|
|
}
|
|
|
|
void
|
|
ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData,
|
|
SmallVectorImpl<ProtocolConformance*> &conformances) {
|
|
PrettyStackTraceDecl trace("loading conformances for", D);
|
|
|
|
uint64_t numConformances;
|
|
uint64_t bitPosition;
|
|
std::tie(numConformances, bitPosition)
|
|
= decodeLazyConformanceContextData(contextData);
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(bitPosition);
|
|
|
|
while (numConformances--) {
|
|
auto conf = readConformance(DeclTypeCursor);
|
|
if (conf.isConcrete())
|
|
conformances.push_back(conf.getConcrete());
|
|
}
|
|
}
|
|
|
|
TypeLoc
|
|
ModuleFile::loadAssociatedTypeDefault(const swift::AssociatedTypeDecl *ATD,
|
|
uint64_t contextData) {
|
|
return TypeLoc::withoutLoc(getType(contextData));
|
|
}
|
|
|
|
void ModuleFile::finishNormalConformance(NormalProtocolConformance *conformance,
|
|
uint64_t contextData) {
|
|
using namespace decls_block;
|
|
|
|
// Find the conformance record.
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
DeclTypeCursor.JumpToBit(contextData);
|
|
auto entry = DeclTypeCursor.advance();
|
|
assert(entry.Kind == llvm::BitstreamEntry::Record &&
|
|
"registered lazy loader incorrectly");
|
|
|
|
DeclID protoID;
|
|
DeclContextID contextID;
|
|
unsigned valueCount, typeCount;
|
|
ArrayRef<uint64_t> rawIDs;
|
|
SmallVector<uint64_t, 16> scratch;
|
|
|
|
unsigned kind = DeclTypeCursor.readRecord(entry.ID, scratch);
|
|
(void) kind;
|
|
assert(kind == NORMAL_PROTOCOL_CONFORMANCE &&
|
|
"registered lazy loader incorrectly");
|
|
NormalProtocolConformanceLayout::readRecord(scratch, protoID,
|
|
contextID, valueCount,
|
|
typeCount,
|
|
rawIDs);
|
|
|
|
// Skip requirement signature conformances.
|
|
auto proto = conformance->getProtocol();
|
|
for (auto req : proto->getRequirementSignature()->getRequirements()) {
|
|
if (req.getKind() == RequirementKind::Conformance) {
|
|
(void)readConformance(DeclTypeCursor);
|
|
}
|
|
}
|
|
|
|
ArrayRef<uint64_t>::iterator rawIDIter = rawIDs.begin();
|
|
|
|
while (valueCount--) {
|
|
auto req = cast<ValueDecl>(getDecl(*rawIDIter++));
|
|
auto witness = cast_or_null<ValueDecl>(getDecl(*rawIDIter++));
|
|
assert(witness ||
|
|
req->getAttrs().hasAttribute<OptionalAttr>() ||
|
|
req->getAttrs().isUnavailable(getContext()));
|
|
if (!witness) {
|
|
conformance->setWitness(req, Witness());
|
|
continue;
|
|
}
|
|
|
|
// Generic signature and environment.
|
|
GenericSignature *syntheticSig = nullptr;
|
|
GenericEnvironment *syntheticEnv = nullptr;
|
|
|
|
// Requirement -> synthetic map.
|
|
SmallVector<Substitution, 4> reqToSyntheticSubs;
|
|
if (unsigned numGenericParams = *rawIDIter++) {
|
|
// Generic parameters of the synthetic environment.
|
|
SmallVector<GenericTypeParamType *, 2> genericParams;
|
|
while (numGenericParams--) {
|
|
genericParams.push_back(
|
|
getType(*rawIDIter++)->castTo<GenericTypeParamType>());
|
|
}
|
|
|
|
// Generic requirements of the synthetic environment.
|
|
SmallVector<Requirement, 4> requirements;
|
|
readGenericRequirements(requirements, DeclTypeCursor);
|
|
|
|
// Form the generic signature for the synthetic environment.
|
|
syntheticSig = GenericSignature::get(genericParams, requirements);
|
|
|
|
// Create the synthetic environment.
|
|
syntheticEnv =
|
|
syntheticSig->createGenericEnvironment(*getAssociatedModule());
|
|
|
|
// Requirement -> synthetic substitutions.
|
|
if (unsigned numReqSubstitutions = *rawIDIter++) {
|
|
while (numReqSubstitutions--) {
|
|
auto sub = maybeReadSubstitution(DeclTypeCursor, nullptr);
|
|
reqToSyntheticSubs.push_back(*sub);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Witness substitutions.
|
|
SmallVector<Substitution, 4> witnessSubstitutions;
|
|
if (unsigned numWitnessSubstitutions = *rawIDIter++) {
|
|
while (numWitnessSubstitutions--) {
|
|
auto sub = maybeReadSubstitution(DeclTypeCursor, syntheticEnv);
|
|
witnessSubstitutions.push_back(*sub);
|
|
}
|
|
}
|
|
|
|
// Handle simple witnesses.
|
|
if (witnessSubstitutions.empty() && !syntheticSig && !syntheticEnv &&
|
|
reqToSyntheticSubs.empty()) {
|
|
conformance->setWitness(req, Witness(witness));
|
|
continue;
|
|
}
|
|
|
|
// Set the witness.
|
|
conformance->setWitness(req, Witness(witness, witnessSubstitutions,
|
|
syntheticEnv, reqToSyntheticSubs));
|
|
}
|
|
assert(rawIDIter <= rawIDs.end() && "read too much");
|
|
|
|
TypeWitnessMap typeWitnesses;
|
|
while (typeCount--) {
|
|
// FIXME: We don't actually want to allocate an archetype here; we just
|
|
// want to get an access path within the protocol.
|
|
auto first = cast<AssociatedTypeDecl>(getDecl(*rawIDIter++));
|
|
auto second = getType(*rawIDIter++);
|
|
auto third = cast_or_null<TypeDecl>(getDecl(*rawIDIter++));
|
|
if (isa<TypeAliasDecl>(third) &&
|
|
third->getModuleContext() != getAssociatedModule() &&
|
|
!third->getDeclaredInterfaceType()->isEqual(second)) {
|
|
// Conservatively drop references to typealiases in other modules
|
|
// that may have changed. This may also drop references to typealiases
|
|
// that /haven't/ changed but just happen to have generics in them, but
|
|
// in practice having a declaration here isn't actually required by the
|
|
// rest of the compiler.
|
|
third = nullptr;
|
|
}
|
|
typeWitnesses[first] = std::make_pair(second, third);
|
|
}
|
|
assert(rawIDIter <= rawIDs.end() && "read too much");
|
|
|
|
|
|
// Set type witnesses.
|
|
for (auto typeWitness : typeWitnesses) {
|
|
conformance->setTypeWitness(typeWitness.first, typeWitness.second.first,
|
|
typeWitness.second.second);
|
|
}
|
|
}
|
|
|
|
GenericEnvironment *ModuleFile::loadGenericEnvironment(const DeclContext *decl,
|
|
uint64_t contextData) {
|
|
return getGenericEnvironment(contextData);
|
|
}
|
|
|
|
static Optional<ForeignErrorConvention::Kind>
|
|
decodeRawStableForeignErrorConventionKind(uint8_t kind) {
|
|
switch (kind) {
|
|
case static_cast<uint8_t>(ForeignErrorConventionKind::ZeroResult):
|
|
return ForeignErrorConvention::ZeroResult;
|
|
case static_cast<uint8_t>(ForeignErrorConventionKind::NonZeroResult):
|
|
return ForeignErrorConvention::NonZeroResult;
|
|
case static_cast<uint8_t>(ForeignErrorConventionKind::ZeroPreservedResult):
|
|
return ForeignErrorConvention::ZeroPreservedResult;
|
|
case static_cast<uint8_t>(ForeignErrorConventionKind::NilResult):
|
|
return ForeignErrorConvention::NilResult;
|
|
case static_cast<uint8_t>(ForeignErrorConventionKind::NonNilError):
|
|
return ForeignErrorConvention::NonNilError;
|
|
default:
|
|
return None;
|
|
}
|
|
}
|
|
|
|
Optional<ForeignErrorConvention> ModuleFile::maybeReadForeignErrorConvention() {
|
|
using namespace decls_block;
|
|
|
|
SmallVector<uint64_t, 8> scratch;
|
|
|
|
BCOffsetRAII restoreOffset(DeclTypeCursor);
|
|
|
|
auto next = DeclTypeCursor.advance(AF_DontPopBlockAtEnd);
|
|
if (next.Kind != llvm::BitstreamEntry::Record)
|
|
return None;
|
|
|
|
unsigned recKind = DeclTypeCursor.readRecord(next.ID, scratch);
|
|
switch (recKind) {
|
|
case FOREIGN_ERROR_CONVENTION:
|
|
restoreOffset.reset();
|
|
break;
|
|
|
|
default:
|
|
return None;
|
|
}
|
|
|
|
uint8_t rawKind;
|
|
bool isOwned;
|
|
bool isReplaced;
|
|
unsigned errorParameterIndex;
|
|
TypeID errorParameterTypeID;
|
|
TypeID resultTypeID;
|
|
ForeignErrorConventionLayout::readRecord(scratch, rawKind,
|
|
isOwned, isReplaced,
|
|
errorParameterIndex,
|
|
errorParameterTypeID,
|
|
resultTypeID);
|
|
|
|
ForeignErrorConvention::Kind kind;
|
|
if (auto optKind = decodeRawStableForeignErrorConventionKind(rawKind))
|
|
kind = *optKind;
|
|
else {
|
|
error();
|
|
return None;
|
|
}
|
|
|
|
Type errorParameterType = getType(errorParameterTypeID);
|
|
CanType canErrorParameterType;
|
|
if (errorParameterType)
|
|
canErrorParameterType = errorParameterType->getCanonicalType();
|
|
|
|
Type resultType = getType(resultTypeID);
|
|
CanType canResultType;
|
|
if (resultType)
|
|
canResultType = resultType->getCanonicalType();
|
|
|
|
auto owned = isOwned ? ForeignErrorConvention::IsOwned
|
|
: ForeignErrorConvention::IsNotOwned;
|
|
auto replaced = ForeignErrorConvention::IsReplaced_t(isOwned);
|
|
switch (kind) {
|
|
case ForeignErrorConvention::ZeroResult:
|
|
return ForeignErrorConvention::getZeroResult(errorParameterIndex,
|
|
owned, replaced,
|
|
canErrorParameterType,
|
|
canResultType);
|
|
|
|
case ForeignErrorConvention::NonZeroResult:
|
|
return ForeignErrorConvention::getNonZeroResult(errorParameterIndex,
|
|
owned, replaced,
|
|
canErrorParameterType,
|
|
canResultType);
|
|
|
|
case ForeignErrorConvention::ZeroPreservedResult:
|
|
return ForeignErrorConvention::getZeroPreservedResult(errorParameterIndex,
|
|
owned, replaced,
|
|
canErrorParameterType);
|
|
|
|
case ForeignErrorConvention::NilResult:
|
|
return ForeignErrorConvention::getNilResult(errorParameterIndex,
|
|
owned, replaced,
|
|
canErrorParameterType);
|
|
|
|
case ForeignErrorConvention::NonNilError:
|
|
return ForeignErrorConvention::getNonNilError(errorParameterIndex,
|
|
owned, replaced,
|
|
canErrorParameterType);
|
|
}
|
|
|
|
llvm_unreachable("Unhandled ForeignErrorConvention in switch.");
|
|
}
|