Skip to content

Commit d6186c9

Browse files
committed
Add a DeclContext Parameter to Opened Archetype Construction
This ensures that opened archetypes always inherit any outer generic parameters from the context in which they reside. This matters because class bounds may bind generic parameters from these outer contexts, and without the outer context you can wind up with ill-formed generic environments like <τ_0_0, where τ_0_0 : C<T>, τ_0_0 : P> Where T is otherwise unbound because there is no entry for it among the generic parameters of the environment's associated generic signature.
1 parent d166035 commit d6186c9

32 files changed

+228
-127
lines changed

include/swift/AST/ASTContext.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,8 +1298,6 @@ class ASTContext final {
12981298
CanGenericSignature getSingleGenericParameterSignature() const;
12991299

13001300
/// Retrieve a generic signature with a single type parameter conforming
1301-
/// to the given protocol or composition type, like <T: type>.
1302-
CanGenericSignature getOpenedArchetypeSignature(Type type);
13031301
/// to the given protocol or composition type, like <T: P>.
13041302
///
13051303
/// The opened archetype may have a different set of conformances from the
@@ -1309,6 +1307,8 @@ class ASTContext final {
13091307
/// particular, the opened archetype signature does not have requirements for
13101308
/// conformances inherited from superclass constraints while existential
13111309
/// values do.
1310+
CanGenericSignature getOpenedArchetypeSignature(Type type,
1311+
const DeclContext *useDC);
13121312

13131313
GenericSignature getOverrideGenericSignature(const ValueDecl *base,
13141314
const ValueDecl *derived);

include/swift/AST/Decl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2693,7 +2693,8 @@ class ValueDecl : public Decl {
26932693
/// property, or the uncurried result type of a method/subscript, e.g.
26942694
/// '() -> () -> Self'.
26952695
GenericParameterReferenceInfo findExistentialSelfReferences(
2696-
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const;
2696+
Type baseTy, const DeclContext *useDC,
2697+
bool treatNonResultCovariantSelfAsInvariant) const;
26972698
};
26982699

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

include/swift/AST/GenericEnvironment.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,14 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
157157
GenericEnvironment *getIncomplete(GenericSignature signature);
158158

159159
/// Create a new generic environment for an opened existential.
160-
static GenericEnvironment *forOpenedExistential(Type existential, UUID uuid);
160+
///
161+
/// \param existential The subject existential type
162+
/// \param useDC The decl context where this existential type is being opened
163+
/// \param uuid The unique identifier for this opened existential
164+
static GenericEnvironment *
165+
forOpenedExistential(Type existential, const DeclContext *useDC, UUID uuid);
166+
static GenericEnvironment *
167+
forOpenedExistential(Type existential, GenericSignature signature, UUID uuid);
161168

162169
/// Create a new generic environment for an opaque type with the given set of
163170
/// outer substitutions.

include/swift/AST/Types.h

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ class alignas(1 << TypeAlignInBits) TypeBase
507507
/// Canonical protocol composition types are minimized only to a certain
508508
/// degree to preserve ABI compatibility. This routine enables performing
509509
/// slower, but stricter minimization at need (e.g. redeclaration checking).
510-
CanType getMinimalCanonicalType() const;
510+
CanType getMinimalCanonicalType(const DeclContext *useDC) const;
511511

512512
/// Reconstitute type sugar, e.g., for array types, dictionary
513513
/// types, optionals, etc.
@@ -648,7 +648,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
648648

649649
/// Replace opened archetypes with the given root with their most
650650
/// specific non-dependent upper bounds throughout this type.
651-
Type typeEraseOpenedArchetypesWithRoot(const OpenedArchetypeType *root) const;
651+
Type typeEraseOpenedArchetypesWithRoot(const OpenedArchetypeType *root,
652+
const DeclContext *useDC) const;
652653

653654
/// Given a declaration context, returns a function type with the 'self'
654655
/// type curried as the input if the declaration context describes a type.
@@ -763,7 +764,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
763764
bool isClassExistentialType();
764765

765766
/// Opens an existential instance or meta-type and returns the opened type.
766-
Type openAnyExistentialType(OpenedArchetypeType *&opened);
767+
Type openAnyExistentialType(OpenedArchetypeType *&opened,
768+
const DeclContext *useDC);
767769

768770
/// Break an existential down into a set of constraints.
769771
ExistentialLayout getExistentialLayout();
@@ -5189,7 +5191,7 @@ class ProtocolCompositionType final : public TypeBase,
51895191
/// Canonical protocol composition types are minimized only to a certain
51905192
/// degree to preserve ABI compatibility. This routine enables performing
51915193
/// slower, but stricter minimization at need (e.g. redeclaration checking).
5192-
CanType getMinimalCanonicalType() const;
5194+
CanType getMinimalCanonicalType(const DeclContext *useDC) const;
51935195

51945196
/// Retrieve the set of members composed to create this type.
51955197
///
@@ -5752,8 +5754,9 @@ class OpenedArchetypeType final : public ArchetypeType,
57525754
///
57535755
/// \param knownID When non-empty, the known ID of the archetype. When empty,
57545756
/// a fresh archetype with a unique ID will be opened.
5755-
static CanTypeWrapper<OpenedArchetypeType> get(
5756-
CanType existential, Optional<UUID> knownID = None);
5757+
static CanTypeWrapper<OpenedArchetypeType> get(CanType existential,
5758+
const DeclContext *useDC,
5759+
Optional<UUID> knownID = None);
57575760

57585761
/// Get or create an archetype that represents the opened type
57595762
/// of an existential value.
@@ -5763,21 +5766,24 @@ class OpenedArchetypeType final : public ArchetypeType,
57635766
///
57645767
/// \param knownID When non-empty, the known ID of the archetype. When empty,
57655768
/// a fresh archetype with a unique ID will be opened.
5766-
static CanTypeWrapper<OpenedArchetypeType> get(
5767-
CanType existential, Type interfaceType, Optional<UUID> knownID = None);
5769+
static CanTypeWrapper<OpenedArchetypeType> get(CanType existential,
5770+
Type interfaceType,
5771+
const DeclContext *useDC,
5772+
Optional<UUID> knownID = None);
57685773

57695774
/// Create a new archetype that represents the opened type
57705775
/// of an existential value.
57715776
///
57725777
/// \param existential The existential type or existential metatype to open.
57735778
/// \param interfaceType The interface type represented by this archetype.
5774-
static CanType getAny(CanType existential, Type interfaceType);
5779+
static CanType getAny(CanType existential, Type interfaceType,
5780+
const DeclContext *useDC);
57755781

57765782
/// Create a new archetype that represents the opened type
57775783
/// of an existential value.
57785784
///
57795785
/// \param existential The existential type or existential metatype to open.
5780-
static CanType getAny(CanType existential);
5786+
static CanType getAny(CanType existential, const DeclContext *useDC);
57815787

57825788
/// Retrieve the ID number of this opened existential.
57835789
UUID getOpenedExistentialID() const;

include/swift/SIL/SILCloner.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef SWIFT_SIL_SILCLONER_H
1818
#define SWIFT_SIL_SILCLONER_H
1919

20+
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/ProtocolConformance.h"
2122
#include "swift/SIL/BasicBlockUtils.h"
2223
#include "swift/SIL/DebugUtils.h"
@@ -251,10 +252,13 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
251252
void remapRootOpenedType(CanOpenedArchetypeType archetypeTy) {
252253
assert(archetypeTy->isRoot());
253254

255+
auto sig = archetypeTy->getGenericEnvironment()->getGenericSignature();
254256
auto existentialTy = archetypeTy->getExistentialType()->getCanonicalType();
255-
auto replacementTy = OpenedArchetypeType::get(
256-
getOpASTType(existentialTy),
257-
archetypeTy->getInterfaceType());
257+
auto env = GenericEnvironment::forOpenedExistential(
258+
getOpASTType(existentialTy), sig, UUID::fromTime());
259+
auto replacementTy =
260+
env->mapTypeIntoContext(archetypeTy->getInterfaceType())
261+
->template castTo<OpenedArchetypeType>();
258262
registerOpenedExistentialRemapping(archetypeTy, replacementTy);
259263
}
260264

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5585,7 +5585,8 @@ Expr *getArgumentLabelTargetExpr(Expr *fn);
55855585
/// the given type variable, type-erase occurences of that opened type
55865586
/// variable and anything that depends on it to their non-dependent bounds.
55875587
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
5588-
TypeVariableType *openedTypeVar);
5588+
TypeVariableType *openedTypeVar,
5589+
const DeclContext *useDC);
55895590

