Skip to content

Commit f96057e

Browse files
authored
Merge pull request #33767 from theblixguy/chore/remove-self-or-associated-type-diagnostic
SE-0309: Unlock existential types for all protocols
2 parents 3fc18f3 + 9a52220 commit f96057e

31 files changed

+825
-572
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
514514
IsComputingSemanticMembers : 1
515515
);
516516

517-
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+1+1+8+16,
517+
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+8+16,
518518
/// Whether the \c RequiresClass bit is valid.
519519
RequiresClassValid : 1,
520520

@@ -527,12 +527,6 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
527527
/// Whether the existential of this protocol conforms to itself.
528528
ExistentialConformsToSelf : 1,
529529

530-
/// Whether the \c ExistentialTypeSupported bit is valid.
531-
ExistentialTypeSupportedValid : 1,
532-
533-
/// Whether the existential of this protocol can be represented.
534-
ExistentialTypeSupported : 1,
535-
536530
/// True if the protocol has requirements that cannot be satisfied (e.g.
537531
/// because they could not be imported from Objective-C).
538532
HasMissingRequirements : 1,
@@ -4151,21 +4145,6 @@ class ProtocolDecl final : public NominalTypeDecl {
41514145
Bits.ProtocolDecl.ExistentialConformsToSelf = result;
41524146
}
41534147

