Skip to content

Commit fe26cba

Browse files
committed
[Sema] Remove separate closure type-checking logic
`participatesInInference` is now always true for a non-empty body, remove it along with the separate type-checking logic such that empty bodies are type-checked together with the context.
1 parent d8ebabb commit fe26cba

File tree

13 files changed

+27
-118
lines changed

13 files changed

+27
-118
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class AnyFunctionRef {
130130
auto *ACE = TheFunction.get<AbstractClosureExpr *>();
131131
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
132132
CE->setBody(stmt);
133-
CE->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
133+
CE->setBodyState(ClosureExpr::BodyState::Parsed);
134134
return;
135135
}
136136

@@ -146,7 +146,7 @@ class AnyFunctionRef {
146146
auto *ACE = TheFunction.get<AbstractClosureExpr *>();
147147
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
148148
CE->setBody(stmt);
149-
CE->setBodyState(ClosureExpr::BodyState::TypeCheckedWithSignature);
149+
CE->setBodyState(ClosureExpr::BodyState::TypeChecked);
150150
return;
151151
}
152152

include/swift/AST/Expr.h

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4080,20 +4080,11 @@ class ClosureExpr : public AbstractClosureExpr {
40804080

40814081
public:
40824082
enum class BodyState {
4083-
/// The body was parsed, but not ready for type checking because
4084-
/// the closure parameters haven't been type checked.
4083+
/// The body was parsed.
40854084
Parsed,
40864085

4087-
/// The type of the closure itself was type checked. But the body has not
4088-
/// been type checked yet.
4089-
ReadyForTypeChecking,
4090-
4091-
/// The body was typechecked with the enclosing closure.
4092-
/// i.e. single expression closure or result builder closure.
4093-
TypeCheckedWithSignature,
4094-
4095-
/// The body was type checked separately from the enclosing closure.
4096-
SeparatelyTypeChecked,
4086+
/// The body was type-checked.
4087+
TypeChecked,
40974088
};
40984089

40994090
private:
@@ -4331,13 +4322,6 @@ class ClosureExpr : public AbstractClosureExpr {
43314322
ExplicitResultTypeAndBodyState.setInt(v);
43324323
}
43334324

4334-
/// Whether this closure's body is/was type checked separately from its
4335-
/// enclosing expression.
4336-
bool isSeparatelyTypeChecked() const {
4337-
return getBodyState() == BodyState::SeparatelyTypeChecked ||
4338-
getBodyState() == BodyState::ReadyForTypeChecking;
4339-
}
4340-
43414325
static bool classof(const Expr *E) {
43424326
return E->getKind() == ExprKind::Closure;
43434327
}

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5687,11 +5687,6 @@ class ConstraintSystem {
56875687
/// imported from C/ObjectiveC.
56885688
bool isArgumentOfImportedDecl(ConstraintLocatorBuilder locator);
56895689

5690-
/// Check whether given closure should participate in inference e.g.
5691-
/// if it's a single-expression closure - it always does, but
5692-
/// multi-statement closures require special flags.
5693-
bool participatesInInference(ClosureExpr *closure) const;
5694-
56955690
/// Visit each subexpression that will be part of the constraint system
56965691
/// of the given expression, including those in closure bodies that will be
56975692
/// part of the constraint system.

lib/Sema/CSApply.cpp

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8844,28 +8844,21 @@ namespace {
88448844
// Note that in this mode `ClosuresToTypeCheck` acts
88458845
// as a stack because multi-statement closures could
88468846
// have other multi-statement closures in the body.
8847-
if (cs.participatesInInference(closure)) {
8848-
hadError |= cs.applySolutionToBody(
8849-
solution, closure, Rewriter.dc,
8850-
[&](SyntacticElementTarget target) {
8851-
auto resultTarget = rewriteTarget(target);
8852-
if (resultTarget) {
8853-
if (auto expr = resultTarget->getAsExpr())
8854-
solution.setExprTypes(expr);
8855-
}
8856-
8857-
return resultTarget;
8858-
});
8847+
hadError |= cs.applySolutionToBody(
8848+
solution, closure, Rewriter.dc, [&](SyntacticElementTarget target) {
8849+
auto resultTarget = rewriteTarget(target);
8850+
if (resultTarget) {
8851+
if (auto expr = resultTarget->getAsExpr())
8852+
solution.setExprTypes(expr);
8853+
}
88598854

8860-
if (!hadError) {
8861-
TypeChecker::checkClosureAttributes(closure);
8862-
TypeChecker::checkParameterList(closure->getParameters(), closure);
8863-
}
8855+
return resultTarget;
8856+
});
88648857

8865-
continue;
8858+
if (!hadError) {
8859+
TypeChecker::checkClosureAttributes(closure);
8860+
TypeChecker::checkParameterList(closure->getParameters(), closure);
88668861
}
8867-
8868-
hadError |= TypeChecker::typeCheckClosureBody(closure);
88698862
}
88708863

88718864
return hadError;

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,10 +2540,7 @@ namespace {
25402540
// If this is a multi-statement closure, let's mark result
25412541
// as potential hole right away.
25422542
return Type(CS.createTypeVariable(
2543-
resultLocator,
2544-
(!CS.participatesInInference(closure) || allowResultBindToHole)
2545-
? TVO_CanBindToHole
2546-
: 0));
2543+
resultLocator, allowResultBindToHole ? TVO_CanBindToHole : 0));
25472544
}();
25482545

25492546
// Determine the isolation of the closure.

lib/Sema/CSSyntacticElement.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,18 +1171,6 @@ class SyntacticElementConstraintGenerator
11711171
for (const auto &capture : captureList->getCaptureList())
11721172
visitPatternBinding(capture.PBD, elements);
11731173
}
1174-
1175-
// Let's not walk into the body if empty or multi-statement closure
1176-
// doesn't participate in inference.
1177-
if (!cs.participatesInInference(closure)) {
1178-
// Although the body doesn't participate in inference we still
1179-
// want to type-check captures to make sure that the context
1180-
// is valid.
1181-
if (captureList)
1182-
createConjunction(elements, locator);
1183-
1184-
return;
1185-
}
11861174
}
11871175

