Skip to content

Commit 9c3b514

Browse files
committed
AST: New getExistentialLayout() method on TypeBase and CanType
This consolidates calculations which need to look at every protocol in an existential type. Soon we will also have to deal with superclass constrained existentials, so start updating call sites that look at all protocols to use the new ExistentialLayout and correctly handle a class constraint as well. Also, eventually I will kill off the AnyObject protocol and model it as a protocol composition with no protocols or superclass, but the requiresClass() flag set. This is not quite modeled this way yet and AnyObject still exists, but the new abstraction is a step in the right direction.
1 parent 95e2802 commit 9c3b514

File tree

10 files changed

+297
-134
lines changed

10 files changed

+297
-134
lines changed

include/swift/AST/ExistentialLayout.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//===--- ExistentialLayout.h - Existential type decomposition ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines the ExistentialLayout struct.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_EXISTENTIAL_LAYOUT_H
18+
#define SWIFT_EXISTENTIAL_LAYOUT_H
19+
20+
#include "swift/AST/ASTContext.h"
21+
#include "swift/AST/Type.h"
22+
#include "llvm/ADT/SmallVector.h"
23+
24+
namespace swift {
25+
class ProtocolDecl;
26+
class ProtocolType;
27+
class ProtocolCompositionType;
28+
29+
struct ExistentialLayout {
30+
ExistentialLayout() {
31+
requiresClass = false;
32+
requiresClassImplied = false;
33+
containsNonObjCProtocol = false;
34+
singleProtocol = nullptr;
35+
}
36+
37+
ExistentialLayout(ProtocolType *type);
38+
ExistentialLayout(ProtocolCompositionType *type);
39+
40+
/// The superclass constraint, if any.
41+
Type superclass;
42+
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;
50+
51+
/// Whether any protocol members are non-@objc.
52+
bool containsNonObjCProtocol : 1;
53+
54+
bool isAnyObject() const;
55+
56+
bool isObjC() const {
57+
// FIXME: Does the superclass have to be @objc?
58+
return requiresClass && !containsNonObjCProtocol;
59+
}
60+
61+
bool isExistentialWithError(ASTContext &ctx) const;
62+
63+
ArrayRef<ProtocolType *> getProtocols() const {
64+
if (singleProtocol)
65+
return ArrayRef<ProtocolType *>{&singleProtocol, 1};
66+
return multipleProtocols;
67+
}
68+
69+
private:
70+
// Inline storage for 'protocols' member above when computing
71+
// layout of a single ProtocolType
72+
ProtocolType *singleProtocol;
73+
74+
/// Zero or more protocol constraints.
75+
ArrayRef<ProtocolType *> multipleProtocols;
76+
};
77+
78+
}
79+
80+
#endif // SWIFT_EXISTENTIAL_LAYOUT_H

include/swift/AST/Type.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class SubstitutionMap;
5151
class TypeBase;
5252
class Type;
5353
class TypeWalker;
54+
struct ExistentialLayout;
5455

5556
/// \brief Type substitution mapping from substitutable types to their
5657
/// replacements.
@@ -410,16 +411,15 @@ class CanType : public Type {
410411
/// Given that this type is an existential, return its
411412
/// protocols in a canonical order.
412413
void getExistentialTypeProtocols(
413-
SmallVectorImpl<ProtocolDecl *> &protocols) {
414-
return getExistentialTypeProtocolsImpl(*this, protocols);
415-
}
414+
SmallVectorImpl<ProtocolDecl *> &protocols);
416415

417416
/// Given that this type is any kind of existential, return its
418417
/// protocols in a canonical order.
419418
void getAnyExistentialTypeProtocols(
420-
SmallVectorImpl<ProtocolDecl *> &protocols) {
421-
return getAnyExistentialTypeProtocolsImpl(*this, protocols);
422-
}
419+
SmallVectorImpl<ProtocolDecl *> &protocols);
420+
421+
/// Break an existential down into a set of constraints.
422+
ExistentialLayout getExistentialLayout();
423423

