Skip to content

AnyObject removal volume 1 #9173

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
May 2, 2017
21 changes: 11 additions & 10 deletions include/swift/AST/ExistentialLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ namespace swift {

struct ExistentialLayout {
ExistentialLayout() {
requiresClass = false;
requiresClassImplied = false;
hasExplicitAnyObject = false;
containsNonObjCProtocol = false;
singleProtocol = nullptr;
}
Expand All @@ -40,13 +39,8 @@ struct ExistentialLayout {
/// The superclass constraint, if any.
Type superclass;

/// Whether the existential requires a class, either via an explicit
/// '& AnyObject' member or because of a superclass or protocol constraint.
bool requiresClass : 1;

/// Whether the class constraint was implied by another constraint and therefore
/// does not need to be stated explicitly.
bool requiresClassImplied : 1;
/// Whether the existential contains an explicit '& AnyObject' constraint.
bool hasExplicitAnyObject : 1;

/// Whether any protocol members are non-@objc.
bool containsNonObjCProtocol : 1;
Expand All @@ -55,9 +49,16 @@ struct ExistentialLayout {

bool isObjC() const {
// FIXME: Does the superclass have to be @objc?
return requiresClass && !containsNonObjCProtocol;
return ((superclass ||
hasExplicitAnyObject ||
getProtocols().size() > 0)
&& !containsNonObjCProtocol);
}

/// Whether the existential requires a class, either via an explicit
/// '& AnyObject' member or because of a superclass or protocol constraint.
bool requiresClass() const;

// Does this existential contain the Error protocol?
bool isExistentialWithError(ASTContext &ctx) const;

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ void ASTMangler::appendType(Type type) {
if (layout.superclass) {
appendType(layout.superclass);
return appendOperator("Xc");
} else if (layout.requiresClass & !layout.requiresClassImplied) {
} else if (layout.hasExplicitAnyObject) {
return appendOperator("Xl");
}
return appendOperator("p");
Expand Down
41 changes: 24 additions & 17 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/AST/ASTWalker.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/Expr.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
Expand Down Expand Up @@ -2883,25 +2884,31 @@ bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
}

bool ProtocolDecl::requiresClassSlow() {
ProtocolDeclBits.RequiresClass =
walkInheritedProtocols([&](ProtocolDecl *proto) {
// If the 'requires class' bit is valid, we don't need to search any
// further.
if (proto->ProtocolDeclBits.RequiresClassValid) {
// If this protocol has a class requirement, we're done.
if (proto->ProtocolDeclBits.RequiresClass)
return TypeWalker::Action::Stop;

return TypeWalker::Action::SkipChildren;
}
// Set this first to catch (invalid) circular inheritance.
ProtocolDeclBits.RequiresClassValid = true;

// Quick check: @objc indicates that it requires a class.
if (proto->getAttrs().hasAttribute<ObjCAttr>() || proto->isObjC())
return TypeWalker::Action::Stop;
// Quick check: @objc protocols require a class.
if (isObjC()) {
ProtocolDeclBits.RequiresClass = true;
return true;
}

// Keep looking.
return TypeWalker::Action::Continue;
});
// Otherwise, check if the inheritance clause contains a
// class-constrained existential.
//
// FIXME: Use the requirement signature if available.
ProtocolDeclBits.RequiresClass = false;
for (auto inherited : getInherited()) {
auto type = inherited.getType();
assert(type && "Should have type checked inheritance clause by now");
if (type->isExistentialType()) {
auto layout = type->getExistentialLayout();
if (layout.requiresClass()) {
ProtocolDeclBits.RequiresClass = true;
return true;
}
}
}

return ProtocolDeclBits.RequiresClass;
}
Expand Down
13 changes: 12 additions & 1 deletion lib/AST/DiagnosticEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,19 @@ static bool isInterestingTypealias(Type type) {
return false;
if (type->is<BuiltinType>())
return false;

auto underlyingTy = aliasTy->getDecl()->getUnderlyingTypeLoc().getType();

// A typealias that directly points at Builtin.AnyObject is not
// 'interesting', since it is in fact the AnyObject typealias in
// the standard library.
if (underlyingTy->isAnyObject() &&
isa<ProtocolCompositionType>(underlyingTy.getPointer()))
return false;

if (aliasTy->getDecl()->isCompatibilityAlias())
return isInterestingTypealias(aliasTy->getSinglyDesugaredType());
return isInterestingTypealias(underlyingTy);

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/AST/LayoutConstraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind) {
case LayoutConstraintKind::UnknownLayout:
return "_UnknownLayout";
case LayoutConstraintKind::Class:
return "_Class";
return "AnyObject";
case LayoutConstraintKind::NativeClass:
return "_NativeClass";
case LayoutConstraintKind::RefCountedObject:
Expand Down
11 changes: 6 additions & 5 deletions lib/AST/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,6 @@ static void lookupVisibleProtocolMemberDecls(
Type BaseTy, ProtocolType *PT, VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason,
LazyResolver *TypeResolver, VisitedSet &Visited) {
if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
// Handle AnyObject in a special way.
doDynamicLookup(Consumer, CurrDC, LS, TypeResolver);
return;
}
if (!Visited.insert(PT->getDecl()).second)
return;

Expand Down Expand Up @@ -527,6 +522,12 @@ static void lookupVisibleMemberDeclsImpl(
return;
}

// If the base is AnyObject, we are doing dynamic lookup.
if (BaseTy->isAnyObject()) {
doDynamicLookup(Consumer, CurrDC, LS, TypeResolver);
return;
}

// If the base is a protocol, enumerate its members.
if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) {
lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason,
Expand Down
42 changes: 20 additions & 22 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,7 @@ ExistentialLayout::ExistentialLayout(ProtocolType *type) {

auto *protoDecl = type->getDecl();

if (protoDecl->requiresClass()) {
requiresClass = true;
requiresClassImplied = true;
} else {
requiresClass = false;
requiresClassImplied = false;
}

hasExplicitAnyObject = false;
containsNonObjCProtocol =
!(protoDecl->isSpecificProtocol(KnownProtocolKind::AnyObject) ||
protoDecl->isObjC());
Expand All @@ -246,26 +239,18 @@ ExistentialLayout::ExistentialLayout(ProtocolType *type) {
ExistentialLayout::ExistentialLayout(ProtocolCompositionType *type) {
assert(type->isCanonical());

requiresClass = type->hasExplicitAnyObject();
requiresClassImplied = false;
hasExplicitAnyObject = type->hasExplicitAnyObject();
containsNonObjCProtocol = false;

auto members = type->getMembers();
if (!members.empty() &&
isa<ClassDecl>(members[0]->getAnyNominal())) {
superclass = members[0];
members = members.slice(1);
requiresClass = true;
requiresClassImplied = true;
}

for (auto member : members) {
auto *protoDecl = member->castTo<ProtocolType>()->getDecl();
if (protoDecl->requiresClass()) {
requiresClass = true;
requiresClassImplied = true;
}

containsNonObjCProtocol |=
!(protoDecl->isSpecificProtocol(KnownProtocolKind::AnyObject) ||
protoDecl->isObjC());
Expand All @@ -291,10 +276,22 @@ ExistentialLayout CanType::getExistentialLayout() {
return ExistentialLayout(comp);
}

bool ExistentialLayout::requiresClass() const {
if (hasExplicitAnyObject || superclass)
return true;

for (auto proto : getProtocols()) {
if (proto->requiresClass())
return true;
}

return false;
}

bool ExistentialLayout::isAnyObject() const {
// New implementation
auto protocols = getProtocols();
if (requiresClass && !requiresClassImplied && protocols.empty())
if (hasExplicitAnyObject && !superclass && protocols.empty())
return true;

// Old implementation -- FIXME: remove this
Expand Down Expand Up @@ -583,7 +580,8 @@ bool TypeBase::isAnyObject() {

bool ExistentialLayout::isErrorExistential() const {
auto protocols = getProtocols();
return (!requiresClass &&
return (!hasExplicitAnyObject &&
!superclass &&
protocols.size() == 1 &&
protocols[0]->getDecl()->isSpecificProtocol(KnownProtocolKind::Error));
}
Expand All @@ -602,7 +600,7 @@ bool ExistentialLayout::isExistentialWithError(ASTContext &ctx) const {
}

LayoutConstraint ExistentialLayout::getLayoutConstraint() const {
if (requiresClass && !requiresClassImplied) {
if (hasExplicitAnyObject) {
return LayoutConstraint::getLayoutConstraint(
LayoutConstraintKind::Class);
}
Expand Down Expand Up @@ -2768,7 +2766,7 @@ bool ProtocolType::requiresClass() {
}

bool ProtocolCompositionType::requiresClass() {
return getExistentialLayout().requiresClass;
return getExistentialLayout().requiresClass();
}

Type ProtocolCompositionType::get(const ASTContext &C,
Expand Down Expand Up @@ -4015,7 +4013,7 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
case TypeKind::Protocol:
case TypeKind::ProtocolComposition: {
auto layout = getExistentialLayout();
assert(layout.requiresClass && "Opaque existentials don't use refcounting");
assert(layout.requiresClass() && "Opaque existentials don't use refcounting");
if (layout.superclass)
return layout.superclass->usesNativeReferenceCounting(resilience);
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
Expand Down
24 changes: 16 additions & 8 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,10 @@ class NodePrinter {
case Node::Kind::ProtocolList:
return Node->getChild(0)->getNumChildren() <= 1;

case Node::Kind::ProtocolListWithClass:
case Node::Kind::ProtocolListWithAnyObject:
return Node->getChild(0)->getChild(0)->getNumChildren() == 0;

case Node::Kind::ProtocolListWithClass:
case Node::Kind::Allocator:
case Node::Kind::ArgumentTuple:
case Node::Kind::AssociatedTypeMetadataAccessor:
Expand Down Expand Up @@ -628,7 +630,8 @@ class NodePrinter {
static bool isExistentialType(NodePointer node) {
return (node->getKind() == Node::Kind::ExistentialMetatype ||
node->getKind() == Node::Kind::ProtocolList ||
node->getKind() == Node::Kind::ProtocolListWithClass);
node->getKind() == Node::Kind::ProtocolListWithClass ||
node->getKind() == Node::Kind::ProtocolListWithAnyObject);
}

/// Print the relevant parameters and return the new index.
Expand Down Expand Up @@ -1362,7 +1365,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
NodePointer superclass = Node->getChild(1);
print(superclass);
Printer << " & ";
printChildren(protocols, " & ");
if (protocols->getNumChildren() < 1)
return nullptr;
NodePointer type_list = protocols->getChild(0);
printChildren(type_list, " & ");
return nullptr;
}
case Node::Kind::ProtocolListWithAnyObject: {
Expand All @@ -1371,12 +1377,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
NodePointer protocols = Node->getChild(0);
if (protocols->getNumChildren() < 1)
return nullptr;
if (protocols->getChild(0)->getNumChildren() == 0) {
Printer << "AnyObject";
} else {
printChildren(protocols->getChild(0), " & ");
Printer << " & AnyObject";
NodePointer type_list = protocols->getChild(0);
if (type_list->getNumChildren() > 0) {
printChildren(type_list, " & ");
Printer << " & ";
}
if (Options.QualifyEntities)
Printer << "Swift.";
Printer << "AnyObject";
return nullptr;
}
case Node::Kind::AssociatedType:
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
SmallVector<llvm::Value*, 4> objcProtos;
SmallVector<llvm::Value*, 4> witnessTableProtos;

bool hasClassConstraint = layout.requiresClass;
bool hasClassConstraint = layout.requiresClass();
bool hasClassConstraintByProtocol = false;

bool hasSuperclassConstraint = bool(layout.superclass);
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1418,7 +1418,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {

// If the existential is class, lower it to a class
// existential representation.
if (layout.requiresClass) {
if (layout.requiresClass()) {
// If we're not using the Objective-C runtime, we can use the
// native reference counting entry points.
ReferenceCounting refcounting = getReferenceCountingForType(IGM, T);
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ namespace {
// Note: ProtocolClassConstraint::Class is 0, ::Any is 1.
auto classConstraint =
llvm::ConstantInt::get(IGF.IGM.Int1Ty,
!layout.requiresClass);
!layout.requiresClass());
llvm::Value *superclassConstraint =
llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy);
if (layout.superclass) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc,
CanType protocolType) {
auto layout = protocolType.getExistentialLayout();

if (layout.requiresClass) {
if (layout.requiresClass()) {
if (!conformingType->mayHaveSuperclass() &&
!conformingType->isObjCExistentialType()) {
P.diagnose(loc, diag::sil_not_class, conformingType);
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/SILType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ SILType::getPreferredExistentialRepresentation(SILModule &M,

// A class-constrained protocol composition can adopt the conforming
// class reference directly.
if (layout.requiresClass)
if (layout.requiresClass())
return ExistentialRepresentation::Class;

// Otherwise, we need to use a fixed-sized buffer.
Expand Down Expand Up @@ -539,7 +539,7 @@ SILType::canUseExistentialRepresentation(SILModule &M,

// A class-constrained composition uses ClassReference representation;
// otherwise, we use a fixed-sized buffer.
if (layout.requiresClass)
if (layout.requiresClass())
return repr == ExistentialRepresentation::Class;

return repr == ExistentialRepresentation::Opaque;
Expand Down
4 changes: 2 additions & 2 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2707,10 +2707,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
"init_existential instruction must have the "
"right number of conformances");

if (layout.requiresClass) {
if (layout.requiresClass()) {
require(concreteType->mayHaveSuperclass() ||
(concreteType.isExistentialType() &&
concreteType.getExistentialLayout().requiresClass),
concreteType.getExistentialLayout().requiresClass()),
"init_existential of class existential with non-class type");
}

Expand Down
Loading