mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[serialization] Add support for generic requirements.
Same-type requirements aren't tested yet because there's currently no support for associated types. This includes an improvement to BCRecordLayout: array elements can be passed inline, and the static checks that the data count matches the field count will take this into account. Swift SVN r5984
This commit is contained in:
@@ -298,6 +298,17 @@ namespace impl {
|
||||
out.EmitRecordWithAbbrev(abbrCode, buffer);
|
||||
}
|
||||
|
||||
template <typename BufferTy, typename FirstData, typename ...RestData>
|
||||
static void emit(llvm::BitstreamWriter &out, BufferTy &buffer,
|
||||
unsigned abbrCode, FirstData firstData,
|
||||
RestData... restData) {
|
||||
std::array<FirstData, 1+sizeof...(restData)> arrayData{ {
|
||||
firstData,
|
||||
restData...
|
||||
} };
|
||||
emit(out, buffer, abbrCode, arrayData);
|
||||
}
|
||||
|
||||
template <typename BufferTy>
|
||||
static void emit(llvm::BitstreamWriter &out, BufferTy &buffer,
|
||||
unsigned abbrCode, Nothing_t) {
|
||||
@@ -344,11 +355,47 @@ namespace impl {
|
||||
template <typename ElementTy, typename DataTy>
|
||||
static void read(ArrayRef<ElementTy> buffer, DataTy &data) = delete;
|
||||
};
|
||||
|
||||
/// A type trait whose \c type field is the last of its template parameters.
|
||||
template<typename First, typename ...Rest>
|
||||
struct last_type {
|
||||
using type = typename last_type<Rest...>::type;
|
||||
};
|
||||
|
||||
template<typename Last>
|
||||
struct last_type<Last> {
|
||||
using type = Last;
|
||||
};
|
||||
|
||||
/// A type trait whose \c value field is \c true if the last type is BCBlob.
|
||||
template<typename ...Types>
|
||||
using has_blob = std::is_same<BCBlob, typename last_type<int, Types...>::type>;
|
||||
|
||||
/// A type trait whose \c value field is \c true if the given type is a
|
||||
/// BCArray (of any element kind).
|
||||
template <typename T>
|
||||
struct is_array {
|
||||
private:
|
||||
template <typename E>
|
||||
static bool check(BCArray<E> *);
|
||||
static int check(...);
|
||||
|
||||
public:
|
||||
typedef bool value_type;
|
||||
static constexpr bool value =
|
||||
!std::is_same<decltype(check((T*)nullptr)),
|
||||
decltype(check(false))>::value;
|
||||
};
|
||||
|
||||
/// A type trait whose \c value field is \c true if the last type is a
|
||||
/// BCArray (of any element kind).
|
||||
template<typename ...Types>
|
||||
using has_array = is_array<typename last_type<int, Types...>::type>;
|
||||
} // end namespace impl
|
||||
|
||||
/// Represents a single bitcode record type.
|
||||
///
|
||||
/// This class template is meant to be instantiated and then given a name,
|
||||
/// This class template is meant to be instantiated and then given a name,
|
||||
/// so that from then on that name can be used
|
||||
template<typename IDField, typename... Fields>
|
||||
class BCGenericRecordLayout {
|
||||
@@ -386,12 +433,15 @@ public:
|
||||
/// Emit a record identified by \p abbrCode to bitstream reader \p out, using
|
||||
/// \p buffer for scratch space.
|
||||
///
|
||||
/// Note that even fixed arguments must be specified here. Currently, arrays
|
||||
/// and blobs can only be passed as StringRefs.
|
||||
/// Note that even fixed arguments must be specified here. Blobs are passed
|
||||
/// as StringRefs, while arrays can be passed inline, as aggregates, or as
|
||||
/// pre-encoded StringRef data. Skipped values and empty arrays should use
|
||||
/// the special Nothing value.
|
||||
template <typename BufferTy, typename... Data>
|
||||
static void emitRecord(llvm::BitstreamWriter &out, BufferTy &buffer,
|
||||
unsigned abbrCode, unsigned recordID, Data... data) {
|
||||
static_assert(sizeof...(data) <= sizeof...(Fields),
|
||||
static_assert(sizeof...(data) <= sizeof...(Fields) ||
|
||||
impl::has_array<Fields...>::value,
|
||||
"Too many record elements");
|
||||
static_assert(sizeof...(data) >= sizeof...(Fields),
|
||||
"Too few record elements");
|
||||
@@ -407,11 +457,10 @@ public:
|
||||
/// in the buffer and should be handled separately by the caller.
|
||||
template <typename BufferTy, typename... Data>
|
||||
static void readRecord(BufferTy buffer, Data &... data) {
|
||||
// Weaker bounds checks here: a trailing blob is not decoded through the
|
||||
// layout.
|
||||
static_assert(sizeof...(data) <= sizeof...(Fields),
|
||||
"Too many record elements");
|
||||
static_assert(sizeof...(data)+1 >= sizeof...(Fields),
|
||||
static_assert(sizeof...(Fields) <=
|
||||
sizeof...(data) + impl::has_blob<Fields...>::value,
|
||||
"Too few record elements");
|
||||
return impl::BCRecordCoding<Fields...>::read(llvm::makeArrayRef(buffer),
|
||||
data...);
|
||||
|
||||
@@ -216,7 +216,47 @@ GenericParamList *ModuleFile::maybeReadGenericParams(DeclContext *DC) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GENERIC_REQUIREMENT: {
|
||||
uint8_t rawKind;
|
||||
ArrayRef<uint64_t> rawTypeIDs;
|
||||
GenericRequirementLayout::readRecord(scratch, rawKind, rawTypeIDs);
|
||||
switch (rawKind) {
|
||||
case GenericRequirementKind::Conformance: {
|
||||
assert(rawTypeIDs.size() == 2);
|
||||
TypeLoc subject, constraint;
|
||||
{
|
||||
BCOffsetRAII restoreInnerOffset(DeclTypeCursor);
|
||||
subject = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
|
||||
constraint = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
|
||||
}
|
||||
|
||||
requirements.push_back(Requirement::getConformance(subject,
|
||||
SourceLoc(),
|
||||
constraint));
|
||||
break;
|
||||
}
|
||||
case GenericRequirementKind::SameType: {
|
||||
assert(rawTypeIDs.size() == 2);
|
||||
TypeLoc first, second;
|
||||
{
|
||||
BCOffsetRAII restoreInnerOffset(DeclTypeCursor);
|
||||
first = TypeLoc::withoutLoc(getType(rawTypeIDs[0]));
|
||||
second = TypeLoc::withoutLoc(getType(rawTypeIDs[1]));
|
||||
}
|
||||
|
||||
requirements.push_back(Requirement::getSameType(first,
|
||||
SourceLoc(),
|
||||
second));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unknown requirement kind. Drop the requirement and continue, but log
|
||||
// an error so that we don't actually try to generate code.
|
||||
error();
|
||||
}
|
||||
}
|
||||
default:
|
||||
// This record is not part of the GenericParamList.
|
||||
shouldContinue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,14 @@ enum OperatorKind : uint8_t {
|
||||
static_assert(sizeof(OperatorKind) <= sizeof(TypeID),
|
||||
"too many operator kinds");
|
||||
|
||||
// These IDs must \em not be renumbered or reordered without incrementing
|
||||
// VERSION_MAJOR.
|
||||
enum GenericRequirementKind : uint8_t {
|
||||
Conformance = 0,
|
||||
SameType
|
||||
};
|
||||
using GenericRequirementKindField = BCFixed<1>;
|
||||
|
||||
/// The various types of blocks that can occur within a serialized Swift
|
||||
/// module.
|
||||
///
|
||||
@@ -425,6 +433,12 @@ namespace decls_block {
|
||||
DeclIDField // Typealias
|
||||
>;
|
||||
|
||||
using GenericRequirementLayout = BCRecordLayout<
|
||||
GENERIC_REQUIREMENT,
|
||||
GenericRequirementKindField, // requirement kind
|
||||
BCArray<TypeIDField> // types involved (currently always two)
|
||||
>;
|
||||
|
||||
using XRefLayout = BCRecordLayout<
|
||||
XREF,
|
||||
XRefKindField, // reference kind
|
||||
|
||||
@@ -386,6 +386,7 @@ void Serializer::writeBlockInfoBlock() {
|
||||
|
||||
RECORD(decls_block, GENERIC_PARAM_LIST);
|
||||
RECORD(decls_block, GENERIC_PARAM);
|
||||
RECORD(decls_block, GENERIC_REQUIREMENT);
|
||||
|
||||
RECORD(decls_block, XREF);
|
||||
RECORD(decls_block, DECL_CONTEXT);
|
||||
@@ -549,10 +550,6 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams) {
|
||||
if (!genericParams)
|
||||
return true;
|
||||
|
||||
// FIXME: Handle generic requirements.
|
||||
if (!genericParams->getRequirements().empty())
|
||||
return false;
|
||||
|
||||
SmallVector<TypeID, 8> archetypeIDs;
|
||||
for (auto archetype : genericParams->getAllArchetypes())
|
||||
archetypeIDs.push_back(addTypeRef(archetype));
|
||||
@@ -567,6 +564,24 @@ bool Serializer::writeGenericParams(const GenericParamList *genericParams) {
|
||||
addDeclRef(next.getDecl()));
|
||||
}
|
||||
|
||||
abbrCode = DeclTypeAbbrCodes[GenericRequirementLayout::Code];
|
||||
for (auto next : genericParams->getRequirements()) {
|
||||
switch (next.getKind()) {
|
||||
case RequirementKind::Conformance:
|
||||
GenericRequirementLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
GenericRequirementKind::Conformance,
|
||||
addTypeRef(next.getSubject()),
|
||||
addTypeRef(next.getConstraint()));
|
||||
break;
|
||||
case RequirementKind::SameType:
|
||||
GenericRequirementLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
GenericRequirementKind::SameType,
|
||||
addTypeRef(next.getFirstType()),
|
||||
addTypeRef(next.getSecondType()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1112,6 +1127,7 @@ void Serializer::writeAllDeclsAndTypes() {
|
||||
|
||||
registerDeclTypeAbbr<GenericParamListLayout>();
|
||||
registerDeclTypeAbbr<GenericParamLayout>();
|
||||
registerDeclTypeAbbr<GenericRequirementLayout>();
|
||||
registerDeclTypeAbbr<XRefLayout>();
|
||||
registerDeclTypeAbbr<DeclContextLayout>();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user