Skip to content

Commit 3b8656d

Browse files
committed
[Function builders] Add stubs for missing buildBlock and buildLimitedAvailability
The lack of these functions in a function builder is diagnosed in different places in the type checker. Extend these diagnostics to provide stubs in the function builder. Thanks to Suyash for the suggestion!
1 parent 25cd671 commit 3b8656d

7 files changed

+85
-16
lines changed

include/swift/AST/DiagnosticsSema.def

+3
Original file line numberDiff line numberDiff line change
@@ -5321,6 +5321,9 @@ NOTE(function_builder_missing_build_either, none,
53215321
NOTE(function_builder_missing_build_array, none,
53225322
"add 'buildArray(_:)' to the function builder %0 to add support for "
53235323
"'for'..'in' loops", (Type))
5324+
NOTE(function_builder_missing_build_limited_availability, none,
5325+
"add 'buildLimitedAvailability(_:)' to the function "
5326+
"builder %0 to erase type information for less-available types", (Type))
53245327

53255328
//------------------------------------------------------------------------------
53265329
// MARK: Tuple Shuffle Diagnostics

include/swift/Sema/IDETypeChecking.h

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Identifier.h"
2323
#include "swift/Basic/SourceLoc.h"
2424
#include <memory>
25+
#include <tuple>
2526

2627
namespace swift {
2728
class AbstractFunctionDecl;
@@ -277,6 +278,11 @@ namespace swift {
277278
NominalTypeDecl *builder, Type componentType,
278279
FunctionBuilderBuildFunction function,
279280
Optional<std::string> stubIndent, llvm::raw_ostream &out);
281+
282+
/// Compute the insertion location, indentation string, and component type
283+
/// for a Fix-It that adds a new build* function to a function builder.
284+
std::tuple<SourceLoc, std::string, Type>
285+
determineFunctionBuilderBuildFixItInfo(NominalTypeDecl *builder);
280286
}
281287

282288
#endif

lib/Sema/BuilderTransform.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,32 @@ class BuilderClosureRewriter
12471247
ctx.Diags.diagnose(
12481248
loc, diag::function_builder_missing_limited_availability,
12491249
builderTransform.builderType);
1250+
1251+
// Add a note to the function builder with a stub for
1252+
// buildLimitedAvailability().
1253+
if (auto builder = builderTransform.builderType->getAnyNominal()) {
1254+
SourceLoc buildInsertionLoc;
1255+
std::string stubIndent;
1256+
Type componentType;
1257+
std::tie(buildInsertionLoc, stubIndent, componentType) =
1258+
determineFunctionBuilderBuildFixItInfo(builder);
1259+
if (buildInsertionLoc.isValid()) {
1260+
std::string fixItString;
1261+
{
1262+
llvm::raw_string_ostream out(fixItString);
1263+
printFunctionBuilderBuildFunction(
1264+
builder, componentType,
1265+
FunctionBuilderBuildFunction::BuildLimitedAvailability,
1266+
stubIndent, out);
1267+
1268+
builder->diagnose(
1269+
diag::function_builder_missing_build_limited_availability,
1270+
builderTransform.builderType)
1271+
.fixItInsert(buildInsertionLoc, fixItString);
1272+
}
1273+
}
1274+
}
1275+
12501276
return true;
12511277
}
12521278

@@ -1917,6 +1943,28 @@ Type swift::inferFunctionBuilderComponentType(NominalTypeDecl *builder) {
19171943
return componentType;
19181944
}
19191945

