16
16
// ===----------------------------------------------------------------------===//
17
17
18
18
#include " ConstraintSystem.h"
19
+ #include " SolutionResult.h"
19
20
#include " TypeChecker.h"
20
21
#include " swift/AST/ASTVisitor.h"
21
22
#include " swift/AST/ASTWalker.h"
@@ -487,31 +488,128 @@ class BuilderClosureVisitor
487
488
488
489
} // end anonymous namespace
489
490
490
- BraceStmt *
491
- TypeChecker::applyFunctionBuilderBodyTransform (FuncDecl *FD,
492
- BraceStmt *body,
493
- Type builderType) {
494
- // Try to build a single result expression.
495
- auto &ctx = FD->getASTContext ();
496
- BuilderClosureVisitor visitor (ctx, nullptr ,
497
- /* wantExpr=*/ true , builderType);
498
- Expr *returnExpr = visitor.visit (body);
499
- if (!returnExpr)
500
- return nullptr ;
491
+ // / Find the return statements in the given body, which block the application
492
+ // / of a function builder.
493
+ static std::vector<ReturnStmt *> findReturnStatements (AnyFunctionRef fn);
494
+
495
+ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform (
496
+ FuncDecl *func, Type builderType) {
497
+ // Pre-check the body: pre-check any expressions in it and look
498
+ // for return statements.
499
+ //
500
+ // If we encountered an error or there was an explicit result type,
501
+ // bail out and report that to the caller.
502
+ auto &ctx = func->getASTContext ();
503
+ auto request = PreCheckFunctionBuilderRequest{func};
504
+ switch (evaluateOrDefault (
505
+ ctx.evaluator , request, FunctionBuilderClosurePreCheck::Error)) {
506
+ case FunctionBuilderClosurePreCheck::Okay:
507
+ // If the pre-check was okay, apply the function-builder transform.
508
+ break ;
501
509
502
- // Make sure we have a usable result type for the body.
503
- Type returnType = AnyFunctionRef (FD).getBodyResultType ();
504
- if (!returnType || returnType->hasError ())
510
+ case FunctionBuilderClosurePreCheck::Error:
505
511
return nullptr ;
506
512
507
- auto loc = returnExpr->getStartLoc ();
508
- auto returnStmt = new (ctx) ReturnStmt (loc, returnExpr, /* implicit*/ true );
509
- return BraceStmt::create (ctx, body->getLBraceLoc (), { returnStmt },
510
- body->getRBraceLoc ());
513
+ case FunctionBuilderClosurePreCheck::HasReturnStmt: {
514
+ // One or more explicit 'return' statements were encountered, which
515
+ // disables the function builder transform. Warn when we do this.
516
+ auto returnStmts = findReturnStatements (func);
517
+ assert (!returnStmts.empty ());
518
+
519
+ ctx.Diags .diagnose (
520
+ returnStmts.front ()->getReturnLoc (),
521
+ diag::function_builder_disabled_by_return, builderType);
522
+
523
+ // Note that one can remove the function builder attribute.
524
+ auto attr = func->getAttachedFunctionBuilder ();
525
+ if (!attr) {
526
+ if (auto accessor = dyn_cast<AccessorDecl>(func)) {
527
+ attr = accessor->getStorage ()->getAttachedFunctionBuilder ();
528
+ }
529
+ }
530
+
531
+ if (attr) {
532
+ ctx.Diags .diagnose (
533
+ attr->getLocation (), diag::function_builder_remove_attr)
534
+ .fixItRemove (attr->getRangeWithAt ());
535
+ attr->setInvalid ();
536
+ }
537
+
538
+ // Note that one can remove all of the return statements.
539
+ {
540
+ auto diag = ctx.Diags .diagnose (
541
+ returnStmts.front ()->getReturnLoc (),
542
+ diag::function_builder_remove_returns);
543
+ for (auto returnStmt : returnStmts) {
544
+ diag.fixItRemove (returnStmt->getReturnLoc ());
545
+ }
546
+ }
547
+
548
+ return None;
549
+ }
550
+ }
551
+
552
+ ConstraintSystemOptions options = ConstraintSystemFlags::AllowFixes;
553
+ auto resultInterfaceTy = func->getResultInterfaceType ();
554
+ auto resultContextType = func->mapTypeIntoContext (resultInterfaceTy);
555
+
556
+ // Determine whether we're inferring the underlying type for the opaque
557
+ // result type of this function.
558
+ ConstraintKind resultConstraintKind = ConstraintKind::Conversion;
559
+ if (auto opaque = resultContextType->getAs <OpaqueTypeArchetypeType>()) {
560
+ if (opaque->getDecl ()->isOpaqueReturnTypeOfFunction (func)) {
561
+ options |= ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType;
562
+ resultConstraintKind = ConstraintKind::OpaqueUnderlyingType;
563
+ }
564
+ }
565
+
566
+ // Build a constraint system in which we can check the body of the function.
567
+ ConstraintSystem cs (func, options);
568
+
569
+ // FIXME: check the result
570
+ cs.matchFunctionBuilder (func, builderType, resultContextType,
571
+ resultConstraintKind,
572
+ /* calleeLocator=*/ nullptr ,
573
+ /* FIXME:*/ ConstraintLocatorBuilder (nullptr ));
574
+
575
+ // Solve the constraint system.
576
+ SmallVector<Solution, 4 > solutions;
577
+ if (cs.solve (solutions) || solutions.size () != 1 ) {
578
+ // Try to fix the system or provide a decent diagnostic.
579
+ auto salvagedResult = cs.salvage ();
580
+ switch (salvagedResult.getKind ()) {
581
+ case SolutionResult::Kind::Success:
582
+ solutions.clear ();
583
+ solutions.push_back (std::move (salvagedResult).takeSolution ());
584
+ break ;
585
+
586
+ case SolutionResult::Kind::Error:
587
+ case SolutionResult::Kind::Ambiguous:
588
+ return nullptr ;
589
+
590
+ case SolutionResult::Kind::UndiagnosedError:
591
+ cs.diagnoseFailureFor (SolutionApplicationTarget (func));
592
+ salvagedResult.markAsDiagnosed ();
593
+ return nullptr ;
594
+
595
+ case SolutionResult::Kind::TooComplex:
596
+ func->diagnose (diag::expression_too_complex)
597
+ .highlight (func->getBodySourceRange ());
598
+ salvagedResult.markAsDiagnosed ();
599
+ return nullptr ;
600
+ }
601
+
602
+ // The system was salvaged; continue on as if nothing happened.
603
+ }
604
+
605
+ // Apply the solution to the function body.
606
+ return cast_or_null<BraceStmt>(
607
+ cs.applySolutionToBody (solutions.front (), func));
511
608
}
512
609
513
610
ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder (
514
611
AnyFunctionRef fn, Type builderType, Type bodyResultType,
612
+ ConstraintKind bodyResultConstraintKind,
515
613
ConstraintLocator *calleeLocator, ConstraintLocatorBuilder locator) {
516
614
auto builder = builderType->getAnyNominal ();
517
615
assert (builder && " Bad function builder type" );
@@ -524,7 +622,7 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder(
524
622
return getTypeMatchSuccess ();
525
623
}
526
624
527
- // Pre-check the closure body: pre-check any expressions in it and look
625
+ // Pre-check the body: pre-check any expressions in it and look
528
626
// for return statements.
529
627
auto request = PreCheckFunctionBuilderRequest{fn};
530
628
switch (evaluateOrDefault (getASTContext ().evaluator , request,
@@ -614,11 +712,12 @@ ConstraintSystem::TypeMatchResult ConstraintSystem::matchFunctionBuilder(
614
712
}) == functionBuilderTransformed.end () &&
615
713
" already transformed this closure along this path!?!" );
616
714
functionBuilderTransformed.push_back (
617
- std::make_pair (fn,
618
- AppliedBuilderTransform{builderType, singleExpr}));
715
+ std::make_pair (
716
+ fn,
717
+ AppliedBuilderTransform{builderType, singleExpr, bodyResultType}));
619
718
620
719
// Bind the body result type to the type of the transformed expression.
621
- addConstraint (ConstraintKind::Equal, bodyResultType, transformedType ,
720
+ addConstraint (bodyResultConstraintKind, transformedType, bodyResultType ,
622
721
locator);
623
722
return getTypeMatchSuccess ();
624
723
}
@@ -628,25 +727,31 @@ namespace {
628
727
// / Pre-check all the expressions in the closure body.
629
728
class PreCheckFunctionBuilderApplication : public ASTWalker {
630
729
AnyFunctionRef Fn;
631
- bool HasReturnStmt = false ;
730
+ bool SkipPrecheck = false ;
731
+ std::vector<ReturnStmt *> ReturnStmts;
632
732
bool HasError = false ;
733
+
734
+ bool hasReturnStmt () const { return !ReturnStmts.empty (); }
735
+
633
736
public:
634
- PreCheckFunctionBuilderApplication (AnyFunctionRef fn) : Fn(fn) {}
737
+ PreCheckFunctionBuilderApplication (AnyFunctionRef fn, bool skipPrecheck)
738
+ : Fn(fn), SkipPrecheck(skipPrecheck) {}
739
+
740
+ const std::vector<ReturnStmt *> getReturnStmts () const { return ReturnStmts; }
635
741
636
742
FunctionBuilderClosurePreCheck run () {
637
743
Stmt *oldBody = Fn.getBody ();
638
744
639
745
Stmt *newBody = oldBody->walk (*this );
640
746
641
747
// If the walk was aborted, it was because we had a problem of some kind.
642
- assert ((newBody == nullptr ) == ( HasError || HasReturnStmt) &&
748
+ assert ((newBody == nullptr ) == HasError &&
643
749
" unexpected short-circuit while walking body" );
644
- if (!newBody) {
645
- if (HasError)
646
- return FunctionBuilderClosurePreCheck::Error;
750
+ if (HasError)
751
+ return FunctionBuilderClosurePreCheck::Error;
647
752
753
+ if (hasReturnStmt ())
648
754
return FunctionBuilderClosurePreCheck::HasReturnStmt;
649
- }
650
755
651
756
assert (oldBody == newBody && " pre-check walk wasn't in-place?" );
652
757
@@ -657,7 +762,8 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
657
762
// Pre-check the expression. If this fails, abort the walk immediately.
658
763
// Otherwise, replace the expression with the result of pre-checking.
659
764
// In either case, don't recurse into the expression.
660
- if (ConstraintSystem::preCheckExpression (E, /* DC*/ Fn.getAsDeclContext ())) {
765
+ if (!SkipPrecheck &&
766
+ ConstraintSystem::preCheckExpression (E, /* DC*/ Fn.getAsDeclContext ())) {
661
767
HasError = true ;
662
768
return std::make_pair (false , nullptr );
663
769
}
@@ -666,10 +772,12 @@ class PreCheckFunctionBuilderApplication : public ASTWalker {
666
772
}
667
773
668
774
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
669
- // If we see a return statement, abort the walk immediately.
670
- if (isa<ReturnStmt>(S)) {
671
- HasReturnStmt = true ;
672
- return std::make_pair (false , nullptr );
775
+ // If we see a return statement, note it..
776
+ if (auto returnStmt = dyn_cast<ReturnStmt>(S)) {
777
+ if (!returnStmt->isImplicit ()) {
778
+ ReturnStmts.push_back (returnStmt);
779
+ return std::make_pair (false , S);
780
+ }
673
781
}
674
782
675
783
// Otherwise, recurse into the statement normally.
@@ -688,5 +796,11 @@ PreCheckFunctionBuilderRequest::evaluate(Evaluator &eval,
688
796
return FunctionBuilderClosurePreCheck::Okay;
689
797
}
690
798
691
- return PreCheckFunctionBuilderApplication (fn).run ();
799
+ return PreCheckFunctionBuilderApplication (fn, false ).run ();
800
+ }
801
+
802
+ std::vector<ReturnStmt *> findReturnStatements (AnyFunctionRef fn) {
803
+ PreCheckFunctionBuilderApplication precheck (fn, true );
804
+ (void )precheck.run ();
805
+ return precheck.getReturnStmts ();
692
806
}
0 commit comments