Skip to content

Commit 6df0de5

Browse files
authored
Merge pull request #73570 from slavapestov/pack-expansion-closures-part-4
Allow local archetypes in interface types of local declarations
2 parents 03ea6a1 + 7e36060 commit 6df0de5

File tree

8 files changed

+88
-121
lines changed

8 files changed

+88
-121
lines changed

include/swift/AST/Decl.h

-11
Original file line numberDiff line numberDiff line change
@@ -6010,10 +6010,6 @@ enum class PropertyWrapperSynthesizedPropertyKind {
60106010
class VarDecl : public AbstractStorageDecl {
60116011
friend class NamingPatternRequest;
60126012
NamedPattern *NamingPattern = nullptr;
6013-
/// When the variable is declared in context of a for-in loop over the elements of
6014-
/// a parameter pack, this is the opened element environment of the pack expansion
6015-
/// to use as the variable's context generic environment.
6016-
GenericEnvironment *OpenedElementEnvironment = nullptr;
60176013

60186014
public:
60196015
enum class Introducer : uint8_t {
@@ -6155,13 +6151,6 @@ class VarDecl : public AbstractStorageDecl {
61556151
NamedPattern *getNamingPattern() const;
61566152
void setNamingPattern(NamedPattern *Pat);
61576153

6158-
GenericEnvironment *getOpenedElementEnvironment() const {
6159-
return OpenedElementEnvironment;
6160-
}
6161-
void setOpenedElementEnvironment(GenericEnvironment *Env) {
6162-
OpenedElementEnvironment = Env;
6163-
}
6164-
61656154
/// If this is a VarDecl that does not belong to a CaseLabelItem's pattern,
61666155
/// return this. Otherwise, this VarDecl must belong to a CaseStmt's
61676156
/// CaseLabelItem. In that case, return the first case label item of the first

include/swift/AST/Types.h

+21-15
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,9 @@ class RecursiveTypeProperties {
128128
/// This type expression contains a TypeVariableType.
129129
HasTypeVariable = 0x01,
130130

131-
/// This type expression contains a context-dependent archetype, either a
132-
/// \c PrimaryArchetypeType, \c OpenedArchetypeType,
133-
/// \c ElementArchetypeType, or \c PackArchetype.
134-
HasArchetype = 0x02,
131+
/// This type expression contains a PrimaryArchetypeType
132+
/// or PackArchetypeType.
133+
HasPrimaryArchetype = 0x02,
135134

136135
/// This type expression contains a GenericTypeParamType.
137136
HasTypeParameter = 0x04,
@@ -171,7 +170,7 @@ class RecursiveTypeProperties {
171170
/// This type contains a parameterized existential type \c any P<T>.
172171
HasParameterizedExistential = 0x2000,
173172

174-
/// This type contains an ElementArchetype.
173+
/// This type contains an ElementArchetypeType.
175174
HasElementArchetype = 0x4000,
176175

177176
/// Whether the type is allocated in the constraint solver arena. This can
@@ -205,9 +204,9 @@ class RecursiveTypeProperties {
205204
/// variable?
206205
bool hasTypeVariable() const { return Bits & HasTypeVariable; }
207206

208-
/// Does a type with these properties structurally contain a
209-
/// context-dependent archetype (that is, a Primary- or OpenedArchetype)?
210-
bool hasArchetype() const { return Bits & HasArchetype; }
207+
/// Does a type with these properties structurally contain a primary
208+
/// archetype?
209+
bool hasPrimaryArchetype() const { return Bits & HasPrimaryArchetype; }
211210

212211
/// Does a type with these properties structurally contain an
213212
/// archetype from an opaque type declaration?
@@ -696,9 +695,21 @@ class alignas(1 << TypeAlignInBits) TypeBase
696695
return getRecursiveProperties().hasPlaceholder();
697696
}
698697

699-
/// Determine whether the type involves a context-dependent archetype.
698+
/// Determine whether the type involves a primary archetype.
699+
bool hasPrimaryArchetype() const {
700+
return getRecursiveProperties().hasPrimaryArchetype();
701+
}
702+
703+
/// Whether the type contains a PackArchetypeType.
704+
bool hasPackArchetype() const {
705+
return getRecursiveProperties().hasPackArchetype();
706+
}
707+
708+
/// Determine whether the type involves a primary, pack or local archetype.
709+
///
710+
/// FIXME: Replace all remaining callers with a more precise check.
700711
bool hasArchetype() const {
701-
return getRecursiveProperties().hasArchetype();
712+
return hasPrimaryArchetype() || hasLocalArchetype();
702713
}
703714

704715
/// Determine whether the type involves an opened existential archetype.
@@ -727,11 +738,6 @@ class alignas(1 << TypeAlignInBits) TypeBase
727738
return getRecursiveProperties().hasPack();
728739
}
729740

730-
/// Whether the type contains a PackArchetypeType.
731-
bool hasPackArchetype() const {
732-
return getRecursiveProperties().hasPackArchetype();
733-
}
734-
735741
/// Whether the type has any flavor of pack.
736742
bool hasAnyPack() const {
737743
return hasParameterPack() || hasPack() || hasPackArchetype();

include/swift/SIL/SILType.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ class SILType {
461461
}
462462

463463
/// Returns true if the referenced type is expressed in terms of one
464-
/// or more opened existential types.
464+
/// or more opened existential archetypes.
465465
bool hasOpenedExistential() const {
466466
return getASTType()->hasOpenedExistential();
467467
}
@@ -470,6 +470,12 @@ class SILType {
470470
return getASTType()->canBeClass();
471471
}
472472

473+
/// Returns true if the referenced type is expressed in terms of one
474+
/// or more element archetypes.
475+
bool hasElementArchetype() const {
476+
return getASTType()->hasElementArchetype();
477+
}
478+
473479
/// Returns true if the referenced type is expressed in terms of one
474480
/// or more local archetypes.
475481
bool hasLocalArchetype() const {
@@ -570,9 +576,14 @@ class SILType {
570576
return false;
571577
}
572578

573-
/// True if the type involves any archetypes.
579+
/// True if the type involves any primary or local archetypes.
574580
bool hasArchetype() const { return getASTType()->hasArchetype(); }
575581

582+
/// True if the type involves any primary archetypes.
583+
bool hasPrimaryArchetype() const {
584+
return getASTType()->hasPrimaryArchetype();
585+
}
586+
576587
/// True if the type involves any opaque archetypes.
577588
bool hasOpaqueArchetype() const {
578589
return getASTType()->hasOpaqueArchetype();

lib/AST/Decl.cpp

+3-9
Original file line numberDiff line numberDiff line change
@@ -5423,8 +5423,8 @@ Type TypeAliasDecl::getUnderlyingType() const {
54235423
void TypeAliasDecl::setUnderlyingType(Type underlying) {
54245424
// lldb creates global typealiases containing archetypes
54255425
// sometimes...
5426-
if (underlying->hasArchetype() && isGenericContext())
5427-
underlying = underlying->mapTypeOutOfContext();
5426+
assert(!underlying->hasArchetype() || !isGenericContext());
5427+
54285428
getASTContext().evaluator.cacheOutput(
54295429
StructuralTypeRequest{const_cast<TypeAliasDecl *>(this)},
54305430
std::move(underlying));
@@ -7260,12 +7260,6 @@ VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer,
72607260
}
72617261

72627262
Type VarDecl::getTypeInContext() const {
7263-
// If the variable is declared in context of a for-in loop over the elements
7264-
// of a parameter pack, its interface type must be mapped into context using
7265-
// the opened element environment of the pack expansion.
7266-
if (auto *env = getOpenedElementEnvironment())
7267-
return GenericEnvironment::mapTypeIntoContext(env, getInterfaceType());
7268-
72697263
return getDeclContext()->mapTypeIntoContext(getInterfaceType());
72707264
}
72717265

@@ -8144,7 +8138,7 @@ Type VarDecl::getPropertyWrapperInitValueInterfaceType() const {
81448138
return Type();
81458139

81468140
Type valueInterfaceTy = initInfo.getWrappedValuePlaceholder()->getType();
8147-
if (valueInterfaceTy->hasArchetype())
8141+
if (valueInterfaceTy->hasPrimaryArchetype())
81488142
valueInterfaceTy = valueInterfaceTy->mapTypeOutOfContext();
81498143

81508144
return valueInterfaceTy;

lib/AST/GenericEnvironment.cpp

+44-43
Original file line numberDiff line numberDiff line change
@@ -404,28 +404,24 @@ GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const {
404404

405405
Type GenericEnvironment::mapTypeIntoContext(GenericEnvironment *env,
406406
Type type) {
407-
assert((!type->hasArchetype() || type->hasLocalArchetype()) &&
408-
"already have a contextual type");
409-
assert((env || !type->hasTypeParameter()) &&
410-
"no generic environment provided for type with type parameters");
407+
assert(!type->hasPrimaryArchetype() && "already have a contextual type");
411408

412409
if (!env) {
410+
assert(!type->hasTypeParameter() &&
411+
"no generic environment provided for type with type parameters");
413412
return type;
414413
}
415414

416415
return env->mapTypeIntoContext(type);
417416
}
418417

419418
Type MapTypeOutOfContext::operator()(SubstitutableType *type) const {
420-
auto archetype = cast<ArchetypeType>(type);
421-
if (isa<OpaqueTypeArchetypeType>(archetype->getRoot()))
422-
return Type();
423-
424-
// Leave opened archetypes alone; they're handled contextually.
425-
if (isa<OpenedArchetypeType>(archetype))
426-
return Type(type);
419+
if (isa<PrimaryArchetypeType>(type) ||
420+
isa<PackArchetypeType>(type)) {
421+
return cast<ArchetypeType>(type)->getInterfaceType();
422+
}
427423

428-
return archetype->getInterfaceType();
424+
return type;
429425
}
430426

431427
Type TypeBase::mapTypeOutOfContext() {
@@ -632,8 +628,7 @@ Type QueryInterfaceTypeSubstitutions::operator()(SubstitutableType *type) const{
632628
Type GenericEnvironment::mapTypeIntoContext(
633629
Type type,
634630
LookupConformanceFn lookupConformance) const {
635-
assert((!type->hasArchetype() || type->hasLocalArchetype()) &&
636-
"already have a contextual type");
631+
assert(!type->hasPrimaryArchetype() && "already have a contextual type");
637632

638633
Type result = type.subst(QueryInterfaceTypeSubstitutions(this),
639634
lookupConformance,
@@ -668,7 +663,7 @@ GenericEnvironment::mapContextualPackTypeIntoElementContext(Type type) const {
668663
assert(getKind() == Kind::OpenedElement);
669664
assert(!type->hasTypeParameter() && "expected contextual type");
670665

671-
if (!type->hasArchetype()) return type;
666+
if (!type->hasPackArchetype()) return type;
672667

673668
auto sig = getGenericSignature();
674669
auto shapeClass = getOpenedElementShapeClass();
@@ -698,9 +693,9 @@ GenericEnvironment::mapContextualPackTypeIntoElementContext(CanType type) const
698693
Type
699694
GenericEnvironment::mapPackTypeIntoElementContext(Type type) const {
700695
assert(getKind() == Kind::OpenedElement);
701-
assert(!type->hasArchetype());
696+
assert(!type->hasPackArchetype());
702697

703-
if (!type->hasTypeParameter()) return type;
698+
if (!type->hasParameterPack()) return type;
704699

705700
// Get a contextual type in the original generic environment, not the
706701
// substituted one, which is what mapContextualPackTypeIntoElementContext()
@@ -720,52 +715,58 @@ GenericEnvironment::mapElementTypeIntoPackContext(Type type) const {
720715
// generic environment.
721716
assert(type->hasElementArchetype());
722717

723-
ElementArchetypeType *element = nullptr;
724-
type.visit([&](Type type) {
725-
auto archetype = type->getAs<ElementArchetypeType>();
726-
if (!element && archetype)
727-
element = archetype;
728-
});
718+
GenericEnvironment *elementEnv = nullptr;
729719

730-
auto sig = getGenericSignature();
731-
auto *elementEnv = element->getGenericEnvironment();
732-
auto shapeClass = elementEnv->getOpenedElementShapeClass();
733-
QueryInterfaceTypeSubstitutions substitutions(this);
720+
// Map element archetypes to interface types in the element generic
721+
// environment's signature.
722+
type = type.subst(
723+
[&](SubstitutableType *type) -> Type {
724+
auto *archetype = cast<ArchetypeType>(type);
734725

735-
type = type->mapTypeOutOfContext();
726+
if (isa<OpenedArchetypeType>(archetype))
727+
return archetype;
736728

737-
auto interfaceType = element->getInterfaceType();
729+
if (isa<ElementArchetypeType>(archetype)) {
730+
assert(!elementEnv ||
731+
elementEnv == archetype->getGenericEnvironment());
732+
elementEnv = archetype->getGenericEnvironment();
733+
}
738734

739-
llvm::SmallDenseMap<GenericParamKey, GenericTypeParamType *>
740-
packParamForElement;
741-
auto elementDepth = interfaceType->getRootGenericParam()->getDepth();
735+
return archetype->getInterfaceType();
736+
},
737+
MakeAbstractConformanceForGenericType(),
738+
SubstFlags::AllowLoweredTypes |
739+
SubstFlags::PreservePackExpansionLevel);
740+
741+
auto shapeClass = elementEnv->getOpenedElementShapeClass();
742+
743+
llvm::SmallVector<GenericTypeParamType *, 2> members;
744+
auto elementDepth = elementEnv->getGenericSignature()->getMaxDepth();
742745

746+
auto sig = getGenericSignature();
743747
for (auto *genericParam : sig.getGenericParams()) {
744748
if (!genericParam->isParameterPack())
745749
continue;
746750

747751
if (!sig->haveSameShape(genericParam, shapeClass))
748752
continue;
749753

750-
GenericParamKey elementKey(/*isParameterPack*/false,
751-
/*depth*/elementDepth,
752-
/*index*/packParamForElement.size());
753-
packParamForElement[elementKey] = genericParam;
754+
members.push_back(genericParam);
754755
}
755756

756-
// Map element archetypes to the pack archetypes by converting
757-
// element types to interface types and adding the isParameterPack
758-
// bit. Then, map type parameters to archetypes.
757+
// Map element interface types to pack archetypes.
758+
QueryInterfaceTypeSubstitutions mapIntoContext(this);
759759
return type.subst(
760760
[&](SubstitutableType *type) {
761761
auto *genericParam = type->getAs<GenericTypeParamType>();
762762
if (!genericParam)
763763
return Type();
764764

765-
if (auto *packParam = packParamForElement[{genericParam}])
766-
return substitutions(packParam);
767-
768-
return substitutions(genericParam);
765+
if (genericParam->getDepth() == elementDepth) {
766+
genericParam = members[genericParam->getIndex()];
767+
assert(genericParam->isParameterPack());
768+
}
769+
return mapIntoContext(genericParam);
769770
},
770771
LookUpConformanceInSignature(sig.getPointer()),
771772
SubstFlags::PreservePackExpansionLevel);

lib/AST/Type.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -3454,7 +3454,7 @@ PrimaryArchetypeType::PrimaryArchetypeType(const ASTContext &Ctx,
34543454
ArrayRef<ProtocolDecl *> ConformsTo,
34553455
Type Superclass, LayoutConstraint Layout)
34563456
: ArchetypeType(TypeKind::PrimaryArchetype, Ctx,
3457-
RecursiveTypeProperties::HasArchetype,
3457+
RecursiveTypeProperties::HasPrimaryArchetype,
34583458
InterfaceType, ConformsTo, Superclass, Layout, GenericEnv)
34593459
{
34603460
assert(!InterfaceType->isParameterPack());
@@ -3518,8 +3518,7 @@ OpenedArchetypeType::OpenedArchetypeType(
35183518
LayoutConstraint layout)
35193519
: LocalArchetypeType(TypeKind::OpenedArchetype,
35203520
interfaceType->getASTContext(),
3521-
RecursiveTypeProperties::HasArchetype
3522-
| RecursiveTypeProperties::HasOpenedExistential,
3521+
RecursiveTypeProperties::HasOpenedExistential,
35233522
interfaceType, conformsTo, superclass, layout,
35243523
environment)
35253524
{
@@ -3535,8 +3534,8 @@ PackArchetypeType::PackArchetypeType(
35353534
ArrayRef<ProtocolDecl *> ConformsTo, Type Superclass,
35363535
LayoutConstraint Layout, PackShape Shape)
35373536
: ArchetypeType(TypeKind::PackArchetype, Ctx,
3538-
RecursiveTypeProperties::HasArchetype |
3539-
RecursiveTypeProperties::HasPackArchetype,
3537+
RecursiveTypeProperties::HasPrimaryArchetype |
3538+
RecursiveTypeProperties::HasPackArchetype,
35403539
InterfaceType, ConformsTo, Superclass, Layout, GenericEnv) {
35413540
assert(InterfaceType->isParameterPack());
35423541
*getTrailingObjects<PackShape>() = Shape;
@@ -3586,7 +3585,6 @@ ElementArchetypeType::ElementArchetypeType(
35863585
ArrayRef<ProtocolDecl *> ConformsTo, Type Superclass,
35873586
LayoutConstraint Layout)
35883587
: LocalArchetypeType(TypeKind::ElementArchetype, Ctx,
3589-
RecursiveTypeProperties::HasArchetype |
35903588
RecursiveTypeProperties::HasElementArchetype,
35913589
InterfaceType,
35923590
ConformsTo, Superclass, Layout, GenericEnv) {

lib/AST/TypeCheckRequests.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,9 @@ void InterfaceTypeRequest::cacheResult(Type type) const {
10741074
if (type) {
10751075
assert(!type->hasTypeVariable() && "Type variable in interface type");
10761076
assert(!type->is<InOutType>() && "Interface type must be materializable");
1077-
assert(!type->hasArchetype() && "Archetype in interface type");
1077+
assert(!type->hasPrimaryArchetype() && "Archetype in interface type");
1078+
assert(decl->getDeclContext()->isLocalContext() || !type->hasLocalArchetype() &&
1079+
"Local archetype in interface type of non-local declaration");
10781080
}
10791081
decl->TypeAndAccess.setPointer(type);
10801082
}

0 commit comments

Comments
 (0)