@@ -68,10 +68,8 @@ class BuilderClosureVisitor
68
68
ConstraintSystem *cs;
69
69
DeclContext *dc;
70
70
ASTContext &ctx;
71
- Type builderType;
72
- NominalTypeDecl *builder = nullptr ;
73
- Identifier buildOptionalId;
74
- llvm::SmallDenseMap<DeclName, bool > supportedOps;
71
+
72
+ ResultBuilder builder;
75
73
76
74
// / The variable used as a base for all `build*` operations added
77
75
// / by this transform.
@@ -121,21 +119,6 @@ class BuilderClosureVisitor
121
119
return CallExpr::createImplicit (ctx, memberRef, argList);
122
120
}
123
121
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
-
139
122
// / Build an implicit variable in this context.
140
123
VarDecl *buildVar (SourceLoc loc) {
141
124
// Create the implicit variable.
@@ -192,27 +175,19 @@ class BuilderClosureVisitor
192
175
public:
193
176
BuilderClosureVisitor (ASTContext &ctx, ConstraintSystem *cs, DeclContext *dc,
194
177
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 () ;
198
181
applied.bodyResultType = bodyResultType;
199
182
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
-
208
183
// If we are about to generate constraints, let's establish builder
209
184
// variable for the base of `build*` calls.
210
185
if (cs) {
211
186
builderVar = new (ctx) VarDecl (
212
187
/* isStatic=*/ false , VarDecl::Introducer::Let,
213
188
/* nameLoc=*/ SourceLoc (), ctx.Id_builderSelf , dc);
214
189
builderVar->setImplicit ();
215
- cs->setType (builderVar, MetatypeType::get (cs-> simplifyType (builderType )));
190
+ cs->setType (builderVar, MetatypeType::get (builder. getType ( )));
216
191
}
217
192
}
218
193
@@ -226,7 +201,7 @@ class BuilderClosureVisitor
226
201
227
202
// If there is a buildFinalResult(_:), call it.
228
203
ASTContext &ctx = cs->getASTContext ();
229
- if (builderSupports (ctx.Id_buildFinalResult , { Identifier () })) {
204
+ if (builder. supports (ctx.Id_buildFinalResult , {Identifier ()})) {
230
205
applied.returnExpr = buildCallIfWanted (
231
206
applied.returnExpr ->getLoc (), ctx.Id_buildFinalResult ,
232
207
{ applied.returnExpr }, { Identifier () });
@@ -350,7 +325,7 @@ class BuilderClosureVisitor
350
325
}
351
326
352
327
auto expr = node.get <Expr *>();
353
- if (cs && builderSupports (ctx.Id_buildExpression )) {
328
+ if (cs && builder. supports (ctx.Id_buildExpression )) {
354
329
expr = buildCallIfWanted (expr->getLoc (), ctx.Id_buildExpression ,
355
330
{ expr }, { Identifier () });
356
331
}
@@ -366,11 +341,11 @@ class BuilderClosureVisitor
366
341
// `buildPartialBlock(accumulated:next:)`, use this to combine
367
342
// subexpressions pairwise.
368
343
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 )) {
374
349
// NOTE: The current implementation uses one-way constraints in between
375
350
// subexpressions. It's functionally equivalent to the following:
376
351
// let v0 = Builder.buildPartialBlock(first: arg_0)
@@ -391,11 +366,11 @@ class BuilderClosureVisitor
391
366
// If `buildBlock` does not exist at this point, it could be the case that
392
367
// `buildPartialBlock` did not have the sufficient availability for this
393
368
// call site. Diagnose it.
394
- else if (!builderSupports (ctx.Id_buildBlock )) {
369
+ else if (!builder. supports (ctx.Id_buildBlock )) {
395
370
ctx.Diags .diagnose (
396
371
braceStmt->getStartLoc (),
397
372
diag::result_builder_missing_available_buildpartialblock,
398
- builderType );
373
+ builder. getType () );
399
374
return nullptr ;
400
375
}
401
376
// Otherwise, call `buildBlock` on all subexpressions.
@@ -462,14 +437,14 @@ class BuilderClosureVisitor
462
437
return false ;
463
438
464
439
// If there's a missing 'else', we need 'buildOptional' to exist.
465
- if (isOptional && !builderSupports (buildOptionalId ))
440
+ if (isOptional && !builder. supportsOptional ( ))
466
441
return false ;
467
442
468
443
// If there are multiple clauses, we need 'buildEither(first:)' and
469
444
// 'buildEither(second:)' to both exist.
470
445
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 }))
473
448
return false ;
474
449
}
475
450
@@ -543,7 +518,7 @@ class BuilderClosureVisitor
543
518
// buildLimitedAvailability(_:).
544
519
auto availabilityCond = findAvailabilityCondition (ifStmt->getCond ());
545
520
bool supportsAvailability =
546
- availabilityCond && builderSupports (ctx.Id_buildLimitedAvailability );
521
+ availabilityCond && builder. supports (ctx.Id_buildLimitedAvailability );
547
522
if (supportsAvailability &&
548
523
!availabilityCond->getAvailability ()->isUnavailability ()) {
549
524
thenVarRefExpr = buildCallIfWanted (ifStmt->getThenStmt ()->getEndLoc (),
@@ -592,10 +567,12 @@ class BuilderClosureVisitor
592
567
// The operand should have optional type if we had optional results,
593
568
// so we just need to call `buildIf` now, since we're at the top level.
594
569
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=*/ {});
599
576
}
600
577
601
578
thenExpr = cs->generateConstraints (thenExpr, dc);
@@ -832,7 +809,7 @@ class BuilderClosureVisitor
832
809
VarDecl *visitForEachStmt (ForEachStmt *forEachStmt) {
833
810
// for...in statements are handled via buildArray(_:); bail out if the
834
811
// builder does not support it.
835
- if (!builderSupports (ctx.Id_buildArray )) {
812
+ if (!builder. supports (ctx.Id_buildArray )) {
836
813
if (!unhandledNode)
837
814
unhandledNode = forEachStmt;
838
815
return nullptr ;
@@ -2220,3 +2197,17 @@ void swift::printResultBuilderBuildFunction(
2220
2197
printer << " }" ;
2221
2198
}
2222
2199
}
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