Skip to content

Commit 4071346

Browse files
authored
Merge pull request #9173 from slavapestov/anyobject-removal-vol-1
AnyObject removal volume 1
2 parents 98aae46 + 67b2354 commit 4071346

File tree

20 files changed

+159
-124
lines changed

20 files changed

+159
-124
lines changed

include/swift/AST/ExistentialLayout.h

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ namespace swift {
2828

2929
struct ExistentialLayout {
3030
ExistentialLayout() {
31-
requiresClass = false;
32-
requiresClassImplied = false;
31+
hasExplicitAnyObject = false;
3332
containsNonObjCProtocol = false;
3433
singleProtocol = nullptr;
3534
}
@@ -40,13 +39,8 @@ struct ExistentialLayout {
4039
/// The superclass constraint, if any.
4140
Type superclass;
4241

43-
/// Whether the existential requires a class, either via an explicit
44-
/// '& AnyObject' member or because of a superclass or protocol constraint.
45-
bool requiresClass : 1;
46-
47-
/// Whether the class constraint was implied by another constraint and therefore
48-
/// does not need to be stated explicitly.
49-
bool requiresClassImplied : 1;
42+
/// Whether the existential contains an explicit '& AnyObject' constraint.
43+
bool hasExplicitAnyObject : 1;
5044

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

5650
bool isObjC() const {
5751
// FIXME: Does the superclass have to be @objc?
58-
return requiresClass && !containsNonObjCProtocol;
52+
return ((superclass ||
53+
hasExplicitAnyObject ||
54+
getProtocols().size() > 0)
55+
&& !containsNonObjCProtocol);
5956
}
6057

58+
/// Whether the existential requires a class, either via an explicit
59+
/// '& AnyObject' member or because of a superclass or protocol constraint.
60+
bool requiresClass() const;
61+
6162
// Does this existential contain the Error protocol?
6263
bool isExistentialWithError(ASTContext &ctx) const;
6364

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ void ASTMangler::appendType(Type type) {
680680
if (layout.superclass) {
681681
appendType(layout.superclass);
682682
return appendOperator("Xc");
683-
} else if (layout.requiresClass & !layout.requiresClassImplied) {
683+
} else if (layout.hasExplicitAnyObject) {
684684
return appendOperator("Xl");
685685
}
686686
return appendOperator("p");

lib/AST/Decl.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/ASTWalker.h"
2222
#include "swift/AST/DiagnosticEngine.h"
2323
#include "swift/AST/DiagnosticsSema.h"
24+
#include "swift/AST/ExistentialLayout.h"
2425
#include "swift/AST/Expr.h"
2526
#include "swift/AST/ForeignErrorConvention.h"
2627
#include "swift/AST/GenericEnvironment.h"
@@ -2883,25 +2884,31 @@ bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
28832884
}
28842885

28852886
bool ProtocolDecl::requiresClassSlow() {
2886-
ProtocolDeclBits.RequiresClass =
2887-
walkInheritedProtocols([&](ProtocolDecl *proto) {
2888-
// If the 'requires class' bit is valid, we don't need to search any
2889-
// further.
2890-
if (proto->ProtocolDeclBits.RequiresClassValid) {
2891-
// If this protocol has a class requirement, we're done.
2892-
if (proto->ProtocolDeclBits.RequiresClass)
2893-
return TypeWalker::Action::Stop;
2894-
2895-
return TypeWalker::Action::SkipChildren;
2896-
}
2887+
// Set this first to catch (invalid) circular inheritance.
2888+
ProtocolDeclBits.RequiresClassValid = true;
28972889

2898-
// Quick check: @objc indicates that it requires a class.
2899-
if (proto->getAttrs().hasAttribute<ObjCAttr>() || proto->isObjC())
2900-
return TypeWalker::Action::Stop;
2890+
// Quick check: @objc protocols require a class.
2891+
if (isObjC()) {
2892+
ProtocolDeclBits.RequiresClass = true;
2893+
return true;
2894+
}
29012895

2902-
// Keep looking.
2903-
return TypeWalker::Action::Continue;
2904-
});
2896+
// Otherwise, check if the inheritance clause contains a
2897+
// class-constrained existential.
2898+
//
2899+
// FIXME: Use the requirement signature if available.
2900+
ProtocolDeclBits.RequiresClass = false;
2901+
for (auto inherited : getInherited()) {
2902+
auto type = inherited.getType();
2903+
assert(type && "Should have type checked inheritance clause by now");
2904+
if (type->isExistentialType()) {
2905+
auto layout = type->getExistentialLayout();
2906+
if (layout.requiresClass()) {
2907+
ProtocolDeclBits.RequiresClass = true;
2908+
return true;
2909+
}
2910+
}
2911+
}
29052912

29062913
return ProtocolDeclBits.RequiresClass;
29072914
}

lib/AST/DiagnosticEngine.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,19 @@ static bool isInterestingTypealias(Type type) {
322322
return false;
323323
if (type->is<BuiltinType>())
324324
return false;
325+
326+
auto underlyingTy = aliasTy->getDecl()->getUnderlyingTypeLoc().getType();
327+
328+
// A typealias that directly points at Builtin.AnyObject is not
329+
// 'interesting', since it is in fact the AnyObject typealias in
330+
// the standard library.
331+
if (underlyingTy->isAnyObject() &&
332+
isa<ProtocolCompositionType>(underlyingTy.getPointer()))
333+
return false;
334+
325335
if (aliasTy->getDecl()->isCompatibilityAlias())
326-
return isInterestingTypealias(aliasTy->getSinglyDesugaredType());
336+
return isInterestingTypealias(underlyingTy);
337+
327338
return true;
328339
}
329340

lib/AST/LayoutConstraint.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ StringRef LayoutConstraintInfo::getName(LayoutConstraintKind Kind) {
6060
case LayoutConstraintKind::UnknownLayout:
6161
return "_UnknownLayout";
6262
case LayoutConstraintKind::Class:
63-
return "_Class";
63+
return "AnyObject";
6464
case LayoutConstraintKind::NativeClass:
6565
return "_NativeClass";
6666
case LayoutConstraintKind::RefCountedObject:

lib/AST/LookupVisibleDecls.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,11 +471,6 @@ static void lookupVisibleProtocolMemberDecls(
471471
Type BaseTy, ProtocolType *PT, VisibleDeclConsumer &Consumer,
472472
const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason,
473473
LazyResolver *TypeResolver, VisitedSet &Visited) {
474-
if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
475-
// Handle AnyObject in a special way.
476-
doDynamicLookup(Consumer, CurrDC, LS, TypeResolver);
477-
return;
478-
}
479474
if (!Visited.insert(PT->getDecl()).second)
480475
return;
481476

@@ -527,6 +522,12 @@ static void lookupVisibleMemberDeclsImpl(
527522
return;
528523
}
529524

525+
// If the base is AnyObject, we are doing dynamic lookup.
526+
if (BaseTy->isAnyObject()) {
527+
doDynamicLookup(Consumer, CurrDC, LS, TypeResolver);
528+
return;
529+
}
530+
530531
// If the base is a protocol, enumerate its members.
531532
if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) {
532533
lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason,

lib/AST/Type.cpp

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,7 @@ ExistentialLayout::ExistentialLayout(ProtocolType *type) {
228228

229229
auto *protoDecl = type->getDecl();
230230

231-
if (protoDecl->requiresClass()) {
232-
requiresClass = true;
233-
requiresClassImplied = true;
234-
} else {
235-
requiresClass = false;
236-
requiresClassImplied = false;
237-
}
238-
231+
hasExplicitAnyObject = false;
239232
containsNonObjCProtocol =
240233
!(protoDecl->isSpecificProtocol(KnownProtocolKind::AnyObject) ||
241234
protoDecl->isObjC());
@@ -246,26 +239,18 @@ ExistentialLayout::ExistentialLayout(ProtocolType *type) {
246239
ExistentialLayout::ExistentialLayout(ProtocolCompositionType *type) {
247240
assert(type->isCanonical());
248241

249-
requiresClass = type->hasExplicitAnyObject();
250-
requiresClassImplied = false;
242+
hasExplicitAnyObject = type->hasExplicitAnyObject();
251243
containsNonObjCProtocol = false;
252244

253245
auto members = type->getMembers();
254246
if (!members.empty() &&
255247
isa<ClassDecl>(members[0]->getAnyNominal())) {
256248
superclass = members[0];
257249
members = members.slice(1);
258-
requiresClass = true;
259-
requiresClassImplied = true;
260250
}
261251

262252
for (auto member : members) {
263253
auto *protoDecl = member->castTo<ProtocolType>()->getDecl();
264-
if (protoDecl->requiresClass()) {
265-
requiresClass = true;
266-
requiresClassImplied = true;
267-
}
268-
269254
containsNonObjCProtocol |=
270255
!(protoDecl->isSpecificProtocol(KnownProtocolKind::AnyObject) ||
271256
protoDecl->isObjC());
@@ -291,10 +276,22 @@ ExistentialLayout CanType::getExistentialLayout() {
291276
return ExistentialLayout(comp);
292277
}
293278

279+
bool ExistentialLayout::requiresClass() const {
280+
if (hasExplicitAnyObject || superclass)
281+
return true;
282+
283+
for (auto proto : getProtocols()) {
284+
if (proto->requiresClass())
285+
return true;
286+
}
287+
288+
return false;
289+
}
290+
294291
bool ExistentialLayout::isAnyObject() const {
295292
// New implementation
296293
auto protocols = getProtocols();
297-
if (requiresClass && !requiresClassImplied && protocols.empty())
294+
if (hasExplicitAnyObject && !superclass && protocols.empty())
298295
return true;
299296

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

584581
bool ExistentialLayout::isErrorExistential() const {
585582
auto protocols = getProtocols();
586-
return (!requiresClass &&
583+
return (!hasExplicitAnyObject &&
584+
!superclass &&
587585
protocols.size() == 1 &&
588586
protocols[0]->getDecl()->isSpecificProtocol(KnownProtocolKind::Error));
589587
}
@@ -602,7 +600,7 @@ bool ExistentialLayout::isExistentialWithError(ASTContext &ctx) const {
602600
}
603601

604602
LayoutConstraint ExistentialLayout::getLayoutConstraint() const {
605-
if (requiresClass && !requiresClassImplied) {
603+
if (hasExplicitAnyObject) {
606604
return LayoutConstraint::getLayoutConstraint(
607605
LayoutConstraintKind::Class);
608606
}
@@ -2768,7 +2766,7 @@ bool ProtocolType::requiresClass() {
27682766
}
27692767

27702768
bool ProtocolCompositionType::requiresClass() {
2771-
return getExistentialLayout().requiresClass;
2769+
return getExistentialLayout().requiresClass();
27722770
}
27732771

27742772
Type ProtocolCompositionType::get(const ASTContext &C,
@@ -4015,7 +4013,7 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40154013
case TypeKind::Protocol:
40164014
case TypeKind::ProtocolComposition: {
40174015
auto layout = getExistentialLayout();
4018-
assert(layout.requiresClass && "Opaque existentials don't use refcounting");
4016+
assert(layout.requiresClass() && "Opaque existentials don't use refcounting");
40194017
if (layout.superclass)
40204018
return layout.superclass->usesNativeReferenceCounting(resilience);
40214019
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());

lib/Demangling/NodePrinter.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,10 @@ class NodePrinter {
278278
case Node::Kind::ProtocolList:
279279
return Node->getChild(0)->getNumChildren() <= 1;
280280

281-
case Node::Kind::ProtocolListWithClass:
282281
case Node::Kind::ProtocolListWithAnyObject:
282+
return Node->getChild(0)->getChild(0)->getNumChildren() == 0;
283+
284+
case Node::Kind::ProtocolListWithClass:
283285
case Node::Kind::Allocator:
284286
case Node::Kind::ArgumentTuple:
285287
case Node::Kind::AssociatedTypeMetadataAccessor:
@@ -628,7 +630,8 @@ class NodePrinter {
628630
static bool isExistentialType(NodePointer node) {
629631
return (node->getKind() == Node::Kind::ExistentialMetatype ||
630632
node->getKind() == Node::Kind::ProtocolList ||
631-
node->getKind() == Node::Kind::ProtocolListWithClass);
633+
node->getKind() == Node::Kind::ProtocolListWithClass ||
634+
node->getKind() == Node::Kind::ProtocolListWithAnyObject);
632635
}
633636

634637
/// Print the relevant parameters and return the new index.
@@ -1362,7 +1365,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
13621365
NodePointer superclass = Node->getChild(1);
13631366
print(superclass);
13641367
Printer << " & ";
1365-
printChildren(protocols, " & ");
1368+
if (protocols->getNumChildren() < 1)
1369+
return nullptr;
1370+
NodePointer type_list = protocols->getChild(0);
1371+
printChildren(type_list, " & ");
13661372
return nullptr;
13671373
}
13681374
case Node::Kind::ProtocolListWithAnyObject: {
@@ -1371,12 +1377,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
13711377
NodePointer protocols = Node->getChild(0);
13721378
if (protocols->getNumChildren() < 1)
13731379
return nullptr;
1374-
if (protocols->getChild(0)->getNumChildren() == 0) {
1375-
Printer << "AnyObject";
1376-
} else {
1377-
printChildren(protocols->getChild(0), " & ");
1378-
Printer << " & AnyObject";
1380+
NodePointer type_list = protocols->getChild(0);
1381+
if (type_list->getNumChildren() > 0) {
1382+
printChildren(type_list, " & ");
1383+
Printer << " & ";
13791384
}
1385+
if (Options.QualifyEntities)
1386+
Printer << "Swift.";
1387+
Printer << "AnyObject";
13801388
return nullptr;
13811389
}
13821390
case Node::Kind::AssociatedType:

lib/IRGen/GenCast.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,7 @@ void irgen::emitScalarExistentialDowncast(IRGenFunction &IGF,
521521
SmallVector<llvm::Value*, 4> objcProtos;
522522
SmallVector<llvm::Value*, 4> witnessTableProtos;
523523

524-
bool hasClassConstraint = layout.requiresClass;
524+
bool hasClassConstraint = layout.requiresClass();
525525
bool hasClassConstraintByProtocol = false;
526526

527527
bool hasSuperclassConstraint = bool(layout.superclass);

lib/IRGen/GenExistential.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1418,7 +1418,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
14181418

14191419
// If the existential is class, lower it to a class
14201420
// existential representation.
1421-
if (layout.requiresClass) {
1421+
if (layout.requiresClass()) {
14221422
// If we're not using the Objective-C runtime, we can use the
14231423
// native reference counting entry points.
14241424
ReferenceCounting refcounting = getReferenceCountingForType(IGM, T);

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ namespace {
951951
// Note: ProtocolClassConstraint::Class is 0, ::Any is 1.
952952
auto classConstraint =
953953
llvm::ConstantInt::get(IGF.IGM.Int1Ty,
954-
!layout.requiresClass);
954+
!layout.requiresClass());
955955
llvm::Value *superclassConstraint =
956956
llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy);
957957
if (layout.superclass) {

lib/Parse/ParseSIL.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1538,7 +1538,7 @@ collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc,
15381538
CanType protocolType) {
15391539
auto layout = protocolType.getExistentialLayout();
15401540

1541-
if (layout.requiresClass) {
1541+
if (layout.requiresClass()) {
15421542
if (!conformingType->mayHaveSuperclass() &&
15431543
!conformingType->isObjCExistentialType()) {
15441544
P.diagnose(loc, diag::sil_not_class, conformingType);

lib/SIL/SILType.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ SILType::getPreferredExistentialRepresentation(SILModule &M,
506506

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

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

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

545545
return repr == ExistentialRepresentation::Opaque;

lib/SIL/SILVerifier.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2707,10 +2707,10 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
27072707
"init_existential instruction must have the "
27082708
"right number of conformances");
27092709

2710-
if (layout.requiresClass) {
2710+
if (layout.requiresClass()) {
27112711
require(concreteType->mayHaveSuperclass() ||
27122712
(concreteType.isExistentialType() &&
2713-
concreteType.getExistentialLayout().requiresClass),
2713+
concreteType.getExistentialLayout().requiresClass()),
27142714
"init_existential of class existential with non-class type");
27152715
}
27162716

0 commit comments

Comments
 (0)