Skip to content

Commit 69be7b1

Browse files
authored
Merge pull request #40282 from hborla/existential-any
[SE-0335] Introduce existential `any`
2 parents 5a6341b + f96104d commit 69be7b1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1035
-24
lines changed

Diff for: include/swift/AST/Decl.h

+28-1
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
520520
IsComputingSemanticMembers : 1
521521
);
522522

523-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16,
523+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+1+1+8+16,
524524
/// Whether the \c RequiresClass bit is valid.
525525
RequiresClassValid : 1,
526526

@@ -533,6 +533,12 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
533533
/// Whether the existential of this protocol conforms to itself.
534534
ExistentialConformsToSelf : 1,
535535

536+
/// Whether the \c ExistentialRequiresAny bit is valid.
537+
ExistentialRequiresAnyValid : 1,
538+
539+
/// Whether the existential of this protocol must be spelled with \c any.
540+
ExistentialRequiresAny : 1,
541+
536542
/// True if the protocol has requirements that cannot be satisfied (e.g.
537543
/// because they could not be imported from Objective-C).
538544
HasMissingRequirements : 1,
@@ -4244,6 +4250,21 @@ class ProtocolDecl final : public NominalTypeDecl {
42444250
Bits.ProtocolDecl.ExistentialConformsToSelf = result;
42454251
}
42464252

