Skip to content

Commit 733648b

Browse files
committed
[Sema] When explicit existential types are enabled, type witnesses that
resolve to ProtocolType or ProtocolCompositionType are always existential types. This can happen because type aliases to protocol constraints can also be used as type witnesses. The type alias itself is still a constraint, because it can be used in generic signatures in addition to being used as an existential type, e.g. in parameter position. So, we need to wrap the type alias in an ExistentialType during type witness resolution.
1 parent 5e4fbc4 commit 733648b

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

include/swift/AST/Type.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ class CanType : public Type {
385385

386386
static bool isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig,
387387
bool functionsCount);
388+
static bool isConstraintTypeImpl(CanType type);
388389
static bool isExistentialTypeImpl(CanType type);
389390
static bool isAnyExistentialTypeImpl(CanType type);
390391
static bool isObjCExistentialTypeImpl(CanType type);
@@ -457,6 +458,10 @@ class CanType : public Type {
457458
/*functions count*/ false);
458459
}
459460

461+
bool isConstraintType() const {
462+
return isConstraintTypeImpl(*this);
463+
}
464+
460465
/// Is this type existential?
461466
bool isExistentialType() const {
462467
return isExistentialTypeImpl(*this);

include/swift/AST/Types.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
727727
return getRecursiveProperties().hasDependentMember();
728728
}
729729

730+
/// Whether this type represents a generic constraint.
731+
bool isConstraintType() const;
732+
730733
/// isExistentialType - Determines whether this type is an existential type,
731734
/// whose real (runtime) type is unknown but which is known to conform to
732735
/// some set of protocols. Protocol and protocol-conformance types are
@@ -6335,6 +6338,15 @@ inline GenericTypeParamType *TypeBase::getRootGenericParam() {
63356338
return t->castTo<GenericTypeParamType>();
63366339
}
63376340

6341+
inline bool TypeBase::isConstraintType() const {
6342+
return getCanonicalType().isConstraintType();
6343+
}
6344+
6345+
inline bool CanType::isConstraintTypeImpl(CanType type) {
6346+
return (isa<ProtocolType>(type) ||
6347+
isa<ProtocolCompositionType>(type));
6348+
}
6349+
63386350
inline bool TypeBase::isExistentialType() {
63396351
return getCanonicalType().isExistentialType();
63406352
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4783,6 +4783,23 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
47834783
auto memberType = TypeChecker::substMemberTypeWithBase(DC->getParentModule(),
47844784
typeDecl, Adoptee);
47854785

4786+
// Type witnesses that resolve to constraint types are always
4787+
// existential types. This can only happen when the type witness
4788+
// is explicitly written with a type alias. The type alias itself
4789+
// is still a constraint type because it can be used as both a
4790+
// type witness and as a generic constraint.
4791+
//
4792+
// With SE-0335, using a type alias as both a type witness and a generic
4793+
// constraint will be disallowed in Swift 6, because existential types
4794+
// must be explicit, and a generic constraint isn't a valid type witness.
4795+
//
4796+
// Note that Any and AnyObject aren't yet resolved using ExistentialType.
4797+
if (getASTContext().LangOpts.EnableExplicitExistentialTypes &&
4798+
memberType->isConstraintType() &&
4799+
!(memberType->isAny() || memberType->isAnyObject())) {
4800+
memberType = ExistentialType::get(memberType);
4801+
}
4802+
47864803
if (!viableTypes.insert(memberType->getCanonicalType()).second)
47874804
continue;
47884805

test/type/explicit_existential.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,24 @@ func testMetatypes() {
164164
}
165165

166166
func generic<T: any P1>(_ t: T) {} // expected-error {{type 'T' constrained to non-protocol, non-class type 'any P1'}}
167+
168+
protocol RawRepresentable {
169+
associatedtype RawValue
170+
var rawValue: RawValue { get }
171+
}
172+
173+
enum E1: RawRepresentable {
174+
typealias RawValue = P1
175+
176+
var rawValue: P1 {
177+
return ConcreteComposition()
178+
}
179+
}
180+
181+
enum E2: RawRepresentable {
182+
typealias RawValue = any P1
183+
184+
var rawValue: any P1 {
185+
return ConcreteComposition()
186+
}
187+
}

0 commit comments

Comments
 (0)