Skip to content

Commit 3f916f5

Browse files
authored
Merge pull request #76297 from hamishknight/together-forever
[Sema] Remove separate closure type-checking logic
2 parents 5eb3062 + ee0e408 commit 3f916f5

17 files changed

+124
-119
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/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,11 @@ NOTE(candidate_with_extraneous_args,none,
16051605
"candidate %0 has %1 parameter%s1, but context %2 has %3",
16061606
(Type, unsigned, Type, unsigned))
16071607

1608+
ERROR(result_builder_missing_element,none,
1609+
"expected expression in result builder %0", (DeclName))
1610+
ERROR(result_builder_missing_element_of_type,none,
1611+
"expected expression of type %0 in result builder %1", (Type, DeclName))
1612+
16081613
ERROR(no_accessible_initializers,none,
16091614
"%0 cannot be constructed because it has no accessible initializers",
16101615
(Type))

include/swift/AST/Expr.h

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

41204120
public:
41214121
enum class BodyState {
4122-
/// The body was parsed, but not ready for type checking because
4123-
/// the closure parameters haven't been type checked.
4122+
/// The body was parsed.
41244123
Parsed,
41254124

4126-
/// The type of the closure itself was type checked. But the body has not
4127-
/// been type checked yet.
4128-
ReadyForTypeChecking,
4129-
4130-
/// The body was typechecked with the enclosing closure.
4131-
/// i.e. single expression closure or result builder closure.
4132-
TypeCheckedWithSignature,
4133-
4134-
/// The body was type checked separately from the enclosing closure.
4135-
SeparatelyTypeChecked,
4125+
/// The body was type-checked.
4126+
TypeChecked,
41364127
};
41374128

41384129
private:
@@ -4370,13 +4361,6 @@ class ClosureExpr : public AbstractClosureExpr {
43704361
ExplicitResultTypeAndBodyState.setInt(v);
43714362
}
43724363

