Skip to content

Commit d49f8fb

Browse files
committed
AST: Introduce primitive AnyObject type
Add a 'hasExplicitAnyObject()' bit to ProtocolCompositionType to represent canonical composition types containing '& AnyObject'. Serialize this bit and take it into account when building ExistentialLayouts. Rename ProtocolCompositionType::getProtocols() to getMembers() since it can contain classes now, and update a few usages that need further attention with FIXMEs or asserts. For now, nothing actually constructs these types, and they will trigger arounds asserts. Upcoming patches will introduce support for this.
1 parent ce3f098 commit d49f8fb

22 files changed

+178
-104
lines changed

include/swift/AST/Types.h

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,15 @@ class alignas(1 << TypeAlignInBits) TypeBase {
325325
};
326326
enum { NumAnyMetatypeTypeBits = NumTypeBaseBits + 2 };
327327
static_assert(NumAnyMetatypeTypeBits <= 32, "fits in an unsigned");
328+
329+
struct ProtocolCompositionTypeBitfields {
330+
unsigned : NumTypeBaseBits;
331+
/// Whether we have an explicitly-stated class constraint not
332+
/// implied by any of our members.
333+
unsigned HasExplicitAnyObject : 1;
334+
};
335+
enum { NumProtocolCompositionTypeBits = NumTypeBaseBits + 1 };
336+
static_assert(NumProtocolCompositionTypeBits <= 32, "fits in an unsigned");
328337

329338
union {
330339
TypeBaseBitfields TypeBaseBits;
@@ -334,6 +343,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
334343
ArchetypeTypeBitfields ArchetypeTypeBits;
335344
SILFunctionTypeBitfields SILFunctionTypeBits;
336345
AnyMetatypeTypeBitfields AnyMetatypeTypeBits;
346+
ProtocolCompositionTypeBitfields ProtocolCompositionTypeBits;
337347
};
338348

339349
protected:
@@ -3662,44 +3672,66 @@ END_CAN_TYPE_WRAPPER(ProtocolType, NominalType)
36623672
/// protocol, then the canonical type is that protocol type. Otherwise, it is
36633673
/// a composition of the protocols in that list.
36643674
class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode {
3665-
ArrayRef<Type> Protocols;
3675+
ArrayRef<Type> Members;
36663676

36673677
public:
36683678
/// \brief Retrieve an instance of a protocol composition type with the
3669-
/// given set of protocols.
3670-
static Type get(const ASTContext &C, ArrayRef<Type> Protocols);
3679+
/// given set of members.
3680+
static Type get(const ASTContext &C, ArrayRef<Type> Members,
3681+
bool HasExplicitAnyObject);
36713682

3672-
/// \brief Retrieve the set of protocols composed to create this type.
3673-
ArrayRef<Type> getProtocols() const { return Protocols; }
3683+
/// \brief Retrieve the set of members composed to create this type.
3684+
///
3685+
/// For non-canonical types, this can contain classes, protocols and
3686+
/// protocol compositions in any order. There can be at most one unique
3687+
/// class constraint, either stated directly or as recursive member.
3688+
///
3689+
/// In canonical types, this list will contain the superclass first if
3690+
/// any, followed by zero or more protocols in a canonical sorted order,
3691+
/// minimized to remove duplicates or protocols implied by inheritance.
3692+
///
3693+
/// Note that the list of members is not sufficient to uniquely identify
3694+
/// a protocol composition type; you also have to look at
3695+
/// hasExplicitAnyObject().
3696+
ArrayRef<Type> getMembers() const { return Members; }
36743697

36753698
void Profile(llvm::FoldingSetNodeID &ID) {
3676-
Profile(ID, Protocols);
3699+
Profile(ID, Members, hasExplicitAnyObject());
36773700
}
3678-
static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef<Type> Protocols);
3701+
static void Profile(llvm::FoldingSetNodeID &ID,
3702+
ArrayRef<Type> Members,
3703+
bool HasExplicitAnyObject);
36793704

