From 4eaa5ce3c5c44b362aa00b55f9ea3018b4246635 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Mar 2025 10:38:35 -0400 Subject: [PATCH 1/5] AST: Move a few things from ASTContext::Implementation::Arena up to Implementation Normal conformances, self conformances, and availability contexts cannot contain types with type variables, so there is no reason to duplicate the uniquing maps between the permanent arena and solver arena. --- lib/AST/ASTContext.cpp | 51 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 686026851328e..9c43e5f05eae2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -575,12 +575,6 @@ struct ASTContext::Implementation { /// The set of function types. llvm::FoldingSet FunctionTypes; - /// The set of normal protocol conformances. - llvm::FoldingSet NormalConformances; - - // The set of self protocol conformances. - llvm::DenseMap SelfConformances; - /// The set of specialized protocol conformances. llvm::FoldingSet SpecializedConformances; @@ -597,9 +591,6 @@ struct ASTContext::Implementation { /// The set of substitution maps (uniqued by their storage). llvm::FoldingSet SubstitutionMaps; - /// The set of unique AvailabilityContexts (uniqued by their storage). - llvm::FoldingSet AvailabilityContexts; - ~Arena() { for (auto &conformance : SpecializedConformances) conformance.~SpecializedProtocolConformance(); @@ -613,11 +604,6 @@ struct ASTContext::Implementation { #if SWIFT_COMPILER_IS_MSVC #pragma warning (default: 4189) #endif - - // Call the normal conformance destructors last since they could be - // referenced by the other conformance types. - for (auto &conformance : NormalConformances) - conformance.~NormalProtocolConformance(); } size_t getTotalMemory() const; @@ -645,6 +631,11 @@ struct ASTContext::Implementation { AutoDiffDerivativeFunctionIdentifiers; llvm::FoldingSet GenericSignatures; + llvm::FoldingSet NormalConformances; + llvm::DenseMap SelfConformances; + + /// The set of unique AvailabilityContexts (uniqued by their storage). + llvm::FoldingSet AvailabilityContexts; /// A cache of information about whether particular nominal types /// are representable in a foreign language. @@ -720,6 +711,9 @@ ASTContext::Implementation::Implementation() : IdentifierTable(Allocator), IntrinsicScratchContext(new llvm::LLVMContext()) {} ASTContext::Implementation::~Implementation() { + for (auto &conformance : NormalConformances) + conformance.~NormalProtocolConformance(); + for (auto &cleanup : Cleanups) cleanup(); } @@ -889,6 +883,9 @@ void ASTContext::Implementation::dump(llvm::raw_ostream &os) const { SIZE_AND_BYTES(SILMoveOnlyWrappedTypes); SIZE_AND_BYTES(BuiltinIntegerTypes); SIZE_AND_BYTES(OpenedElementEnvironments); + SIZE(NormalConformances); + SIZE(SelfConformances); + SIZE(AvailabilityContexts); SIZE_AND_BYTES(ForeignRepresentableCache); SIZE(SearchPathsSet); @@ -2912,15 +2909,14 @@ ASTContext::getNormalConformance(Type conformingType, // Did we already record the normal conformance? void *insertPos; - auto &normalConformances = - getImpl().getArena(AllocationArena::Permanent).NormalConformances; + auto &normalConformances = getImpl().NormalConformances; if (auto result = normalConformances.FindNodeOrInsertPos(id, insertPos)) return result; // Build a new normal protocol conformance. - auto result = new (*this, AllocationArena::Permanent) - NormalProtocolConformance(conformingType, protocol, loc, dc, state, - options, preconcurrencyLoc); + auto result = new (*this) NormalProtocolConformance( + conformingType, protocol, loc, dc, state, + options, preconcurrencyLoc); normalConformances.InsertNode(result, insertPos); return result; @@ -2929,12 +2925,11 @@ ASTContext::getNormalConformance(Type conformingType, /// Produce a self-conformance for the given protocol. SelfProtocolConformance * ASTContext::getSelfConformance(ProtocolDecl *protocol) { - auto &selfConformances = - getImpl().getArena(AllocationArena::Permanent).SelfConformances; + auto &selfConformances = getImpl().SelfConformances; auto &entry = selfConformances[protocol]; if (!entry) { - entry = new (*this, AllocationArena::Permanent) - SelfProtocolConformance(protocol->getDeclaredExistentialType()); + entry = new (*this) SelfProtocolConformance( + protocol->getDeclaredExistentialType()); } return entry; } @@ -3274,6 +3269,9 @@ size_t ASTContext::getTotalMemory() const { // getImpl().GenericSignatures ? // getImpl().CompoundNames ? // getImpl().IntegerTypes ? + // getImpl().NormalConformances ? + // getImpl().SelfConformances ? + // getImpl().AvailabilityContexts getImpl().Permanent.getTotalMemory(); Size += getSolverMemory(); @@ -3315,7 +3313,6 @@ size_t ASTContext::Implementation::Arena::getTotalMemory() const { // FunctionTypes ? // UnboundGenericTypes ? // BoundGenericTypes ? - // NormalConformances ? // SpecializedConformances ? // InheritedConformances ? // BuiltinConformances ? @@ -3360,14 +3357,11 @@ void ASTContext::Implementation::Arena::dump(llvm::raw_ostream &os) const { SIZE_AND_BYTES(OpaqueArchetypeEnvironments); SIZE_AND_BYTES(OpenedExistentialEnvironments); SIZE(FunctionTypes); - SIZE(NormalConformances); - SIZE(SelfConformances); SIZE(SpecializedConformances); SIZE(InheritedConformances); SIZE_AND_BYTES(BuiltinConformances); SIZE(PackConformances); SIZE(SubstitutionMaps); - SIZE(AvailabilityContexts); #undef SIZE #undef SIZE_AND_BYTES @@ -5720,8 +5714,7 @@ const AvailabilityContext::Storage *AvailabilityContext::Storage::get( AvailabilityContext::Storage::Profile(id, platformRange, isDeprecated, domainInfos); - auto &foldingSet = - ctx.getImpl().getArena(AllocationArena::Permanent).AvailabilityContexts; + auto &foldingSet = ctx.getImpl().AvailabilityContexts; void *insertPos; auto *existing = foldingSet.FindNodeOrInsertPos(id, insertPos); if (existing) From a7a19a0915e02839275309b5b2196ca82fb6be8d Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Mar 2025 12:51:44 -0400 Subject: [PATCH 2/5] Sema: Optimize Constraint layout to save 16 bytes The largest union member was for SyntacticElement constraints; let's tail-allocate the ContextualTypeInfo instead of storing one in every constraint. --- include/swift/Sema/Constraint.h | 54 +++++++----- lib/Sema/Constraint.cpp | 149 +++++++++++++++++++------------- 2 files changed, 120 insertions(+), 83 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 40b538f2c8fb9..4397d01fb8036 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -336,6 +336,7 @@ class Constraint final : public llvm::ilist_node, private llvm::TrailingObjects { friend TrailingObjects; @@ -345,7 +346,12 @@ class Constraint final : public llvm::ilist_node, /// The kind of restriction placed on this constraint. ConversionRestrictionKind Restriction : 8; - /// Whether we have a fix. + /// The number of type variables referenced by this constraint. + /// + /// The type variables themselves are tail-allocated. + unsigned NumTypeVariables : 11; + + /// Whether we have a tail-allocated fix. unsigned HasFix : 1; /// Whether the \c Restriction field is valid. @@ -375,14 +381,19 @@ class Constraint final : public llvm::ilist_node, /// the rest of the constraint system. Currently only applies to conjunctions. unsigned IsIsolated : 1; - /// The number of type variables referenced by this constraint. - /// - /// The type variables themselves are tail-allocated. - unsigned NumTypeVariables : 11; - /// The kind of function reference, for member references. unsigned TheFunctionRefInfo : 3; + /// The trailing closure matching for an applicable function constraint, + /// if any. 0 = None, 1 = Forward, 2 = Backward. + unsigned trailingClosureMatching : 2; + + /// For a SyntacticElement constraint, identify whether the result of this + /// node is unused. + unsigned isDiscarded : 1; + + // 23 bits remaining + union { struct { /// The first type. @@ -433,10 +444,6 @@ class Constraint final : public llvm::ilist_node, struct { /// The node itself. ASTNode Element; - /// Contextual information associated with the element (if any). - ContextualTypeInfo Context; - /// Identifies whether result of this node is unused. - bool IsDiscarded; } SyntacticElement; struct { @@ -447,9 +454,6 @@ class Constraint final : public llvm::ilist_node, /// The type being called, primarily a function type, but could /// be a metatype, a tuple or a nominal type. Type Callee; - /// The trailing closure matching for an applicable function constraint, - /// if any. 0 = None, 1 = Forward, 2 = Backward. - unsigned TrailingClosureMatching : 2; /// The declaration context in which the application appears. DeclContext *UseDC; } Apply; @@ -527,6 +531,10 @@ class Constraint final : public llvm::ilist_node, return HasFix ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return Kind == ConstraintKind::SyntacticElement ? 1 : 0; + } + size_t numTrailingObjects(OverloadToken) const { return Kind == ConstraintKind::BindOverload ? 1 : 0; } @@ -604,15 +612,15 @@ class Constraint final : public llvm::ilist_node, DeclContext *useDC, ConstraintLocator *locator); static Constraint *createSyntacticElement(ConstraintSystem &cs, - ASTNode node, - ConstraintLocator *locator, - bool isDiscarded = false); + ASTNode node, + ConstraintLocator *locator, + bool isDiscarded = false); static Constraint *createSyntacticElement(ConstraintSystem &cs, - ASTNode node, - ContextualTypeInfo context, - ConstraintLocator *locator, - bool isDiscarded = false); + ASTNode node, + ContextualTypeInfo context, + ConstraintLocator *locator, + bool isDiscarded = false); /// Determine the kind of constraint. ConstraintKind getKind() const { return Kind; } @@ -903,13 +911,13 @@ class Constraint final : public llvm::ilist_node, } ContextualTypeInfo getElementContext() const { - assert(Kind == ConstraintKind::SyntacticElement); - return SyntacticElement.Context; + ASSERT(Kind == ConstraintKind::SyntacticElement); + return *getTrailingObjects(); } bool isDiscardedElement() const { assert(Kind == ConstraintKind::SyntacticElement); - return SyntacticElement.IsDiscarded; + return isDiscarded; } /// For an applicable function constraint, retrieve the trailing closure diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index b699ea56127b6..7c83d26575602 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -30,9 +30,10 @@ using namespace constraints; Constraint::Constraint(ConstraintKind kind, ArrayRef constraints, bool isIsolated, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(isIsolated), NumTypeVariables(typeVars.size()), + : Kind(kind), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(isIsolated), Nested(constraints), Locator(locator) { assert(kind == ConstraintKind::Disjunction || kind == ConstraintKind::Conjunction); @@ -54,10 +55,11 @@ static bool isAdmissibleType(Type type) { Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(Kind), HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Types{First, Second, Type()}, + : Kind(Kind), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(false), + Types{First, Second, Type()}, Locator(locator) { ASSERT(isAdmissibleType(First)); ASSERT(isAdmissibleType(Second)); @@ -135,10 +137,11 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(Kind), HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Types{First, Second, Third}, + : Kind(Kind), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(false), + Types{First, Second, Third}, Locator(locator) { ASSERT(isAdmissibleType(First)); ASSERT(isAdmissibleType(Second)); @@ -201,10 +204,11 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, FunctionRefInfo functionRefInfo, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Member{first, second, {member}, useDC}, + : Kind(kind), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(false), + Member{first, second, {member}, useDC}, Locator(locator) { assert(kind == ConstraintKind::ValueMember || kind == ConstraintKind::UnresolvedValueMember); @@ -221,9 +225,10 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, FunctionRefInfo functionRefInfo, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(kind), HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(false), NumTypeVariables(typeVars.size()), + : Kind(kind), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(false), Locator(locator) { Member.First = first; Member.Second = second; @@ -242,10 +247,11 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC, ConstraintFix *fix, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(ConstraintKind::BindOverload), HasFix(fix != nullptr), HasRestriction(false), - IsActive(false), IsDisabled(bool(fix)), IsDisabledForPerformance(false), + : Kind(ConstraintKind::BindOverload), NumTypeVariables(typeVars.size()), + HasFix(fix != nullptr), HasRestriction(false), IsActive(false), + IsDisabled(bool(fix)), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Overload{type, useDC}, + Overload{type, useDC}, Locator(locator) { std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); if (fix) @@ -257,10 +263,10 @@ Constraint::Constraint(ConstraintKind kind, ConversionRestrictionKind restriction, Type first, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(kind), Restriction(restriction), HasFix(false), HasRestriction(true), - IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), - RememberChoice(false), IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Types{first, second, Type()}, + : Kind(kind), Restriction(restriction), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(true), IsActive(false), IsDisabled(false), + IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), + IsIsolated(false), Types{first, second, Type()}, Locator(locator) { ASSERT(isAdmissibleType(first)); ASSERT(isAdmissibleType(second)); @@ -270,10 +276,11 @@ Constraint::Constraint(ConstraintKind kind, Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(kind), HasFix(fix != nullptr), HasRestriction(false), IsActive(false), + : Kind(kind), NumTypeVariables(typeVars.size()), + HasFix(fix != nullptr), HasRestriction(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), - NumTypeVariables(typeVars.size()), Types{first, second, Type()}, + Types{first, second, Type()}, Locator(locator) { ASSERT(isAdmissibleType(first)); ASSERT(isAdmissibleType(second)); @@ -285,24 +292,25 @@ Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first, Constraint::Constraint(ASTNode node, ContextualTypeInfo context, bool isDiscarded, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(ConstraintKind::SyntacticElement), HasFix(false), - HasRestriction(false), IsActive(false), IsDisabled(false), - IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), - IsIsolated(false), - NumTypeVariables(typeVars.size()), SyntacticElement{node, context, - isDiscarded}, + : Kind(ConstraintKind::SyntacticElement), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), + IsFavored(false), IsIsolated(false), isDiscarded(isDiscarded), + SyntacticElement{node}, Locator(locator) { std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); + *getTrailingObjects() = context; } Constraint::Constraint(FunctionType *appliedFn, Type calleeType, unsigned trailingClosureMatching, DeclContext *useDC, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) - : Kind(ConstraintKind::ApplicableFunction), HasFix(false), - HasRestriction(false), IsActive(false), IsDisabled(false), + : Kind(ConstraintKind::ApplicableFunction), NumTypeVariables(typeVars.size()), + HasFix(false), HasRestriction(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), - IsIsolated(false), NumTypeVariables(typeVars.size()), Locator(locator) { + IsIsolated(false), trailingClosureMatching(trailingClosureMatching), + Locator(locator) { ASSERT(isAdmissibleType(appliedFn)); ASSERT(isAdmissibleType(calleeType)); assert(trailingClosureMatching >= 0 && trailingClosureMatching <= 2); @@ -310,7 +318,6 @@ Constraint::Constraint(FunctionType *appliedFn, Type calleeType, Apply.AppliedFn = appliedFn; Apply.Callee = calleeType; - Apply.TrailingClosureMatching = trailingClosureMatching; Apply.UseDC = useDC; std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); @@ -782,8 +789,10 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return ::new (mem) Constraint(kind, first, second, locator, typeVars); } @@ -803,8 +812,10 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind, third->getTypeVariables(typeVars); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return ::new (mem) Constraint(kind, first, second, third, @@ -846,8 +857,10 @@ Constraint *Constraint::createMember(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, first, second, member, useDC, functionRefInfo, locator, typeVars); @@ -868,8 +881,10 @@ Constraint *Constraint::createValueWitness( // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, first, second, requirement, useDC, functionRefInfo, locator, typeVars); @@ -890,8 +905,10 @@ Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), fix ? 1 : 0, /*hasOverloadChoice=*/1); + totalSizeToAlloc( + typeVars.size(), fix ? 1 : 0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/1); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(type, choice, useDC, fix, locator, typeVars); } @@ -910,8 +927,10 @@ Constraint *Constraint::createRestricted(ConstraintSystem &cs, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, restriction, first, second, locator, typeVars); @@ -929,8 +948,10 @@ Constraint *Constraint::createFixed(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), fix ? 1 : 0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), fix ? 1 : 0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, fix, first, second, locator, typeVars); } @@ -1001,8 +1022,10 @@ Constraint *Constraint::createDisjunction(ConstraintSystem &cs, // Create the disjunction constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto disjunction = new (mem) Constraint(ConstraintKind::Disjunction, cs.allocateCopy(constraints), @@ -1022,8 +1045,10 @@ Constraint *Constraint::createConjunction( assert(!constraints.empty() && "Empty conjunction constraint"); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto conjunction = new (mem) Constraint(ConstraintKind::Conjunction, cs.allocateCopy(constraints), @@ -1058,8 +1083,10 @@ Constraint *Constraint::createApplicableFunction( // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto constraint = new (mem) Constraint(argumentFnType, calleeType, rawTrailingClosureMatching, useDC, @@ -1087,8 +1114,10 @@ Constraint *Constraint::createSyntacticElement(ConstraintSystem &cs, contextTy->getTypeVariables(typeVars); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, /*hasOverloadChoice=*/0); + totalSizeToAlloc( + typeVars.size(), /*hasFix=*/0, + /*hasContextualTypeInfo=*/1, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(node, context, isDiscarded, locator, typeVars); } @@ -1096,7 +1125,7 @@ Constraint *Constraint::createSyntacticElement(ConstraintSystem &cs, std::optional Constraint::getTrailingClosureMatching() const { assert(Kind == ConstraintKind::ApplicableFunction); - switch (Apply.TrailingClosureMatching) { + switch (trailingClosureMatching) { case 0: return std::nullopt; case 1: return TrailingClosureMatching::Forward; From ada6f77655561386dfd4ef53b7e427ac6acd1b72 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Mar 2025 14:03:05 -0400 Subject: [PATCH 3/5] Sema: Track solver arena size in statistics --- include/swift/Sema/ConstraintSolverStats.def | 1 + lib/Sema/CSSolver.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/swift/Sema/ConstraintSolverStats.def b/include/swift/Sema/ConstraintSolverStats.def index 6e090a1df001d..cc7f2a047e1f8 100644 --- a/include/swift/Sema/ConstraintSolverStats.def +++ b/include/swift/Sema/ConstraintSolverStats.def @@ -18,6 +18,7 @@ # error #define CS_STATISTIC(Name, Description) before including #endif +CS_STATISTIC(ASTBytesAllocated, "bytes allocated in solver arena") CS_STATISTIC(NumTypeVariablesBound, "# of type variables bound") CS_STATISTIC(NumTypeVariableBindings, "# of type variable bindings attempted") CS_STATISTIC(NumDisjunctions, "# of disjunctions explored") diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index 6bb6bd517861f..07aeef0ce1529 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -669,6 +669,10 @@ ConstraintSystem::SolverState::~SolverState() { CS.Options -= ConstraintSystemFlags::DebugConstraints; } + // This statistic is special because it's not a counter; we just update + // it in one shot at the end. + ASTBytesAllocated = CS.getASTContext().getSolverMemory(); + // Write our local statistics back to the overall statistics. #define CS_STATISTIC(Name, Description) JOIN2(Overall,Name) += Name; #include "swift/Sema/ConstraintSolverStats.def" From 83118a73ede64403f5264d7fa6ae3856587303b4 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Mar 2025 14:40:26 -0400 Subject: [PATCH 4/5] Sema: Shave another 8 bytes off of Constraint --- include/swift/Sema/Constraint.h | 45 +++----- lib/Sema/CSSimplify.cpp | 10 +- lib/Sema/Constraint.cpp | 100 +++++++++--------- .../Sema/ConstraintSimplificationTests.cpp | 2 +- 4 files changed, 73 insertions(+), 84 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 4397d01fb8036..e1c8638e722b2 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -336,6 +336,7 @@ class Constraint final : public llvm::ilist_node, private llvm::TrailingObjects { friend TrailingObjects; @@ -354,6 +355,9 @@ class Constraint final : public llvm::ilist_node, /// Whether we have a tail-allocated fix. unsigned HasFix : 1; + /// Whether we have a tail-allocated DeclContext. + unsigned HasDeclContext : 1; + /// Whether the \c Restriction field is valid. unsigned HasRestriction : 1; @@ -392,7 +396,7 @@ class Constraint final : public llvm::ilist_node, /// node is unused. unsigned isDiscarded : 1; - // 23 bits remaining + // 22 bits remaining union { struct { @@ -425,20 +429,14 @@ class Constraint final : public llvm::ilist_node, /// Used for ValueWitness constraints. ValueDecl *Ref; } Member; - - /// The DC in which the use appears. - DeclContext *UseDC; } Member; /// The set of constraints for a disjunction. ArrayRef Nested; struct { - /// The first type + /// The first type. Type First; - - /// The DC in which the use appears. - DeclContext *UseDC; } Overload; struct { @@ -454,8 +452,6 @@ class Constraint final : public llvm::ilist_node, /// The type being called, primarily a function type, but could /// be a metatype, a tuple or a nominal type. Type Callee; - /// The declaration context in which the application appears. - DeclContext *UseDC; } Apply; }; @@ -531,6 +527,10 @@ class Constraint final : public llvm::ilist_node, return HasFix ? 1 : 0; } + size_t numTrailingObjects(OverloadToken) const { + return HasDeclContext ? 1 : 0; + } + size_t numTrailingObjects(OverloadToken) const { return Kind == ConstraintKind::SyntacticElement ? 1 : 0; } @@ -876,20 +876,6 @@ class Constraint final : public llvm::ilist_node, return *getTrailingObjects(); } - /// Retrieve the DC in which the overload was used. - DeclContext *getOverloadUseDC() const { - assert(Kind == ConstraintKind::BindOverload); - return Overload.UseDC; - } - - /// Retrieve the DC in which the member was used. - DeclContext *getMemberUseDC() const { - assert(Kind == ConstraintKind::ValueMember || - Kind == ConstraintKind::UnresolvedValueMember || - Kind == ConstraintKind::ValueWitness); - return Member.UseDC; - } - FunctionType *getAppliedFunctionType() const { assert(Kind == ConstraintKind::ApplicableFunction); return Apply.AppliedFn; @@ -900,11 +886,6 @@ class Constraint final : public llvm::ilist_node, return Apply.Callee; } - DeclContext *getApplicationDC() const { - assert(Kind == ConstraintKind::ApplicableFunction); - return Apply.UseDC; - } - ASTNode getSyntacticElement() const { assert(Kind == ConstraintKind::SyntacticElement); return SyntacticElement.Element; @@ -920,6 +901,12 @@ class Constraint final : public llvm::ilist_node, return isDiscarded; } + /// Retrieve the DC in which the overload was used. + DeclContext *getDeclContext() const { + assert(HasDeclContext); + return *getTrailingObjects(); + } + /// For an applicable function constraint, retrieve the trailing closure /// matching rule. std::optional getTrailingClosureMatching() const; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 2128e1c4240e6..233df84a30b17 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -13089,7 +13089,7 @@ bool ConstraintSystem::simplifyAppliedOverloadsImpl( // Determine the type that this choice will have. Type choiceType = getEffectiveOverloadType( constraint->getLocator(), choice, /*allowMembers=*/true, - constraint->getOverloadUseDC()); + constraint->getDeclContext()); if (!choiceType) { hasUnhandledConstraints = true; return true; @@ -16335,7 +16335,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyApplicableFnConstraint( constraint.getAppliedFunctionType(), constraint.getCalleeType(), constraint.getTrailingClosureMatching(), - constraint.getApplicationDC(), /*flags=*/std::nullopt, + constraint.getDeclContext(), /*flags=*/std::nullopt, constraint.getLocator()); case ConstraintKind::DynamicCallableApplicableFunction: @@ -16382,7 +16382,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { resolveOverload(constraint.getLocator(), constraint.getFirstType(), constraint.getOverloadChoice(), - constraint.getOverloadUseDC()); + constraint.getDeclContext()); return SolutionKind::Solved; case ConstraintKind::SubclassOf: @@ -16429,7 +16429,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { case ConstraintKind::UnresolvedValueMember: return simplifyMemberConstraint( constraint.getKind(), constraint.getFirstType(), constraint.getMember(), - constraint.getSecondType(), constraint.getMemberUseDC(), + constraint.getSecondType(), constraint.getDeclContext(), constraint.getFunctionRefInfo(), /*outerAlternatives=*/{}, /*flags*/ std::nullopt, constraint.getLocator()); @@ -16438,7 +16438,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { return simplifyValueWitnessConstraint( constraint.getKind(), constraint.getFirstType(), constraint.getRequirement(), constraint.getSecondType(), - constraint.getMemberUseDC(), constraint.getFunctionRefInfo(), + constraint.getDeclContext(), constraint.getFunctionRefInfo(), /*flags*/ std::nullopt, constraint.getLocator()); case ConstraintKind::Defaultable: diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 7c83d26575602..850f3fc378558 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -31,8 +31,8 @@ Constraint::Constraint(ConstraintKind kind, ArrayRef constraints, bool isIsolated, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(kind), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), + HasFix(false), HasDeclContext(false), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(isIsolated), Nested(constraints), Locator(locator) { assert(kind == ConstraintKind::Disjunction || @@ -56,8 +56,8 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(Kind), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), + HasFix(false), HasDeclContext(false), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), Types{First, Second, Type()}, Locator(locator) { @@ -138,8 +138,8 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(Kind), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), + HasFix(false), HasDeclContext(false), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), Types{First, Second, Third}, Locator(locator) { @@ -205,10 +205,10 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(kind), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), + HasFix(false), HasDeclContext(true), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), - Member{first, second, {member}, useDC}, + Member{first, second, {member}}, Locator(locator) { assert(kind == ConstraintKind::ValueMember || kind == ConstraintKind::UnresolvedValueMember); @@ -218,6 +218,7 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, assert(useDC && "Member constraint has no use DC"); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); + *getTrailingObjects() = useDC; } Constraint::Constraint(ConstraintKind kind, Type first, Type second, @@ -226,14 +227,13 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(kind), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), + HasFix(false), HasDeclContext(true), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), Locator(locator) { Member.First = first; Member.Second = second; Member.Member.Ref = requirement; - Member.UseDC = useDC; TheFunctionRefInfo = functionRefInfo.getOpaqueValue(); assert(kind == ConstraintKind::ValueWitness); @@ -242,20 +242,21 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, assert(useDC && "Member constraint has no use DC"); std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); + *getTrailingObjects() = useDC; } Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC, ConstraintFix *fix, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(ConstraintKind::BindOverload), NumTypeVariables(typeVars.size()), - HasFix(fix != nullptr), HasRestriction(false), IsActive(false), - IsDisabled(bool(fix)), IsDisabledForPerformance(false), + HasFix(fix != nullptr), HasDeclContext(true), HasRestriction(false), + IsActive(false), IsDisabled(bool(fix)), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), - Overload{type, useDC}, - Locator(locator) { + Overload{type}, Locator(locator) { std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); if (fix) *getTrailingObjects() = fix; + *getTrailingObjects() = useDC; *getTrailingObjects() = choice; } @@ -264,9 +265,9 @@ Constraint::Constraint(ConstraintKind kind, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(kind), Restriction(restriction), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(true), IsActive(false), IsDisabled(false), - IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), - IsIsolated(false), Types{first, second, Type()}, + HasFix(false), HasDeclContext(false), HasRestriction(true), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), + IsFavored(false), IsIsolated(false), Types{first, second, Type()}, Locator(locator) { ASSERT(isAdmissibleType(first)); ASSERT(isAdmissibleType(second)); @@ -277,9 +278,9 @@ Constraint::Constraint(ConstraintKind kind, ConstraintFix *fix, Type first, Type second, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(kind), NumTypeVariables(typeVars.size()), - HasFix(fix != nullptr), HasRestriction(false), IsActive(false), - IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), - IsFavored(false), IsIsolated(false), + HasFix(fix != nullptr), HasDeclContext(false), HasRestriction(false), + IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), + RememberChoice(false), IsFavored(false), IsIsolated(false), Types{first, second, Type()}, Locator(locator) { ASSERT(isAdmissibleType(first)); @@ -293,7 +294,7 @@ Constraint::Constraint(ASTNode node, ContextualTypeInfo context, bool isDiscarded, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(ConstraintKind::SyntacticElement), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), + HasFix(false), HasDeclContext(false), HasRestriction(false), IsActive(false), IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), isDiscarded(isDiscarded), SyntacticElement{node}, @@ -307,9 +308,10 @@ Constraint::Constraint(FunctionType *appliedFn, Type calleeType, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(ConstraintKind::ApplicableFunction), NumTypeVariables(typeVars.size()), - HasFix(false), HasRestriction(false), IsActive(false), IsDisabled(false), - IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), - IsIsolated(false), trailingClosureMatching(trailingClosureMatching), + HasFix(false), HasDeclContext(true), HasRestriction(false), IsActive(false), + IsDisabled(false), IsDisabledForPerformance(false), RememberChoice(false), + IsFavored(false), IsIsolated(false), + trailingClosureMatching(trailingClosureMatching), Locator(locator) { ASSERT(isAdmissibleType(appliedFn)); ASSERT(isAdmissibleType(calleeType)); @@ -318,9 +320,9 @@ Constraint::Constraint(FunctionType *appliedFn, Type calleeType, Apply.AppliedFn = appliedFn; Apply.Callee = calleeType; - Apply.UseDC = useDC; std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); + *getTrailingObjects() = useDC; } ProtocolDecl *Constraint::getProtocol() const { @@ -789,9 +791,9 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return ::new (mem) Constraint(kind, first, second, locator, typeVars); @@ -812,9 +814,9 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind, third->getTypeVariables(typeVars); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return ::new (mem) Constraint(kind, @@ -857,9 +859,9 @@ Constraint *Constraint::createMember(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, first, second, member, useDC, @@ -881,9 +883,9 @@ Constraint *Constraint::createValueWitness( // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, first, second, requirement, useDC, @@ -905,9 +907,9 @@ Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), fix ? 1 : 0, + typeVars.size(), fix ? 1 : 0, /*hasDeclContext=*/1, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/1); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(type, choice, useDC, fix, locator, typeVars); @@ -927,9 +929,9 @@ Constraint *Constraint::createRestricted(ConstraintSystem &cs, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, restriction, first, second, locator, @@ -948,9 +950,9 @@ Constraint *Constraint::createFixed(ConstraintSystem &cs, ConstraintKind kind, // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), fix ? 1 : 0, + typeVars.size(), fix ? 1 : 0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(kind, fix, first, second, locator, typeVars); @@ -1022,9 +1024,9 @@ Constraint *Constraint::createDisjunction(ConstraintSystem &cs, // Create the disjunction constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto disjunction = new (mem) @@ -1045,9 +1047,9 @@ Constraint *Constraint::createConjunction( assert(!constraints.empty() && "Empty conjunction constraint"); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto conjunction = new (mem) @@ -1083,9 +1085,9 @@ Constraint *Constraint::createApplicableFunction( // Create the constraint. auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/1, /*hasContextualTypeInfo=*/0, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); auto constraint = new (mem) @@ -1114,9 +1116,9 @@ Constraint *Constraint::createSyntacticElement(ConstraintSystem &cs, contextTy->getTypeVariables(typeVars); auto size = - totalSizeToAlloc( - typeVars.size(), /*hasFix=*/0, + typeVars.size(), /*hasFix=*/0, /*hasDeclContext=*/0, /*hasContextualTypeInfo=*/1, /*hasOverloadChoice=*/0); void *mem = cs.getAllocator().Allocate(size, alignof(Constraint)); return new (mem) Constraint(node, context, isDiscarded, locator, typeVars); diff --git a/unittests/Sema/ConstraintSimplificationTests.cpp b/unittests/Sema/ConstraintSimplificationTests.cpp index 062644198a37d..43f8d80329b29 100644 --- a/unittests/Sema/ConstraintSimplificationTests.cpp +++ b/unittests/Sema/ConstraintSimplificationTests.cpp @@ -218,7 +218,7 @@ TEST_F(SemaTest, TestInitializerUseDCIsSetCorrectlyInClosure) { ->isLastElement()); for (auto *choice : constraint->getNestedConstraints()) - ASSERT_EQ(choice->getOverloadUseDC(), closure); + ASSERT_EQ(choice->getDeclContext(), closure); } } } From 6d90d16f61dbae1cd172b1f48c4a65309c032d70 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 10 Mar 2025 15:10:15 -0400 Subject: [PATCH 5/5] Sema: Use ASSERT before getting trailing objects of Constraint If the precondition doesn't hold, we will return a pointer to some random memory, so it's best to always crash since this indicates something is seriously wrong. --- include/swift/Sema/Constraint.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index e1c8638e722b2..f58d53f514f48 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -872,7 +872,7 @@ class Constraint final : public llvm::ilist_node, /// Retrieve the overload choice for an overload-binding constraint. OverloadChoice getOverloadChoice() const { - assert(Kind == ConstraintKind::BindOverload); + ASSERT(Kind == ConstraintKind::BindOverload); return *getTrailingObjects(); } @@ -903,7 +903,7 @@ class Constraint final : public llvm::ilist_node, /// Retrieve the DC in which the overload was used. DeclContext *getDeclContext() const { - assert(HasDeclContext); + ASSERT(HasDeclContext); return *getTrailingObjects(); }