Skip to content

Commit ac24491

Browse files
committed
[Constraint system] Generalize function builder application APIs.
Teach the constraint system to handle matching a function builder to a function as well as a closure.
1 parent fffe129 commit ac24491

File tree

7 files changed

+59
-37
lines changed

7 files changed

+59
-37
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ class AnyFunctionRef {
216216
return lhs.TheFunction != rhs.TheFunction;
217217
}
218218

219+
friend llvm::hash_code hash_value(AnyFunctionRef fn) {
220+
using llvm::hash_value;
221+
return hash_value(fn.TheFunction.getOpaqueValue());
222+
}
223+
224+
friend SourceLoc extractNearestSourceLoc(AnyFunctionRef fn) {
225+
return fn.getLoc();
226+
}
227+
219228
private:
220229
ArrayRef<AnyFunctionType::Yield>
221230
getYieldResultsImpl(SmallVectorImpl<AnyFunctionType::Yield> &buffer,
@@ -243,6 +252,8 @@ class AnyFunctionRef {
243252
#pragma warning(pop)
244253
#endif
245254

255+
void simple_display(llvm::raw_ostream &out, AnyFunctionRef fn);
256+
246257
} // namespace swift
247258

248259
namespace llvm {

include/swift/AST/TypeCheckRequests.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#ifndef SWIFT_TYPE_CHECK_REQUESTS_H
1717
#define SWIFT_TYPE_CHECK_REQUESTS_H
1818

19+
#include "swift/AST/AnyFunctionRef.h"
1920
#include "swift/AST/ASTTypeIDs.h"
2021
#include "swift/AST/GenericSignature.h"
2122
#include "swift/AST/Type.h"
@@ -1760,7 +1761,7 @@ enum class FunctionBuilderClosurePreCheck : uint8_t {
17601761

17611762
class PreCheckFunctionBuilderRequest
17621763
: public SimpleRequest<PreCheckFunctionBuilderRequest,
1763-
FunctionBuilderClosurePreCheck(ClosureExpr *),
1764+
FunctionBuilderClosurePreCheck(AnyFunctionRef),
17641765
CacheKind::Cached> {
17651766
public:
17661767
using SimpleRequest::SimpleRequest;
@@ -1770,7 +1771,7 @@ class PreCheckFunctionBuilderRequest
17701771

17711772
// Evaluation.
17721773
llvm::Expected<FunctionBuilderClosurePreCheck>
1773-
evaluate(Evaluator &evaluator, ClosureExpr *closure) const;
1774+
evaluate(Evaluator &evaluator, AnyFunctionRef fn) const;
17741775

17751776
public:
17761777
// Separate caching.

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ SWIFT_REQUEST(TypeChecker, HasUserDefinedDesignatedInitRequest,
196196
SWIFT_REQUEST(TypeChecker, HasMemberwiseInitRequest,
197197
bool(StructDecl *), Cached, NoLocationInfo)
198198
SWIFT_REQUEST(TypeChecker, PreCheckFunctionBuilderRequest,
199-
FunctionBuilderClosurePreCheck(ClosureExpr *),
199+
FunctionBuilderClosurePreCheck(AnyFunctionRef),
200200
Cached, NoLocationInfo)
201201
SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
202202
bool(NominalTypeDecl *, ImplicitMemberAction), Uncached,

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7907,3 +7907,10 @@ void ParseAbstractFunctionBodyRequest::cacheResult(BraceStmt *value) const {
79077907
}
79087908

79097909
}
7910+
7911+
void swift::simple_display(llvm::raw_ostream &out, AnyFunctionRef fn) {
7912+
if (auto func = fn.getAbstractFunctionDecl())
7913+
simple_display(out, func);
7914+
else
7915+
out << "closure";
7916+
}

lib/Sema/BuilderTransform.cpp

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -510,21 +510,23 @@ TypeChecker::applyFunctionBuilderBodyTransform(FuncDecl *FD,
510510
body->getRBraceLoc());
511511
}
512512

513-
ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
514-
ClosureExpr *closure, Type builderType, ConstraintLocator *calleeLocator,
515-
ConstraintLocatorBuilder locator) {
513+
ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder(
514+
AnyFunctionRef fn, Type builderType, Type bodyResultType,
515+
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator) {
516516
auto builder = builderType->getAnyNominal();
517517
assert(builder && "Bad function builder type");
518518
assert(builder->getAttrs().hasAttribute<FunctionBuilderAttr>());
519519

520520
// FIXME: Right now, single-expression closures suppress the function
521521
// builder translation.
522-
if (closure->hasSingleExpressionBody())
523-
return getTypeMatchSuccess();
522+
if (auto closure = fn.getAbstractClosureExpr()) {
523+
if (closure->hasSingleExpressionBody())
524+
return getTypeMatchSuccess();
525+
}
524526

525527
// Pre-check the closure body: pre-check any expressions in it and look
526528
// for return statements.
527-
auto request = PreCheckFunctionBuilderRequest{closure};
529+
auto request = PreCheckFunctionBuilderRequest{fn};
528530
switch (evaluateOrDefault(getASTContext().evaluator, request,
529531
FunctionBuilderClosurePreCheck::Error)) {
530532
case FunctionBuilderClosurePreCheck::Okay:
@@ -547,7 +549,7 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
547549
// Check whether we can apply this specific function builder.
548550
BuilderClosureVisitor visitor(getASTContext(), this,
549551
/*wantExpr=*/false, builderType);
550-
(void)visitor.visit(closure->getBody());
552+
(void)visitor.visit(fn.getBody());
551553

552554
// If we saw a control-flow statement or declaration that the builder
553555
// cannot handle, we don't have a well-formed function builder application.
@@ -585,17 +587,18 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
585587

586588
BuilderClosureVisitor visitor(getASTContext(), this,
587589
/*wantExpr=*/true, builderType);
588-
Expr *singleExpr = visitor.visit(closure->getBody());
590+
Expr *singleExpr = visitor.visit(fn.getBody());
589591

590592
// We've already pre-checked all the original expressions, but do the
591593
// pre-check to the generated expression just to set up any preconditions
592594
// that CSGen might have.
593595
//
594596
// TODO: just build the AST the way we want it in the first place.
595-
if (ConstraintSystem::preCheckExpression(singleExpr, closure))
597+
auto dc = fn.getAsDeclContext();
598+
if (ConstraintSystem::preCheckExpression(singleExpr, dc))
596599
return getTypeMatchFailure(locator);
597600

598-
singleExpr = generateConstraints(singleExpr, closure);
601+
singleExpr = generateConstraints(singleExpr, dc);
599602
if (!singleExpr)
600603
return getTypeMatchFailure(locator);
601604

@@ -607,41 +610,37 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
607610
functionBuilderTransformed.begin(),
608611
functionBuilderTransformed.end(),
609612
[&](const std::pair<AnyFunctionRef, AppliedBuilderTransform> &elt) {
610-
return elt.first == closure;
613+
return elt.first == fn;
611614
}) == functionBuilderTransformed.end() &&
612615
"already transformed this closure along this path!?!");
613616
functionBuilderTransformed.push_back(
614-
std::make_pair(closure,
617+
std::make_pair(fn,
615618
AppliedBuilderTransform{builderType, singleExpr}));
616619

617-
// Bind the result type of the closure to the type of the transformed
618-
// expression.
619-
Type closureType = getType(closure);
620-
auto fnType = closureType->castTo<FunctionType>();
621-
addConstraint(ConstraintKind::Equal, fnType->getResult(), transformedType,
620+
// Bind the body result type to the type of the transformed expression.
621+
addConstraint(ConstraintKind::Equal, bodyResultType, transformedType,
622622
locator);
623623
return getTypeMatchSuccess();
624624
}
625625

626626
namespace {
627627

628628
/// Pre-check all the expressions in the closure body.
629-
class PreCheckFunctionBuilderClosure : public ASTWalker {
630-
ClosureExpr *Closure;
629+
class PreCheckFunctionBuilderApplication : public ASTWalker {
630+
AnyFunctionRef Fn;
631631
bool HasReturnStmt = false;
632632
bool HasError = false;
633633
public:
634-
PreCheckFunctionBuilderClosure(ClosureExpr *closure)
635-
: Closure(closure) {}
634+
PreCheckFunctionBuilderApplication(AnyFunctionRef fn) : Fn(fn) {}
636635

637636
FunctionBuilderClosurePreCheck run() {
638-
Stmt *oldBody = Closure->getBody();
637+
Stmt *oldBody = Fn.getBody();
639638

640639
Stmt *newBody = oldBody->walk(*this);
641640

642641
// If the walk was aborted, it was because we had a problem of some kind.
643642
assert((newBody == nullptr) == (HasError || HasReturnStmt) &&
644-
"unexpected short-circuit while walking closure body");
643+
"unexpected short-circuit while walking body");
645644
if (!newBody) {
646645
if (HasError)
647646
return FunctionBuilderClosurePreCheck::Error;
@@ -658,7 +657,7 @@ class PreCheckFunctionBuilderClosure : public ASTWalker {
658657
// Pre-check the expression. If this fails, abort the walk immediately.
659658
// Otherwise, replace the expression with the result of pre-checking.
660659
// In either case, don't recurse into the expression.
661-
if (ConstraintSystem::preCheckExpression(E, /*DC*/ Closure)) {
660+
if (ConstraintSystem::preCheckExpression(E, /*DC*/ Fn.getAsDeclContext())) {
662661
HasError = true;
663662
return std::make_pair(false, nullptr);
664663
}
@@ -682,10 +681,12 @@ class PreCheckFunctionBuilderClosure : public ASTWalker {
682681

683682
llvm::Expected<FunctionBuilderClosurePreCheck>
684683
PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval,
685-
ClosureExpr *closure) const {
684+
AnyFunctionRef fn) const {
686685
// Single-expression closures should already have been pre-checked.
687-
if (closure->hasSingleExpressionBody())
688-
return FunctionBuilderClosurePreCheck::Okay;
686+
if (auto closure = fn.getAbstractClosureExpr()) {
687+
if (closure->hasSingleExpressionBody())
688+
return FunctionBuilderClosurePreCheck::Okay;
689+
}
689690

690-
return PreCheckFunctionBuilderClosure(closure).run();
691+
return PreCheckFunctionBuilderApplication(fn).run();
691692
}

lib/Sema/CSSimplify.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,9 +1145,11 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
11451145
= paramInfo.getFunctionBuilderType(paramIdx)) {
11461146
Expr *arg = getArgumentExpr(locator.getAnchor(), argIdx);
11471147
if (auto closure = dyn_cast_or_null<ClosureExpr>(arg)) {
1148-
auto result =
1149-
cs.applyFunctionBuilder(closure, functionBuilderType,
1150-
calleeLocator, loc);
1148+
auto closureType = cs.getType(closure);
1149+
auto result = cs.matchFunctionBuilder(
1150+
closure, functionBuilderType,
1151+
closureType->castTo<FunctionType>()->getResult(),
1152+
calleeLocator, loc);
11511153
if (result.isFailure())
11521154
return result;
11531155
}

lib/Sema/ConstraintSystem.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3477,9 +3477,9 @@ class ConstraintSystem {
34773477
void simplifyDisjunctionChoice(Constraint *choice);
34783478

34793479
/// Apply the given function builder to the closure expression.
3480-
TypeMatchResult applyFunctionBuilder(ClosureExpr *closure, Type builderType,
3481-
ConstraintLocator *calleeLocator,
3482-
ConstraintLocatorBuilder locator);
3480+
TypeMatchResult matchFunctionBuilder(
3481+
AnyFunctionRef fn, Type builderType, Type bodyResultType,
3482+
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator);
34833483

34843484
private:
34853485
/// The kind of bindings that are permitted.

0 commit comments

Comments
 (0)