Skip to content

Commit 85419cf

Browse files
authored
Merge pull request #61942 from slavapestov/archetype-existential-type-fixes
More accurate ArchetypeType::getExistentialType()
2 parents 50439e5 + f9867b7 commit 85419cf

15 files changed

+257
-64
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4721,7 +4721,7 @@ class ProtocolDecl final : public NominalTypeDecl {
47214721
AssociatedTypeDecl *getAssociatedType(Identifier name) const;
47224722

47234723
/// Returns the existential type for this protocol.
4724-
Type getExistentialType() const {
4724+
Type getDeclaredExistentialType() const {
47254725
return ExistentialType::get(getDeclaredInterfaceType());
47264726
}
47274727

include/swift/AST/GenericSignature.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
457457
/// will return an instance of \c ExistentialType.
458458
Type getNonDependentUpperBounds(Type type) const;
459459

460+
/// Given a type parameter, compute the most specific supertype (upper bound)
461+
/// that is possibly dependent on other type parameters.
462+
///
463+
/// \note If the upper bound is a protocol or protocol composition,
464+
/// will return an instance of \c ExistentialType.
465+
Type getDependentUpperBounds(Type type) const;
466+
460467
static void Profile(llvm::FoldingSetNodeID &ID,
461468
TypeArrayView<GenericTypeParamType> genericParams,
462469
ArrayRef<Requirement> requirements);

include/swift/AST/Types.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6689,17 +6689,6 @@ inline bool TypeBase::isOpenedExistential() const {
66896689
return isa<OpenedArchetypeType>(T);
66906690
}
66916691

6692-
inline bool TypeBase::isOpenedExistentialWithError() {
6693-
if (!hasOpenedExistential())
6694-
return false;
6695-
6696-
CanType T = getCanonicalType();
6697-
if (auto archetype = dyn_cast<OpenedArchetypeType>(T)) {
6698-
return archetype->getExistentialType()->isExistentialWithError();
6699-
}
6700-
return false;
6701-
}
6702-
67036692
inline bool TypeBase::canDynamicallyBeOptionalType(bool includeExistential) {
67046693
CanType T = getCanonicalType();
67056694
auto isArchetypeOrExistential = isa<ArchetypeType>(T) ||

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -930,8 +930,8 @@ Type ASTContext::get##NAME##Type() const { \
930930
#include "swift/AST/KnownStdlibTypes.def"
931931

932932
CanType ASTContext::getErrorExistentialType() const {
933-
if (auto exn = getErrorDecl()) {
934-
return exn->getExistentialType()->getCanonicalType();
933+
if (auto *errorProto = getErrorDecl()) {
934+
return errorProto->getDeclaredExistentialType()->getCanonicalType();
935935
} else {
936936
// Use Builtin.NativeObject just as a stand-in.
937937
return TheNativeObjectType;
@@ -2605,7 +2605,7 @@ ASTContext::getSelfConformance(ProtocolDecl *protocol) {
26052605
auto &entry = selfConformances[protocol];
26062606
if (!entry) {
26072607
entry = new (*this, AllocationArena::Permanent)
2608-
SelfProtocolConformance(protocol->getExistentialType());
2608+
SelfProtocolConformance(protocol->getDeclaredExistentialType());
26092609
}
26102610
return entry;
26112611
}

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6473,6 +6473,13 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
64736473
if (auto existential = constraint->getAs<ExistentialType>())
64746474
constraint = existential->getConstraintType();
64756475

6476+
// Opaque archetype substitutions are always canonical, so re-sugar the
6477+
// constraint type using the owning declaration's generic parameter names.
6478+
auto genericSig = T->getDecl()->getNamingDecl()->getInnermostDeclContext()
6479+
->getGenericSignatureOfContext();
6480+
if (genericSig)
6481+
constraint = genericSig->getSugaredType(constraint);
6482+
64766483
visit(constraint);
64776484
return;
64786485
}

lib/AST/GenericSignature.cpp

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,8 @@ unsigned GenericSignatureImpl::getGenericParamOrdinal(
598598
Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
599599
assert(type->isTypeParameter());
600600

601+
bool hasExplicitAnyObject = requiresClass(type);
602+
601603
llvm::SmallVector<Type, 2> types;
602604
if (Type superclass = getSuperclassBound(type)) {
603605
// If the class contains a type parameter, try looking for a non-dependent
@@ -606,24 +608,119 @@ Type GenericSignatureImpl::getNonDependentUpperBounds(Type type) const {
606608
superclass = superclass->getSuperclass();
607609
}
608610

609-
if (superclass)
611+
if (superclass) {
610612
types.push_back(superclass);
613+
hasExplicitAnyObject = false;
614+
}
611615
}
612-
for (const auto &elt : getRequiredProtocols(type)) {
613-
types.push_back(elt->getDeclaredInterfaceType());
616+
for (auto *proto : getRequiredProtocols(type)) {
617+
if (proto->requiresClass())
618+
hasExplicitAnyObject = false;
619+
620+
types.push_back(proto->getDeclaredInterfaceType());
614621
}
615622

616-
const auto layout = getLayoutConstraint(type);
617-
const auto boundsTy = ProtocolCompositionType::get(
623+
auto constraint = ProtocolCompositionType::get(
618624
getASTContext(), types,
619-
/*HasExplicitAnyObject=*/layout &&
620-
layout->getKind() == LayoutConstraintKind::Class);
625+
hasExplicitAnyObject);
626+
627+
if (!constraint->isConstraintType()) {
628+
assert(constraint->getClassOrBoundGenericClass());
629+
return constraint;
630+
}
631+
632+
return ExistentialType::get(constraint);
633+
}
634+
635+
Type GenericSignatureImpl::getDependentUpperBounds(Type type) const {
636+
assert(type->isTypeParameter());
637+
638+
llvm::SmallVector<Type, 2> types;
639+
640+
auto &ctx = type->getASTContext();
641+
642+
bool hasExplicitAnyObject = requiresClass(type);
643+
644+
// FIXME: If the superclass bound is implied by one of our protocols, we
645+
// shouldn't add it to the constraint type.
646+
if (Type superclass = getSuperclassBound(type)) {
647+
types.push_back(superclass);
648+
hasExplicitAnyObject = false;
649+
}
650+
651+
for (auto proto : getRequiredProtocols(type)) {
652+
if (proto->requiresClass())
653+
hasExplicitAnyObject = false;
654+
655+
auto *baseType = proto->getDeclaredInterfaceType()->castTo<ProtocolType>();
656+
657+
auto primaryAssocTypes = proto->getPrimaryAssociatedTypes();
658+
if (!primaryAssocTypes.empty()) {
659+
SmallVector<Type, 2> argTypes;
660+
661+
// Attempt to recover same-type requirements on primary associated types.
662+
for (auto *assocType : primaryAssocTypes) {
663+
// For each primary associated type A of P, compute the reduced type
664+
// of T.[P]A.
665+
auto *memberType = DependentMemberType::get(type, assocType);
666+
auto reducedType = getReducedType(memberType);
667+
668+
// If the reduced type is at a lower depth than the root generic
669+
// parameter of T, then it's constrained.
670+
bool hasOuterGenericParam = false;
671+
bool hasInnerGenericParam = false;
672+
reducedType.visit([&](Type t) {
673+
if (auto *paramTy = t->getAs<GenericTypeParamType>()) {
674+
unsigned rootDepth = type->getRootGenericParam()->getDepth();
675+
if (paramTy->getDepth() == rootDepth)
676+
hasInnerGenericParam = true;
677+
else {
678+
assert(paramTy->getDepth() < rootDepth);
679+
hasOuterGenericParam = true;
680+
}
681+
}
682+
});
683+
684+
if (hasInnerGenericParam && hasOuterGenericParam) {
685+
llvm::errs() << "Weird same-type requirements?\n";
686+
llvm::errs() << "Interface type: " << type << "\n";
687+
llvm::errs() << "Member type: " << memberType << "\n";
688+
llvm::errs() << "Reduced member type: " << reducedType << "\n";
689+
llvm::errs() << GenericSignature(this) << "\n";
690+
abort();
691+
}
692+
693+
if (!hasInnerGenericParam)
694+
argTypes.push_back(reducedType);
695+
}
696+
697+
// We should have either constrained all primary associated types,
698+
// or none of them.
699+
if (!argTypes.empty()) {
700+
if (argTypes.size() != primaryAssocTypes.size()) {
701+
llvm::errs() << "Not all primary associated types constrained?\n";
702+
llvm::errs() << "Interface type: " << type << "\n";
703+
llvm::errs() << GenericSignature(this) << "\n";
704+
abort();
705+
}
706+
707+
types.push_back(ParameterizedProtocolType::get(ctx, baseType, argTypes));
708+
continue;
709+
}
710+
}
711+
712+
types.push_back(baseType);
713+
}
714+
715+
auto constraint = ProtocolCompositionType::get(
716+
ctx, types, hasExplicitAnyObject);
621717

622-
if (boundsTy->isExistentialType()) {
623-
return ExistentialType::get(boundsTy);
718+
if (!constraint->isConstraintType()) {
719+
assert(constraint->getClassOrBoundGenericClass());
720+
return constraint;
624721
}
625722

626-
return boundsTy;
723+
return ExistentialType::get(constraint);
627724
}
628725

629726
void GenericSignature::Profile(llvm::FoldingSetNodeID &id) const {

lib/AST/Type.cpp

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,19 @@ bool TypeBase::isExistentialWithError() {
11131113
return layout.isExistentialWithError(getASTContext());
11141114
}
11151115

1116+
bool TypeBase::isOpenedExistentialWithError() {
1117+
if (auto archetype = getAs<OpenedArchetypeType>()) {
1118+
auto errorProto = getASTContext().getErrorDecl();
1119+
if (!errorProto) return false;
1120+
1121+
for (auto protoDecl : archetype->getConformsTo()) {
1122+
if (protoDecl == errorProto || protoDecl->inheritsFrom(errorProto))
1123+
return true;
1124+
}
1125+
}
1126+
return false;
1127+
}
1128+
11161129
bool TypeBase::isStdlibType() {
11171130
if (auto *NTD = getAnyNominal()) {
11181131
auto *DC = NTD->getDeclContext();
@@ -3493,34 +3506,22 @@ bool ArchetypeType::isRoot() const {
34933506
}
34943507

34953508
Type ArchetypeType::getExistentialType() const {
3509+
auto *genericEnv = getGenericEnvironment();
3510+
34963511
// Opened types hold this directly.
34973512
if (auto *opened = dyn_cast<OpenedArchetypeType>(this)) {
34983513
if (opened->isRoot()) {
3499-
return getGenericEnvironment()->getOpenedExistentialType();
3514+
return genericEnv->getOpenedExistentialType();
35003515
}
35013516
}
35023517

3503-
// Otherwise, compute it from scratch.
3504-
SmallVector<Type, 4> constraintTypes;
3505-
3506-
if (auto super = getSuperclass()) {
3507-
constraintTypes.push_back(super);
3508-
}
3509-
for (auto proto : getConformsTo()) {
3510-
constraintTypes.push_back(proto->getDeclaredInterfaceType());
3511-
}
3512-
auto &ctx = const_cast<ArchetypeType*>(this)->getASTContext();
3513-
auto constraint = ProtocolCompositionType::get(
3514-
ctx, constraintTypes, requiresClass());
3518+
// Otherwise we compute it via a generic signature query.
3519+
auto interfaceType = getInterfaceType();
3520+
auto genericSig = genericEnv->getGenericSignature();
35153521

3516-
// If the archetype is only constrained to a class type,
3517-
// return the class type directly.
3518-
if (!constraint->isConstraintType()) {
3519-
assert(constraint->getClassOrBoundGenericClass());
3520-
return constraint;
3521-
}
3522+
auto upperBound = genericSig->getDependentUpperBounds(interfaceType);
35223523

3523-
return ExistentialType::get(constraint);
3524+
return genericEnv->mapTypeIntoContext(upperBound);
35243525
}
35253526

35263527
bool ArchetypeType::requiresClass() const {

lib/SILGen/SILGenType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,8 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM,
866866

867867
// Open the protocol type.
868868
auto openedType = OpenedArchetypeType::get(
869-
protocol->getExistentialType()->getCanonicalType(), GenericSignature());
869+
protocol->getDeclaredExistentialType()->getCanonicalType(),
870+
GenericSignature());
870871

871872
// Form the substitutions for calling the witness.
872873
auto witnessSubs = SubstitutionMap::getProtocolSubstitutions(protocol,

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ static bool isOpenedAnyObject(Type type) {
7676
if (!archetype || !archetype->isRoot())
7777
return false;
7878

79-
return archetype->getExistentialType()->isAnyObject();
79+
return (archetype->requiresClass() &&
80+
!archetype->hasRequirements());
8081
}
8182

8283
SubstitutionMap

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8118,7 +8118,7 @@ static bool isCastToExpressibleByNilLiteral(ConstraintSystem &cs, Type fromType,
81188118
if (!nilLiteral)
81198119
return false;
81208120

8121-
return toType->isEqual(nilLiteral->getExistentialType()) &&
8121+
return toType->isEqual(nilLiteral->getDeclaredExistentialType()) &&
81228122
fromType->getOptionalObjectType();
81238123
}
81248124

lib/Sema/TypeCheckType.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,6 @@ bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
647647
llvm_unreachable("invalid requirement check type");
648648
}
649649

650-
static void diagnoseUnboundGenericType(Type ty, SourceLoc loc);
651-
652650
/// Apply generic arguments to the given type.
653651
///
654652
/// If the type is itself not generic, this does nothing.
@@ -756,10 +754,11 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
756754
// Build ParameterizedProtocolType if the protocol has a primary associated
757755
// type and we're in a supported context (for now just generic requirements,
758756
// inheritance clause, extension binding).
759-
if (resolution.getOptions().isConstraintImplicitExistential() && !ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
757+
if (resolution.getOptions().isConstraintImplicitExistential() &&
758+
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
760759
diags.diagnose(loc, diag::existential_requires_any,
761760
protoDecl->getDeclaredInterfaceType(),
762-
protoDecl->getExistentialType(),
761+
protoDecl->getDeclaredExistentialType(),
763762
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
764763

765764
return ErrorType::get(ctx);
@@ -1700,7 +1699,7 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
17001699
auto DC = resolution.getDeclContext();
17011700
auto &ctx = DC->getASTContext();
17021701
auto &diags = ctx.Diags;
1703-
auto isExtenstionBinding = options.is(TypeResolverContext::ExtensionBinding);
1702+
auto isExtensionBinding = options.is(TypeResolverContext::ExtensionBinding);
17041703

17051704
auto maybeDiagnoseBadMemberType = [&](TypeDecl *member, Type memberType,
17061705
AssociatedTypeDecl *inferredAssocType) {
@@ -1715,13 +1714,13 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
17151714

17161715
if (options.contains(TypeResolutionFlags::SilenceErrors)) {
17171716
if (TypeChecker::isUnsupportedMemberTypeAccess(
1718-
parentTy, member, hasUnboundOpener, isExtenstionBinding) !=
1717+
parentTy, member, hasUnboundOpener, isExtensionBinding) !=
17191718
TypeChecker::UnsupportedMemberTypeAccessKind::None)
17201719
return ErrorType::get(ctx);
17211720
}
17221721

17231722
switch (TypeChecker::isUnsupportedMemberTypeAccess(
1724-
parentTy, member, hasUnboundOpener, isExtenstionBinding)) {
1723+
parentTy, member, hasUnboundOpener, isExtensionBinding)) {
17251724
case TypeChecker::UnsupportedMemberTypeAccessKind::None:
17261725
break;
17271726

@@ -1910,7 +1909,9 @@ static Type applyNonEscapingIfNecessary(Type ty,
19101909

19111910
// We lost the sugar to flip the isNoEscape bit.
19121911
//
1913-
// FIXME(https://github.com/apple/swift/issues/45125): It would be better to add a new AttributedType sugared type, which would wrap the TypeAliasType or ParenType, and apply the isNoEscape bit when de-sugaring.
1912+
// FIXME(https://github.com/apple/swift/issues/45125): It would be better
1913+
// to add a new AttributedType sugared type, which would wrap the
1914+
// TypeAliasType and apply the isNoEscape bit when de-sugaring.
19141915
return FunctionType::get(funcTy->getParams(), funcTy->getResult(), extInfo);
19151916
}
19161917

@@ -2340,10 +2341,11 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
23402341
return ty;
23412342
};
23422343

2343-
if(getASTContext().LangOpts.hasFeature(Feature::ImplicitSome)){
2344+
if(getASTContext().LangOpts.hasFeature(Feature::ImplicitSome)) {
23442345
if (auto opaqueDecl = dyn_cast<OpaqueTypeDecl>(DC)) {
23452346
if (auto ordinal = opaqueDecl->getAnonymousOpaqueParamOrdinal(repr))
2346-
return diagnoseDisallowedExistential(getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
2347+
return diagnoseDisallowedExistential(
2348+
getIdentityOpaqueTypeArchetypeType(opaqueDecl, *ordinal));
23472349
}
23482350
}
23492351

@@ -4790,7 +4792,7 @@ class ExistentialTypeVisitor
47904792
Ctx.Diags.diagnose(comp->getNameLoc(),
47914793
diag::existential_requires_any,
47924794
proto->getDeclaredInterfaceType(),
4793-
proto->getExistentialType(),
4795+
proto->getDeclaredExistentialType(),
47944796
/*isAlias=*/false)
47954797
.fixItReplace(replaceRepr->getSourceRange(), fix);
47964798
}

0 commit comments

Comments
 (0)