16
16
//
17
17
// ===----------------------------------------------------------------------===//
18
18
#include " TypeChecker.h"
19
+ #include " swift/AST/ExistentialLayout.h"
19
20
#include " swift/AST/Initializer.h"
20
21
#include " swift/AST/NameLookup.h"
21
22
#include " swift/AST/ProtocolConformance.h"
@@ -121,35 +122,52 @@ namespace {
121
122
if (!Options.contains (NameLookupFlags::ProtocolMembers) ||
122
123
!isa<ProtocolDecl>(foundDC) ||
123
124
isa<GenericTypeParamDecl>(found) ||
124
- (isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator ()) ||
125
- foundInType->isAnyExistentialType ()) {
125
+ (isa<FuncDecl>(found) && cast<FuncDecl>(found)->isOperator ())) {
126
126
addResult (found);
127
127
return ;
128
128
}
129
129
130
130
assert (isa<ProtocolDecl>(foundDC));
131
131
132
+ auto conformingType = foundInType;
133
+
134
+ // When performing a lookup on a subclass existential, we might
135
+ // find a member of the class that witnesses a requirement on a
136
+ // protocol that the class conforms to.
137
+ //
138
+ // Since subclass existentials don't normally conform to protocols,
139
+ // pull out the superclass instead, and use that below.
140
+ if (foundInType->isExistentialType ()) {
141
+ auto layout = foundInType->getExistentialLayout ();
142
+ if (layout.superclass )
143
+ conformingType = layout.superclass ;
144
+ }
145
+
132
146
// If we found something within the protocol itself, and our
133
147
// search began somewhere that is not in a protocol or extension
134
148
// thereof, remap this declaration to the witness.
135
149
if (foundInType->is <ArchetypeType>() ||
150
+ foundInType->isExistentialType () ||
136
151
Options.contains (NameLookupFlags::PerformConformanceCheck)) {
137
152
// Dig out the protocol conformance.
138
- auto conformance = TC.conformsToProtocol (foundInType , foundProto, DC,
153
+ auto conformance = TC.conformsToProtocol (conformingType , foundProto, DC,
139
154
conformanceOptions);
140
- if (!conformance)
155
+ if (!conformance) {
156
+ // If there's no conformance, we have an existential
157
+ // and we found a member from one of the protocols, and
158
+ // not a class constraint if any.
159
+ assert (foundInType->isExistentialType ());
160
+ addResult (found);
141
161
return ;
162
+ }
142
163
143
164
if (conformance->isAbstract ()) {
144
- assert (foundInType->is <ArchetypeType>());
165
+ assert (foundInType->is <ArchetypeType>() ||
166
+ foundInType->isExistentialType ());
145
167
addResult (found);
146
168
return ;
147
169
}
148
170
149
- // If we're validating the protocol recursively, bail out.
150
- if (!foundProto->hasValidSignature ())
151
- return ;
152
-
153
171
// Dig out the witness.
154
172
ValueDecl *witness = nullptr ;
155
173
auto concrete = conformance->getConcrete ();
@@ -162,6 +180,10 @@ namespace {
162
180
163
181
// FIXME: the "isa<ProtocolDecl>()" check will be wrong for
164
182
// default implementations in protocols.
183
+ //
184
+ // If we have an imported conformance or the witness could
185
+ // not be deserialized, getWitnessDecl() will just return
186
+ // the requirement, so just drop the lookup result here.
165
187
if (witness && !isa<ProtocolDecl>(witness->getDeclContext ()))
166
188
addResult (witness);
167
189
0 commit comments