4373-
/// Whether this closure's body is/was type checked separately from its
4374-
/// enclosing expression.
4375-
bool isSeparatelyTypeChecked() const {
4376-
return getBodyState() == BodyState::SeparatelyTypeChecked ||
4377-
getBodyState() == BodyState::ReadyForTypeChecking;
4378-
}
4379-
43804364
static bool classof(const Expr *E) {
43814365
return E->getKind() == ExprKind::Closure;
43824366
}

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
@@ -8853,28 +8853,21 @@ namespace {
88538853
// Note that in this mode `ClosuresToTypeCheck` acts
88548854
// as a stack because multi-statement closures could
88558855
// have other multi-statement closures in the body.
8856-
if (cs.participatesInInference(closure)) {
8857-
hadError |= cs.applySolutionToBody(
8858-
solution, closure, Rewriter.dc,
8859-
[&](SyntacticElementTarget target) {
8860-
auto resultTarget = rewriteTarget(target);
8861-
if (resultTarget) {
8862-
if (auto expr = resultTarget->getAsExpr())
8863-
solution.setExprTypes(expr);
8864-
}
8865-
8866-
return resultTarget;
8867-
});
8856+
hadError |= cs.applySolutionToBody(
8857+
solution, closure, Rewriter.dc, [&](SyntacticElementTarget target) {
8858+
auto resultTarget = rewriteTarget(target);
8859+
if (resultTarget) {
8860+
if (auto expr = resultTarget->getAsExpr())
8861+
solution.setExprTypes(expr);
8862+
}
88688863

8869-
if (!hadError) {
8870-
TypeChecker::checkClosureAttributes(closure);
8871-
TypeChecker::checkParameterList(closure->getParameters(), closure);
8872-
}
8864+
return resultTarget;
8865+
});
88738866

8874-
continue;
8867+
if (!hadError) {
8868+
TypeChecker::checkClosureAttributes(closure);
8869+
TypeChecker::checkParameterList(closure->getParameters(), closure);
88758870
}
8876-
8877-
hadError |= TypeChecker::typeCheckClosureBody(closure);
88788871
}
88798872

88808873
return hadError;

lib/Sema/CSDiagnostics.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,21 @@ FailureDiagnostic::getArgumentListFor(ConstraintLocator *locator) const {
177177
return S.getArgumentList(locator);
178178
}
179179

180+
StringRef FailureDiagnostic::getEditorPlaceholder(
181+
StringRef description, Type ty,
182+
llvm::SmallVectorImpl<char> &scratch) const {
183+
llvm::raw_svector_ostream OS(scratch);
184+
OS << "<#";
185+
if (!ty || ty->is<UnresolvedType>()) {
186+
OS << description;
187+
} else {
188+
OS << "T##";
189+
ty.print(OS);
190+
}
191+
OS << "#>";
192+
return StringRef(scratch.data(), scratch.size());
193+
}
194+
180195
Expr *FailureDiagnostic::getBaseExprFor(const Expr *anchor) const {
181196
if (!anchor)
182197
return nullptr;
@@ -5177,6 +5192,9 @@ bool MissingArgumentsFailure::diagnoseAsError() {
51775192
return true;
51785193
}
51795194

5195+
if (diagnoseMissingResultBuilderElement())
5196+
return true;
5197+
51805198
if (diagnoseInvalidTupleDestructuring())
51815199
return true;
51825200

@@ -5514,6 +5532,55 @@ bool MissingArgumentsFailure::diagnoseClosure(const ClosureExpr *closure) {
55145532
return true;
55155533
}
55165534

5535+
bool MissingArgumentsFailure::diagnoseMissingResultBuilderElement() const {
5536+
auto &ctx = getASTContext();
5537+
5538+
// Only handle a single missing argument in an empty builder for now. This
5539+
// should be the most common case though since most builders support N >= 1
5540+
// elements.
5541+
if (SynthesizedArgs.size() != 1)
5542+
return false;
5543+
5544+
auto *call = getAsExpr<CallExpr>(getRawAnchor());
5545+
if (!call || !call->isImplicit() || !call->getArgs()->empty())
5546+
return false;
5547+
5548+
auto *UDE = dyn_cast<UnresolvedDotExpr>(call->getFn());
5549+
if (!UDE || !isResultBuilderMethodReference(ctx, UDE))
5550+
return false;
5551+
5552+
auto overload = getCalleeOverloadChoiceIfAvailable(getLocator());
5553+
if (!overload)
5554+
return false;
5555+
5556+
auto *decl = overload->choice.getDeclOrNull();
5557+
if (!decl || decl->getBaseName() != ctx.Id_buildBlock)
5558+
return false;
5559+
5560+
auto resultBuilder =
5561+
getType(UDE->getBase())->getMetatypeInstanceType()->getAnyNominal();
5562+
if (!resultBuilder)
5563+
return false;
5564+
5565+
auto paramType = resolveType(SynthesizedArgs.front().param.getPlainType());
5566+
5567+
SmallString<64> scratch;
5568+
auto fixIt = getEditorPlaceholder("result", paramType, scratch);
5569+
auto fixItLoc = call->getStartLoc();
5570+
5571+
if (paramType->is<UnresolvedType>()) {
5572+
emitDiagnostic(diag::result_builder_missing_element,
5573+
resultBuilder->getName())
5574+
.fixItInsertAfter(fixItLoc, fixIt);
5575+
} else {
5576+
emitDiagnostic(diag::result_builder_missing_element_of_type, paramType,
5577+
resultBuilder->getName())
5578+
.fixItInsertAfter(fixItLoc, fixIt);
5579+
}
5580+
emitDiagnosticAt(decl, diag::decl_declared_here, decl);
5581+
return true;
5582+
}
5583+
55175584
bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const {
55185585
auto *locator = getLocator();
55195586
if (!locator->isLastElement<LocatorPathElt::ApplyArgument>())

lib/Sema/CSDiagnostics.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ class FailureDiagnostic {
203203
[](GenericTypeParamType *, Type) {});
204204

205205
bool conformsToKnownProtocol(Type type, KnownProtocolKind protocol) const;
206+
207+
/// Retrieve an editor placeholder with a given description, or a given
208+
/// type if specified.
209+
StringRef getEditorPlaceholder(StringRef description, Type ty,
210+
llvm::SmallVectorImpl<char> &scratch) const;
206211
};
207212

208213
/// Base class for all of the diagnostics related to generic requirement
@@ -1505,6 +1510,9 @@ class MissingArgumentsFailure final : public FailureDiagnostic {
15051510
/// let's produce tailored diagnostics.
15061511
bool diagnoseClosure(const ClosureExpr *closure);
15071512

1513+
/// Diagnose a single missing argument to a buildBlock call.
1514+
bool diagnoseMissingResultBuilderElement() const;
1515+
15081516
/// Diagnose cases when instead of multiple distinct arguments
15091517
/// call got a single tuple argument with expected arity/types.
15101518
bool diagnoseInvalidTupleDestructuring() const;

lib/Sema/CSGen.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,10 +2555,7 @@ namespace {
25552555
// If this is a multi-statement closure, let's mark result
25562556
// as potential hole right away.
25572557
return Type(CS.createTypeVariable(
2558-
resultLocator,
2559-
(!CS.participatesInInference(closure) || allowResultBindToHole)
2560-
? TVO_CanBindToHole
2561-
: 0));
2558+
resultLocator, allowResultBindToHole ? TVO_CanBindToHole : 0));
25622559
}();
25632560

25642561
// 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
@@ -2363,10 +2363,6 @@ void ConstraintSystem::forEachExpr(
23632363
if (!NewE)
23642364
return Action::Stop();
23652365

2366-
if (auto closure = dyn_cast<ClosureExpr>(E)) {
2367-
if (!CS.participatesInInference(closure))
2368-
return Action::SkipNode(NewE);
2369-
}
23702366
return Action::Continue(NewE);
23712367
}
23722368

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,

0 commit comments

Comments
 (0)