Skip to content

Commit fb4720d

Browse files
committed
[BuilderTransform] Replace use of TypeExpr with a special $builderSelf variable
For all of the `build*` calls, let's use a special variable declaration `$builderSelf` which refers to a type of the builder used. This allows us to remove hacks related to use of `TypeExpr`. Reference to `$builderSelf` is replaced with `TypeExpr` during solution application when the builder type is completely resolved.
1 parent 21f35ba commit fb4720d

File tree

4 files changed

+44
-38
lines changed

4 files changed

+44
-38
lines changed

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ IDENTIFIER(InvocationEncoder)
303303
IDENTIFIER(whenLocal)
304304
IDENTIFIER(decodeNextArgument)
305305
IDENTIFIER(SerializationRequirement)
306+
IDENTIFIER_WITH_NAME(builderSelf, "$builderSelf")
306307

307308
#undef IDENTIFIER
308309
#undef IDENTIFIER_

lib/Sema/BuilderTransform.cpp

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class BuilderClosureVisitor
7373
Identifier buildOptionalId;
7474
llvm::SmallDenseMap<DeclName, bool> supportedOps;
7575

76+
/// The variable used as a base for all `build*` operations added
77+
/// by this transform.
78+
VarDecl *builderVar = nullptr;
79+
7680
SkipUnhandledConstructInResultBuilder::UnhandledNode unhandledNode;
7781

7882
/// Whether an error occurred during application of the builder closure,
@@ -94,32 +98,6 @@ class BuilderClosureVisitor
9498
if (!cs)
9599
return nullptr;
96100

97-
// FIXME: Setting a base on this expression is necessary in order
98-
// to get diagnostics if something about this builder call fails,
99-
// e.g. if there isn't a matching overload for `buildBlock`.
100-
TypeExpr *typeExpr;
101-
auto simplifiedTy = cs->simplifyType(builderType);
102-
if (!simplifiedTy->hasTypeVariable()) {
103-
typeExpr = TypeExpr::createImplicitHack(loc, simplifiedTy, ctx);
104-
} else if (auto *decl = simplifiedTy->getAnyGeneric()) {
105-
// HACK: If there's not enough information to completely resolve the
106-
// builder type, but we have the base available to us, form an *explicit*
107-
// TypeExpr pointing at it. We cannot form an implicit base without
108-
// a fully-resolved concrete type. Really, whatever we put here has no
109-
// bearing on the generated solution because we're going to use this node
110-
// to stash the builder type and hand it back to the ambient
111-
// constraint system.
112-
typeExpr = TypeExpr::createForDecl(DeclNameLoc(loc), decl, dc);
113-
} else {
114-
// HACK: If there's not enough information in the constraint system,
115-
// create a garbage base type to force it to diagnose
116-
// this as an ambiguous expression.
117-
// FIXME: We can also construct an UnresolvedMemberExpr here instead of
118-
// an UnresolvedDotExpr and get a slightly better diagnostic.
119-
typeExpr = TypeExpr::createImplicitHack(loc, ErrorType::get(ctx), ctx);
120-
}
121-
cs->setType(typeExpr, MetatypeType::get(builderType));
122-
123101
SmallVector<Argument, 4> args;
124102
for (auto i : indices(argExprs)) {
125103
auto *expr = argExprs[i];
@@ -128,8 +106,11 @@ class BuilderClosureVisitor
128106
args.emplace_back(labelLoc, label, expr);
129107
}
130108

109+
auto *baseExpr = new (ctx) DeclRefExpr({builderVar}, DeclNameLoc(loc),
110+
/*isImplicit=*/true);
111+
131112
auto memberRef = new (ctx) UnresolvedDotExpr(
132-
typeExpr, loc, DeclNameRef(fnName), DeclNameLoc(loc),
113+
baseExpr, loc, DeclNameRef(fnName), DeclNameLoc(loc),
133114
/*implicit=*/true);
134115
memberRef->setFunctionRefKind(FunctionRefKind::SingleApply);
135116

