Skip to content

Commit f95d9b0

Browse files
committed
[TypeChecker] Add new type of overload choice to support keypath dynamic lookup
1 parent b3cb1a1 commit f95d9b0

File tree

8 files changed

+71
-32
lines changed

8 files changed

+71
-32
lines changed

lib/Sema/CSApply.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,10 @@ namespace {
26952695
/*isImplicit*/false,
26962696
AccessSemantics::Ordinary, selected);
26972697
}
2698+
2699+
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
2700+
break;
2701+
}
26982702
}
26992703

27002704
llvm_unreachable("Unhandled OverloadChoiceKind in switch.");
@@ -4194,8 +4198,10 @@ namespace {
41944198
if (foundDecl) {
41954199
// If this was a @dynamicMemberLookup property, then we actually
41964200
// form a subscript reference, so switch the kind.
4197-
if (foundDecl->choice.getKind()
4198-
== OverloadChoiceKind::DynamicMemberLookup) {
4201+
if (foundDecl->choice.getKind() ==
4202+
OverloadChoiceKind::DynamicMemberLookup ||
4203+
foundDecl->choice.getKind() ==
4204+
OverloadChoiceKind::KeyPathDynamicMemberLookup) {
41994205
kind = KeyPathExpr::Component::Kind::UnresolvedSubscript;
42004206
}
42014207
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,9 @@ bool RValueTreatedAsLValueFailure::diagnoseAsError() {
856856

857857
if (auto resolvedOverload = getResolvedOverload(getLocator()))
858858
if (resolvedOverload->Choice.getKind() ==
859-
OverloadChoiceKind::DynamicMemberLookup)
859+
OverloadChoiceKind::DynamicMemberLookup ||
860+
resolvedOverload->Choice.getKind() ==
861+
OverloadChoiceKind::KeyPathDynamicMemberLookup)
860862
subElementDiagID = diag::assignment_dynamic_property_has_immutable_base;
861863
} else if (auto sub = dyn_cast<SubscriptExpr>(diagExpr)) {
862864
subElementDiagID = diag::assignment_subscript_has_immutable_base;

lib/Sema/CSRanking.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static bool sameOverloadChoice(const OverloadChoice &x,
151151
case OverloadChoiceKind::DeclViaBridge:
152152
case OverloadChoiceKind::DeclViaUnwrappedOptional:
153153
case OverloadChoiceKind::DynamicMemberLookup:
154+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
154155
return sameDecl(x.getDecl(), y.getDecl());
155156

156157
case OverloadChoiceKind::TupleIndex:
@@ -893,6 +894,7 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
893894
case OverloadChoiceKind::DeclViaBridge:
894895
case OverloadChoiceKind::DeclViaUnwrappedOptional:
895896
case OverloadChoiceKind::DynamicMemberLookup:
897+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
896898
break;
897899
}
898900

lib/Sema/CSSimplify.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ bool constraints::areConservativelyCompatibleArgumentLabels(
117117

118118
case OverloadChoiceKind::BaseType:
119119
case OverloadChoiceKind::DynamicMemberLookup:
120+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
120121
case OverloadChoiceKind::TupleIndex:
121122
return true;
122123
}
@@ -3946,17 +3947,21 @@ performMemberLookup(ConstraintKind constraintKind, DeclName memberName,
39463947
baseTy, functionRefKind,
39473948
memberLocator,
39483949
includeInaccessibleMembers);
3949-
3950+
39503951
// Reflect the candidates found as `DynamicMemberLookup` results.
39513952
for (auto candidate : subscripts.ViableCandidates) {
3952-
auto decl = cast<SubscriptDecl>(candidate.getDecl());
3953-
if (isValidDynamicMemberLookupSubscript(decl, DC, TC))
3954-
result.addViable(
3955-
OverloadChoice::getDynamicMemberLookup(baseTy, decl, name));
3953+
auto *SD = cast<SubscriptDecl>(candidate.getDecl());
3954+
bool isKeyPathBased = isValidKeyPathDynamicMemberLookup(SD, TC);
3955+
3956+
if (isValidStringDynamicMemberLookup(SD, DC, TC) || isKeyPathBased)
3957+
result.addViable(OverloadChoice::getDynamicMemberLookup(
3958+
baseTy, SD, name, isKeyPathBased));
39563959
}
3960+
39573961
for (auto index : indices(subscripts.UnviableCandidates)) {
3958-
auto decl = subscripts.UnviableCandidates[index].getDecl();
3959-
auto choice = OverloadChoice::getDynamicMemberLookup(baseTy, decl,name);
3962+
auto *SD = cast<SubscriptDecl>(subscripts.UnviableCandidates[index].getDecl());
3963+
auto choice = OverloadChoice::getDynamicMemberLookup(
3964+
baseTy, SD, name, isValidKeyPathDynamicMemberLookup(SD, TC));
39603965
result.addUnviable(choice, subscripts.UnviableReasons[index]);
39613966
}
39623967
}

lib/Sema/Constraint.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
356356
printDecl();
357357
break;
358358
case OverloadChoiceKind::DynamicMemberLookup:
359+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
359360
Out << "dynamic member lookup '" << overload.getName() << "'";
360361
break;
361362
case OverloadChoiceKind::BaseType:

lib/Sema/ConstraintSystem.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,7 @@ Type ConstraintSystem::getEffectiveOverloadType(const OverloadChoice &overload,
14011401
case OverloadChoiceKind::DeclViaDynamic:
14021402
case OverloadChoiceKind::DeclViaUnwrappedOptional:
14031403
case OverloadChoiceKind::DynamicMemberLookup:
1404+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
14041405
case OverloadChoiceKind::KeyPathApplication:
14051406
case OverloadChoiceKind::TupleIndex:
14061407
return Type();
@@ -1717,7 +1718,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
17171718
case OverloadChoiceKind::DeclViaBridge:
17181719
case OverloadChoiceKind::DeclViaDynamic:
17191720
case OverloadChoiceKind::DeclViaUnwrappedOptional:
1720-
case OverloadChoiceKind::DynamicMemberLookup: {
1721+
case OverloadChoiceKind::DynamicMemberLookup:
1722+
case OverloadChoiceKind::KeyPathDynamicMemberLookup: {
17211723
// Retrieve the type of a reference to the specific declaration choice.
17221724
if (auto baseTy = choice.getBaseType()) {
17231725
assert(!baseTy->hasTypeParameter());
@@ -1879,6 +1881,10 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
18791881
protocol->getDeclaredType(),
18801882
locator);
18811883
}
1884+
1885+
if (kind == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1886+
assert(false && "not yet implemented");
1887+
}
18821888
break;
18831889
}
18841890

@@ -2115,8 +2121,9 @@ DeclName OverloadChoice::getName() const {
21152121
return DeclBaseName::createSubscript();
21162122

21172123
case OverloadChoiceKind::DynamicMemberLookup:
2118-
return DeclName(DynamicNameAndFRK.getPointer());
2119-
2124+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
2125+
return DeclName(DynamicMember.getPointer());
2126+
21202127
case OverloadChoiceKind::BaseType:
21212128
case OverloadChoiceKind::TupleIndex:
21222129
llvm_unreachable("no name!");
@@ -2453,6 +2460,7 @@ bool ConstraintSystem::diagnoseAmbiguity(Expr *expr,
24532460

24542461
case OverloadChoiceKind::KeyPathApplication:
24552462
case OverloadChoiceKind::DynamicMemberLookup:
2463+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
24562464
// Skip key path applications and dynamic member lookups, since we don't
24572465
// want them to noise up unrelated subscript diagnostics.
24582466
break;

lib/Sema/OverloadChoice.h

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ enum class OverloadChoiceKind : int {
4848
KeyPathApplication,
4949
/// The member is looked up using @dynamicMemberLookup.
5050
DynamicMemberLookup,
51+
/// The member with KeyPath parameter is looked up using
52+
/// @dynamicMemberLookup.
53+
KeyPathDynamicMemberLookup,
5154
/// The overload choice selects a particular declaration that
5255
/// was found by bridging the base value type to its Objective-C
5356
/// class type.
@@ -97,21 +100,26 @@ class OverloadChoice {
97100
///
98101
llvm::PointerUnion<ValueDecl*, OverloadChoiceKindWithTupleIndex> DeclOrKind;
99102

103+
/// If this OverloadChoice represents a DynamicMemberLookup result,
104+
/// then this holds the identifier for the original member being
105+
/// looked up, as well as 1 bit tag which identifies whether this
106+
/// choice represents a key-path based dynamic lookup.
107+
llvm::PointerIntPair<Identifier, 1, unsigned> DynamicMember;
108+
100109
/// This holds the kind of function reference (Unapplied, SingleApply,
101-
/// DoubleApply, Compound). If this OverloadChoice represents a
102-
/// DynamicMemberLookup result, then this holds the identifier for the
103-
/// original member being looked up.
104-
llvm::PointerIntPair<Identifier, 2, FunctionRefKind> DynamicNameAndFRK;
105-
110+
/// DoubleApply, Compound).
111+
/// FIXME: This needs two bits. Can we pack them somewhere?
112+
FunctionRefKind TheFunctionRefKind;
113+
106114
public:
107115
OverloadChoice()
108116
: BaseAndDeclKind(nullptr, 0), DeclOrKind(),
109-
DynamicNameAndFRK(Identifier(), FunctionRefKind::Unapplied) {}
117+
TheFunctionRefKind(FunctionRefKind::Unapplied) {}
110118

111119
OverloadChoice(Type base, ValueDecl *value,
112120
FunctionRefKind functionRefKind)
113121
: BaseAndDeclKind(base, 0),
114-
DynamicNameAndFRK(Identifier(), functionRefKind) {
122+
TheFunctionRefKind(functionRefKind) {
115123
assert(!base || !base->hasTypeParameter());
116124
assert((reinterpret_cast<uintptr_t>(value) & (uintptr_t)0x03) == 0 &&
117125
"Badly aligned decl");
@@ -121,7 +129,7 @@ class OverloadChoice {
121129

122130
OverloadChoice(Type base, OverloadChoiceKind kind)
123131
: BaseAndDeclKind(base, 0), DeclOrKind(uint32_t(kind)),
124-
DynamicNameAndFRK(Identifier(), FunctionRefKind::Unapplied) {
132+
TheFunctionRefKind(FunctionRefKind::Unapplied) {
125133
assert(base && "Must have a base type for overload choice");
126134
assert(!base->hasTypeParameter());
127135
assert(kind != OverloadChoiceKind::Decl &&
@@ -134,15 +142,15 @@ class OverloadChoice {
134142
OverloadChoice(Type base, unsigned index)
135143
: BaseAndDeclKind(base, 0),
136144
DeclOrKind(uint32_t(OverloadChoiceKind::TupleIndex)+index),
137-
DynamicNameAndFRK(Identifier(), FunctionRefKind::Unapplied) {
145+
TheFunctionRefKind(FunctionRefKind::Unapplied) {
138146
assert(base->getRValueType()->is<TupleType>() && "Must have tuple type");
139147
}
140148

141149
bool isInvalid() const {
142150
return BaseAndDeclKind.getPointer().isNull() &&
143151
BaseAndDeclKind.getInt() == 0 &&
144152
DeclOrKind.isNull() &&
145-
DynamicNameAndFRK.getInt() == FunctionRefKind::Unapplied;
153+
TheFunctionRefKind == FunctionRefKind::Unapplied;
146154
}
147155

148156
/// Retrieve an overload choice for a declaration that was found via
@@ -153,7 +161,7 @@ class OverloadChoice {
153161
result.BaseAndDeclKind.setPointer(base);
154162
result.BaseAndDeclKind.setInt(IsDeclViaDynamic);
155163
result.DeclOrKind = value;
156-
result.DynamicNameAndFRK.setInt(functionRefKind);
164+
result.TheFunctionRefKind = functionRefKind;
157165
return result;
158166
}
159167

@@ -165,7 +173,7 @@ class OverloadChoice {
165173
result.BaseAndDeclKind.setPointer(base);
166174
result.BaseAndDeclKind.setInt(IsDeclViaBridge);
167175
result.DeclOrKind = value;
168-
result.DynamicNameAndFRK.setInt(functionRefKind);
176+
result.TheFunctionRefKind = functionRefKind;
169177
return result;
170178
}
171179

@@ -178,20 +186,22 @@ class OverloadChoice {
178186
result.BaseAndDeclKind.setPointer(base);
179187
result.BaseAndDeclKind.setInt(IsDeclViaUnwrappedOptional);
180188
result.DeclOrKind = value;
181-
result.DynamicNameAndFRK.setInt(functionRefKind);
189+
result.TheFunctionRefKind = functionRefKind;
182190
return result;
183191
}
184192

185193
/// Retrieve an overload choice for a declaration that was found via
186194
/// dynamic member lookup. The `ValueDecl` is a `subscript(dynamicMember:)`
187195
/// method.
188196
static OverloadChoice getDynamicMemberLookup(Type base, ValueDecl *value,
189-
Identifier name) {
197+
Identifier name,
198+
bool isKeyPathBased) {
190199
OverloadChoice result;
191200
result.BaseAndDeclKind.setPointer(base);
192201
result.DeclOrKind = value;
193-
result.DynamicNameAndFRK.setPointer(name);
194-
result.DynamicNameAndFRK.setInt(FunctionRefKind::SingleApply);
202+
result.DynamicMember.setPointer(name);
203+
result.DynamicMember.setInt(isKeyPathBased);
204+
result.TheFunctionRefKind = FunctionRefKind::SingleApply;
195205
return result;
196206
}
197207

@@ -202,8 +212,11 @@ class OverloadChoice {
202212

203213
/// Determines the kind of overload choice this is.
204214
OverloadChoiceKind getKind() const {
205-
if (!DynamicNameAndFRK.getPointer().empty())
206-
return OverloadChoiceKind::DynamicMemberLookup;
215+
if (!DynamicMember.getPointer().empty()) {
216+
return DynamicMember.getInt()
217+
? OverloadChoiceKind::KeyPathDynamicMemberLookup
218+
: OverloadChoiceKind::DynamicMemberLookup;
219+
}
207220

208221
if (DeclOrKind.is<ValueDecl*>()) {
209222
switch (BaseAndDeclKind.getInt()) {
@@ -255,7 +268,7 @@ class OverloadChoice {
255268

256269
FunctionRefKind getFunctionRefKind() const {
257270
assert(isDecl() && "only makes sense for declaration choices");
258-
return DynamicNameAndFRK.getInt();
271+
return TheFunctionRefKind;
259272
}
260273
};
261274

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3311,6 +3311,7 @@ void Solution::dump(raw_ostream &out) const {
33113311
break;
33123312

33133313
case OverloadChoiceKind::DynamicMemberLookup:
3314+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
33143315
out << "dynamic member lookup root "
33153316
<< choice.getBaseType()->getString()
33163317
<< " name='" << choice.getName() << "'\n";
@@ -3504,6 +3505,7 @@ void ConstraintSystem::print(raw_ostream &out) {
35043505
break;
35053506

35063507
case OverloadChoiceKind::DynamicMemberLookup:
3508+
case OverloadChoiceKind::KeyPathDynamicMemberLookup:
35073509
out << "dynamic member lookup:"
35083510
<< choice.getBaseType()->getString() << " name="
35093511
<< choice.getName() << "\n";

0 commit comments

Comments
 (0)