@@ -432,12 +432,7 @@ class BuilderClosureVisitor
432
432
// If the builder supports `buildPartialBlock(first:)` and
433
433
// `buildPartialBlock(accumulated:next:)`, use this to combine
434
434
// subexpressions pairwise.
435
- if (!expressions.empty () &&
436
- builder.supports (ctx.Id_buildPartialBlock , {ctx.Id_first },
437
- /* checkAvailability*/ true ) &&
438
- builder.supports (ctx.Id_buildPartialBlock ,
439
- {ctx.Id_accumulated , ctx.Id_next },
440
- /* checkAvailability*/ true )) {
435
+ if (!expressions.empty () && builder.canUseBuildPartialBlock ()) {
441
436
// NOTE: The current implementation uses one-way constraints in between
442
437
// subexpressions. It's functionally equivalent to the following:
443
438
// let v0 = Builder.buildPartialBlock(first: arg_0)
@@ -1087,12 +1082,7 @@ class ResultBuilderTransform
1087
1082
// If the builder supports `buildPartialBlock(first:)` and
1088
1083
// `buildPartialBlock(accumulated:next:)`, use this to combine
1089
1084
// sub-expressions pairwise.
1090
- if (!buildBlockArguments.empty () &&
1091
- builder.supports (ctx.Id_buildPartialBlock , {ctx.Id_first },
1092
- /* checkAvailability*/ true ) &&
1093
- builder.supports (ctx.Id_buildPartialBlock ,
1094
- {ctx.Id_accumulated , ctx.Id_next },
1095
- /* checkAvailability*/ true )) {
1085
+ if (!buildBlockArguments.empty () && builder.canUseBuildPartialBlock ()) {
1096
1086
// let v0 = Builder.buildPartialBlock(first: arg_0)
1097
1087
// let v1 = Builder.buildPartialBlock(accumulated: v0, next: arg_1)
1098
1088
// ...
@@ -2777,11 +2767,22 @@ std::vector<ReturnStmt *> TypeChecker::findReturnStatements(AnyFunctionRef fn) {
2777
2767
return precheck.getReturnStmts ();
2778
2768
}
2779
2769
2780
- bool TypeChecker::typeSupportsBuilderOp (
2770
+ ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport (
2781
2771
Type builderType, DeclContext *dc, Identifier fnName,
2782
- ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults,
2783
- bool checkAvailability) {
2772
+ ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults) {
2773
+
2774
+ auto isUnavailable = [&](Decl *D) -> bool {
2775
+ if (AvailableAttr::isUnavailable (D))
2776
+ return true ;
2777
+
2778
+ auto loc = extractNearestSourceLoc (dc);
2779
+ auto context = ExportContext::forFunctionBody (dc, loc);
2780
+ return TypeChecker::checkDeclarationAvailability (D, context).hasValue ();
2781
+ };
2782
+
2784
2783
bool foundMatch = false ;
2784
+ bool foundUnavailable = false ;
2785
+
2785
2786
SmallVector<ValueDecl *, 4 > foundDecls;
2786
2787
dc->lookupQualified (
2787
2788
builderType, DeclNameRef (fnName),
@@ -2800,17 +2801,12 @@ bool TypeChecker::typeSupportsBuilderOp(
2800
2801
continue ;
2801
2802
}
2802
2803
2803
- // If we are checking availability, the candidate must have enough
2804
- // availability in the calling context.
2805
- if (checkAvailability) {
2806
- if (AvailableAttr::isUnavailable (func))
2807
- continue ;
2808
- if (TypeChecker::checkDeclarationAvailability (
2809
- func, ExportContext::forFunctionBody (
2810
- dc, extractNearestSourceLoc (dc))))
2811
- continue ;
2804
+ // Check if the the candidate has a suitable availability for the
2805
+ // calling context.
2806
+ if (isUnavailable (func)) {
2807
+ foundUnavailable = true ;
2808
+ continue ;
2812
2809
}
2813
-
2814
2810
foundMatch = true ;
2815
2811
break ;
2816
2812
}
@@ -2819,7 +2815,24 @@ bool TypeChecker::typeSupportsBuilderOp(
2819
2815
if (allResults)
2820
2816
allResults->append (foundDecls.begin (), foundDecls.end ());
2821
2817
2822
- return foundMatch;
2818
+ if (!foundMatch) {
2819
+ return foundUnavailable ? ResultBuilderOpSupport::Unavailable
2820
+ : ResultBuilderOpSupport::Unsupported;
2821
+ }
2822
+ // If the builder type itself isn't available, don't consider any builder
2823
+ // method available.
2824
+ if (auto *D = builderType->getAnyNominal ()) {
2825
+ if (isUnavailable (D))
2826
+ return ResultBuilderOpSupport::Unavailable;
2827
+ }
2828
+ return ResultBuilderOpSupport::Supported;
2829
+ }
2830
+
2831
+ bool TypeChecker::typeSupportsBuilderOp (
2832
+ Type builderType, DeclContext *dc, Identifier fnName,
2833
+ ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults) {
2834
+ return checkBuilderOpSupport (builderType, dc, fnName, argLabels, allResults)
2835
+ .isSupported (/* requireAvailable*/ false );
2823
2836
}
2824
2837
2825
2838
Type swift::inferResultBuilderComponentType (NominalTypeDecl *builder) {
@@ -2978,18 +2991,43 @@ ResultBuilder::ResultBuilder(ConstraintSystem *CS, DeclContext *DC,
2978
2991
}
2979
2992
}
2980
2993
2994
+ bool ResultBuilder::supportsBuildPartialBlock (bool checkAvailability) {
2995
+ auto &ctx = DC->getASTContext ();
2996
+ return supports (ctx.Id_buildPartialBlock , {ctx.Id_first },
2997
+ checkAvailability) &&
2998
+ supports (ctx.Id_buildPartialBlock , {ctx.Id_accumulated , ctx.Id_next },
2999
+ checkAvailability);
3000
+ }
3001
+
3002
+ bool ResultBuilder::canUseBuildPartialBlock () {
3003
+ // If buildPartialBlock doesn't exist at all, we can't use it.
3004
+ if (!supportsBuildPartialBlock (/* checkAvailability*/ false ))
3005
+ return false ;
3006
+
3007
+ // If buildPartialBlock exists and is available, use it.
3008
+ if (supportsBuildPartialBlock (/* checkAvailability*/ true ))
3009
+ return true ;
3010
+
3011
+ // We have buildPartialBlock, but it is unavailable. We can however still
3012
+ // use it if buildBlock is also unavailable.
3013
+ auto &ctx = DC->getASTContext ();
3014
+ return supports (ctx.Id_buildBlock ) &&
3015
+ !supports (ctx.Id_buildBlock , /* labels*/ {},
3016
+ /* checkAvailability*/ true );
3017
+ }
3018
+
2981
3019
bool ResultBuilder::supports (Identifier fnBaseName,
2982
3020
ArrayRef<Identifier> argLabels,
2983
3021
bool checkAvailability) {
2984
3022
DeclName name (DC->getASTContext (), fnBaseName, argLabels);
2985
3023
auto known = SupportedOps.find (name);
2986
- if (known != SupportedOps.end ()) {
2987
- return known->second ;
2988
- }
3024
+ if (known != SupportedOps.end ())
3025
+ return known->second .isSupported (checkAvailability);
2989
3026
2990
- return SupportedOps[name] = TypeChecker::typeSupportsBuilderOp (
2991
- BuilderType, DC, fnBaseName, argLabels, /* allResults*/ {},
2992
- checkAvailability);
3027
+ auto support = TypeChecker::checkBuilderOpSupport (
3028
+ BuilderType, DC, fnBaseName, argLabels, /* allResults*/ {});
3029
+ SupportedOps.insert ({name, support});
3030
+ return support.isSupported (checkAvailability);
2993
3031
}
2994
3032
2995
3033
Expr *ResultBuilder::buildCall (SourceLoc loc, Identifier fnName,
0 commit comments