Skip to content

Commit b3ee4b0

Browse files
committed
AST, Sema: Use the opened archetype's generic signature to determine existential member availability
1 parent 756bf30 commit b3ee4b0

16 files changed

+949
-345
lines changed

include/swift/AST/Decl.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,14 +2674,15 @@ class ValueDecl : public Decl {
26742674
/// that this declaration dynamically replaces.
26752675
ValueDecl *getDynamicallyReplacedDecl() const;
26762676

2677-
/// Report 'Self' references within the type of this protocol member.
2677+
/// Report 'Self' references within the type of this declaration as a
2678+
/// member of the given existential base type.
26782679
///
26792680
/// \param treatNonResultCovariantSelfAsInvariant If true, 'Self' or 'Self?'
26802681
/// is considered covariant only when it appears as the immediate type of a
2681-
/// property, or the uncurried result type of a method/subscript.
2682-
SelfReferenceInfo
2683-
findProtocolSelfReferences(const ProtocolDecl *proto,
2684-
bool treatNonResultCovariantSelfAsInvariant) const;
2682+
/// property, or the uncurried result type of a method/subscript, e.g.
2683+
/// '() -> () -> Self'.
2684+
SelfReferenceInfo findExistentialSelfReferences(
2685+
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const;
26852686
};
26862687

26872688
/// This is a common base class for declarations which declare a type.

include/swift/AST/GenericSignature.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
390390

391391
bool isCanonicalTypeInContext(Type type) const;
392392

393+
/// Determine whether the given type parameter is defined under this generic
394+
/// signature.
393395
bool isValidTypeInContext(Type type) const;
394396

395397
/// Retrieve the conformance access path used to extract the conformance of
@@ -428,6 +430,13 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
428430
/// generic parameter types by their sugared form.
429431
Type getSugaredType(Type type) const;
430432

433+
/// Given a type parameter, compute the most specific supertype (upper bound)
434+
/// that is not dependent on other type parameters.
435+
///
436+
/// \note If the upper bound is a protocol or protocol composition,
437+
/// will return an instance of \c ExistentialType.
438+
Type getNonDependentUpperBounds(Type type) const;
439+
431440
static void Profile(llvm::FoldingSetNodeID &ID,
432441
TypeArrayView<GenericTypeParamType> genericParams,
433442
ArrayRef<Requirement> requirements);

include/swift/AST/Types.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -513,13 +513,13 @@ class alignas(1 << TypeAlignInBits) TypeBase
513513
TypeBase *getWithoutSyntaxSugar();
514514

515515
/// getASTContext - Return the ASTContext that this type belongs to.
516-
ASTContext &getASTContext();
517-
516+
ASTContext &getASTContext() const;
517+
518518
/// isEqual - Return true if these two types are equal, ignoring sugar.
519519
///
520520
/// To compare sugar, check for pointer equality of the underlying TypeBase *
521521
/// values, obtained by calling getPointer().
522-
bool isEqual(Type Other);
522+
bool isEqual(Type Other) const;
523523

524524
/// getDesugaredType - If this type is a sugared type, remove all levels of
525525
/// sugar until we get down to a non-sugar type.
@@ -621,7 +621,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
621621

622622
/// Determine whether the type involves the given opened existential
623623
/// archetype.
624-
bool hasOpenedExistential(OpenedArchetypeType *opened);
624+
bool hasOpenedExistential(const OpenedArchetypeType *opened);
625625

626626
/// Determine whether the type involves an opaque type.
627627
bool hasOpaqueArchetype() const {
@@ -641,9 +641,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
641641
/// within this type.
642642
void getOpenedExistentials(SmallVectorImpl<OpenedArchetypeType *> &opened);
643643

644-
/// Erase the given opened existential type by replacing it with its
645-
/// existential type throughout the given type.
646-
Type eraseOpenedExistential(OpenedArchetypeType *opened);
644+
/// Replace opened archetypes with the given root with their most
645+
/// specific non-dependent upper bounds throughout this type.
646+
Type typeEraseOpenedArchetypesWithRoot(const OpenedArchetypeType *root) const;
647647

648648
/// Given a declaration context, returns a function type with the 'self'
649649
/// type curried as the input if the declaration context describes a type.
@@ -6287,7 +6287,7 @@ BEGIN_CAN_TYPE_WRAPPER(PackExpansionType, Type)
62876287
END_CAN_TYPE_WRAPPER(PackExpansionType, Type)
62886288

62896289
/// getASTContext - Return the ASTContext that this type belongs to.
6290-
inline ASTContext &TypeBase::getASTContext() {
6290+
inline ASTContext &TypeBase::getASTContext() const {
62916291
// If this type is canonical, it has the ASTContext in it.
62926292
if (isCanonical())
62936293
return *const_cast<ASTContext*>(Context);

include/swift/Sema/ConstraintSystem.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5296,12 +5296,13 @@ class ConstraintSystem {
52965296
/// in (if any) has a result builder applied to its body.
52975297
bool isInResultBuilderContext(ClosureExpr *closure) const;
52985298

5299-
/// Determine whether we are allowed to refer to an existential type
5300-
/// conforming to the given protocol. This is only permitted if the type of
5301-
/// the member does not contain any associated types, and does not
5302-
/// contain 'Self' in 'parameter' or 'other' position.
5303-
bool isAvailableInExistential(const ProtocolDecl *proto,
5304-
const ValueDecl *member) const;
5299+
/// Determine whether referencing the given member on the
5300+
/// given existential base type is supported. This is the case only if the
5301+
/// type of the member, spelled in the context of \p baseTy,
5302+
/// - does not contain any 'Self'-rooted dependent member types, and
5303+
/// - does not contain 'Self' in non-covariant position.
5304+
bool isMemberAvailableOnExistential(Type baseTy,
5305+
const ValueDecl *member) const;
53055306

53065307
SWIFT_DEBUG_DUMP;
53075308
SWIFT_DEBUG_DUMPER(dump(Expr *));

lib/AST/Decl.cpp

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3739,12 +3739,13 @@ SelfReferenceInfo::operator|=(const SelfReferenceInfo &other) {
37393739
return *this;
37403740
}
37413741

3742-
/// Report references to 'Self' within the given type.
3742+
/// Report references to 'Self' within the given type using the given
3743+
/// existential generic signature.
37433744
///
37443745
/// \param position The current position in terms of variance.
3745-
static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
3746-
Type type,
3747-
TypePosition position) {
3746+
static SelfReferenceInfo
3747+
findExistentialSelfReferences(CanGenericSignature existentialSig, Type type,
3748+
TypePosition position) {
37483749
// If there are no type parameters, we're done.
37493750
if (!type->hasTypeParameter())
37503751
return SelfReferenceInfo();
@@ -3753,7 +3754,8 @@ static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
37533754
if (auto tuple = type->getAs<TupleType>()) {
37543755
auto info = SelfReferenceInfo();
37553756
for (auto &elt : tuple->getElements()) {
3756-
info |= findProtocolSelfReferences(proto, elt.getType(), position);
3757+
info |= findExistentialSelfReferences(existentialSig, elt.getType(),
3758+
position);
37573759
}
37583760

37593761
// A covariant Self result inside a tuple will not be bona fide.
@@ -3769,19 +3771,19 @@ static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
37693771
for (auto param : funcTy->getParams()) {
37703772
// inout parameters are invariant.
37713773
if (param.isInOut()) {
3772-
inputInfo |= findProtocolSelfReferences(proto, param.getPlainType(),
3773-
TypePosition::Invariant);
3774+
inputInfo |= findExistentialSelfReferences(
3775+
existentialSig, param.getPlainType(), TypePosition::Invariant);
37743776
continue;
37753777
}
3776-
inputInfo |= findProtocolSelfReferences(proto, param.getParameterType(),
3777-
position.flipped());
3778+
inputInfo |= findExistentialSelfReferences(
3779+
existentialSig, param.getParameterType(), position.flipped());
37783780
}
37793781

37803782
// A covariant Self result inside a parameter will not be bona fide.
37813783
inputInfo.hasCovariantSelfResult = false;
37823784

3783-
auto resultInfo =
3784-
findProtocolSelfReferences(proto, funcTy->getResult(), position);
3785+
auto resultInfo = findExistentialSelfReferences(
3786+
existentialSig, funcTy->getResult(), position);
37853787
if (resultInfo.selfRef == TypePosition::Covariant) {
37863788
resultInfo.hasCovariantSelfResult = true;
37873789
}
@@ -3790,46 +3792,48 @@ static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
37903792

37913793
// Metatypes preserve variance.
37923794
if (auto metaTy = type->getAs<MetatypeType>()) {
3793-
return findProtocolSelfReferences(proto, metaTy->getInstanceType(),
3794-
position);
3795+
return findExistentialSelfReferences(existentialSig,
3796+
metaTy->getInstanceType(), position);
37953797
}
37963798

37973799
// Optionals preserve variance.
37983800
if (auto optType = type->getOptionalObjectType()) {
3799-
return findProtocolSelfReferences(proto, optType, position);
3801+
return findExistentialSelfReferences(existentialSig, optType, position);
38003802
}
38013803

38023804
// DynamicSelfType preserves variance.
38033805
// FIXME: This shouldn't ever appear in protocol requirement
38043806
// signatures.
38053807
if (auto selfType = type->getAs<DynamicSelfType>()) {
3806-
return findProtocolSelfReferences(proto, selfType->getSelfType(), position);
3808+
return findExistentialSelfReferences(existentialSig,
3809+
selfType->getSelfType(), position);
38073810
}
38083811

38093812
if (auto *const nominal = type->getAs<NominalOrBoundGenericNominalType>()) {
38103813
auto info = SelfReferenceInfo();
38113814

38123815
// Don't forget to look in the parent.
38133816
if (const auto parent = nominal->getParent()) {
3814-
info |= findProtocolSelfReferences(proto, parent, position);
3817+
info |= findExistentialSelfReferences(existentialSig, parent, position);
38153818
}
38163819

38173820
// Most bound generic types are invariant.
38183821
if (auto *const bgt = type->getAs<BoundGenericType>()) {
38193822
if (bgt->isArray()) {
3820-
// Swift.Array preserves variance in its Value type.
3821-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
3822-
position);
3823+
// Swift.Array preserves variance in its 'Value' type.
3824+
info |= findExistentialSelfReferences(
3825+
existentialSig, bgt->getGenericArgs().front(), position);
38233826
} else if (bgt->isDictionary()) {
3824-
// Swift.Dictionary preserves variance in its Element type.
3825-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().front(),
3826-
TypePosition::Invariant);
3827-
info |= findProtocolSelfReferences(proto, bgt->getGenericArgs().back(),
3828-
position);
3827+
// Swift.Dictionary preserves variance in its 'Element' type.
3828+
info |= findExistentialSelfReferences(existentialSig,
3829+
bgt->getGenericArgs().front(),
3830+
TypePosition::Invariant);
3831+
info |= findExistentialSelfReferences(
3832+
existentialSig, bgt->getGenericArgs().back(), position);
38293833
} else {
38303834
for (auto paramType : bgt->getGenericArgs()) {
3831-
info |= findProtocolSelfReferences(proto, paramType,
3832-
TypePosition::Invariant);
3835+
info |= findExistentialSelfReferences(existentialSig, paramType,
3836+
TypePosition::Invariant);
38333837
}
38343838
}
38353839
}
@@ -3849,29 +3853,45 @@ static SelfReferenceInfo findProtocolSelfReferences(const ProtocolDecl *proto,
38493853
if (auto *comp = constraint->getAs<ProtocolCompositionType>()) {
38503854
// 'Self' may be referenced only in a superclass component.
38513855
if (const auto superclass = comp->getSuperclass()) {
3852-
return findProtocolSelfReferences(proto, superclass, position);
3856+
return findExistentialSelfReferences(existentialSig, superclass,
3857+
position);
38533858
}
38543859

38553860
return SelfReferenceInfo();
38563861
}
38573862

3863+
if (!type->isTypeParameter()) {
3864+
return SelfReferenceInfo();
3865+
}
3866+
3867+
const auto selfTy = existentialSig.getGenericParams().front();
3868+
if (!type->getRootGenericParam()->isEqual(selfTy)) {
3869+
return SelfReferenceInfo();
3870+
}
3871+
38583872
// A direct reference to 'Self'.
3859-
if (proto->getSelfInterfaceType()->isEqual(type))
3873+
if (selfTy->isEqual(type)) {
38603874
return SelfReferenceInfo::forSelfRef(position);
3875+
}
38613876

3862-
// A reference to an associated type rooted on 'Self'.
3863-
if (type->is<DependentMemberType>()) {
3864-
type = type->getRootGenericParam();
3865-
if (proto->getSelfInterfaceType()->isEqual(type))
3866-
return SelfReferenceInfo::forAssocTypeRef(position);
3877+
// If the type parameter is beyond the domain of the existential generic
3878+
// signature, ignore it.
3879+
if (!existentialSig->isValidTypeInContext(type)) {
3880+
return SelfReferenceInfo();
38673881
}
38683882

3869-
return SelfReferenceInfo();
3883+
if (const auto concreteTy = existentialSig->getConcreteType(type)) {
3884+
return findExistentialSelfReferences(existentialSig, concreteTy, position);
3885+
}
3886+
3887+
// A reference to an associated type rooted on 'Self'.
3888+
return SelfReferenceInfo::forAssocTypeRef(position);
38703889
}
38713890

3872-
SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
3873-
const ProtocolDecl *proto,
3874-
bool treatNonResultCovariantSelfAsInvariant) const {
3891+
SelfReferenceInfo ValueDecl::findExistentialSelfReferences(
3892+
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const {
3893+
assert(baseTy->isExistentialType());
3894+
38753895
// Types never refer to 'Self'.
38763896
if (isa<TypeDecl>(this))
38773897
return SelfReferenceInfo();
@@ -3882,6 +3902,8 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
38823902
if (type->hasError())
38833903
return SelfReferenceInfo();
38843904

3905+
const auto sig = getASTContext().getOpenedArchetypeSignature(baseTy);
3906+
38853907
if (isa<AbstractFunctionDecl>(this) || isa<SubscriptDecl>(this)) {
38863908
// For a method, skip the 'self' parameter.
38873909
if (isa<AbstractFunctionDecl>(this))
@@ -3891,12 +3913,12 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
38913913
for (auto param : type->castTo<AnyFunctionType>()->getParams()) {
38923914
// inout parameters are invariant.
38933915
if (param.isInOut()) {
3894-
inputInfo |= ::findProtocolSelfReferences(proto, param.getPlainType(),
3895-
TypePosition::Invariant);
3916+
inputInfo |= ::findExistentialSelfReferences(sig, param.getPlainType(),
3917+
TypePosition::Invariant);
38963918
continue;
38973919
}
3898-
inputInfo |= ::findProtocolSelfReferences(proto, param.getParameterType(),
3899-
TypePosition::Contravariant);
3920+
inputInfo |= ::findExistentialSelfReferences(
3921+
sig, param.getParameterType(), TypePosition::Contravariant);
39003922
}
39013923

39023924
// A covariant Self result inside a parameter will not be bona fide.
@@ -3913,8 +3935,8 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
39133935
inputInfo.selfRef = TypePosition::Invariant;
39143936
}
39153937

3916-
auto resultInfo = ::findProtocolSelfReferences(
3917-
proto, type->castTo<AnyFunctionType>()->getResult(),
3938+
auto resultInfo = ::findExistentialSelfReferences(
3939+
sig, type->castTo<AnyFunctionType>()->getResult(),
39183940
TypePosition::Covariant);
39193941
if (resultInfo.selfRef == TypePosition::Covariant) {
39203942
resultInfo.hasCovariantSelfResult = true;
@@ -3925,7 +3947,7 @@ SelfReferenceInfo ValueDecl::findProtocolSelfReferences(
39253947
assert(isa<VarDecl>(this));
39263948

39273949
auto info =
3928-
::findProtocolSelfReferences(proto, type, TypePosition::Covariant);
3950+
::findExistentialSelfReferences(sig, type, TypePosition::Covariant);
39293951
if (info.selfRef == TypePosition::Covariant) {
39303952
info.hasCovariantSelfResult = true;
39313953
}

lib/AST/GenericEnvironment.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,11 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
290290
switch (getKind()) {
291291
case Kind::Normal:
292292
case Kind::OpenedExistential:
293-
return mapTypeIntoContext(type, conformanceLookupFn);
294-
293+
if (type->hasTypeParameter()) {
294+
return mapTypeIntoContext(type, conformanceLookupFn);
295+
} else {
296+
return type;
297+
}
295298
case Kind::Opaque:
296299
return maybeApplyOpaqueTypeSubstitutions(type);
297300
}

lib/AST/GenericSignature.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,37 @@ unsigned GenericSignatureImpl::getGenericParamOrdinal(
542542
return GenericParamKey(param).findIndexIn(getGenericParams());
543543
}
544544

545+
Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
546+
assert(type->isTypeParameter());
547+
548+
llvm::SmallVector<Type, 2> types;
549+
if (Type superclass = getSuperclassBound(type)) {
550+
// If the class contains a type parameter, try looking for a non-dependent
551+
// superclass.
552+
while (superclass && superclass->hasTypeParameter()) {
553+
superclass = superclass->getSuperclass();
554+
}
555+
556+
if (superclass)
557+
types.push_back(superclass);
558+
}
559+
for (const auto &elt : getRequiredProtocols(type)) {
560+
types.push_back(elt->getDeclaredInterfaceType());
561+
}
562+
563+
const auto layout = getLayoutConstraint(type);
564+
const auto boundsTy = ProtocolCompositionType::get(
565+
getASTContext(), types,
566+
/*HasExplicitAnyObject=*/layout &&
567+
layout->getKind() == LayoutConstraintKind::Class);
568+
569+
if (boundsTy->isExistentialType()) {
570+
return ExistentialType::get(boundsTy);
571+
}
572+
573+
return boundsTy;
574+
}
575+
545576
void GenericSignature::Profile(llvm::FoldingSetNodeID &id) const {
546577
return GenericSignature::Profile(id, getPointer()->getGenericParams(),
547578
getPointer()->getRequirements());

0 commit comments

Comments
 (0)