Skip to content

Commit f15fae4

Browse files
authored
Merge pull request #84822 from hamishknight/just-a-phase
[CS] Remove `ConstraintSystemPhase`
2 parents 8397a7a + 0a1905a commit f15fae4

File tree

9 files changed

+76
-105
lines changed

9 files changed

+76
-105
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,11 +2137,6 @@ class SyntacticElementTargetRewriter {
21372137
virtual ~SyntacticElementTargetRewriter() = default;
21382138
};
21392139

2140-
enum class ConstraintSystemPhase {
2141-
ConstraintGeneration,
2142-
Solving
2143-
};
2144-
21452140
/// Retrieve the closure type from the constraint system.
21462141
struct GetClosureType {
21472142
ConstraintSystem &cs;
@@ -2203,9 +2198,6 @@ class ConstraintSystem {
22032198
/// Do not set directly, call \c recordFailedConstraint instead.
22042199
Constraint *failedConstraint = nullptr;
22052200

2206-
/// Current phase of the constraint system lifetime.
2207-
ConstraintSystemPhase Phase = ConstraintSystemPhase::ConstraintGeneration;
2208-
22092201
/// The set of expressions for which we have generated constraints.
22102202
llvm::SetVector<Expr *> InputExprs;
22112203

@@ -2683,30 +2675,6 @@ class ConstraintSystem {
26832675
/// \c nullptr if no constraint has failed.
26842676
Constraint *getFailedConstraint() const { return failedConstraint; }
26852677

2686-
ConstraintSystemPhase getPhase() const { return Phase; }
2687-
2688-
/// Move constraint system to a new phase of its lifetime.
2689-
void setPhase(ConstraintSystemPhase newPhase) {
2690-
if (Phase == newPhase)
2691-
return;
2692-
2693-
#ifndef NDEBUG
2694-
switch (Phase) {
2695-
case ConstraintSystemPhase::ConstraintGeneration:
2696-
assert(newPhase == ConstraintSystemPhase::Solving);
2697-
break;
2698-
2699-
case ConstraintSystemPhase::Solving:
2700-
// We can come back to constraint generation phase while
2701-
// processing result builder body.
2702-
assert(newPhase == ConstraintSystemPhase::ConstraintGeneration);
2703-
break;
2704-
}
2705-
#endif
2706-
2707-
Phase = newPhase;
2708-
}
2709-
27102678
/// Check whether constraint system is in valid state e.g.
27112679
/// has left-over active/inactive constraints which should
27122680
/// have been simplified.
@@ -3914,7 +3882,7 @@ class ConstraintSystem {
39143882
// Add this constraint to the constraint graph.
39153883
CG.addConstraint(constraint);
39163884

3917-
if (isDebugMode() && getPhase() == ConstraintSystemPhase::Solving) {
3885+
if (isDebugMode() && solverState) {
39183886
auto &log = llvm::errs();
39193887
log.indent(solverState->getCurrentIndent() + 4) << "(added constraint: ";
39203888
constraint->print(log, &getASTContext().SourceMgr,
@@ -3935,7 +3903,7 @@ class ConstraintSystem {
39353903
if (solverState)
39363904
recordChange(SolverTrail::Change::RetiredConstraint(where, constraint));
39373905

3938-
if (isDebugMode() && getPhase() == ConstraintSystemPhase::Solving) {
3906+
if (isDebugMode() && solverState) {
39393907
auto &log = llvm::errs();
39403908
log.indent(solverState->getCurrentIndent() + 4)
39413909
<< "(removed constraint: ";

lib/Sema/CSBindings.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,9 +1828,7 @@ PotentialBindings::inferFromRelational(ConstraintSystem &CS,
18281828
// Since inference now happens during constraint generation,
18291829
// this hack should be allowed in both `Solving`
18301830
// (during non-diagnostic mode) and `ConstraintGeneration` phases.
1831-
if (isGenericParameter(TypeVar) &&
1832-
(!CS.shouldAttemptFixes() ||
1833-
CS.getPhase() == ConstraintSystemPhase::ConstraintGeneration)) {
1831+
if (isGenericParameter(TypeVar) && !CS.inSalvageMode()) {
18341832
type = fnTy->withExtInfo(fnTy->getExtInfo().withNoEscape(false));
18351833
}
18361834
}

lib/Sema/CSGen.cpp

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,6 @@ namespace {
944944
class ConstraintGenerator : public ExprVisitor<ConstraintGenerator, Type> {
945945
ConstraintSystem &CS;
946946
DeclContext *CurDC;
947-
ConstraintSystemPhase CurrPhase;
948947

949948
/// A map from each UnresolvedMemberExpr to the respective (implicit) base
950949
/// found during our walk.
@@ -1158,6 +1157,33 @@ namespace {
11581157
if (addedTypeVars)
11591158
addedTypeVars->push_back(memberTy);
11601159

1160+
SmallVector<AnyFunctionType::Param, 8> params;
1161+
getMatchingParams(argList, params);
1162+
1163+
// Add the constraint that the index expression's type be convertible
1164+
// to the input type of the subscript operator.
1165+
auto addApplicableFn = [&]() {
1166+
CS.addApplicationConstraint(
1167+
FunctionType::get(params, outputTy), memberTy,
1168+
/*trailingClosureMatching=*/std::nullopt, CurDC, fnLocator);
1169+
};
1170+
1171+
// If we have a dynamic member base we need to add the applicable function
1172+
// first since solving the member constraint requires the constraint to be
1173+
// available since it may retire it. We can't yet do this in the general
1174+
// case since the simplifying of the applicable fn in CSGen is currently
1175+
// load-bearing for existential opening.
1176+
// FIXME: Once existential opening is no longer sensitive to solving
1177+
// order, we ought to be able to just always record the applicable fn as
1178+
// an unsolved constraint before the member.
1179+
auto hasDynamicMemberLookup = CS.simplifyType(baseTy)
1180+
->getRValueType()
1181+
->getMetatypeInstanceType()
1182+
->eraseDynamicSelfType()
1183+
->hasDynamicMemberLookupAttribute();
1184+
if (hasDynamicMemberLookup)
1185+
addApplicableFn();
1186+
11611187
// FIXME: synthesizeMaterializeForSet() wants to statically dispatch to
11621188
// a known subscript here. This might be cleaner if we split off a new
11631189
// UnresolvedSubscriptExpr from SubscriptExpr.
@@ -1173,14 +1199,10 @@ namespace {
11731199
/*outerAlternatives=*/{}, memberLocator);
11741200
}
11751201

1176-
SmallVector<AnyFunctionType::Param, 8> params;
1177-
getMatchingParams(argList, params);
1178-
1179-
// Add the constraint that the index expression's type be convertible
1180-
// to the input type of the subscript operator.
1181-
CS.addApplicationConstraint(FunctionType::get(params, outputTy), memberTy,
1182-
/*trailingClosureMatching=*/std::nullopt,
1183-
CurDC, fnLocator);
1202+
// If we don't have a dynamic member, we add the application after the
1203+
// member, see the above comment.
1204+
if (!hasDynamicMemberLookup)
1205+
addApplicableFn();
11841206

11851207
if (CS.performanceHacksEnabled()) {
11861208
Type fixedOutputType =
@@ -1250,23 +1272,15 @@ namespace {
12501272

12511273
public:
12521274
ConstraintGenerator(ConstraintSystem &CS, DeclContext *DC)
1253-
: CS(CS), CurDC(DC ? DC : CS.DC), CurrPhase(CS.getPhase()) {
1254-
// Although constraint system is initialized in `constraint
1255-
// generation` phase, we have to set it here manually because e.g.
1256-
// result builders could generate constraints for its body
1257-
// in the middle of the solving.
1258-
CS.setPhase(ConstraintSystemPhase::ConstraintGeneration);
1259-
1275+
: CS(CS), CurDC(DC ? DC : CS.DC) {
12601276
// Pick up the saved stack of pack expansions so we can continue
12611277
// to handle pack element references inside the closure body.
12621278
if (auto *ACE = dyn_cast<AbstractClosureExpr>(CurDC)) {
12631279
OuterExpansions = CS.getCapturedExpansions(ACE);
12641280
}
12651281
}
12661282

1267-
virtual ~ConstraintGenerator() {
1268-
CS.setPhase(CurrPhase);
1269-
}
1283+
virtual ~ConstraintGenerator() = default;
12701284

12711285
ConstraintSystem &getConstraintSystem() const { return CS; }
12721286

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11457,22 +11457,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
1145711457
if (result.actualBaseType)
1145811458
baseTy = result.actualBaseType;
1145911459

11460-
// If only possible choice to refer to member is via keypath
11461-
// dynamic member dispatch, let's delay solving this constraint
11462-
// until constraint generation phase is complete, because
11463-
// subscript dispatch relies on presence of function application.
11464-
if (result.ViableCandidates.size() == 1) {
11465-
auto &choice = result.ViableCandidates.front();
11466-
if (Phase == ConstraintSystemPhase::ConstraintGeneration &&
11467-
choice.isKeyPathDynamicMemberLookup() &&
11468-
member.getBaseName().isSubscript()) {
11469-
// Let's move this constraint to the active
11470-
// list so it could be picked up right after
11471-
// constraint generation is done.
11472-
return formUnsolved(/*activate=*/true);
11473-
}
11474-
}
11475-
1147611460
generateOverloadConstraints(
1147711461
candidates, memberTy, result.ViableCandidates, useDC, locator,
1147811462
result.getFavoredIndex(), /*requiresFix=*/false,
@@ -13948,26 +13932,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyApplicableFnConstraint(
1394813932
if (instance2->isTypeVariableOrMember())
1394913933
return formUnsolved();
1395013934

13951-
auto *argumentsLoc = getConstraintLocator(
13952-
outerLocator.withPathElement(ConstraintLocator::ApplyArgument));
13953-
13954-
auto *argumentList = getArgumentList(argumentsLoc);
13955-
assert(argumentList);
13956-
13957-
// Cannot simplify construction of callable types during constraint
13958-
// generation when trailing closures are present because such calls
13959-
// have special trailing closure matching semantics. It's unclear
13960-
// whether trailing arguments belong to `.init` or implicit
13961-
// `.callAsFunction` in this case.
13962-
//
13963-
// Note that the constraint has to be activate so that solver attempts
13964-
// once constraint generation is done.
13965-
if (getPhase() == ConstraintSystemPhase::ConstraintGeneration &&
13966-
argumentList->hasAnyTrailingClosures() &&
13967-
instance2->isCallAsFunctionType(DC)) {
13968-
return formUnsolved(/*activate=*/true);
13969-
}
13970-
1397113935
// Construct the instance from the input arguments.
1397213936
auto simplified = simplifyConstructionConstraint(
1397313937
instance2, func1, subflags,

lib/Sema/CSSolver.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,8 +1577,6 @@ bool ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions,
15771577
void ConstraintSystem::solveImpl(SmallVectorImpl<Solution> &solutions) {
15781578
assert(solverState);
15791579

1580-
setPhase(ConstraintSystemPhase::Solving);
1581-
15821580
// If constraint system failed while trying to
15831581
// genenerate constraints, let's stop right here.
15841582
if (failedConstraint)
@@ -1798,12 +1796,6 @@ ConstraintSystem::filterDisjunction(
17981796
// constraint, so instead let's keep the disjunction, but disable all
17991797
// unviable choices.
18001798
if (choice->getOverloadChoice().isKeyPathDynamicMemberLookup()) {
1801-
// Early simplification of the "keypath dynamic member lookup" choice
1802-
// is impossible because it requires constraints associated with
1803-
// subscript index expression to be present.
1804-
if (Phase == ConstraintSystemPhase::ConstraintGeneration)
1805-
return SolutionKind::Unsolved;
1806-
18071799
for (auto *currentChoice : disjunction->getNestedConstraints()) {
18081800
if (currentChoice->isDisabled())
18091801
continue;

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,10 +1808,8 @@ struct TypeSimplifier {
18081808
// so the concrete dependent member type is considered a "hole" in
18091809
// order to continue solving.
18101810
auto memberTy = DependentMemberType::get(lookupBaseType, assocType);
1811-
if (CS.shouldAttemptFixes() &&
1812-
CS.getPhase() == ConstraintSystemPhase::Solving) {
1811+
if (CS.inSalvageMode())
18131812
return PlaceholderType::get(CS.getASTContext(), memberTy);
1814-
}
18151813

18161814
return memberTy;
18171815
}

lib/Sema/TypeOfReference.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2483,7 +2483,7 @@ void ConstraintSystem::bindOverloadType(const SelectedOverload &overload,
24832483
return constraint->getKind() == ConstraintKind::ApplicableFunction;
24842484
});
24852485

2486-
assert(constraints.size() == 1);
2486+
ASSERT(constraints.size() == 1);
24872487
auto *applicableFn = constraints.front();
24882488
retireConstraint(applicableFn);
24892489

test/Constraints/keypath_dynamic_member_lookup.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,3 +601,18 @@ struct TestIssue56837 {
601601
_ = value[type: Int8.max]
602602
}
603603
}
604+
605+
@dynamicMemberLookup
606+
class TestDynamicSelf {
607+
struct S {
608+
subscript() -> Int { 0 }
609+
}
610+
func foo() -> Self {
611+
// Make sure we can do dynamic member lookup on a dynamic self.
612+
_ = self[]
613+
return self
614+
}
615+
subscript<T>(dynamicMember dynamicMember: KeyPath<S, T>) -> T {
616+
fatalError()
617+
}
618+
}

test/Constraints/opened_existentials_overload.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
protocol P {}
44

55
func g(_: some P) {}
6-
// expected-note@-1 {{required by global function 'g' where 'some P' = 'any P'}}
6+
// expected-note@-1 2{{required by global function 'g' where 'some P' = 'any P'}}
77

88
// rdar://problem/160389221
99
func good(_ x: Array<any P>) {
@@ -28,3 +28,25 @@ func bad(_ x: Array<any P>) {
2828
// expected-error@-1 {{type 'any P' cannot conform to 'P'}}
2929
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
3030
}
31+
32+
func testSubscript() {
33+
struct S1<T> {
34+
subscript() -> T { fatalError() }
35+
}
36+
func foo(_ xs: S1<any P>) {
37+
g(xs[])
38+
}
39+
40+
struct S2<T> {
41+
subscript() -> Int { fatalError() }
42+
subscript() -> T { fatalError() }
43+
}
44+
func foo(_ xs: S2<any P>) {
45+
// FIXME: This should work, if you fix this you can also remove the
46+
// dynamic member lookup hack in `addSubscriptConstraints`, we should always
47+
// just add the applicable fn as an unsolved constraint before the member.
48+
g(xs[])
49+
// expected-error@-1 {{type 'any P' cannot conform to 'P'}}
50+
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
51+
}
52+
}

0 commit comments

Comments
 (0)