Skip to content

Commit cb06d5a

Browse files
committed
Support nested examples like @Array.Builder
1 parent e5002b2 commit cb06d5a

4 files changed

Lines changed: 98 additions & 46 deletions

File tree

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7798,7 +7798,7 @@ NOTE(result_builder_infer_pick_specific, none,
77987798
"apply result builder %0 (inferred from %select{protocol|dynamic replacement of}1 %2)",
77997799
(Type, unsigned, DeclName))
78007800
ERROR(result_builder_generic_inference_failed, none,
7801-
"unable to infer generic parameters for result builder %0", (DeclName))
7801+
"unable to infer generic parameters for result builder %0", (DeclAttribute))
78027802
GROUPED_WARNING(result_builder_missing_limited_availability,
78037803
ResultBuilderMethods, none,
78047804
"result builder %0 does not implement 'buildLimitedAvailability'; "

lib/Sema/TypeCheckType.cpp

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6984,47 +6984,33 @@ struct ResultBuilderUnboundTypeOpener {
69846984
CustomAttr *attr;
69856985

69866986
Type operator()(UnboundGenericType *unboundTy) const {
6987-
auto resultBuilderDecl =
6988-
dyn_cast_or_null<NominalTypeDecl>(unboundTy->getDecl());
6989-
if (!resultBuilderDecl ||
6990-
!resultBuilderDecl->getAttrs().hasAttribute<ResultBuilderAttr>()) {
6991-
return invalidResultBuilderType(unboundTy);
6987+
auto resultBuilderDecl = attr->getNominalDecl();
6988+
if (!resultBuilderDecl) {
6989+
return invalidResultBuilderType();
69926990
}
69936991

6994-
Decl *owningDecl = attr->getOwner().getAsDecl();
6995-
if (!owningDecl) {
6996-
return invalidResultBuilderType(unboundTy);
6997-
}
6998-
6999-
// Retrieve the return type of the owning declaration that
7000-
// provides type inference for the result builder type.
7001-
Type owningDeclResultType;
7002-
if (auto varDecl = dyn_cast<VarDecl>(owningDecl)) {
7003-
if (auto closureResultType =
7004-
varDecl->getInterfaceType()->getAs<FunctionType>()) {
7005-
owningDeclResultType = closureResultType->getResult();
7006-
} else {
7007-
owningDeclResultType = varDecl->getInterfaceType();
7008-
}
7009-
} else if (auto funcDecl = dyn_cast<FuncDecl>(owningDecl)) {
7010-
owningDeclResultType = funcDecl->getResultInterfaceType();
6992+
auto unboundTyDecl =
6993+
dyn_cast_or_null<NominalTypeDecl>(unboundTy->getDecl());
6994+
if (!resultBuilderDecl) {
6995+
return invalidResultBuilderType();
70116996
}
70126997

7013-
if (!owningDeclResultType) {
7014-
return invalidResultBuilderType(unboundTy);
6998+
auto owningDeclReturnType = getOwningDeclReturnType();
6999+
if (!owningDeclReturnType) {
7000+
return invalidResultBuilderType();
70157001
}
70167002

70177003
// Retrieve the supported result types of the result builder.
7018-
auto resultTypes = retrieveResultBuilderResultTypes(resultBuilderDecl);
7004+
auto resultTypes = getResultBuilderResultTypes(resultBuilderDecl);
70197005
if (resultTypes.empty()) {
7020-
return invalidResultBuilderType(unboundTy);
7006+
return invalidResultBuilderType();
70217007
}
70227008

7023-
auto genericSig = resultBuilderDecl->getGenericSignature();
7009+
auto genericSig = unboundTyDecl->getGenericSignature();
70247010

70257011
// Try each result type and return the first one that
70267012
// produces a valid solution.
7027-
for (auto componentType : resultTypes) {
7013+
for (auto resultType : resultTypes) {
70287014
using namespace constraints;
70297015

70307016
// Avoid recording failed constraints, which are not used here.
@@ -7038,7 +7024,7 @@ struct ResultBuilderUnboundTypeOpener {
70387024
llvm::SmallVector<TypeVariableType *, 8> typeVars;
70397025
for (unsigned i = 0; i < genericSig.getGenericParams().size(); ++i) {
70407026
auto locator = cs.getConstraintLocator(
7041-
resultBuilderDecl, {ConstraintLocator::GenericArgument, i});
7027+
unboundTyDecl, {ConstraintLocator::GenericArgument, i});
70427028
auto typeVar = cs.createTypeVariable(locator, TVO_CanBindToHole);
70437029
typeVarReplacements.push_back(typeVar);
70447030
typeVars.push_back(typeVar);
@@ -7049,12 +7035,12 @@ struct ResultBuilderUnboundTypeOpener {
70497035
auto subMap = SubstitutionMap::get(genericSig, typeVarReplacements,
70507036
LookUpConformanceInModule());
70517037

7052-
auto componentTypeWithTypeVars = componentType.subst(subMap);
7038+
auto resultTypeWithTypeVars = resultType.subst(subMap);
70537039

70547040
// The result builder result type should be equal to the return type of
70557041
// the attached declaration.
7056-
cs.addConstraint(ConstraintKind::Equal, owningDeclResultType,
7057-
componentTypeWithTypeVars,
7042+
cs.addConstraint(ConstraintKind::Equal, owningDeclReturnType,
7043+
resultTypeWithTypeVars,
70587044
/*preparedOverload:*/ nullptr);
70597045

70607046
auto solution = cs.solveSingle();
@@ -7067,30 +7053,52 @@ struct ResultBuilderUnboundTypeOpener {
70677053
solvedReplacements.push_back(solution->typeBindings[typeVar]);
70687054
}
70697055

7070-
return BoundGenericType::get(resultBuilderDecl, unboundTy->getParent(),
7056+
return BoundGenericType::get(unboundTyDecl, unboundTy->getParent(),
70717057
solvedReplacements);
70727058
}
70737059
}
70747060

70757061
// No result type produced a valid solution
7076-
return invalidResultBuilderType(unboundTy);
7062+
return invalidResultBuilderType();
70777063
}
70787064

70797065
private:
7080-
Type invalidResultBuilderType(UnboundGenericType *unboundTy) const {
7066+
Type invalidResultBuilderType() const {
70817067
dc->getASTContext().Diags.diagnose(
70827068
attr->getTypeExpr()->getLoc(),
7083-
diag::result_builder_generic_inference_failed,
7084-
unboundTy->getDecl()->getName());
7069+
diag::result_builder_generic_inference_failed, attr);
70857070

70867071
return ErrorType::get(dc->getASTContext());
70877072
}
70887073

7074+
/// Retrieve the return type of the owning declaration that
7075+
/// provides type inference for the result builder type.
7076+
Type getOwningDeclReturnType() const {
7077+
Decl *owningDecl = attr->getOwner().getAsDecl();
7078+
if (!owningDecl) {
7079+
return nullptr;
7080+
}
7081+
7082+
Type owningDeclReturnType;
7083+
if (auto varDecl = dyn_cast<VarDecl>(owningDecl)) {
7084+
if (auto closureResultType =
7085+
varDecl->getInterfaceType()->getAs<FunctionType>()) {
7086+
owningDeclReturnType = closureResultType->getResult();
7087+
} else {
7088+
owningDeclReturnType = varDecl->getInterfaceType();
7089+
}
7090+
} else if (auto funcDecl = dyn_cast<FuncDecl>(owningDecl)) {
7091+
owningDeclReturnType = funcDecl->getResultInterfaceType();
7092+
}
7093+
7094+
return owningDeclReturnType;
7095+
}
7096+
70897097
/// Retrieves the valid result types of the result builder
70907098
/// (the return types of `buildFinalResult` / `buildBlock` /
70917099
/// `buildPartialBlock`).
70927100
llvm::SmallVector<Type, 4>
7093-
retrieveResultBuilderResultTypes(NominalTypeDecl *builder) const {
7101+
getResultBuilderResultTypes(NominalTypeDecl *builder) const {
70947102
ASTContext &ctx = builder->getASTContext();
70957103
llvm::SmallVector<Type, 4> resultTypes;
70967104

test/Constraints/result_builder_diags.swift

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ func testInferResultBuilderGenerics() {
11191119
print(makeArray())
11201120
}
11211121

1122-
@SimpleArrayBuilder // expected-error{{unable to infer generic parameters for result builder 'SimpleArrayBuilder'}}
1122+
@SimpleArrayBuilder // expected-error{{unable to infer generic parameters for result builder @SimpleArrayBuilder}}
11231123
var string: String {
11241124
"foo"
11251125
}
@@ -1167,7 +1167,7 @@ func testInferResultBuilderGenerics() {
11671167
}
11681168
}
11691169

1170-
@TooManyArgsBuilder // expected-error {{unable to infer generic parameters for result builder 'TooManyArgsBuilder'}}
1170+
@TooManyArgsBuilder // expected-error {{unable to infer generic parameters for result builder @TooManyArgsBuilder}}
11711171
var invalidTupleArray: [(String, Int)] {
11721172
("foo", 1) // expected-warning {{expression of type '(String, Int)' is unused}}
11731173
("bar", 2) // expected-warning {{expression of type '(String, Int)' is unused}}
@@ -1235,7 +1235,7 @@ func testInferResultBuilderGenerics() {
12351235
"d"
12361236
}
12371237

1238-
@CollectionBuilder // expected-error {{unable to infer generic parameters for result builder 'CollectionBuilder'}}
1238+
@CollectionBuilder // expected-error {{unable to infer generic parameters for result builder @CollectionBuilder}}
12391239
var contiguousArray: ContiguousArray<String> {
12401240
"c" // expected-warning {{string literal is unused}}
12411241
"d" // expected-warning {{string literal is unused}}
@@ -1255,7 +1255,7 @@ extension Array {
12551255
self = build3()
12561256
}
12571257

1258-
init(@SimpleArrayBuilder build3: () -> ContiguousArray<Element>) { // expected-error {{unable to infer generic parameters for result builder 'SimpleArrayBuilder'}}
1258+
init(@SimpleArrayBuilder build3: () -> ContiguousArray<Element>) { // expected-error {{unable to infer generic parameters for result builder @SimpleArrayBuilder}}
12591259
self = Array(build3())
12601260
}
12611261
}
@@ -1269,7 +1269,51 @@ extension Set {
12691269
self = Set(build2())
12701270
}
12711271

1272-
init(@SimpleArrayBuilder build3: () -> Self) { // expected-error {{unable to infer generic parameters for result builder 'SimpleArrayBuilder'}}
1272+
init(@SimpleArrayBuilder build3: () -> Self) { // expected-error {{unable to infer generic parameters for result builder @SimpleArrayBuilder}}
12731273
self = build3()
12741274
}
12751275
}
1276+
1277+
extension Array {
1278+
@resultBuilder
1279+
struct Builder {
1280+
static func buildBlock(_ elements: Element...) -> [Element] {
1281+
elements
1282+
}
1283+
}
1284+
}
1285+
1286+
extension Dictionary {
1287+
@resultBuilder
1288+
struct Builder {
1289+
static func buildBlock(_ elements: (Key, Value)...) -> Dictionary {
1290+
Dictionary(elements, uniquingKeysWith: { $1 })
1291+
}
1292+
}
1293+
}
1294+
1295+
func testNonGenericResultBuildersInGenericTypeExtensions() {
1296+
@Array.Builder
1297+
var elements: [String] {
1298+
"foo"
1299+
"bar"
1300+
}
1301+
1302+
@Array.Builder // expected-error {{unable to infer generic parameters for result builder @Array.Builder}}
1303+
var set: Set<String> {
1304+
"foo" // expected-warning {{string literal is unused}}
1305+
"bar" // expected-warning {{string literal is unused}}
1306+
}
1307+
1308+
@Dictionary.Builder
1309+
var dictionary: [String: String] {
1310+
("foo", "bar")
1311+
("baaz", "quux")
1312+
}
1313+
1314+
@Dictionary.Builder // expected-error {{unable to infer generic parameters for result builder @Dictionary.Builder}}
1315+
var dictionary2: [(String, String)] {
1316+
("foo", "bar") // expected-warning {{expression of type '(String, String)' is unused}}
1317+
("baaz", "quux") // expected-warning {{expression of type '(String, String)' is unused}}
1318+
}
1319+
}

test/decl/var/result_builders.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,13 @@ struct GenericContainer<T> {
7272
struct Maker {} // expected-error {{result builder must provide at least one static 'buildBlock' method}}
7373
}
7474

75-
func makeParamUnbound(@GenericMaker // expected-error {{unable to infer generic parameters for result builder 'GenericMaker'}}
75+
func makeParamUnbound(@GenericMaker // expected-error {{unable to infer generic parameters for result builder @GenericMaker}}
7676
fn: () -> ()) {}
7777

7878
func makeParamBound(@GenericMaker<Int>
7979
fn: () -> ()) {}
8080

81-
func makeParamNestedUnbound(@GenericContainer.Maker // expected-error {{unable to infer generic parameters for result builder 'GenericContainer'}}
81+
func makeParamNestedUnbound(@GenericContainer.Maker // expected-error {{unable to infer generic parameters for result builder @GenericContainer.Maker}}
8282
fn: () -> ()) {}
8383

8484
func makeParamNestedBound(@GenericContainer<Int>.Maker

0 commit comments

Comments
 (0)