Skip to content
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