4253+
/// Returns the cached result of \c existentialRequiresAny or \c None if it
4254+
/// hasn't yet been computed.
4255+
Optional<bool> getCachedExistentialRequiresAny() {
4256+
if (Bits.ProtocolDecl.ExistentialRequiresAnyValid)
4257+
return Bits.ProtocolDecl.ExistentialRequiresAny;
4258+
4259+
return None;
4260+
}
4261+
4262+
/// Caches the result of \c existentialRequiresAny
4263+
void setCachedExistentialRequiresAny(bool requiresAny) {
4264+
Bits.ProtocolDecl.ExistentialRequiresAnyValid = true;
4265+
Bits.ProtocolDecl.ExistentialRequiresAny = requiresAny;
4266+
}
4267+
42474268
bool hasLazyRequirementSignature() const {
42484269
return Bits.ProtocolDecl.HasLazyRequirementSignature;
42494270
}
@@ -4257,6 +4278,7 @@ class ProtocolDecl final : public NominalTypeDecl {
42574278
friend class RequirementSignatureRequestRQM;
42584279
friend class ProtocolRequiresClassRequest;
42594280
friend class ExistentialConformsToSelfRequest;
4281+
friend class ExistentialRequiresAnyRequest;
42604282
friend class InheritedProtocolsRequest;
42614283

42624284
public:
@@ -4345,6 +4367,11 @@ class ProtocolDecl final : public NominalTypeDecl {
43454367
/// contain 'Self' in 'parameter' or 'other' position.
43464368
bool isAvailableInExistential(const ValueDecl *decl) const;
43474369

4370+
/// Determine whether an existential type must be explicitly prefixed
4371+
/// with \c any. \c any is required if any of the members contain
4372+
/// an associated type, or if \c Self appears in non-covariant position.
4373+
bool existentialRequiresAny() const;
4374+
43484375
/// Returns a list of protocol requirements that must be assessed to
43494376
/// determine a concrete's conformance effect polymorphism kind.
43504377
PolymorphicEffectRequirementList getPolymorphicEffectRequirements(

Diff for: include/swift/AST/DiagnosticsParse.def

+2-1
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,8 @@ ERROR(sil_function_subs_without_generics,none,
873873

874874
// Opaque types
875875
ERROR(opaque_mid_composition,none,
876-
"'some' should appear at the beginning of a composition", ())
876+
"'%0' should appear at the beginning of a composition",
877+
(StringRef))
877878

878879
//------------------------------------------------------------------------------
879880
// MARK: Layout constraint diagnostics

Diff for: include/swift/AST/DiagnosticsSema.def

+13
Original file line numberDiff line numberDiff line change
@@ -4615,6 +4615,19 @@ ERROR(unchecked_not_inheritance_clause,none,
46154615
ERROR(unchecked_not_existential,none,
46164616
"'unchecked' attribute cannot apply to non-protocol type %0", (Type))
46174617

4618+
WARNING(unnecessary_any,none,
4619+
"'any' is redundant on type %0", (Type))
4620+
ERROR(any_not_existential,none,
4621+
"'any' has no effect on %select{concrete type|type parameter}0 %1",
4622+
(bool, Type))
4623+
ERROR(existential_requires_any,none,
4624+
"protocol %0 as a type must be explicitly marked as 'any'",
4625+
(Identifier))
4626+
ERROR(explicit_existential_not_supported,none,
4627+
"explicit 'any' not supported; use frontend flag "
4628+
"-enable-explicit-existential-types to enable this feature",
4629+
())
4630+
46184631
ERROR(nonisolated_let,none,
46194632
"'nonisolated' is meaningless on 'let' declarations because "
46204633
"they are immutable",

Diff for: include/swift/AST/TypeCheckRequests.h

+26
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,32 @@ class ExistentialConformsToSelfRequest :
287287
void cacheResult(bool value) const;
288288
};
289289

290+
/// Determine whether an existential type conforming to this protocol
291+
/// requires the \c any syntax.
292+
class ExistentialRequiresAnyRequest :
293+
public SimpleRequest<ExistentialRequiresAnyRequest,
294+
bool(ProtocolDecl *),
295+
RequestFlags::SeparatelyCached> {
296+
public:
297+
using SimpleRequest::SimpleRequest;
298+
299+
private:
300+
friend SimpleRequest;
301+
302+
// Evaluation.
303+
bool evaluate(Evaluator &evaluator, ProtocolDecl *decl) const;
304+
305+
public:
306+
// Cycle handling.
307+
void diagnoseCycle(DiagnosticEngine &diags) const;
308+
void noteCycleStep(DiagnosticEngine &diags) const;
309+
310+
// Separate caching.
311+
bool isCached() const { return true; }
312+
Optional<bool> getCachedResult() const;
313+
void cacheResult(bool value) const;
314+
};
315+
290316
class PolymorphicEffectRequirementsRequest :
291317
public SimpleRequest<PolymorphicEffectRequirementsRequest,
292318
PolymorphicEffectRequirementList(EffectKind, ProtocolDecl *),

Diff for: include/swift/AST/TypeCheckerTypeIDZone.def

+2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ SWIFT_REQUEST(TypeChecker, EnumRawTypeRequest,
9292
Type(EnumDecl *), Cached, NoLocationInfo)
9393
SWIFT_REQUEST(TypeChecker, ExistentialConformsToSelfRequest,
9494
bool(ProtocolDecl *), SeparatelyCached, NoLocationInfo)
95+
SWIFT_REQUEST(TypeChecker, ExistentialRequiresAnyRequest,
96+
bool(ProtocolDecl *), SeparatelyCached, NoLocationInfo)
9597
SWIFT_REQUEST(TypeChecker, ExtendedTypeRequest, Type(ExtensionDecl *), Cached,
9698
NoLocationInfo)
9799
SWIFT_REQUEST(TypeChecker, ResultBuilderTypeRequest, Type(ValueDecl *),

Diff for: include/swift/AST/TypeDifferenceVisitor.h

+6
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
}

Diff for: include/swift/AST/TypeMatcher.h

+14
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>()) {

Diff for: include/swift/AST/TypeNodes.def

+1
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)

Diff for: include/swift/AST/TypeRepr.h

+30
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,35 @@ class NamedOpaqueReturnTypeRepr : public TypeRepr {
11581158
friend class TypeRepr;
11591159
};
11601160

1161+
/// A TypeRepr for an existential type spelled with \c any
1162+
///
1163+
/// Can appear anywhere a normal existential type would. This is
1164+
/// purely a more explicit spelling for existential types.
1165+
class ExistentialTypeRepr: public TypeRepr {
1166+
TypeRepr *Constraint;
1167+
SourceLoc AnyLoc;
1168+
1169+
public:
1170+
ExistentialTypeRepr(SourceLoc anyLoc, TypeRepr *constraint)
1171+
: TypeRepr(TypeReprKind::Existential), Constraint(constraint),
1172+
AnyLoc(anyLoc) {}
1173+
1174+
TypeRepr *getConstraint() const { return Constraint; }
1175+
SourceLoc getAnyLoc() const { return AnyLoc; }
1176+
1177+
static bool classof(const TypeRepr *T) {
1178+
return T->getKind() == TypeReprKind::Existential;
1179+
}
1180+
static bool classof(const ExistentialTypeRepr *T) { return true; }
1181+
1182+
private:
1183+
SourceLoc getStartLocImpl() const { return AnyLoc; }
1184+
SourceLoc getEndLocImpl() const { return Constraint->getEndLoc(); }
1185+
SourceLoc getLocImpl() const { return AnyLoc; }
1186+
void printImpl(ASTPrinter &Printer, const PrintOptions &Opts) const;
1187+
friend class TypeRepr;
1188+
};
1189+
11611190
/// TypeRepr for a user-specified placeholder (essentially, a user-facing
11621191
/// representation of an anonymous type variable.
11631192
///
@@ -1285,6 +1314,7 @@ inline bool TypeRepr::isSimple() const {
12851314
case TypeReprKind::Composition:
12861315
case TypeReprKind::OpaqueReturn:
12871316
case TypeReprKind::NamedOpaqueReturn:
1317+
case TypeReprKind::Existential:
12881318
return false;
12891319
case TypeReprKind::SimpleIdent:
12901320
case TypeReprKind::GenericIdent:

Diff for: include/swift/AST/TypeReprNodes.def

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ TYPEREPR(Metatype, TypeRepr)
5555
TYPEREPR(Protocol, TypeRepr)
5656
TYPEREPR(OpaqueReturn, TypeRepr)
5757
TYPEREPR(NamedOpaqueReturn, TypeRepr)
58+
TYPEREPR(Existential, TypeRepr)
5859
TYPEREPR(Placeholder, TypeRepr)
5960
ABSTRACT_TYPEREPR(Specifier, TypeRepr)
6061
TYPEREPR(InOut, SpecifierTypeRepr)

Diff for: include/swift/AST/Types.h

+44-1
Original file line numberDiff line numberDiff line change
@@ -5202,6 +5202,42 @@ class ProtocolCompositionType final : public TypeBase,
52025202
BEGIN_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
52035203
END_CAN_TYPE_WRAPPER(ProtocolCompositionType, Type)
52045204

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

61596195
inline bool CanType::isExistentialTypeImpl(CanType type) {
6160-
return isa<ProtocolType>(type) || isa<ProtocolCompositionType>(type);
6196+
return (isa<ProtocolType>(type) ||
6197+
isa<ProtocolCompositionType>(type) ||
6198+
isa<ExistentialType>(type));
61616199
}
61626200

61636201
inline bool CanType::isAnyExistentialTypeImpl(CanType type) {
@@ -6170,6 +6208,8 @@ inline bool TypeBase::isClassExistentialType() {
61706208
return pt->requiresClass();
61716209
if (auto pct = dyn_cast<ProtocolCompositionType>(T))
61726210
return pct->requiresClass();
6211+
if (auto existential = dyn_cast<ExistentialType>(T))
6212+
return existential->requiresClass();
61736213
return false;
61746214
}
61756215

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

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

Diff for: include/swift/Basic/LangOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ namespace swift {
310310
/// `func f() -> <T> T`.
311311
bool EnableExperimentalNamedOpaqueTypes = false;
312312

313+
/// Enable support for explicit existential types via the \c any
314+
/// keyword.
315+
bool EnableExplicitExistentialTypes = false;
316+
313317
/// Enable experimental flow-sensitive concurrent captures.
314318
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
315319

Diff for: include/swift/Option/FrontendOptions.td

+4
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@ def enable_experimental_structural_opaque_types :
484484
Flag<["-"], "enable-experimental-structural-opaque-types">,
485485
HelpText<"Enable experimental support for structural opaque result types">;
486486

487+
def enable_explicit_existential_types :
488+
Flag<["-"], "enable-explicit-existential-types">,
489+
HelpText<"Enable experimental support for explicit existential types">;
490+
487491
def enable_deserialization_recovery :
488492
Flag<["-"], "enable-deserialization-recovery">,
489493
HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">;

Diff for: lib/AST/ASTContext.cpp

+16
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;
@@ -4113,6 +4114,21 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, Type Parent,
41134114
RecursiveTypeProperties properties)
41144115
: NominalType(TypeKind::Protocol, &Ctx, TheDecl, Parent, properties) { }
41154116

4117+
ExistentialType *ExistentialType::get(Type constraint) {
4118+
auto properties = constraint->getRecursiveProperties();
4119+
auto arena = getArena(properties);
4120+
4121+
auto &C = constraint->getASTContext();
4122+
auto &entry = C.getImpl().getArena(arena).ExistentialTypes[constraint];
4123+
if (entry)
4124+
return entry;
4125+
4126+
const ASTContext *canonicalContext = constraint->isCanonical() ? &C : nullptr;
4127+
return entry = new (C, arena) ExistentialType(constraint,
4128+
canonicalContext,
4129+
properties);
4130+
}
4131+
41164132
LValueType *LValueType::get(Type objectTy) {
41174133
assert(!objectTy->is<LValueType>() && !objectTy->is<InOutType>() &&
41184134
"cannot have 'inout' or @lvalue wrapped inside an @lvalue");

Diff for: lib/AST/ASTDemangler.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,12 @@ Type ASTBuilder::createProtocolCompositionType(
589589
members.push_back(protocol->getDeclaredInterfaceType());
590590
if (superclass && superclass->getClassOrBoundGenericClass())
591591
members.push_back(superclass);
592-
return ProtocolCompositionType::get(Ctx, members, isClassBound);
592+
Type composition = ProtocolCompositionType::get(Ctx, members, isClassBound);
593+
if (Ctx.LangOpts.EnableExplicitExistentialTypes &&
594+
!(composition->isAny() || composition->isAnyObject())) {
595+
composition = ExistentialType::get(composition);
596+
}
597+
return composition;
593598
}
594599

595600
static MetatypeRepresentation
@@ -607,6 +612,8 @@ getMetatypeRepresentation(ImplMetatypeRepresentation repr) {
607612

608613
Type ASTBuilder::createExistentialMetatypeType(Type instance,
609614
Optional<Demangle::ImplMetatypeRepresentation> repr) {
615+
if (auto existential = instance->getAs<ExistentialType>())
616+
instance = existential->getConstraintType();
610617
if (!instance->isAnyExistentialType())
611618
return Type();
612619
if (!repr)

0 commit comments

Comments
 (0)