Skip to content

Commit 7bd3e83

Browse files
committed
[Type System] Introduce a dedicated type to represent existential types.
The new type, called ExistentialType, is not yet used in type resolution. Later, existential types written with `any` will resolve to this type, and bare protocol names will resolve to this type depending on context.
1 parent 8531361 commit 7bd3e83

28 files changed

+248
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4618,6 +4618,11 @@ ERROR(unchecked_not_inheritance_clause,none,
46184618
ERROR(unchecked_not_existential,none,
46194619
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))
46204620

4621+
WARNING(unnecessary_any,none,
4622+
"'any' is redundant on type %0", (Type))
4623+
ERROR(any_not_existential,none,
4624+
"'any' has no effect on %select{concrete type|type parameter}0 %1",
4625+
(bool, Type))
46214626
ERROR(explicit_existential_not_supported,none,
46224627
"explicit 'any' not supported; use frontend flag "
46234628
"-enable-explicit-existential-types to enable this feature",

include/swift/AST/TypeDifferenceVisitor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,12 @@ class CanTypeDifferenceVisitor : public CanTypePairVisitor<Impl, bool> {
328328
type1->getMembers(), type2->getMembers());
329329
}
330330

331+
bool visitExistentialType(CanExistentialType type1,
332+
CanExistentialType type2) {
333+
return asImpl().visit(type1.getConstraintType(),
334+
type2.getConstraintType());
335+
}
336+
331337
bool visitLValueType(CanLValueType type1, CanLValueType type2) {
332338
return asImpl().visit(type1.getObjectType(), type2.getObjectType());
333339
}

