@@ -451,45 +451,6 @@ class BuilderClosureVisitor
451
451
452
452
} // end anonymous namespace
453
453
454
- // / Determine whether the given statement contains a 'return' statement anywhere.
455
- static bool hasReturnStmt (Stmt *stmt) {
456
- class ReturnStmtFinder : public ASTWalker {
457
- public:
458
- bool hasReturnStmt = false ;
459
-
460
- std::pair<bool , Expr *> walkToExprPre (Expr *expr) override {
461
- return { false , expr };
462
- }
463
-
464
- std::pair<bool , Stmt *> walkToStmtPre (Stmt *stmt) override {
465
- // Did we find a 'return' statement?
466
- if (isa<ReturnStmt>(stmt)) {
467
- hasReturnStmt = true ;
468
- }
469
-
470
- return { !hasReturnStmt, stmt };
471
- }
472
-
473
- Stmt *walkToStmtPost (Stmt *stmt) override {
474
- return hasReturnStmt ? nullptr : stmt;
475
- }
476
-
477
- std::pair<bool , Pattern*> walkToPatternPre (Pattern *pattern) override {
478
- return { false , pattern };
479
- }
480
-
481
- bool walkToDeclPre (Decl *D) override { return false ; }
482
-
483
- bool walkToTypeLocPre (TypeLoc &TL) override { return false ; }
484
-
485
- bool walkToTypeReprPre (TypeRepr *T) override { return false ; }
486
- };
487
-
488
- ReturnStmtFinder finder{};
489
- stmt->walk (finder);
490
- return finder.hasReturnStmt ;
491
- }
492
-
493
454
BraceStmt *
494
455
TypeChecker::applyFunctionBuilderBodyTransform (FuncDecl *FD,
495
456
BraceStmt *body,
@@ -520,26 +481,36 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
520
481
assert (builder && " Bad function builder type" );
521
482
assert (builder->getAttrs ().hasAttribute <FunctionBuilderAttr>());
522
483
523
- // Check the form of this closure to see if we can apply the function-builder
524
- // translation at all.
525
- {
526
- // FIXME: Right now, single-expression closures suppress the function
527
- // builder translation.
528
- if (closure->hasSingleExpressionBody ())
529
- return getTypeMatchSuccess ();
530
-
531
- // The presence of an explicit return suppresses the function builder
532
- // translation.
533
- if (hasReturnStmt (closure->getBody ())) {
534
- return getTypeMatchSuccess ();
535
- }
484
+ // FIXME: Right now, single-expression closures suppress the function
485
+ // builder translation.
486
+ if (closure->hasSingleExpressionBody ())
487
+ return getTypeMatchSuccess ();
488
+
489
+ // Pre-check the closure body: pre-check any expressions in it and look
490
+ // for return statements.
491
+ switch (TC.preCheckFunctionBuilderClosureBody (closure)) {
492
+ case FunctionBuilderClosurePreCheck::Okay:
493
+ // If the pre-check was okay, apply the function-builder transform.
494
+ break ;
536
495
537
- // Check whether we can apply this function builder.
496
+ case FunctionBuilderClosurePreCheck::Error:
497
+ // If the pre-check had an error, flag that.
498
+ return getTypeMatchFailure (locator);
499
+
500
+ case FunctionBuilderClosurePreCheck::HasReturnStmt:
501
+ // If the closure has a return statement, suppress the transform but
502
+ // continue solving the constraint system.
503
+ return getTypeMatchSuccess ();
504
+ }
505
+
506
+ // Check the form of this closure to see if we can apply the
507
+ // function-builder translation at all.
508
+ {
509
+ // Check whether we can apply this specific function builder.
538
510
BuilderClosureVisitor visitor (getASTContext (), this ,
539
511
/* wantExpr=*/ false , builderType);
540
512
(void )visitor.visit (closure->getBody ());
541
513
542
-
543
514
// If we saw a control-flow statement or declaration that the builder
544
515
// cannot handle, we don't have a well-formed function builder application.
545
516
if (visitor.unhandledNode ) {
@@ -584,8 +555,12 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
584
555
/* wantExpr=*/ true , builderType);
585
556
Expr *singleExpr = visitor.visit (closure->getBody ());
586
557
587
- if (TC.precheckedClosures .insert (closure).second &&
588
- TC.preCheckExpression (singleExpr, closure))
558
+ // We've already pre-checked all the original expressions, but do the
559
+ // pre-check to the generated expression just to set up any preconditions
560
+ // that CSGen might have.
561
+ //
562
+ // TODO: just build the AST the way we want it in the first place.
563
+ if (TC.preCheckExpression (singleExpr, closure))
589
564
return getTypeMatchFailure (locator);
590
565
591
566
singleExpr = generateConstraints (singleExpr, closure);
@@ -613,3 +588,80 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::applyFunctionBuilder(
613
588
locator);
614
589
return getTypeMatchSuccess ();
615
590
}
591
+
592
+ namespace {
593
+
594
+ // / Pre-check all the expressions in the closure body.
595
+ class PreCheckFunctionBuilderClosure : public ASTWalker {
596
+ TypeChecker &TC;
597
+ ClosureExpr *Closure;
598
+ bool HasReturnStmt = false ;
599
+ bool HasError = false ;
600
+ public:
601
+ PreCheckFunctionBuilderClosure (TypeChecker &tc, ClosureExpr *closure)
602
+ : TC(tc), Closure(closure) {}
603
+
604
+ FunctionBuilderClosurePreCheck run () {
605
+ Stmt *oldBody = Closure->getBody ();
606
+
607
+ Stmt *newBody = oldBody->walk (*this );
608
+
609
+ // If the walk was aborted, it was because we had a problem of some kind.
610
+ assert ((newBody == nullptr ) == (HasError || HasReturnStmt) &&
611
+ " unexpected short-circuit while walking closure body" );
612
+ if (!newBody) {
613
+ if (HasError)
614
+ return FunctionBuilderClosurePreCheck::Error;
615
+
616
+ return FunctionBuilderClosurePreCheck::HasReturnStmt;
617
+ }
618
+
619
+ assert (oldBody == newBody && " pre-check walk wasn't in-place?" );
620
+
621
+ return FunctionBuilderClosurePreCheck::Okay;
622
+ }
623
+
624
+ std::pair<bool , Expr *> walkToExprPre (Expr *E) override {
625
+ // Pre-check the expression. If this fails, abort the walk immediately.
626
+ // Otherwise, replace the expression with the result of pre-checking.
627
+ // In either case, don't recurse into the expression.
628
+ if (TC.preCheckExpression (E, /* DC*/ Closure)) {
629
+ HasError = true ;
630
+ return std::make_pair (false , nullptr );
631
+ }
632
+
633
+ return std::make_pair (false , E);
634
+ }
635
+
636
+ std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
637
+ // If we see a return statement, abort the walk immediately.
638
+ if (isa<ReturnStmt>(S)) {
639
+ HasReturnStmt = true ;
640
+ return std::make_pair (false , nullptr );
641
+ }
642
+
643
+ // Otherwise, recurse into the statement normally.
644
+ return std::make_pair (true , S);
645
+ }
646
+ };
647
+
648
+ }
649
+
650
+ FunctionBuilderClosurePreCheck
651
+ TypeChecker::preCheckFunctionBuilderClosureBody (ClosureExpr *closure) {
652
+ // Single-expression closures should already have been pre-checked.
653
+ if (closure->hasSingleExpressionBody ())
654
+ return FunctionBuilderClosurePreCheck::Okay;
655
+
656
+ // Check whether we've already done this analysis.
657
+ auto it = precheckedFunctionBuilderClosures.find (closure);
658
+ if (it != precheckedFunctionBuilderClosures.end ())
659
+ return it->second ;
660
+
661
+ auto result = PreCheckFunctionBuilderClosure (*this , closure).run ();
662
+
663
+ // Cache the result.
664
+ precheckedFunctionBuilderClosures.insert (std::make_pair (closure, result));
665
+
666
+ return result;
667
+ }
0 commit comments