Skip to content

Tiny bit more progress on IRGen support for subclass existentials #8788

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 18, 2017
Merged
5 changes: 4 additions & 1 deletion include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,10 @@ ERROR(sil_member_decl_type_mismatch,none,
"member defined with mismatching type %0 (expected %1)", (Type, Type))
ERROR(sil_substitution_mismatch,none,
"substitution replacement type %0 does not conform to protocol %1",
(Type, DeclName))
(Type, Type))
ERROR(sil_not_class,none,
"substitution replacement type %0 is not a class type",
(Type))
ERROR(sil_missing_substitutions,none,
"missing substitutions", ())
ERROR(sil_too_many_substitutions,none,
Expand Down
7 changes: 0 additions & 7 deletions include/swift/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,6 @@ class CanType : public Type {
static bool isReferenceTypeImpl(CanType type, bool functionsCount);
static bool isExistentialTypeImpl(CanType type);
static bool isAnyExistentialTypeImpl(CanType type);
static void getExistentialTypeProtocolsImpl(CanType type,
SmallVectorImpl<ProtocolDecl*> &protocols);
static bool isObjCExistentialTypeImpl(CanType type);
static CanType getAnyOptionalObjectTypeImpl(CanType type,
OptionalTypeKind &kind);
Expand Down Expand Up @@ -406,11 +404,6 @@ class CanType : public Type {
return isAnyExistentialTypeImpl(*this);
}

/// Given that this type is an existential, return its
/// protocols in a canonical order.
void getExistentialTypeProtocols(
SmallVectorImpl<ProtocolDecl *> &protocols);

/// Break an existential down into a set of constraints.
ExistentialLayout getExistentialLayout();

Expand Down
4 changes: 0 additions & 4 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,6 @@ class alignas(1 << TypeAlignInBits) TypeBase {
/// bound.
bool isClassExistentialType();

/// Given that this type is an existential type, produce
/// its list of protocols.
void getExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);

/// Break an existential down into a set of constraints.
ExistentialLayout getExistentialLayout();

Expand Down
9 changes: 4 additions & 5 deletions lib/AST/ASTVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,11 +1128,10 @@ class Verifier : public ASTWalker {
abort();
}

SmallVector<ProtocolDecl*, 1> protocols;
srcTy->getExistentialTypeProtocols(protocols);

if (protocols.size() != 1
|| !protocols[0]->isObjC()) {
auto layout = srcTy->getExistentialLayout();
if (layout.superclass ||
!layout.isObjC() ||
layout.getProtocols().size() != 1) {
Out << "ProtocolMetatypeToObject with non-ObjC-protocol metatype:\n";
E->print(Out);
Out << "\n";
Expand Down
37 changes: 14 additions & 23 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,22 +208,6 @@ bool TypeBase::allowsOwnership() {
return getCanonicalType().isAnyClassReferenceType();
}

void TypeBase::getExistentialTypeProtocols(
SmallVectorImpl<ProtocolDecl*> &protocols) {
getCanonicalType().getExistentialTypeProtocols(protocols);
}

void CanType::getExistentialTypeProtocols(
SmallVectorImpl<ProtocolDecl*> &protocols) {
// FIXME: Remove this completely
auto layout = getExistentialLayout();
assert(!layout.superclass && "Subclass existentials not fully supported yet");
assert((!layout.requiresClass || layout.requiresClassImplied) &&
"Explicit AnyObject should not appear yet");
for (auto proto : layout.getProtocols())
protocols.push_back(proto->getDecl());
}

ExistentialLayout::ExistentialLayout(ProtocolType *type) {
assert(type->isCanonical());

Expand Down Expand Up @@ -2637,7 +2621,7 @@ void ArchetypeType::populateNestedTypes() const {
ProtocolType::visitAllProtocols(getConformsTo(),
[&](ProtocolDecl *proto) -> bool {
// Objective-C protocols don't have type members.
if (proto->hasClangNode()) return false;
if (proto->isObjC()) return false;

for (auto member : proto->getMembers()) {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member)) {
Expand Down Expand Up @@ -3977,7 +3961,6 @@ static bool doesOpaqueClassUseNativeReferenceCounting(const ASTContext &ctx) {

static bool usesNativeReferenceCounting(ClassDecl *theClass,
ResilienceExpansion resilience) {
// NOTE: if you change this, change irgen::getReferenceCountingForClass.
// TODO: Resilience? there might be some legal avenue of changing this.
while (Type supertype = theClass->getSuperclass()) {
theClass = supertype->getClassOrBoundGenericClass();
Expand All @@ -3987,8 +3970,6 @@ static bool usesNativeReferenceCounting(ClassDecl *theClass,
}

bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
assert(allowsOwnership());

CanType type = getCanonicalType();
switch (type->getKind()) {
#define SUGARED_TYPE(id, parent) case TypeKind::id:
Expand All @@ -4011,24 +3992,34 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
return ::usesNativeReferenceCounting(
cast<BoundGenericClassType>(type)->getDecl(),
resilience);
case TypeKind::UnboundGeneric:
return ::usesNativeReferenceCounting(
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()),
resilience);

case TypeKind::DynamicSelf:
return cast<DynamicSelfType>(type).getSelfType()
->usesNativeReferenceCounting(resilience);

case TypeKind::Archetype: {
auto archetype = cast<ArchetypeType>(type);
assert(archetype->requiresClass());
auto layout = archetype->getLayoutConstraint();
assert(archetype->requiresClass() ||
(layout && layout->isRefCounted()));
if (auto supertype = archetype->getSuperclass())
return supertype->usesNativeReferenceCounting(resilience);
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
}

case TypeKind::Protocol:
case TypeKind::ProtocolComposition:
case TypeKind::ProtocolComposition: {
auto layout = getExistentialLayout();
assert(layout.requiresClass && "Opaque existentials don't use refcounting");
if (layout.superclass)
return layout.superclass->usesNativeReferenceCounting(resilience);
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
}

case TypeKind::UnboundGeneric:
case TypeKind::Function:
case TypeKind::GenericFunction:
case TypeKind::SILFunction:
Expand Down
16 changes: 10 additions & 6 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "swift/AST/Builtins.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsClangImporter.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignature.h"
Expand Down Expand Up @@ -4742,12 +4743,15 @@ static bool inheritanceListContainsProtocol(ArrayRef<TypeLoc> inherited,
return llvm::any_of(inherited, [proto](TypeLoc type) -> bool {
if (!type.getType()->isExistentialType())
return false;
SmallVector<ProtocolDecl *, 8> protos;
type.getType()->getExistentialTypeProtocols(protos);
return ProtocolType::visitAllProtocols(protos,
[proto](const ProtocolDecl *next) {
return next == proto;
});

auto layout = type.getType()->getExistentialLayout();
for (auto protoTy : layout.getProtocols()) {
auto *protoDecl = protoTy->getDecl();
if (protoDecl == proto || protoDecl->inheritsFrom(proto))
return true;
}

return false;
});
}

Expand Down
19 changes: 14 additions & 5 deletions lib/FrontendTool/ReferenceDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Module.h"
#include "swift/AST/ModuleLoader.h"
#include "swift/AST/NameLookup.h"
Expand Down Expand Up @@ -85,18 +86,24 @@ static bool declIsPrivate(const Decl *member) {
}

static bool extendedTypeIsPrivate(TypeLoc inheritedType) {
if (!inheritedType.getType())
auto type = inheritedType.getType();
if (!type)
return true;

if (!inheritedType.getType()->isExistentialType()) {
if (!type->isExistentialType()) {
// Be conservative. We don't know how to deal with other extended types.
return false;
}

SmallVector<ProtocolDecl *, 2> protocols;
inheritedType.getType()->getExistentialTypeProtocols(protocols);
auto layout = type->getExistentialLayout();
assert(!layout.superclass && "Should not have a subclass existential "
"in the inheritance clause of an extension");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion isn't valid; this code runs even when type-checking fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a test case in mind I can try? I'll address this in an upcoming patch along with the other stuff above about spare bits.

Copy link
Contributor

@jrose-apple jrose-apple Apr 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think even just the obvious thing would crash:

// compile with -emit-reference-dependencies and check the resulting swiftdeps file
class MyClass {}
extension Int: (MyClass & Equatable) {}

for (auto protoTy : layout.getProtocols()) {
if (!declIsPrivate(protoTy->getDecl()))
return false;
}

return std::all_of(protocols.begin(), protocols.end(), declIsPrivate);
return true;
}

static std::string mangleTypeAsContext(const NominalTypeDecl *type) {
Expand Down Expand Up @@ -172,6 +179,8 @@ bool swift::emitReferenceDependencies(DiagnosticEngine &diags,
break;
}

// Check if the extension is just adding members, or if it is
// introducing a conformance to a public protocol.
bool justMembers = std::all_of(ED->getInherited().begin(),
ED->getInherited().end(),
extendedTypeIsPrivate);
Expand Down
34 changes: 15 additions & 19 deletions lib/IRGen/GenArchetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,32 +277,28 @@ llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
assert(isExemplarArchetype(archetype) && "lowering non-exemplary archetype");

LayoutConstraint LayoutInfo = archetype->getLayoutConstraint();
auto layout = archetype->getLayoutConstraint();

// If the archetype is class-constrained, use a class pointer
// representation.
if (archetype->requiresClass() ||
(LayoutInfo && LayoutInfo->isRefCounted())) {
ReferenceCounting refcount;
llvm::PointerType *reprTy;
(layout && layout->isRefCounted())) {
auto refcount = getReferenceCountingForType(IGM, CanType(archetype));

if (!IGM.ObjCInterop) {
refcount = ReferenceCounting::Native;
reprTy = IGM.RefCountedPtrTy;
} else {
refcount = ReferenceCounting::Unknown;
reprTy = IGM.UnknownRefCountedPtrTy;
}
llvm::PointerType *reprTy;

// If the archetype has a superclass constraint, it has at least the
// retain semantics of its superclass, and it can be represented with
// the supertype's pointer type.
if (Type super = archetype->getSuperclass()) {
ClassDecl *superClass = super->getClassOrBoundGenericClass();
refcount = getReferenceCountingForClass(IGM, superClass);

if (auto super = archetype->getSuperclass()) {
auto &superTI = IGM.getTypeInfoForUnlowered(super);
reprTy = cast<llvm::PointerType>(superTI.StorageType);
} else {
if (refcount == ReferenceCounting::Native) {
reprTy = IGM.RefCountedPtrTy;
} else {
reprTy = IGM.UnknownRefCountedPtrTy;
}
}

// As a hack, assume class archetypes never have spare bits. There's a
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jckarter @rjmccall This hack doesn't make sense -- we should just use the spare bits from the superclass constraint, if any, otherwise the spare bits of an unknown pointer, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that would work and be a bit more optimal. If we don't already, we should also check the @_unsafe_no_tagged_pointer attribute and whether ObjC interop is enabled at all.

Expand All @@ -320,9 +316,9 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {

// If the archetype is trivial fixed-size layout-constrained, use a fixed size
// representation.
if (LayoutInfo && LayoutInfo->isFixedSizeTrivial()) {
Size size(LayoutInfo->getTrivialSizeInBytes());
Alignment align(LayoutInfo->getTrivialSizeInBytes());
if (layout && layout->isFixedSizeTrivial()) {
Size size(layout->getTrivialSizeInBytes());
Alignment align(layout->getTrivialSizeInBytes());
auto spareBits =
SpareBitVector::getConstant(size.getValueInBits(), false);
// Get an integer type of the required size.
Expand All @@ -336,7 +332,7 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
// If the archetype is a trivial layout-constrained, use a POD
// representation. This type is not loadable, but it is known
// to be a POD.
if (LayoutInfo && LayoutInfo->isAddressOnlyTrivial()) {
if (layout && layout->isAddressOnlyTrivial()) {
// TODO: Create NonFixedSizeArchetypeTypeInfo and return it.
}

Expand Down
23 changes: 14 additions & 9 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,25 @@ static ClassDecl *getRootClass(ClassDecl *theClass) {
return theClass;
}

/// What reference counting mechanism does a class have?
ReferenceCounting irgen::getReferenceCountingForClass(IRGenModule &IGM,
ClassDecl *theClass) {
/// What reference counting mechanism does a class-like type have?
ReferenceCounting irgen::getReferenceCountingForType(IRGenModule &IGM,
CanType type) {
// If ObjC interop is disabled, we have a Swift refcount.
if (!IGM.ObjCInterop)
return ReferenceCounting::Native;

// NOTE: if you change this, change Type::usesNativeReferenceCounting.
// If the root class is implemented in swift, then we have a swift
// refcount; otherwise, we have an ObjC refcount.
if (getRootClass(theClass)->hasKnownSwiftImplementation())
if (type->usesNativeReferenceCounting(ResilienceExpansion::Maximal))
return ReferenceCounting::Native;

return ReferenceCounting::ObjC;
// Class-constrained archetypes and existentials that don't use
// native reference counting and yet have a superclass must be
// using ObjC reference counting.
auto superclass = type->getSuperclass(nullptr);
if (superclass)
return ReferenceCounting::ObjC;

// Otherwise, it could be either one.
return ReferenceCounting::Unknown;
}

/// What isa encoding mechanism does a type have?
Expand Down Expand Up @@ -2087,7 +2092,7 @@ const TypeInfo *
TypeConverter::convertClassType(CanType type, ClassDecl *D) {
llvm::StructType *ST = IGM.createNominalType(type);
llvm::PointerType *irType = ST->getPointerTo();
ReferenceCounting refcount = ::getReferenceCountingForClass(IGM, D);
ReferenceCounting refcount = ::getReferenceCountingForType(IGM, type);

SpareBitVector spareBits;

Expand Down
10 changes: 5 additions & 5 deletions lib/IRGen/GenClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,11 @@ namespace irgen {
/// correspond to the runtime alignment of instances of the class.
llvm::Constant *tryEmitClassConstantFragileInstanceAlignMask(IRGenModule &IGM,
ClassDecl *theClass);
/// What reference counting mechanism does a class use?
ReferenceCounting getReferenceCountingForClass(IRGenModule &IGM,
ClassDecl *theClass);

/// What reference counting mechanism does a class-like type use?
ReferenceCounting getReferenceCountingForType(IRGenModule &IGM,
CanType type);

/// What isa-encoding mechanism does a type use?
IsaEncoding getIsaEncodingForType(IRGenModule &IGM, CanType type);

Expand Down
Loading