4154-
/// Returns the cached result of \c existentialTypeSupported or \c None if it
4155-
/// hasn't yet been computed.
4156-
Optional<bool> getCachedExistentialTypeSupported() {
4157-
if (Bits.ProtocolDecl.ExistentialTypeSupportedValid)
4158-
return Bits.ProtocolDecl.ExistentialTypeSupported;
4159-
4160-
return None;
4161-
}
4162-
4163-
/// Caches the result of \c existentialTypeSupported
4164-
void setCachedExistentialTypeSupported(bool supported) {
4165-
Bits.ProtocolDecl.ExistentialTypeSupportedValid = true;
4166-
Bits.ProtocolDecl.ExistentialTypeSupported = supported;
4167-
}
4168-
41694148
bool hasLazyRequirementSignature() const {
41704149
return Bits.ProtocolDecl.HasLazyRequirementSignature;
41714150
}
@@ -4175,7 +4154,6 @@ class ProtocolDecl final : public NominalTypeDecl {
41754154
friend class RequirementSignatureRequest;
41764155
friend class ProtocolRequiresClassRequest;
41774156
friend class ExistentialConformsToSelfRequest;
4178-
friend class ExistentialTypeSupportedRequest;
41794157
friend class InheritedProtocolsRequest;
41804158

41814159
public:
@@ -4264,12 +4242,6 @@ class ProtocolDecl final : public NominalTypeDecl {
42644242
/// contain 'Self' in 'parameter' or 'other' position.
42654243
bool isAvailableInExistential(const ValueDecl *decl) const;
42664244

4267-
/// Determine whether we are allowed to refer to an existential type
4268-
/// conforming to this protocol. This is only permitted if the types of
4269-
/// all the members do not contain any associated types, and do not
4270-
/// contain 'Self' in 'parameter' or 'other' position.
4271-
bool existentialTypeSupported() const;
4272-
42734245
/// Returns a list of protocol requirements that must be assessed to
42744246
/// determine a concrete's conformance effect polymorphism kind.
42754247
PolymorphicEffectRequirementList getPolymorphicEffectRequirements(

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -920,9 +920,6 @@ NOTE(object_literal_resolve_import,none,
920920

921921
ERROR(use_local_before_declaration,none,
922922
"use of local variable %0 before its declaration", (DeclNameRef))
923-
ERROR(unsupported_existential_type,none,
924-
"protocol %0 can only be used as a generic constraint because it has "
925-
"Self or associated type requirements", (Identifier))
926923

927924
ERROR(decl_does_not_exist_in_module,none,
928925
"%select{%error|type|struct|class|enum|protocol|variable|function}0 "

include/swift/AST/EducationalNotes.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121

2222
// EDUCATIONAL_NOTES(DIAG_ID, EDUCATIONAL_NOTE_FILENAMES...)
2323

24-
EDUCATIONAL_NOTES(unsupported_existential_type,
25-
"associated-type-requirements.md")
24+
EDUCATIONAL_NOTES(could_not_use_member_on_existential,
25+
"existential-member-access-limitations.md")
2626

2727
EDUCATIONAL_NOTES(cannot_pass_type_to_non_ephemeral, "temporary-pointers.md")
2828
EDUCATIONAL_NOTES(cannot_pass_type_to_non_ephemeral_warning,

include/swift/AST/TypeCheckRequests.h

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

290-
/// Determine whether we are allowed to refer to an existential type conforming
291-
/// to this protocol.
292-
class ExistentialTypeSupportedRequest :
293-
public SimpleRequest<ExistentialTypeSupportedRequest,
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-
316290
class PolymorphicEffectRequirementsRequest :
317291
public SimpleRequest<PolymorphicEffectRequirementsRequest,
318292
PolymorphicEffectRequirementList(EffectKind, ProtocolDecl *),

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,6 @@ SWIFT_REQUEST(TypeChecker, EnumRawTypeRequest,
8787
Type(EnumDecl *), Cached, NoLocationInfo)
8888
SWIFT_REQUEST(TypeChecker, ExistentialConformsToSelfRequest,
8989
bool(ProtocolDecl *), SeparatelyCached, NoLocationInfo)
90-
SWIFT_REQUEST(TypeChecker, ExistentialTypeSupportedRequest,
91-
bool(ProtocolDecl *), SeparatelyCached, NoLocationInfo)
9290
SWIFT_REQUEST(TypeChecker, ExtendedTypeRequest, Type(ExtensionDecl *), Cached,
9391
NoLocationInfo)
9492
SWIFT_REQUEST(TypeChecker, ResultBuilderTypeRequest, Type(ValueDecl *),

lib/AST/Decl.cpp

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5008,24 +5008,31 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
50085008
return findProtocolSelfReferences(proto, selfType->getSelfType(), position);
50095009
}
50105010

5011-
// Most bound generic types are invariant.
5012-
if (auto *const bgt = type->getAs<BoundGenericType>()) {
5011+
if (auto *const nominal = type->getAs<NominalOrBoundGenericNominalType>()) {
50135012
auto info = SelfReferenceInfo();
50145013

5015-
if (bgt->isArray()) {
5016-
// Swift.Array preserves variance in its Value type.
5017-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
5018-
position);
5019-
} else if (bgt->isDictionary()) {
5020-
// Swift.Dictionary preserves variance in its Element type.
5021-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
5022-
SelfReferencePosition::Invariant);
5023-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().back(),
5024-
position);
5025-
} else {
5026-
for (auto paramType : bgt->getGenericArgs()) {
5027-
info |= findProtocolSelfReferences(proto, paramType,
5014+
// Don't forget to look in the parent.
5015+
if (const auto parent = nominal->getParent()) {
5016+
info |= findProtocolSelfReferences(proto, parent, position);
5017+
}
5018+
5019+
// Most bound generic types are invariant.
5020+
if (auto *const bgt = type->getAs<BoundGenericType>()) {
5021+
if (bgt->isArray()) {
5022+
// Swift.Array preserves variance in its Value type.
5023+
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
5024+
position);
5025+
} else if (bgt->isDictionary()) {
5026+
// Swift.Dictionary preserves variance in its Element type.
5027+
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
50285028
SelfReferencePosition::Invariant);
5029+
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().back(),
5030+
position);
5031+
} else {
5032+
for (auto paramType : bgt->getGenericArgs()) {
5033+
info |= findProtocolSelfReferences(proto, paramType,
5034+
SelfReferencePosition::Invariant);
5035+
}
50295036
}
50305037
}
50315038

@@ -5037,6 +5044,16 @@ findProtocolSelfReferences(const ProtocolDecl *proto, Type type,
50375044
if (type->is<OpaqueTypeArchetypeType>())
50385045
return SelfReferenceInfo::forSelfRef(SelfReferencePosition::Invariant);
50395046

5047+
// Protocol compositions preserve variance.
5048+
if (auto *comp = type->getAs<ProtocolCompositionType>()) {
5049+
// 'Self' may be referenced only in a superclass component.
5050+
if (const auto superclass = comp->getSuperclass()) {
5051+
return findProtocolSelfReferences(proto, superclass, position);
5052+
}
5053+
5054+
return SelfReferenceInfo();
5055+
}
5056+
50405057
// A direct reference to 'Self'.
50415058
if (proto->getSelfInterfaceType()->isEqual(type))
50425059
return SelfReferenceInfo::forSelfRef(position);
@@ -5136,11 +5153,6 @@ bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const {
51365153
return true;
51375154
}
51385155

5139-
bool ProtocolDecl::existentialTypeSupported() const {
5140-
return evaluateOrDefault(getASTContext().evaluator,
5141-
ExistentialTypeSupportedRequest{const_cast<ProtocolDecl *>(this)}, true);
5142-
}
5143-
51445156
StringRef ProtocolDecl::getObjCRuntimeName(
51455157
llvm::SmallVectorImpl<char> &buffer) const {
51465158
// If there is an 'objc' attribute with a name, use that name.

lib/AST/TypeCheckRequests.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -253,31 +253,6 @@ void ExistentialConformsToSelfRequest::cacheResult(bool value) const {
253253
decl->setCachedExistentialConformsToSelf(value);
254254
}
255255

256-
//----------------------------------------------------------------------------//
257-
// existentialTypeSupported computation.
258-
//----------------------------------------------------------------------------//
259-
260-
void ExistentialTypeSupportedRequest::diagnoseCycle(DiagnosticEngine &diags) const {
261-
auto decl = std::get<0>(getStorage());
262-
diags.diagnose(decl, diag::circular_protocol_def, decl->getName());
263-
}
264-
265-
void ExistentialTypeSupportedRequest::noteCycleStep(DiagnosticEngine &diags) const {
266-
auto requirement = std::get<0>(getStorage());
267-
diags.diagnose(requirement, diag::kind_declname_declared_here,
268-
DescriptiveDeclKind::Protocol, requirement->getName());
269-
}
270-
271-
Optional<bool> ExistentialTypeSupportedRequest::getCachedResult() const {
272-
auto decl = std::get<0>(getStorage());
273-
return decl->getCachedExistentialTypeSupported();
274-
}
275-
276-
void ExistentialTypeSupportedRequest::cacheResult(bool value) const {
277-
auto decl = std::get<0>(getStorage());
278-
decl->setCachedExistentialTypeSupported(value);
279-
}
280-
281256
//----------------------------------------------------------------------------//
282257
// isFinal computation.
283258
//----------------------------------------------------------------------------//

lib/Sema/CSSimplify.cpp

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7322,7 +7322,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
73227322
// Dig out the instance type and figure out what members of the instance type
73237323
// we are going to see.
73247324
auto baseTy = candidate.getBaseType();
7325-
auto baseObjTy = baseTy->getRValueType();
7325+
const auto baseObjTy = baseTy->getRValueType();
73267326

73277327
bool hasInstanceMembers = false;
73287328
bool hasInstanceMethods = false;
@@ -7369,18 +7369,6 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
73697369
hasInstanceMethods = true;
73707370
}
73717371

7372-
// If our base is an existential type, we can't make use of any
7373-
// member whose signature involves associated types.
7374-
if (instanceTy->isExistentialType()) {
7375-
if (auto *proto = decl->getDeclContext()->getSelfProtocolDecl()) {
7376-
if (!proto->isAvailableInExistential(decl)) {
7377-
result.addUnviable(candidate,
7378-
MemberLookupResult::UR_UnavailableInExistential);
7379-
return;
7380-
}
7381-
}
7382-
}
7383-
73847372
// If the invocation's argument expression has a favored type,
73857373
// use that information to determine whether a specific overload for
73867374
// the candidate should be favored.
@@ -7400,6 +7388,20 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
74007388
}
74017389
}
74027390

7391+
const auto isUnsupportedExistentialMemberAccess = [&] {
7392+
// If our base is an existential type, we can't make use of any
7393+
// member whose signature involves associated types.
7394+
if (instanceTy->isExistentialType()) {
7395+
if (auto *proto = decl->getDeclContext()->getSelfProtocolDecl()) {
7396+
if (!proto->isAvailableInExistential(decl)) {
7397+
return true;
7398+
}
7399+
}
7400+
}
7401+
7402+
return false;
7403+
};
7404+
74037405
// See if we have an instance method, instance member or static method,
74047406
// and check if it can be accessed on our base type.
74057407

@@ -7413,20 +7415,35 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
74137415
? candidate
74147416
: OverloadChoice(instanceTy, decl,
74157417
FunctionRefKind::SingleApply);
7416-
// If this is an instance member referenced from metatype
7417-
// let's add unviable result to the set because it could be
7418-
// either curried reference or an invalid call.
7419-
//
7420-
// New candidate shouldn't affect performance because such
7421-
// choice would only be attempted when solver is in diagnostic mode.
7422-
result.addUnviable(choice, MemberLookupResult::UR_InstanceMemberOnType);
7423-
7424-
bool invalidMethodRef = isa<FuncDecl>(decl) && !hasInstanceMethods;
7425-
bool invalidMemberRef = !isa<FuncDecl>(decl) && !hasInstanceMembers;
7426-
// If this is definitely an invalid way to reference a method or member
7427-
// on the metatype, let's stop here.
7428-
if (invalidMethodRef || invalidMemberRef)
7418+
7419+
const bool invalidMethodRef = isa<FuncDecl>(decl) && !hasInstanceMethods;
7420+
const bool invalidMemberRef = !isa<FuncDecl>(decl) && !hasInstanceMembers;
7421+
7422+
if (invalidMethodRef || invalidMemberRef) {
7423+
// If this is definitely an invalid way to reference a method or member
7424+
// on the metatype, let's stop here.
7425+
result.addUnviable(choice,
7426+
MemberLookupResult::UR_InstanceMemberOnType);
7427+
return;
7428+
} else if (isUnsupportedExistentialMemberAccess()) {
7429+
// If the member reference itself is legal, but it turns out to be an
7430+
// unsupported existential member access, do not make further
7431+
// assumptions about the correctness of a potential call -- let
7432+
// the unsupported member access error prevail.
7433+
result.addUnviable(candidate,
7434+
MemberLookupResult::UR_UnavailableInExistential);
74297435
return;
7436+
} else {
7437+
// Otherwise, still add an unviable result to the set, because it
7438+
// could be an invalid call that was supposed to be performed on an
7439+
// instance of the type.
7440+
//
7441+
// New candidate shouldn't affect performance because such
7442+
// choice would only be attempted when solver is in diagnostic mode.
7443+
result.addUnviable(choice,
7444+
MemberLookupResult::UR_InstanceMemberOnType);
7445+
7446+
}
74307447
}
74317448

74327449
// If the underlying type of a typealias is fully concrete, it is legal
@@ -7477,6 +7494,12 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
74777494
}
74787495
}
74797496

7497+
if (isUnsupportedExistentialMemberAccess()) {
7498+
result.addUnviable(candidate,
7499+
MemberLookupResult::UR_UnavailableInExistential);
7500+
return;
7501+
}
7502+
74807503
// If we have an rvalue base, make sure that the result isn't 'mutating'
74817504
// (only valid on lvalues).
74827505
if (!baseTy->is<AnyMetatypeType>() &&

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3329,8 +3329,6 @@ static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt) {
33293329
// We want to warn about "case .Foo, .Bar where 1 != 100:" since the where
33303330
// clause only applies to the second case, and this is surprising.
33313331
for (auto cs : stmt->getCases()) {
3332-
TypeChecker::checkUnsupportedProtocolType(ctx, cs);
3333-
33343332
// The case statement can have multiple case items, each can have a where.
33353333
// If we find a "where", and there is a preceding item without a where, and
33363334
// if they are on the same source line, then warn.
@@ -4747,8 +4745,6 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
47474745
void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) {
47484746
auto &ctx = DC->getASTContext();
47494747

4750-
TypeChecker::checkUnsupportedProtocolType(ctx, const_cast<Stmt *>(S));
4751-
47524748
if (auto switchStmt = dyn_cast<SwitchStmt>(S))
47534749
checkSwitch(ctx, switchStmt);
47544750

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -672,34 +672,6 @@ ExistentialConformsToSelfRequest::evaluate(Evaluator &evaluator,
672672
return true;
673673
}
674674

675-
bool
676-
ExistentialTypeSupportedRequest::evaluate(Evaluator &evaluator,
677-
ProtocolDecl *decl) const {
678-
// ObjC protocols can always be existential.
679-
if (decl->isObjC())
680-
return true;
681-
682-
for (auto member : decl->getMembers()) {
683-
// Existential types cannot be used if the protocol has an associated type.
684-
if (isa<AssociatedTypeDecl>(member))
685-
return false;
686-
687-
// For value members, look at their type signatures.
688-
if (auto valueMember = dyn_cast<ValueDecl>(member)) {
689-
if (!decl->isAvailableInExistential(valueMember))
690-
return false;
691-
}
692-
}
693-
694-
// Check whether all of the inherited protocols support existential types.
695-
for (auto proto : decl->getInheritedProtocols()) {
696-
if (!proto->existentialTypeSupported())
697-
return false;
698-
}
699-
700-
return true;
701-
}
702-
703675
bool
704676
IsFinalRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
705677
if (isa<ClassDecl>(decl))

0 commit comments

Comments
 (0)