include/swift/AST/TypeMatcher.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,20 @@ class TypeMatcher {
269269
TRIVIAL_CASE(SILBoxType)
270270
TRIVIAL_CASE(ProtocolCompositionType)
271271

272+
bool visitExistentialType(CanExistentialType firstExistential,
273+
Type secondType,
274+
Type sugaredFirstType) {
275+
if (auto secondExistential = secondType->getAs<ExistentialType>()) {
276+
return this->visit(firstExistential.getConstraintType(),
277+
secondExistential->getConstraintType(),
278+
sugaredFirstType->castTo<ExistentialType>()
279+
->getConstraintType());
280+
}
281+
282+
return mismatch(firstExistential.getPointer(), secondType,
283+
sugaredFirstType);
284+
}
285+
272286
bool visitLValueType(CanLValueType firstLValue, Type secondType,
273287
Type sugaredFirstType) {
274288
if (auto secondLValue = secondType->getAs<LValueType>()) {

include/swift/AST/TypeNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ ARTIFICIAL_TYPE(SILBlockStorage, Type)
162162
ARTIFICIAL_TYPE(SILBox, Type)
163163
ARTIFICIAL_TYPE(SILToken, Type)
164164
TYPE(ProtocolComposition, Type)
165+
TYPE(Existential, Type)
165166
TYPE(LValue, Type)
166167
TYPE(InOut, Type)
167168
UNCHECKED_TYPE(TypeVariable, Type)

include/swift/AST/TypeRepr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@ class ExistentialTypeRepr: public TypeRepr {
11721172
AnyLoc(anyLoc) {}
11731173

11741174
TypeRepr *getConstraint() const { return Constraint; }
1175+
SourceLoc getAnyLoc() const { return AnyLoc; }
11751176

11761177
static bool classof(const TypeRepr *T) {
11771178
return T->getKind() == TypeReprKind::Existential;

include/swift/AST/Types.h

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5199,6 +5199,42 @@ class ProtocolCompositionType final : public TypeBase,
51995199
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
52005200
END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
52015201

5202+
/// An existential type, spelled with \c any .
5203+
///
5204+
/// In Swift 5 mode, a plain protocol name in type
5205+
/// context is an implicit existential type.
5206+
class ExistentialType final : public TypeBase {
5207+
Type ConstraintType;
5208+
5209+
ExistentialType(Type constraintType,
5210+
const ASTContext *canonicalContext,
5211+
RecursiveTypeProperties properties)
5212+
: TypeBase(TypeKind::Existential, canonicalContext, properties),
5213+
ConstraintType(constraintType) {}
5214+
5215+
public:
5216+
static ExistentialType *get(Type constraint);
5217+
5218+
Type getConstraintType() const { return ConstraintType; }
5219+
5220+
bool requiresClass() const {
5221+
if (auto protocol = ConstraintType->getAs<ProtocolType>())
5222+
return protocol->requiresClass();
5223+
5224+
if (auto composition = ConstraintType->getAs<ProtocolCompositionType>())
5225+
return composition->requiresClass();
5226+
5227+
return false;
5228+
}
5229+
5230+
static bool classof(const TypeBase *type) {
5231+
return type->getKind() == TypeKind::Existential;
5232+
}
5233+
};
5234+
BEGIN_CAN_TYPE_WRAPPER(ExistentialType, Type)
5235+
PROXY_CAN_TYPE_SIMPLE_GETTER(getConstraintType)
5236+
END_CAN_TYPE_WRAPPER(ExistentialType, Type)
5237+
52025238
/// LValueType - An l-value is a handle to a physical object. The
52035239
/// type of that object uniquely determines the type of an l-value
52045240
/// for it.
@@ -6154,7 +6190,9 @@ inline bool TypeBase::isAnyExistentialType() {
61546190
}
61556191

61566192
inline bool CanType::isExistentialTypeImpl(CanType type) {
6157-
return isa<ProtocolType>(type) || isa<ProtocolCompositionType>(type);
6193+
return (isa<ProtocolType>(type) ||
6194+
isa<ProtocolCompositionType>(type) ||
6195+
isa<ExistentialType>(type));
61586196
}
61596197

61606198
inline bool CanType::isAnyExistentialTypeImpl(CanType type) {
@@ -6167,6 +6205,8 @@ inline bool TypeBase::isClassExistentialType() {
61676205
return pt->requiresClass();
61686206
if (auto pct = dyn_cast<ProtocolCompositionType>(T))
61696207
return pct->requiresClass();
6208+
if (auto existential = dyn_cast<ExistentialType>(T))
6209+
return existential->requiresClass();
61706210
return false;
61716211
}
61726212

@@ -6427,6 +6467,9 @@ inline bool TypeBase::hasSimpleTypeRepr() const {
64276467
case TypeKind::ExistentialMetatype:
64286468
return !cast<const AnyMetatypeType>(this)->hasRepresentation();
64296469

6470+
case TypeKind::Existential:
6471+
return false;
6472+
64306473
case TypeKind::NestedArchetype:
64316474
return cast<NestedArchetypeType>(this)->getParent()->hasSimpleTypeRepr();
64326475

@@ -6436,8 +6479,6 @@ inline bool TypeBase::hasSimpleTypeRepr() const {
64366479

64376480
case TypeKind::ProtocolComposition: {
64386481
// 'Any', 'AnyObject' and single protocol compositions are simple
6439-
// FIXME: single protocol compositions spelled with `any` are not
6440-
// simple.
64416482
auto composition = cast<const ProtocolCompositionType>(this);
64426483
auto memberCount = composition->getMembers().size();
64436484
if (composition->hasExplicitAnyObject())

lib/AST/ASTContext.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ struct ASTContext::Implementation {
408408
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
409409
llvm::DenseMap<std::pair<ClassDecl*, Type>, ClassType*> ClassTypes;
410410
llvm::DenseMap<std::pair<ProtocolDecl*, Type>, ProtocolType*> ProtocolTypes;
411+
llvm::DenseMap<Type, ExistentialType *> ExistentialTypes;
411412
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
412413
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
413414
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
@@ -4093,6 +4094,21 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent,
40934094
RecursiveTypeProperties properties)
40944095
: NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { }
40954096

4097+
ExistentialType *ExistentialType::get(Type constraint) {
4098+
auto properties = constraint->getRecursiveProperties();
4099+
auto arena = getArena(properties);
4100+
4101+
auto &C = constraint->getASTContext();
4102+
auto &entry = C.getImpl().getArena(arena).ExistentialTypes[constraint];
4103+
if (entry)
4104+
return entry;
4105+
4106+
const ASTContext *canonicalContext = constraint->isCanonical() ? &C : nullptr;
4107+
return entry = new (C, arena) ExistentialType(constraint,
4108+
canonicalContext,
4109+
properties);
4110+
}
4111+
40964112
LValueType *LValueType::get(Type objectTy) {
40974113
assert(!objectTy->is<LValueType>() && !objectTy->is<InOutType>() &&
40984114
"cannot have 'inout' or @lvalue wrapped inside an @lvalue");

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3933,6 +3933,13 @@ namespace {
39333933
PrintWithColorRAII(OS, ParenthesisColor) << ')';
39343934
}
39353935

3936+
void visitExistentialType(ExistentialType *T,
3937+
StringRef label) {
3938+
printCommon(label, "existential_type");
3939+
printRec(T->getConstraintType());
3940+
PrintWithColorRAII(OS, ParenthesisColor) << ')';
3941+
}
3942+
39363943
void visitLValueType(LValueType *T, StringRef label) {
39373944
printCommon(label, "lvalue_type");
39383945
printRec(T->getObjectType());

lib/AST/ASTMangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,6 +1251,11 @@ void ASTMangler::appendType(Type type, GenericSignature sig,
12511251
return appendExistentialLayout(layout, sig, forDecl);
12521252
}
12531253

1254+
case TypeKind::Existential: {
1255+
auto constraint = cast<ExistentialType>(tybase)->getConstraintType();
1256+
return appendType(constraint, sig, forDecl);
1257+
}
1258+
12541259
case TypeKind::UnboundGeneric:
12551260
case TypeKind::Class:
12561261
case TypeKind::Enum:

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5329,6 +5329,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
53295329
}
53305330
}
53315331

5332+
void visitExistentialType(ExistentialType *T) {
5333+
Printer << "any ";
5334+
visit(T->getConstraintType());
5335+
}
5336+
53325337
void visitLValueType(LValueType *T) {
53335338
Printer << "@lvalue ";
53345339
visit(T->getObjectType());

0 commit comments

Comments
 (0)