From 0d90b624913b3ab2ffd4fc5715f4c27d26498daa Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 13 Sep 2025 16:14:03 -0400 Subject: [PATCH 1/4] AST: Clean up in preparation for non-canonical archetypes --- include/swift/AST/GenericEnvironment.h | 30 ++++--- include/swift/AST/Types.h | 19 ++-- lib/AST/ASTContext.cpp | 22 ++--- lib/AST/CaptureInfo.cpp | 2 +- lib/AST/GenericEnvironment.cpp | 87 +++++++++---------- .../LocalArchetypeRequirementCollector.cpp | 4 +- lib/AST/Type.cpp | 21 ++--- lib/IRGen/GenPack.cpp | 2 +- lib/Sema/OpenedExistentials.cpp | 2 +- lib/Serialization/Serialization.cpp | 4 +- 10 files changed, 101 insertions(+), 92 deletions(-) diff --git a/include/swift/AST/GenericEnvironment.h b/include/swift/AST/GenericEnvironment.h index 2a7e3279fec63..b5578631bb535 100644 --- a/include/swift/AST/GenericEnvironment.h +++ b/include/swift/AST/GenericEnvironment.h @@ -61,13 +61,13 @@ struct OpaqueEnvironmentData { }; /// Extra data in a generic environment for an opened existential. -struct OpenedExistentialEnvironmentData { +struct ExistentialEnvironmentData { Type existential; UUID uuid; }; /// Extra data in a generic environment for an opened pack element. -struct OpenedElementEnvironmentData { +struct ElementEnvironmentData { UUID uuid; CanGenericTypeParamType shapeClass; }; @@ -85,37 +85,38 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final GenericEnvironment, SubstitutionMap, OpaqueEnvironmentData, - OpenedExistentialEnvironmentData, - OpenedElementEnvironmentData, + ExistentialEnvironmentData, + ElementEnvironmentData, Type> { public: - enum class Kind { + enum class Kind: uint8_t { /// A normal generic environment, determined only by its generic /// signature. Primary, /// A generic environment describing an opaque type archetype. Opaque, /// A generic environment describing an opened existential archetype. - OpenedExistential, + Existential, /// A generic environment describing an opened element type of a /// pack archetype inside a pack expansion expression. - OpenedElement, + Element, }; class NestedTypeStorage; private: - mutable llvm::PointerIntPair SignatureAndKind{ - GenericSignature(), Kind::Primary}; + GenericSignature sig; NestedTypeStorage *nestedTypeStorage = nullptr; + Kind kind; + bool canonical; friend TrailingObjects; friend OpaqueTypeArchetypeType; size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; - size_t numTrailingObjects(OverloadToken) const; - size_t numTrailingObjects(OverloadToken) const; + size_t numTrailingObjects(OverloadToken) const; + size_t numTrailingObjects(OverloadToken) const; size_t numTrailingObjects(OverloadToken) const; /// Retrieve the array containing the context types associated with the @@ -168,10 +169,13 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final public: GenericSignature getGenericSignature() const { - return SignatureAndKind.getPointer(); + return sig; } - Kind getKind() const { return SignatureAndKind.getInt(); } + Kind getKind() const { return kind; } + + /// Returns if the archetypes from this environment are canonical types. + bool isCanonical() const { return canonical; } ArrayRef getGenericParams() const; diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 5a3ca5c7ff11f..aac8afe09a439 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7009,7 +7009,7 @@ class ArchetypeType : public SubstitutableType, } protected: ArchetypeType(TypeKind Kind, - const ASTContext &C, + const ASTContext *C, RecursiveTypeProperties properties, Type InterfaceType, ArrayRef ConformsTo, @@ -7088,7 +7088,8 @@ class OpaqueTypeArchetypeType final : public ArchetypeType, } private: - OpaqueTypeArchetypeType(GenericEnvironment *environment, + OpaqueTypeArchetypeType(const ASTContext *ctx, + GenericEnvironment *environment, RecursiveTypeProperties properties, Type interfaceType, ArrayRef conformsTo, @@ -7232,11 +7233,13 @@ class ExistentialArchetypeType final : public LocalArchetypeType, } private: - ExistentialArchetypeType(GenericEnvironment *environment, Type interfaceType, - ArrayRef conformsTo, - Type superclass, - LayoutConstraint layout, - RecursiveTypeProperties properties); + ExistentialArchetypeType(const ASTContext *ctx, + GenericEnvironment *environment, + Type interfaceType, + ArrayRef conformsTo, + Type superclass, + LayoutConstraint layout, + RecursiveTypeProperties properties); }; BEGIN_CAN_TYPE_WRAPPER(ExistentialArchetypeType, LocalArchetypeType) END_CAN_TYPE_WRAPPER(ExistentialArchetypeType, LocalArchetypeType) @@ -7309,7 +7312,7 @@ class ElementArchetypeType final : public LocalArchetypeType, } private: - ElementArchetypeType(const ASTContext &ctx, + ElementArchetypeType(const ASTContext *ctx, GenericEnvironment *environment, Type interfaceType, ArrayRef conformsTo, Type superclass, LayoutConstraint layout); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 07b932e8c75f3..da872a1f50ea6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5731,7 +5731,8 @@ OpaqueTypeArchetypeType *OpaqueTypeArchetypeType::getNew( ASTContext &ctx = interfaceType->getASTContext(); auto mem = ctx.Allocate(size, alignof(OpaqueTypeArchetypeType), arena); return ::new (mem) - OpaqueTypeArchetypeType(environment, properties, interfaceType, + OpaqueTypeArchetypeType(environment->isCanonical() ? &ctx : nullptr, + environment, properties, interfaceType, conformsTo, superclass, layout); } @@ -5759,6 +5760,7 @@ CanTypeWrapper ExistentialArchetypeType::getNew( void *mem = ctx.Allocate(size, alignof(ExistentialArchetypeType), arena); return CanExistentialArchetypeType(::new (mem) ExistentialArchetypeType( + environment->isCanonical() ? &ctx : nullptr, environment, interfaceType, conformsTo, superclass, layout, properties)); } @@ -6014,8 +6016,8 @@ GenericEnvironment *GenericEnvironment::forPrimary(GenericSignature signature) { unsigned numGenericParams = signature.getGenericParams().size(); size_t bytes = totalSizeToAlloc( + ExistentialEnvironmentData, + ElementEnvironmentData, Type>( 0, 0, 0, 0, numGenericParams); void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment)); return new (mem) GenericEnvironment(signature); @@ -6044,9 +6046,9 @@ GenericEnvironment *GenericEnvironment::forOpaqueType( auto signature = opaque->getOpaqueInterfaceGenericSignature(); unsigned numGenericParams = signature.getGenericParams().size(); size_t bytes = totalSizeToAlloc( + OpaqueEnvironmentData, + ExistentialEnvironmentData, + ElementEnvironmentData, Type>( 1, 1, 0, 0, numGenericParams); void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment), arena); env = new (mem) GenericEnvironment(signature, opaque, subs); @@ -6108,8 +6110,8 @@ GenericEnvironment::forOpenedExistential( unsigned numGenericParams = signature.getGenericParams().size(); size_t bytes = totalSizeToAlloc( + ExistentialEnvironmentData, + ElementEnvironmentData, Type>( 1, 0, 1, 0, numGenericParams); void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment)); auto *genericEnv = @@ -6146,8 +6148,8 @@ GenericEnvironment::forOpenedElement(GenericSignature signature, unsigned numOpenedParams = signature.getInnermostGenericParams().size(); size_t bytes = totalSizeToAlloc( 1, 0, 0, 1, numGenericParams + numOpenedParams); void *mem = ctx.Allocate(bytes, alignof(GenericEnvironment)); diff --git a/lib/AST/CaptureInfo.cpp b/lib/AST/CaptureInfo.cpp index f2b12c76ff843..4a88879a085a9 100644 --- a/lib/AST/CaptureInfo.cpp +++ b/lib/AST/CaptureInfo.cpp @@ -77,7 +77,7 @@ CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef captures, // This is the only kind of local generic environment we can capture right now. #ifndef NDEBUG for (auto *env : genericEnv) { - assert(env->getKind() == GenericEnvironment::Kind::OpenedElement); + assert(env->getKind() == GenericEnvironment::Kind::Element); } #endif diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 10b54f89806b9..0cd42afb59081 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -31,8 +31,8 @@ size_t GenericEnvironment::numTrailingObjects( case Kind::Primary: return 0; - case Kind::OpenedExistential: - case Kind::OpenedElement: + case Kind::Existential: + case Kind::Element: case Kind::Opaque: return 1; } @@ -42,8 +42,8 @@ size_t GenericEnvironment::numTrailingObjects( OverloadToken) const { switch (getKind()) { case Kind::Primary: - case Kind::OpenedExistential: - case Kind::OpenedElement: + case Kind::Existential: + case Kind::Element: return 0; case Kind::Opaque: @@ -52,34 +52,34 @@ size_t GenericEnvironment::numTrailingObjects( } size_t GenericEnvironment::numTrailingObjects( - OverloadToken) const { + OverloadToken) const { switch (getKind()) { case Kind::Primary: case Kind::Opaque: - case Kind::OpenedElement: + case Kind::Element: return 0; - case Kind::OpenedExistential: + case Kind::Existential: return 1; } } size_t GenericEnvironment::numTrailingObjects( - OverloadToken) const { + OverloadToken) const { switch (getKind()) { case Kind::Primary: case Kind::Opaque: - case Kind::OpenedExistential: + case Kind::Existential: return 0; - case Kind::OpenedElement: + case Kind::Element: return 1; } } size_t GenericEnvironment::numTrailingObjects(OverloadToken) const { return getGenericParams().size() - + (getKind() == Kind::OpenedElement ? getNumOpenedPackParams() : 0); + + (getKind() == Kind::Element ? getNumOpenedPackParams() : 0); } /// Retrieve the array containing the context types associated with the @@ -99,7 +99,7 @@ ArrayRef GenericEnvironment::getContextTypes() const { } unsigned GenericEnvironment::getNumOpenedPackParams() const { - assert(getKind() == Kind::OpenedElement); + assert(getKind() == Kind::Element); return getGenericSignature().getInnermostGenericParams().size(); } @@ -130,24 +130,24 @@ OpaqueTypeDecl *GenericEnvironment::getOpaqueTypeDecl() const { CanGenericTypeParamType GenericEnvironment::getOpenedElementShapeClass() const { - assert(getKind() == Kind::OpenedElement); - auto environmentData = getTrailingObjects(); + assert(getKind() == Kind::Element); + auto environmentData = getTrailingObjects(); return environmentData->shapeClass; } Type GenericEnvironment::getOpenedExistentialType() const { - assert(getKind() == Kind::OpenedExistential); - return getTrailingObjects()->existential; + assert(getKind() == Kind::Existential); + return getTrailingObjects()->existential; } UUID GenericEnvironment::getOpenedExistentialUUID() const { - assert(getKind() == Kind::OpenedExistential); - return getTrailingObjects()->uuid; + assert(getKind() == Kind::Existential); + return getTrailingObjects()->uuid; } UUID GenericEnvironment::getOpenedElementUUID() const { - assert(getKind() == Kind::OpenedElement); - return getTrailingObjects()->uuid; + assert(getKind() == Kind::Element); + return getTrailingObjects()->uuid; } void GenericEnvironment::forEachPackElementArchetype( @@ -203,22 +203,21 @@ void GenericEnvironment::forEachPackElementBinding( assert(elementIt == packElements.end()); } -GenericEnvironment::GenericEnvironment(GenericSignature signature) - : SignatureAndKind(signature, Kind::Primary) -{ +GenericEnvironment::GenericEnvironment(GenericSignature sig) + : sig(sig), kind(Kind::Primary), canonical(true) { // Clear out the memory that holds the context types. std::uninitialized_fill(getContextTypes().begin(), getContextTypes().end(), Type()); } GenericEnvironment::GenericEnvironment( - GenericSignature signature, + GenericSignature sig, Type existential, SubstitutionMap subs, UUID uuid) - : SignatureAndKind(signature, Kind::OpenedExistential) -{ + : sig(sig), kind(Kind::Existential), canonical(subs.isCanonical()) { + ASSERT(canonical); *getTrailingObjects() = subs; - new (getTrailingObjects()) - OpenedExistentialEnvironmentData{ existential, uuid }; + new (getTrailingObjects()) + ExistentialEnvironmentData{ existential, uuid }; // Clear out the memory that holds the context types. std::uninitialized_fill(getContextTypes().begin(), getContextTypes().end(), @@ -226,9 +225,9 @@ GenericEnvironment::GenericEnvironment( } GenericEnvironment::GenericEnvironment( - GenericSignature signature, OpaqueTypeDecl *opaque, SubstitutionMap subs) - : SignatureAndKind(signature, Kind::Opaque) -{ + GenericSignature sig, OpaqueTypeDecl *opaque, SubstitutionMap subs) + : sig(sig), kind(Kind::Opaque), canonical(subs.isCanonical()) { + ASSERT(canonical); *getTrailingObjects() = subs; new (getTrailingObjects()) OpaqueEnvironmentData{opaque}; @@ -238,15 +237,15 @@ GenericEnvironment::GenericEnvironment( Type()); } -GenericEnvironment::GenericEnvironment(GenericSignature signature, +GenericEnvironment::GenericEnvironment(GenericSignature sig, UUID uuid, CanGenericTypeParamType shapeClass, SubstitutionMap outerSubs) - : SignatureAndKind(signature, Kind::OpenedElement) -{ + : sig(sig), kind(Kind::Element), canonical(true) { + // FIXME: ASSERT(outerSubs.isCanonical()); *getTrailingObjects() = outerSubs; - new (getTrailingObjects()) - OpenedElementEnvironmentData{uuid, shapeClass}; + new (getTrailingObjects()) + ElementEnvironmentData{uuid, shapeClass}; // Clear out the memory that holds the context types. std::uninitialized_fill(getContextTypes().begin(), getContextTypes().end(), @@ -255,9 +254,9 @@ GenericEnvironment::GenericEnvironment(GenericSignature signature, // Fill in the array of opened pack parameters. auto openedPacksBuffer = getOpenedPackParams(); unsigned i = 0; - for (auto param : signature.getGenericParams()) { + for (auto param : sig.getGenericParams()) { if (!param->isParameterPack()) continue; - if (!signature->haveSameShape(param, shapeClass)) continue; + if (!sig->haveSameShape(param, shapeClass)) continue; openedPacksBuffer[i++] = param; } assert(i == openedPacksBuffer.size()); @@ -314,8 +313,8 @@ GenericEnvironment::maybeApplyOuterContextSubstitutions(Type type) const { case Kind::Primary: return type; - case Kind::OpenedExistential: - case Kind::OpenedElement: + case Kind::Existential: + case Kind::Element: case Kind::Opaque: { if (auto subs = getOuterSubstitutions()) { OuterSubstitutions replacer{subs, @@ -446,7 +445,7 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) { break; } - case Kind::OpenedExistential: { + case Kind::Existential: { if (rootGP->getDepth() < genericSig->getMaxDepth()) { result = maybeApplyOuterContextSubstitutions(reducedType); break; @@ -479,7 +478,7 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) { break; } - case Kind::OpenedElement: { + case Kind::Element: { if (rootGP->getDepth() < genericSig->getMaxDepth()) { result = maybeApplyOuterContextSubstitutions(reducedType); break; @@ -610,7 +609,7 @@ struct FindElementArchetypeForOpenedPackParam { /// does not apply outer substitutions, which might not be what you expect. Type GenericEnvironment::mapContextualPackTypeIntoElementContext(Type type) const { - assert(getKind() == Kind::OpenedElement); + assert(getKind() == Kind::Element); assert(!type->hasTypeParameter() && "expected contextual type"); if (!type->hasPackArchetype()) return type; @@ -642,7 +641,7 @@ GenericEnvironment::mapContextualPackTypeIntoElementContext(CanType type) const /// substitutions, so it behaves like mapTypeIntoContext() in that respect. Type GenericEnvironment::mapPackTypeIntoElementContext(Type type) const { - assert(getKind() == Kind::OpenedElement); + assert(getKind() == Kind::Element); assert(!type->hasPackArchetype()); if (!type->hasParameterPack()) return type; diff --git a/lib/AST/LocalArchetypeRequirementCollector.cpp b/lib/AST/LocalArchetypeRequirementCollector.cpp index 53c47d54340f3..7ccdf504a7cc3 100644 --- a/lib/AST/LocalArchetypeRequirementCollector.cpp +++ b/lib/AST/LocalArchetypeRequirementCollector.cpp @@ -135,14 +135,14 @@ GenericSignature swift::buildGenericSignatureWithCapturedEnvironments( case GenericEnvironment::Kind::Opaque: break; - case GenericEnvironment::Kind::OpenedExistential: { + case GenericEnvironment::Kind::Existential: { auto existentialTy = genericEnv->maybeApplyOuterContextSubstitutions( genericEnv->getOpenedExistentialType()) ->mapTypeOutOfContext(); collector.addOpenedExistential(existentialTy); continue; } - case GenericEnvironment::Kind::OpenedElement: { + case GenericEnvironment::Kind::Element: { collector.addOpenedElement( genericEnv->getOpenedElementShapeClass()); continue; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a95cc1cdc5f5e..b861767f0c2c9 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3682,13 +3682,13 @@ int TupleType::getNamedElementId(Identifier I) const { } ArchetypeType::ArchetypeType(TypeKind Kind, - const ASTContext &Ctx, + const ASTContext *Ctx, RecursiveTypeProperties properties, Type InterfaceType, ArrayRef ConformsTo, Type Superclass, LayoutConstraint Layout, GenericEnvironment *Environment) - : SubstitutableType(Kind, &Ctx, properties), + : SubstitutableType(Kind, Ctx, properties), InterfaceType(InterfaceType), Environment(Environment) { @@ -3822,7 +3822,7 @@ PrimaryArchetypeType::PrimaryArchetypeType(const ASTContext &Ctx, ArrayRef ConformsTo, Type Superclass, LayoutConstraint Layout, RecursiveTypeProperties Properties) - : ArchetypeType(TypeKind::PrimaryArchetype, Ctx, Properties, + : ArchetypeType(TypeKind::PrimaryArchetype, &Ctx, Properties, InterfaceType, ConformsTo, Superclass, Layout, GenericEnv) { assert(!InterfaceType->isParameterPack()); @@ -3858,12 +3858,13 @@ PrimaryArchetypeType::getNew(const ASTContext &Ctx, } OpaqueTypeArchetypeType::OpaqueTypeArchetypeType( + const ASTContext *ctx, GenericEnvironment *environment, RecursiveTypeProperties properties, Type interfaceType, ArrayRef conformsTo, Type superclass, LayoutConstraint layout) - : ArchetypeType(TypeKind::OpaqueTypeArchetype, interfaceType->getASTContext(), + : ArchetypeType(TypeKind::OpaqueTypeArchetype, ctx, properties, interfaceType, conformsTo, superclass, layout, environment) { @@ -3879,11 +3880,10 @@ SubstitutionMap OpaqueTypeArchetypeType::getSubstitutions() const { } ExistentialArchetypeType::ExistentialArchetypeType( - GenericEnvironment *environment, Type interfaceType, + const ASTContext *ctx, GenericEnvironment *environment, Type interfaceType, ArrayRef conformsTo, Type superclass, LayoutConstraint layout, RecursiveTypeProperties properties) - : LocalArchetypeType(TypeKind::ExistentialArchetype, - interfaceType->getASTContext(), properties, + : LocalArchetypeType(TypeKind::ExistentialArchetype, ctx, properties, interfaceType, conformsTo, superclass, layout, environment) { @@ -3895,7 +3895,7 @@ PackArchetypeType::PackArchetypeType( ArrayRef ConformsTo, Type Superclass, LayoutConstraint Layout, PackShape Shape, RecursiveTypeProperties Properties) - : ArchetypeType(TypeKind::PackArchetype, Ctx, Properties, + : ArchetypeType(TypeKind::PackArchetype, &Ctx, Properties, InterfaceType, ConformsTo, Superclass, Layout, GenericEnv) { assert(InterfaceType->isParameterPack()); *getTrailingObjects() = Shape; @@ -3947,7 +3947,7 @@ CanType PackArchetypeType::getReducedShape() { } ElementArchetypeType::ElementArchetypeType( - const ASTContext &Ctx, GenericEnvironment *GenericEnv, Type InterfaceType, + const ASTContext *Ctx, GenericEnvironment *GenericEnv, Type InterfaceType, ArrayRef ConformsTo, Type Superclass, LayoutConstraint Layout) : LocalArchetypeType(TypeKind::ElementArchetype, Ctx, @@ -3973,7 +3973,8 @@ CanTypeWrapper ElementArchetypeType::getNew( alignof(ElementArchetypeType), arena); return CanElementArchetypeType(::new (mem) ElementArchetypeType( - ctx, environment, interfaceType, conformsTo, superclass, layout)); + environment->isCanonical() ? &ctx : nullptr, + environment, interfaceType, conformsTo, superclass, layout)); } UUID ElementArchetypeType::getOpenedElementID() const { diff --git a/lib/IRGen/GenPack.cpp b/lib/IRGen/GenPack.cpp index 82d0de41cfbc9..9ffca6d8ca07c 100644 --- a/lib/IRGen/GenPack.cpp +++ b/lib/IRGen/GenPack.cpp @@ -1050,7 +1050,7 @@ llvm::Value *irgen::emitTypeMetadataPackElementRef( void irgen::bindOpenedElementArchetypesAtIndex(IRGenFunction &IGF, GenericEnvironment *environment, llvm::Value *index) { - assert(environment->getKind() == GenericEnvironment::Kind::OpenedElement); + ASSERT(environment->getKind() == GenericEnvironment::Kind::Element); // Record the generic type parameters of interest. llvm::SmallPtrSet openablePackParams; diff --git a/lib/Sema/OpenedExistentials.cpp b/lib/Sema/OpenedExistentials.cpp index 567eceea9e3a9..4a39cf9f1b69f 100644 --- a/lib/Sema/OpenedExistentials.cpp +++ b/lib/Sema/OpenedExistentials.cpp @@ -915,7 +915,7 @@ Type swift::typeEraseOpenedExistentialReference( Type swift::typeEraseOpenedArchetypesFromEnvironment( Type type, GenericEnvironment *env) { - assert(env->getKind() == GenericEnvironment::Kind::OpenedExistential); + ASSERT(env->getKind() == GenericEnvironment::Kind::Existential); return typeEraseExistentialSelfReferences( type, diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index b76da1d0234f5..d871389d146f9 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1795,7 +1795,7 @@ void Serializer::writeASTBlockEntity(const GenericEnvironment *genericEnv) { assert(GenericEnvironmentsToSerialize.hasRef(genericEnv)); switch (genericEnv->getKind()) { - case GenericEnvironment::Kind::OpenedExistential: { + case GenericEnvironment::Kind::Existential: { auto kind = GenericEnvironmentKind::OpenedExistential; auto existentialTypeID = addTypeRef(genericEnv->getOpenedExistentialType()); auto parentSigID = addGenericSignatureRef(genericEnv->getGenericSignature()); @@ -1809,7 +1809,7 @@ void Serializer::writeASTBlockEntity(const GenericEnvironment *genericEnv) { return; } - case GenericEnvironment::Kind::OpenedElement: { + case GenericEnvironment::Kind::Element: { auto kind = GenericEnvironmentKind::OpenedElement; auto shapeClassID = addTypeRef(genericEnv->getOpenedElementShapeClass()); auto parentSigID = addGenericSignatureRef(genericEnv->getGenericSignature()); From 8cf491f8253763165b31438c370a23d931b421e3 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 13 Sep 2025 16:18:46 -0400 Subject: [PATCH 2/4] AST: Allow non-canonical opaque archetypes --- include/swift/AST/TypeNodes.def | 2 +- lib/AST/ASTContext.cpp | 5 ----- lib/AST/GenericEnvironment.cpp | 1 - lib/AST/Type.cpp | 8 ++++++++ 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index ec990d09eec8b..869a7cc7e99d5 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -176,7 +176,7 @@ TYPE(DynamicSelf, Type) ABSTRACT_TYPE(Substitutable, Type) ABSTRACT_TYPE(Archetype, SubstitutableType) ALWAYS_CANONICAL_TYPE(PrimaryArchetype, ArchetypeType) - ALWAYS_CANONICAL_TYPE(OpaqueTypeArchetype, ArchetypeType) + TYPE(OpaqueTypeArchetype, ArchetypeType) ABSTRACT_TYPE(LocalArchetype, ArchetypeType) ALWAYS_CANONICAL_TYPE(ExistentialArchetype, LocalArchetypeType) ALWAYS_CANONICAL_TYPE(ElementArchetype, LocalArchetypeType) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index da872a1f50ea6..0eb5da09b369a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -6027,11 +6027,6 @@ GenericEnvironment *GenericEnvironment::forPrimary(GenericSignature signature) { /// outer substitutions. GenericEnvironment *GenericEnvironment::forOpaqueType( OpaqueTypeDecl *opaque, SubstitutionMap subs) { - // TODO: We could attempt to preserve type sugar in the substitution map. - // Currently archetypes are assumed to be always canonical in many places, - // though, so doing so would require fixing those places. - subs = subs.getCanonical(); - auto &ctx = opaque->getASTContext(); auto properties = ArchetypeType::archetypeProperties( diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp index 0cd42afb59081..f3633002506b8 100644 --- a/lib/AST/GenericEnvironment.cpp +++ b/lib/AST/GenericEnvironment.cpp @@ -227,7 +227,6 @@ GenericEnvironment::GenericEnvironment( GenericEnvironment::GenericEnvironment( GenericSignature sig, OpaqueTypeDecl *opaque, SubstitutionMap subs) : sig(sig), kind(Kind::Opaque), canonical(subs.isCanonical()) { - ASSERT(canonical); *getTrailingObjects() = subs; new (getTrailingObjects()) OpaqueEnvironmentData{opaque}; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index b861767f0c2c9..b7c37172bbd13 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2023,6 +2023,14 @@ CanType TypeBase::computeCanonicalType() { Result = ErrorUnionType::get(ctx, newTerms).getPointer(); break; } + case TypeKind::OpaqueTypeArchetype: { + auto *AT = cast(this); + Result = OpaqueTypeArchetypeType::get( + AT->getDecl(), AT->getInterfaceType(), + AT->getSubstitutions().getCanonical()) + ->castTo(); + break; + } case TypeKind::Integer: { auto intTy = cast(this); APInt value = intTy->getValue(); From 52e496dfdb046187aeee425dc829ec1df8ec1f54 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 13 Sep 2025 16:22:48 -0400 Subject: [PATCH 3/4] ASTPrinter: Remove opaque archetype re-sugaring hack We cannot in general assume the substitution map's replacement types are written in terms of the generic signautre of the owner declaration. This was only necessary because this substitution map did not preserve type sugar, but now that it does, we no longer need this hack. --- lib/AST/ASTPrinter.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 80cacbdefbd97..672ece35e33f2 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -3634,16 +3634,6 @@ void PrintAST::visitTypeAliasDecl(TypeAliasDecl *decl) { if (ShouldPrint) { Printer << " = "; - // FIXME: An inferred associated type witness type alias may reference - // an opaque type, but OpaqueTypeArchetypes are always canonicalized - // so lose type sugar for generic params. Bind the generic signature so - // we can map params back into the generic signature and print them - // correctly. - // - // Remove this when we have a way to represent non-canonical archetypes - // preserving sugar. - PrintOptions::OverrideScope scope(Options); - OVERRIDE_PRINT_OPTION(scope, GenericSig, decl->getGenericSignature().getPointer()); printTypeLoc(TypeLoc(decl->getUnderlyingTypeRepr(), Ty)); printDeclGenericRequirements(decl); } @@ -7500,11 +7490,6 @@ class TypePrinter : public TypeVisitorgetAs()) constraint = existential->getConstraintType(); - // Opaque archetype substitutions are always canonical, so re-sugar the - // constraint type using the owning declaration's generic parameter names. - if (genericSig) - constraint = genericSig->getSugaredType(constraint); - visit(constraint); return; } From d7726dc46380485fee286282711a5c76c93a35e4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Sat, 13 Sep 2025 16:55:08 -0400 Subject: [PATCH 4/4] AST: Simplify TypeSubstituter::transformOpaqueTypeArchetypeType() --- lib/AST/TypeSubstitution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AST/TypeSubstitution.cpp b/lib/AST/TypeSubstitution.cpp index ab8d1ddfeaf5c..3eaf3cd55e5ab 100644 --- a/lib/AST/TypeSubstitution.cpp +++ b/lib/AST/TypeSubstitution.cpp @@ -407,7 +407,7 @@ TypeSubstituter::transformOpaqueTypeArchetypeType(OpaqueTypeArchetypeType *opaqu // If we return an opaque archetype unchanged, recurse into its substitutions // as a special case. - if (known->getCanonicalType() == opaque->getCanonicalType()) + if (known.getPointer() == opaque) return std::nullopt; // Recursively process the substitutions of the // opaque type archetype. return known;