blob: 4bf0d3e69db2c19103de52415e3b3b1f3291aa4e [file] [log] [blame]
//===--- Deserialization.cpp - Loading a serialized AST -------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 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 "BCReadingExtras.h"
#include "DeserializationErrors.h"
#include "ModuleFile.h"
#include "ModuleFormat.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/AutoDiff.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/ClangImporter/SwiftAbstractBasicReader.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Basic/Defer.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.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(NumNormalProtocolConformancesLoaded,
"# of normal protocol conformances deserialized");
STATISTIC(NumNormalProtocolConformancesCompleted,
"# of normal protocol conformances completed");
STATISTIC(NumNestedTypeShortcuts,
"# of nested types resolved without full lookup");
using namespace swift;
using namespace swift::serialization;
using llvm::Expected;
StringRef swift::getNameOfModule(const ModuleFile *MF) {
return MF->getName();
}
namespace {
struct DeclAndOffset {
const Decl *D;
uint64_t offset;
};
static raw_ostream &operator<<(raw_ostream &os, DeclAndOffset &&pair) {
return os << Decl::getKindName(pair.D->getKind())
<< "Decl @ " << pair.offset;
}
class PrettyDeclDeserialization : public llvm::PrettyStackTraceEntry {
const ModuleFile *MF;
const ModuleFile::Serialized<Decl*> &DeclOrOffset;
uint64_t offset;
decls_block::RecordKind Kind;
public:
PrettyDeclDeserialization(ModuleFile *module,
const ModuleFile::Serialized<Decl*> &declOrOffset,
decls_block::RecordKind kind)
: MF(module), DeclOrOffset(declOrOffset), offset(declOrOffset),
Kind(kind) {
}
static const char *getRecordKindString(decls_block::RecordKind Kind) {
switch (Kind) {
#define RECORD(Id) case decls_block::Id: return #Id;
#include "DeclTypeRecordNodes.def"
}
llvm_unreachable("Unhandled RecordKind in switch.");
}
void print(raw_ostream &os) const override {
if (!DeclOrOffset.isComplete()) {
os << "While deserializing decl @ " << offset << " ("
<< getRecordKindString(Kind) << ")";
} else {
os << "While deserializing ";
if (auto VD = dyn_cast<ValueDecl>(DeclOrOffset.get())) {
os << "'" << VD->getBaseName() << "' (" << DeclAndOffset{VD, offset}
<< ")";
} else if (auto ED = dyn_cast<ExtensionDecl>(DeclOrOffset.get())) {
os << "extension of '" << ED->getExtendedType() << "' ("
<< DeclAndOffset{ED, offset} << ")";
} else {
os << DeclAndOffset{DeclOrOffset.get(), offset};
}
}
os << " in '" << getNameOfModule(MF) << "'\n";
}
};
class PrettySupplementalDeclNameTrace : public llvm::PrettyStackTraceEntry {
DeclName name;
public:
PrettySupplementalDeclNameTrace(DeclName name)
: name(name) { }
void print(raw_ostream &os) const override {
os << " ...decl is named '" << name << "'\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");
}
};
} // end anonymous namespace
const char DeclDeserializationError::ID = '\0';
void DeclDeserializationError::anchor() {}
const char XRefError::ID = '\0';
void XRefError::anchor() {}
const char XRefNonLoadedModuleError::ID = '\0';
void XRefNonLoadedModuleError::anchor() {}
const char OverrideError::ID = '\0';
void OverrideError::anchor() {}
const char TypeError::ID = '\0';
void TypeError::anchor() {}
const char ExtensionError::ID = '\0';
void ExtensionError::anchor() {}
const char DeclAttributesDidNotMatch::ID = '\0';
void DeclAttributesDidNotMatch::anchor() {}
/// Skips a single record in the bitstream.
///
/// Destroys the stream position if the next entry is not a record.
static void skipRecord(llvm::BitstreamCursor &cursor, unsigned recordKind) {
auto next = llvm::cantFail<llvm::BitstreamEntry>(
cursor.advance(AF_DontPopBlockAtEnd));
assert(next.Kind == llvm::BitstreamEntry::Record);
unsigned kind = llvm::cantFail<unsigned>(cursor.skipRecord(next.ID));
assert(kind == recordKind);
(void)kind;
}
void ModuleFile::fatal(llvm::Error error) {
if (FileContext) {
getContext().Diags.diagnose(SourceLoc(), diag::serialization_fatal, Core->Name);
getContext().Diags.diagnose(SourceLoc(), diag::serialization_misc_version,
Core->Name, Core->MiscVersion);
if (!Core->CompatibilityVersion.empty()) {
if (getContext().LangOpts.EffectiveLanguageVersion
!= Core->CompatibilityVersion) {
SmallString<16> effectiveVersionBuffer, compatVersionBuffer;
{
llvm::raw_svector_ostream out(effectiveVersionBuffer);
out << getContext().LangOpts.EffectiveLanguageVersion;
}
{
llvm::raw_svector_ostream out(compatVersionBuffer);
out << Core->CompatibilityVersion;
}
getContext().Diags.diagnose(
SourceLoc(), diag::serialization_compatibility_version_mismatch,
effectiveVersionBuffer, Core->Name, compatVersionBuffer);
}
}
}
ModuleFileSharedCore::fatal(std::move(error));
}
static Optional<swift::AccessorKind>
getActualAccessorKind(uint8_t raw) {
switch (serialization::AccessorKind(raw)) {
#define ACCESSOR(ID) \
case serialization::AccessorKind::ID: return swift::AccessorKind::ID;
#include "swift/AST/AccessorKinds.def"
}
return None;
}
/// 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)) {
#define CASE(X) \
case serialization::DefaultArgumentKind::X: \
return swift::DefaultArgumentKind::X;
CASE(None)
CASE(Normal)
CASE(Inherited)
CASE(Column)
CASE(FileID)
CASE(FileIDSpelledAsFile)
CASE(FilePath)
CASE(FilePathSpelledAsFile)
CASE(Line)
CASE(Function)
CASE(DSOHandle)
CASE(NilLiteral)
CASE(EmptyArray)
CASE(EmptyDictionary)
CASE(StoredProperty)
#undef CASE
}
return None;
}
static Optional<StableSerializationPath::ExternalPath::ComponentKind>
getActualClangDeclPathComponentKind(uint64_t raw) {
switch (static_cast<serialization::ClangDeclPathComponentKind>(raw)) {
#define CASE(ID) \
case serialization::ClangDeclPathComponentKind::ID: \
return StableSerializationPath::ExternalPath::ID;
CASE(Record)
CASE(Enum)
CASE(Namespace)
CASE(Typedef)
CASE(TypedefAnonDecl)
CASE(ObjCInterface)
CASE(ObjCProtocol)
#undef CASE
}
return None;
}
ParameterList *ModuleFile::readParameterList() {
using namespace decls_block;
SmallVector<uint64_t, 8> scratch;
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
unsigned recordID =
fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, scratch));
assert(recordID == PARAMETERLIST);
(void) recordID;
ArrayRef<uint64_t> rawMemberIDs;
decls_block::ParameterListLayout::readRecord(scratch, rawMemberIDs);
SmallVector<ParamDecl *, 8> params;
for (DeclID paramID : rawMemberIDs)
params.push_back(cast<ParamDecl>(getDecl(paramID)));
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);
llvm::BitstreamEntry next =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (next.Kind != llvm::BitstreamEntry::Record)
fatal();
/// 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 =
fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch));
switch (kind) {
case decls_block::PAREN_PATTERN: {
Pattern *subPattern = readPatternUnchecked(owningDC);
auto result = ParenPattern::createImplicit(getContext(), subPattern);
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;
TuplePatternLayout::readRecord(scratch, tupleTypeID, count);
SmallVector<TuplePatternElt, 8> elements;
for ( ; count > 0; --count) {
scratch.clear();
next = fatalIfUnexpected(DeclTypeCursor.advance());
assert(next.Kind == llvm::BitstreamEntry::Record);
kind = fatalIfUnexpected(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::createImplicit(getContext(), elements);
recordPatternType(result, getType(tupleTypeID));
restoreOffset.reset();
return result;
}
case decls_block::NAMED_PATTERN: {
DeclID varID;
TypeID typeID;
NamedPatternLayout::readRecord(scratch, varID, typeID);
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 = NamedPattern::createImplicit(getContext(), var);
recordPatternType(result, getType(typeID));
restoreOffset.reset();
return result;
}
case decls_block::ANY_PATTERN: {
TypeID typeID;
AnyPatternLayout::readRecord(scratch, typeID);
auto result = AnyPattern::createImplicit(getContext());
recordPatternType(result, getType(typeID));
restoreOffset.reset();
return result;
}
case decls_block::TYPED_PATTERN: {
TypeID typeID;
TypedPatternLayout::readRecord(scratch, typeID);
Expected<Pattern *> subPattern = readPattern(owningDC);
if (!subPattern) {
// Pass through any errors.
return subPattern;
}
auto type = getType(typeID);
auto result = TypedPattern::createImplicit(getContext(),
subPattern.get(), type);
recordPatternType(result, type);
restoreOffset.reset();
return result;
}
case decls_block::VAR_PATTERN: {
bool isLet;
BindingPatternLayout::readRecord(scratch, isLet);
Pattern *subPattern = readPatternUnchecked(owningDC);
auto result =
BindingPattern::createImplicit(getContext(), isLet, subPattern);
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;
llvm::BitstreamEntry next =
fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd));
assert(next.Kind == llvm::BitstreamEntry::Record);
unsigned kind = fatalIfUnexpected(Cursor.readRecord(next.ID, scratch));
switch (kind) {
case decls_block::SIL_LAYOUT: {
GenericSignatureID rawGenericSig;
unsigned numFields;
ArrayRef<uint64_t> types;
decls_block::SILLayoutLayout::readRecord(scratch, rawGenericSig,
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));
}
CanGenericSignature canSig;
if (auto sig = getGenericSignature(rawGenericSig))
canSig = sig.getCanonicalSignature();
return SILLayout::get(getContext(), canSig, fields);
}
default:
fatal();
}
}
ProtocolConformanceRef ModuleFile::readConformance(
llvm::BitstreamCursor &Cursor,
GenericEnvironment *genericEnv) {
auto conformance = readConformanceChecked(Cursor, genericEnv);
if (!conformance)
fatal(conformance.takeError());
return conformance.get();
}
Expected<ProtocolConformanceRef>
ModuleFile::readConformanceChecked(llvm::BitstreamCursor &Cursor,
GenericEnvironment *genericEnv) {
using namespace decls_block;
SmallVector<uint64_t, 16> scratch;
llvm::BitstreamEntry next =
fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd));
assert(next.Kind == llvm::BitstreamEntry::Record);
if (auto *Stats = getContext().Stats)
++Stats->getFrontendCounters().NumConformancesDeserialized;
unsigned kind = fatalIfUnexpected(Cursor.readRecord(next.ID, scratch));
switch (kind) {
case INVALID_PROTOCOL_CONFORMANCE: {
return ProtocolConformanceRef::forInvalid();
}
case ABSTRACT_PROTOCOL_CONFORMANCE: {
DeclID protoID;
AbstractProtocolConformanceLayout::readRecord(scratch, protoID);
auto decl = getDeclChecked(protoID);
if (!decl)
return decl.takeError();
auto proto = cast<ProtocolDecl>(decl.get());
return ProtocolConformanceRef(proto);
}
case SELF_PROTOCOL_CONFORMANCE: {
DeclID protoID;
SelfProtocolConformanceLayout::readRecord(scratch, protoID);
auto decl = getDeclChecked(protoID);
if (!decl)
return decl.takeError();
auto proto = cast<ProtocolDecl>(decl.get());
auto conformance = getContext().getSelfConformance(proto);
return ProtocolConformanceRef(conformance);
}
case SPECIALIZED_PROTOCOL_CONFORMANCE: {
TypeID conformingTypeID;
SubstitutionMapID substitutionMapID;
SpecializedProtocolConformanceLayout::readRecord(scratch, conformingTypeID,
substitutionMapID);
ASTContext &ctx = getContext();
Type conformingType = getType(conformingTypeID);
if (genericEnv) {
conformingType = genericEnv->mapTypeIntoContext(conformingType);
}
PrettyStackTraceType trace(getAssociatedModule()->getASTContext(),
"reading specialized conformance for",
conformingType);
auto subMapOrError = getSubstitutionMapChecked(substitutionMapID);
if (!subMapOrError)
return subMapOrError.takeError();
auto subMap = subMapOrError.get();
ProtocolConformanceRef genericConformance =
readConformance(Cursor, genericEnv);
PrettyStackTraceDecl traceTo("... to", genericConformance.getRequirement());
assert(genericConformance.isConcrete() && "Abstract generic conformance?");
auto conformance =
ctx.getSpecializedConformance(conformingType,
genericConformance.getConcrete(),
subMap);
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);
auto conformance = readNormalConformanceChecked(conformanceID);
if (!conformance)
return conformance.takeError();
return ProtocolConformanceRef(conformance.get());
}
case PROTOCOL_CONFORMANCE_XREF: {
DeclID protoID;
DeclID nominalID;
ModuleID moduleID;
ProtocolConformanceXrefLayout::readRecord(scratch, protoID, nominalID,
moduleID);
auto maybeNominal = getDeclChecked(nominalID);
if (!maybeNominal)
return maybeNominal.takeError();
auto nominal = cast<NominalTypeDecl>(maybeNominal.get());
PrettyStackTraceDecl trace("cross-referencing conformance for", nominal);
auto proto = cast<ProtocolDecl>(getDecl(protoID));
PrettyStackTraceDecl traceTo("... to", proto);
auto module = getModule(moduleID);
// FIXME: If the module hasn't been loaded, we probably don't want to fall
// back to the current module like this.
if (!module)
module = getAssociatedModule();
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:
fatal();
}
}
Expected<NormalProtocolConformance *> ModuleFile::readNormalConformanceChecked(
NormalConformanceID conformanceID) {
auto &conformanceEntry = NormalConformances[conformanceID-1];
if (conformanceEntry.isComplete()) {
return conformanceEntry.get();
}
using namespace decls_block;
// Find the conformance record.
BCOffsetRAII restoreOffset(DeclTypeCursor);
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(conformanceEntry));
llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance());
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
DeclID protoID;
DeclContextID contextID;
unsigned valueCount, typeCount, conformanceCount;
ArrayRef<uint64_t> rawIDs;
SmallVector<uint64_t, 16> scratch;
unsigned kind =
fatalIfUnexpected(DeclTypeCursor.readRecord(entry.ID, scratch));
if (kind != NORMAL_PROTOCOL_CONFORMANCE)
fatal();
NormalProtocolConformanceLayout::readRecord(scratch, protoID,
contextID, typeCount,
valueCount, conformanceCount,
rawIDs);
ASTContext &ctx = getContext();
auto doOrError = getDeclContextChecked(contextID);
if (!doOrError)
return doOrError.takeError();
DeclContext *dc = doOrError.get();
assert(!isa<ClangModuleUnit>(dc->getModuleScopeContext())
&& "should not have serialized a conformance from a clang module");
Type conformingType = dc->getDeclaredInterfaceType();
PrettyStackTraceType trace(ctx, "reading conformance for", conformingType);
auto protoOrError = getDeclChecked(protoID);
if (!protoOrError)
return protoOrError.takeError();
auto proto = cast<ProtocolDecl>(protoOrError.get());
PrettyStackTraceDecl traceTo("... to", proto);
++NumNormalProtocolConformancesLoaded;
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->getSelfNominalTypeDecl()->registerProtocolConformance(conformance);
// If the conformance is complete, we're done.
if (conformance->isComplete())
return conformance;
conformance->setState(ProtocolConformanceState::Complete);
conformance->setLazyLoader(this, offset);
return conformance;
}
GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
using namespace decls_block;
assert(DC && "need a context for the decls in the list");
BCOffsetRAII lastRecordOffset(DeclTypeCursor);
SmallVector<uint64_t, 8> scratch;
StringRef blobData;
llvm::BitstreamEntry next =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (next.Kind != llvm::BitstreamEntry::Record)
return nullptr;
unsigned kind =
fatalIfUnexpected(DeclTypeCursor.readRecord(next.ID, scratch, &blobData));
if (kind != GENERIC_PARAM_LIST)
return nullptr;
lastRecordOffset.reset();
SmallVector<GenericTypeParamDecl *, 8> params;
ArrayRef<uint64_t> paramIDs;
GenericParamListLayout::readRecord(scratch, paramIDs);
for (DeclID nextParamID : paramIDs) {
auto genericParam = cast<GenericTypeParamDecl>(getDecl(nextParamID));
params.push_back(genericParam);
}
// Don't create empty generic parameter lists. (This should never happen in
// practice, but it doesn't hurt to be defensive.)
if (params.empty())
return nullptr;
return GenericParamList::create(getContext(), SourceLoc(),
params, SourceLoc(), { },
SourceLoc());
}
void ModuleFile::readGenericRequirements(
SmallVectorImpl<Requirement> &requirements,
llvm::BitstreamCursor &Cursor) {
auto error = readGenericRequirementsChecked(requirements, Cursor);
if (error)
fatal(std::move(error));
}
llvm::Error ModuleFile::readGenericRequirementsChecked(
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;
llvm::BitstreamEntry entry =
fatalIfUnexpected(Cursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
break;
scratch.clear();
unsigned recordID = fatalIfUnexpected(
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 = getTypeChecked(rawTypeIDs[0]);
if (!subject)
return subject.takeError();
auto constraint = getTypeChecked(rawTypeIDs[1]);
if (!constraint)
return constraint.takeError();
requirements.push_back(Requirement(RequirementKind::Conformance,
subject.get(), constraint.get()));
break;
}
case GenericRequirementKind::Superclass: {
auto subject = getTypeChecked(rawTypeIDs[0]);
if (!subject)
return subject.takeError();
auto constraint = getTypeChecked(rawTypeIDs[1]);
if (!constraint)
return constraint.takeError();
requirements.push_back(Requirement(RequirementKind::Superclass,
subject.get(), constraint.get()));
break;
}
case GenericRequirementKind::SameType: {
auto first = getTypeChecked(rawTypeIDs[0]);
if (!first)
return first.takeError();
auto second = getTypeChecked(rawTypeIDs[1]);
if (!second)
return second.takeError();
requirements.push_back(Requirement(RequirementKind::SameType,
first.get(), second.get()));
break;
}
default:
// Unknown requirement kind.
fatal();
}
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 = getTypeChecked(rawTypeID);
if (!first)
return first.takeError();
LayoutConstraint layout;
LayoutConstraintKind kind = LayoutConstraintKind::UnknownLayout;
switch (rawKind) {
default:
// Unknown layout requirement kind.
fatal();
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.get(), layout));
break;
}
default:
// This record is not part of the GenericParamList.
shouldContinue = false;
break;
}
if (!shouldContinue)
break;
}
return llvm::Error::success();
}
/// Advances past any records that might be part of a requirement signature.
static llvm::Error skipGenericRequirements(llvm::BitstreamCursor &Cursor) {
using namespace decls_block;
BCOffsetRAII lastRecordOffset(Cursor);
while (true) {
Expected<llvm::BitstreamEntry> maybeEntry =
Cursor.advance(AF_DontPopBlockAtEnd);
if (!maybeEntry)
return maybeEntry.takeError();
llvm::BitstreamEntry entry = maybeEntry.get();
if (entry.Kind != llvm::BitstreamEntry::Record)
break;
Expected<unsigned> maybeRecordID = Cursor.skipRecord(entry.ID);
if (!maybeRecordID)
return maybeRecordID.takeError();
switch (maybeRecordID.get()) {
case GENERIC_REQUIREMENT:
case LAYOUT_REQUIREMENT:
break;
default:
// This record is not a generic requirement.
return llvm::Error::success();
}
lastRecordOffset.reset();
}
return llvm::Error::success();
}
GenericSignature ModuleFile::getGenericSignature(
serialization::GenericSignatureID ID) {
auto signature = getGenericSignatureChecked(ID);
if (!signature)
fatal(signature.takeError());
return signature.get();
}
Expected<GenericSignature>
ModuleFile::getGenericSignatureChecked(serialization::GenericSignatureID ID) {
using namespace decls_block;
// Zero is a sentinel for having no generic signature.
if (ID == 0) return nullptr;
assert(ID <= GenericSignatures.size() &&
"invalid GenericSignature ID");
auto &sigOffset = GenericSignatures[ID-1];
// If we've already deserialized this generic signature, return it.
if (sigOffset.isComplete())
return sigOffset.get();
// Read the generic signature.
BCOffsetRAII restoreOffset(DeclTypeCursor);
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(sigOffset));
// Read the parameter types.
SmallVector<GenericTypeParamType *, 4> paramTypes;
StringRef blobData;
SmallVector<uint64_t, 8> scratch;
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
unsigned recordID = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
switch (recordID) {
case GENERIC_SIGNATURE: {
ArrayRef<uint64_t> rawParamIDs;
GenericSignatureLayout::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_SIGNATURE: {
ArrayRef<uint64_t> rawParamIDs;
SILGenericSignatureLayout::readRecord(scratch, rawParamIDs);
if (rawParamIDs.size() % 2 != 0)
fatal();
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:
// Not a generic signature; no way to recover.
fatal();
}
// Read the generic requirements.
SmallVector<Requirement, 4> requirements;
auto error = readGenericRequirementsChecked(requirements, DeclTypeCursor);
if (error)
return std::move(error);
// If we've already deserialized this generic signature, start over to return
// it directly.
// FIXME: Is this kind of re-entrancy actually possible?
if (sigOffset.isComplete())
return getGenericSignature(ID);
// Construct the generic signature from the loaded parameters and
// requirements.
auto signature = GenericSignature::get(paramTypes, requirements);
sigOffset = signature;
return signature;
}
SubstitutionMap ModuleFile::getSubstitutionMap(
serialization::SubstitutionMapID id) {
auto map = getSubstitutionMapChecked(id);
if (!map)
fatal(map.takeError());
return map.get();
}
Expected<SubstitutionMap>
ModuleFile::getSubstitutionMapChecked(serialization::SubstitutionMapID id) {
using namespace decls_block;
// Zero is a sentinel for having an empty substitution map.
if (id == 0) return SubstitutionMap();
assert(id <= SubstitutionMaps.size() && "invalid SubstitutionMap ID");
auto &substitutionsOrOffset = SubstitutionMaps[id-1];
// If we've already deserialized this substitution map, return it.
if (substitutionsOrOffset.isComplete()) {
return substitutionsOrOffset.get();
}
// Read the substitution map.
BCOffsetRAII restoreOffset(DeclTypeCursor);
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(substitutionsOrOffset));
// Read the substitution map.
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
StringRef blobData;
SmallVector<uint64_t, 8> scratch;
unsigned recordID = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
if (recordID != SUBSTITUTION_MAP)
fatal();
GenericSignatureID genericSigID;
uint64_t numConformances;
ArrayRef<uint64_t> replacementTypeIDs;
SubstitutionMapLayout::readRecord(scratch, genericSigID, numConformances,
replacementTypeIDs);
// Generic signature.
auto genericSigOrError = getGenericSignatureChecked(genericSigID);
if (!genericSigOrError)
return genericSigOrError.takeError();
auto genericSig = genericSigOrError.get();
if (!genericSig)
fatal();
// Load the replacement types.
SmallVector<Type, 4> replacementTypes;
replacementTypes.reserve(replacementTypeIDs.size());
for (auto typeID : replacementTypeIDs) {
replacementTypes.push_back(getType(typeID));
}
// Read the conformances.
SmallVector<ProtocolConformanceRef, 4> conformances;
conformances.reserve(numConformances);
for (unsigned i : range(numConformances)) {
(void)i;
auto conformanceOrError = readConformanceChecked(DeclTypeCursor);
if (!conformanceOrError)
return conformanceOrError.takeError();
conformances.push_back(conformanceOrError.get());
}
// Form the substitution map and record it.
auto substitutions =
SubstitutionMap::get(genericSig, ArrayRef<Type>(replacementTypes),
ArrayRef<ProtocolConformanceRef>(conformances));
substitutionsOrOffset = substitutions;
return substitutions;
}
bool ModuleFile::readDefaultWitnessTable(ProtocolDecl *proto) {
using namespace decls_block;
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
return true;
SmallVector<uint64_t, 16> witnessIDBuffer;
unsigned kind =
fatalIfUnexpected(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;
}
static bool isReExportedToModule(const ValueDecl *value,
const ModuleDecl *expectedModule) {
const DeclContext *valueDC = value->getDeclContext();
auto fromClangModule
= dyn_cast<ClangModuleUnit>(valueDC->getModuleScopeContext());
if (!fromClangModule)
return false;
StringRef exportedName = fromClangModule->getExportedModuleName();
auto toClangModule
= dyn_cast<ClangModuleUnit>(expectedModule->getFiles().front());
if (toClangModule)
return exportedName == toClangModule->getExportedModuleName();
return exportedName == expectedModule->getName().str();
}
/// 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 importedFromClang,
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) {
// Ignore anything that was parsed (vs. deserialized), because a serialized
// module cannot refer to it.
if (value->getDeclContext()->getParentSourceFile())
return true;
if (isType != isa<TypeDecl>(value))
return true;
// If we're expecting a type, make sure this decl has the expected type.
if (canTy && !value->getInterfaceType()->isEqual(canTy))
return true;
if (value->isStatic() != isStatic)
return true;
if (value->hasClangNode() != importedFromClang)
return true;
if (value->getAttrs().hasAttribute<ForbidSerializingReferenceAttr>())
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 &&
!isReExportedToModule(value, 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()->getSelfProtocolDecl() &&
(bool)value->getDeclContext()->getExtendedProtocolDecl()
!= 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());
}
static TypeDecl *
findNestedTypeDeclInModule(FileUnit *thisFile, ModuleDecl *extensionModule,
Identifier name, NominalTypeDecl *parent) {
assert(extensionModule && "NULL is not a valid module");
for (FileUnit *file : extensionModule->getFiles()) {
if (file == thisFile)
continue;
if (auto nestedType = file->lookupNestedType(name, parent)) {
return nestedType;
}
}
return nullptr;
}
Expected<Decl *>
ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
using namespace decls_block;
ModuleDecl *baseModule = getModule(MID);
if (!baseModule) {
return llvm::make_error<XRefNonLoadedModuleError>(getIdentifier(MID));
}
assert(baseModule && "missing dependency");
PrettyXRefTrace pathTrace(*baseModule);
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
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 = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
switch (recordID) {
case XREF_TYPE_PATH_PIECE:
case XREF_VALUE_PATH_PIECE: {
IdentifierID IID;
IdentifierID privateDiscriminator = 0;
TypeID TID = 0;
bool isType = (recordID == XREF_TYPE_PATH_PIECE);
bool inProtocolExt = false;
bool importedFromClang = false;
bool isStatic = false;
if (isType)
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
inProtocolExt, importedFromClang);
else
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
importedFromClang, isStatic);
DeclBaseName name = getDeclBaseName(IID);
pathTrace.addValue(name);
if (privateDiscriminator)
pathTrace.addValue(getIdentifier(privateDiscriminator));
Type filterTy;
if (!isType) {
auto maybeType = getTypeChecked(TID);
if (!maybeType) {
// FIXME: Don't throw away the inner error's information.
consumeError(maybeType.takeError());
return llvm::make_error<XRefError>("couldn't decode type",
pathTrace, name);
}
filterTy = maybeType.get();
pathTrace.addType(filterTy);
}
if (privateDiscriminator) {
baseModule->lookupMember(values, baseModule, name,
getIdentifier(privateDiscriminator));
} else {
baseModule->lookupQualified(baseModule, DeclNameRef(name),
NL_QualifiedDefault,
values);
}
filterValues(filterTy, nullptr, nullptr, isType, inProtocolExt,
importedFromClang, isStatic, None, values);
break;
}
case XREF_OPAQUE_RETURN_TYPE_PATH_PIECE: {
IdentifierID DefiningDeclNameID;
XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, DefiningDeclNameID);
auto name = getIdentifier(DefiningDeclNameID);
pathTrace.addOpaqueReturnType(name);
if (auto opaque = baseModule->lookupOpaqueResultType(name.str())) {
values.push_back(opaque);
}
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);
auto &ctx = getContext();
auto desc = OperatorLookupDescriptor::forModule(baseModule, opName);
switch (rawOpKind) {
case OperatorKind::Infix:
case OperatorKind::Prefix:
case OperatorKind::Postfix: {
auto req = DirectOperatorLookupRequest{
desc, getASTOperatorFixity(static_cast<OperatorKind>(rawOpKind))};
auto results = evaluateOrDefault(ctx.evaluator, req, {});
if (results.size() != 1) {
return llvm::make_error<XRefError>("operator not found", pathTrace,
opName);
}
return results[0];
}
case OperatorKind::PrecedenceGroup: {
auto results = evaluateOrDefault(
ctx.evaluator, DirectPrecedenceGroupLookupRequest{desc}, {});
if (results.size() != 1) {
return llvm::make_error<XRefError>("precedencegroup not found",
pathTrace, opName);
}
return results[0];
}
default:
// Unknown operator kind.
fatal();
}
llvm_unreachable("Unhandled case in switch!");
}
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);
fatal();
}
auto getXRefDeclNameForError = [&]() -> DeclName {
DeclName result = pathTrace.getLastName();
while (--pathLen) {
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
return Identifier();
scratch.clear();
unsigned recordID = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
IdentifierID IID;
XRefTypePathPieceLayout::readRecord(scratch, IID, None, None, None);
result = getIdentifier(IID);
break;
}
case XREF_VALUE_PATH_PIECE: {
IdentifierID IID;
XRefValuePathPieceLayout::readRecord(scratch, None, IID, None, None,
None);
result = getIdentifier(IID);
break;
}
case XREF_OPAQUE_RETURN_TYPE_PATH_PIECE: {
IdentifierID IID;
XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, IID);
auto mangledName = getIdentifier(IID);
SmallString<64> buf;
{
llvm::raw_svector_ostream os(buf);
os << "<<opaque return type of ";
os << mangledName.str();
os << ">>";
}
result = getContext().getIdentifier(buf);
break;
}
case XREF_INITIALIZER_PATH_PIECE:
result = DeclBaseName::createConstructor();
break;
case XREF_EXTENSION_PATH_PIECE:
case XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE:
break;
case XREF_GENERIC_PARAM_PATH_PIECE:
// Can't get the name without deserializing.
result = Identifier();
break;
default:
// Unknown encoding.
return Identifier();
}
}
return result;
};
if (values.empty()) {
return llvm::make_error<XRefError>("top-level value not found", pathTrace,
getXRefDeclNameForError());
}
// Filters for values discovered in the remaining path pieces.
ModuleDecl *M = nullptr;
CanGenericSignature genericSig = CanGenericSignature();
// For remaining path pieces, filter or drill down into the results we have.
while (--pathLen) {
llvm::BitstreamEntry entry =
fatalIfUnexpected(DeclTypeCursor.advance(AF_DontPopBlockAtEnd));
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
scratch.clear();
unsigned recordID = fatalIfUnexpected(
DeclTypeCursor.readRecord(entry.ID, scratch, &blobData));
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
if (values.size() == 1 && isa<NominalTypeDecl>(values.front())) {
// Fast path for nested types that avoids deserializing all
// members of the parent type.
IdentifierID IID;
IdentifierID privateDiscriminator;
bool importedFromClang = false;
bool inProtocolExt = false;
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
inProtocolExt, importedFromClang);
if (privateDiscriminator)
goto giveUpFastPath;
Identifier memberName = getIdentifier(IID);
pathTrace.addValue(memberName);
auto *baseType = cast<NominalTypeDecl>(values.front());
ModuleDecl *extensionModule = M;
if (!extensionModule)
extensionModule = baseType->getModuleContext();
// Fault in extensions, then ask every file in the module.
(void)baseType->getExtensions();
auto *nestedType =
findNestedTypeDeclInModule(getFile(), extensionModule,
memberName, baseType);
// For clang module units, also search tables in the overlays.
if (!nestedType) {
if (auto LF =
dyn_cast<LoadedFile>(baseType->getModuleScopeContext())) {
if (auto overlayModule = LF->getOverlayModule()) {
nestedType = findNestedTypeDeclInModule(getFile(), overlayModule,
memberName, baseType);
} else if (LF->getParentModule() != extensionModule) {
nestedType = findNestedTypeDeclInModule(getFile(),
LF->getParentModule(),
memberName, baseType);
}
}
}
if (nestedType) {
SmallVector<ValueDecl *, 1> singleValueBuffer{nestedType};
filterValues(/*expectedTy*/Type(), extensionModule, genericSig,
/*isType*/true, inProtocolExt, importedFromClang,
/*isStatic*/false, /*ctorInit*/None, singleValueBuffer);
if (!singleValueBuffer.empty()) {
values.assign({nestedType});
++NumNestedTypeShortcuts;
break;
}
}
pathTrace.removeLast();
}
giveUpFastPath:
LLVM_FALLTHROUGH;
}
case XREF_VALUE_PATH_PIECE:
case XREF_INITIALIZER_PATH_PIECE: {
TypeID TID = 0;
DeclBaseName memberName;
Identifier privateDiscriminator;
Optional<swift::CtorInitializerKind> ctorInit;
bool isType = false;
bool inProtocolExt = false;
bool importedFromClang = false;
bool isStatic = false;
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
IdentifierID IID, discriminatorID;
XRefTypePathPieceLayout::readRecord(scratch, IID, discriminatorID,
inProtocolExt, importedFromClang);
memberName = getDeclBaseName(IID);
privateDiscriminator = getIdentifier(discriminatorID);
isType = true;
break;
}
case XREF_VALUE_PATH_PIECE: {
IdentifierID IID;
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
importedFromClang, isStatic);
memberName = getDeclBaseName(IID);
break;
}
case XREF_INITIALIZER_PATH_PIECE: {
uint8_t kind;
XRefInitializerPathPieceLayout::readRecord(scratch, TID, inProtocolExt,
importedFromClang, kind);
memberName = DeclBaseName::createConstructor();
ctorInit = getActualCtorInitializerKind(kind);
break;
}
default:
llvm_unreachable("Unhandled path piece");
}
pathTrace.addValue(memberName);
if (!privateDiscriminator.empty())
pathTrace.addPrivateDiscriminator(privateDiscriminator);
Type filterTy;
if (!isType) {
auto maybeType = getTypeChecked(TID);
if (!maybeType) {
// FIXME: Don't throw away the inner error's information.
consumeError(maybeType.takeError());
return llvm::make_error<XRefError>("couldn't decode type",
pathTrace, memberName);
}
filterTy = maybeType.get();
pathTrace.addType(filterTy);
}
if (values.size() != 1) {
return llvm::make_error<XRefError>("multiple matching base values",
pathTrace,
getXRefDeclNameForError());
}
auto nominal = dyn_cast<NominalTypeDecl>(values.front());
values.clear();
if (!nominal) {
return llvm::make_error<XRefError>("base is not a nominal type",
pathTrace,
getXRefDeclNameForError());
}
if (memberName.getKind() == DeclBaseName::Kind::Destructor) {
assert(isa<ClassDecl>(nominal));
// Force creation of an implicit destructor
auto CD = dyn_cast<ClassDecl>(nominal);
values.push_back(CD->getDestructor());
break;
}
if (!privateDiscriminator.empty()) {
ModuleDecl *searchModule = M;
if (!searchModule)
searchModule = nominal->getModuleContext();
searchModule->lookupMember(values, nominal, memberName,
privateDiscriminator);
} else {
auto members = nominal->lookupDirect(memberName);
values.append(members.begin(), members.end());
}
filterValues(filterTy, M, genericSig, isType, inProtocolExt,
importedFromClang, isStatic, ctorInit, values);
break;
}
case XREF_EXTENSION_PATH_PIECE: {
ModuleID ownerID;
GenericSignatureID rawGenericSig;
XRefExtensionPathPieceLayout::readRecord(scratch, ownerID, rawGenericSig);
M = getModule(ownerID);
if (!M) {
return llvm::make_error<XRefError>("module is not loaded",
pathTrace, getIdentifier(ownerID));
}
pathTrace.addExtension(M);
// Read the generic signature, if we have one.
genericSig = CanGenericSignature(getGenericSignature(rawGenericSig));
continue;
}
case XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE: {
uint8_t rawKind;
XRefOperatorOrAccessorPathPieceLayout::readRecord(scratch, None,
rawKind);
if (values.empty())
break;
if (!values.front()->getBaseName().isOperator()) {
pathTrace.addAccessor(rawKind);
if (auto storage = dyn_cast<AbstractStorageDecl>(values.front())) {
auto actualKind = getActualAccessorKind(rawKind);
if (!actualKind) {
// Unknown accessor kind.
fatal();
}
values.front() = storage->getAccessor(*actualKind);
if (!values.front()) {
return llvm::make_error<XRefError>("missing accessor",
pathTrace,
getXRefDeclNameForError());
}
}
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()->getFixity()) != 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,
getXRefDeclNameForError());
}
uint32_t depth, paramIndex;
XRefGenericParamPathPieceLayout::readRecord(scratch, depth, paramIndex);
pathTrace.addGenericParam(paramIndex);
ValueDecl *base = values.front();
GenericSignature currentSig;
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) {
currentSig = ext->getGenericSignature();
break;
}
}
assert(currentSig && "Couldn't find constrained extension");
} else {
// Simple case: use the nominal type's generic parameters.
currentSig = nominal->getGenericSignature();
}
} else if (auto alias = dyn_cast<TypeAliasDecl>(base)) {
currentSig = alias->getGenericSignature();
} else if (auto fn = dyn_cast<AbstractFunctionDecl>(base)) {
currentSig = fn->getGenericSignature();
} else if (auto subscript = dyn_cast<SubscriptDecl>(base)) {
currentSig = subscript->getGenericSignature();
} else if (auto opaque = dyn_cast<OpaqueTypeDecl>(base)) {
currentSig = opaque->getGenericSignature();
}
if (!currentSig) {
return llvm::make_error<XRefError>(
"cross-reference to generic param for non-generic type",
pathTrace, getXRefDeclNameForError());
}
bool found = false;
for (auto paramTy : currentSig->getGenericParams()) {
if (paramTy->getIndex() == paramIndex &&
paramTy->getDepth() == depth) {
values.clear();
values.push_back(paramTy->getDecl());
found = true;
break;
}
}
if (!found) {
return llvm::make_error<XRefError>(
"invalid generic argument index or depth",
pathTrace, getXRefDeclNameForError());
}
break;
}
case XREF_OPAQUE_RETURN_TYPE_PATH_PIECE: {
values.clear();
IdentifierID DefiningDeclNameID;
XRefOpaqueReturnTypePathPieceLayout::readRecord(scratch, DefiningDeclNameID);
auto name = getIdentifier(DefiningDeclNameID);
pathTrace.addOpaqueReturnType(name);
auto lookupModule = M ? M : baseModule;
if (auto opaqueTy = lookupModule->lookupOpaqueResultType(name.str())) {
values.push_back(opaqueTy);
}
break;
}
default:
// Unknown xref path piece.
pathTrace.addUnknown(recordID);
fatal();
}
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,
getXRefDeclNameForError());
}
// 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)
fatal();
// When all is said and done, we should have a single value here to return.
if (values.size() != 1) {
return llvm::make_error<XRefError>("result is ambiguous", pathTrace,
getXRefDeclNameForError());
}
assert(values.front() != nullptr);
return values.front();
}
DeclBaseName ModuleFile::getDeclBaseName(IdentifierID IID) {
if (IID == 0)
return Identifier();
if (IID < NUM_SPECIAL_IDS) {
switch (static_cast<SpecialIdentifierID>(static_cast<uint8_t>(IID))) {
case BUILTIN_MODULE_ID:
case CURRENT_MODULE_ID:
case OBJC_HEADER_MODULE_ID:
llvm_unreachable("Cannot get DeclBaseName of special module id");
case SUBSCRIPT_ID:
return DeclBaseName::createSubscript();
case serialization::CONSTRUCTOR_ID:
return DeclBaseName::createConstructor();
case serialization::DESTRUCTOR_ID:
return DeclBaseName::createDestructor();
case NUM_SPECIAL_IDS:
llvm_unreachable("implementation detail only");
}
}
size_t rawID = IID - NUM_SPECIAL_IDS;
assert(rawID < Identifiers.size() && "invalid identifier ID");
auto &identRecord = Identifiers[rawID];
if (identRecord.Ident.empty()) {
StringRef text = getIdentifierText(IID);
identRecord.Ident = getContext().getIdentifier(text);
}
return identRecord.Ident;
}
Identifier ModuleFile::getIdentifier(IdentifierID IID) {
auto name = getDeclBaseName(IID);
assert(!name.isSpecial());
return name.getIdentifier();
}
StringRef ModuleFile::getIdentifierText(IdentifierID IID) {
if (IID == 0)
return StringRef();
assert(IID >= NUM_SPECIAL_IDS);
size_t rawID = IID - NUM_SPECIAL_IDS;
assert(rawID < Identifiers.size() && "invalid identifier ID");
auto identRecord = Identifiers[rawID];
if (!identRecord.Ident.empty())
return identRecord.Ident.str();
return Core->getIdentifierText(IID);
}
DeclContext *ModuleFile::getLocalDeclContext(LocalDeclContextID DCID) {
assert(DCID != 0 && "invalid local DeclContext ID 0");
auto &declContextOrOffset = LocalDeclContexts[DCID-1];
if (declContextOrOffset.isComplete())
return declContextOrOffset;
BCOffsetRAII restoreOffset(DeclTypeCursor);
fatalIfNotSuccess(DeclTypeCursor.JumpToBit(declContextOrOffset));
llvm::BitstreamEntry entry = fatalIfUnexpected(DeclTypeCursor.advance());
if (entry.Kind != llvm::BitstreamEntry::Record)
fatal();
ASTContext &ctx = getContext();
SmallVector<uint64_t, 64> scratch;
StringRef blobData;
unsigned recordID = fatalIfUnexpected(
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);
if (!blobData.empty())
binding->setInitStringRepresentation(bindingIndex, blobData);
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) {
auto deserialized = getDeclContextChecked(DCID);
if (!deserialized) {
fatal(deserialized.takeError());
}
return deserialized.get();
}
Expected<DeclContext *> ModuleFile::getDeclContextChecked(DeclContextID DCID) {
if (!DCID)
return FileContext;
if (Optional<LocalDeclContextID> contextID = DCID.getAsLocalDeclContextID())
return getLocalDeclContext(contextID.getValue());
auto deserialized = getDeclChecked(DCID.getAsDeclID().getValue());
if (!deserialized)
return deserialized.takeError();
auto D = deserialized.get();
if (auto GTD = dyn_cast<GenericTypeDecl>(D))
return GTD;
if (auto ED = dyn_cast<ExtensionDecl>(D))
return ED;
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D))
return AFD;
if (auto SD = dyn_cast<SubscriptDecl>(D))
return SD;
if (auto EED = dyn_cast<EnumElementDecl>(D))
return EED;
llvm_unreachable("Unknown Decl : DeclContext kind");
}
ModuleDecl *ModuleFile::getModule(ModuleID MID) {
if (MID < NUM_SPECIAL_IDS) {
switch (static_cast<SpecialIdentifierID>(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 SUBSCRIPT_ID:
case CONSTRUCTOR_ID:
case DESTRUCTOR_ID:
llvm_unreachable("Modules cannot be named with special names");
case NUM_SPECIAL_IDS:
llvm_unreachable("implementation detail only");
}
}
return getModule(ImportPath::Module::Builder(getIdentifier(MID)).get(),
getContext().LangOpts.AllowDeserializingImplementationOnly);
}
ModuleDecl *ModuleFile::getModule(ImportPath::Module name,
bool allowLoading) {
if (name.empty() || name.front().Item.empty())
return getContext().TheBuiltinModule;
// FIXME: duplicated from ImportResolver::getModule
if (name.size() == 1 &&
name.front().Item == FileContext->getParentModule()->getName()) {
if (!UnderlyingModule && allowLoading) {
auto importer = getContext().getClangModuleLoader();
assert(importer && "no way to import shadowed module");
UnderlyingModule =
importer->loadModule(SourceLoc(), name.getTopLevelPath());
}
return UnderlyingModule;
}
if (allowLoading)
return getContext().getModule(name);
return getContext().getLoadedModule(name);
}
/// 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 "DeclTypeRecordNodes.def"
default: return false;
}
}
static Optional<swift::AccessLevel> getActualAccessLevel(uint8_t raw) {
switch (serialization::AccessLevel(raw)) {
#define CASE(NAME) \
case serialization::AccessLevel::NAME: \
return swift::AccessLevel::NAME;
CASE(Private)
CASE(FilePrivate)
CASE(Internal)
CASE(Public)
CASE(Open)
#undef CASE
}
return None;
}
static Optional<swift::SelfAccessKind>
getActualSelfAccessKind(uint8_t raw) {
switch (serialization::SelfAccessKind(raw)) {
case serialization::SelfAccessKind::NonMutating:
return swift::SelfAccessKind::NonMutating;
case serialization::SelfAccessKind::Mutating:
return swift::SelfAccessKind::Mutating;
case serialization::SelfAccessKind::Consuming:
return swift::SelfAccessKind::Consuming;
}
return None;
}
/// Translate from the serialization VarDeclSpecifier enumerators, which are
/// guaranteed to be stable, to the AST ones.
static Optional<swift::ParamDecl::Specifier>
getActualParamDeclSpecifier(serialization::ParamDeclSpecifier raw) {
switch (raw) {
#define CASE(ID) \
case serialization::ParamDeclSpecifier::ID: \
return swift::ParamDecl::Specifier::ID;
CASE(Default)
CASE(InOut)
CASE(Shared)
CASE(Owned)
}
#undef CASE
return None;
}
static Optional<swift::VarDecl::Introducer>
getActualVarDeclIntroducer(serialization::VarDeclIntroducer raw) {
switch (raw) {
#define CASE(ID) \
case serialization::VarDeclIntroducer::ID: \
return swift::VarDecl::Introducer::ID;
CASE(Let)
CASE(Var)
}
#undef CASE
return None;
}
static Optional<swift::OpaqueReadOwnership>
getActualOpaqueReadOwnership(unsigned rawKind) {
switch (serialization::OpaqueReadOwnership(rawKind)) {
#define CASE(KIND) \
case serialization::OpaqueReadOwnership::KIND: \
return swift::OpaqueReadOwnership::KIND;
CASE(Owned)
CASE(Borrowed)
CASE(OwnedOrBorrowed)
#undef CASE
}
return None;
}
static Optional<swift::ReadImplKind>
getActualReadImplKind(unsigned rawKind) {
switch (serialization::ReadImplKind(rawKind)) {
#define CASE(KIND) \
case serialization::ReadImplKind::KIND: \
return swift::ReadImplKind::KIND;
CASE(Stored)
CASE(Get)
CASE(Inherited)
CASE(Address)
CASE(Read)
#undef CASE
}
return None;
}
static Optional<swift::WriteImplKind>
getActualWriteImplKind(unsigned rawKind) {
switch (serialization::WriteImplKind(rawKind)) {
#define CASE(KIND) \
case serialization::WriteImplKind::KIND: \
return swift::WriteImplKind::KIND;
CASE(Immutable)
CASE(Stored)
CASE(Set)
CASE(StoredWithObservers)
CASE(InheritedWithObservers)
CASE(MutableAddress)
CASE(Modify)
#undef CASE
}
return None;
}
static Optional<swift::ReadWriteImplKind>
getActualReadWriteImplKind(unsigned rawKind) {
switch (serialization::ReadWriteImplKind(rawKind)) {
#define CASE(KIND) \
case serialization::ReadWriteImplKind::KIND: \
return swift::ReadWriteImplKind::KIND;
CASE(Immutable)
CASE(Stored)
CASE(MutableAddress)
CASE(MaterializeToTemporary)
CASE(Modify)
CASE(StoredWithDidSet)
CASE(InheritedWithDidSet)
#undef CASE
}
return None;
}
/// Translate from the serialization DifferentiabilityKind enumerators, which
/// are guaranteed to be stable, to the AST ones.
static Optional<swift::AutoDiffDerivativeFunctionKind>
getActualAutoDiffDerivativeFunctionKind(uint8_t raw) {
switch (serialization::AutoDiffDerivativeFunctionKind(raw)) {
#define CASE(ID) \
case serialization::AutoDiffDerivativeFunctionKind::ID: \
return {swift::AutoDiffDerivativeFunctionKind::ID};
CASE(JVP)
CASE(VJP)
#undef CASE
}
return None;
}
void ModuleFile::configureStorage(AbstractStorageDecl *decl,
uint8_t rawOpaqueReadOwnership,
uint8_t rawReadImplKind,
uint8_t rawWriteImplKind,
uint8_t rawReadWriteImplKind,
AccessorRecord &rawIDs) {
auto opaqueReadOwnership =
getActualOpaqueReadOwnership(rawOpaqueReadOwnership);
if (!opaqueReadOwnership)
return;
decl->setOpaqueReadOwnership(*opaqueReadOwnership);
auto readImpl = getActualReadImplKind(rawReadImplKind);
if (!readImpl) return;
auto writeImpl = getActualWriteImplKind(rawWriteImplKind);
if (!writeImpl) return;
auto readWriteImpl = getActualReadWriteImplKind(rawReadWriteImplKind);
if (!readWriteImpl) return;
SmallVector<AccessorDecl*, 8> accessors;
for (DeclID id : rawIDs.IDs) {
auto accessor = dyn_cast_or_null<AccessorDecl>(getDecl(id));
if (!accessor) return;
accessors.push_back(accessor);
}
auto implInfo = StorageImplInfo(*readImpl, *writeImpl, *readWriteImpl);
decl->setImplInfo(implInfo);
if (implInfo.isSimpleStored() && accessors.empty())
return;
// We currently don't serialize these locations.
SourceLoc beginLoc, endLoc;
decl->setAccessors(beginLoc, accessors, endLoc);
}
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");
return new (getContext()) T(std::forward<Args>(args)...);
}
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;
}
template <typename DERIVED>
static bool attributeChainContains(DeclAttribute *attr) {
DeclAttributes tempAttrs;
tempAttrs.setRawAttributeChain(attr);
static_assert(std::is_trivially_destructible<DeclAttributes>::value,
"must not try to destroy the attribute chain");
return tempAttrs.hasAttribute<DERIVED>();
}
// Set original declaration and parameter indices in `@differentiable`
// attributes.
//
// Serializing/deserializing the original declaration DeclID in
// `@differentiable` attributes does not work because it causes
// `@differentiable` attribute deserialization to enter an infinite loop.
//
// Instead, call this ad-hoc function after deserializing a declaration to set
// the original declaration and parameter indices for its `@differentiable`
// attributes.
static void setOriginalDeclarationAndParameterIndicesInDifferentiableAttributes(
Decl *decl, DeclAttribute *attrs,
llvm::DenseMap<DifferentiableAttr *, IndexSubset *>
&diffAttrParamIndicesMap) {
DeclAttributes tempAttrs;
tempAttrs.setRawAttributeChain(attrs);
for (auto *attr : tempAttrs.getAttributes<DifferentiableAttr>()) {
auto *diffAttr = const_cast<DifferentiableAttr *>(attr);
diffAttr->setOriginalDeclaration(decl);
diffAttr->setParameterIndices(diffAttrParamIndicesMap[diffAttr]);
}
}
Decl *ModuleFile::getDecl(DeclID DID) {
Expected<Decl *> deserialized = getDeclChecked(DID);
if (!deserialized) {
fatal(deserialized.takeError());
}
return deserialized.get();
}
/// Used to split up methods that would otherwise live in ModuleFile.
namespace swift {
class DeclDeserializer {
template <typename T>
using Serialized = ModuleFile::Serialized<T>;
using TypeID = serialization::TypeID;
ModuleFile &MF;
ASTContext &ctx;
Serialized<Decl *> &declOrOffset;
DeclAttribute *DAttrs = nullptr;
DeclAttribute **AttrsNext = &DAttrs;
Identifier privateDiscriminator;
unsigned localDiscriminator = 0;
StringRef filenameForPrivate;
// Auxiliary map for deserializing `@differentiable` attributes.
llvm::DenseMap<DifferentiableAttr *, IndexSubset *> diffAttrParamIndicesMap;
void AddAttribute(DeclAttribute *Attr) {
// Advance the linked list.
// This isn't just using DeclAttributes because that would result in the
// attributes getting reversed.
// FIXME: If we reverse them at serialization time we could get rid of this.
*AttrsNext = Attr;
AttrsNext = Attr->getMutableNext();
};
void handleInherited(llvm::PointerUnion<TypeDecl *, ExtensionDecl *> decl,
ArrayRef<uint64_t> rawInheritedIDs) {
SmallVector<TypeLoc, 2> inheritedTypes;
for (auto rawID : rawInheritedIDs) {
auto maybeType = MF.getTypeChecked(rawID);
if (!maybeType) {
llvm::consumeError(maybeType.takeError());
continue;
}
inheritedTypes.push_back(TypeLoc::withoutLoc(MF.getType(rawID)));
}
auto inherited = ctx.AllocateCopy(inheritedTypes);
if (auto *typeDecl = decl.dyn_cast<TypeDecl *>())
typeDecl->setInherited(inherited);
else
decl.get<ExtensionDecl *>()->setInherited(inherited);
}
public:
DeclDeserializer(ModuleFile &MF, Serialized<Decl *> &declOrOffset)
: MF(MF), ctx(MF.getContext()), declOrOffset(declOrOffset) {}
~DeclDeserializer() {
if (!declOrOffset.isComplete()) {
// We failed to deserialize this declaration.
return;
}
Decl *decl = declOrOffset.get();
if (!decl)
return;
if (DAttrs)
decl->getAttrs().setRawAttributeChain(DAttrs);
if (auto value = dyn_cast<ValueDecl>(decl)) {
if (!privateDiscriminator.empty())
MF.PrivateDiscriminatorsByValue[value] = privateDiscriminator;
if (localDiscriminator != 0)
value->setLocalDiscriminator(localDiscriminator);
if (!filenameForPrivate.empty())
MF.FilenamesForPrivateValues[value] = filenameForPrivate;
}
}
/// Deserializes decl attribute and attribute-like records from
/// \c MF.DeclTypesCursor until a non-attribute record is found,
/// passing each one to AddAttribute.
llvm::Error deserializeDeclAttributes();
Expected<Decl *> getDeclCheckedImpl(
llvm::function_ref<bool(DeclAttributes)> matchAttributes = nullptr);
Expected<Decl *> deserializeTypeAlias(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID nameID;
DeclContextID contextID;
TypeID underlyingTypeID, interfaceTypeID;
bool isImplicit;
GenericSignatureID genericSigID;
uint8_t rawAccessLevel;
ArrayRef<uint64_t> dependencyIDs;
decls_block::TypeAliasLayout::readRecord(scratch, nameID, contextID,
underlyingTypeID, interfaceTypeID,
isImplicit, genericSigID,
rawAccessLevel, dependencyIDs);
Identifier name = MF.getIdentifier(nameID);
PrettySupplementalDeclNameTrace trace(name);
for (TypeID dependencyID : dependencyIDs) {
auto dependency = MF.getTypeChecked(dependencyID);
if (!dependency) {
return llvm::make_error<TypeError>(
name, takeErrorInfo(dependency.takeError()));
}
}
auto DC = MF.getDeclContext(contextID);
auto genericParams = MF.maybeReadGenericParams(DC);
if (declOrOffset.isComplete())
return declOrOffset;
auto alias = MF.createDecl<TypeAliasDecl>(SourceLoc(), SourceLoc(), name,
SourceLoc(), genericParams, DC);
declOrOffset = alias;
auto genericSig = MF.getGenericSignature(genericSigID);
alias->setGenericSignature(genericSig);
auto underlying = MF.getType(underlyingTypeID);
alias->setUnderlyingType(underlying);
if (auto accessLevel = getActualAccessLevel(rawAccessLevel))
alias->setAccess(*accessLevel);
else
MF.fatal();
if (isImplicit)
alias->setImplicit();
return alias;
}
Expected<Decl *>
deserializeGenericTypeParamDecl(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID nameID;
bool isImplicit;
unsigned depth;
unsigned index;
decls_block::GenericTypeParamDeclLayout::readRecord(scratch, nameID,
isImplicit,
depth,
index);
// Always create GenericTypeParamDecls in the associated file; the real
// context will reparent them.
auto *DC = MF.getFile();
auto genericParam = MF.createDecl<GenericTypeParamDecl>(
DC, MF.getIdentifier(nameID), SourceLoc(), depth, index);
declOrOffset = genericParam;
if (isImplicit)
genericParam->setImplicit();
return genericParam;
}
Expected<Decl *>
deserializeAssociatedTypeDecl(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID nameID;
DeclContextID contextID;
TypeID defaultDefinitionID;
bool isImplicit;
ArrayRef<uint64_t> rawOverriddenIDs;
decls_block::AssociatedTypeDeclLayout::readRecord(scratch, nameID,
contextID,
defaultDefinitionID,
isImplicit,
rawOverriddenIDs);
auto DC = MF.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 = MF.createDecl<AssociatedTypeDecl>(
DC, SourceLoc(), MF.getIdentifier(nameID), SourceLoc(), trailingWhere,
&MF, defaultDefinitionID);
declOrOffset = assocType;
assert(!assocType->getDeclaredInterfaceType()->hasError() &&
"erroneous associated type");
AccessLevel parentAccess = cast<ProtocolDecl>(DC)->getFormalAccess();
assocType->setAccess(std::max(parentAccess, AccessLevel::Internal));
if (isImplicit)
assocType->setImplicit();
// Overridden associated types.
SmallVector<ValueDecl *, 2> overriddenAssocTypes;
for (auto overriddenID : rawOverriddenIDs) {
if (auto overriddenAssocType =
dyn_cast_or_null<AssociatedTypeDecl>(MF.getDecl(overriddenID))) {
overriddenAssocTypes.push_back(overriddenAssocType);
}
}
assocType->setOverriddenDecls(overriddenAssocTypes);
return assocType;
}
Expected<Decl *> deserializeStruct(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID nameID;
DeclContextID contextID;
bool isImplicit;
bool isObjC;
GenericSignatureID genericSigID;
uint8_t rawAccessLevel;
unsigned numConformances, numInheritedTypes;
ArrayRef<uint64_t> rawInheritedAndDependencyIDs;
decls_block::StructLayout::readRecord(scratch, nameID, contextID,
isImplicit, isObjC, genericSigID,
rawAccessLevel,
numConformances, numInheritedTypes,
rawInheritedAndDependencyIDs);
Identifier name = MF.getIdentifier(nameID);
PrettySupplementalDeclNameTrace trace(name);
for (TypeID dependencyID :
rawInheritedAndDependencyIDs.slice(numInheritedTypes)) {
auto dependency = MF.getTypeChecked(dependencyID);
if (!dependency) {
return llvm::make_error<TypeError>(
name, takeErrorInfo(dependency.takeError()));
}
}
auto DC = MF.getDeclContext(contextID);
if (declOrOffset.isComplete())
return declOrOffset;
auto genericParams = MF.maybeReadGenericParams(DC);
if (declOrOffset.isComplete())
return declOrOffset;
auto theStruct = MF.createDecl<StructDecl>(SourceLoc(), name, SourceLoc(),
None, genericParams, DC);
declOrOffset = theStruct;
// Read the generic environment.
theStruct->setGenericSignature(MF.getGenericSignature(genericSigID));
if (auto accessLevel = getActualAccessLevel(rawAccessLevel))
theStruct->setAccess(*accessLevel);
else
MF.fatal();
theStruct->setAddedImplicitInitializers();
if (isImplicit)
theStruct->setImplicit();
theStruct->setIsObjC(isObjC);
handleInherited(theStruct,
rawInheritedAndDependencyIDs.slice(0, numInheritedTypes));
theStruct->setMemberLoader(&MF, MF.DeclTypeCursor.GetCurrentBitNo());
skipRecord(MF.DeclTypeCursor, decls_block::MEMBERS);
theStruct->setConformanceLoader(
&MF,
encodeLazyConformanceContextData(numConformances,
MF.DeclTypeCursor.GetCurrentBitNo()));
return theStruct;
}
Expected<Decl *> deserializeConstructor(ArrayRef<uint64_t> scratch,
StringRef blobData) {
DeclContextID contextID;
bool isIUO, isFailable;
bool isImplicit, isObjC, hasStubImplementation, throws;
GenericSignatureID genericSigID;
uint8_t storedInitKind, rawAccessLevel;
DeclID overriddenID;
bool needsNewVTableEntry, firstTimeRequired;
unsigned numArgNames;
ArrayRef<uint64_t> argNameAndDependencyIDs;
decls_block::ConstructorLayout::readRecord(scratch, contextID,
isFailable, isIUO, isImplicit,
isObjC, hasStubImplementation,
throws, storedInitKind,
genericSigID,
overriddenID,
rawAccessLevel,
needsNewVTableEntry,
firstTimeRequired,
numArgNames,
argNameAndDependencyIDs);
// Resolve the name ids.
SmallVector<Identifier, 2> argNames;
for (auto argNameID : argNameAndDependencyIDs.slice(0, numArgNames))
argNames.push_back(MF.getIdentifier(argNameID));
DeclName name(ctx, DeclBaseName::createConstructor(), argNames);
PrettySupplementalDeclNameTrace trace(name);
Optional<swift::CtorInitializerKind> initKind =
getActualCtorInitializerKind(storedInitKind);
DeclDeserializationError::Flags errorFlags;
unsigned numVTableEntries = 0;
if (initKind == CtorInitializerKind::Designated)
errorFlags |= DeclDeserializationError::DesignatedInitializer;
if (needsNewVTableEntry) {
numVTableEntries = 1;
DeclAttributes attrs;
attrs.setRawAttributeChain(DAttrs);
}
auto overridden = MF.getDeclChecked(overriddenID);
if (!overridden) {
llvm::consumeError(overridden.takeError());
return llvm::make_error<OverrideError>(
name, errorFlags, numVTableEntries);
}
for (auto dependencyID : argNameAndDependencyIDs.slice(numArgNames)) {
auto dependency = MF.getTypeChecked(dependencyID);
if (!dependency) {
return llvm::make_error<TypeError>(
name, takeErrorInfo(dependency.takeError()),
errorFlags, numVTableEntries);
}
}
auto parent = MF.getDeclContext(contextID);
if (declOrOffset.isComplete())
return declOrOffset;
auto *genericParams = MF.maybeReadGenericParams(parent);
if (declOrOffset.isComplete())
return declOrOffset;
auto ctor = MF.createDecl<ConstructorDecl>(name, SourceLoc(), isFailable,
/*FailabilityLoc=*/SourceLoc(),
/*Throws=*/throws,
/*ThrowsLoc=*/SourceLoc(),
/*BodyParams=*/nullptr,
genericParams, parent);
declOrOffset = ctor;
ctor->setGenericSignature(MF.getGenericSignature(genericSigID));
if (auto accessLevel = getActualAccessLevel(rawAccessLevel))
ctor->setAccess(*accessLevel);
else
MF.fatal();
auto *bodyParams = MF.readParameterList();
assert(bodyParams && "missing parameters for constructor");
ctor->setParameters(bodyParams);
if (auto errorConvention = MF.maybeReadForeignErrorConvention())
ctor->setForeignErrorConvention(*errorConvention);
if (auto bodyText = MF.maybeReadInlinableBodyText())
ctor->setBodyStringRepresentation(*bodyText);
if (isImplicit)
ctor->setImplicit();
ctor->setIsObjC(isObjC);
if (hasStubImplementation)
ctor->setStubImplementation(true);
if (initKind.hasValue())
ctx.evaluator.cacheOutput(InitKindRequest{ctor},
std::move(initKind.getValue()));
ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{ctor},
std::move(needsNewVTableEntry));
ctor->setOverriddenDecl(cast_or_null<ConstructorDecl>(overridden.get()));
if (auto *overridden = ctor->getOverriddenDecl()) {
if (!attributeChainContains<RequiredAttr>(DAttrs) ||
!overridden->isRequired()) {
// FIXME: why is a convenience init considered overridden when the
// overriding init can't be marked overriding in source?
if (!overridden->isConvenienceInit())
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
}
}
ctor->setImplicitlyUnwrappedOptional(isIUO);
return ctor;
}
Expected<Decl *> deserializeVar(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID nameID;
DeclContextID contextID;
bool isImplicit, isObjC, isStatic;
uint8_t rawIntroducer;
bool isGetterMutating, isSetterMutating;
bool isLazyStorageProperty;
bool isTopLevelGlobal;
DeclID lazyStorageID;
unsigned numAccessors, numBackingProperties;
uint8_t readImpl, writeImpl, readWriteImpl, opaqueReadOwnership;
uint8_t rawAccessLevel, rawSetterAccessLevel;
TypeID interfaceTypeID;
bool isIUO;
ModuleFile::AccessorRecord accessors;
DeclID overriddenID, opaqueReturnTypeID;
unsigned numVTableEntries;
ArrayRef<uint64_t> arrayFieldIDs;
decls_block::VarLayout::readRecord(scratch, nameID, contextID,
isImplicit, isObjC, isStatic, rawIntroducer,
isGetterMutating, isSetterMutating,
isLazyStorageProperty,
isTopLevelGlobal,
lazyStorageID,
opaqueReadOwnership,
readImpl, writeImpl, readWriteImpl,
numAccessors,
interfaceTypeID,
isIUO,
overriddenID,
rawAccessLevel, rawSetterAccessLevel,
opaqueReturnTypeID,
numBackingProperties,
numVTableEntries,
arrayFieldIDs);
Identifier name = MF.getIdentifier(nameID);
PrettySupplementalDeclNameTrace trace(name);
auto getErrorFlags = [&]() {
// Stored properties in classes still impact class object layout because
// their offset is computed and stored in the field offset vector.
DeclDeserializationError::Flags errorFlags;
if (!isStatic) {
auto actualReadImpl = getActualReadImplKind(readImpl);
if (actualReadImpl && *actualReadImpl == ReadImplKind::Stored) {
errorFlags |= DeclDeserializationError::Flag::NeedsFieldOffsetVectorEntry;
}
}
return errorFlags;
};
Expected<Decl *> overridden = MF.getDeclChecked(overriddenID);
if (!overridden) {
llvm::consumeError(overridden.takeError());
return llvm::make_error<OverrideError>(
name, getErrorFlags(), numVTableEntries);
}
// Extract the accessor IDs.
for (DeclID accessorID : arrayFieldIDs.slice(0, numAccessors)) {
accessors.IDs.push_back(accessorID);
}
arrayFieldIDs = arrayFieldIDs.slice(numAccessors);
// Extract the backing property IDs.
auto backingPropertyIDs = arrayFieldIDs.slice(0, numBackingProperties);
arrayFieldIDs = arrayFieldIDs.slice(numBackingProperties);
for (TypeID dependencyID : arrayFieldIDs) {
auto dependency = MF.getTypeChecked(dependencyID);
if (!dependency) {
return llvm::make_error<TypeError>(
name, takeErrorInfo(dependency.takeError()),
getErrorFlags(), numVTableEntries);
}
}
auto DC = MF.getDeclContext(contextID);
if (declOrOffset.isComplete())
return declOrOffset;
auto introducer = getActualVarDeclIntroducer(
(serialization::VarDeclIntroducer) rawIntroducer);
if (!introducer)
MF.fatal();
auto var = MF.createDecl<VarDecl>(/*IsStatic*/ isStatic, *introducer,
SourceLoc(), name, DC);
var->setIsGetterMutating(isGetterMutating);
var->setIsSetterMutating(isSetterMutating);
declOrOffset = var;
auto interfaceTypeOrError = MF.getTypeChecked(interfaceTypeID);
if (!interfaceTypeOrError)
return interfaceTypeOrError.takeError();
Type interfaceType = interfaceTypeOrError.get();
var->setInterfaceType(interfaceType);
var->setImplicitlyUnwrappedOptional(isIUO);
if (auto referenceStorage = interfaceType->getAs<ReferenceStorageType>())
AddAttribute(
new (ctx) ReferenceOwnershipAttr(referenceStorage->getOwnership()));
MF.configureStorage(var, opaqueReadOwnership,
readImpl, writeImpl, readWriteImpl, accessors);
auto accessLevel = getActualAccessLevel(rawAccessLevel);
if (!accessLevel)
MF.fatal();
var->setAccess(*accessLevel);
if (var->isSettable(nullptr)) {
auto setterAccess = getActualAccessLevel(rawSetterAccessLevel);
if (!setterAccess)
MF.fatal();
var->setSetterAccess(*setterAccess);
// If we have a less-accessible setter, honor that by adding the
// setter access attribute.
if (*setterAccess < *accessLevel) {
AddAttribute(
new (ctx) SetterAccessAttr(SourceLoc(), SourceLoc(),
*setterAccess, /*implicit*/true));
}
}
if (isImplicit)
var->setImplicit();
var->setIsObjC(isObjC);
var->setOverriddenDecl(cast_or_null<VarDecl>(overridden.get()));
if (var->getOverriddenDecl())
AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
// Add the @_hasStorage attribute if this var has storage.
if (var->hasStorage())
AddAttribute(new (ctx) HasStorageAttr(/*isImplicit:*/true));
if (opaqueReturnTypeID) {
ctx.evaluator.cacheOutput(
OpaqueResultTypeRequest{var},
cast<OpaqueTypeDecl>(MF.getDecl(opaqueReturnTypeID)));
}
// If this is a lazy property, record its backing storage.
if (lazyStorageID) {
VarDecl *storage = cast<VarDecl>(MF.getDecl(lazyStorageID));
ctx.evaluator.cacheOutput(
LazyStoragePropertyRequest{var}, std::move(storage));
}
var->setLazyStorageProperty(isLazyStorageProperty);
var->setTopLevelGlobal(isTopLevelGlobal);
// If there are any backing properties, record them.
if (numBackingProperties > 0) {
auto backingDecl = MF.getDeclChecked(backingPropertyIDs[0]);
if (!backingDecl) {
// FIXME: This is actually wrong. We can't just drop stored properties
// willy-nilly if the struct is @frozen.
consumeError(backingDecl.takeError());
return var;
}
VarDecl *backingVar = cast<VarDecl>(backingDecl.get());
VarDecl *projectionVar = nullptr;
if (numBackingProperties > 1) {
projectionVar = cast<VarDecl>(MF.getDecl(backingPropertyIDs[1]));
}
PropertyWrapperBackingPropertyInfo info(
backingVar, projectionVar, nullptr, nullptr);
ctx.evaluator.cacheOutput(
PropertyWrapperBackingPropertyInfoRequest{var}, std::move(info));
ctx.evaluator.cacheOutput(
PropertyWrapperBackingPropertyTypeRequest{var},
backingVar->getInterfaceType());
backingVar->setOriginalWrappedProperty(var);
if (projectionVar)
projectionVar->setOriginalWrappedProperty(var);
}
return var;
}
Expected<Decl *> deserializeParam(ArrayRef<uint64_t> scratch,
StringRef blobData) {
IdentifierID argNameID, paramNameID;
DeclContextID contextID;
unsigned rawSpecifier;
TypeID interfaceTypeID;
bool isIUO;
bool isVariadic;
bool isAutoClosure;
uint8_t rawDefaultArg;
<