Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3598347
Sema: Tweak VarDecl concurrency adjustment in getTypeOfReference() to…
slavapestov Sep 15, 2025
4c1ce3a
Sema: Split off getTypeOfReferenceImpl() from getTypeOfReference()
slavapestov Sep 15, 2025
c93496d
Sema: Remove replacements parameter from getMemberReferenceTypeFromOp…
slavapestov Sep 15, 2025
1f03462
Sema: Pass baseObjTy instead of baseRValueTy to adjustFunctionTypeFor…
slavapestov Sep 15, 2025
cb56b6f
Sema: Remove duplicate logic for throwing accessor witness matching
slavapestov Sep 16, 2025
fffbc32
Sema: Split off getTypeOfMemberReferenceImpl() from getTypeOfMemberRe…
slavapestov Sep 16, 2025
4f5c7f9
Sema: Refactor getTypeOf{Member,}Reference() to take the OverloadChoice
slavapestov Sep 16, 2025
127f012
Sema: Don't need to return new baseObjTy from getTypeOfMemberReferenc…
slavapestov Sep 16, 2025
d25fbfd
Sema: Simplify getConcreteReplacementForProtocolSelfType()
slavapestov Sep 17, 2025
9ffab77
Sema: Remove replacementsPtr parameter from getTypeOfMemberReference()
slavapestov Sep 16, 2025
1ea7382
Sema: Rename getTypeOf{Member,}ReferenceImpl() to Pre() and factor ou…
slavapestov Sep 16, 2025
00972e0
Sema: Add -solver-{enable,disable}-prepared-overloads frontend flags
slavapestov Sep 17, 2025
5a9e50f
Sema: Get prepared overloads working again with the Pre()/Post() split
slavapestov Sep 17, 2025
9a04b0a
Sema: Replace calls to OverloadChoice constructor with two overloads …
slavapestov Sep 17, 2025
74e92ff
Sema: Sink ModuleDecl handling back down into getTypeOfMemberReferenc…
slavapestov Sep 17, 2025
5067221
Sema: Clean up ConstraintSystem::resolveOverload() a bit
slavapestov Sep 17, 2025
00fce05
Sema: Remove unused variable
slavapestov Sep 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,9 @@ namespace swift {

/// Disable the component splitter phase of the expression type checker.
bool SolverDisableSplitter = false;

/// Enable the experimental "prepared overloads" optimization.
bool SolverEnablePreparedOverloads = false;
};

/// Options for controlling the behavior of the Clang importer.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,12 @@ def solver_scope_threshold_EQ : Joined<["-"], "solver-scope-threshold=">,
def solver_trail_threshold_EQ : Joined<["-"], "solver-trail-threshold=">,
HelpText<"Expression type checking trail change limit">;

def solver_disable_prepared_overloads : Flag<["-"], "solver-disable-prepared-overloads">,
HelpText<"Disable experimental prepared overloads optimization">;

def solver_enable_prepared_overloads : Flag<["-"], "solver-enable-prepared-overloads">,
HelpText<"Enable experimental prepared overloads optimization">;

def solver_disable_splitter : Flag<["-"], "solver-disable-splitter">,
HelpText<"Disable the component splitter phase of expression type checking">;

Expand Down
67 changes: 39 additions & 28 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -3795,7 +3795,7 @@ 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,
resolveOverload(choice, useDC, locator, boundTy,
/*preparedOverload=*/nullptr);
}

Expand Down Expand Up @@ -4437,24 +4437,18 @@ class ConstraintSystem {
FunctionType *adjustFunctionTypeForConcurrency(
FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc,
unsigned numApplies, bool isMainDispatchQueue,
ArrayRef<OpenedType> replacements, ConstraintLocatorBuilder locator,
PreparedOverloadBuilder *preparedOverload);
bool openGlobalActorType, ConstraintLocatorBuilder locator);

