From 02cc5a2a272bc7ed1684b91e6a0077dfb101e48e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 13:59:26 -0400 Subject: [PATCH 1/7] Sema: Fix handling of AddedConstraint in PreparedOverload::discharge() --- lib/Sema/TypeOfReference.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 1a972ad80a264..96fd179f523d1 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2502,8 +2502,7 @@ void PreparedOverload::discharge(ConstraintSystem &cs, break; case PreparedOverload::Change::AddedConstraint: - cs.addUnsolvedConstraint(change.TheConstraint); - cs.activateConstraint(change.TheConstraint); + cs.simplifyDisjunctionChoice(change.TheConstraint); break; case PreparedOverload::Change::OpenedTypes: { From 8f0eaff8df82293f0aa08f0339045b2e86f3d22f Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 14:13:46 -0400 Subject: [PATCH 2/7] Sema: Plumb PreparedOverload into getTypeOfReferenceWithSpecialTypeCheckingSemantics() --- lib/Sema/TypeOfReference.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 96fd179f523d1..b308e5d51359d 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2377,7 +2377,8 @@ isInvalidPartialApplication(ConstraintSystem &cs, /// the full opened type and the reference's type. static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( ConstraintSystem &CS, ConstraintLocator *locator, - DeclTypeCheckingSemantics semantics) { + DeclTypeCheckingSemantics semantics, + PreparedOverload *preparedOverload) { switch (semantics) { case DeclTypeCheckingSemantics::Normal: llvm_unreachable("Decl does not have special type checking semantics!"); @@ -2389,17 +2390,18 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( // be expressed in the type system currently. auto input = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); auto output = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); FunctionType::Param inputArg(input, CS.getASTContext().getIdentifier("of")); CS.addConstraint( ConstraintKind::DynamicTypeOf, output, input, - CS.getConstraintLocator(locator, ConstraintLocator::DynamicType)); + CS.getConstraintLocator(locator, ConstraintLocator::DynamicType), + /*isFavored=*/false, preparedOverload); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; auto refType = FunctionType::get({inputArg}, output, info); @@ -2411,18 +2413,19 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( // @escaping. auto noescapeClosure = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); auto escapeClosure = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); CS.addConstraint(ConstraintKind::EscapableFunctionOf, escapeClosure, - noescapeClosure, CS.getConstraintLocator(locator)); + noescapeClosure, CS.getConstraintLocator(locator), + /*isFavored=*/false, preparedOverload); auto result = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); auto thrownError = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::ThrownErrorType), - 0); + 0, preparedOverload); FunctionType::Param arg(escapeClosure); auto bodyClosure = FunctionType::get(arg, result, FunctionType::ExtInfoBuilder() @@ -2448,18 +2451,19 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( // existential type as its input. auto openedTy = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); auto existentialTy = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionArgument), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); CS.addConstraint(ConstraintKind::OpenedExistentialOf, openedTy, - existentialTy, CS.getConstraintLocator(locator)); + existentialTy, CS.getConstraintLocator(locator), + /*isFavored=*/false, preparedOverload); auto result = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::FunctionResult), - TVO_CanBindToNoEscape); + TVO_CanBindToNoEscape, preparedOverload); auto thrownError = CS.createTypeVariable( CS.getConstraintLocator(locator, ConstraintLocator::ThrownErrorType), - 0); + 0, preparedOverload); FunctionType::Param bodyArgs[] = {FunctionType::Param(openedTy)}; auto bodyClosure = FunctionType::get(bodyArgs, result, FunctionType::ExtInfoBuilder() From 8527e88423babca223e49ccbc1f6684ef95efd85 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 9 Jul 2025 22:15:14 -0400 Subject: [PATCH 3/7] Sema: Extract prepareOverload() from resolveOverload() --- include/swift/Sema/ConstraintSystem.h | 9 ++++ lib/Sema/TypeOfReference.cpp | 72 +++++++++++++++++++-------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 3dfb878e3f890..a692b8f86a6f4 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -4929,6 +4929,15 @@ class ConstraintSystem { void recordResolvedOverload(ConstraintLocator *locator, SelectedOverload choice); + /// Populate the prepared overload with all type variables and constraints + /// that are to be introduced into the constraint system when this choice + /// is taken. + DeclReferenceType + prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC, + PreparedOverload *preparedOverload); + /// Resolve the given overload set to the given choice. void resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice, DeclContext *useDC); diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index b308e5d51359d..1f40d358117e1 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2550,6 +2550,39 @@ void PreparedOverload::discharge(ConstraintSystem &cs, } } +/// Populate the prepared overload with all type variables and constraints +/// that are to be introduced into the constraint system when this choice +/// is taken. +/// +/// FIXME: As a transitional mechanism, if preparedOverload is nullptr, this +/// immediately performs all operations. +DeclReferenceType +ConstraintSystem::prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC, + PreparedOverload *preparedOverload) { + // If we refer to a top-level decl with special type-checking semantics, + // handle it now. + auto semantics = + TypeChecker::getDeclTypeCheckingSemantics(choice.getDecl()); + if (semantics != DeclTypeCheckingSemantics::Normal) { + return getTypeOfReferenceWithSpecialTypeCheckingSemantics( + *this, locator, semantics, preparedOverload); + } else if (auto baseTy = choice.getBaseType()) { + // Retrieve the type of a reference to the specific declaration choice. + assert(!baseTy->hasTypeParameter()); + + return getTypeOfMemberReference( + baseTy, choice.getDecl(), useDC, + (choice.getKind() == OverloadChoiceKind::DeclViaDynamic), + choice.getFunctionRefInfo(), locator, nullptr, preparedOverload); + } else { + return getTypeOfReference( + choice.getDecl(), choice.getFunctionRefInfo(), locator, useDC, + preparedOverload); + } +} + void ConstraintSystem::resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice, DeclContext *useDC) { @@ -2560,34 +2593,29 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, Type adjustedRefType; Type thrownErrorTypeOnAccess; - switch (auto kind = choice.getKind()) { + switch (choice.getKind()) { case OverloadChoiceKind::Decl: case OverloadChoiceKind::DeclViaBridge: case OverloadChoiceKind::DeclViaDynamic: case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { - // If we refer to a top-level decl with special type-checking semantics, - // handle it now. - const auto semantics = - TypeChecker::getDeclTypeCheckingSemantics(choice.getDecl()); - DeclReferenceType declRefType; - if (semantics != DeclTypeCheckingSemantics::Normal) { - declRefType = getTypeOfReferenceWithSpecialTypeCheckingSemantics( - *this, locator, semantics); - } else if (auto baseTy = choice.getBaseType()) { - // Retrieve the type of a reference to the specific declaration choice. - assert(!baseTy->hasTypeParameter()); - - declRefType = getTypeOfMemberReference( - baseTy, choice.getDecl(), useDC, - (kind == OverloadChoiceKind::DeclViaDynamic), - choice.getFunctionRefInfo(), locator, nullptr, - /*preparedOverload=*/nullptr); - } else { - declRefType = getTypeOfReference( - choice.getDecl(), choice.getFunctionRefInfo(), locator, useDC, - /*preparedOverload=*/nullptr); + bool enablePreparedOverloads = false; + + PreparedOverload preparedOverload; + if (enablePreparedOverloads) { + ASSERT(!PreparingOverload); + PreparingOverload = true; + } + + auto declRefType = prepareOverload(locator, choice, useDC, + (enablePreparedOverloads + ? &preparedOverload + : nullptr)); + + if (enablePreparedOverloads) { + PreparingOverload = false; + preparedOverload.discharge(*this, locator); } openedType = declRefType.openedType; From f7a552385c52787a81113958aa0ca98868fcc0ee Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 14:35:16 -0400 Subject: [PATCH 4/7] Sema: PreparedOverload => PreparedOverloadBuilder --- include/swift/Sema/ConstraintSystem.h | 54 +++++++++-------- include/swift/Sema/PreparedOverload.h | 40 +++++++------ lib/Sema/CSGen.cpp | 4 +- lib/Sema/CSSimplify.cpp | 6 +- lib/Sema/CSSolver.cpp | 2 +- lib/Sema/ConstraintSystem.cpp | 2 +- lib/Sema/TypeOfReference.cpp | 85 ++++++++++++++------------- 7 files changed, 102 insertions(+), 91 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index a692b8f86a6f4..a92ab4c5fa142 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -65,6 +65,7 @@ namespace constraints { class ConstraintSystem; class SyntacticElementTarget; struct PreparedOverload; +struct PreparedOverloadBuilder; } // end namespace constraints @@ -2954,7 +2955,7 @@ class ConstraintSystem { /// Create a new type variable. TypeVariableType *createTypeVariable(ConstraintLocator *locator, unsigned options, - PreparedOverload *preparedOverload + PreparedOverloadBuilder *preparedOverload = nullptr); /// Retrieve the set of active type variables. @@ -3414,7 +3415,8 @@ class ConstraintSystem { /// Update OpenedExistentials and record a change in the trail. void recordOpenedExistentialType(ConstraintLocator *locator, ExistentialArchetypeType *opened, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload + = nullptr); /// Retrieve the generic environment for the opened element of a given pack /// expansion, or \c nullptr if no environment was recorded yet. @@ -3622,7 +3624,7 @@ class ConstraintSystem { /// Log and record the application of the fix. Return true iff any /// subsequent solution would be worse than the best known solution. bool recordFix(ConstraintFix *fix, unsigned impact = 1, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); void recordPotentialHole(TypeVariableType *typeVar); void recordAnyTypeVarAsPotentialHole(Type type); @@ -3698,13 +3700,13 @@ class ConstraintSystem { void addConstraint(ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, bool isFavored = false, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Add a requirement as a constraint to the constraint system. void addConstraint(Requirement req, ConstraintLocatorBuilder locator, bool isFavored, bool prohibitNonisolatedConformance, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); void addApplicationConstraint( FunctionType *appliedFn, Type calleeType, @@ -4319,7 +4321,7 @@ class ConstraintSystem { Type openUnboundGenericType(GenericTypeDecl *decl, Type parentTy, ConstraintLocatorBuilder locator, bool isTypeResolution, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Replace placeholder types with fresh type variables, and unbound generic /// types with bound generic types whose generic args are fresh type @@ -4330,7 +4332,7 @@ class ConstraintSystem { /// \returns The converted type. Type replaceInferableTypesWithTypeVars(Type type, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload + PreparedOverloadBuilder *preparedOverload = nullptr); /// "Open" the given type by replacing any occurrences of generic @@ -4343,7 +4345,7 @@ class ConstraintSystem { /// \returns The opened type, or \c type if there are no archetypes in it. Type openType(Type type, ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// "Open" an opaque archetype type, similar to \c openType. Type openOpaqueType(OpaqueTypeArchetypeType *type, @@ -4360,12 +4362,12 @@ class ConstraintSystem { Type openPackExpansionType(PackExpansionType *expansion, ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Update OpenedPackExpansionTypes and record a change in the trail. void recordOpenedPackExpansionType(PackExpansionType *expansion, TypeVariableType *expansionVar, - PreparedOverload *preparedOverload + PreparedOverloadBuilder *preparedOverload = nullptr); /// Undo the above change. @@ -4392,7 +4394,7 @@ class ConstraintSystem { ConstraintLocatorBuilder locator, SmallVectorImpl &replacements, DeclContext *outerDC, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Open the generic parameter list and its requirements, /// creating type variables for each of the type parameters. @@ -4400,7 +4402,7 @@ class ConstraintSystem { GenericSignature signature, ConstraintLocatorBuilder locator, SmallVectorImpl &replacements, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Open the generic parameter list creating type variables for each of the /// type parameters. @@ -4408,13 +4410,13 @@ class ConstraintSystem { GenericSignature signature, SmallVectorImpl &replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Open a generic parameter into a type variable and record /// it in \c replacements. TypeVariableType *openGenericParameter(GenericTypeParamType *parameter, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Given generic signature open its generic requirements, /// using substitution function, and record them in the @@ -4424,7 +4426,7 @@ class ConstraintSystem { bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator, llvm::function_ref subst, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); // Record the given requirement in the constraint system. void openGenericRequirement(DeclContext *outerDC, @@ -4434,18 +4436,18 @@ class ConstraintSystem { bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator, llvm::function_ref subst, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Update OpenedTypes and record a change in the trail. void recordOpenedType( ConstraintLocator *locator, ArrayRef openedTypes, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Record the set of opened types for the given locator. void recordOpenedTypes( ConstraintLocatorBuilder locator, const SmallVectorImpl &replacements, - PreparedOverload *preparedOverload = nullptr, + PreparedOverloadBuilder *preparedOverload = nullptr, bool fixmeAllowDuplicates = false); /// Check whether the given type conforms to the given protocol and if @@ -4458,7 +4460,7 @@ class ConstraintSystem { FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc, unsigned numApplies, bool isMainDispatchQueue, ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Retrieve the type of a reference to the given value declaration. /// @@ -4474,7 +4476,7 @@ class ConstraintSystem { FunctionRefInfo functionRefInfo, ConstraintLocatorBuilder locator, DeclContext *useDC, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); /// Return the type-of-reference of the given value. /// @@ -4516,7 +4518,7 @@ class ConstraintSystem { Type baseTy, ValueDecl *decl, DeclContext *useDC, bool isDynamicLookup, FunctionRefInfo functionRefInfo, ConstraintLocator *locator, SmallVectorImpl *replacements = nullptr, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Retrieve a list of generic parameter types solver has "opened" (replaced /// with a type variable) at the given location. @@ -4936,7 +4938,11 @@ class ConstraintSystem { prepareOverload(ConstraintLocator *locator, OverloadChoice choice, DeclContext *useDC, - PreparedOverload *preparedOverload); + PreparedOverloadBuilder *preparedOverload); + + void replayChanges( + ConstraintLocatorBuilder locator, + PreparedOverload preparedOverload); /// Resolve the given overload set to the given choice. void resolveOverload(ConstraintLocator *locator, Type boundType, @@ -5351,13 +5357,13 @@ class ConstraintSystem { ConstraintKind matchKind, ConstraintLocator *locator, ConstraintLocator *calleeLocator, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Used by applyPropertyWrapperToParameter() to update appliedPropertyWrappers /// and record a change in the trail. void applyPropertyWrapper(Expr *anchor, AppliedPropertyWrapper applied, - PreparedOverload *preparedOverload = nullptr); + PreparedOverloadBuilder *preparedOverload = nullptr); /// Undo the above change. void removePropertyWrapper(Expr *anchor); diff --git a/include/swift/Sema/PreparedOverload.h b/include/swift/Sema/PreparedOverload.h index 78962f8927081..f770afc53f159 100644 --- a/include/swift/Sema/PreparedOverload.h +++ b/include/swift/Sema/PreparedOverload.h @@ -100,66 +100,68 @@ struct PreparedOverload { }; }; - SmallVector Changes; + ArrayRef Changes; +}; + +struct PreparedOverloadBuilder { + SmallVector Changes; void addedTypeVariable(TypeVariableType *typeVar) { - Change change; - change.Kind = Change::AddedTypeVariable; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::AddedTypeVariable; change.TypeVar = typeVar; Changes.push_back(change); } void addedConstraint(Constraint *constraint) { - Change change; - change.Kind = Change::AddedConstraint; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::AddedConstraint; change.TheConstraint = constraint; Changes.push_back(change); } void openedTypes(ArrayRef replacements) { - Change change; - change.Kind = Change::OpenedTypes; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::OpenedTypes; change.Replacements.Data = replacements.data(); change.Replacements.Count = replacements.size(); Changes.push_back(change); } void openedExistentialType(ExistentialArchetypeType *openedExistential) { - Change change; - change.Kind = Change::OpenedExistentialType; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::OpenedExistentialType; change.TheExistential = openedExistential; Changes.push_back(change); } void openedPackExpansionType(PackExpansionType *packExpansion, TypeVariableType *typeVar) { - Change change; - change.Kind = Change::OpenedPackExpansionType; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::OpenedPackExpansionType; change.PackExpansion.TheExpansion = packExpansion; change.PackExpansion.TypeVar = typeVar; Changes.push_back(change); } void appliedPropertyWrapper(AppliedPropertyWrapper wrapper) { - Change change; - change.Kind = Change::AppliedPropertyWrapper; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::AppliedPropertyWrapper; change.PropertyWrapper.WrapperType = wrapper.wrapperType.getPointer(); change.PropertyWrapper.InitKind = wrapper.initKind; Changes.push_back(change); } void addedFix(ConstraintFix *fix, unsigned impact) { - Change change; - change.Kind = Change::AddedFix; + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::AddedFix; change.Fix.TheFix = fix; change.Fix.Impact = impact; Changes.push_back(change); } - - void discharge(ConstraintSystem &cs, ConstraintLocatorBuilder locator) const; }; -} -} +} // end namespace constraints +} // end namespace swift #endif diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 0b0e1af42d96b..91f8f7817843b 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -5124,7 +5124,7 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition, void ConstraintSystem::applyPropertyWrapper( Expr *anchor, AppliedPropertyWrapper applied, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { ASSERT(PreparingOverload); preparedOverload->appliedPropertyWrapper(applied); @@ -5160,7 +5160,7 @@ ConstraintSystem::applyPropertyWrapperToParameter( ConstraintKind matchKind, ConstraintLocator *locator, ConstraintLocator *calleeLocator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { Expr *anchor = getAsExpr(calleeLocator->getAnchor()); auto recordPropertyWrapperFix = [&](ConstraintFix *fix) -> TypeMatchResult { diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 80fe95cc8d617..c23923975ea24 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -15422,7 +15422,7 @@ static bool isAugmentingFix(ConstraintFix *fix) { } bool ConstraintSystem::recordFix(ConstraintFix *fix, unsigned impact, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { ASSERT(PreparingOverload); preparedOverload->addedFix(fix, impact); @@ -16298,7 +16298,7 @@ void ConstraintSystem::addConstraint(Requirement req, ConstraintLocatorBuilder locator, bool isFavored, bool prohibitNonisolatedConformance, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { bool conformsToAnyObject = false; std::optional kind; switch (req.getKind()) { @@ -16362,7 +16362,7 @@ void ConstraintSystem::addConstraint(ConstraintKind kind, Type first, Type second, ConstraintLocatorBuilder locator, bool isFavored, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { ASSERT(PreparingOverload); auto c = Constraint::create(*this, kind, first, second, diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp index b3f96ee3f8819..2f6d0c5f0100d 100644 --- a/lib/Sema/CSSolver.cpp +++ b/lib/Sema/CSSolver.cpp @@ -60,7 +60,7 @@ STATISTIC(LargestSolutionAttemptNumber, "# of the largest solution attempt"); TypeVariableType *ConstraintSystem::createTypeVariable( ConstraintLocator *locator, unsigned options, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { ++TotalNumTypeVariables; auto tv = TypeVariableType::getNew(getASTContext(), assignTypeVariableID(), locator, options); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 177093469d121..3d6c091a5b665 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -904,7 +904,7 @@ ConstraintSystem::openAnyExistentialType(Type type, void ConstraintSystem::recordOpenedExistentialType( ConstraintLocator *locator, ExistentialArchetypeType *opened, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { preparedOverload->openedExistentialType(opened); return; diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 1f40d358117e1..b380386fdf9e8 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -46,7 +46,7 @@ Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl, Type parentTy, ConstraintLocatorBuilder locator, bool isTypeResolution, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (parentTy) { parentTy = replaceInferableTypesWithTypeVars( parentTy, locator, preparedOverload); @@ -121,7 +121,7 @@ Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl, static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { // If this is a type defined inside of constrained extension, let's add all // of the generic requirements to the constraint system to make sure that it's // something we can use. @@ -200,7 +200,7 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, Type ConstraintSystem::replaceInferableTypesWithTypeVars( Type type, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (!type->hasUnboundGenericType() && !type->hasPlaceholder()) return type; @@ -246,12 +246,12 @@ namespace { struct TypeOpener : public TypeTransform { ArrayRef replacements; ConstraintLocatorBuilder locator; - PreparedOverload *preparedOverload; + PreparedOverloadBuilder *preparedOverload; ConstraintSystem &cs; TypeOpener(ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload, + PreparedOverloadBuilder *preparedOverload, ConstraintSystem &cs) : TypeTransform(cs.getASTContext()), replacements(replacements), locator(locator), @@ -295,7 +295,7 @@ struct TypeOpener : public TypeTransform { Type ConstraintSystem::openType(Type type, ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { assert(!type->hasUnboundGenericType()); if (!type->hasTypeParameter()) @@ -308,7 +308,7 @@ Type ConstraintSystem::openType(Type type, ArrayRef replacements, Type ConstraintSystem::openPackExpansionType(PackExpansionType *expansion, ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { auto patternType = openType(expansion->getPatternType(), replacements, locator, preparedOverload); @@ -357,7 +357,7 @@ Type ConstraintSystem::openPackExpansionType(PackExpansionType *expansion, void ConstraintSystem::recordOpenedPackExpansionType(PackExpansionType *expansion, TypeVariableType *expansionVar, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { ASSERT(PreparingOverload); preparedOverload->openedPackExpansionType(expansion, expansionVar); @@ -477,7 +477,7 @@ FunctionType *ConstraintSystem::openFunctionType( ConstraintLocatorBuilder locator, SmallVectorImpl &replacements, DeclContext *outerDC, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (auto *genericFn = funcType->getAs()) { auto signature = genericFn->getGenericSignature(); openGenericParameters(outerDC, signature, replacements, locator, @@ -701,7 +701,7 @@ Type ConstraintSystem::getUnopenedTypeOfReference( void ConstraintSystem::recordOpenedType( ConstraintLocator *locator, ArrayRef replacements, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (preparedOverload) { ASSERT(PreparingOverload); preparedOverload->openedTypes(replacements); @@ -720,7 +720,7 @@ void ConstraintSystem::recordOpenedType( void ConstraintSystem::recordOpenedTypes( ConstraintLocatorBuilder locator, const SmallVectorImpl &replacements, - PreparedOverload *preparedOverload, + PreparedOverloadBuilder *preparedOverload, bool fixmeAllowDuplicates) { if (replacements.empty()) return; @@ -810,7 +810,7 @@ unwrapPropertyWrapperParameterTypes(ConstraintSystem &cs, FunctionRefInfo functionRefInfo, FunctionType *functionType, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { // Only apply property wrappers to unapplied references to functions. if (!functionRefInfo.isUnapplied()) return functionType; @@ -870,7 +870,7 @@ static bool isRequirementOrWitness(const ConstraintLocatorBuilder &locator) { FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency( FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc, unsigned numApplies, bool isMainDispatchQueue, ArrayRef replacements, - ConstraintLocatorBuilder locator, PreparedOverload *preparedOverload) { + ConstraintLocatorBuilder locator, PreparedOverloadBuilder *preparedOverload) { auto *adjustedTy = swift::adjustFunctionTypeForConcurrency( fnType, decl, dc, numApplies, isMainDispatchQueue, GetClosureType{*this}, @@ -997,7 +997,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, FunctionRefInfo functionRefInfo, ConstraintLocatorBuilder locator, DeclContext *useDC, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { ASSERT(!!preparedOverload == PreparingOverload); if (value->getDeclContext()->isTypeContext() && isa(value)) { @@ -1181,7 +1181,7 @@ static void bindArchetypesFromContext( DeclContext *outerDC, ConstraintLocator *locatorPtr, ArrayRef replacements, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { auto bindPrimaryArchetype = [&](Type paramTy, Type contextTy) { // We might not have a type variable for this generic parameter @@ -1227,7 +1227,7 @@ void ConstraintSystem::openGeneric( GenericSignature sig, ConstraintLocatorBuilder locator, SmallVectorImpl &replacements, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { if (!sig) return; @@ -1245,7 +1245,7 @@ void ConstraintSystem::openGenericParameters(DeclContext *outerDC, GenericSignature sig, SmallVectorImpl &replacements, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { ASSERT(sig); ASSERT(replacements.empty()); @@ -1263,7 +1263,7 @@ void ConstraintSystem::openGenericParameters(DeclContext *outerDC, TypeVariableType *ConstraintSystem::openGenericParameter(GenericTypeParamType *parameter, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { auto *paramLocator = getConstraintLocator( locator.withPathElement(LocatorPathElt::GenericParameter(parameter))); @@ -1282,7 +1282,7 @@ void ConstraintSystem::openGenericRequirements( DeclContext *outerDC, GenericSignature signature, bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator, llvm::function_ref substFn, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { auto requirements = signature.getRequirements(); for (unsigned pos = 0, n = requirements.size(); pos != n; ++pos) { auto openedGenericLoc = @@ -1298,7 +1298,7 @@ void ConstraintSystem::openGenericRequirement( unsigned index, const Requirement &req, bool skipProtocolSelfConstraint, ConstraintLocatorBuilder locator, llvm::function_ref substFn, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { std::optional openedReq; auto openedFirst = substFn(req.getFirstType()); @@ -1351,7 +1351,7 @@ void ConstraintSystem::openGenericRequirement( /// declared. static void addSelfConstraint(ConstraintSystem &cs, Type objectTy, Type selfTy, ConstraintLocatorBuilder locator, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { assert(!selfTy->is()); // Otherwise, use a subtype constraint for classes to cope with inheritance. @@ -1590,7 +1590,7 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( Type baseTy, ValueDecl *value, DeclContext *useDC, bool isDynamicLookup, FunctionRefInfo functionRefInfo, ConstraintLocator *locator, SmallVectorImpl *replacementsPtr, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { ASSERT(!!preparedOverload == PreparingOverload); // Figure out the instance type used for the base. @@ -2378,7 +2378,7 @@ isInvalidPartialApplication(ConstraintSystem &cs, static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( ConstraintSystem &CS, ConstraintLocator *locator, DeclTypeCheckingSemantics semantics, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { switch (semantics) { case DeclTypeCheckingSemantics::Normal: llvm_unreachable("Decl does not have special type checking semantics!"); @@ -2497,54 +2497,55 @@ void ConstraintSystem::recordResolvedOverload(ConstraintLocator *locator, recordChange(SolverTrail::Change::ResolvedOverload(locator)); } -void PreparedOverload::discharge(ConstraintSystem &cs, - ConstraintLocatorBuilder locator) const { - for (auto change : Changes) { +void ConstraintSystem::replayChanges( + ConstraintLocatorBuilder locator, + PreparedOverload preparedOverload) { + for (auto change : preparedOverload.Changes) { switch (change.Kind) { case PreparedOverload::Change::AddedTypeVariable: - cs.addTypeVariable(change.TypeVar); + addTypeVariable(change.TypeVar); break; case PreparedOverload::Change::AddedConstraint: - cs.simplifyDisjunctionChoice(change.TheConstraint); + simplifyDisjunctionChoice(change.TheConstraint); break; case PreparedOverload::Change::OpenedTypes: { - auto *locatorPtr = cs.getConstraintLocator(locator); + auto *locatorPtr = getConstraintLocator(locator); ArrayRef replacements( change.Replacements.Data, change.Replacements.Count); // FIXME: Get rid of this conditional. - if (cs.getOpenedTypes(locatorPtr).empty()) - cs.recordOpenedType(locatorPtr, replacements); + if (getOpenedTypes(locatorPtr).empty()) + recordOpenedType(locatorPtr, replacements); break; } case PreparedOverload::Change::OpenedExistentialType: { - auto *locatorPtr = cs.getConstraintLocator(locator); - cs.recordOpenedExistentialType(locatorPtr, - change.TheExistential); + auto *locatorPtr = getConstraintLocator(locator); + recordOpenedExistentialType(locatorPtr, + change.TheExistential); break; } case PreparedOverload::Change::OpenedPackExpansionType: - cs.recordOpenedPackExpansionType( + recordOpenedPackExpansionType( change.PackExpansion.TheExpansion, change.PackExpansion.TypeVar); break; case PreparedOverload::Change::AppliedPropertyWrapper: { - auto *locatorPtr = cs.getConstraintLocator(locator); + auto *locatorPtr = getConstraintLocator(locator); Expr *anchor = getAsExpr(locatorPtr->getAnchor()); - cs.applyPropertyWrapper(anchor, + applyPropertyWrapper(anchor, { Type(change.PropertyWrapper.WrapperType), change.PropertyWrapper.InitKind }); break; } case PreparedOverload::Change::AddedFix: - cs.recordFix(change.Fix.TheFix, change.Fix.Impact); + recordFix(change.Fix.TheFix, change.Fix.Impact); break; } } @@ -2560,7 +2561,7 @@ DeclReferenceType ConstraintSystem::prepareOverload(ConstraintLocator *locator, OverloadChoice choice, DeclContext *useDC, - PreparedOverload *preparedOverload) { + PreparedOverloadBuilder *preparedOverload) { // If we refer to a top-level decl with special type-checking semantics, // handle it now. auto semantics = @@ -2600,9 +2601,10 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { + // FIXME: Transitional hack bool enablePreparedOverloads = false; - PreparedOverload preparedOverload; + PreparedOverloadBuilder preparedOverload; if (enablePreparedOverloads) { ASSERT(!PreparingOverload); PreparingOverload = true; @@ -2615,7 +2617,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, if (enablePreparedOverloads) { PreparingOverload = false; - preparedOverload.discharge(*this, locator); + PreparedOverload result{preparedOverload.Changes}; + replayChanges(locator, result); } openedType = declRefType.openedType; From 7916ed982f299f086ca6843faf221ffe7668432e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 16:08:46 -0400 Subject: [PATCH 5/7] Sema: Move DeclReferenceType to PreparedOverload.h --- include/swift/Sema/ConstraintSystem.h | 31 +++------------------------ include/swift/Sema/PreparedOverload.h | 29 +++++++++++++++++++++++++ lib/Sema/TypeCheckProtocol.cpp | 1 + lib/Sema/TypeOfReference.cpp | 2 +- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index a92ab4c5fa142..536859a5b5510 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -64,6 +64,9 @@ namespace constraints { class ConstraintSystem; class SyntacticElementTarget; + +// PreparedOverload.h +struct DeclReferenceType; struct PreparedOverload; struct PreparedOverloadBuilder; @@ -2144,34 +2147,6 @@ struct ClosureIsolatedByPreconcurrency { bool operator()(const ClosureExpr *expr) const; }; -/// Describes the type produced when referencing a declaration. -struct DeclReferenceType { - /// The "opened" type, which is the type of the declaration where any - /// generic parameters have been replaced with type variables. - /// - /// The mapping from generic parameters to type variables will have been - /// recorded by \c recordOpenedTypes when this type is produced. - Type openedType; - - /// The opened type, after performing contextual type adjustments such as - /// removing concurrency-related annotations for a `@preconcurrency` - /// operation. - Type adjustedOpenedType; - - /// The type of the reference, based on the original opened type. This is the - /// type that the expression used to form the declaration reference would - /// have if no adjustments had been applied. - Type referenceType; - - /// The type of the reference, which is the adjusted opened type after - /// (e.g.) applying the base of a member access. This is the type of the - /// expression used to form the declaration reference. - Type adjustedReferenceType; - - /// The type that could be thrown by accessing this declaration. - Type thrownErrorTypeOnAccess; -}; - /// Describes a system of constraints on type variables, the /// solution of which assigns concrete types to each of the type variables. /// Constraint systems are typically generated given an (untyped) expression. diff --git a/include/swift/Sema/PreparedOverload.h b/include/swift/Sema/PreparedOverload.h index f770afc53f159..6592b7f0cb74b 100644 --- a/include/swift/Sema/PreparedOverload.h +++ b/include/swift/Sema/PreparedOverload.h @@ -27,6 +27,34 @@ namespace constraints { class ConstraintLocatorBuilder; class ConstraintSystem; +/// Describes the type produced when referencing a declaration. +struct DeclReferenceType { + /// The "opened" type, which is the type of the declaration where any + /// generic parameters have been replaced with type variables. + /// + /// The mapping from generic parameters to type variables will have been + /// recorded by \c recordOpenedTypes when this type is produced. + Type openedType; + + /// The opened type, after performing contextual type adjustments such as + /// removing concurrency-related annotations for a `@preconcurrency` + /// operation. + Type adjustedOpenedType; + + /// The type of the reference, based on the original opened type. This is the + /// type that the expression used to form the declaration reference would + /// have if no adjustments had been applied. + Type referenceType; + + /// The type of the reference, which is the adjusted opened type after + /// (e.g.) applying the base of a member access. This is the type of the + /// expression used to form the declaration reference. + Type adjustedReferenceType; + + /// The type that could be thrown by accessing this declaration. + Type thrownErrorTypeOnAccess; +}; + /// Describes a dependent type that has been opened to a particular type /// variable. using OpenedType = std::pair; @@ -101,6 +129,7 @@ struct PreparedOverload { }; ArrayRef Changes; + DeclReferenceType DeclType; }; struct PreparedOverloadBuilder { diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 679b3c282a523..c7d579352da16 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -62,6 +62,7 @@ #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Sema/IDETypeChecking.h" +#include "swift/Sema/PreparedOverload.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index b380386fdf9e8..fa45ca9d9a9d6 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2617,7 +2617,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, if (enablePreparedOverloads) { PreparingOverload = false; - PreparedOverload result{preparedOverload.Changes}; + PreparedOverload result{preparedOverload.Changes, declRefType}; replayChanges(locator, result); } From 83f95aeaed12d848e567eb822a6c9065382d48c2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 17:03:26 -0400 Subject: [PATCH 6/7] Sema: Allocate PreparedOverload in solver arena --- include/swift/Sema/ConstraintSystem.h | 19 +-- include/swift/Sema/PreparedOverload.h | 161 ++++++++++++++++---------- lib/Sema/TypeOfReference.cpp | 79 +++++++------ 3 files changed, 160 insertions(+), 99 deletions(-) diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 536859a5b5510..74297f857471b 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -67,7 +67,7 @@ class SyntacticElementTarget; // PreparedOverload.h struct DeclReferenceType; -struct PreparedOverload; +class PreparedOverload; struct PreparedOverloadBuilder; } // end namespace constraints @@ -4906,18 +4906,23 @@ class ConstraintSystem { void recordResolvedOverload(ConstraintLocator *locator, SelectedOverload choice); + /// Build and allocate a prepared overload in the solver arena. + const PreparedOverload *prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC); + /// Populate the prepared overload with all type variables and constraints /// that are to be introduced into the constraint system when this choice /// is taken. DeclReferenceType - prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC, - PreparedOverloadBuilder *preparedOverload); + prepareOverloadImpl(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC, + PreparedOverloadBuilder *preparedOverload); void replayChanges( - ConstraintLocatorBuilder locator, - PreparedOverload preparedOverload); + ConstraintLocator *locator, + const PreparedOverload *preparedOverload); /// Resolve the given overload set to the given choice. void resolveOverload(ConstraintLocator *locator, Type boundType, diff --git a/include/swift/Sema/PreparedOverload.h b/include/swift/Sema/PreparedOverload.h index 6592b7f0cb74b..7cba8076eabce 100644 --- a/include/swift/Sema/PreparedOverload.h +++ b/include/swift/Sema/PreparedOverload.h @@ -13,8 +13,10 @@ #define SWIFT_SEMA_PREPAREDOVERLOAD_H #include "swift/AST/PropertyWrappers.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/TrailingObjects.h" namespace swift { @@ -59,77 +61,118 @@ struct DeclReferenceType { /// variable. using OpenedType = std::pair; -/// A "pre-cooked" representation of all type variables and constraints -/// that are generated as part of an overload choice. -struct PreparedOverload { - /// A change to be introduced into the constraint system when this - /// overload choice is chosen. - struct Change { - enum ChangeKind : unsigned { - /// A generic parameter was opened to a type variable. - AddedTypeVariable, +/// A change to be introduced into the constraint system when this +/// overload choice is chosen. +struct PreparedOverloadChange { + enum ChangeKind : unsigned { + /// A generic parameter was opened to a type variable. + AddedTypeVariable, - /// A generic requirement was opened to a constraint. - AddedConstraint, + /// A generic requirement was opened to a constraint. + AddedConstraint, - /// A mapping of generic parameter types to type variables - /// was recorded. - OpenedTypes, + /// A mapping of generic parameter types to type variables + /// was recorded. + OpenedTypes, - /// An existential type was opened. - OpenedExistentialType, + /// An existential type was opened. + OpenedExistentialType, - /// A pack expansion type was opened. - OpenedPackExpansionType, + /// A pack expansion type was opened. + OpenedPackExpansionType, - /// A property wrapper was applied to a parameter. - AppliedPropertyWrapper, + /// A property wrapper was applied to a parameter. + AppliedPropertyWrapper, - /// A fix was recorded because a property wrapper application failed. - AddedFix - }; + /// A fix was recorded because a property wrapper application failed. + AddedFix + }; - /// The kind of change. - ChangeKind Kind; + /// The kind of change. + ChangeKind Kind; - union { - /// For ChangeKind::AddedTypeVariable. - TypeVariableType *TypeVar; + union { + /// For ChangeKind::AddedTypeVariable. + TypeVariableType *TypeVar; - /// For ChangeKind::AddedConstraint. - Constraint *TheConstraint; - - /// For ChangeKind::OpenedTypes. - struct { - const OpenedType *Data; - size_t Count; - } Replacements; - - /// For ChangeKind::OpenedExistentialType. - ExistentialArchetypeType *TheExistential; - - /// For ChangeKind::OpenedPackExpansionType. - struct { - PackExpansionType *TheExpansion; - TypeVariableType *TypeVar; - } PackExpansion; - - /// For ChangeKind::AppliedPropertyWrapper. - struct { - TypeBase *WrapperType; - PropertyWrapperInitKind InitKind; - } PropertyWrapper; - - /// For ChangeKind::Fix. - struct { - ConstraintFix *TheFix; - unsigned Impact; - } Fix; - }; + /// For ChangeKind::AddedConstraint. + Constraint *TheConstraint; + + /// For ChangeKind::OpenedTypes. + struct { + const OpenedType *Data; + size_t Count; + } Replacements; + + /// For ChangeKind::OpenedExistentialType. + ExistentialArchetypeType *TheExistential; + + /// For ChangeKind::OpenedPackExpansionType. + struct { + PackExpansionType *TheExpansion; + TypeVariableType *TypeVar; + } PackExpansion; + + /// For ChangeKind::AppliedPropertyWrapper. + struct { + TypeBase *WrapperType; + PropertyWrapperInitKind InitKind; + } PropertyWrapper; + + /// For ChangeKind::Fix. + struct { + ConstraintFix *TheFix; + unsigned Impact; + } Fix; }; +}; + +/// A "pre-cooked" representation of all type variables and constraints +/// that are generated as part of an overload choice. +class PreparedOverload final : + public llvm::TrailingObjects { - ArrayRef Changes; +public: + using Change = PreparedOverloadChange; + +private: + size_t Count; DeclReferenceType DeclType; + + size_t numTrailingObjects(OverloadToken) const { + return Count; + } + +public: + PreparedOverload(const DeclReferenceType &declType, ArrayRef changes) + : Count(changes.size()), DeclType(declType) { + std::uninitialized_copy(changes.begin(), changes.end(), + getTrailingObjects()); + } + + Type getOpenedType() const { + return DeclType.openedType; + } + + Type getAdjustedOpenedType() const { + return DeclType.adjustedOpenedType; + } + + Type getReferenceType() const { + return DeclType.referenceType; + } + + Type getAdjustedReferenceType() const { + return DeclType.adjustedReferenceType; + } + + Type getThrownErrorTypeOnAccess() const { + return DeclType.thrownErrorTypeOnAccess; + } + + ArrayRef getChanges() const { + return ArrayRef(getTrailingObjects(), Count); + } }; struct PreparedOverloadBuilder { diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index fa45ca9d9a9d6..2bad1f765ec3e 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2498,9 +2498,9 @@ void ConstraintSystem::recordResolvedOverload(ConstraintLocator *locator, } void ConstraintSystem::replayChanges( - ConstraintLocatorBuilder locator, - PreparedOverload preparedOverload) { - for (auto change : preparedOverload.Changes) { + ConstraintLocator *locator, + const PreparedOverload *preparedOverload) { + for (auto change : preparedOverload->getChanges()) { switch (change.Kind) { case PreparedOverload::Change::AddedTypeVariable: addTypeVariable(change.TypeVar); @@ -2511,20 +2511,18 @@ void ConstraintSystem::replayChanges( break; case PreparedOverload::Change::OpenedTypes: { - auto *locatorPtr = getConstraintLocator(locator); ArrayRef replacements( change.Replacements.Data, change.Replacements.Count); // FIXME: Get rid of this conditional. - if (getOpenedTypes(locatorPtr).empty()) - recordOpenedType(locatorPtr, replacements); + if (getOpenedTypes(locator).empty()) + recordOpenedType(locator, replacements); break; } case PreparedOverload::Change::OpenedExistentialType: { - auto *locatorPtr = getConstraintLocator(locator); - recordOpenedExistentialType(locatorPtr, + recordOpenedExistentialType(locator, change.TheExistential); break; } @@ -2536,8 +2534,7 @@ void ConstraintSystem::replayChanges( break; case PreparedOverload::Change::AppliedPropertyWrapper: { - auto *locatorPtr = getConstraintLocator(locator); - Expr *anchor = getAsExpr(locatorPtr->getAnchor()); + Expr *anchor = getAsExpr(locator->getAnchor()); applyPropertyWrapper(anchor, { Type(change.PropertyWrapper.WrapperType), change.PropertyWrapper.InitKind }); @@ -2558,10 +2555,10 @@ void ConstraintSystem::replayChanges( /// FIXME: As a transitional mechanism, if preparedOverload is nullptr, this /// immediately performs all operations. DeclReferenceType -ConstraintSystem::prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC, - PreparedOverloadBuilder *preparedOverload) { +ConstraintSystem::prepareOverloadImpl(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC, + PreparedOverloadBuilder *preparedOverload) { // If we refer to a top-level decl with special type-checking semantics, // handle it now. auto semantics = @@ -2584,6 +2581,25 @@ ConstraintSystem::prepareOverload(ConstraintLocator *locator, } } +const PreparedOverload * +ConstraintSystem::prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC) { + ASSERT(!PreparingOverload); + PreparingOverload = true; + + PreparedOverloadBuilder builder; + auto declRefType = prepareOverloadImpl(locator, choice, useDC, &builder); + + PreparingOverload = false; + + size_t count = builder.Changes.size(); + auto size = PreparedOverload::totalSizeToAlloc(count); + auto mem = Allocator.Allocate(size, alignof(PreparedOverload)); + + return new (mem) PreparedOverload(declRefType, builder.Changes); +} + void ConstraintSystem::resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice, DeclContext *useDC) { @@ -2602,30 +2618,27 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { // FIXME: Transitional hack - bool enablePreparedOverloads = false; + bool enablePreparedOverloads = true; - PreparedOverloadBuilder preparedOverload; if (enablePreparedOverloads) { - ASSERT(!PreparingOverload); - PreparingOverload = true; - } - - auto declRefType = prepareOverload(locator, choice, useDC, - (enablePreparedOverloads - ? &preparedOverload - : nullptr)); + auto *preparedOverload = prepareOverload(locator, choice, useDC); + replayChanges(locator, preparedOverload); + + openedType = preparedOverload->getOpenedType(); + adjustedOpenedType = preparedOverload->getAdjustedOpenedType(); + refType = preparedOverload->getReferenceType(); + adjustedRefType = preparedOverload->getAdjustedReferenceType(); + thrownErrorTypeOnAccess = preparedOverload->getThrownErrorTypeOnAccess(); + } else { + auto declRefType = prepareOverloadImpl(locator, choice, useDC, nullptr); - if (enablePreparedOverloads) { - PreparingOverload = false; - PreparedOverload result{preparedOverload.Changes, declRefType}; - replayChanges(locator, result); + openedType = declRefType.openedType; + adjustedOpenedType = declRefType.adjustedOpenedType; + refType = declRefType.referenceType; + adjustedRefType = declRefType.adjustedReferenceType; + thrownErrorTypeOnAccess = declRefType.thrownErrorTypeOnAccess; } - openedType = declRefType.openedType; - adjustedOpenedType = declRefType.adjustedOpenedType; - refType = declRefType.referenceType; - adjustedRefType = declRefType.adjustedReferenceType; - thrownErrorTypeOnAccess = declRefType.thrownErrorTypeOnAccess; break; } From 9a8f3baa06e3099195d28a44c65dd79a10ef2de2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 10 Jul 2025 18:51:25 -0400 Subject: [PATCH 7/7] Sema: Add room for a PreparedOverload to BindOverload constraint --- include/swift/Sema/Constraint.h | 15 ++++++++++++++- include/swift/Sema/ConstraintSystem.h | 17 +++++++++-------- include/swift/Sema/OverloadChoice.h | 17 +++++++++++++++++ lib/Sema/CSGen.cpp | 2 +- lib/Sema/CSSimplify.cpp | 7 ++++--- lib/Sema/Constraint.cpp | 23 +++++++++++++++++++---- lib/Sema/TypeOfReference.cpp | 18 +++++++----------- 7 files changed, 71 insertions(+), 28 deletions(-) diff --git a/include/swift/Sema/Constraint.h b/include/swift/Sema/Constraint.h index 72db2f161ba39..4428ab650a31e 100644 --- a/include/swift/Sema/Constraint.h +++ b/include/swift/Sema/Constraint.h @@ -49,6 +49,7 @@ namespace constraints { class ConstraintFix; class ConstraintLocator; class ConstraintSystem; +class PreparedOverload; enum class TrailingClosureMatching; /// Describes the kind of constraint placed on one or more types. @@ -437,6 +438,9 @@ class Constraint final : public llvm::ilist_node, struct { /// The first type. Type First; + + /// The prepared overload, if any. + PreparedOverload *Prepared; } Overload; struct { @@ -490,7 +494,9 @@ class Constraint final : public llvm::ilist_node, SmallPtrSetImpl &typeVars); /// Construct a new overload-binding constraint, which might have a fix. - Constraint(Type type, OverloadChoice choice, DeclContext *useDC, + Constraint(Type type, OverloadChoice choice, + PreparedOverload *preparedOverload, + DeclContext *useDC, ConstraintFix *fix, ConstraintLocator *locator, SmallPtrSetImpl &typeVars); @@ -871,6 +877,13 @@ class Constraint final : public llvm::ilist_node, return *getTrailingObjects(); } + /// Retrieve the prepared overload choice for an overload-binding + /// constraint. + PreparedOverload *getPreparedOverload() const { + ASSERT(Kind == ConstraintKind::BindOverload); + return Overload.Prepared; + } + FunctionType *getAppliedFunctionType() const { assert(Kind == ConstraintKind::ApplicableFunction); return Apply.AppliedFn; diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 74297f857471b..45524d70713e3 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -3791,9 +3791,9 @@ class ConstraintSystem { /// Add a constraint that binds an overload set to a specific choice. void addBindOverloadConstraint(Type boundTy, OverloadChoice choice, - ConstraintLocator *locator, - DeclContext *useDC) { - resolveOverload(locator, boundTy, choice, useDC); + ConstraintLocator *locator, DeclContext *useDC) { + resolveOverload(locator, boundTy, choice, useDC, + /*preparedOverload=*/nullptr); } /// Add a value member constraint to the constraint system. @@ -4907,9 +4907,9 @@ class ConstraintSystem { SelectedOverload choice); /// Build and allocate a prepared overload in the solver arena. - const PreparedOverload *prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC); + PreparedOverload *prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC); /// Populate the prepared overload with all type variables and constraints /// that are to be introduced into the constraint system when this choice @@ -4922,11 +4922,12 @@ class ConstraintSystem { void replayChanges( ConstraintLocator *locator, - const PreparedOverload *preparedOverload); + PreparedOverload *preparedOverload); /// Resolve the given overload set to the given choice. void resolveOverload(ConstraintLocator *locator, Type boundType, - OverloadChoice choice, DeclContext *useDC); + OverloadChoice choice, DeclContext *useDC, + PreparedOverload *preparedOverload); /// Simplify a type, by replacing type variables with either their /// fixed types (if available) or their representatives. diff --git a/include/swift/Sema/OverloadChoice.h b/include/swift/Sema/OverloadChoice.h index 111703be8f50e..9e01884189045 100644 --- a/include/swift/Sema/OverloadChoice.h +++ b/include/swift/Sema/OverloadChoice.h @@ -250,6 +250,23 @@ class OverloadChoice { return (OverloadChoiceKind)kind; } + bool canBePrepared() const { + switch (getKind()) { + case OverloadChoiceKind::Decl: + case OverloadChoiceKind::DeclViaBridge: + case OverloadChoiceKind::DeclViaDynamic: + case OverloadChoiceKind::DeclViaUnwrappedOptional: + case OverloadChoiceKind::DynamicMemberLookup: + case OverloadChoiceKind::KeyPathDynamicMemberLookup: + return true; + case OverloadChoiceKind::TupleIndex: + case OverloadChoiceKind::MaterializePack: + case OverloadChoiceKind::ExtractFunctionIsolation: + case OverloadChoiceKind::KeyPathApplication: + return false; + } + } + /// Determine whether this choice is for a declaration. bool isDecl() const { return DeclOrKind.is(); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 91f8f7817843b..5c0bc687ae108 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1660,7 +1660,7 @@ namespace { OverloadChoice choice = OverloadChoice(Type(), E->getDecl(), E->getFunctionRefInfo()); - CS.resolveOverload(locator, tv, choice, CurDC); + CS.addBindOverloadConstraint(tv, choice, locator, CurDC); return tv; } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index c23923975ea24..bb07eac4d5541 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -11834,8 +11834,8 @@ ConstraintSystem::simplifyValueWitnessConstraint( return fail(); auto choice = OverloadChoice(resolvedBaseType, witness.getDecl(), functionRefInfo); - resolveOverload(getConstraintLocator(locator), memberType, choice, - useDC); + addBindOverloadConstraint(memberType, choice, getConstraintLocator(locator), + useDC); return SolutionKind::Solved; } @@ -16661,7 +16661,8 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { resolveOverload(constraint.getLocator(), constraint.getFirstType(), constraint.getOverloadChoice(), - constraint.getDeclContext()); + constraint.getDeclContext(), + constraint.getPreparedOverload()); return SolutionKind::Solved; case ConstraintKind::SubclassOf: diff --git a/lib/Sema/Constraint.cpp b/lib/Sema/Constraint.cpp index 850f3fc378558..af6bbf0f17c44 100644 --- a/lib/Sema/Constraint.cpp +++ b/lib/Sema/Constraint.cpp @@ -245,14 +245,16 @@ Constraint::Constraint(ConstraintKind kind, Type first, Type second, *getTrailingObjects() = useDC; } -Constraint::Constraint(Type type, OverloadChoice choice, DeclContext *useDC, +Constraint::Constraint(Type type, OverloadChoice choice, + PreparedOverload *preparedOverload, + DeclContext *useDC, ConstraintFix *fix, ConstraintLocator *locator, SmallPtrSetImpl &typeVars) : Kind(ConstraintKind::BindOverload), NumTypeVariables(typeVars.size()), HasFix(fix != nullptr), HasDeclContext(true), HasRestriction(false), IsActive(false), IsDisabled(bool(fix)), IsDisabledForPerformance(false), RememberChoice(false), IsFavored(false), IsIsolated(false), - Overload{type}, Locator(locator) { + Overload{type, preparedOverload}, Locator(locator) { std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin()); if (fix) *getTrailingObjects() = fix; @@ -893,10 +895,22 @@ Constraint *Constraint::createValueWitness( } Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type, - OverloadChoice choice, + OverloadChoice choice, DeclContext *useDC, ConstraintFix *fix, ConstraintLocator *locator) { + // FIXME: Transitional hack. + bool enablePreparedOverloads = false; + + PreparedOverload *preparedOverload = nullptr; + + // Prepare the overload. + if (enablePreparedOverloads) { + if (choice.canBePrepared()) { + preparedOverload = cs.prepareOverload(locator, choice, useDC); + } + } + // Collect type variables. SmallPtrSet typeVars; if (type->hasTypeVariable()) @@ -912,7 +926,8 @@ Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type, 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); + return new (mem) Constraint(type, choice, preparedOverload, useDC, + fix, locator, typeVars); } Constraint *Constraint::createRestricted(ConstraintSystem &cs, diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 2bad1f765ec3e..96536eee7c545 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -2499,7 +2499,7 @@ void ConstraintSystem::recordResolvedOverload(ConstraintLocator *locator, void ConstraintSystem::replayChanges( ConstraintLocator *locator, - const PreparedOverload *preparedOverload) { + PreparedOverload *preparedOverload) { for (auto change : preparedOverload->getChanges()) { switch (change.Kind) { case PreparedOverload::Change::AddedTypeVariable: @@ -2581,10 +2581,9 @@ ConstraintSystem::prepareOverloadImpl(ConstraintLocator *locator, } } -const PreparedOverload * -ConstraintSystem::prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC) { +PreparedOverload *ConstraintSystem::prepareOverload(ConstraintLocator *locator, + OverloadChoice choice, + DeclContext *useDC) { ASSERT(!PreparingOverload); PreparingOverload = true; @@ -2602,7 +2601,8 @@ ConstraintSystem::prepareOverload(ConstraintLocator *locator, void ConstraintSystem::resolveOverload(ConstraintLocator *locator, Type boundType, OverloadChoice choice, - DeclContext *useDC) { + DeclContext *useDC, + PreparedOverload *preparedOverload) { // Determine the type to which we'll bind the overload set's type. Type openedType; Type adjustedOpenedType; @@ -2617,11 +2617,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { - // FIXME: Transitional hack - bool enablePreparedOverloads = true; - - if (enablePreparedOverloads) { - auto *preparedOverload = prepareOverload(locator, choice, useDC); + if (preparedOverload) { replayChanges(locator, preparedOverload); openedType = preparedOverload->getOpenedType();