Skip to content

Commit 71e8148

Browse files
committed
[CSApply] Implement AST transformation for keypath dynamic member lookup
1 parent cde23ec commit 71e8148

File tree

1 file changed

+61
-40
lines changed

1 file changed

+61
-40
lines changed

lib/Sema/CSApply.cpp

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -323,27 +323,18 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
323323
/// Form a type checked expression for the index of a @dynamicMemberLookup
324324
/// subscript index parameter.
325325
/// The index expression will have a tuple type of `(dynamicMember: T)`.
326-
static Expr *buildDynamicMemberLookupIndexExpr(StringRef name, Type ty,
327-
SourceLoc loc, DeclContext *dc,
326+
static Expr *buildDynamicMemberLookupIndexExpr(StringRef name, SourceLoc loc,
327+
DeclContext *dc,
328328
ConstraintSystem &cs) {
329329
auto &ctx = cs.TC.Context;
330-
331330
// Build and type check the string literal index value to the specific
332331
// string type expected by the subscript.
333332
Expr *nameExpr = new (ctx) StringLiteralExpr(name, loc, /*implicit*/true);
334333
(void)cs.TC.typeCheckExpression(nameExpr, dc);
335334
cs.cacheExprTypes(nameExpr);
336-
337-
// Build a tuple so that the argument has a label.
338-
Expr *tuple = TupleExpr::create(ctx, loc, nameExpr, ctx.Id_dynamicMember,
339-
loc, loc, /*hasTrailingClosure*/false,
340-
/*implicit*/true);
341-
cs.setType(tuple, ty);
342-
tuple->setType(ty);
343-
return tuple;
335+
return nameExpr;
344336
}
345337

346-
347338
namespace {
348339

349340
/// Rewrites an expression by applying the solution of a constraint
@@ -1380,7 +1371,8 @@ namespace {
13801371

13811372
// Use the correct locator kind based on the subscript kind.
13821373
auto locatorKind = ConstraintLocator::SubscriptMember;
1383-
if (choice.getKind() == OverloadChoiceKind::DynamicMemberLookup)
1374+
if (choice.getKind() == OverloadChoiceKind::DynamicMemberLookup ||
1375+
choice.getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup)
13841376
locatorKind = ConstraintLocator::Member;
13851377

13861378
// If we opened up an existential when performing the subscript, open
@@ -1395,7 +1387,8 @@ namespace {
13951387

13961388
// Figure out the index and result types.
13971389
Type resultTy;
1398-
if (choice.getKind() != OverloadChoiceKind::DynamicMemberLookup) {
1390+
if (choice.getKind() != OverloadChoiceKind::DynamicMemberLookup &&
1391+
choice.getKind() != OverloadChoiceKind::KeyPathDynamicMemberLookup) {
13991392
auto subscriptTy = simplifyType(selected.openedType);
14001393
auto *subscriptFnTy = subscriptTy->castTo<FunctionType>();
14011394
resultTy = subscriptFnTy->getResult();
@@ -1415,7 +1408,7 @@ namespace {
14151408
// the subscript.
14161409
resultTy = simplifyType(selected.openedType);
14171410
}
1418-
1411+
14191412
auto getType = [&](const Expr *E) -> Type {
14201413
return cs.getType(E);
14211414
};
@@ -1522,6 +1515,20 @@ namespace {
15221515
return ctorRef;
15231516
}
15241517

1518+
Expr *buildKeyPathDynamicMemberIndexExpr(ConstraintLocator *memberLoc) {
1519+
auto arg = solution.DynamicMemberArguments.find(memberLoc);
1520+
assert(arg != solution.DynamicMemberArguments.end() &&
1521+
"cannot find argument for keypath dynamic member lookup");
1522+
1523+
auto *keyPath = arg->getSecond();
1524+
keyPath->forEachChildExpr([&](Expr *childExpr) -> Expr * {
1525+
simplifyExprType(childExpr);
1526+
return childExpr;
1527+
});
1528+
1529+
return visitKeyPathExpr(keyPath);
1530+
}
1531+
15251532
/// Bridge the given value (which is an error type) to NSError.
15261533
Expr *bridgeErrorToObjectiveC(Expr *value) {
15271534
auto &tc = cs.getTypeChecker();
@@ -2592,7 +2599,8 @@ namespace {
25922599
AccessSemantics::Ordinary);
25932600
}
25942601

2595-
switch (selected.choice.getKind()) {
2602+
auto choiceKind = selected.choice.getKind();
2603+
switch (choiceKind) {
25962604
case OverloadChoiceKind::DeclViaBridge: {
25972605
base = cs.coerceToRValue(base);
25982606

@@ -2663,30 +2671,45 @@ namespace {
26632671

26642672
case OverloadChoiceKind::KeyPathApplication:
26652673
llvm_unreachable("should only happen in a subscript");
2666-
2667-
case OverloadChoiceKind::DynamicMemberLookup: {
2668-
// Application of a DynamicMemberLookup result turns a member access of
2669-
// x.foo into x[dynamicMember: "foo"].
2674+
2675+
case OverloadChoiceKind::DynamicMemberLookup:
2676+
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2677+
// Application of a DynamicMemberLookup result turns
2678+
// a member access of `x.foo` into x[dynamicMember: "foo"], or
2679+
// x[dynamicMember: KeyPath<T, U>]
26702680
auto &ctx = cs.getASTContext();
26712681
auto loc = nameLoc.getStartLoc();
2672-
2673-
// Figure out the expected type of the string. We know the
2682+
2683+
// Figure out the expected type of the lookup parameter. We know the
26742684
// openedFullType will be "xType -> indexType -> resultType". Dig out
26752685
// its index type.
26762686
auto declTy = solution.simplifyType(selected.openedFullType);
26772687
auto subscriptTy = declTy->castTo<FunctionType>()->getResult();
26782688
auto refFnType = subscriptTy->castTo<FunctionType>();
26792689
assert(refFnType->getParams().size() == 1 &&
26802690
"subscript always has one arg");
2681-
auto stringType = refFnType->getParams()[0].getPlainType();
2682-
auto tupleTy = TupleType::get(TupleTypeElt(stringType,
2683-
ctx.Id_dynamicMember), ctx);
2691+
auto paramTy = refFnType->getParams()[0].getPlainType();
2692+
2693+
Expr *argExpr = nullptr;
2694+
if (choiceKind == OverloadChoiceKind::DynamicMemberLookup) {
2695+
// Build and type check the string literal index value to the specific
2696+
// string type expected by the subscript.
2697+
auto fieldName = selected.choice.getName().getBaseIdentifier().str();
2698+
argExpr = buildDynamicMemberLookupIndexExpr(fieldName, loc, dc, cs);
2699+
} else {
2700+
argExpr = buildKeyPathDynamicMemberIndexExpr(memberLocator);
2701+
}
2702+
2703+
assert(argExpr);
26842704

2685-
// Build and type check the string literal index value to the specific
2686-
// string type expected by the subscript.
2687-
auto fieldName = selected.choice.getName().getBaseIdentifier().str();
2688-
auto index =
2689-
buildDynamicMemberLookupIndexExpr(fieldName, tupleTy, loc, dc, cs);
2705+
// Build a tuple so that the argument has a label.
2706+
auto tupleTy =
2707+
TupleType::get(TupleTypeElt(paramTy, ctx.Id_dynamicMember), ctx);
2708+
Expr *index = TupleExpr::create(ctx, loc, argExpr, ctx.Id_dynamicMember,
2709+
loc, loc, /*hasTrailingClosure*/ false,
2710+
/*implicit*/ true);
2711+
index->setType(tupleTy);
2712+
cs.cacheType(index);
26902713

26912714
// Build and return a subscript that uses this string as the index.
26922715
return buildSubscript(base, index, ctx.Id_dynamicMember,
@@ -2695,10 +2718,6 @@ namespace {
26952718
/*isImplicit*/false,
26962719
AccessSemantics::Ordinary, selected);
26972720
}
2698-
2699-
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2700-
break;
2701-
}
27022721
}
27032722

27042723
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
@@ -4109,6 +4128,10 @@ namespace {
41094128
KeyPathSubscriptComponents;
41104129
public:
41114130
Expr *visitKeyPathExpr(KeyPathExpr *E) {
4131+
return visitKeyPathExpr(E, cs.getConstraintLocator(E));
4132+
}
4133+
4134+
Expr *visitKeyPathExpr(KeyPathExpr *E, ConstraintLocator *baseLocator) {
41124135
if (E->isObjC()) {
41134136
cs.setType(E, cs.getType(E->getObjCStringLiteralExpr()));
41144137
return E;
@@ -4181,9 +4204,9 @@ namespace {
41814204
auto kind = origComponent.getKind();
41824205
Optional<SelectedOverload> foundDecl;
41834206

4184-
auto locator =
4185-
cs.getConstraintLocator(E,
4186-
ConstraintLocator::PathElement::getKeyPathComponent(i));
4207+
auto locator = cs.getConstraintLocator(
4208+
baseLocator,
4209+
ConstraintLocator::PathElement::getKeyPathComponent(i));
41874210
if (kind == KeyPathExpr::Component::Kind::UnresolvedSubscript) {
41884211
locator =
41894212
cs.getConstraintLocator(locator,
@@ -4199,9 +4222,7 @@ namespace {
41994222
// If this was a @dynamicMemberLookup property, then we actually
42004223
// form a subscript reference, so switch the kind.
42014224
if (foundDecl->choice.getKind() ==
4202-
OverloadChoiceKind::DynamicMemberLookup ||
4203-
foundDecl->choice.getKind() ==
4204-
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
4225+
OverloadChoiceKind::DynamicMemberLookup) {
42054226
kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
42064227
}
42074228
}

0 commit comments

Comments
 (0)