From 115ba5c54f3a8d5ed81bd397537eb0337f4a42b6 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 29 Apr 2025 13:40:41 -0400 Subject: [PATCH 1/5] AST: Factor out GenericTypeParamType::withDepth() --- include/swift/AST/SubstitutionMap.h | 1 - include/swift/AST/Types.h | 2 ++ lib/AST/RequirementEnvironment.cpp | 15 ++++--------- lib/AST/SubstitutionMap.cpp | 8 ++----- lib/AST/Type.cpp | 8 +++++++ lib/SILOptimizer/Utils/Devirtualize.cpp | 29 +++++++------------------ lib/Sema/TypeCheckProtocol.cpp | 6 +---- 7 files changed, 25 insertions(+), 44 deletions(-) diff --git a/include/swift/AST/SubstitutionMap.h b/include/swift/AST/SubstitutionMap.h index 41a3ae3d9e6e4..b67266c50d112 100644 --- a/include/swift/AST/SubstitutionMap.h +++ b/include/swift/AST/SubstitutionMap.h @@ -306,7 +306,6 @@ class LookUpConformanceInSubstitutionMap { }; struct OverrideSubsInfo { - ASTContext &Ctx; unsigned BaseDepth; unsigned OrigDepth; SubstitutionMap BaseSubMap; diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 249dbbad06879..c8f5d85db06f9 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7366,6 +7366,8 @@ class GenericTypeParamType : public SubstitutableType, Type getValueType() const; + GenericTypeParamType *withDepth(unsigned depth) const; + void Profile(llvm::FoldingSetNodeID &ID) { // Note: We explicitly don't use 'getName()' because for canonical forms // which don't store an identifier we'll go create a tau based form. We diff --git a/lib/AST/RequirementEnvironment.cpp b/lib/AST/RequirementEnvironment.cpp index d60ea83df6f69..5c28f05e20128 100644 --- a/lib/AST/RequirementEnvironment.cpp +++ b/lib/AST/RequirementEnvironment.cpp @@ -46,10 +46,8 @@ RequirementEnvironment::RequirementEnvironment( auto conformanceToWitnessThunkGenericParamFn = [&](GenericTypeParamType *genericParam) -> GenericTypeParamType * { - return GenericTypeParamType::get(genericParam->getParamKind(), - genericParam->getDepth() + (covariantSelf ? 1 : 0), - genericParam->getIndex(), - genericParam->getValueType(), ctx); + return genericParam->withDepth( + genericParam->getDepth() + (covariantSelf ? 1 : 0)); }; // This is a substitution function from the generic parameters of the @@ -109,9 +107,7 @@ RequirementEnvironment::RequirementEnvironment( // invalid code. if (genericParam->getDepth() != 1) return Type(); - Type substGenericParam = GenericTypeParamType::get( - genericParam->getParamKind(), depth, genericParam->getIndex(), - genericParam->getValueType(), ctx); + Type substGenericParam = genericParam->withDepth(depth); if (genericParam->isParameterPack()) { substGenericParam = PackType::getSingletonPackExpansion( substGenericParam); @@ -210,10 +206,7 @@ RequirementEnvironment::RequirementEnvironment( } // Create an equivalent generic parameter at the next depth. - auto substGenericParam = GenericTypeParamType::get( - genericParam->getParamKind(), depth, genericParam->getIndex(), - genericParam->getValueType(), ctx); - + auto substGenericParam = genericParam->withDepth(depth); genericParamTypes.push_back(substGenericParam); } diff --git a/lib/AST/SubstitutionMap.cpp b/lib/AST/SubstitutionMap.cpp index 2e35984f245ce..788cc66710a7e 100644 --- a/lib/AST/SubstitutionMap.cpp +++ b/lib/AST/SubstitutionMap.cpp @@ -427,8 +427,7 @@ OverrideSubsInfo::OverrideSubsInfo(const NominalTypeDecl *baseNominal, const NominalTypeDecl *derivedNominal, GenericSignature baseSig, const GenericParamList *derivedParams) - : Ctx(baseSig->getASTContext()), - BaseDepth(0), + : BaseDepth(0), OrigDepth(0), DerivedParams(derivedParams) { @@ -468,10 +467,7 @@ Type QueryOverrideSubs::operator()(SubstitutableType *type) const { ->getDeclaredInterfaceType(); } - return GenericTypeParamType::get( - gp->getParamKind(), - gp->getDepth() + info.OrigDepth - info.BaseDepth, - gp->getIndex(), gp->getValueType(), info.Ctx); + return gp->withDepth(gp->getDepth() + info.OrigDepth - info.BaseDepth); } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1af4bc152f343..377133e13dbd3 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2163,6 +2163,14 @@ Type GenericTypeParamType::getValueType() const { return ValueType; } +GenericTypeParamType *GenericTypeParamType::withDepth(unsigned depth) const { + return GenericTypeParamType::get(getParamKind(), + depth, + getIndex(), + getValueType(), + getASTContext()); +} + const llvm::fltSemantics &BuiltinFloatType::getAPFloatSemantics() const { switch (getFPKind()) { case BuiltinFloatType::IEEE16: return APFloat::IEEEhalf(); diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index c4aec4cb77e48..f6f67f7fb644b 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -405,8 +405,6 @@ combineSubstitutionMaps(SubstitutionMap firstSubMap, unsigned firstDepth, unsigned secondDepth, GenericSignature genericSig) { - auto &ctx = genericSig->getASTContext(); - return SubstitutionMap::get( genericSig, [&](SubstitutableType *type) { @@ -414,12 +412,8 @@ combineSubstitutionMaps(SubstitutionMap firstSubMap, if (gp->getDepth() < firstDepth) return QuerySubstitutionMap{firstSubMap}(gp); - auto *replacement = GenericTypeParamType::get( - gp->getParamKind(), - gp->getDepth() + secondDepth - firstDepth, - gp->getIndex(), - gp->getValueType(), - ctx); + auto *replacement = gp->withDepth( + gp->getDepth() + secondDepth - firstDepth); return QuerySubstitutionMap{secondSubMap}(replacement); }, // We might not have enough information in the substitution maps alone. @@ -1056,16 +1050,13 @@ getWitnessMethodSubstitutions( } if (depth < baseDepth) { - paramType = GenericTypeParamType::get(paramType->getParamKind(), - depth, paramType->getIndex(), paramType->getValueType(), ctx); - + paramType = paramType->withDepth(depth); return Type(paramType).subst(baseSubMap); } depth = depth - baseDepth + 1; - paramType = GenericTypeParamType::get(paramType->getParamKind(), - depth, paramType->getIndex(), paramType->getValueType(), ctx); + paramType = paramType->withDepth(depth); return Type(paramType).subst(origSubMap); }, [&](CanType type, Type substType, ProtocolDecl *proto) { @@ -1084,10 +1075,8 @@ getWitnessMethodSubstitutions( if (depth < baseDepth) { type = CanType(type.transformRec([&](TypeBase *t) -> std::optional { - if (t == paramType) { - return Type(GenericTypeParamType::get(paramType->getParamKind(), - depth, paramType->getIndex(), paramType->getValueType(), ctx)); - } + if (t == paramType) + return paramType->withDepth(depth); assert(!isa(t)); return std::nullopt; @@ -1099,10 +1088,8 @@ getWitnessMethodSubstitutions( depth = depth - baseDepth + 1; type = CanType(type.transformRec([&](TypeBase *t) -> std::optional { - if (t == paramType) { - return Type(GenericTypeParamType::get(paramType->getParamKind(), - depth, paramType->getIndex(), paramType->getValueType(), ctx)); - } + if (t == paramType) + return paramType->withDepth(depth); assert(!isa(t)); return std::nullopt; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index bc0e9d5bd7d25..8619559ea1bda 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1034,11 +1034,7 @@ findMissingGenericRequirementForSolutionFix( return conformance->getType(); ASSERT(gp->getDepth() > 0); - gp = GenericTypeParamType::get(gp->getParamKind(), - gp->getDepth() - 1, - gp->getIndex(), - gp->getValueType(), - ctx); + gp = gp->withDepth(gp->getDepth() - 1); } if (!sig) From e1fc29193da58bf7a86fef459c54d68f18b0f322 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 29 Apr 2025 12:36:37 -0400 Subject: [PATCH 2/5] AST: Add GenericTypeParamType::getWeight() This is currently always 0, but can be set to 1. --- include/swift/AST/Types.h | 40 +++++++++++++++++++++------ lib/AST/ASTContext.cpp | 27 +++++++++++------- lib/AST/Type.cpp | 15 ++++++---- lib/SIL/IR/AbstractionPattern.cpp | 3 +- lib/Serialization/Deserialization.cpp | 6 ++-- lib/Serialization/ModuleFormat.h | 5 ++-- lib/Serialization/Serialization.cpp | 1 + 7 files changed, 68 insertions(+), 29 deletions(-) diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index c8f5d85db06f9..c1cd0f082891d 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -7254,9 +7254,10 @@ class GenericTypeParamType : public SubstitutableType, Identifier Name; }; - unsigned Depth : 15; unsigned IsDecl : 1; - unsigned Index : 16; + unsigned Depth : 15; + unsigned Weight : 1; + unsigned Index : 15; /// The kind of generic type parameter this is. GenericTypeParamKind ParamKind; @@ -7281,15 +7282,21 @@ class GenericTypeParamType : public SubstitutableType, Type valueType, const ASTContext &ctx); /// Retrieve a canonical generic type parameter with the given kind, depth, - /// index, and optional value type. + /// index, weight, and optional value type. static GenericTypeParamType *get(GenericTypeParamKind paramKind, - unsigned depth, unsigned index, + unsigned depth, unsigned index, unsigned weight, Type valueType, const ASTContext &ctx); - /// Retrieve a canonical generic type parameter at the given depth and index. + /// Retrieve a canonical generic type parameter at the given depth and index, + /// with weight 0. static GenericTypeParamType *getType(unsigned depth, unsigned index, const ASTContext &ctx); + /// Retrieve a canonical generic type parameter at the given depth and index + /// for an opaque result type, so with weight 1. + static GenericTypeParamType *getOpaqueResultType(unsigned depth, unsigned index, + const ASTContext &ctx); + /// Retrieve a canonical generic parameter pack at the given depth and index. static GenericTypeParamType *getPack(unsigned depth, unsigned index, const ASTContext &ctx); @@ -7345,6 +7352,14 @@ class GenericTypeParamType : public SubstitutableType, return Index; } + /// The weight of this generic parameter in the type parameter order. + /// + /// Opaque result types have weight 1, while all other generic parameters + /// have weight 0. + unsigned getWeight() const { + return Weight; + } + /// Returns \c true if this type parameter is declared as a pack. /// /// \code @@ -7373,15 +7388,17 @@ class GenericTypeParamType : public SubstitutableType, // which don't store an identifier we'll go create a tau based form. We // really want to just plumb down the null Identifier because that's what's // inside the cache. - Profile(ID, getParamKind(), getDepth(), getIndex(), getValueType(), - Name); + Profile(ID, getParamKind(), getDepth(), getIndex(), getWeight(), + getValueType(), Name); } static void Profile(llvm::FoldingSetNodeID &ID, GenericTypeParamKind paramKind, unsigned depth, - unsigned index, Type valueType, Identifier name) { + unsigned index, unsigned weight, Type valueType, + Identifier name) { ID.AddInteger((uint8_t)paramKind); ID.AddInteger(depth); ID.AddInteger(index); + ID.AddInteger(weight); ID.AddPointer(valueType.getPointer()); ID.AddPointer(name.get()); } @@ -7404,7 +7421,7 @@ class GenericTypeParamType : public SubstitutableType, const ASTContext &ctx); explicit GenericTypeParamType(GenericTypeParamKind paramKind, unsigned depth, - unsigned index, Type valueType, + unsigned index, unsigned weight, Type valueType, RecursiveTypeProperties props, const ASTContext &ctx); }; @@ -7414,6 +7431,11 @@ static CanGenericTypeParamType getType(unsigned depth, unsigned index, return CanGenericTypeParamType( GenericTypeParamType::getType(depth, index, C)); } +static CanGenericTypeParamType getOpaqueResultType(unsigned depth, unsigned index, + const ASTContext &C) { + return CanGenericTypeParamType( + GenericTypeParamType::getOpaqueResultType(depth, index, C)); +} END_CAN_TYPE_WRAPPER(GenericTypeParamType, SubstitutableType) /// A type that refers to a member type of some type that is dependent on a diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a9c3d88e332c8..74f15f4f6985c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5099,8 +5099,8 @@ GenericTypeParamType *GenericTypeParamType::get(Identifier name, Type valueType, const ASTContext &ctx) { llvm::FoldingSetNodeID id; - GenericTypeParamType::Profile(id, paramKind, depth, index, valueType, - name); + GenericTypeParamType::Profile(id, paramKind, depth, index, /*weight=*/0, + valueType, name); void *insertPos; if (auto gpTy = ctx.getImpl().GenericParamTypes.FindNodeOrInsertPos(id, insertPos)) @@ -5110,8 +5110,8 @@ GenericTypeParamType *GenericTypeParamType::get(Identifier name, if (paramKind == GenericTypeParamKind::Pack) props |= RecursiveTypeProperties::HasParameterPack; - auto canType = GenericTypeParamType::get(paramKind, depth, index, valueType, - ctx); + auto canType = GenericTypeParamType::get(paramKind, depth, index, /*weight=*/0, + valueType, ctx); auto result = new (ctx, AllocationArena::Permanent) GenericTypeParamType(name, canType, ctx); @@ -5130,10 +5130,10 @@ GenericTypeParamType *GenericTypeParamType::get(GenericTypeParamDecl *param) { GenericTypeParamType *GenericTypeParamType::get(GenericTypeParamKind paramKind, unsigned depth, unsigned index, - Type valueType, + unsigned weight, Type valueType, const ASTContext &ctx) { llvm::FoldingSetNodeID id; - GenericTypeParamType::Profile(id, paramKind, depth, index, valueType, + GenericTypeParamType::Profile(id, paramKind, depth, index, weight, valueType, Identifier()); void *insertPos; @@ -5145,7 +5145,7 @@ GenericTypeParamType *GenericTypeParamType::get(GenericTypeParamKind paramKind, props |= RecursiveTypeProperties::HasParameterPack; auto result = new (ctx, AllocationArena::Permanent) - GenericTypeParamType(paramKind, depth, index, valueType, props, ctx); + GenericTypeParamType(paramKind, depth, index, weight, valueType, props, ctx); ctx.getImpl().GenericParamTypes.InsertNode(result, insertPos); return result; } @@ -5154,14 +5154,21 @@ GenericTypeParamType *GenericTypeParamType::getType(unsigned depth, unsigned index, const ASTContext &ctx) { return GenericTypeParamType::get(GenericTypeParamKind::Type, depth, index, - /*valueType*/ Type(), ctx); + /*weight=*/0, /*valueType=*/Type(), ctx); +} + +GenericTypeParamType *GenericTypeParamType::getOpaqueResultType(unsigned depth, + unsigned index, + const ASTContext &ctx) { + return GenericTypeParamType::get(GenericTypeParamKind::Type, depth, index, + /*weight=*/1, /*valueType=*/Type(), ctx); } GenericTypeParamType *GenericTypeParamType::getPack(unsigned depth, unsigned index, const ASTContext &ctx) { return GenericTypeParamType::get(GenericTypeParamKind::Pack, depth, index, - /*valueType*/ Type(), ctx); + /*weight=*/0, /*valueType=*/Type(), ctx); } GenericTypeParamType *GenericTypeParamType::getValue(unsigned depth, @@ -5169,7 +5176,7 @@ GenericTypeParamType *GenericTypeParamType::getValue(unsigned depth, Type valueType, const ASTContext &ctx) { return GenericTypeParamType::get(GenericTypeParamKind::Value, depth, index, - valueType, ctx); + /*weight=*/0, valueType, ctx); } ArrayRef diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 377133e13dbd3..a2b09b3905114 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1736,7 +1736,8 @@ CanType TypeBase::computeCanonicalType() { auto &C = gpDecl->getASTContext(); Result = GenericTypeParamType::get(gp->getParamKind(), gp->getDepth(), - gp->getIndex(), gp->getValueType(), + gp->getIndex(), gp->getWeight(), + gp->getValueType(), C); break; } @@ -2081,8 +2082,9 @@ GenericTypeParamType::GenericTypeParamType(GenericTypeParamDecl *param, : SubstitutableType(TypeKind::GenericTypeParam, nullptr, props), Decl(param) { ASSERT(param->getDepth() != GenericTypeParamDecl::InvalidDepth); - Depth = param->getDepth(); IsDecl = true; + Depth = param->getDepth(); + Weight = 0; Index = param->getIndex(); ParamKind = param->getParamKind(); ValueType = param->getValueType(); @@ -2095,8 +2097,9 @@ GenericTypeParamType::GenericTypeParamType(Identifier name, canType->getRecursiveProperties()), Decl(nullptr) { Name = name; - Depth = canType->getDepth(); IsDecl = false; + Depth = canType->getDepth(); + Weight = canType->getWeight(); Index = canType->getIndex(); ParamKind = canType->getParamKind(); ValueType = canType->getValueType(); @@ -2106,13 +2109,14 @@ GenericTypeParamType::GenericTypeParamType(Identifier name, GenericTypeParamType::GenericTypeParamType(GenericTypeParamKind paramKind, unsigned depth, unsigned index, - Type valueType, + unsigned weight, Type valueType, RecursiveTypeProperties props, const ASTContext &ctx) : SubstitutableType(TypeKind::GenericTypeParam, &ctx, props), Decl(nullptr) { - Depth = depth; IsDecl = false; + Depth = depth; + Weight = weight; Index = index; ParamKind = paramKind; ValueType = valueType; @@ -2167,6 +2171,7 @@ GenericTypeParamType *GenericTypeParamType::withDepth(unsigned depth) const { return GenericTypeParamType::get(getParamKind(), depth, getIndex(), + getWeight(), getValueType(), getASTContext()); } diff --git a/lib/SIL/IR/AbstractionPattern.cpp b/lib/SIL/IR/AbstractionPattern.cpp index b27ccc849abe7..59fe0da628ed0 100644 --- a/lib/SIL/IR/AbstractionPattern.cpp +++ b/lib/SIL/IR/AbstractionPattern.cpp @@ -2423,7 +2423,8 @@ class SubstFunctionTypePatternVisitor paramKind = GenericTypeParamKind::Pack; } - auto gp = GenericTypeParamType::get(paramKind, 0, paramIndex, Type(), + auto gp = GenericTypeParamType::get(paramKind, /*depth=*/0, paramIndex, + /*weight=*/0, /*valueType=*/Type(), TC.Context); substGenericParams.push_back(gp); diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 65fb03a81e38e..12668a90ebd01 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -7621,12 +7621,13 @@ DESERIALIZE_TYPE(GENERIC_TYPE_PARAM_TYPE)( unsigned rawParamKind; bool hasDecl; unsigned depth; + unsigned weight; unsigned index; DeclID declOrIdentifier; TypeID valueTypeID; decls_block::GenericTypeParamTypeLayout::readRecord( - scratch, rawParamKind, hasDecl, depth, index, declOrIdentifier, + scratch, rawParamKind, hasDecl, depth, weight, index, declOrIdentifier, valueTypeID); auto paramKind = getActualParamKind(rawParamKind); @@ -7655,10 +7656,11 @@ DESERIALIZE_TYPE(GENERIC_TYPE_PARAM_TYPE)( return valueType.takeError(); if (declOrIdentifier == 0) { - return GenericTypeParamType::get(*paramKind, depth, index, *valueType, + return GenericTypeParamType::get(*paramKind, depth, index, weight, *valueType, MF.getContext()); } + ASSERT(weight == 0); auto name = MF.getDeclBaseName(declOrIdentifier).getIdentifier(); return GenericTypeParamType::get(name, *paramKind, depth, index, *valueType, MF.getContext()); diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 8af75eaf3342a..55b5c0b5ade65 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 944; // specialized witness tables +const uint16_t SWIFTMODULE_VERSION_MINOR = 945; // generic parameter weight /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1290,7 +1290,8 @@ namespace decls_block { GenericParamKindField, // param kind BCFixed<1>, // has decl? BCFixed<15>, // depth - BCFixed<16>, // index + BCFixed<1>, // weight + BCFixed<15>, // index DeclIDField, // generic type parameter decl or identifier TypeIDField // value type (if param kind == Value) ); diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index afacf625fe6b7..196e6dc6da9b9 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -5812,6 +5812,7 @@ class Serializer::TypeSerializer : public TypeVisitor { paramKind, hasDecl, genericParam->getDepth(), + genericParam->getWeight(), genericParam->getIndex(), declOrIdentifier, valueTypeID); From fa3d8c520b79c1d2060510f3d8067ba643c53c16 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 29 Apr 2025 12:39:35 -0400 Subject: [PATCH 3/5] AST: Compare weight before length in swift::compareDependentTypes() --- lib/AST/GenericSignature.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp index 3ac5bc6f80b37..d629055e23c94 100644 --- a/lib/AST/GenericSignature.cpp +++ b/lib/AST/GenericSignature.cpp @@ -831,8 +831,7 @@ int swift::compareAssociatedTypes(AssociatedTypeDecl *assocType1, return 0; } -/// Canonical ordering for type parameters. -int swift::compareDependentTypes(Type type1, Type type2) { +static int compareDependentTypesRec(Type type1, Type type2) { // Fast-path check for equality. if (type1->isEqual(type2)) return 0; @@ -853,7 +852,7 @@ int swift::compareDependentTypes(Type type1, Type type2) { // - by base, so t_0_n.`P.T` < t_1_m.`P.T` if (int compareBases = - compareDependentTypes(depMemTy1->getBase(), depMemTy2->getBase())) + compareDependentTypesRec(depMemTy1->getBase(), depMemTy2->getBase())) return compareBases; // - by name, so t_n_m.`P.T` < t_n_m.`P.U` @@ -869,6 +868,17 @@ int swift::compareDependentTypes(Type type1, Type type2) { return 0; } +/// Canonical ordering for type parameters. +int swift::compareDependentTypes(Type type1, Type type2) { + auto *root1 = type1->getRootGenericParam(); + auto *root2 = type2->getRootGenericParam(); + if (root1->getWeight() != root2->getWeight()) { + return root2->getWeight() ? -1 : +1; + } + + return compareDependentTypesRec(type1, type2); +} + #pragma mark Generic signature verification void GenericSignature::verify() const { From 651e0af4d1af4489faace891a79cfa728767bd4f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 29 Apr 2025 12:48:50 -0400 Subject: [PATCH 4/5] RequirementMachine: Compare weight before length in Term/MutableTerm::compare() --- lib/AST/RequirementMachine/Term.cpp | 53 +++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/lib/AST/RequirementMachine/Term.cpp b/lib/AST/RequirementMachine/Term.cpp index 90e5b885cb6d3..5455fb348fa56 100644 --- a/lib/AST/RequirementMachine/Term.cpp +++ b/lib/AST/RequirementMachine/Term.cpp @@ -122,19 +122,42 @@ bool Term::containsNameSymbols() const { return false; } -/// Shortlex order on symbol ranges. +/// Weighted shortlex order on symbol ranges, used for implementing +/// Term::compare() and MutableTerm::compare(). /// -/// First we compare length, then perform a lexicographic comparison -/// on symbols if the two ranges have the same length. +/// We first compute a weight vector for both terms and compare the +/// vectors lexicographically: +/// - Weight of generic param symbols +/// - Number of name symbols +/// - Number of element symbols /// -/// This is used to implement Term::compare() and MutableTerm::compare() -/// below. -static std::optional shortlexCompare(const Symbol *lhsBegin, - const Symbol *lhsEnd, - const Symbol *rhsBegin, - const Symbol *rhsEnd, - RewriteContext &ctx) { - // First, compare the number of name and pack element symbols. +/// If the terms have the same weight, we compare length. +/// +/// If the terms have the same weight and length, we perform a +/// lexicographic comparison on symbols. +/// +static std::optional compareImpl(const Symbol *lhsBegin, + const Symbol *lhsEnd, + const Symbol *rhsBegin, + const Symbol *rhsEnd, + RewriteContext &ctx) { + ASSERT(lhsBegin != lhsEnd); + ASSERT(rhsBegin != rhsEnd); + + // First compare weights on generic parameters. The implicit + // assumption here is we don't form terms with generic parameter + // symbols in the middle, which is true. Otherwise, we'd need + // to add up their weights like we do below for name symbols, + // of course. + if (lhsBegin->getKind() == Symbol::Kind::GenericParam && + rhsBegin->getKind() == Symbol::Kind::GenericParam) { + unsigned lhsWeight = lhsBegin->getGenericParam()->getWeight(); + unsigned rhsWeight = rhsBegin->getGenericParam()->getWeight(); + if (lhsWeight != rhsWeight) + return lhsWeight > rhsWeight ? 1 : -1; + } + + // Compare the number of name and pack element symbols. unsigned lhsNameCount = 0; unsigned lhsPackElementCount = 0; for (auto *iter = lhsBegin; iter != lhsEnd; ++iter) { @@ -192,17 +215,17 @@ static std::optional shortlexCompare(const Symbol *lhsBegin, return 0; } -/// Shortlex order on terms. Returns None if the terms are identical except +/// Reduction order on terms. Returns None if the terms are identical except /// for an incomparable superclass or concrete type symbol at the end. std::optional Term::compare(Term other, RewriteContext &ctx) const { - return shortlexCompare(begin(), end(), other.begin(), other.end(), ctx); + return compareImpl(begin(), end(), other.begin(), other.end(), ctx); } -/// Shortlex order on mutable terms. Returns None if the terms are identical +/// Reduction order on mutable terms. Returns None if the terms are identical /// except for an incomparable superclass or concrete type symbol at the end. std::optional MutableTerm::compare(const MutableTerm &other, RewriteContext &ctx) const { - return shortlexCompare(begin(), end(), other.begin(), other.end(), ctx); + return compareImpl(begin(), end(), other.begin(), other.end(), ctx); } /// Replace the subterm in the range [from,to) of this term with \p rhs. From 8ab5ca2a7aed0263507e786392f8e6a710059b09 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 29 Apr 2025 13:54:56 -0400 Subject: [PATCH 5/5] Sema: Use weighted reduction order for opaque return types If the opaque generic signature has a same-type requirement between an outer type parameter and an opaque type parameter, the former should always precede the latter in the type parameter order, even if it is longer. Achieve this by giving the innermost generic parameters a non-zero weight in the opaque generic signature. Now, when we map a type parameter into an opaque generic environment, we correctly decide if it is represented by a type parameter of the outer generic signature, in which case we apply the outer substitution map instead of instantiating an archetype. The included test case demonstrates the issue; we declare an opaque return type `some P`, so the opaque generic signature has a requirement `T.A.A == <>.A`. Previously, the reduced type of `<>.A` was `<>.A`, so it remained opaque; now we apply outer substitutions to `T.A.A`. - Fixes https://github.com/swiftlang/swift/issues/81036. - Fixes rdar://problem/149871931. --- lib/Sema/TypeCheckGeneric.cpp | 8 +++--- .../opaque_result_type_reduction_order.swift | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 test/SILGen/opaque_result_type_reduction_order.swift diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp index 779e6bdf4e6c8..bc05134590a67 100644 --- a/lib/Sema/TypeCheckGeneric.cpp +++ b/lib/Sema/TypeCheckGeneric.cpp @@ -142,7 +142,7 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, for (unsigned i = 0; i < opaqueReprs.size(); ++i) { auto *currentRepr = opaqueReprs[i]; - if( auto opaqueReturn = dyn_cast(currentRepr) ) { + if (auto opaqueReturn = dyn_cast(currentRepr)) { // Usually, we resolve the opaque constraint and bail if it isn't a class // or existential type (see below). However, in this case we know we will // fail, so we can bail early and provide a better diagnostic. @@ -163,13 +163,13 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, } } - auto *paramType = GenericTypeParamType::getType(opaqueSignatureDepth, i, - ctx); + auto *paramType = GenericTypeParamType::getOpaqueResultType( + opaqueSignatureDepth, i, ctx); genericParamTypes.push_back(paramType); TypeRepr *constraint = currentRepr; - if (auto opaqueReturn = dyn_cast(currentRepr)){ + if (auto opaqueReturn = dyn_cast(currentRepr)) { constraint = opaqueReturn->getConstraint(); } // Try to resolve the constraint repr in the parent decl context. It diff --git a/test/SILGen/opaque_result_type_reduction_order.swift b/test/SILGen/opaque_result_type_reduction_order.swift new file mode 100644 index 0000000000000..0714d75c05880 --- /dev/null +++ b/test/SILGen/opaque_result_type_reduction_order.swift @@ -0,0 +1,27 @@ +// RUN: %target-swift-emit-silgen %s + +protocol N { + associatedtype A: N +} + +struct G: N { + typealias A = G> +} + +protocol P { + associatedtype A +} + +struct GG: P { + typealias A = T +} + +func f(_: T) -> some P { + return GG() +} + +func g(_: T) -> T.A { fatalError() } + +func h(_: G>>) {} + +h(g(f(G())))