3680-
/// True if one or more of the protocols is class.
3705+
/// True if the composition requires the concrete conforming type to
3706+
/// be a class, either via a directly-stated superclass constraint or
3707+
/// one of its member protocols being class-constrained.
36813708
bool requiresClass();
3682-
3709+
3710+
/// True if the class requirement is stated directly via '& AnyObject'.
3711+
bool hasExplicitAnyObject() {
3712+
return ProtocolCompositionTypeBits.HasExplicitAnyObject;
3713+
}
3714+
36833715
// Implement isa/cast/dyncast/etc.
36843716
static bool classof(const TypeBase *T) {
36853717
return T->getKind() == TypeKind::ProtocolComposition;
36863718
}
36873719

36883720
private:
36893721
static ProtocolCompositionType *build(const ASTContext &C,
3690-
ArrayRef<Type> Protocols);
3722+
ArrayRef<Type> Members,
3723+
bool HasExplicitAnyObject);
36913724

3692-
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> protocols,
3725+
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> members,
3726+
bool hasExplicitAnyObject,
36933727
RecursiveTypeProperties properties)
36943728
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx,
36953729
properties),
3696-
Protocols(protocols) { }
3730+
Members(members) {
3731+
ProtocolCompositionTypeBits.HasExplicitAnyObject = hasExplicitAnyObject;
3732+
}
36973733
};
36983734
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
3699-
/// In the canonical representation, these are all ProtocolTypes.
3700-
CanTypeArrayRef getProtocols() const {
3701-
return CanTypeArrayRef(getPointer()->getProtocols());
3702-
}
37033735
END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
37043736

