Skip to content

Commit 21ee10b

Browse files
committed
[Type checker] Detangling the constraints of interpolated string literals.
Constraint generation for interpolated string literals was meticulously producing a constraint system that included all of the generated calls to init(stringInterpolationSegment:). While accurate, this is completely unnecessary (because the ExpressibleByStringInterpolation protocol allows *anything* to be interpolated) and leads to large, intertwined constraint systems where: (1) There are two additional type variables per string interpolation segment, and (2) Those type variables form a bridge between the string interpolation's type variable and the type variables of each string interpolation segment, and (3) init(stringInterpolationSegment:) tends to be overloaded (4 overloads, down from 17 due to 2935301) which left each string interpolation as a large connected component with big disjunctions. Drop the calls to init(stringInterpolationSegment:) from the constraint system. This eliminates two type variables per segment (due to (1) going away), and breaks the bridge described in (2), so that each string interpolation segment is treated as an separate connected component and, therefore, will be solved independently. The actual resolution of init(stringInterpolationSegment:) overloads is pushed to the constraint application phase, where we are only dealing with concrete types and *much* smaller constraint systems. Fixes rdar://problem/29389887 more thoroughly.
1 parent 207fffc commit 21ee10b

File tree

3 files changed

+55
-44
lines changed

3 files changed

+55
-44
lines changed

lib/Sema/CSApply.cpp

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2081,45 +2081,32 @@ namespace {
20812081
// Create a tuple containing all of the segments.
20822082
SmallVector<Expr *, 4> segments;
20832083
SmallVector<Identifier, 4> names;
2084-
unsigned index = 0;
20852084
ConstraintLocatorBuilder locatorBuilder(cs.getConstraintLocator(expr));
20862085
for (auto segment : expr->getSegments()) {
2087-
auto locator = cs.getConstraintLocator(
2088-
locatorBuilder.withPathElement(
2089-
LocatorPathElt::getInterpolationArgument(index++)));
2090-
2091-
// Find the initializer we chose.
2092-
auto choice = getOverloadChoice(locator);
2093-
2094-
auto memberRef = buildMemberRef(
2095-
typeRef, choice.openedFullType,
2096-
segment->getStartLoc(), choice.choice.getDecl(),
2097-
DeclNameLoc(segment->getStartLoc()),
2098-
choice.openedType,
2099-
locator, locator, /*Implicit=*/true,
2100-
choice.choice.getFunctionRefKind(),
2101-
AccessSemantics::Ordinary,
2102-
/*isDynamic=*/false);
21032086
ApplyExpr *apply =
21042087
CallExpr::createImplicit(
2105-
tc.Context, memberRef,
2088+
tc.Context, typeRef,
21062089
{ segment },
21072090
{ tc.Context.Id_stringInterpolationSegment });
21082091
cs.cacheType(apply->getArg());
21092092

2110-
auto converted = finishApply(apply, openedType, locatorBuilder);
2111-
if (!converted)
2112-
return nullptr;
2093+
Expr *convertedSegment = apply;
2094+
if (tc.typeCheckExpressionShallow(convertedSegment, cs.DC))
2095+
continue;
21132096

2114-
segments.push_back(converted);
2097+
segments.push_back(convertedSegment);
21152098

2116-
if (index == 1) {
2099+
if (names.empty()) {
21172100
names.push_back(tc.Context.Id_stringInterpolation);
21182101
} else {
21192102
names.push_back(Identifier());
21202103
}
21212104
}
21222105

2106+
// If all of the segments had errors, bail out.
2107+
if (segments.empty())
2108+
return nullptr;
2109+
21232110
// Call the init(stringInterpolation:) initializer with the arguments.
21242111
ApplyExpr *apply = CallExpr::createImplicit(tc.Context, memberRef,
21252112
segments, names);

lib/Sema/CSGen.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,6 @@ namespace {
12341234
visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *expr) {
12351235
// Dig out the ExpressibleByStringInterpolation protocol.
12361236
auto &tc = CS.getTypeChecker();
1237-
auto &C = CS.getASTContext();
12381237
auto interpolationProto
12391238
= tc.getProtocol(expr->getLoc(),
12401239
KnownProtocolKind::ExpressibleByStringInterpolation);
@@ -1251,26 +1250,6 @@ namespace {
12511250
interpolationProto->getDeclaredType(),
12521251
locator);
12531252

1254-
// Each of the segments is passed as an argument to
1255-
// init(stringInterpolationSegment:).
1256-
unsigned index = 0;
1257-
auto tvMeta = MetatypeType::get(tv);
1258-
for (auto segment : expr->getSegments()) {
1259-
auto locator = CS.getConstraintLocator(
1260-
expr,
1261-
LocatorPathElt::getInterpolationArgument(index++));
1262-
auto segmentTyV = CS.createTypeVariable(locator, /*options=*/0);
1263-
auto returnTyV = CS.createTypeVariable(locator, /*options=*/0);
1264-
auto methodTy = FunctionType::get(segmentTyV, returnTyV);
1265-
1266-
CS.addConstraint(ConstraintKind::Conversion, CS.getType(segment),
1267-
segmentTyV, locator);
1268-
1269-
DeclName segmentName(C, C.Id_init, { C.Id_stringInterpolationSegment });
1270-
CS.addValueMemberConstraint(tvMeta, segmentName, methodTy, CurDC,
1271-
FunctionRefKind::DoubleApply, locator);
1272-
}
1273-
12741253
return tv;
12751254
}
12761255

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-typecheck-verify-swift -typecheck -debug-constraints %s > %t.dump 2>&1
2+
// RUN: %FileCheck %s < %t.dump
3+
4+
// Make sure that the interpolation segments get placed into separate connected
5+
// components.
6+
// CHECK: ---Connected components---
7+
// CHECK-NEXT: 0:
8+
// CHECK-NEXT: 1:
9+
// CHECK-NEXT: 2:
10+
// CHECK-NEXT: 3:
11+
// CHECK-NEXT: 4:
12+
// CHECK-NEXT: 5:
13+
// CHECK-NEXT: 6:
14+
// CHECK-NEXT: 7:
15+
// CHECK-NEXT: 8:
16+
// CHECK-NEXT: 9:
17+
18+
// CHECK: (solving component #
19+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByStringLiteral) String)
20+
21+
// CHECK: (solving component #
22+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByIntegerLiteral) Int)
23+
24+
// CHECK: (solving component #
25+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByStringLiteral) String)
26+
27+
// CHECK: (solving component #
28+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByIntegerLiteral) Int)
29+
30+
// CHECK: (solving component #
31+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByStringLiteral) String)
32+
33+
// CHECK: (solving component #
34+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByIntegerLiteral) Int)
35+
36+
// CHECK: (solving component #
37+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByStringLiteral) String)
38+
39+
// CHECK: (solving component #
40+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByIntegerLiteral) Int)
41+
42+
// CHECK: (solving component #
43+
// CHECK: literal=3 bindings=(subtypes of) (default from ExpressibleByStringLiteral) String)
44+
45+
_ = "\(1), \(2), \(3), \(4)"

0 commit comments

Comments
 (0)