Skip to content

Commit a5fd009

Browse files
authored
Merge pull request #8650 from slavapestov/subclass-existentials
Preliminary Sema and AST support for subclass existentials (SE-0156)
2 parents e26c08f + de323b5 commit a5fd009

39 files changed

+1341
-609
lines changed

include/swift/AST/ConcreteDeclRef.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,12 @@ class ConcreteDeclRef {
9393
/// given declaration. This array will be copied into the ASTContext by the
9494
/// constructor.
9595
ConcreteDeclRef(ASTContext &ctx, ValueDecl *decl,
96-
SubstitutionList substitutions)
97-
: Data(SpecializedDeclRef::create(ctx, decl, substitutions)) { }
96+
SubstitutionList substitutions) {
97+
if (substitutions.empty())
98+
Data = decl;
99+
else
100+
Data = SpecializedDeclRef::create(ctx, decl, substitutions);
101+
}
98102

99103
/// Determine whether this declaration reference refers to anything.
100104
explicit operator bool() const { return !Data.isNull(); }

include/swift/AST/DiagnosticsParse.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -699,9 +699,9 @@ ERROR(tuple_type_multiple_labels,none,
699699

700700
// Protocol Types
701701
ERROR(expected_rangle_protocol,PointsToFirstBadToken,
702-
"expected '>' to complete protocol composition type", ())
702+
"expected '>' to complete protocol-constrained type", ())
703703
ERROR(disallowed_protocol_composition,PointsToFirstBadToken,
704-
"protocol composition is neither allowed nor needed here", ())
704+
"protocol-constrained type is neither allowed nor needed here", ())
705705