424424
/// Is this an ObjC-compatible existential type?
425425
bool isObjCExistentialType() const {

include/swift/AST/Types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,9 @@ class alignas(1 << TypeAlignInBits) TypeBase {
584584
/// its list of protocols.
585585
void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);
586586

587+
/// Break an existential down into a set of constraints.
588+
ExistentialLayout getExistentialLayout();
589+
587590
/// Determines the element type of a known *UnsafeMutablePointer
588591
/// variant, or returns null if the type is not a pointer.
589592
Type getAnyPointerElementType(PointerTypeKind &PTK);

lib/AST/ASTContext.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/ASTContext.h"
1818
#include "ForeignRepresentationInfo.h"
1919
#include "swift/Strings.h"
20+
#include "swift/AST/ExistentialLayout.h"
2021
#include "swift/AST/GenericSignatureBuilder.h"
2122
#include "swift/AST/ConcreteDeclRef.h"
2223
#include "swift/AST/DiagnosticEngine.h"
@@ -3454,19 +3455,22 @@ CanArchetypeType ArchetypeType::getOpened(Type existential,
34543455
knownID = UUID::fromTime();
34553456
}
34563457

3457-
llvm::SmallVector<ProtocolDecl *, 4> conformsTo;
3458-
assert(existential->isExistentialType());
3459-
existential->getExistentialTypeProtocols(conformsTo);
3460-
Type superclass = existential->getSuperclass(nullptr);
3458+
auto layout = existential->getExistentialLayout();
3459+
3460+
SmallVector<ProtocolDecl *, 2> protos;
3461+
for (auto proto : layout.getProtocols())
3462+
protos.push_back(proto->getDecl());
34613463

34623464
auto arena = AllocationArena::Permanent;
34633465
void *mem = ctx.Allocate(
34643466
totalSizeToAlloc<ProtocolDecl *, Type, LayoutConstraint, UUID>(
3465-
conformsTo.size(), superclass ? 1 : 0, 0, 1),
3467+
protos.size(), layout.superclass ? 1 : 0, 0, 1),
34663468
alignof(ArchetypeType), arena);
34673469

3470+
// FIXME: Pass in class layout constraint
34683471
auto result =
3469-
::new (mem) ArchetypeType(ctx, existential, conformsTo, superclass,
3472+
::new (mem) ArchetypeType(ctx, existential,
3473+
protos, layout.superclass,
34703474
existential->getLayoutConstraint(), *knownID);
34713475
openedExistentialArchetypes[*knownID] = result;
34723476

lib/AST/Module.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/ASTWalker.h"
2323
#include "swift/AST/Builtins.h"
2424
#include "swift/AST/DiagnosticsSema.h"
25+
#include "swift/AST/ExistentialLayout.h"
2526
#include "swift/AST/GenericEnvironment.h"
2627
#include "swift/AST/LazyResolver.h"
2728
#include "swift/AST/LinkLibrary.h"
@@ -586,6 +587,7 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol,
586587
}
587588
}
588589