55905591
/// Returns true if a reference to a member on a given base type will apply
55915592
/// its curried self parameter, assuming it has one.

lib/AST/ASTContext.cpp

Lines changed: 62 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ struct ASTContext::Implementation {
328328
CanGenericSignature SingleGenericParameterSignature;
329329

330330
/// The existential signature <T : P> for each P.
331-
llvm::DenseMap<CanType, CanGenericSignature> ExistentialSignatures;
331+
llvm::DenseMap<std::pair<CanType, const DeclContext *>, CanGenericSignature>
332+
ExistentialSignatures;
332333

333334
/// Overridden declarations.
334335
llvm::DenseMap<const ValueDecl *, ArrayRef<ValueDecl *>> Overrides;
@@ -4421,6 +4422,12 @@ CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::getNew(
44214422
GenericEnvironment *environment, Type interfaceType,
44224423
ArrayRef<ProtocolDecl *> conformsTo, Type superclass,
44234424
LayoutConstraint layout) {
4425+
// FIXME: It'd be great if all of our callers could submit interface types.
4426+
// But the constraint solver submits archetypes when trying to issue checks
4427+
// against members of existential types. For now, we'll work around them by
4428+
// forcing an interface type.
4429+
// assert((!superclass || !superclass->hasArchetype())
4430+
// && "superclass must be interface type");
44244431
auto arena = AllocationArena::Permanent;
44254432
ASTContext &ctx = interfaceType->getASTContext();
44264433
void *mem = ctx.Allocate(
@@ -4434,16 +4441,21 @@ CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::getNew(
44344441
environment, interfaceType, conformsTo, superclass, layout));
44354442
}
44364443

4437-
CanTypeWrapper<OpenedArchetypeType> OpenedArchetypeType::get(
4438-
CanType existential, Optional<UUID> knownID) {
4444+
CanTypeWrapper<OpenedArchetypeType>
4445+
OpenedArchetypeType::get(CanType existential, const DeclContext *useDC,
4446+
Optional<UUID> knownID) {
44394447
Type interfaceType = GenericTypeParamType::get(
4440-
/*isTypeSequence=*/false, 0, 0, existential->getASTContext());
4441-
return get(existential, interfaceType, knownID);
4448+
/*isTypeSequence=*/false,
4449+
/*depth*/ useDC->getGenericContextDepth() + 1, /*index*/ 0,
4450+
existential->getASTContext());
4451+
return get(existential, interfaceType, useDC, knownID);
44424452
}
44434453

44444454
CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential,
44454455
Type interfaceType,
4456+
const DeclContext *useDC,
44464457
Optional<UUID> knownID) {
4458+
assert(!interfaceType->hasArchetype() && "must be interface type");
44474459
// FIXME: Opened archetypes can't be transformed because the
44484460
// the identity of the archetype has to be preserved. This
44494461
// means that simplifying an opened archetype in the constraint
@@ -4475,8 +4487,8 @@ CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential,
44754487
}
44764488

