Skip to content

Commit a3204b9

Browse files
committed
Allow #keyPath() to resolve type refs
1 parent baa1a73 commit a3204b9

15 files changed

+89
-25
lines changed

include/swift/AST/Expr.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4944,6 +4944,7 @@ class KeyPathExpr : public Expr {
49444944
OptionalWrap,
49454945
Identity,
49464946
TupleElement,
4947+
Type,
49474948
};
49484949

49494950
private:
@@ -5052,7 +5053,17 @@ class KeyPathExpr : public Expr {
50525053
propertyType,
50535054
loc);
50545055
}
5055-
5056+
5057+
/// Create a component for a type.
5058+
static Component forType(ConcreteDeclRef typeRef,
5059+
Type type,
5060+
SourceLoc loc) {
5061+
return Component(nullptr, typeRef, nullptr, {}, {},
5062+
Kind::Type,
5063+
type,
5064+
loc);
5065+
}
5066+
50565067
/// Create a component for a subscript.
50575068
static Component forSubscript(ASTContext &ctx,
50585069
ConcreteDeclRef subscript,
@@ -5135,6 +5146,7 @@ class KeyPathExpr : public Expr {
51355146
case Kind::Property:
51365147
case Kind::Identity:
51375148
case Kind::TupleElement:
5149+
case Kind::Type:
51385150
return true;
51395151

51405152
case Kind::UnresolvedSubscript:
@@ -5159,6 +5171,7 @@ class KeyPathExpr : public Expr {
51595171
case Kind::Property:
51605172
case Kind::Identity:
51615173
case Kind::TupleElement:
5174+
case Kind::Type:
51625175
return nullptr;
51635176
}
51645177
llvm_unreachable("unhandled kind");
@@ -5178,6 +5191,7 @@ class KeyPathExpr : public Expr {
51785191
case Kind::Property:
51795192
case Kind::Identity:
51805193
case Kind::TupleElement:
5194+
case Kind::Type:
51815195
llvm_unreachable("no subscript labels for this kind");
51825196
}
51835197
llvm_unreachable("unhandled kind");
@@ -5200,6 +5214,7 @@ class KeyPathExpr : public Expr {
52005214
case Kind::Property:
52015215
case Kind::Identity:
52025216
case Kind::TupleElement:
5217+
case Kind::Type:
52035218
return {};
52045219
}
52055220
llvm_unreachable("unhandled kind");
@@ -5222,6 +5237,7 @@ class KeyPathExpr : public Expr {
52225237
case Kind::Property:
52235238
case Kind::Identity:
52245239
case Kind::TupleElement:
5240+
case Kind::Type:
52255241
llvm_unreachable("no unresolved name for this kind");
52265242
}
52275243
llvm_unreachable("unhandled kind");
@@ -5231,6 +5247,7 @@ class KeyPathExpr : public Expr {
52315247
switch (getKind()) {
52325248
case Kind::Property:
52335249
case Kind::Subscript:
5250+
case Kind::Type:
52345251
return Decl.ResolvedDecl;
52355252

52365253
case Kind::Invalid:
@@ -5260,6 +5277,7 @@ class KeyPathExpr : public Expr {
52605277
case Kind::Identity:
52615278
case Kind::Property:
52625279
case Kind::Subscript:
5280+
case Kind::Type:
52635281
llvm_unreachable("no field number for this kind");
52645282
}
52655283
llvm_unreachable("unhandled kind");

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,7 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
27342734
PrintWithColorRAII(OS, ASTNodeColor) << "unresolved_subscript";
27352735
printArgumentLabels(component.getSubscriptLabels());
27362736
break;
2737+
27372738
case KeyPathExpr::Component::Kind::Identity:
27382739
PrintWithColorRAII(OS, ASTNodeColor) << "identity";
27392740
break;
@@ -2743,6 +2744,10 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
27432744
PrintWithColorRAII(OS, DiscriminatorColor)
27442745
<< "#" << component.getTupleIndex();
27452746
break;
2747+
2748+
case KeyPathExpr::Component::Kind::Type:
2749+
OS << "type_ref ";
2750+
break;
27462751
}
27472752
PrintWithColorRAII(OS, TypeColor)
27482753
<< " type='" << GetTypeOfKeyPathComponent(E, i) << "'";

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
10711071
case KeyPathExpr::Component::Kind::Invalid:
10721072
case KeyPathExpr::Component::Kind::Identity:
10731073
case KeyPathExpr::Component::Kind::TupleElement:
1074+
case KeyPathExpr::Component::Kind::Type:
10741075
// No subexpr to visit.
10751076
break;
10761077
}

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,6 +2141,7 @@ void KeyPathExpr::Component::setSubscriptIndexHashableConformances(
21412141
case Kind::Property:
21422142
case Kind::Identity:
21432143
case Kind::TupleElement:
2144+
case Kind::Type:
21442145
llvm_unreachable("no hashable conformances for this kind");
21452146
}
21462147
}

lib/IDE/SourceEntityWalker.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ std::pair<bool, Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
350350
for (auto &component : KPE->getComponents()) {
351351
switch (component.getKind()) {
352352
case KeyPathExpr::Component::Kind::Property:
353-
case KeyPathExpr::Component::Kind::Subscript: {
353+
case KeyPathExpr::Component::Kind::Subscript:
354+
case KeyPathExpr::Component::Kind::Type: {
354355
auto *decl = component.getDeclRef().getDecl();
355356
auto loc = component.getLoc();
356357
SourceRange range(loc, loc);

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,8 @@ RValue RValueEmitter::visitKeyPathExpr(KeyPathExpr *E, SGFContext C) {
35643564
for (auto &component : E->getComponents()) {
35653565
switch (auto kind = component.getKind()) {
35663566
case KeyPathExpr::Component::Kind::Property:
3567-
case KeyPathExpr::Component::Kind::Subscript: {
3567+
case KeyPathExpr::Component::Kind::Subscript:
3568+
case KeyPathExpr::Component::Kind::Type: {
35683569
auto decl = cast<AbstractStorageDecl>(component.getDeclRef().getDecl());
35693570

35703571
unsigned numOperands = operands.size();

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ static bool buildObjCKeyPathString(KeyPathExpr *E,
246246
}
247247
case KeyPathExpr::Component::Kind::TupleElement:
248248
case KeyPathExpr::Component::Kind::Subscript:
249-
// Subscripts and tuples aren't generally represented in KVC.
249+
case KeyPathExpr::Component::Kind::Type:
250+
// Subscripts, tuples and types aren't generally represented in KVC.
250251
// TODO: There are some subscript forms we could map to KVC, such as
251252
// when indexing a Dictionary or NSDictionary by string, or when applying
252253
// a mapping subscript operation to Array/Set or NSArray/NSSet.
@@ -4265,6 +4266,7 @@ namespace {
42654266
case KeyPathExpr::Component::Kind::Subscript:
42664267
case KeyPathExpr::Component::Kind::OptionalWrap:
42674268
case KeyPathExpr::Component::Kind::TupleElement:
4269+
case KeyPathExpr::Component::Kind::Type:
42684270
llvm_unreachable("already resolved");
42694271
}
42704272

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3049,7 +3049,8 @@ namespace {
30493049
case KeyPathExpr::Component::Kind::UnresolvedProperty:
30503050
// This should only appear in resolved ASTs, but we may need to
30513051
// re-type-check the constraints during failure diagnosis.
3052-
case KeyPathExpr::Component::Kind::Property: {
3052+
case KeyPathExpr::Component::Kind::Property:
3053+
case KeyPathExpr::Component::Kind::Type: {
30533054
auto memberTy = CS.createTypeVariable(resultLocator,
30543055
TVO_CanBindToLValue |
30553056
TVO_CanBindToNoEscape);

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6949,6 +6949,7 @@ ConstraintSystem::simplifyKeyPathConstraint(
69496949

69506950
case KeyPathExpr::Component::Kind::Property:
69516951
case KeyPathExpr::Component::Kind::Subscript:
6952+
case KeyPathExpr::Component::Kind::Type:
69526953
case KeyPathExpr::Component::Kind::UnresolvedProperty:
69536954
case KeyPathExpr::Component::Kind::UnresolvedSubscript: {
69546955
auto *componentLoc = getConstraintLocator(

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,8 @@ ConstraintSystem::getCalleeLocator(ConstraintLocator *locator,
466466
anchor, {*componentElt, ConstraintLocator::SubscriptMember});
467467
case ComponentKind::UnresolvedProperty:
468468
case ComponentKind::Property:
469-
// For a property, the choice is just given by the component.
469+
case ComponentKind::Type:
470+
// For properties and types, the choice is just given by the component.
470471
return getConstraintLocator(anchor, *componentElt);
471472
case ComponentKind::TupleElement:
472473
llvm_unreachable("Not implemented by CSGen");

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2472,7 +2472,8 @@ class AvailabilityWalker : public ASTWalker {
24722472
for (auto &component : KP->getComponents()) {
24732473
switch (component.getKind()) {
24742474
case KeyPathExpr::Component::Kind::Property:
2475-
case KeyPathExpr::Component::Kind::Subscript: {
2475+
case KeyPathExpr::Component::Kind::Subscript:
2476+
case KeyPathExpr::Component::Kind::Type: {
24762477
auto *decl = component.getDeclRef().getDecl();
24772478
auto loc = component.getLoc();
24782479
SourceRange range(loc, loc);

lib/Sema/TypeCheckExprObjC.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,16 @@ Optional<Type> TypeChecker::checkObjCKeyPathExpr(DeclContext *dc,
218218
diag::expr_unsupported_objc_key_path_component,
219219
(unsigned)kind);
220220
continue;
221-
case KeyPathExpr::Component::Kind::OptionalWrap:
222221
case KeyPathExpr::Component::Kind::Property:
222+
case KeyPathExpr::Component::Kind::Type: {
223+
//For code completion purposes, we only care about the last expression.
224+
if (&component == &expr->getComponents().back()) {
225+
return component.getComponentType();
226+
} else {
227+
continue;
228+
}
229+
}
230+
case KeyPathExpr::Component::Kind::OptionalWrap:
223231
case KeyPathExpr::Component::Kind::Subscript:
224232
llvm_unreachable("already resolved!");
225233
}
@@ -321,10 +329,11 @@ Optional<Type> TypeChecker::checkObjCKeyPathExpr(DeclContext *dc,
321329
if (auto var = dyn_cast<VarDecl>(found)) {
322330
// Resolve this component to the variable we found.
323331
auto varRef = ConcreteDeclRef(var);
332+
Type type = var->getInterfaceType();
324333
auto resolved =
325-
KeyPathExpr::Component::forProperty(varRef, Type(), componentNameLoc);
334+
KeyPathExpr::Component::forProperty(varRef, type, componentNameLoc);
326335
resolvedComponents.push_back(resolved);
327-
updateState(/*isProperty=*/true, var->getInterfaceType());
336+
updateState(/*isProperty=*/true, type);
328337

329338
// Check that the property is @objc.
330339
if (!var->isObjC()) {
@@ -390,6 +399,11 @@ Optional<Type> TypeChecker::checkObjCKeyPathExpr(DeclContext *dc,
390399
break;
391400
}
392401

402+
// Resolve this component to the type we found.
403+
auto typeRef = ConcreteDeclRef(type);
404+
auto resolved =
405+
KeyPathExpr::Component::forType(typeRef, newType, componentNameLoc);
406+
resolvedComponents.push_back(resolved);
393407
updateState(/*isProperty=*/false, newType);
394408
continue;
395409
}

test/IDE/complete_pound_keypath.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_2 | %FileCheck -check-prefix=CHECK-IN_KEYPATH %s
88

9+
// RUN: %target-swift-ide-test(mock-sdk: %clang-importer-sdk) -code-completion -source-filename %s -code-completion-token=IN_KEYPATH_3 | %FileCheck -check-prefix=CHECK-IN_KEYPATH_3 %s
10+
911

1012
// REQUIRES: objc_interop
1113

@@ -34,6 +36,10 @@ func completeInKeyPath2() {
3436
_ = #keyPath(ObjCClass.#^IN_KEYPATH_2^#
3537
}
3638

39+
func completeInKeyPath3() {
40+
_ = #keyPath(ObjCClass.prop1.#^IN_KEYPATH_3^#
41+
}
42+
3743
// CHECK-AFTER_POUND-NOT: keyPath
3844

3945
// CHECK-KEYPATH_ARG: Keyword/None/TypeRelation[Identical]: #keyPath({#@objc property sequence#})[#String#]; name=#keyPath(@objc property sequence)
@@ -42,4 +48,5 @@ func completeInKeyPath2() {
4248
// CHECK-IN_KEYPATH: Decl[InstanceVar]/CurrNominal: prop2[#ObjCClass?#]; name=prop2
4349
// CHECK-IN_KEYPATH: Decl[InstanceVar]/Super: hashValue[#Int#]; name=hashValue
4450

51+
// CHECK-IN_KEYPATH_3: Decl[InstanceVar]/CurrNominal: hashValue[#Int#]; name=hashValue
4552

test/Index/index_keypaths.swift

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,31 @@ struct MyStruct {
77
}
88
}
99

10-
class MyClass {
11-
class Inner {
12-
@objc var myProp = 1
13-
}
14-
}
15-
1610
let a = \MyStruct.Inner.myProp
1711
// CHECK: [[@LINE-1]]:25 | {{.*}} | myProp
1812
// CHECK: [[@LINE-2]]:10 | {{.*}} | MyStruct
1913
// CHECK: [[@LINE-3]]:19 | {{.*}} | Inner
2014
let b: KeyPath<MyStruct.Inner, Int> = \.myProp
2115
// CHECK: [[@LINE-1]]:41 | {{.*}} | myProp
22-
let c = \MyClass.Inner.myProp
16+
17+
class MyClass {
18+
class Inner {
19+
@objc var myProp = 1
20+
func method() {
21+
let c: String = #keyPath(myProp)
22+
// CHECK: [[@LINE-1]]:32 | {{.*}} | myProp
23+
}
24+
}
25+
}
26+
27+
let d: String = #keyPath(MyClass.Inner.myProp)
28+
// CHECK: [[@LINE-1]]:26 | {{.*}} | MyClass
29+
// CHECK: [[@LINE-2]]:34 | {{.*}} | Inner
30+
// CHECK: [[@LINE-3]]:40 | {{.*}} | myProp
31+
32+
let e = \MyClass.Inner.myProp
2333
// CHECK: [[@LINE-1]]:24 | {{.*}} | myProp
2434
// CHECK: [[@LINE-2]]:10 | {{.*}} | MyClass
2535
// CHECK: [[@LINE-3]]:18 | {{.*}} | Inner
26-
let d: KeyPath<MyClass.Inner, Int> = \.myProp
36+
let f: KeyPath<MyClass.Inner, Int> = \.myProp
2737
// CHECK: [[@LINE-1]]:40 | {{.*}} | myProp

test/expr/primary/keypath/keypath-objc.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func testKeyPath(a: A, b: B) {
5757
let _: String = #keyPath(A.propString)
5858

5959
// Property of String property (which looks on NSString)
60-
let _: String = #keyPath(A.propString.URLsInText)
60+
let _: String = #keyPath(A.propString.urlsInText)
6161

6262
// String property with a suffix
6363
let _: String = #keyPath(A.propString).description
@@ -72,36 +72,36 @@ func testKeyPath(a: A, b: B) {
7272

7373
// Array property (make sure we look at the array element).
7474
let _: String = #keyPath(A.propArray)
75-
let _: String = #keyPath(A.propArray.URLsInText)
75+
let _: String = #keyPath(A.propArray.urlsInText)
7676

7777
// Dictionary property (make sure we look at the value type).
7878
let _: String = #keyPath(A.propDict.anyKeyName)
7979
let _: String = #keyPath(A.propDict.anyKeyName.propA)
8080

8181
// Set property (make sure we look at the set element).
8282
let _: String = #keyPath(A.propSet)
83-
let _: String = #keyPath(A.propSet.URLsInText)
83+
let _: String = #keyPath(A.propSet.urlsInText)
8484

8585
// AnyObject property
86-
let _: String = #keyPath(A.propAnyObject.URLsInText)
86+
let _: String = #keyPath(A.propAnyObject.urlsInText)
8787
let _: String = #keyPath(A.propAnyObject.propA)
8888
let _: String = #keyPath(A.propAnyObject.propB)
8989
let _: String = #keyPath(A.propAnyObject.description)
9090

9191
// NSString property
92-
let _: String = #keyPath(A.propNSString.URLsInText)
92+
let _: String = #keyPath(A.propNSString.urlsInText)
9393

9494
// NSArray property (AnyObject array element).
9595
let _: String = #keyPath(A.propNSArray)
96-
let _: String = #keyPath(A.propNSArray.URLsInText)
96+
let _: String = #keyPath(A.propNSArray.urlsInText)
9797

9898
// NSDictionary property (AnyObject value type).
9999
let _: String = #keyPath(A.propNSDict.anyKeyName)
100100
let _: String = #keyPath(A.propNSDict.anyKeyName.propA)
101101

102102
// NSSet property (AnyObject set element).
103103
let _: String = #keyPath(A.propNSSet)
104-
let _: String = #keyPath(A.propNSSet.URLsInText)
104+
let _: String = #keyPath(A.propNSSet.urlsInText)
105105

106106
// Property with keyword name.
107107
let _: String = #keyPath(A.repeat)

0 commit comments

Comments
 (0)