Skip to content

Commit 80e8a6a

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. (cherry picked from commit 21ee10b)
1 parent db6694b commit 80e8a6a

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
@@ -2099,45 +2099,32 @@ namespace {
20992099
// Create a tuple containing all of the segments.
21002100
SmallVector<Expr *, 4> segments;
21012101
SmallVector<Identifier, 4> names;
2102-
unsigned index = 0;
21032102
ConstraintLocatorBuilder locatorBuilder(cs.getConstraintLocator(expr));
21042103
for (auto segment : expr->getSegments()) {
2105-
auto locator = cs.getConstraintLocator(
2106-
locatorBuilder.withPathElement(
2107-
LocatorPathElt::getInterpolationArgument(index++)));
2108-
2109-
// Find the initializer we chose.
2110-
auto choice = getOverloadChoice(locator);
2111-
2112-
auto memberRef = buildMemberRef(
2113-
typeRef, choice.openedFullType,
2114-
segment->getStartLoc(), choice.choice.getDecl(),
2115-
DeclNameLoc(segment->getStartLoc()),
2116-
choice.openedType,
2117-
locator, locator, /*Implicit=*/true,
2118-
choice.choice.getFunctionRefKind(),
2119-
AccessSemantics::Ordinary,
2120-
/*isDynamic=*/false);
21212104
ApplyExpr *apply =
21222105
CallExpr::createImplicit(
2123-
tc.Context, memberRef,
2106+
tc.Context, typeRef,
21242107
{ segment },
21252108
{ tc.Context.Id_stringInterpolationSegment });
21262109
cs.cacheType(apply->getArg());
21272110

2128-
auto converted = finishApply(apply, openedType, locatorBuilder);
2129-
if (!converted)
2130-
return nullptr;
2111+
Expr *convertedSegment = apply;
2112+
if (tc.typeCheckExpressionShallow(convertedSegment, cs.DC))
2113+
continue;
21312114

2132-
segments.push_back(converted);
2115+
segments.push_back(convertedSegment);
21332116

2134-
if (index == 1) {
2117+
if (names.empty()) {
21352118
names.push_back(tc.Context.Id_stringInterpolation);
21362119
} else {
21372120
names.push_back(Identifier());
21382121
}
21392122
}
21402123

2124+
// If all of the segments had errors, bail out.
2125+
if (segments.empty())
2126+
return nullptr;
2127+
21412128
// Call the init(stringInterpolation:) initializer with the arguments.
21422129
ApplyExpr *apply = CallExpr::createImplicit(tc.Context, memberRef,
21432130
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)