@@ -223,6 +204,16 @@ class BuilderClosureVisitor
223204
buildOptionalId = ctx.Id_buildOptional;
224205
else
225206
buildOptionalId = ctx.Id_buildIf;
207+
208+
// If we are about to generate constraints, let's establish builder
209+
// variable for the base of `build*` calls.
210+
if (cs) {
211+
builderVar = new (ctx) VarDecl(
212+
/*isStatic=*/false, VarDecl::Introducer::Let,
213+
/*nameLoc=*/SourceLoc(), ctx.Id_builderSelf, dc);
214+
builderVar->setImplicit();
215+
cs->setType(builderVar, MetatypeType::get(cs->simplifyType(builderType)));
216+
}
226217
}
227218

228219
/// Apply the builder transform to the given statement.

lib/Sema/CSApply.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2869,6 +2869,20 @@ namespace {
28692869
Expr *visitDeclRefExpr(DeclRefExpr *expr) {
28702870
auto locator = cs.getConstraintLocator(expr);
28712871

2872+
// Check whether this is a reference to `__buildSelf`, and if so,
2873+
// replace it with a type expression with fully resolved type.
2874+
if (auto *var = dyn_cast<VarDecl>(expr->getDecl())) {
2875+
auto &ctx = cs.getASTContext();
2876+
if (var->getName() == ctx.Id_builderSelf) {
2877+
assert(expr->isImplicit() && var->isImplicit());
2878+
auto builderTy =
2879+
solution.getResolvedType(var)->getMetatypeInstanceType();
2880+
2881+
return cs.cacheType(
2882+
TypeExpr::createImplicitHack(expr->getLoc(), builderTy, ctx));
2883+
}
2884+
}
2885+
28722886
// Find the overload choice used for this declaration reference.
28732887
auto selected = solution.getOverloadChoice(locator);
28742888
return buildDeclRef(selected, expr->getNameLoc(), locator,

test/Constraints/result_builder_one_way.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@ func tuplify<C: Collection, T>(_ collection: C, @TupleBuilder body: (C.Element)
4949
}
5050

5151
// CHECK: ---Connected components---
52-
// CHECK-NEXT: 1: $T10 depends on 0
53-
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T77 $T78 depends on 3
54-
// CHECK-NEXT: 3: $T12 $T17 $T28 $T42 $T53 $T54 $T55 $T56 $T57 $T58 $T59 $T60 $T61 $T62 $T63 $T64 $T65 $T66 $T68 $T69 $T70 $T71 $T72 $T73 $T74 $T75 $T76 depends on 2, 4, 5, 7, 10
55-
// CHECK-NEXT: 10: $T48 $T49 $T50 $T51 $T52 depends on 9
56-
// CHECK-NEXT: 9: $T43 $T44 $T45 $T46 $T47
57-
// CHECK-NEXT: 7: $T31 $T35 $T36 $T37 $T38 $T39 $T40 $T41 depends on 6, 8
58-
// CHECK-NEXT: 8: $T32 $T33 $T34
59-
// CHECK-NEXT: 6: $T30
60-
// CHECK-NEXT: 5: $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27
61-
// CHECK-NEXT: 4: $T15 $T16
62-
// CHECK-NEXT: 2: $T11
52+
// CHECK-NEXT: 1: $T10 depends on 0
53+
// CHECK-NEXT: 0: $T1 $T2 $T3 $T5 $T6 $T7 $T8 $T82 $T83 depends on 3
54+
// CHECK-NEXT: 3: $T12 $T17 $T28 $T43 $T55 $T57 $T58 $T59 $T60 $T61 $T63 $T64 $T65 $T66 $T67 $T68 $T70 $T71 $T73 $T74 $T75 $T76 $T77 $T78 $T79 $T80 $T81 depends on 2, 4, 5, 7, 10
55+
// CHECK-NEXT: 10: $T49 $T51 $T52 $T53 $T54 depends on 9
56+
// CHECK-NEXT: 9: $T44 $T45 $T46 $T47 $T48
57+
// CHECK-NEXT: 7: $T31 $T35 $T37 $T38 $T39 $T40 $T41 $T42 depends on 6, 8
58+
// CHECK-NEXT: 8: $T32 $T33 $T34
59+
// CHECK-NEXT: 6: $T30
60+
// CHECK-NEXT: 5: $T18 $T19 $T20 $T21 $T22 $T23 $T24 $T25 $T26 $T27
61+
// CHECK-NEXT: 4: $T15 $T16
62+
// CHECK-NEXT: 2: $T11
6363
let names = ["Alice", "Bob", "Charlie"]
6464
let b = true
6565
var number = 17

0 commit comments

Comments
 (0)