/// Retrieve the type of a reference to the given value declaration.
///
/// For references to polymorphic function types, this routine "opens up"
/// the type by replacing each instance of an archetype with a fresh type
/// variable.
///
/// \param decl The declarations whose type is being computed.
///
/// \returns a description of the type of this declaration reference.
DeclReferenceType getTypeOfReference(
ValueDecl *decl,
FunctionRefInfo functionRefInfo,
ConstraintLocatorBuilder locator,
DeclContext *useDC,
PreparedOverloadBuilder *preparedOverload);
OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator,
PreparedOverloadBuilder *preparedOverload);

/// Retrieve the type of a reference to the given value declaration,
/// as a member with a base of the given type.
Expand All @@ -4463,15 +4457,10 @@ class ConstraintSystem {
/// this routine "opens up" the type by replacing each instance of a generic
/// parameter with a fresh type variable.
///
/// \param isDynamicLookup Indicates that this declaration was found via
/// dynamic lookup.
///
/// \returns a description of the type of this declaration reference.
DeclReferenceType getTypeOfMemberReference(
Type baseTy, ValueDecl *decl, DeclContext *useDC, bool isDynamicLookup,
FunctionRefInfo functionRefInfo, ConstraintLocator *locator,
SmallVectorImpl<OpenedType> *replacements = nullptr,
PreparedOverloadBuilder *preparedOverload = nullptr);
OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator,
PreparedOverloadBuilder *preparedOverload);

/// Retrieve a list of generic parameter types solver has "opened" (replaced
/// with a type variable) at the given location.
Expand All @@ -4483,7 +4472,25 @@ class ConstraintSystem {
}

