blob: d4d15e4c253c9ec8f0ab24c777c7549dbf61c1d4 [file] [log] [blame]
//===--- TypeLowering.cpp - Swift Type Lowering for Reflection ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Implements logic for computing in-memory layouts from TypeRefs loaded from
// reflection metadata.
//
// This has to match up with layout algorithms used in IRGen and the runtime,
// and a bit of SIL type lowering to boot.
//
//===----------------------------------------------------------------------===//
#include "swift/Reflection/TypeLowering.h"
#include "swift/Reflection/TypeRef.h"
#include "swift/Reflection/TypeRefBuilder.h"
#include <iostream>
using namespace swift;
using namespace reflection;
void TypeInfo::dump() const {
dump(std::cerr);
}
namespace {
class PrintTypeInfo {
std::ostream &OS;
unsigned Indent;
std::ostream &indent(unsigned Amount) {
for (unsigned i = 0; i < Amount; ++i)
OS << ' ';
return OS;
}
std::ostream &printHeader(const std::string &name) {
indent(Indent) << '(' << name;
return OS;
}
template<typename T>
std::ostream &printField(const std::string &name, const T &value) {
if (!name.empty())
OS << " " << name << "=" << value;
else
OS << " " << value;
return OS;
}
void printRec(const TypeInfo &TI) {
OS << "\n";
Indent += 2;
print(TI);
Indent -= 2;
}
void printBasic(const TypeInfo &TI) {
printField("size", TI.getSize());
printField("alignment", TI.getAlignment());
printField("stride", TI.getStride());
printField("num_extra_inhabitants", TI.getNumExtraInhabitants());
}
void printFields(const RecordTypeInfo &TI) {
Indent += 2;
for (auto Field : TI.getFields()) {
OS << "\n";
printHeader("field");
if (!Field.Name.empty())
printField("name", Field.Name);
printField("offset", Field.Offset);
printRec(Field.TI);
OS << ")";
}
Indent -= 2;
}
public:
PrintTypeInfo(std::ostream &OS, unsigned Indent)
: OS(OS), Indent(Indent) {}
void print(const TypeInfo &TI) {
switch (TI.getKind()) {
case TypeInfoKind::Builtin:
printHeader("builtin");
printBasic(TI);
OS << ")";
return;
case TypeInfoKind::Record: {
auto &RecordTI = cast<RecordTypeInfo>(TI);
switch (RecordTI.getRecordKind()) {
case RecordKind::Struct:
printHeader("struct");
break;
case RecordKind::Tuple:
printHeader("tuple");
break;
case RecordKind::ThickFunction:
printHeader("thick_function");
break;
case RecordKind::Existential:
printHeader("existential");
break;
case RecordKind::ClassExistential:
printHeader("class_existential");
break;
case RecordKind::ExistentialMetatype:
printHeader("existential_metatype");
break;
case RecordKind::ClassInstance:
printHeader("class_instance");
break;
}
printBasic(TI);
printFields(RecordTI);
OS << ")";
return;
}
case TypeInfoKind::Reference: {
printHeader("reference");
auto &ReferenceTI = cast<ReferenceTypeInfo>(TI);
switch (ReferenceTI.getReferenceKind()) {
case ReferenceKind::Strong:
printField("kind", "strong");
break;
case ReferenceKind::Unowned:
printField("kind", "unowned");
break;
case ReferenceKind::Weak:
printField("kind", "weak");
break;
case ReferenceKind::Unmanaged:
printField("kind", "unmanaged");
break;
}
switch (ReferenceTI.getReferenceCounting()) {
case ReferenceCounting::Native:
printField("refcounting", "native");
break;
case ReferenceCounting::Unknown:
printField("refcounting", "unknown");
break;
}
OS << ")";
return;
}
}
assert(false && "Bad TypeInfo kind");
}
};
}
void TypeInfo::dump(std::ostream &OS, unsigned Indent) const {
PrintTypeInfo(OS, Indent).print(*this);
OS << '\n';
}
namespace {
class BuiltinTypeInfo : public TypeInfo {
public:
BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor)
: TypeInfo(TypeInfoKind::Builtin,
descriptor->Size, descriptor->Alignment,
descriptor->Stride, descriptor->NumExtraInhabitants) {}
static bool classof(const TypeInfo *TI) {
return TI->getKind() == TypeInfoKind::Builtin;
}
};
/// Utility class for performing universal layout for types such as
/// tuples, structs, thick functions, etc.
class RecordTypeInfoBuilder {
TypeConverter &TC;
unsigned Size, Alignment, Stride, NumExtraInhabitants;
RecordKind Kind;
std::vector<FieldInfo> Fields;
bool Invalid;
public:
RecordTypeInfoBuilder(TypeConverter &TC, RecordKind Kind)
: TC(TC), Size(0), Alignment(1), Stride(0), NumExtraInhabitants(0),
Kind(Kind), Invalid(false) {}
unsigned addField(unsigned fieldSize, unsigned fieldAlignment) {
// Align the current size appropriately
Size = ((Size + fieldAlignment - 1) & ~(fieldAlignment - 1));
// Record the offset
unsigned offset = Size;
// Update the aggregate size
Size += fieldSize;
// Update the aggregate alignment
Alignment = std::max(Alignment, fieldAlignment);
// Re-calculate the stride
Stride = ((Size + Alignment - 1) & ~(Alignment - 1));
return offset;
}
void addField(const std::string &Name, const TypeRef *TR) {
const TypeInfo *TI = TC.getTypeInfo(TR);
if (TI == nullptr) {
Invalid = true;
return;
}
// FIXME: I just made this up
if (Size == 0)
NumExtraInhabitants = TI->getNumExtraInhabitants();
else
NumExtraInhabitants = 0;
unsigned fieldSize = TI->getSize();
unsigned fieldAlignment = TI->getAlignment();
unsigned fieldOffset = addField(fieldSize, fieldAlignment);
Fields.push_back({Name, fieldOffset, TR, *TI});
}
const RecordTypeInfo *build() {
if (Invalid)
return nullptr;
return TC.makeTypeInfo<RecordTypeInfo>(
Size, Alignment, Stride,
NumExtraInhabitants, Kind, Fields);
}
};
/// Utility class for building values that contain witness tables.
class ExistentialTypeInfoBuilder {
TypeConverter &TC;
bool ObjC;
bool Class;
unsigned WitnessTableCount;
bool Invalid;
public:
ExistentialTypeInfoBuilder(TypeConverter &TC)
: TC(TC), ObjC(false), Class(false), WitnessTableCount(0),
Invalid(false) {}
void addProtocol(const TypeRef *TR) {
auto *P = dyn_cast<ProtocolTypeRef>(TR);
if (P == nullptr) {
Invalid = true;
return;
}
// FIXME: AnyObject should go away
if (P->getMangledName() == "Ps9AnyObject_") {
// No witness table for AnyObject
Class = true;
return;
}
const FieldDescriptor *FD = TC.getBuilder().getFieldTypeInfo(TR);
if (FD == nullptr) {
Invalid = true;
return;
}
switch (FD->Kind) {
case FieldDescriptorKind::ObjCProtocol:
// Objective-C protocols do not have any witness tables.
ObjC = true;
break;
case FieldDescriptorKind::ClassProtocol:
Class = true;
WitnessTableCount++;
break;
case FieldDescriptorKind::Protocol:
WitnessTableCount++;
break;
case FieldDescriptorKind::Struct:
case FieldDescriptorKind::Enum:
case FieldDescriptorKind::Class:
Invalid = true;
break;
}
}
const TypeInfo *build() {
if (Invalid)
return nullptr;
if (ObjC) {
if (WitnessTableCount > 0)
return nullptr;
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Unknown);
}
RecordTypeInfoBuilder builder(TC,
Class
? RecordKind::ClassExistential
: RecordKind::Existential);
if (Class) {
// Class existentials consist of a single retainable pointer
// followed by witness tables.
builder.addField("object", TC.getUnknownObjectTypeRef());
} else {
// Non-class existentials consist of a three-word buffer and
// value metadata, followed by witness tables.
builder.addField("value", TC.getRawPointerTypeRef());
builder.addField("value", TC.getRawPointerTypeRef());
builder.addField("value", TC.getRawPointerTypeRef());
builder.addField("metadata", TC.getRawPointerTypeRef());
}
for (unsigned i = 0; i < WitnessTableCount; i++)
builder.addField("wtable", TC.getRawPointerTypeRef());
return builder.build();
}
const TypeInfo *buildMetatype() {
if (Invalid)
return nullptr;
if (ObjC) {
if (WitnessTableCount > 0)
return nullptr;
return TC.getTypeInfo(TC.getRawPointerTypeRef());
}
RecordTypeInfoBuilder builder(TC, RecordKind::ExistentialMetatype);
builder.addField("metadata", TC.getRawPointerTypeRef());
for (unsigned i = 0; i < WitnessTableCount; i++)
builder.addField("wtable", TC.getRawPointerTypeRef());
return builder.build();
}
};
}
const ReferenceTypeInfo *
TypeConverter::getReferenceTypeInfo(ReferenceKind Kind,
ReferenceCounting Refcounting) {
auto key = std::make_pair(unsigned(Kind), unsigned(Refcounting));
auto found = ReferenceCache.find(key);
if (found != ReferenceCache.end())
return found->second;
const TypeRef *TR;
switch (Refcounting) {
case ReferenceCounting::Native:
TR = getNativeObjectTypeRef();
break;
case ReferenceCounting::Unknown:
TR = getUnknownObjectTypeRef();
break;
}
// FIXME: Weak, Unowned references have different extra inhabitants
auto *BuiltinTI = Builder.getBuiltinTypeInfo(TR);
if (BuiltinTI == nullptr)
return nullptr;
auto *TI = makeTypeInfo<ReferenceTypeInfo>(BuiltinTI->Size,
BuiltinTI->Alignment,
BuiltinTI->Stride,
BuiltinTI->NumExtraInhabitants,
Kind, Refcounting);
ReferenceCache[key] = TI;
return TI;
}
/// Thick functions consist of a function pointer and nullable retainable
/// context pointer. The context is modeled exactly like a native Swift
/// class reference.
const TypeInfo *
TypeConverter::getThickFunctionTypeInfo() {
if (ThickFunctionTI != nullptr)
return ThickFunctionTI;
RecordTypeInfoBuilder builder(*this, RecordKind::ThickFunction);
builder.addField("function", getRawPointerTypeRef());
builder.addField("context", getNativeObjectTypeRef());
ThickFunctionTI = builder.build();
return ThickFunctionTI;
}
const TypeInfo *TypeConverter::getEmptyTypeInfo() {
if (EmptyTI != nullptr)
return EmptyTI;
EmptyTI = makeTypeInfo<TypeInfo>(TypeInfoKind::Builtin, 0, 1, 0, 0);
return EmptyTI;
}
const TypeRef *TypeConverter::getRawPointerTypeRef() {
if (RawPointerTR != nullptr)
return RawPointerTR;
RawPointerTR = BuiltinTypeRef::create(Builder, "Bp");
return RawPointerTR;
}
const TypeRef *TypeConverter::getNativeObjectTypeRef() {
if (NativeObjectTR != nullptr)
return NativeObjectTR;
NativeObjectTR = BuiltinTypeRef::create(Builder, "Bo");
return NativeObjectTR;
}
const TypeRef *TypeConverter::getUnknownObjectTypeRef() {
if (UnknownObjectTR != nullptr)
return UnknownObjectTR;
UnknownObjectTR = BuiltinTypeRef::create(Builder, "BO");
return UnknownObjectTR;
}
enum class MetatypeRepresentation : unsigned {
/// Singleton metatype values are empty.
Thin,
/// Metatypes containing classes, or where the original unsubstituted
/// type contains a type parameter, must be represented as pointers
/// to metadata structures.
Thick,
/// Insufficient information to determine which.
Unknown
};
MetatypeRepresentation combineRepresentations(MetatypeRepresentation rep1,
MetatypeRepresentation rep2) {
if (rep1 == rep2)
return rep1;
if (rep1 == MetatypeRepresentation::Unknown ||
rep2 == MetatypeRepresentation::Unknown)
return MetatypeRepresentation::Unknown;
if (rep1 == MetatypeRepresentation::Thick ||
rep2 == MetatypeRepresentation::Thick)
return MetatypeRepresentation::Thick;
return MetatypeRepresentation::Thin;
}
/// Visitor class to determine if a metatype should use the empty
/// representation.
///
/// This relies on substitution correctly setting wasAbstract() on
/// MetatypeTypeRefs.
class HasSingletonMetatype
: public TypeRefVisitor<HasSingletonMetatype, MetatypeRepresentation> {
TypeRefBuilder &Builder;
public:
HasSingletonMetatype(TypeRefBuilder &Builder) : Builder(Builder) {}
using TypeRefVisitor<HasSingletonMetatype, MetatypeRepresentation>::visit;
MetatypeRepresentation visitBuiltinTypeRef(const BuiltinTypeRef *B) {
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation visitAnyNominalTypeRef(const TypeRef *TR) {
const FieldDescriptor *FD = Builder.getFieldTypeInfo(TR);
if (FD == nullptr)
return MetatypeRepresentation::Unknown;
switch (FD->Kind) {
case FieldDescriptorKind::Class:
// Classes can have subclasses, so the metatype is always thick.
return MetatypeRepresentation::Thick;
case FieldDescriptorKind::Struct:
case FieldDescriptorKind::Enum:
return MetatypeRepresentation::Thin;
case FieldDescriptorKind::ObjCProtocol:
case FieldDescriptorKind::ClassProtocol:
case FieldDescriptorKind::Protocol:
// Invalid field descriptor.
return MetatypeRepresentation::Unknown;
}
}
MetatypeRepresentation visitNominalTypeRef(const NominalTypeRef *N) {
return visitAnyNominalTypeRef(N);
}
MetatypeRepresentation visitBoundGenericTypeRef(const BoundGenericTypeRef *BG) {
return visitAnyNominalTypeRef(BG);
}
MetatypeRepresentation visitTupleTypeRef(const TupleTypeRef *T) {
auto result = MetatypeRepresentation::Thin;
for (auto Element : T->getElements())
result = combineRepresentations(result, visit(Element));
return result;
}
MetatypeRepresentation visitFunctionTypeRef(const FunctionTypeRef *F) {
auto result = visit(F->getResult());
for (auto Arg : F->getArguments())
result = combineRepresentations(result, visit(Arg));
return result;
}
MetatypeRepresentation visitProtocolTypeRef(const ProtocolTypeRef *P) {
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation
visitProtocolCompositionTypeRef(const ProtocolCompositionTypeRef *PC) {
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation visitMetatypeTypeRef(const MetatypeTypeRef *M) {
if (M->wasAbstract())
return MetatypeRepresentation::Thick;
return visit(M->getInstanceType());
}
MetatypeRepresentation
visitExistentialMetatypeTypeRef(const ExistentialMetatypeTypeRef *EM) {
return MetatypeRepresentation::Thin;
}
MetatypeRepresentation
visitGenericTypeParameterTypeRef(const GenericTypeParameterTypeRef *GTP) {
assert(false && "Must have concrete TypeRef");
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation
visitDependentMemberTypeRef(const DependentMemberTypeRef *DM) {
assert(false && "Must have concrete TypeRef");
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation
visitForeignClassTypeRef(const ForeignClassTypeRef *F) {
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation visitObjCClassTypeRef(const ObjCClassTypeRef *OC) {
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation
visitUnownedStorageTypeRef(const UnownedStorageTypeRef *US) {
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation visitWeakStorageTypeRef(const WeakStorageTypeRef *WS) {
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation
visitUnmanagedStorageTypeRef(const UnmanagedStorageTypeRef *US) {
return MetatypeRepresentation::Unknown;
}
MetatypeRepresentation visitOpaqueTypeRef(const OpaqueTypeRef *O) {
return MetatypeRepresentation::Unknown;
}
};
class LowerType
: public TypeRefVisitor<LowerType, const TypeInfo *> {
TypeConverter &TC;
public:
using TypeRefVisitor<LowerType, const TypeInfo *>::visit;
LowerType(TypeConverter &TC) : TC(TC) {}
const TypeInfo *visitBuiltinTypeRef(const BuiltinTypeRef *B) {
/// The context field of a thick function is a Builtin.NativeObject.
/// Since we want this to round-trip, lower these as reference
/// types.
if (B->getMangledName() == "Bo") {
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Native);
} else if (B->getMangledName() == "BO") {
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Unknown);
}
/// Otherwise, get the fixed layout information from reflection
/// metadata.
auto *descriptor = TC.getBuilder().getBuiltinTypeInfo(B);
if (descriptor == nullptr)
return nullptr;
return TC.makeTypeInfo<BuiltinTypeInfo>(descriptor);
}
const TypeInfo *visitAnyNominalTypeRef(const TypeRef *TR) {
const FieldDescriptor *FD = TC.getBuilder().getFieldTypeInfo(TR);
if (FD == nullptr)
return nullptr;
switch (FD->Kind) {
case FieldDescriptorKind::Class:
// A value of class type is a single retainable pointer.
//
// FIXME: need to know if this is a NativeObject or UnknownObject
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Native);
case FieldDescriptorKind::Struct: {
// Lower the struct's fields using substitutions from the
// TypeRef to make field types concrete.
RecordTypeInfoBuilder builder(TC, RecordKind::Struct);
for (auto Field : TC.getBuilder().getFieldTypeRefs(TR, FD))
builder.addField(Field.first, Field.second);
return builder.build();
}
case FieldDescriptorKind::Enum: {
// Sort enum into payload and no-payload cases.
unsigned NoPayloadCases = 0;
unsigned PayloadCases = 0;
const TypeInfo *PayloadTI = nullptr;
for (auto Field : TC.getBuilder().getFieldTypeRefs(TR, FD)) {
if (Field.second == nullptr) {
NoPayloadCases++;
continue;
}
// FIXME: If the unsubstituted payload type is empty, but not
// resilient, we treat the case as a no-payload case.
//
// This should be handled by IRGen emitting the enum strategy
// explicitly.
PayloadCases++;
PayloadTI = TC.getTypeInfo(Field.second);
if (PayloadTI == nullptr)
return nullptr;
}
// FIXME: Implement remaining enum layout strategies
//
// Also this is wrong if we wrap a reference in multiple levels of
// optionality
if (NoPayloadCases == 1 && PayloadCases == 1) {
if (isa<ReferenceTypeInfo>(PayloadTI))
return PayloadTI;
if (auto *RecordTI = dyn_cast<RecordTypeInfo>(PayloadTI)) {
auto SubKind = RecordTI->getRecordKind();
if (SubKind == RecordKind::ClassExistential)
return PayloadTI;
}
}
return nullptr;
}
case FieldDescriptorKind::ObjCProtocol:
case FieldDescriptorKind::ClassProtocol:
case FieldDescriptorKind::Protocol:
// Invalid field descriptor
return nullptr;
}
}
const TypeInfo *visitNominalTypeRef(const NominalTypeRef *N) {
return visitAnyNominalTypeRef(N);
}
const TypeInfo *visitBoundGenericTypeRef(const BoundGenericTypeRef *BG) {
return visitAnyNominalTypeRef(BG);
}
const TypeInfo *visitTupleTypeRef(const TupleTypeRef *T) {
RecordTypeInfoBuilder builder(TC, RecordKind::Tuple);
for (auto Element : T->getElements())
builder.addField("", Element);
return builder.build();
}
const TypeInfo *visitFunctionTypeRef(const FunctionTypeRef *F) {
switch (F->getFlags().getConvention()) {
case FunctionMetadataConvention::Swift:
return TC.getThickFunctionTypeInfo();
case FunctionMetadataConvention::Block:
// FIXME: Native convention if blocks are ever supported on Linux?
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Unknown);
case FunctionMetadataConvention::Thin:
case FunctionMetadataConvention::CFunctionPointer:
return TC.getTypeInfo(TC.getRawPointerTypeRef());
}
}
const TypeInfo *visitProtocolTypeRef(const ProtocolTypeRef *P) {
ExistentialTypeInfoBuilder builder(TC);
builder.addProtocol(P);
return builder.build();
}
const TypeInfo *
visitProtocolCompositionTypeRef(const ProtocolCompositionTypeRef *PC) {
ExistentialTypeInfoBuilder builder(TC);
for (auto *P : PC->getProtocols())
builder.addProtocol(P);
return builder.build();
}
const TypeInfo *visitMetatypeTypeRef(const MetatypeTypeRef *M) {
switch (HasSingletonMetatype(TC.getBuilder()).visit(M)) {
case MetatypeRepresentation::Unknown:
return nullptr;
case MetatypeRepresentation::Thin:
return TC.getEmptyTypeInfo();
case MetatypeRepresentation::Thick:
return TC.getTypeInfo(TC.getRawPointerTypeRef());
}
}
const TypeInfo *
visitExistentialMetatypeTypeRef(const ExistentialMetatypeTypeRef *EM) {
ExistentialTypeInfoBuilder builder(TC);
auto *TR = EM->getInstanceType();
if (auto *P = dyn_cast<ProtocolTypeRef>(TR)) {
builder.addProtocol(P);
} else if (auto *PC = dyn_cast<ProtocolCompositionTypeRef>(TR)) {
for (auto *P : PC->getProtocols())
builder.addProtocol(P);
} else {
// Invalid TypeRef
return nullptr;
}
return builder.buildMetatype();
}
const TypeInfo *
visitGenericTypeParameterTypeRef(const GenericTypeParameterTypeRef *GTP) {
assert(false && "Must have concrete TypeRef");
return nullptr;
}
const TypeInfo *
visitDependentMemberTypeRef(const DependentMemberTypeRef *DM) {
assert(false && "Must have concrete TypeRef");
return nullptr;
}
const TypeInfo *visitForeignClassTypeRef(const ForeignClassTypeRef *F) {
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Unknown);
}
const TypeInfo *visitObjCClassTypeRef(const ObjCClassTypeRef *OC) {
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
ReferenceCounting::Unknown);
}
// Apply a storage qualifier, like 'weak', 'unowned' or 'unowned(unsafe)'
// to a type with reference semantics, such as a class reference or
// class-bound existential.
const TypeInfo *
rebuildStorageTypeInfo(const TypeInfo *TI, ReferenceKind Kind) {
// If we can't lower the original storage type, give up.
if (TI == nullptr)
return nullptr;
// Simple case: Just change the reference kind
if (auto *ReferenceTI = dyn_cast<ReferenceTypeInfo>(TI))
return TC.getReferenceTypeInfo(Kind, ReferenceTI->getReferenceCounting());
// Class existentials are represented as record types.
// Destructure the existential and replace the "object"
// field with the right reference kind.
if (auto *RecordTI = dyn_cast<RecordTypeInfo>(TI)) {
auto SubKind = RecordTI->getRecordKind();
if (SubKind == RecordKind::ClassExistential) {
std::vector<FieldInfo> Fields;
for (auto &Field : RecordTI->getFields()) {
if (Field.Name == "object") {
auto *FieldTI = rebuildStorageTypeInfo(&Field.TI, Kind);
Fields.push_back({Field.Name, Field.Offset, Field.TR, *FieldTI});
continue;
}
Fields.push_back(Field);
}
return TC.makeTypeInfo<RecordTypeInfo>(
RecordTI->getSize(),
RecordTI->getAlignment(),
RecordTI->getStride(),
RecordTI->getNumExtraInhabitants(),
SubKind, Fields);
}
}
// Anything else -- give up
return nullptr;
}
const TypeInfo *
visitAnyStorageTypeRef(const TypeRef *TR, ReferenceKind Kind) {
return rebuildStorageTypeInfo(TC.getTypeInfo(TR), Kind);
}
const TypeInfo *
visitUnownedStorageTypeRef(const UnownedStorageTypeRef *US) {
return visitAnyStorageTypeRef(US->getType(), ReferenceKind::Unowned);
}
const TypeInfo *visitWeakStorageTypeRef(const WeakStorageTypeRef *WS) {
return visitAnyStorageTypeRef(WS->getType(), ReferenceKind::Weak);
}
const TypeInfo *
visitUnmanagedStorageTypeRef(const UnmanagedStorageTypeRef *US) {
return visitAnyStorageTypeRef(US->getType(), ReferenceKind::Unmanaged);
}
const TypeInfo *visitOpaqueTypeRef(const OpaqueTypeRef *O) {
assert(false && "Can't lower opaque TypeRef");
return nullptr;
}
};
const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) {
auto found = Cache.find(TR);
if (found != Cache.end()) {
auto *TI = found->second;
assert(TI != nullptr && "TypeRef recursion detected");
return TI;
}
// Detect recursion
Cache[TR] = nullptr;
auto *TI = LowerType(*this).visit(TR);
// Cache the result
if (TI != nullptr)
Cache[TR] = TI;
return TI;
}
const TypeInfo *TypeConverter::getClassInstanceTypeInfo(const TypeRef *TR,
unsigned start,
unsigned align) {
const FieldDescriptor *FD = getBuilder().getFieldTypeInfo(TR);
if (FD == nullptr)
return nullptr;
switch (FD->Kind) {
case FieldDescriptorKind::Class: {
// Lower the class's fields using substitutions from the
// TypeRef to make field types concrete.
RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance);
// Start layout from the given instance start offset.
builder.addField(start, align);
for (auto Field : getBuilder().getFieldTypeRefs(TR, FD))
builder.addField(Field.first, Field.second);
return builder.build();
}
case FieldDescriptorKind::Struct:
case FieldDescriptorKind::Enum:
case FieldDescriptorKind::ObjCProtocol:
case FieldDescriptorKind::ClassProtocol:
case FieldDescriptorKind::Protocol:
// Invalid field descriptor.
return nullptr;
}
}