blob: 8f61cafed4cd67c7ed002fadede6e213182939d4 [file] [log] [blame]
//===--- DeserializationErrors.h - Problems in deserialization --*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H
#define SWIFT_SERIALIZATION_DESERIALIZATIONERRORS_H
#include "ModuleFormat.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/Module.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/PrettyStackTrace.h"
namespace swift {
class ModuleFile;
StringRef getNameOfModule(const ModuleFile *);
namespace serialization {
class XRefTracePath {
class PathPiece {
public:
enum class Kind {
Value,
Type,
Operator,
OperatorFilter,
Accessor,
Extension,
GenericParam,
PrivateDiscriminator,
OpaqueReturnType,
Unknown
};
private:
Kind kind;
void *data;
template <typename T>
T getDataAs() const {
return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(data);
}
public:
template <typename T>
PathPiece(Kind K, T value)
: kind(K),
data(llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(value)) {}
DeclBaseName getAsBaseName() const {
switch (kind) {
case Kind::Value:
case Kind::Operator:
case Kind::PrivateDiscriminator:
case Kind::OpaqueReturnType:
return getDataAs<DeclBaseName>();
case Kind::Type:
case Kind::OperatorFilter:
case Kind::Accessor:
case Kind::Extension:
case Kind::GenericParam:
case Kind::Unknown:
return Identifier();
}
llvm_unreachable("unhandled kind");
}
void print(raw_ostream &os) const {
switch (kind) {
case Kind::Value:
os << getDataAs<DeclBaseName>();
break;
case Kind::Type:
os << "with type " << getDataAs<Type>();
break;
case Kind::Extension:
if (getDataAs<ModuleDecl *>()) {
os << "in an extension in module '"
<< getDataAs<ModuleDecl *>()->getName()
<< "'";
} else {
os << "in an extension in any module";
}
break;
case Kind::Operator:
os << "operator " << getDataAs<Identifier>();
break;
case Kind::OperatorFilter:
switch (getDataAs<uintptr_t>()) {
case Infix:
os << "(infix)";
break;
case Prefix:
os << "(prefix)";
break;
case Postfix:
os << "(postfix)";
break;
default:
os << "(unknown operator filter)";
break;
}
break;
case Kind::Accessor:
switch (getDataAs<uintptr_t>()) {
case Get:
os << "(getter)";
break;
case Set:
os << "(setter)";
break;
case Address:
os << "(addressor)";
break;
case MutableAddress:
os << "(mutableAddressor)";
break;
case WillSet:
os << "(willSet)";
break;
case DidSet:
os << "(didSet)";
break;
case Read:
os << "(read)";
break;
case Modify:
os << "(modify)";
break;
default:
os << "(unknown accessor kind)";
break;
}
break;
case Kind::GenericParam:
os << "generic param #" << getDataAs<uintptr_t>();
break;
case Kind::PrivateDiscriminator:
os << "(in " << getDataAs<Identifier>() << ")";
break;
case Kind::OpaqueReturnType:
os << "opaque return type of " << getDataAs<DeclBaseName>();
break;
case Kind::Unknown:
os << "unknown xref kind " << getDataAs<uintptr_t>();
break;
}
}
};
ModuleDecl &baseM;
SmallVector<PathPiece, 8> path;
public:
explicit XRefTracePath(ModuleDecl &M) : baseM(M) {}
void addValue(DeclBaseName name) {
path.push_back({ PathPiece::Kind::Value, name });
}
void addType(Type ty) {
path.push_back({ PathPiece::Kind::Type, ty });
}
void addOperator(Identifier name) {
path.push_back({ PathPiece::Kind::Operator, name });
}
void addOperatorFilter(uint8_t fixity) {
path.push_back({ PathPiece::Kind::OperatorFilter,
static_cast<uintptr_t>(fixity) });
}
void addAccessor(uint8_t kind) {
path.push_back({ PathPiece::Kind::Accessor,
static_cast<uintptr_t>(kind) });
}
void addExtension(ModuleDecl *M) {
path.push_back({ PathPiece::Kind::Extension, M });
}
void addGenericParam(uintptr_t index) {
path.push_back({ PathPiece::Kind::GenericParam, index });
}
void addPrivateDiscriminator(Identifier name) {
path.push_back({ PathPiece::Kind::PrivateDiscriminator, name });
}
void addUnknown(uintptr_t kind) {
path.push_back({ PathPiece::Kind::Unknown, kind });
}
void addOpaqueReturnType(Identifier name) {
path.push_back({ PathPiece::Kind::OpaqueReturnType, name });
}
DeclBaseName getLastName() const {
for (auto &piece : reversed(path)) {
DeclBaseName result = piece.getAsBaseName();
if (!result.empty())
return result;
}
return DeclBaseName();
}
void removeLast() {
path.pop_back();
}
void print(raw_ostream &os, StringRef leading = "") const {
os << "Cross-reference to module '" << baseM.getName() << "'\n";
for (auto &piece : path) {
os << leading << "... ";
piece.print(os);
os << "\n";
}
}
};
class DeclDeserializationError : public llvm::ErrorInfoBase {
static const char ID;
void anchor() override;
public:
enum Flag : unsigned {
DesignatedInitializer = 1 << 0,
NeedsFieldOffsetVectorEntry = 1 << 1,
};
using Flags = OptionSet<Flag>;
protected:
DeclName name;
Flags flags;
uint8_t numVTableEntries = 0;
public:
DeclName getName() const {
return name;
}
bool isDesignatedInitializer() const {
return flags.contains(Flag::DesignatedInitializer);
}
unsigned getNumberOfVTableEntries() const {
return numVTableEntries;
}
bool needsFieldOffsetVectorEntry() const {
return flags.contains(Flag::NeedsFieldOffsetVectorEntry);
}
bool isA(const void *const ClassID) const override {
return ClassID == classID() || ErrorInfoBase::isA(ClassID);
}
static const void *classID() { return &ID; }
};
class XRefError : public llvm::ErrorInfo<XRefError, DeclDeserializationError> {
friend ErrorInfo;
static const char ID;
void anchor() override;
XRefTracePath path;
const char *message;
public:
template <size_t N>
XRefError(const char (&message)[N], XRefTracePath path, DeclName name)
: path(path), message(message) {
this->name = name;
}
void log(raw_ostream &OS) const override {
OS << message << "\n";
path.print(OS);
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
class XRefNonLoadedModuleError :
public llvm::ErrorInfo<XRefNonLoadedModuleError, DeclDeserializationError> {
friend ErrorInfo;
static const char ID;
void anchor() override;
public:
explicit XRefNonLoadedModuleError(Identifier name) {
this->name = name;
}
void log(raw_ostream &OS) const override {
OS << "module '" << name << "' was not loaded";
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
class OverrideError : public llvm::ErrorInfo<OverrideError,
DeclDeserializationError> {
private:
friend ErrorInfo;
static const char ID;
void anchor() override;
public:
explicit OverrideError(DeclName name,
Flags flags={}, unsigned numVTableEntries=0) {
this->name = name;
this->flags = flags;
this->numVTableEntries = numVTableEntries;
}
void log(raw_ostream &OS) const override {
OS << "could not find '" << name << "' in parent class";
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
class TypeError : public llvm::ErrorInfo<TypeError, DeclDeserializationError> {
friend ErrorInfo;
static const char ID;
void anchor() override;
std::unique_ptr<ErrorInfoBase> underlyingReason;
public:
explicit TypeError(DeclName name, std::unique_ptr<ErrorInfoBase> reason,
Flags flags={}, unsigned numVTableEntries=0)
: underlyingReason(std::move(reason)) {
this->name = name;
this->flags = flags;
this->numVTableEntries = numVTableEntries;
}
void log(raw_ostream &OS) const override {
OS << "could not deserialize type for '" << name << "'";
if (underlyingReason) {
OS << ": ";
underlyingReason->log(OS);
}
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
class ExtensionError : public llvm::ErrorInfo<ExtensionError> {
friend ErrorInfo;
static const char ID;
void anchor() override;
std::unique_ptr<ErrorInfoBase> underlyingReason;
public:
explicit ExtensionError(std::unique_ptr<ErrorInfoBase> reason)
: underlyingReason(std::move(reason)) {}
void log(raw_ostream &OS) const override {
OS << "could not deserialize extension";
if (underlyingReason) {
OS << ": ";
underlyingReason->log(OS);
}
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
class SILEntityError : public llvm::ErrorInfo<SILEntityError> {
friend ErrorInfo;
static const char ID;
void anchor() override;
std::unique_ptr<ErrorInfoBase> underlyingReason;
StringRef name;
public:
SILEntityError(StringRef name, std::unique_ptr<ErrorInfoBase> reason)
: underlyingReason(std::move(reason)), name(name) {}
void log(raw_ostream &OS) const override {
OS << "could not deserialize SIL entity '" << name << "'";
if (underlyingReason) {
OS << ": ";
underlyingReason->log(OS);
}
}
std::error_code convertToErrorCode() const override {
return llvm::inconvertibleErrorCode();
}
};
LLVM_NODISCARD
static inline 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;
}
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
const char *Action;
const ModuleFile &MF;
public:
explicit PrettyStackTraceModuleFile(const char *action, ModuleFile &module)
: Action(action), MF(module) {}
explicit PrettyStackTraceModuleFile(ModuleFile &module)
: PrettyStackTraceModuleFile("While reading from", module) {}
void print(raw_ostream &os) const override {
os << Action << " \'" << getNameOfModule(&MF) << "'\n";
}
};
} // end namespace serialization
} // end namespace swift
#endif