590+
// FIXME: This will go away soon.
589591
if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
590592
if (archetype->requiresClass())
591593
return ProtocolConformanceRef(protocol);
@@ -605,35 +607,38 @@ ModuleDecl::lookupConformance(Type type, ProtocolDecl *protocol,
605607
// existential's list of conformances and the existential conforms to
606608
// itself.
607609
if (type->isExistentialType()) {
608-
SmallVector<ProtocolDecl *, 4> protocols;
609-
type->getExistentialTypeProtocols(protocols);
610-
611-
// Due to an IRGen limitation, witness tables cannot be passed from an
612-
// existential to an archetype parameter, so for now we restrict this to
613-
// @objc protocols.
614-
for (auto proto : protocols) {
615-
if (!proto->isObjC() &&
616-
!proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
617-
return None;
618-
}
619-
620610
// If the existential type cannot be represented or the protocol does not
621611
// conform to itself, there's no point in looking further.
622612
if (!protocol->existentialConformsToSelf() ||
623613
!protocol->existentialTypeSupported(resolver))
624614
return None;
625615

626-
// Special-case AnyObject, which may not be in the list of conformances.
627-
if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject)) {
628-
if (type->isClassExistentialType())
629-
return ProtocolConformanceRef(protocol);
616+
auto layout = type->getExistentialLayout();
630617

618+
// Due to an IRGen limitation, witness tables cannot be passed from an
619+
// existential to an archetype parameter, so for now we restrict this to
620+
// @objc protocols.
621+
if (!layout.isObjC())
631622
return None;
623+
624+
// Special-case AnyObject, which may not be in the list of conformances.
625+
//
626+
// FIXME: This is going away soon.
627+
if (protocol->isSpecificProtocol(KnownProtocolKind::AnyObject))
628+
return ProtocolConformanceRef(protocol);
629+
630+
// If the existential is class-constrained, the class might conform
631+
// concretely.
632+
if (layout.superclass) {
633+
if (auto result = lookupConformance(layout.superclass, protocol,
634+
resolver))
635+
return result;
632636
}
633637

634-
// Look for this protocol within the existential's list of conformances.
635-
for (auto proto : protocols) {
636-
if (proto == protocol || proto->inheritsFrom(protocol))
638+
// Otherwise, the existential might conform abstractly.
639+
for (auto proto : layout.getProtocols()) {
640+
auto *protoDecl = proto->getDecl();
641+
if (protoDecl == protocol || protoDecl->inheritsFrom(protocol))
637642
return ProtocolConformanceRef(protocol);
638643
}
639644

lib/AST/NameLookup.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/AST/ASTScope.h"
2121
#include "swift/AST/ASTVisitor.h"
2222
#include "swift/AST/DebuggerClient.h"
23+
#include "swift/AST/ExistentialLayout.h"
2324
#include "swift/AST/LazyResolver.h"
2425
#include "swift/AST/Initializer.h"
2526
#include "swift/AST/ReferencedNameTracker.h"
@@ -1391,6 +1392,8 @@ bool DeclContext::lookupQualified(Type type,
13911392

13921393
// If we want dynamic lookup and we're searching in the
13931394
// AnyObject protocol, note this for later.
1395+
//
1396+
// FIXME: This will go away soon.
13941397
if (options & NL_DynamicLookup) {
13951398
if (auto proto = dyn_cast<ProtocolDecl>(nominal)) {
13961399
if (proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
@@ -1406,28 +1409,29 @@ bool DeclContext::lookupQualified(Type type,
14061409
stack.push_back(proto);
14071410

14081411
// Look into the superclasses of this archetype.
1409-
if (auto superclassTy = archetypeTy->getSuperclass()) {
1410-
if (auto superclassDecl = superclassTy->getAnyNominal()) {
1411-
if (visited.insert(superclassDecl).second) {
1412+
if (auto superclassTy = archetypeTy->getSuperclass())
1413+
if (auto superclassDecl = superclassTy->getAnyNominal())
1414+
if (visited.insert(superclassDecl).second)
14121415
stack.push_back(superclassDecl);
1413-
}
1414-
}
1415-
}
14161416
}
14171417
// Handle protocol compositions.
14181418
else if (auto compositionTy = type->getAs<ProtocolCompositionType>()) {
1419-
SmallVector<ProtocolDecl *, 4> protocols;
1420-
compositionTy->getExistentialTypeProtocols(protocols);
1421-
for (auto proto : protocols) {
1422-
if (visited.insert(proto).second) {
1423-
stack.push_back(proto);
1419+
auto layout = compositionTy->getExistentialLayout();
14241420

1425-
// If we want dynamic lookup and this is the AnyObject
1426-
// protocol, note this for later.
1427-
if ((options & NL_DynamicLookup) &&
1428-
proto->isSpecificProtocol(KnownProtocolKind::AnyObject))
1429-
wantLookupInAllClasses = true;
1430-
}
1421+
if (layout.isAnyObject() &&
1422+
(options & NL_DynamicLookup))
1423+
wantLookupInAllClasses = true;
1424+
1425+
for (auto proto : layout.getProtocols()) {
1426+
auto *protoDecl = proto->getDecl();
1427+
if (visited.insert(protoDecl).second)
1428+
stack.push_back(protoDecl);
1429+
}
1430+
1431+
if (layout.superclass) {
1432+
auto *nominalDecl = layout.superclass->getAnyNominal();
1433+
if (visited.insert(nominalDecl).second)
1434+
stack.push_back(nominalDecl);
14311435
}
14321436
} else {
14331437
llvm_unreachable("Bad type for qualified lookup");

0 commit comments

Comments
 (0)