37053737
/// LValueType - An l-value is a handle to a physical object. The

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 333; // Last change: AST constant_string_literal
57+
const uint16_t VERSION_MINOR = 334; // Last change: AnyObject bit in ProtocolCompositionType
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;
@@ -660,6 +660,7 @@ namespace decls_block {
660660

661661
using ProtocolCompositionTypeLayout = BCRecordLayout<
662662
PROTOCOL_COMPOSITION_TYPE,
663+
BCFixed<1>, // has AnyObject constraint
663664
BCArray<TypeIDField> // protocols
664665
>;
665666

lib/AST/ASTContext.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,8 @@ ASTContext::ASTContext(LangOptions &langOpts, SearchPathOptions &SearchPathOpts,
415415
TheUnresolvedType(new (*this, AllocationArena::Permanent)
416416
UnresolvedType(*this)),
417417
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
418-
TheAnyType(ProtocolCompositionType::get(*this, ArrayRef<Type>())),
418+
TheAnyType(ProtocolCompositionType::get(*this, ArrayRef<Type>(),
419+
/*hasExplicitAnyObject=*/false)),
419420
TheNativeObjectType(new (*this, AllocationArena::Permanent)
420421
BuiltinNativeObjectType(*this)),
421422
TheBridgeObjectType(new (*this, AllocationArena::Permanent)
@@ -2834,15 +2835,16 @@ void ClassType::Profile(llvm::FoldingSetNodeID &ID, ClassDecl *D, Type Parent) {
28342835
}
28352836

28362837
ProtocolCompositionType *
2837-
ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Protocols) {
2838+
ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Members,
2839+
bool HasExplicitAnyObject) {
28382840
// Check to see if we've already seen this protocol composition before.
28392841
void *InsertPos = nullptr;
28402842
llvm::FoldingSetNodeID ID;
2841-
ProtocolCompositionType::Profile(ID, Protocols);
2843+
ProtocolCompositionType::Profile(ID, Members, HasExplicitAnyObject);
28422844

28432845
bool isCanonical = true;
28442846
RecursiveTypeProperties properties;
2845-
for (Type t : Protocols) {
2847+
for (Type t : Members) {
28462848
if (!t->isCanonical())
28472849
isCanonical = false;
28482850
properties |= t->getRecursiveProperties();
@@ -2859,7 +2861,8 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Protocols) {
28592861
auto compTy
28602862
= new (C, arena)
28612863
ProtocolCompositionType(isCanonical ? &C : nullptr,
2862-
C.AllocateCopy(Protocols),
2864+
C.AllocateCopy(Members),
2865+
HasExplicitAnyObject,
28632866
properties);
28642867
C.Impl.getArena(arena).ProtocolCompositionTypes
28652868
.InsertNode(compTy, InsertPos);

lib/AST/ASTDumper.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3075,7 +3075,9 @@ namespace {
30753075
void visitProtocolCompositionType(ProtocolCompositionType *T,
30763076
StringRef label) {
30773077
printCommon(T, label, "protocol_composition_type");
3078-
for (auto proto : T->getProtocols()) {
3078+
if (T->hasExplicitAnyObject())
3079+
OS << " any_object";
3080+
for (auto proto : T->getMembers()) {
30793081
printRec(proto);
30803082
}
30813083
OS << ")";

lib/AST/ASTPrinter.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3513,9 +3513,12 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
35133513
}
35143514

35153515
case TypeKind::ProtocolComposition: {
3516-
// 'Any' and single protocol compositions are simple
3516+
// 'Any', 'AnyObject' and single protocol compositions are simple
35173517
auto composition = type->getAs<ProtocolCompositionType>();
3518-
return composition->getProtocols().size() <= 1;
3518+
auto memberCount = composition->getMembers().size();
3519+
if (composition->hasExplicitAnyObject())
3520+
return memberCount == 0;
3521+
return memberCount <= 1;
35193522
}
35203523

35213524
default:
@@ -4187,11 +4190,16 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
41874190
}
41884191

41894192
void visitProtocolCompositionType(ProtocolCompositionType *T) {
4190-
if (T->getProtocols().empty()) {
4191-
Printer << "Any";
4193+
if (T->getMembers().empty()) {
4194+
if (T->hasExplicitAnyObject())
4195+
Printer << "AnyObject";
4196+
else
4197+
Printer << "Any";
41924198
} else {
4193-
interleave(T->getProtocols(), [&](Type Proto) { visit(Proto); },
4199+
interleave(T->getMembers(), [&](Type Ty) { visit(Ty); },
41944200
[&] { Printer << " & "; });
4201+
if (T->hasExplicitAnyObject())
4202+
Printer << " & AnyObject";
41954203
}
41964204
}
41974205

lib/AST/ASTVerifier.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/ASTWalker.h"
1919
#include "swift/AST/AccessScope.h"
2020
#include "swift/AST/Decl.h"
21+
#include "swift/AST/ExistentialLayout.h"
2122
#include "swift/AST/Expr.h"
2223
#include "swift/AST/ForeignErrorConvention.h"
2324
#include "swift/AST/GenericEnvironment.h"
@@ -2042,9 +2043,12 @@ class Verifier : public ASTWalker {
20422043
SmallVector<Type, 4> protocolTypes;
20432044
for (auto proto : protocols)
20442045
protocolTypes.push_back(proto->getDeclaredType());
2046+
auto type = ProtocolCompositionType::get(Ctx, protocolTypes,
2047+
/*hasExplicitAnyObject=*/false);
2048+
auto layout = type->getExistentialLayout();
20452049
SmallVector<ProtocolDecl *, 4> canonicalProtocols;
2046-
ProtocolCompositionType::get(Ctx, protocolTypes)
2047-
->getExistentialTypeProtocols(canonicalProtocols);
2050+
for (auto *protoTy : layout.getProtocols())
2051+
canonicalProtocols.push_back(protoTy->getDecl());
20482052
if (nominalProtocols != canonicalProtocols) {
20492053
dumpRef(decl);
20502054
Out << " doesn't have a complete set of protocols\n";

lib/AST/ConformanceLookupTable.cpp

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "ConformanceLookupTable.h"
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/Decl.h"
20+
#include "swift/AST/ExistentialLayout.h"
2021
#include "swift/AST/Module.h"
2122
#include "swift/AST/ProtocolConformance.h"
2223
#include "swift/AST/ProtocolConformanceRef.h"
@@ -416,28 +417,6 @@ void ConformanceLookupTable::loadAllConformances(
416417
}
417418
}
418419

419-
namespace {
420-
/// Visit the protocols referenced by the given type, which was
421-
/// uttered at the given location.
422-
template<typename AddProtocolFunc>
423-
void visitProtocols(Type type, SourceLoc loc, AddProtocolFunc addProtocol) {
424-
if (!type) return;
425-
426-
// Protocol types.
427-
if (auto protocol = type->getAs<ProtocolType>()) {
428-
addProtocol(protocol->getDecl(), loc);
429-
return;
430-
}
431-
432-
// Protocol compositions.
433-
if (auto composition = type->getAs<ProtocolCompositionType>()) {
434-
for (auto protocol : composition->getProtocols())
435-
visitProtocols(protocol, loc, addProtocol);
436-
return;
437-
}
438-
}
439-
} // end anonymous namespace
440-
441420
bool ConformanceLookupTable::addProtocol(NominalTypeDecl *nominal,
442421
ProtocolDecl *protocol, SourceLoc loc,
443422
ConformanceSource source) {
@@ -492,10 +471,11 @@ void ConformanceLookupTable::addProtocols(NominalTypeDecl *nominal,
492471
// Visit each of the types in the inheritance list to find
493472
// protocols.
494473
for (const auto &entry : inherited) {
495-
visitProtocols(entry.getType(), entry.getLoc(),
496-
[&](ProtocolDecl *protocol, SourceLoc loc) {
497-
addProtocol(nominal, protocol, loc, source);
498-
});
474+
if (!entry.getType() || !entry.getType()->isExistentialType())
475+
continue;
476+
auto layout = entry.getType()->getExistentialLayout();
477+
for (auto *proto : layout.getProtocols())
478+
addProtocol(nominal, proto->getDecl(), entry.getLoc(), source);
499479
}
500480
}
501481

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2199,13 +2199,16 @@ static ConstraintResult visitInherited(
21992199
// Local function that (recursively) adds inherited types.
22002200
ConstraintResult result = ConstraintResult::Resolved;
22012201
std::function<void(Type, const TypeRepr *)> visitInherited;
2202+
2203+
// FIXME: Should this whole thing use getExistentialLayout() instead?
2204+
22022205
visitInherited = [&](Type inheritedType, const TypeRepr *typeRepr) {
22032206
// Decompose protocol compositions.
22042207
auto composition = dyn_cast_or_null<CompositionTypeRepr>(typeRepr);
22052208
if (auto compositionType
22062209
= inheritedType->getAs<ProtocolCompositionType>()) {
22072210
unsigned index = 0;
2208-
for (auto protoType : compositionType->getProtocols()) {
2211+
for (auto protoType : compositionType->getMembers()) {
22092212
if (composition && index < composition->getTypes().size())
22102213
visitInherited(protoType, composition->getTypes()[index]);
22112214
else

lib/AST/LookupVisibleDecls.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ static void lookupVisibleMemberDeclsImpl(
536536

537537
// If the base is a protocol composition, enumerate members of the protocols.
538538
if (auto PC = BaseTy->getAs<ProtocolCompositionType>()) {
539-
for (auto Proto : PC->getProtocols())
540-
lookupVisibleMemberDeclsImpl(Proto, Consumer, CurrDC, LS, Reason,
539+
for (auto Member : PC->getMembers())
540+
lookupVisibleMemberDeclsImpl(Member, Consumer, CurrDC, LS, Reason,
541541
TypeResolver, Visited);
542542
return;
543543
}

0 commit comments

Comments
 (0)