44774489
/// Create a generic environment for this opened archetype.
4478-
auto genericEnv = GenericEnvironment::forOpenedExistential(
4479-
existential, *knownID);
4490+
auto genericEnv =
4491+
GenericEnvironment::forOpenedExistential(existential, useDC, *knownID);
44804492
openedExistentialEnvironments[*knownID] = genericEnv;
44814493

44824494
// Map the interface type into that environment.
@@ -4485,22 +4497,24 @@ CanOpenedArchetypeType OpenedArchetypeType::get(CanType existential,
44854497
return CanOpenedArchetypeType(result);
44864498
}
44874499

4488-
4489-
CanType OpenedArchetypeType::getAny(CanType existential, Type interfaceType) {
4500+
CanType OpenedArchetypeType::getAny(CanType existential, Type interfaceType,
4501+
const DeclContext *useDC) {
44904502
if (auto metatypeTy = existential->getAs<ExistentialMetatypeType>()) {
44914503
auto instanceTy =
44924504
metatypeTy->getExistentialInstanceType()->getCanonicalType();
44934505
return CanMetatypeType::get(
4494-
OpenedArchetypeType::getAny(instanceTy, interfaceType));
4506+
OpenedArchetypeType::getAny(instanceTy, interfaceType, useDC));
44954507
}
44964508
assert(existential->isExistentialType());
4497-
return OpenedArchetypeType::get(existential, interfaceType);
4509+
return OpenedArchetypeType::get(existential, interfaceType, useDC);
44984510
}
44994511