1946+
std::tuple<SourceLoc, std::string, Type>
1947+
swift::determineFunctionBuilderBuildFixItInfo(NominalTypeDecl *builder) {
1948+
SourceLoc buildInsertionLoc = builder->getBraces().Start;
1949+
std::string stubIndent;
1950+
Type componentType;
1951+
1952+
if (buildInsertionLoc.isInvalid())
1953+
return std::make_tuple(buildInsertionLoc, stubIndent, componentType);
1954+
1955+
ASTContext &ctx = builder->getASTContext();
1956+
buildInsertionLoc = Lexer::getLocForEndOfToken(
1957+
ctx.SourceMgr, buildInsertionLoc);
1958+
1959+
StringRef extraIndent;
1960+
StringRef currentIndent = Lexer::getIndentationForLine(
1961+
ctx.SourceMgr, buildInsertionLoc, &extraIndent);
1962+
stubIndent = (currentIndent + extraIndent).str();
1963+
1964+
componentType = inferFunctionBuilderComponentType(builder);
1965+
return std::make_tuple(buildInsertionLoc, stubIndent, componentType);
1966+
}
1967+
19201968
void swift::printFunctionBuilderBuildFunction(
19211969
NominalTypeDecl *builder, Type componentType,
19221970
FunctionBuilderBuildFunction function,

lib/Sema/CSDiagnostics.cpp

+3-13
Original file line numberDiff line numberDiff line change
@@ -5511,21 +5511,11 @@ void SkipUnhandledConstructInFunctionBuilderFailure::diagnosePrimary(
55115511

55125512
// Emit custom notes to help the user introduce the appropriate 'build'
55135513
// functions.
5514-
SourceLoc buildInsertionLoc = builder->getBraces().Start;
5514+
SourceLoc buildInsertionLoc;
55155515
std::string stubIndent;
55165516
Type componentType;
5517-
if (buildInsertionLoc.isValid()) {
5518-
buildInsertionLoc = Lexer::getLocForEndOfToken(
5519-
getASTContext().SourceMgr, buildInsertionLoc);
5520-
5521-
ASTContext &ctx = getASTContext();
5522-
StringRef extraIndent;
5523-
StringRef currentIndent = Lexer::getIndentationForLine(
5524-
ctx.SourceMgr, buildInsertionLoc, &extraIndent);
5525-
stubIndent = (currentIndent + extraIndent).str();
5526-
5527-
componentType = inferFunctionBuilderComponentType(builder);
5528-
}
5517+
std::tie(buildInsertionLoc, stubIndent, componentType) =
5518+
determineFunctionBuilderBuildFixItInfo(builder);
55295519

55305520
if (buildInsertionLoc.isInvalid()) {
55315521
// Do nothing.

lib/Sema/TypeCheckAttr.cpp

+23-1
Original file line numberDiff line numberDiff line change
@@ -3024,7 +3024,29 @@ void AttributeChecker::visitFunctionBuilderAttr(FunctionBuilderAttr *attr) {
30243024
/*argLabels=*/{}, &potentialMatches);
30253025

30263026
if (!supportsBuildBlock) {
3027-
diagnose(nominal->getLoc(), diag::function_builder_static_buildblock);
3027+
{
3028+
auto diag = diagnose(
3029+
nominal->getLoc(), diag::function_builder_static_buildblock);
3030+
3031+
// If there were no close matches, propose adding a stub.
3032+
SourceLoc buildInsertionLoc;
3033+
std::string stubIndent;
3034+
Type componentType;
3035+
std::tie(buildInsertionLoc, stubIndent, componentType) =
3036+
determineFunctionBuilderBuildFixItInfo(nominal);
3037+
if (buildInsertionLoc.isValid() && potentialMatches.empty()) {
3038+
std::string fixItString;
3039+
{
3040+
llvm::raw_string_ostream out(fixItString);
3041+
printFunctionBuilderBuildFunction(
3042+
nominal, componentType,
3043+
FunctionBuilderBuildFunction::BuildBlock,
3044+
stubIndent, out);
3045+
}
3046+
3047+
diag.fixItInsert(buildInsertionLoc, fixItString);
3048+
}
3049+
}
30283050

30293051
// For any close matches, attempt to explain to the user why they aren't
30303052
// valid.

test/Constraints/function_builder_availability.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ enum Either<T,U> {
88
}
99

1010
@_functionBuilder
11-
struct TupleBuilder {
11+
struct TupleBuilder { // expected-note{{add 'buildLimitedAvailability(_:)' to the function builder 'TupleBuilder' to erase type information for less-available types}}{{22-22=\n static func buildLimitedAvailability(_ component: <#Component#>) -> <#Component#> {\n <#code#>\n \}}}
1212
static func buildBlock<T1>(_ t1: T1) -> (T1) {
1313
return (t1)
1414
}

test/decl/var/function_builders.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var globalBuilder: Int
77
func globalBuilderFunction() -> Int { return 0 }
88

99
@_functionBuilder
10-
struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}}
10+
struct Maker {} // expected-error {{function builder must provide at least one static 'buildBlock' method}}{{15-15=\n static func buildBlock(_ components: <#Component#>...) -> <#Component#> {\n <#code#>\n \}}}
1111

1212
@_functionBuilder
1313
class Inventor {} // expected-error {{function builder must provide at least one static 'buildBlock' method}}

0 commit comments

Comments
 (0)