706706
WARNING(deprecated_protocol_composition,none,
707707
"'protocol<...>' composition syntax is deprecated; join the protocols using '&'", ())
@@ -1361,7 +1361,7 @@ ERROR(unexpected_class_constraint,none,
13611361
NOTE(suggest_anyobject,none,
13621362
"did you mean to constrain %0 with the 'AnyObject' protocol?", (Identifier))
13631363
ERROR(expected_generics_type_restriction,none,
1364-
"expected a type name or protocol composition restricting %0",
1364+
"expected a class type or protocol-constrained type restricting %0",
13651365
(Identifier))
13661366
ERROR(requires_single_equal,none,
13671367
"use '==' for same-type requirements rather than '='", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,14 +1552,19 @@ ERROR(circular_protocol_def,none,
15521552
"circular protocol inheritance %0", (StringRef))
15531553
NOTE(protocol_here,none,
15541554
"protocol %0 declared here", (Identifier))
1555-
ERROR(protocol_composition_not_protocol,none,
1556-
"non-protocol type %0 cannot be used within a protocol composition", (Type))
15571555
ERROR(objc_protocol_inherits_non_objc_protocol,none,
15581556
"@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type))
15591557
WARNING(protocol_composition_with_postfix,none,
1560-
"protocol composition with postfix '%0' is ambiguous "
1558+
"protocol-constrained type with postfix '%0' is ambiguous "
15611559
"and will be rejected in future version of Swift", (StringRef))
15621560

1561+
ERROR(invalid_protocol_composition_member,none,
1562+
"non-protocol, non-class type %0 cannot be used within a "
1563+
"protocol-constrained type", (Type))
1564+
ERROR(protocol_composition_one_class,none,
1565+
"protocol-constrained type cannot contain class %0 because it already "
1566+
"contains class %1", (Type, Type))
1567+
15631568
ERROR(requires_conformance_nonprotocol,none,
15641569
"type %0 constrained to non-protocol type %1", (TypeLoc, TypeLoc))
15651570
ERROR(requires_not_suitable_archetype,none,
@@ -3090,7 +3095,7 @@ NOTE(not_objc_empty_protocol_composition,none,
30903095
NOTE(not_objc_protocol,none,
30913096
"protocol %0 is not '@objc'", (Type))
30923097
NOTE(not_objc_error_protocol_composition,none,
3093-
"protocol composition involving 'Error' cannot be represented "
3098+
"protocol-constrained type containing 'Error' cannot be represented "
30943099
"in Objective-C", ())
30953100
NOTE(not_objc_empty_tuple,none,
30963101
"empty tuple type cannot be represented in Objective-C", ())

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: 15 additions & 9 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);
@@ -3602,7 +3605,7 @@ class ProtocolType : public NominalType, public llvm::FoldingSetNode {
36023605
}
36033606

36043607
/// True if only classes may conform to the protocol.
3605-
bool requiresClass() const;
3608+
bool requiresClass();
36063609

36073610
// Implement isa/cast/dyncast/etc.
36083611
static bool classof(const TypeBase *T) {
@@ -3669,16 +3672,13 @@ class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode {
36693672
/// \brief Retrieve the set of protocols composed to create this type.
36703673
ArrayRef<Type> getProtocols() const { return Protocols; }
36713674

3672-
/// \brief Return the protocols of this type in canonical order.
3673-
void getAnyExistentialTypeProtocols(SmallVectorImpl<ProtocolDecl *> &protos);
3674-
36753675
void Profile(llvm::FoldingSetNodeID &ID) {
36763676
Profile(ID, Protocols);
36773677
}
36783678
static void Profile(llvm::FoldingSetNodeID &ID, ArrayRef<Type> Protocols);
36793679

36803680
/// True if one or more of the protocols is class.
3681-
bool requiresClass() const;
3681+
bool requiresClass();
36823682

36833683
// Implement isa/cast/dyncast/etc.
36843684
static bool classof(const TypeBase *T) {
@@ -3689,10 +3689,11 @@ class ProtocolCompositionType : public TypeBase, public llvm::FoldingSetNode {
36893689
static ProtocolCompositionType *build(const ASTContext &C,
36903690
ArrayRef<Type> Protocols);
36913691

3692-
ProtocolCompositionType(const ASTContext *Ctx, ArrayRef<Type> Protocols)
3693-
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/Ctx,
3694-
RecursiveTypeProperties()),
3695-
Protocols(Protocols) { }
3692+
ProtocolCompositionType(const ASTContext *ctx, ArrayRef<Type> protocols,
3693+
RecursiveTypeProperties properties)
3694+
: TypeBase(TypeKind::ProtocolComposition, /*Context=*/ctx,
3695+
properties),
3696+
Protocols(protocols) { }
36963697
};
36973698
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
36983699
/// In the canonical representation, these are all ProtocolTypes.
@@ -4555,9 +4556,14 @@ inline bool TypeBase::mayHaveSuperclass() {
45554556
if (getClassOrBoundGenericClass())
45564557
return true;
45574558

4559+
// FIXME: requiresClass() is not the same as having an explicit superclass;
4560+
// is this wrong?
45584561
if (auto archetype = getAs<ArchetypeType>())
45594562
return (bool)archetype->requiresClass();
45604563

4564+
if (isExistentialType())
4565+
return (bool)getSuperclass(nullptr);
4566+
45614567
return is<DynamicSelfType>();
45624568
}
45634569

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ namespace swift {
162162
/// optimized custom allocator, so that memory debugging tools can be used.
163163
bool UseMalloc = false;
164164

165+
/// \brief Enable classes to appear in protocol composition types.
166+
bool EnableExperimentalSubclassExistentials = false;
167+
165168
/// \brief Enable experimental property behavior feature.
166169
bool EnableExperimentalPropertyBehaviors = false;
167170

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,10 @@ def enable_experimental_deserialization_recovery :
267267
Flag<["-"], "enable-experimental-deserialization-recovery">,
268268
HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">;
269269

270+
def enable_experimental_subclass_existentials : Flag<["-"],
271+
"enable-experimental-subclass-existentials">,
272+
HelpText<"Enable classes to appear in protocol composition types">;
273+
270274
def enable_cow_existentials : Flag<["-"], "enable-cow-existentials">,
271275
HelpText<"Enable the copy-on-write existential implementation">;
272276

lib/AST/ASTContext.cpp

Lines changed: 27 additions & 15 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"
@@ -269,6 +270,7 @@ struct ASTContext::Implementation {
269270
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
270271
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
271272
llvm::FoldingSet<ProtocolType> ProtocolTypes;
273+
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
272274
llvm::FoldingSet<LayoutConstraintInfo> LayoutConstraints;
273275

274276
/// The set of normal protocol conformances.
@@ -311,7 +313,6 @@ struct ASTContext::Implementation {
311313
llvm::DenseMap<CanType, SILBlockStorageType *> SILBlockStorageTypes;
312314
llvm::FoldingSet<SILBoxType> SILBoxTypes;
313315
llvm::DenseMap<BuiltinIntegerWidth, BuiltinIntegerType*> IntegerTypes;
314-
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
315316
llvm::FoldingSet<BuiltinVectorType> BuiltinVectorTypes;
316317
llvm::FoldingSet<GenericSignature> GenericSignatures;
317318
llvm::FoldingSet<DeclName::CompoundDeclName> CompoundNames;
@@ -2797,23 +2798,31 @@ ProtocolCompositionType::build(const ASTContext &C, ArrayRef<Type> Protocols) {
27972798
void *InsertPos = nullptr;
27982799
llvm::FoldingSetNodeID ID;
27992800
ProtocolCompositionType::Profile(ID, Protocols);
2800-
if (ProtocolCompositionType *Result
2801-
= C.Impl.ProtocolCompositionTypes.FindNodeOrInsertPos(ID, InsertPos))
2802-
return Result;
28032801

28042802
bool isCanonical = true;
2803+
RecursiveTypeProperties properties;
28052804
for (Type t : Protocols) {
28062805
if (!t->isCanonical())
28072806
isCanonical = false;
2807+
properties |= t->getRecursiveProperties();
28082808
}
28092809

28102810
// Create a new protocol composition type.
2811-
ProtocolCompositionType *New
2812-
= new (C, AllocationArena::Permanent)
2811+
auto arena = getArena(properties);
2812+
2813+
if (auto compTy
2814+
= C.Impl.getArena(arena).ProtocolCompositionTypes
2815+
.FindNodeOrInsertPos(ID, InsertPos))
2816+
return compTy;
2817+
2818+
auto compTy
2819+
= new (C, arena)
28132820
ProtocolCompositionType(isCanonical ? &C : nullptr,
2814-
C.AllocateCopy(Protocols));
2815-
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
2816-
return New;
2821+
C.AllocateCopy(Protocols),
2822+
properties);
2823+
C.Impl.getArena(arena).ProtocolCompositionTypes
2824+
.InsertNode(compTy, InsertPos);
2825+
return compTy;
28172826
}
28182827

28192828
ReferenceStorageType *ReferenceStorageType::get(Type T, Ownership ownership,
@@ -3454,19 +3463,22 @@ CanArchetypeType ArchetypeType::getOpened(Type existential,
34543463
knownID = UUID::fromTime();
34553464
}
34563465

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

34623472
auto arena = AllocationArena::Permanent;
34633473
void *mem = ctx.Allocate(
34643474
totalSizeToAlloc<ProtocolDecl *, Type, LayoutConstraint, UUID>(
3465-
conformsTo.size(), superclass ? 1 : 0, 0, 1),
3475+
protos.size(), layout.superclass ? 1 : 0, 0, 1),
34663476
alignof(ArchetypeType), arena);
34673477

3478+
// FIXME: Pass in class layout constraint
34683479
auto result =
3469-
::new (mem) ArchetypeType(ctx, existential, conformsTo, superclass,
3480+
::new (mem) ArchetypeType(ctx, existential,
3481+
protos, layout.superclass,
34703482
existential->getLayoutConstraint(), *knownID);
34713483
openedExistentialArchetypes[*knownID] = result;
34723484

lib/AST/Decl.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2727,16 +2727,16 @@ ProtocolDecl::getInheritedProtocols() const {
27272727
// FIXME: Gather inherited protocols from the "inherited" list.
27282728
// We shouldn't need this, but it shows up in recursive invocations.
27292729
if (!isRequirementSignatureComputed()) {
2730+
SmallPtrSet<ProtocolDecl *, 4> known;
27302731
for (auto inherited : getInherited()) {
2731-
SmallPtrSet<ProtocolDecl *, 4> known;
27322732
if (auto type = inherited.getType()) {
2733-
if (type->isExistentialType()) {
2734-
SmallVector<ProtocolDecl *, 4> protocols;
2735-
type->getExistentialTypeProtocols(protocols);
2736-
for (auto proto : protocols) {
2737-
if (known.insert(proto).second)
2738-
result.push_back(proto);
2739-
}
2733+
// Only protocols can appear in the inheritance clause
2734+
// of a protocol -- anything else should get diagnosed
2735+
// elsewhere.
2736+
if (auto *protoTy = type->getAs<ProtocolType>()) {
2737+
auto *protoDecl = protoTy->getDecl();
2738+
if (known.insert(protoDecl).second)
2739+
result.push_back(protoDecl);
27402740
}
27412741
}
27422742
}

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,7 @@ MemberRefExpr::MemberRefExpr(Expr *base, SourceLoc dotLoc,
13211321

13221322
MemberRefExprBits.Semantics = (unsigned) semantics;
13231323
MemberRefExprBits.IsSuper = false;
1324+
assert(Member);
13241325
}
13251326

13261327
Type OverloadSetRefExpr::getBaseType() const {

0 commit comments

Comments
 (0)