private:
DeclReferenceType getTypeOfMemberTypeReference(
/// \returns The opened type and the thrown error type.
std::pair<Type, Type> getTypeOfReferencePre(
OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator,
PreparedOverloadBuilder *preparedOverload);

DeclReferenceType getTypeOfReferencePost(
OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator,
Type openedType, Type thrownErrorType);

/// \returns the opened type and the thrown error type.
std::pair<Type, Type> getTypeOfMemberReferencePre(
OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator,
PreparedOverloadBuilder *preparedOverload);

DeclReferenceType getTypeOfMemberReferencePost(
OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator,
Type openedType, Type thrownErrorType);

Type getTypeOfMemberTypeReference(
Type baseObjTy, TypeDecl *typeDecl, ConstraintLocator *locator,
PreparedOverloadBuilder *preparedOverload);

Expand Down Expand Up @@ -4513,8 +4520,7 @@ class ConstraintSystem {
/// determine the reference type of the member reference.
Type getMemberReferenceTypeFromOpenedType(
Type type, Type baseObjTy, ValueDecl *value,
ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup,
ArrayRef<OpenedType> replacements);
ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup);

/// Add the constraints needed to bind an overload's type variable.
void bindOverloadType(const SelectedOverload &overload, Type boundType,
Expand Down Expand Up @@ -4918,26 +4924,31 @@ class ConstraintSystem {
SelectedOverload choice);

/// Build and allocate a prepared overload in the solver arena.
PreparedOverload *prepareOverload(ConstraintLocator *locator,
OverloadChoice choice,
DeclContext *useDC);
PreparedOverload *prepareOverload(OverloadChoice choice,
DeclContext *useDC,
ConstraintLocator *locator);

/// 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
prepareOverloadImpl(ConstraintLocator *locator,
OverloadChoice choice,
///
/// Returns a pair consisting of the opened type, and the thrown error type.
///
/// FIXME: As a transitional mechanism, if preparedOverload is nullptr, this
/// immediately performs all operations.
std::pair<Type, Type>
prepareOverloadImpl(OverloadChoice choice,
DeclContext *useDC,
ConstraintLocator *locator,
PreparedOverloadBuilder *preparedOverload);

void replayChanges(
ConstraintLocator *locator,
PreparedOverload *preparedOverload);

/// Resolve the given overload set to the given choice.
void resolveOverload(ConstraintLocator *locator, Type boundType,
OverloadChoice choice, DeclContext *useDC,
void resolveOverload(OverloadChoice choice, DeclContext *useDC,
ConstraintLocator *locator, Type boundType,
PreparedOverload *preparedOverload);

/// Simplify a type, by replacing type variables with either their
Expand Down
23 changes: 19 additions & 4 deletions include/swift/Sema/OverloadChoice.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,19 @@ class OverloadChoice {
/// FIXME: This needs three bits. Can we pack them somewhere?
FunctionRefInfo TheFunctionRefInfo = FunctionRefInfo::unappliedBaseName();

public:
OverloadChoice() : BaseAndDeclKind(nullptr, 0), DeclOrKind() {}

OverloadChoice(Type base, ValueDecl *value,
FunctionRefInfo functionRefInfo)
: BaseAndDeclKind(base, 0),
TheFunctionRefInfo(functionRefInfo) {
assert(!base || !base->hasTypeParameter());
assert((reinterpret_cast<uintptr_t>(value) & (uintptr_t)0x03) == 0 &&
"Badly aligned decl");

DeclOrKind = value;
}

public:
OverloadChoice() : BaseAndDeclKind(nullptr, 0), DeclOrKind() {}

OverloadChoice(Type base, OverloadChoiceKind kind)
: BaseAndDeclKind(base, 0), DeclOrKind(uint32_t(kind)) {
assert(base && "Must have a base type for overload choice");
Expand All @@ -162,6 +161,22 @@ class OverloadChoice {
BaseAndDeclKind.getInt() == 0 && DeclOrKind.isNull();
}

/// Retrieve an overload choice for a declaration that was found via
/// unqualified lookup.
static OverloadChoice getDecl(ValueDecl *value,
FunctionRefInfo functionRefInfo) {
return OverloadChoice(Type(), value, functionRefInfo);
}


/// Retrieve an overload choice for a declaration that was found via
/// qualified lookup.
static OverloadChoice getDecl(Type base, ValueDecl *value,
FunctionRefInfo functionRefInfo) {
ASSERT(!base->hasTypeParameter());
return OverloadChoice(base, value, functionRefInfo);
}

/// Retrieve an overload choice for a declaration that was found via
/// dynamic lookup.
static OverloadChoice getDeclViaDynamic(Type base, ValueDecl *value,
Expand Down
27 changes: 9 additions & 18 deletions include/swift/Sema/PreparedOverload.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,38 +144,29 @@ class PreparedOverload final :
using Change = PreparedOverloadChange;

private:
Type OpenedType;
Type ThrownErrorType;
size_t Count;
DeclReferenceType DeclType;

size_t numTrailingObjects(OverloadToken<Change>) const {
return Count;
}

public:
PreparedOverload(const DeclReferenceType &declType, ArrayRef<Change> changes)
: Count(changes.size()), DeclType(declType) {
PreparedOverload(Type openedType, Type thrownErrorType,
ArrayRef<Change> changes)
: OpenedType(openedType), ThrownErrorType(thrownErrorType),
Count(changes.size()) {
std::uninitialized_copy(changes.begin(), changes.end(),
getTrailingObjects<Change>());
}

Type getOpenedType() const {
return DeclType.openedType;
return 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;
Type getThrownErrorType() const {
return ThrownErrorType;
}

ArrayRef<Change> getChanges() const {
Expand Down
4 changes: 4 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2000,6 +2000,10 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args,
if (Args.getLastArg(OPT_solver_disable_splitter))
Opts.SolverDisableSplitter = true;

if (Args.hasArg(OPT_solver_enable_prepared_overloads) ||
Args.hasArg(OPT_solver_disable_prepared_overloads))
Opts.SolverEnablePreparedOverloads = Args.hasArg(OPT_solver_enable_prepared_overloads);

if (FrontendOpts.RequestedAction == FrontendOptions::ActionType::Immediate)
Opts.DeferToRuntime = true;

Expand Down
15 changes: 8 additions & 7 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2457,9 +2457,10 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
const auto &declRef = SE->getDecl();
if (auto *subscript =
dyn_cast_or_null<SubscriptDecl>(declRef.getDecl())) {
if (isImmutable(subscript))
return {expr, OverloadChoice(getType(SE->getBase()), subscript,
FunctionRefInfo::doubleBaseNameApply())};
if (isImmutable(subscript)) {
return {expr, OverloadChoice::getDecl(getType(SE->getBase()), subscript,
FunctionRefInfo::doubleBaseNameApply())};
}
}
}

Expand Down Expand Up @@ -2514,8 +2515,8 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
// If the member isn't settable, then it is the problem: return it.
if (auto member = dyn_cast<AbstractStorageDecl>(MRE->getMember().getDecl()))
if (isImmutable(member))
return {expr, OverloadChoice(getType(MRE->getBase()), member,
FunctionRefInfo::singleBaseNameApply())};
return {expr, OverloadChoice::getDecl(getType(MRE->getBase()), member,
FunctionRefInfo::singleBaseNameApply())};

// If we weren't able to resolve a member or if it is mutable, then the
// problem must be with the base, recurse.
Expand All @@ -2535,8 +2536,8 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const {
}

if (auto *DRE = dyn_cast<DeclRefExpr>(expr))
return {expr, OverloadChoice(Type(), DRE->getDecl(),
FunctionRefInfo::unappliedBaseName())};
return {expr, OverloadChoice::getDecl(DRE->getDecl(),
FunctionRefInfo::unappliedBaseName())};

// Look through x!
if (auto *FVE = dyn_cast<ForceValueExpr>(expr))
Expand Down
18 changes: 9 additions & 9 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ namespace {
options);
SmallVector<OverloadChoice, 4> outerChoices;
for (auto decl : outerAlternatives) {
outerChoices.push_back(OverloadChoice(Type(), decl, functionRefInfo));
outerChoices.push_back(OverloadChoice::getDecl(decl, functionRefInfo));
}
CS.addValueMemberConstraint(
baseTy, name, tv, CurDC, functionRefInfo, outerChoices,
Expand All @@ -1044,8 +1044,8 @@ namespace {
auto tv = CS.createTypeVariable(memberLocator,
TVO_CanBindToLValue | TVO_CanBindToNoEscape);

OverloadChoice choice =
OverloadChoice(CS.getType(base), decl, functionRefInfo);
auto choice =
OverloadChoice::getDecl(CS.getType(base), decl, functionRefInfo);

auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member);
CS.addBindOverloadConstraint(tv, choice, locator, CurDC);
Expand Down Expand Up @@ -1162,7 +1162,7 @@ namespace {
// a known subscript here. This might be cleaner if we split off a new
// UnresolvedSubscriptExpr from SubscriptExpr.
if (auto decl = declOrNull) {
OverloadChoice choice = OverloadChoice(
auto choice = OverloadChoice::getDecl(
baseTy, decl, FunctionRefInfo::doubleBaseNameApply());
CS.addBindOverloadConstraint(memberTy, choice, memberLocator,
CurDC);
Expand Down Expand Up @@ -1657,8 +1657,8 @@ namespace {
// resolve it. This records the overload for use later.
auto tv = CS.createTypeVariable(locator, options);

OverloadChoice choice =
OverloadChoice(Type(), E->getDecl(), E->getFunctionRefInfo());
auto choice =
OverloadChoice::getDecl(E->getDecl(), E->getFunctionRefInfo());
CS.addBindOverloadConstraint(tv, choice, locator, CurDC);
return tv;
}
Expand Down Expand Up @@ -1775,8 +1775,8 @@ namespace {
if (decls[i]->isInvalid())
continue;

OverloadChoice choice =
OverloadChoice(Type(), decls[i], expr->getFunctionRefInfo());
auto choice =
OverloadChoice::getDecl(decls[i], expr->getFunctionRefInfo());
choices.push_back(choice);
}

Expand Down Expand Up @@ -4110,7 +4110,7 @@ namespace {
// logic.
if (result->isInvalid())
continue;
OverloadChoice choice = OverloadChoice(Type(), result, functionRefInfo);
auto choice = OverloadChoice::getDecl(result, functionRefInfo);
choices.push_back(choice);
}

Expand Down
Loading