@@ -68,10 +68,8 @@ class BuilderClosureVisitor
6868 ConstraintSystem *cs;
6969 DeclContext *dc;
7070 ASTContext &ctx;
71- Type builderType;
72- NominalTypeDecl *builder = nullptr ;
73- Identifier buildOptionalId;
74- llvm::SmallDenseMap<DeclName, bool > supportedOps;
71+
72+ ResultBuilder builder;
7573
7674 // / The variable used as a base for all `build*` operations added
7775 // / by this transform.
@@ -121,21 +119,6 @@ class BuilderClosureVisitor
121119 return CallExpr::createImplicit (ctx, memberRef, argList);
122120 }
123121
124- // / Check whether the builder supports the given operation.
125- bool builderSupports (Identifier fnBaseName,
126- ArrayRef<Identifier> argLabels = {},
127- bool checkAvailability = false ) {
128- DeclName name (dc->getASTContext (), fnBaseName, argLabels);
129- auto known = supportedOps.find (name);
130- if (known != supportedOps.end ()) {
131- return known->second ;
132- }
133-
134- return supportedOps[name] = TypeChecker::typeSupportsBuilderOp (
135- builderType, dc, fnBaseName, argLabels, /* allResults*/ {},
136- checkAvailability);
137- }
138-
139122 // / Build an implicit variable in this context.
140123 VarDecl *buildVar (SourceLoc loc) {
141124 // Create the implicit variable.
@@ -192,27 +175,19 @@ class BuilderClosureVisitor
192175public:
193176 BuilderClosureVisitor (ASTContext &ctx, ConstraintSystem *cs, DeclContext *dc,
194177 Type builderType, Type bodyResultType)
195- : cs(cs), dc(dc), ctx(ctx), builderType(builderType) {
196- builder = builderType-> getAnyNominal ();
197- applied.builderType = builderType ;
178+ : cs(cs), dc(dc), ctx(ctx),
179+ builder (dc, cs ? cs-> simplifyType (builderType) : builderType) {
180+ applied.builderType = builder. getType () ;
198181 applied.bodyResultType = bodyResultType;
199182
200- // Use buildOptional(_:) if available, otherwise fall back to buildIf
201- // when available.
202- if (builderSupports (ctx.Id_buildOptional ) ||
203- !builderSupports (ctx.Id_buildIf ))
204- buildOptionalId = ctx.Id_buildOptional ;
205- else
206- buildOptionalId = ctx.Id_buildIf ;
207-
208183 // If we are about to generate constraints, let's establish builder
209184 // variable for the base of `build*` calls.
210185 if (cs) {
211186 builderVar = new (ctx) VarDecl (
212187 /* isStatic=*/ false , VarDecl::Introducer::Let,
213188 /* nameLoc=*/ SourceLoc (), ctx.Id_builderSelf , dc);
214189 builderVar->setImplicit ();
215- cs->setType (builderVar, MetatypeType::get (cs-> simplifyType (builderType )));
190+ cs->setType (builderVar, MetatypeType::get (builder. getType ( )));
216191 }
217192 }
218193
@@ -226,7 +201,7 @@ class BuilderClosureVisitor
226201
227202 // If there is a buildFinalResult(_:), call it.
228203 ASTContext &ctx = cs->getASTContext ();
229- if (builderSupports (ctx.Id_buildFinalResult , { Identifier () })) {
204+ if (builder. supports (ctx.Id_buildFinalResult , {Identifier ()})) {
230205 applied.returnExpr = buildCallIfWanted (
231206 applied.returnExpr ->getLoc (), ctx.Id_buildFinalResult ,
232207 { applied.returnExpr }, { Identifier () });
@@ -350,7 +325,7 @@ class BuilderClosureVisitor
350325 }
351326
352327 auto expr = node.get <Expr *>();
353- if (cs && builderSupports (ctx.Id_buildExpression )) {
328+ if (cs && builder. supports (ctx.Id_buildExpression )) {
354329 expr = buildCallIfWanted (expr->getLoc (), ctx.Id_buildExpression ,
355330 { expr }, { Identifier () });
356331 }
@@ -366,11 +341,11 @@ class BuilderClosureVisitor
366341 // `buildPartialBlock(accumulated:next:)`, use this to combine
367342 // subexpressions pairwise.
368343 if (!expressions.empty () &&
369- builderSupports (ctx.Id_buildPartialBlock , {ctx.Id_first },
370- /* checkAvailability*/ true ) &&
371- builderSupports (ctx.Id_buildPartialBlock ,
372- {ctx.Id_accumulated , ctx.Id_next },
373- /* checkAvailability*/ true )) {
344+ builder. supports (ctx.Id_buildPartialBlock , {ctx.Id_first },
345+ /* checkAvailability*/ true ) &&
346+ builder. supports (ctx.Id_buildPartialBlock ,
347+ {ctx.Id_accumulated , ctx.Id_next },
348+ /* checkAvailability*/ true )) {
374349 // NOTE: The current implementation uses one-way constraints in between
375350 // subexpressions. It's functionally equivalent to the following:
376351 // let v0 = Builder.buildPartialBlock(first: arg_0)
@@ -391,11 +366,11 @@ class BuilderClosureVisitor
391366 // If `buildBlock` does not exist at this point, it could be the case that
392367 // `buildPartialBlock` did not have the sufficient availability for this
393368 // call site. Diagnose it.
394- else if (!builderSupports (ctx.Id_buildBlock )) {
369+ else if (!builder. supports (ctx.Id_buildBlock )) {
395370 ctx.Diags .diagnose (
396371 braceStmt->getStartLoc (),
397372 diag::result_builder_missing_available_buildpartialblock,
398- builderType );
373+ builder. getType () );
399374 return nullptr ;
400375 }
401376 // Otherwise, call `buildBlock` on all subexpressions.
@@ -462,14 +437,14 @@ class BuilderClosureVisitor
462437 return false ;
463438
464439 // If there's a missing 'else', we need 'buildOptional' to exist.
465- if (isOptional && !builderSupports (buildOptionalId ))
440+ if (isOptional && !builder. supportsOptional ( ))
466441 return false ;
467442
468443 // If there are multiple clauses, we need 'buildEither(first:)' and
469444 // 'buildEither(second:)' to both exist.
470445 if (numPayloads > 1 ) {
471- if (!builderSupports (ctx.Id_buildEither , {ctx.Id_first }) ||
472- !builderSupports (ctx.Id_buildEither , {ctx.Id_second }))
446+ if (!builder. supports (ctx.Id_buildEither , {ctx.Id_first }) ||
447+ !builder. supports (ctx.Id_buildEither , {ctx.Id_second }))
473448 return false ;
474449 }
475450
@@ -543,7 +518,7 @@ class BuilderClosureVisitor
543518 // buildLimitedAvailability(_:).
544519 auto availabilityCond = findAvailabilityCondition (ifStmt->getCond ());
545520 bool supportsAvailability =
546- availabilityCond && builderSupports (ctx.Id_buildLimitedAvailability );
521+ availabilityCond && builder. supports (ctx.Id_buildLimitedAvailability );
547522 if (supportsAvailability &&
548523 !availabilityCond->getAvailability ()->isUnavailability ()) {
549524 thenVarRefExpr = buildCallIfWanted (ifStmt->getThenStmt ()->getEndLoc (),
@@ -592,10 +567,12 @@ class BuilderClosureVisitor
592567 // The operand should have optional type if we had optional results,
593568 // so we just need to call `buildIf` now, since we're at the top level.
594569 if (isOptional && isTopLevel) {
595- thenExpr = buildCallIfWanted (ifStmt->getEndLoc (), buildOptionalId,
596- thenExpr, /* argLabels=*/ { });
597- elseExpr = buildCallIfWanted (ifStmt->getEndLoc (), buildOptionalId,
598- elseExpr, /* argLabels=*/ { });
570+ thenExpr =
571+ buildCallIfWanted (ifStmt->getEndLoc (), builder.getBuildOptionalId (),
572+ thenExpr, /* argLabels=*/ {});
573+ elseExpr =
574+ buildCallIfWanted (ifStmt->getEndLoc (), builder.getBuildOptionalId (),
575+ elseExpr, /* argLabels=*/ {});
599576 }
600577
601578 thenExpr = cs->generateConstraints (thenExpr, dc);
@@ -832,7 +809,7 @@ class BuilderClosureVisitor
832809 VarDecl *visitForEachStmt (ForEachStmt *forEachStmt) {
833810 // for...in statements are handled via buildArray(_:); bail out if the
834811 // builder does not support it.
835- if (!builderSupports (ctx.Id_buildArray )) {
812+ if (!builder. supports (ctx.Id_buildArray )) {
836813 if (!unhandledNode)
837814 unhandledNode = forEachStmt;
838815 return nullptr ;
@@ -2220,3 +2197,17 @@ void swift::printResultBuilderBuildFunction(
22202197 printer << " }" ;
22212198 }
22222199}
2200+
2201+ bool ResultBuilder::supports (Identifier fnBaseName,
2202+ ArrayRef<Identifier> argLabels,
2203+ bool checkAvailability) {
2204+ DeclName name (DC->getASTContext (), fnBaseName, argLabels);
2205+ auto known = SupportedOps.find (name);
2206+ if (known != SupportedOps.end ()) {
2207+ return known->second ;
2208+ }
2209+
2210+ return SupportedOps[name] = TypeChecker::typeSupportsBuilderOp (
2211+ BuilderType, DC, fnBaseName, argLabels, /* allResults*/ {},
2212+ checkAvailability);
2213+ }
0 commit comments