4500-
CanType OpenedArchetypeType::getAny(CanType existential) {
4512+
CanType OpenedArchetypeType::getAny(CanType existential,
4513+
const DeclContext *useDC) {
45014514
Type interfaceType = GenericTypeParamType::get(
4502-
/*isTypeSequence=*/false, 0, 0, existential->getASTContext());
4503-
return getAny(existential, interfaceType);
4515+
/*isTypeSequence=*/false, useDC->getGenericContextDepth() + 1, 0,
4516+
existential->getASTContext());
4517+
return getAny(existential, interfaceType, useDC);
45044518
}
45054519

45064520
void SubstitutionMap::Storage::Profile(
@@ -4655,12 +4669,23 @@ GenericEnvironment *GenericEnvironment::getIncomplete(
46554669
}
46564670

46574671
/// Create a new generic environment for an opened archetype.
4658-
GenericEnvironment *GenericEnvironment::forOpenedExistential(
4659-
Type existential, UUID uuid) {
4672+
GenericEnvironment *
4673+
GenericEnvironment::forOpenedExistential(Type existential,
4674+
const DeclContext *useDC, UUID uuid) {
46604675
auto &ctx = existential->getASTContext();
4661-
auto signature = ctx.getOpenedArchetypeSignature(existential);
4676+
auto signature = ctx.getOpenedArchetypeSignature(existential, useDC);
4677+
4678+
SubstitutionMap subs;
4679+
if (auto *useEnvironment = useDC->getGenericEnvironmentOfContext()) {
4680+
subs = useEnvironment->getForwardingSubstitutionMap();
4681+
}
4682+
return GenericEnvironment::forOpenedExistential(existential, signature, uuid);
4683+
}
46624684

4685+
GenericEnvironment *GenericEnvironment::forOpenedExistential(
4686+
Type existential, GenericSignature signature, UUID uuid) {
46634687
// Allocate and construct the new environment.
4688+
auto &ctx = existential->getASTContext();
46644689
unsigned numGenericParams = signature.getGenericParams().size();
46654690
size_t bytes = totalSizeToAlloc<OpaqueTypeDecl *, SubstitutionMap,
46664691
OpenedGenericEnvironmentData, Type>(
@@ -5166,38 +5191,47 @@ CanGenericSignature ASTContext::getSingleGenericParameterSignature() const {
51665191
return canonicalSig;
51675192
}
51685193

5169-
CanGenericSignature ASTContext::getOpenedArchetypeSignature(Type type) {
5194+
CanGenericSignature
5195+
ASTContext::getOpenedArchetypeSignature(Type type, const DeclContext *useDC) {
51705196
assert(type->isExistentialType());
5197+
assert(useDC && "Must have a working declaration context!");
5198+
51715199
if (auto existential = type->getAs<ExistentialType>())
51725200
type = existential->getConstraintType();
51735201

51745202
const CanType constraint = type->getCanonicalType();
51755203
assert(!constraint->hasTypeParameter() && "This only works with archetypes");
51765204

51775205
// The opened archetype signature for a protocol type is identical
5178-
// to the protocol's own canonical generic signature.
5179-
if (const auto protoTy = dyn_cast<ProtocolType>(constraint)) {
5180-
return protoTy->getDecl()->getGenericSignature().getCanonicalSignature();
5206+
// to the protocol's own canonical generic signature if there aren't any
5207+
// outer generic parameters to worry about.
5208+
if (!useDC->isGenericContext()) {
5209+
if (const auto protoTy = dyn_cast<ProtocolType>(constraint)) {
5210+
return protoTy->getDecl()->getGenericSignature().getCanonicalSignature();
5211+
}
51815212
}
51825213

5183-
auto found = getImpl().ExistentialSignatures.find(constraint);
5214+
// Otherwise we need to build a generic signature that captures any outer
5215+
// generic parameters. This ensures that we keep e.g. generic superclass
5216+
// existentials contained in a well-formed generic context.
5217+
auto found = getImpl().ExistentialSignatures.find({constraint, useDC});
51845218
if (found != getImpl().ExistentialSignatures.end())
51855219
return found->second;
51865220

5221+
auto depth = useDC->getGenericContextDepth() + 1;
51875222
auto genericParam =
51885223
GenericTypeParamType::get(/*type sequence*/ false,
5189-
/*depth*/ 0, /*index*/ 0, *this);
5224+
/*depth*/ depth, /*index*/ 0, *this);
51905225
Requirement requirement(RequirementKind::Conformance, genericParam,
51915226
constraint);
5192-
auto genericSig = buildGenericSignature(*this,
5193-
GenericSignature(),
5194-
{genericParam},
5195-
{requirement});
5227+
auto genericSig = buildGenericSignature(
5228+
*this, useDC->getGenericSignatureOfContext().getCanonicalSignature(),
5229+
{genericParam}, {requirement});
51965230

51975231
CanGenericSignature canGenericSig(genericSig);
51985232

51995233
auto result = getImpl().ExistentialSignatures.insert(
5200-
std::make_pair(constraint, canGenericSig));
5234+
std::make_pair(std::make_pair(constraint, useDC), canGenericSig));
52015235
assert(result.second);
52025236
(void) result;
52035237

lib/AST/Decl.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,7 +2926,7 @@ CanType ValueDecl::getOverloadSignatureType() const {
29262926
/*topLevelFunction=*/true, isMethod,
29272927
/*isInitializer=*/isa<ConstructorDecl>(afd),
29282928
getNumCurryLevels())
2929-
->getCanonicalType();
2929+
->getMinimalCanonicalType(afd);
29302930
}
29312931

29322932
if (isa<AbstractStorageDecl>(this)) {
@@ -2942,22 +2942,22 @@ CanType ValueDecl::getOverloadSignatureType() const {
29422942
/*topLevelFunction=*/true,
29432943
/*isMethod=*/false,
29442944
/*isInitializer=*/false, getNumCurryLevels())
2945-
->getCanonicalType();
2945+
->getMinimalCanonicalType(getDeclContext());
29462946
}
29472947

29482948
// We want to curry the default signature type with the 'self' type of the
29492949
// given context (if any) in order to ensure the overload signature type
29502950
// is unique across different contexts, such as between a protocol extension
29512951
// and struct decl.
29522952
return defaultSignatureType->addCurriedSelfType(getDeclContext())
2953-
->getCanonicalType();
2953+
->getMinimalCanonicalType(getDeclContext());
29542954
}
29552955

29562956
if (isa<EnumElementDecl>(this)) {
29572957
auto mappedType = mapSignatureFunctionType(
29582958
getASTContext(), getInterfaceType(), /*topLevelFunction=*/false,
29592959
/*isMethod=*/false, /*isInitializer=*/false, getNumCurryLevels());
2960-
return mappedType->getCanonicalType();
2960+
return mappedType->getMinimalCanonicalType(getDeclContext());
29612961
}
29622962

29632963
// Note: If you add more cases to this function, you should update the
@@ -4085,7 +4085,8 @@ GenericParameterReferenceInfo swift::findGenericParameterReferences(
40854085
}
40864086

40874087
GenericParameterReferenceInfo ValueDecl::findExistentialSelfReferences(
4088-
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const {
4088+
Type baseTy, const DeclContext *useDC,
4089+
bool treatNonResultCovariantSelfAsInvariant) const {
40894090
assert(baseTy->isExistentialType());
40904091

40914092
// Types never refer to 'Self'.
@@ -4098,7 +4099,8 @@ GenericParameterReferenceInfo ValueDecl::findExistentialSelfReferences(
40984099
if (type->hasError())
40994100
return GenericParameterReferenceInfo();
41004101

4101-
const auto sig = getASTContext().getOpenedArchetypeSignature(baseTy);
4102+
const auto sig =
4103+
getASTContext().getOpenedArchetypeSignature(baseTy, useDC);
41024104
auto genericParam = sig.getGenericParams().front();
41034105
return findGenericParameterReferences(
41044106
this, sig, genericParam, treatNonResultCovariantSelfAsInvariant, None);

0 commit comments

Comments
 (0)