11881176
if (isChildOf(StmtKind::Case)) {
@@ -2598,7 +2586,6 @@ SolutionApplicationToFunctionResult ConstraintSystem::applySolution(
25982586

25992587
// Otherwise, we need to delay type checking of the closure until later.
26002588
solution.setExprTypes(closure);
2601-
closure->setBodyState(ClosureExpr::BodyState::ReadyForTypeChecking);
26022589
return SolutionApplicationToFunctionResult::Delay;
26032590
}
26042591

lib/Sema/ConstraintSystem.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7432,16 +7432,6 @@ bool ConstraintSystem::isArgumentGenericFunction(Type argType, Expr *argExpr) {
74327432
return false;
74337433
}
74347434

7435-
bool ConstraintSystem::participatesInInference(ClosureExpr *closure) const {
7436-
if (getAppliedResultBuilderTransform(closure))
7437-
return true;
7438-
7439-
if (closure->hasEmptyBody())
7440-
return false;
7441-
7442-
return true;
7443-
}
7444-
74457435
ProtocolConformanceRef
74467436
ConstraintSystem::lookupConformance(Type type, ProtocolDecl *protocol) {
74477437
auto cacheKey = std::make_pair(type.getPointer(), protocol);

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1822,11 +1822,8 @@ static void findAvailabilityFixItNodes(
18221822
InnermostAncestorFinder::MatchPredicate IsGuardable =
18231823
[](ASTNode Node, ASTWalker::ParentTy Parent) {
18241824
if (Expr *ParentExpr = Parent.getAsExpr()) {
1825-
auto *ParentClosure = dyn_cast<ClosureExpr>(ParentExpr);
1826-
if (!ParentClosure ||
1827-
ParentClosure->isSeparatelyTypeChecked()) {
1825+
if (!isa<ClosureExpr>(ParentExpr))
18281826
return false;
1829-
}
18301827
} else if (auto *ParentStmt = Parent.getAsStmt()) {
18311828
if (!isa<BraceStmt>(ParentStmt)) {
18321829
return false;

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,10 +2365,6 @@ void ConstraintSystem::forEachExpr(
23652365
if (!NewE)
23662366
return Action::Stop();
23672367

2368-
if (auto closure = dyn_cast<ClosureExpr>(E)) {
2369-
if (!CS.participatesInInference(closure))
2370-
return Action::SkipNode(NewE);
2371-
}
23722368
return Action::Continue(NewE);
23732369
}
23742370

lib/Sema/TypeCheckStmt.cpp

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,7 @@ namespace {
104104

105105
if (auto CE = dyn_cast<ClosureExpr>(E)) {
106106
CE->setParent(ParentDC);
107-
108-
// If the closure was type checked within its enclosing context,
109-
// we need to walk into it. Otherwise, it'll have been separately
110-
// type-checked.
111-
if (!CE->isSeparatelyTypeChecked())
112-
CE->getBody()->walk(ContextualizeClosuresAndMacros(CE));
107+
CE->getBody()->walk(ContextualizeClosuresAndMacros(CE));
113108

114109
TypeChecker::computeCaptures(CE);
115110
return Action::SkipNode(E);
@@ -283,18 +278,14 @@ namespace {
283278
if(CE->getRawDiscriminator() == ClosureExpr::InvalidDiscriminator)
284279
CE->setDiscriminator(NextClosureDiscriminator++);
285280

286-
// If the closure was type checked within its enclosing context,
287-
// we need to walk into it with a new sequence.
288-
// Otherwise, it'll have been separately type-checked.
289-
if (!CE->isSeparatelyTypeChecked()) {
290-
SetLocalDiscriminators innerVisitor;
291-
if (auto params = CE->getParameters()) {
292-
for (auto *param : *params) {
293-
innerVisitor.setLocalDiscriminator(param);
294-
}
281+
// We need to walk into closure bodies with a new sequence.
282+
SetLocalDiscriminators innerVisitor;
283+
if (auto params = CE->getParameters()) {
284+
for (auto *param : *params) {
285+
innerVisitor.setLocalDiscriminator(param);
295286
}
296-
CE->getBody()->walk(innerVisitor);
297287
}
288+
CE->getBody()->walk(innerVisitor);
298289

299290
return Action::SkipNode(E);
300291
}
@@ -2978,25 +2969,6 @@ TypeCheckFunctionBodyRequest::evaluate(Evaluator &eval,
29782969
return hadError ? errorBody() : body;
29792970
}
29802971

2981-
bool TypeChecker::typeCheckClosureBody(ClosureExpr *closure) {
2982-
TypeChecker::checkClosureAttributes(closure);
2983-
TypeChecker::checkParameterList(closure->getParameters(), closure);
2984-
2985-
BraceStmt *body = closure->getBody();
2986-
2987-
std::optional<FunctionBodyTimer> timer;
2988-
const auto &tyOpts = closure->getASTContext().TypeCheckerOpts;
2989-
if (tyOpts.DebugTimeFunctionBodies || tyOpts.WarnLongFunctionBodies)
2990-
timer.emplace(closure);
2991-
2992-
bool HadError = StmtChecker(closure).typeCheckBody(body);
2993-
if (body) {
2994-
closure->setBody(body);
2995-
}
2996-
closure->setBodyState(ClosureExpr::BodyState::SeparatelyTypeChecked);
2997-
return HadError;
2998-
}
2999-
30002972
bool TypeChecker::typeCheckTapBody(TapExpr *expr, DeclContext *DC) {
30012973
// We intentionally use typeCheckStmt instead of typeCheckBody here
30022974
// because we want to contextualize TapExprs with the body they're in.

lib/Sema/TypeChecker.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,8 +463,6 @@ std::optional<BraceStmt *> applyResultBuilderBodyTransform(FuncDecl *func,
463463
/// Find the return statements within the body of the given function.
464464
std::vector<ReturnStmt *> findReturnStatements(AnyFunctionRef fn);
465465

466-
bool typeCheckClosureBody(ClosureExpr *closure);
467-
468466
bool typeCheckTapBody(TapExpr *expr, DeclContext *DC);
469467

470468
Type typeCheckParameterDefault(Expr *&defaultValue, DeclContext *DC,

unittests/Sema/ConstraintSimplificationTests.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ TEST_F(SemaTest, TestClosureInferenceFromOptionalContext) {
109109
cs.setClosureType(closure, defaultTy);
110110

111111
auto *closureTy = cs.createTypeVariable(closureLoc, /*options=*/0);
112+
cs.setType(closure, closureTy);
112113

113114
cs.addUnsolvedConstraint(Constraint::create(
114115
cs, ConstraintKind::FallbackType, closureTy, defaultTy,

validation-test/Sema/SwiftUI/rdar88256059.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ struct MyView: View {
1010
var body: some View {
1111
Table(self.data) {
1212
// expected-error@-1 {{expected expression in result builder 'TableColumnBuilder'}} {{23-23=<#result#>}}
13-
// expected-error@-2 {{cannot infer return type of empty closure}} {{23-23=<#result#>}}
1413
}
1514
}
1615
}

0 commit comments

Comments
 (0)