Skip to content

Commit 26c4ccc

Browse files
authored
Convert InterpolatedStringLiteralExpr to not use tc.callWitness(). (#26076)
For reference, all other callers of callWitness have been migrated.
1 parent 3844cb2 commit 26c4ccc

File tree

9 files changed

+165
-100
lines changed

9 files changed

+165
-100
lines changed

include/swift/AST/Expr.h

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,14 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
954954
/// would not work for \c stringLiteral->getEndLoc().
955955
SourceLoc TrailingQuoteLoc;
956956
TapExpr *AppendingExpr;
957-
Expr *SemanticExpr;
958-
957+
958+
// Set by Sema:
959+
OpaqueValueExpr *interpolationExpr = nullptr;
960+
ConcreteDeclRef builderInit;
961+
ConcreteDeclRef resultInit;
962+
Expr *interpolationCountExpr = nullptr;
963+
Expr *literalCapacityExpr = nullptr;
964+
959965
public:
960966
InterpolatedStringLiteralExpr(SourceLoc Loc,
961967
SourceLoc TrailingQuoteLoc,
@@ -965,11 +971,35 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
965971
: LiteralExpr(ExprKind::InterpolatedStringLiteral, /*Implicit=*/false),
966972
Loc(Loc),
967973
TrailingQuoteLoc(TrailingQuoteLoc),
968-
AppendingExpr(AppendingExpr), SemanticExpr() {
974+
AppendingExpr(AppendingExpr) {
969975
Bits.InterpolatedStringLiteralExpr.InterpolationCount = InterpolationCount;
970976
Bits.InterpolatedStringLiteralExpr.LiteralCapacity = LiteralCapacity;
971977
}
972978

979+
// Sets the constructor for the interpolation type.
980+
void setBuilderInit(ConcreteDeclRef decl) { builderInit = decl; }
981+
ConcreteDeclRef getBuilderInit() const { return builderInit; }
982+
983+
/// Sets the decl that constructs the final result type after the
984+
/// AppendingExpr has been evaluated.
985+
void setResultInit(ConcreteDeclRef decl) { resultInit = decl; }
986+
ConcreteDeclRef getResultInit() const { return resultInit; }
987+
988+
/// Sets the OpaqueValueExpr that is passed into AppendingExpr as the SubExpr
989+
/// that the tap operates on.
990+
void setInterpolationExpr(OpaqueValueExpr *expr) { interpolationExpr = expr; }
991+
OpaqueValueExpr *getInterpolationExpr() const { return interpolationExpr; }
992+
993+
/// Store a builtin integer literal expr wrapping getInterpolationCount().
994+
/// This is an arg to builderInit.
995+
void setInterpolationCountExpr(Expr *expr) { interpolationCountExpr = expr; }
996+
Expr *getInterpolationCountExpr() const { return interpolationCountExpr; }
997+
998+
/// Store a builtin integer literal expr wrapping getLiteralCapacity().
999+
/// This is an arg to builderInit.
1000+
void setLiteralCapacityExpr(Expr *expr) { literalCapacityExpr = expr; }
1001+
Expr *getLiteralCapacityExpr() const { return literalCapacityExpr; }
1002+
9731003
/// Retrieve the value of the literalCapacity parameter to the
9741004
/// initializer.
9751005
unsigned getLiteralCapacity() const {
@@ -989,11 +1019,6 @@ class InterpolatedStringLiteralExpr : public LiteralExpr {
9891019
TapExpr * getAppendingExpr() const { return AppendingExpr; }
9901020
void setAppendingExpr(TapExpr * AE) { AppendingExpr = AE; }
9911021

992-
/// Retrieve the expression that actually evaluates the resulting
993-
/// string, typically with a series of '+' operations.
994-
Expr *getSemanticExpr() const { return SemanticExpr; }
995-
void setSemanticExpr(Expr *SE) { SemanticExpr = SE; }
996-
9971022
SourceLoc getStartLoc() const {
9981023
return Loc;
9991024
}

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,9 +1949,13 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
19491949
PrintWithColorRAII(OS, LiteralValueColor)
19501950
<< " literal_capacity="
19511951
<< E->getLiteralCapacity() << " interpolation_count="
1952-
<< E->getInterpolationCount() << '\n';
1952+
<< E->getInterpolationCount();
1953+
PrintWithColorRAII(OS, LiteralValueColor) << " builder_init=";
1954+
E->getBuilderInit().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS());
1955+
PrintWithColorRAII(OS, LiteralValueColor) << " result_init=";
1956+
E->getResultInit().dump(PrintWithColorRAII(OS, LiteralValueColor).getOS());
1957+
OS << "\n";
19531958
printRec(E->getAppendingExpr());
1954-
printSemanticExpr(E->getSemanticExpr());
19551959
PrintWithColorRAII(OS, ParenthesisColor) << ')';
19561960
}
19571961
void visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E) {
@@ -3772,4 +3776,4 @@ StringRef swift::getAccessorKindString(AccessorKind value) {
37723776
}
37733777

37743778
llvm_unreachable("Unhandled AccessorKind in switch.");
3775-
}
3779+
}

lib/AST/ASTVerifier.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,26 @@ class Verifier : public ASTWalker {
804804
OpaqueValues.erase(S->getElementExpr());
805805
}
806806

807+
bool shouldVerify(InterpolatedStringLiteralExpr *expr) {
808+
if (!shouldVerify(cast<Expr>(expr)))
809+
return false;
810+
811+
if (!expr->getInterpolationExpr())
812+
return true;
813+
814+
assert(!OpaqueValues.count(expr->getInterpolationExpr()));
815+
OpaqueValues[expr->getInterpolationExpr()] = 0;
816+
return true;
817+
}
818+
819+
void cleanup(InterpolatedStringLiteralExpr *expr) {
820+
if (!expr->getInterpolationExpr())
821+
return;
822+
823+
assert(OpaqueValues.count(expr->getInterpolationExpr()));
824+
OpaqueValues.erase(expr->getInterpolationExpr());
825+
}
826+
807827
bool shouldVerify(OpenExistentialExpr *expr) {
808828
if (!shouldVerify(cast<Expr>(expr)))
809829
return false;

lib/AST/ASTWalker.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,6 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
472472
}
473473

474474
Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) {
475-
HANDLE_SEMANTIC_EXPR(E);
476-
477475
if (auto oldAppendingExpr = E->getAppendingExpr()) {
478476
if (auto appendingExpr = doIt(oldAppendingExpr))
479477
E->setAppendingExpr(dyn_cast<TapExpr>(appendingExpr));

lib/AST/Expr.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,16 +2191,6 @@ void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
21912191
void InterpolatedStringLiteralExpr::forEachSegment(ASTContext &Ctx,
21922192
llvm::function_ref<void(bool, CallExpr *)> callback) {
21932193
auto appendingExpr = getAppendingExpr();
2194-
if (SemanticExpr) {
2195-
SemanticExpr->forEachChildExpr([&](Expr *subExpr) -> Expr * {
2196-
if (auto tap = dyn_cast_or_null<TapExpr>(subExpr)) {
2197-
appendingExpr = tap;
2198-
return nullptr;
2199-
}
2200-
return subExpr;
2201-
});
2202-
}
2203-
22042194
for (auto stmt : appendingExpr->getBody()->getElements()) {
22052195
if (auto expr = stmt.dyn_cast<Expr*>()) {
22062196
if (auto call = dyn_cast<CallExpr>(expr)) {

lib/SILGen/SILGenExpr.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2380,7 +2380,59 @@ RValue RValueEmitter::visitAbstractClosureExpr(AbstractClosureExpr *e,
23802380
RValue RValueEmitter::
23812381
visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E,
23822382
SGFContext C) {
2383-
return visit(E->getSemanticExpr(), C);
2383+
RValue interpolation;
2384+
{
2385+
TapExpr *ETap = E->getAppendingExpr();
2386+
// Inlined from TapExpr:
2387+
// TODO: This is only necessary because constant evaluation requires that
2388+
// the box for the var gets defined before the initializer happens.
2389+
auto Var = ETap->getVar();
2390+
auto VarType = ETap->getType()->getCanonicalType();
2391+
2392+
Scope outerScope(SGF, CleanupLocation(ETap));
2393+
2394+
// Initialize the var with our SubExpr.
2395+
auto VarInit =
2396+
SGF.emitInitializationForVarDecl(Var, /*forceImmutable=*/false);
2397+
{
2398+
// Modified from TapExpr to evaluate the SubExpr directly rather than
2399+
// indirectly through the OpaqueValue system.
2400+
PreparedArguments builderInitArgs;
2401+
RValue literalCapacity = visit(E->getLiteralCapacityExpr(), SGFContext());
2402+
RValue interpolationCount =
2403+
visit(E->getInterpolationCountExpr(), SGFContext());
2404+
builderInitArgs.emplace(
2405+
{AnyFunctionType::Param(literalCapacity.getType()),
2406+
AnyFunctionType::Param(interpolationCount.getType())});
2407+
builderInitArgs.add(E, std::move(literalCapacity));
2408+
builderInitArgs.add(E, std::move(interpolationCount));
2409+
RValue subexpr_result = SGF.emitApplyAllocatingInitializer(
2410+
E, E->getBuilderInit(), std::move(builderInitArgs), Type(),
2411+
SGFContext(VarInit.get()));
2412+
if (!subexpr_result.isInContext()) {
2413+
ArgumentSource(
2414+
SILLocation(E),
2415+
std::move(subexpr_result).ensurePlusOne(SGF, SILLocation(E)))
2416+
.forwardInto(SGF, VarInit.get());
2417+
}
2418+
}
2419+
2420+
// Emit the body and let it mutate the var if it chooses.
2421+
SGF.emitStmt(ETap->getBody());
2422+
2423+
// Retrieve and return the var, making it +1 so it survives the scope.
2424+
auto result = SGF.emitRValueForDecl(SILLocation(ETap), Var, VarType,
2425+
AccessSemantics::Ordinary, SGFContext());
2426+
result = std::move(result).ensurePlusOne(SGF, SILLocation(ETap));
2427+
interpolation = outerScope.popPreservingValue(std::move(result));
2428+
}
2429+
2430+
PreparedArguments resultInitArgs;
2431+
resultInitArgs.emplace(AnyFunctionType::Param(interpolation.getType()));
2432+
resultInitArgs.add(E, std::move(interpolation));
2433+
2434+
return SGF.emitApplyAllocatingInitializer(
2435+
E, E->getResultInit(), std::move(resultInitArgs), Type(), C);
23842436
}
23852437

23862438
RValue RValueEmitter::

lib/Sema/CSApply.cpp

Lines changed: 38 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,16 +2109,12 @@ namespace {
21092109
auto type = simplifyType(openedType);
21102110
cs.setType(expr, type);
21112111

2112-
if (expr->getSemanticExpr() != nullptr) {
2113-
return expr;
2114-
}
2115-
21162112
auto &tc = cs.getTypeChecker();
21172113
auto loc = expr->getStartLoc();
21182114

2119-
auto buildProtocolInitCall =
2120-
[&](KnownProtocolKind protocolKind, Type type,
2121-
ArrayRef<Identifier> argLabels, ArrayRef<Expr *> args) -> Expr * {
2115+
auto fetchProtocolInitWitness =
2116+
[&](KnownProtocolKind protocolKind, Type type,
2117+
ArrayRef<Identifier> argLabels) -> ConcreteDeclRef {
21222118

21232119
auto proto = tc.getProtocol(loc, protocolKind);
21242120
assert(proto && "Missing string interpolation protocol?");
@@ -2129,16 +2125,12 @@ namespace {
21292125
assert(conformance && "string interpolation type conforms to protocol");
21302126

21312127
DeclName constrName(tc.Context, DeclBaseName::createConstructor(), argLabels);
2132-
2133-
Expr *base = TypeExpr::createImplicitHack(loc, type,
2134-
tc.Context);
2135-
Expr *semanticExpr = tc.callWitness(base, dc, proto, *conformance,
2136-
constrName, args,
2137-
diag::interpolation_broken_proto);
2138-
if (semanticExpr)
2139-
cs.cacheExprTypes(semanticExpr);
2140-
2141-
return semanticExpr;
2128+
2129+
ConcreteDeclRef witness =
2130+
conformance->getWitnessByName(type->getRValueType(), constrName);
2131+
if (!witness || !isa<AbstractFunctionDecl>(witness.getDecl()))
2132+
return nullptr;
2133+
return witness;
21422134
};
21432135

21442136
auto associatedTypeArray =
@@ -2154,59 +2146,42 @@ namespace {
21542146
auto interpolationType =
21552147
simplifyType(DependentMemberType::get(openedType, associatedTypeDecl));
21562148

2157-
// interpolationInitCall = """
2158-
// StringInterpolationProtocol.init(
2159-
// literalCapacity: \(expr->getLiteralCapacity()),
2160-
// interpolationCount: \(expr->getInterpolationCount()))
2161-
// """
2162-
2163-
// Make the integer literals for the parameters.
2164-
Expr *literalCapacity =
2165-
IntegerLiteralExpr::createFromUnsigned(tc.Context,
2166-
expr->getLiteralCapacity());
2167-
cs.setType(literalCapacity, tc.getIntType(cs.DC));
2168-
literalCapacity =
2169-
handleIntegerLiteralExpr((LiteralExpr*)literalCapacity);
2170-
2171-
Expr *interpolationCount =
2172-
IntegerLiteralExpr::createFromUnsigned(tc.Context,
2173-
expr->getInterpolationCount());
2174-
cs.setType(interpolationCount, tc.getIntType(cs.DC));
2175-
interpolationCount =
2176-
handleIntegerLiteralExpr((LiteralExpr*)interpolationCount);
2177-
2178-
// Make the call itself.
2179-
auto interpolationInitCall =
2180-
buildProtocolInitCall(
2149+
// Fetch needed witnesses.
2150+
ConcreteDeclRef builderInit = fetchProtocolInitWitness(
21812151
KnownProtocolKind::StringInterpolationProtocol, interpolationType,
2182-
{ tc.Context.Id_literalCapacity, tc.Context.Id_interpolationCount },
2183-
{ literalCapacity, interpolationCount });
2152+
{ tc.Context.Id_literalCapacity, tc.Context.Id_interpolationCount });
2153+
if (!builderInit) return nullptr;
2154+
expr->setBuilderInit(builderInit);
21842155

2185-
// appendingExpr = """
2186-
// _tap var \(expr->getBody()->getElement(0)) =
2187-
// \(interpolationInitCall) {
2188-
// \(expr->getBody())
2189-
// }
2190-
// """
2156+
ConcreteDeclRef resultInit = fetchProtocolInitWitness(
2157+
KnownProtocolKind::ExpressibleByStringInterpolation, type,
2158+
{ tc.Context.Id_stringInterpolation });
2159+
if (!resultInit) return nullptr;
2160+
expr->setResultInit(resultInit);
21912161

2192-
auto appendingExpr = expr->getAppendingExpr();
2193-
appendingExpr->setSubExpr(interpolationInitCall);
2162+
// Make the integer literals for the parameters.
2163+
auto buildExprFromUnsigned = [&](unsigned value) {
2164+
LiteralExpr *expr =
2165+
IntegerLiteralExpr::createFromUnsigned(tc.Context, value);
2166+
cs.setType(expr, tc.getIntType(cs.DC));
2167+
return handleIntegerLiteralExpr(expr);
2168+
};
21942169

2195-
// initStringInterpolationExpr = """
2196-
// ExpressibleByStringInterpolation.init(
2197-
// stringInterpolation: \(appendingExpr))
2198-
// """
2170+
expr->setLiteralCapacityExpr(
2171+
buildExprFromUnsigned(expr->getLiteralCapacity()));
2172+
expr->setInterpolationCountExpr(
2173+
buildExprFromUnsigned(expr->getInterpolationCount()));
21992174

2200-
auto initStringInterpolationExpr =
2201-
buildProtocolInitCall(
2202-
KnownProtocolKind::ExpressibleByStringInterpolation, type,
2203-
{ tc.Context.Id_stringInterpolation },
2204-
{ appendingExpr });
2175+
// This OpaqueValueExpr represents the result of builderInit above in
2176+
// silgen.
2177+
OpaqueValueExpr *interpolationExpr =
2178+
new (tc.Context) OpaqueValueExpr(expr->getLoc(), interpolationType);
2179+
cs.setType(interpolationExpr, interpolationType);
2180+
expr->setInterpolationExpr(interpolationExpr);
22052181

2206-
// Set that as the semantic expr.
2207-
expr->setSemanticExpr(initStringInterpolationExpr);
2182+
auto appendingExpr = expr->getAppendingExpr();
2183+
appendingExpr->setSubExpr(interpolationExpr);
22082184

2209-
// And we're done!
22102185
return expr;
22112186
}
22122187

lib/Sema/CSGen.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,14 +1176,7 @@ namespace {
11761176
interpolationProto->getDeclaredType(),
11771177
locator);
11781178

1179-
if (auto semanticExpr = expr->getSemanticExpr()) {
1180-
// The semanticExpr must have the same type as this node.
1181-
auto semanticTV = CS.getType(semanticExpr);
1182-
auto semanticLocator = CS.getConstraintLocator(semanticExpr);
1183-
CS.addConstraint(ConstraintKind::Bind, tv, semanticTV,
1184-
semanticLocator);
1185-
}
1186-
else if (auto appendingExpr = expr->getAppendingExpr()) {
1179+
if (auto appendingExpr = expr->getAppendingExpr()) {
11871180
auto associatedTypeArray =
11881181
interpolationProto->lookupDirect(tc.Context.Id_StringInterpolation);
11891182
if (associatedTypeArray.empty()) {
@@ -3260,6 +3253,16 @@ namespace {
32603253
return { false, OOE->getSubExpr()->walk(*this) };
32613254
}
32623255

3256+
// Hacky, this behaves just like an OpenedExistential in that it changes
3257+
// the expr tree.
3258+
if (auto ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr)) {
3259+
if (auto subExpr = ISLE->getAppendingExpr()->getSubExpr()) {
3260+
if (auto opaqueValue = dyn_cast<OpaqueValueExpr>(subExpr)) {
3261+
ISLE->getAppendingExpr()->setSubExpr(nullptr);
3262+
}
3263+
}
3264+
}
3265+
32633266
// Substitute OpaqueValue with its representing existental.
32643267
if (auto OVE = dyn_cast<OpaqueValueExpr>(expr)) {
32653268
auto value = OpenExistentials.find(OVE);
@@ -3297,9 +3300,7 @@ namespace {
32973300
}
32983301

32993302
// Remove any semantic expression injected by typechecking.
3300-
if (auto ISLE = dyn_cast<InterpolatedStringLiteralExpr>(expr)) {
3301-
ISLE->setSemanticExpr(nullptr);
3302-
} else if (auto EPE = dyn_cast<EditorPlaceholderExpr>(expr)) {
3303+
if (auto EPE = dyn_cast<EditorPlaceholderExpr>(expr)) {
33033304
EPE->setSemanticExpr(nullptr);
33043305
}
33053306

lib/Sema/TypeCheckError.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,8 +1472,8 @@ class CheckErrorCoverage : public ErrorHandlingWalker<CheckErrorCoverage> {
14721472
ShouldRecurse_t
14731473
checkInterpolatedStringLiteral(InterpolatedStringLiteralExpr *E) {
14741474
ContextScope scope(*this, CurContext.withInterpolatedString(E));
1475-
if (E->getSemanticExpr())
1476-
E->getSemanticExpr()->walk(*this);
1475+
if (E->getAppendingExpr())
1476+
E->getAppendingExpr()->walk(*this);
14771477
scope.preserveCoverageFromInterpolatedString();
14781478
return ShouldNotRecurse;
14791479
}

0 commit comments

Comments
 (0)