@@ -741,11 +741,124 @@ class BuilderClosureVisitor
741
741
return visit (caseStmt->getBody ());
742
742
}
743
743
744
+ VarDecl *visitForEachStmt (ForEachStmt *forEachStmt) {
745
+ // for...in statements are handled via buildArray(_:); bail out if the
746
+ // builder does not support it.
747
+ if (!builderSupports (ctx.Id_buildArray )) {
748
+ if (!unhandledNode)
749
+ unhandledNode = forEachStmt;
750
+ return nullptr ;
751
+ }
752
+
753
+ // For-each statements require the Sequence protocol. If we don't have
754
+ // it (which generally means the standard library isn't loaded), fall
755
+ // out of the function-builder path entirely to let normal type checking
756
+ // take care of this.
757
+ auto sequenceProto = TypeChecker::getProtocol (
758
+ dc->getASTContext (), forEachStmt->getForLoc (),
759
+ KnownProtocolKind::Sequence);
760
+ if (!sequenceProto) {
761
+ if (!unhandledNode)
762
+ unhandledNode = forEachStmt;
763
+ return nullptr ;
764
+ }
765
+
766
+ // Generate constraints for the loop header. This also wires up the
767
+ // types for the patterns.
768
+ auto target = SolutionApplicationTarget::forForEachStmt (
769
+ forEachStmt, sequenceProto, dc, /* bindPatternVarsOneWay=*/ true );
770
+ if (cs) {
771
+ if (cs->generateConstraints (target, FreeTypeVariableBinding::Disallow)) {
772
+ hadError = true ;
773
+ return nullptr ;
774
+ }
775
+
776
+ cs->setSolutionApplicationTarget (forEachStmt, target);
777
+ }
778
+
779
+ // Visit the loop body itself.
780
+ VarDecl *bodyVar = visit (forEachStmt->getBody ());
781
+ if (!bodyVar)
782
+ return nullptr ;
783
+
784
+ // If there's no constraint system, there is nothing left to visit.
785
+ if (!cs)
786
+ return nullptr ;
787
+
788
+ // Form a variable of array type that will capture the result of each
789
+ // iteration of the loop. We need a fresh type variable to remove the
790
+ // lvalue-ness of the array variable.
791
+ SourceLoc loc = forEachStmt->getForLoc ();
792
+ VarDecl *arrayVar = buildVar (loc);
793
+ Type arrayElementType = cs->createTypeVariable (
794
+ cs->getConstraintLocator (forEachStmt), 0 );
795
+ cs->addConstraint (
796
+ ConstraintKind::Equal, cs->getType (bodyVar), arrayElementType,
797
+ cs->getConstraintLocator (
798
+ forEachStmt, ConstraintLocator::RValueAdjustment));
799
+ Type arrayType = ArraySliceType::get (arrayElementType);
800
+ cs->setType (arrayVar, arrayType);
801
+
802
+ // Form an initialization of the array to an empty array literal.
803
+ Expr *arrayInitExpr = ArrayExpr::create (ctx, loc, { }, { }, loc);
804
+ cs->setContextualType (
805
+ arrayInitExpr, TypeLoc::withoutLoc (arrayType), CTP_CannotFail);
806
+ arrayInitExpr = cs->generateConstraints (arrayInitExpr, dc);
807
+ if (!arrayInitExpr) {
808
+ hadError = true ;
809
+ return nullptr ;
810
+ }
811
+ cs->addConstraint (
812
+ ConstraintKind::Equal, cs->getType (arrayInitExpr), arrayType,
813
+ cs->getConstraintLocator (arrayInitExpr));
814
+
815
+ // Form a call to Array.append(_:) to add the result of executing each
816
+ // iteration of the loop body to the array formed above.
817
+ SourceLoc endLoc = forEachStmt->getEndLoc ();
818
+ auto arrayVarRef = buildVarRef (arrayVar, endLoc);
819
+ auto arrayAppendRef = new (ctx) UnresolvedDotExpr (
820
+ arrayVarRef, endLoc, DeclNameRef (ctx.getIdentifier (" append" )),
821
+ DeclNameLoc (endLoc), /* implicit=*/ true );
822
+ arrayAppendRef->setFunctionRefKind (FunctionRefKind::SingleApply);
823
+ auto bodyVarRef = buildVarRef (bodyVar, endLoc);
824
+ Expr *arrayAppendCall = CallExpr::create (
825
+ ctx, arrayAppendRef, endLoc, { bodyVarRef } , { Identifier () },
826
+ { endLoc }, endLoc, /* trailingClosure=*/ nullptr , /* implicit=*/ true );
827
+ arrayAppendCall = cs->generateConstraints (arrayAppendCall, dc);
828
+ if (!arrayAppendCall) {
829
+ hadError = true ;
830
+ return nullptr ;
831
+ }
832
+
833
+ // Form the final call to buildArray(arrayVar) to allow the function
834
+ // builder to reshape the array into whatever it wants as the result of
835
+ // the for-each loop.
836
+ auto finalArrayVarRef = buildVarRef (arrayVar, endLoc);
837
+ auto buildArrayCall = buildCallIfWanted (
838
+ endLoc, ctx.Id_buildArray , { finalArrayVarRef }, { Identifier () });
839
+ assert (buildArrayCall);
840
+ buildArrayCall = cs->generateConstraints (buildArrayCall, dc);
841
+ if (!buildArrayCall) {
842
+ hadError = true ;
843
+ return nullptr ;
844
+ }
845
+
846
+ // Form a final variable for the for-each expression itself, which will
847
+ // be initialized with the call to the function builder's buildArray(_:).
848
+ auto finalForEachVar = buildVar (loc);
849
+ cs->setType (finalForEachVar, cs->getType (buildArrayCall));
850
+ applied.capturedStmts .insert (
851
+ {forEachStmt, {
852
+ finalForEachVar,
853
+ { arrayVarRef, arrayInitExpr, arrayAppendCall, buildArrayCall }}});
854
+
855
+ return finalForEachVar;
856
+ }
857
+
744
858
CONTROL_FLOW_STMT (Guard)
745
859
CONTROL_FLOW_STMT (While)
746
860
CONTROL_FLOW_STMT (DoCatch)
747
861
CONTROL_FLOW_STMT (RepeatWhile)
748
- CONTROL_FLOW_STMT (ForEach)
749
862
CONTROL_FLOW_STMT (Case)
750
863
CONTROL_FLOW_STMT (Break)
751
864
CONTROL_FLOW_STMT (Continue)
@@ -765,6 +878,9 @@ struct FunctionBuilderTarget {
765
878
ReturnValue,
766
879
// / The temporary variable into which the result should be assigned.
767
880
TemporaryVar,
881
+ // / An expression to evaluate at the end of the block, allowing the update
882
+ // / of some state from an outer scope.
883
+ Expression,
768
884
} kind;
769
885
770
886
// / Captured variable information.
@@ -778,6 +894,10 @@ struct FunctionBuilderTarget {
778
894
llvm::TinyPtrVector<Expr *> exprs) {
779
895
return FunctionBuilderTarget{TemporaryVar, {temporaryVar, exprs}};
780
896
}
897
+
898
+ static FunctionBuilderTarget forExpression (Expr *expr) {
899
+ return FunctionBuilderTarget{Expression, { nullptr , { expr }}};
900
+ }
781
901
};
782
902
783
903
// / Handles the rewrite of the body of a closure to which a function builder
@@ -882,6 +1002,10 @@ class BuilderClosureRewriter
882
1002
assign->setType (TupleType::getEmpty (ctx));
883
1003
return assign;
884
1004
}
1005
+
1006
+ case FunctionBuilderTarget::Expression:
1007
+ // Execute the expression.
1008
+ return rewriteExpr (capturedExpr);
885
1009
}
886
1010
}
887
1011
@@ -1181,6 +1305,59 @@ class BuilderClosureRewriter
1181
1305
return caseStmt;
1182
1306
}
1183
1307
1308
+ Stmt *visitForEachStmt (
1309
+ ForEachStmt *forEachStmt, FunctionBuilderTarget target) {
1310
+ // Translate the for-each loop header.
1311
+ ConstraintSystem &cs = solution.getConstraintSystem ();
1312
+ auto forEachTarget =
1313
+ rewriteTarget (*cs.getSolutionApplicationTarget (forEachStmt));
1314
+ if (!forEachTarget)
1315
+ return nullptr ;
1316
+
1317
+ const auto &captured = target.captured ;
1318
+ auto finalForEachVar = captured.first ;
1319
+ auto arrayVarRef = captured.second [0 ];
1320
+ auto arrayVar = cast<VarDecl>(cast<DeclRefExpr>(arrayVarRef)->getDecl ());
1321
+ auto arrayInitExpr = captured.second [1 ];
1322
+ auto arrayAppendCall = captured.second [2 ];
1323
+ auto buildArrayCall = captured.second [3 ];
1324
+
1325
+ // Collect the three steps to initialize the array variable to an
1326
+ // empty array, execute the loop to collect the results of each iteration,
1327
+ // then form the buildArray() call to the write the result.
1328
+ std::vector<ASTNode> outerBodySteps;
1329
+
1330
+ // Step 1: Declare and initialize the array variable.
1331
+ arrayVar->setInterfaceType (solution.simplifyType (cs.getType (arrayVar)));
1332
+ arrayInitExpr = rewriteExpr (arrayInitExpr);
1333
+ declareTemporaryVariable (arrayVar, outerBodySteps, arrayInitExpr);
1334
+
1335
+ // Step 2. Transform the body of the for-each statement. Each iteration
1336
+ // will append the result of executing the loop body to the array.
1337
+ auto body = forEachStmt->getBody ();
1338
+ auto capturedBody = takeCapturedStmt (body);
1339
+ auto newBody = cast<BraceStmt>(
1340
+ visitBraceStmt (
1341
+ body,
1342
+ FunctionBuilderTarget::forExpression (arrayAppendCall),
1343
+ FunctionBuilderTarget::forAssign (
1344
+ capturedBody.first , {capturedBody.second .front ()})));
1345
+ forEachStmt->setBody (newBody);
1346
+ outerBodySteps.push_back (forEachStmt);
1347
+
1348
+ // Step 3. Perform the buildArray() call to turn the array of results
1349
+ // collected from the iterations into a single value under the control of
1350
+ // the function builder.
1351
+ outerBodySteps.push_back (
1352
+ initializeTarget (
1353
+ FunctionBuilderTarget::forAssign (finalForEachVar, {buildArrayCall})));
1354
+
1355
+ // Form a brace statement to put together the three main steps for the
1356
+ // for-each loop translation outlined above.
1357
+ return BraceStmt::create (
1358
+ ctx, forEachStmt->getStartLoc (), outerBodySteps, newBody->getEndLoc ());
1359
+ }
1360
+
1184
1361
#define UNHANDLED_FUNCTION_BUILDER_STMT (STMT ) \
1185
1362
Stmt *visit##STMT##Stmt(STMT##Stmt *stmt, FunctionBuilderTarget target) { \
1186
1363
llvm_unreachable (" Function builders do not allow statement of kind " \
@@ -1194,7 +1371,6 @@ class BuilderClosureRewriter
1194
1371
UNHANDLED_FUNCTION_BUILDER_STMT (Defer)
1195
1372
UNHANDLED_FUNCTION_BUILDER_STMT (DoCatch)
1196
1373
UNHANDLED_FUNCTION_BUILDER_STMT (RepeatWhile)
1197
- UNHANDLED_FUNCTION_BUILDER_STMT (ForEach)
1198
1374
UNHANDLED_FUNCTION_BUILDER_STMT (Break)
1199
1375
UNHANDLED_FUNCTION_BUILDER_STMT (Continue)
1200
1376
UNHANDLED_FUNCTION_BUILDER_STMT (Fallthrough)
0 commit comments