Skip to content

Commit dd1da22

Browse files
committed
[CS] Separate availability checking from SupportedOps cache
Previously we would cache the result of the first query, with any further query of `ResultBuilder::supports` ignoring the `checkAvailability` parameter. Separate out the availability checking such that we compute the information up front, and adjust the result depending on `checkAvailability`.
1 parent 599afbf commit dd1da22

File tree

3 files changed

+79
-23
lines changed

3 files changed

+79
-23
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ enum class FreeTypeVariableBinding {
107107
UnresolvedType
108108
};
109109

110+
/// Describes whether or not a result builder method is supported.
111+
struct ResultBuilderOpSupport {
112+
enum Classification {
113+
Unsupported,
114+
Unavailable,
115+
Supported
116+
};
117+
Classification Kind;
118+
119+
ResultBuilderOpSupport(Classification Kind) : Kind(Kind) {}
120+
121+
/// Returns whether or not the builder method is supported. If
122+
/// \p requireAvailable is true, an unavailable method will be considered
123+
/// unsupported.
124+
bool isSupported(bool requireAvailable) const {
125+
switch (Kind) {
126+
case Unsupported:
127+
return false;
128+
case Unavailable:
129+
return !requireAvailable;
130+
case Supported:
131+
return true;
132+
}
133+
llvm_unreachable("Unhandled case in switch!");
134+
}
135+
};
136+
110137
namespace constraints {
111138

112139
struct ResultBuilder {
@@ -115,7 +142,9 @@ struct ResultBuilder {
115142
/// An implicit variable that represents `Self` type of the result builder.
116143
VarDecl *BuilderSelf;
117144
Type BuilderType;
118-
llvm::SmallDenseMap<DeclName, bool> SupportedOps;
145+
146+
/// Cache of supported result builder operations.
147+
llvm::SmallDenseMap<DeclName, ResultBuilderOpSupport> SupportedOps;
119148

120149
Identifier BuildOptionalId;
121150

lib/Sema/BuilderTransform.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2770,11 +2770,22 @@ std::vector<ReturnStmt *> TypeChecker::findReturnStatements(AnyFunctionRef fn) {
27702770
return precheck.getReturnStmts();
27712771
}
27722772

2773-
bool TypeChecker::typeSupportsBuilderOp(
2773+
ResultBuilderOpSupport TypeChecker::checkBuilderOpSupport(
27742774
Type builderType, DeclContext *dc, Identifier fnName,
2775-
ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults,
2776-
bool checkAvailability) {
2775+
ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults) {
2776+
2777+
auto isUnavailable = [&](Decl *D) -> bool {
2778+
if (AvailableAttr::isUnavailable(D))
2779+
return true;
2780+
2781+
auto loc = extractNearestSourceLoc(dc);
2782+
auto context = ExportContext::forFunctionBody(dc, loc);
2783+
return TypeChecker::checkDeclarationAvailability(D, context).hasValue();
2784+
};
2785+
27772786
bool foundMatch = false;
2787+
bool foundUnavailable = false;
2788+
27782789
SmallVector<ValueDecl *, 4> foundDecls;
27792790
dc->lookupQualified(
27802791
builderType, DeclNameRef(fnName),
@@ -2793,17 +2804,12 @@ bool TypeChecker::typeSupportsBuilderOp(
27932804
continue;
27942805
}
27952806

2796-
// If we are checking availability, the candidate must have enough
2797-
// availability in the calling context.
2798-
if (checkAvailability) {
2799-
if (AvailableAttr::isUnavailable(func))
2800-
continue;
2801-
if (TypeChecker::checkDeclarationAvailability(
2802-
func, ExportContext::forFunctionBody(
2803-
dc, extractNearestSourceLoc(dc))))
2804-
continue;
2807+
// Check if the the candidate has a suitable availability for the
2808+
// calling context.
2809+
if (isUnavailable(func)) {
2810+
foundUnavailable = true;
2811+
continue;
28052812
}
2806-
28072813
foundMatch = true;
28082814
break;
28092815
}
@@ -2812,7 +2818,18 @@ bool TypeChecker::typeSupportsBuilderOp(
28122818
if (allResults)
28132819
allResults->append(foundDecls.begin(), foundDecls.end());
28142820

2815-
return foundMatch;
2821+
if (!foundMatch) {
2822+
return foundUnavailable ? ResultBuilderOpSupport::Unavailable
2823+
: ResultBuilderOpSupport::Unsupported;
2824+
}
2825+
return ResultBuilderOpSupport::Supported;
2826+
}
2827+
2828+
bool TypeChecker::typeSupportsBuilderOp(
2829+
Type builderType, DeclContext *dc, Identifier fnName,
2830+
ArrayRef<Identifier> argLabels, SmallVectorImpl<ValueDecl *> *allResults) {
2831+
return checkBuilderOpSupport(builderType, dc, fnName, argLabels, allResults)
2832+
.isSupported(/*requireAvailable*/ false);
28162833
}
28172834

28182835
Type swift::inferResultBuilderComponentType(NominalTypeDecl *builder) {
@@ -2976,13 +2993,13 @@ bool ResultBuilder::supports(Identifier fnBaseName,
29762993
bool checkAvailability) {
29772994
DeclName name(DC->getASTContext(), fnBaseName, argLabels);
29782995
auto known = SupportedOps.find(name);
2979-
if (known != SupportedOps.end()) {
2980-
return known->second;
2981-
}
2996+
if (known != SupportedOps.end())
2997+
return known->second.isSupported(checkAvailability);
29822998

2983-
return SupportedOps[name] = TypeChecker::typeSupportsBuilderOp(
2984-
BuilderType, DC, fnBaseName, argLabels, /*allResults*/ {},
2985-
checkAvailability);
2999+
auto support = TypeChecker::checkBuilderOpSupport(
3000+
BuilderType, DC, fnBaseName, argLabels, /*allResults*/ {});
3001+
SupportedOps.insert({name, support});
3002+
return support.isSupported(checkAvailability);
29863003
}
29873004

29883005
Expr *ResultBuilder::buildCall(SourceLoc loc, Identifier fnName,

lib/Sema/TypeChecker.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,10 +1234,20 @@ UnresolvedMemberExpr *getUnresolvedMemberChainBase(Expr *expr);
12341234
/// Checks whether a result builder type has a well-formed result builder
12351235
/// method with the given name. If provided and non-empty, the argument labels
12361236
/// are verified against any candidates.
1237+
ResultBuilderOpSupport
1238+
checkBuilderOpSupport(Type builderType, DeclContext *dc, Identifier fnName,
1239+
ArrayRef<Identifier> argLabels = {},
1240+
SmallVectorImpl<ValueDecl *> *allResults = nullptr);
1241+
1242+
/// Checks whether a result builder type has a well-formed result builder
1243+
/// method with the given name. If provided and non-empty, the argument labels
1244+
/// are verified against any candidates.
1245+
///
1246+
/// This will return \c true even if the builder method is unavailable. Use
1247+
/// \c checkBuilderOpSupport if availability should be checked.
12371248
bool typeSupportsBuilderOp(Type builderType, DeclContext *dc, Identifier fnName,
12381249
ArrayRef<Identifier> argLabels = {},
1239-
SmallVectorImpl<ValueDecl *> *allResults = nullptr,
1240-
bool checkAvailability = false);
1250+
SmallVectorImpl<ValueDecl *> *allResults = nullptr);
12411251

12421252
/// Forces all changes specified by the module's access notes file to be
12431253
/// applied to this declaration. It is safe to call this function more than

0 commit comments

Comments
 (0)