@@ -880,6 +880,11 @@ class swift::MemberLookupTable {
880
880
// / Lookup table mapping names to the set of declarations with that name.
881
881
LookupTable Lookup;
882
882
883
+ // / The set of names of lazily-loaded members that the lookup table has a
884
+ // / complete accounting of with respect to all known extensions of its
885
+ // / parent nominal type.
886
+ llvm::DenseSet<DeclBaseName> LazilyCompleteNames;
887
+
883
888
public:
884
889
// / Create a new member lookup table.
885
890
explicit MemberLookupTable (ASTContext &ctx);
@@ -893,6 +898,24 @@ class swift::MemberLookupTable {
893
898
// / Add the given members to the lookup table.
894
899
void addMembers (DeclRange members);
895
900
901
+ // / Returns \c true if the lookup table has a complete accounting of the
902
+ // / given name.
903
+ bool isLazilyComplete (DeclBaseName name) const {
904
+ return LazilyCompleteNames.find (name) != LazilyCompleteNames.end ();
905
+ }
906
+
907
+ // / Mark a given lazily-loaded name as being complete.
908
+ void markLazilyComplete (DeclBaseName name) {
909
+ LazilyCompleteNames.insert (name);
910
+ }
911
+
912
+ // / Clears the cache of lazily-complete names. This _must_ be called when
913
+ // / new extensions with lazy members are added to the type, or direct lookup
914
+ // / will return inconsistent or stale results.
915
+ void clearLazilyCompleteCache () {
916
+ LazilyCompleteNames.clear ();
917
+ }
918
+
896
919
// / Iterator into the lookup table.
897
920
typedef LookupTable::iterator iterator;
898
921
@@ -912,7 +935,11 @@ class swift::MemberLookupTable {
912
935
913
936
os << " Lookup:\n " ;
914
937
for (auto &pair : Lookup) {
915
- pair.getFirst ().print (os) << " :\n " ;
938
+ pair.getFirst ().print (os);
939
+ if (isLazilyComplete (pair.getFirst ().getBaseName ())) {
940
+ os << " (lazily complete)" ;
941
+ }
942
+ os << " :\n " ;
916
943
for (auto &decl : pair.getSecond ()) {
917
944
os << " - " ;
918
945
decl->dumpRef (os);
@@ -926,21 +953,6 @@ class swift::MemberLookupTable {
926
953
dump (llvm::errs ());
927
954
}
928
955
929
- // Mark all Decls in this table as not-resident in a table, drop
930
- // references to them. Should only be called when this was not fully-populated
931
- // from an IterableDeclContext.
932
- void clear () {
933
- // LastExtensionIncluded would only be non-null if this was populated from
934
- // an IterableDeclContext (though it might still be null in that case).
935
- assert (LastExtensionIncluded == nullptr );
936
- for (auto const &i : Lookup) {
937
- for (auto d : i.getSecond ()) {
938
- d->setAlreadyInLookupTable (false );
939
- }
940
- }
941
- Lookup.clear ();
942
- }
943
-
944
956
// Only allow allocation of member lookup tables using the allocator in
945
957
// ASTContext or by doing a placement new.
946
958
void *operator new (size_t Bytes, ASTContext &C,
@@ -1043,25 +1055,26 @@ void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) {
1043
1055
}
1044
1056
}
1045
1057
1046
- void NominalTypeDecl::addedMember (Decl *member) {
1047
- auto *vd = dyn_cast<ValueDecl>(member);
1048
- if (!vd)
1049
- return ;
1058
+ void NominalTypeDecl::addedExtension (ExtensionDecl *ext) {
1059
+ if (!LookupTable) return ;
1050
1060
1061
+ if (ext->hasLazyMembers ()) {
1062
+ LookupTable->addMembers (ext->getCurrentMembersWithoutLoading ());
1063
+ LookupTable->clearLazilyCompleteCache ();
1064
+ } else {
1065
+ LookupTable->addMembers (ext->getMembers ());
1066
+ }
1067
+ }
1068
+
1069
+ void NominalTypeDecl::addedMember (Decl *member) {
1051
1070
// If we have a lookup table, add the new member to it. If not, we'll pick up
1052
1071
// this member when we first create the table.
1053
- if (auto *lookup = LookupTable) {
1054
- if (hasLazyMembers ()) {
1055
- // If we have lazy members, only add the new member to the lookup
1056
- // table if we already have another member with the same name.
1057
- // The presence of a lookup table entry indicates that the
1058
- // nominal as well as all extensions have already been searched.
1059
- if (lookup->find (vd->getBaseName ()) == lookup->end ())
1060
- return ;
1061
- }
1072
+ auto *vd = dyn_cast<ValueDecl>(member);
1073
+ auto *lookup = LookupTable;
1074
+ if (!vd || !lookup)
1075
+ return ;
1062
1076
1063
- lookup->addMember (vd);
1064
- }
1077
+ lookup->addMember (vd);
1065
1078
}
1066
1079
1067
1080
void ExtensionDecl::addedMember (Decl *member) {
@@ -1094,8 +1107,8 @@ void ExtensionDecl::addedMember(Decl *member) {
1094
1107
// │ExtensionDecl *LastExtension ─┼───────┐│ │ └───┐
1095
1108
// │ │ ││ └──────────────────────┐│
1096
1109
// │MemberLookupTable *LookupTable├─┐ ││ ││
1097
- // │bool LookupTableComplete │ │ ││ ┌─────────────────┐ ││
1098
- // └──────────────────────────────┘ │ ││ │ExtensionDecl │ ││
1110
+ // └──────────────────────────────┘ │ ││ ┌─────────────────┐ ││
1111
+ // │ ││ │ExtensionDecl │ ││
1099
1112
// │ ││ │------------- │ ││
1100
1113
// ┌─────────────┘ │└────▶│ExtensionDecl │ ││
1101
1114
// │ │ │ *NextExtension ├──┐ ││
@@ -1156,34 +1169,30 @@ populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx,
1156
1169
}
1157
1170
}
1158
1171
1159
- static void populateLookupTableEntryFromCurrentMembers (
1160
- ASTContext &ctx, MemberLookupTable &LookupTable, DeclBaseName name,
1161
- IterableDeclContext *IDC) {
1162
- for (auto m : IDC->getMembers ()) {
1163
- if (auto v = dyn_cast<ValueDecl>(m)) {
1164
- if (v->getBaseName () == name) {
1165
- LookupTable.addMember (m);
1166
- }
1167
- }
1168
- }
1169
- }
1170
-
1171
1172
static void
1172
1173
populateLookupTableEntryFromExtensions (ASTContext &ctx,
1173
1174
MemberLookupTable &table,
1174
1175
NominalTypeDecl *nominal,
1175
1176
DeclBaseName name) {
1177
+ assert (!table.isLazilyComplete (name) &&
1178
+ " Should not be searching extensions for complete name!" );
1179
+
1176
1180
for (auto e : nominal->getExtensions ()) {
1177
- // If we can retrieve the members of this extension without deserializing
1178
- // anything, do so now.
1179
- if (!e->wasDeserialized () && !e->hasClangNode ()) {
1180
- populateLookupTableEntryFromCurrentMembers (ctx, table, name, e);
1181
+ // If there's no lazy members to look at, all the members of this extension
1182
+ // are present in the lookup table.
1183
+ if (!e->hasLazyMembers ()) {
1181
1184
continue ;
1182
1185
}
1183
1186
1187
+ assert (e->wasDeserialized () || e->hasClangNode () &&
1188
+ " Extension without deserializable content has lazy members!" );
1184
1189
assert (!e->hasUnparsedMembers ());
1190
+
1191
+ // Try lazy loading. If that fails, then we fall back by loading the
1192
+ // entire extension. FIXME: It's rather unfortunate that we fall off the
1193
+ // happy path because the Clang Importer can't handle lazy import-as-member.
1185
1194
if (populateLookupTableEntryFromLazyIDCLoader (ctx, table, name, e)) {
1186
- populateLookupTableEntryFromCurrentMembers (ctx, table, name, e );
1195
+ e-> loadAllMembers ( );
1187
1196
}
1188
1197
}
1189
1198
}
@@ -1204,19 +1213,18 @@ void NominalTypeDecl::prepareLookupTable() {
1204
1213
1205
1214
// Lazy members: if the table needs population, populate the table _only
1206
1215
// from those members already in the IDC member list_ such as implicits or
1207
- // globals-as-members, then update table entries from the extensions that
1208
- // have the same names as any such initial-population members.
1216
+ // globals-as-members.
1209
1217
LookupTable->addMembers (getCurrentMembersWithoutLoading ());
1210
-
1211
- llvm::SmallSet<DeclBaseName, 4 > baseNamesPresent;
1212
- for ( auto entry : *LookupTable) {
1213
- auto baseName = entry. getFirst (). getBaseName ();
1214
- if (!baseNamesPresent. insert (baseName). second )
1218
+ for ( auto e : getExtensions ()) {
1219
+ // If we can lazy-load this extension, only take the members we've loaded
1220
+ // so far.
1221
+ if (e-> wasDeserialized () || e-> hasClangNode ()) {
1222
+ LookupTable-> addMembers (e-> getCurrentMembersWithoutLoading ());
1215
1223
continue ;
1224
+ }
1216
1225
1217
- populateLookupTableEntryFromExtensions (getASTContext (),
1218
- *LookupTable,
1219
- this , baseName);
1226
+ // Else, load all the members into the table.
1227
+ LookupTable->addMembers (e->getMembers ());
1220
1228
}
1221
1229
} else {
1222
1230
LookupTable->addMembers (getMembers ());
@@ -1276,8 +1284,9 @@ NominalTypeDecl::lookupDirect(DeclName name,
1276
1284
DeclName name) -> Optional<TinyPtrVector<ValueDecl *>> {
1277
1285
// Look for a declaration with this name.
1278
1286
auto known = table->find (name);
1279
- if (known == table->end ())
1287
+ if (known == table->end ()) {
1280
1288
return None;
1289
+ }
1281
1290
1282
1291
// We found something; return it.
1283
1292
return maybeFilterOutAttrImplements (known->second , name,
@@ -1297,29 +1306,22 @@ NominalTypeDecl::lookupDirect(DeclName name,
1297
1306
1298
1307
if (!useNamedLazyMemberLoading) {
1299
1308
updateLookupTable (LookupTable);
1309
+ } else if (!LookupTable->isLazilyComplete (name.getBaseName ())) {
1310
+ // The lookup table believes it doesn't have a complete accounting of this
1311
+ // name - either because we're never seen it before, or another extension
1312
+ // was registered since the last time we searched. Ask the loaders to give
1313
+ // us a hand.
1314
+ auto &Table = *LookupTable;
1315
+ DeclBaseName baseName (name.getBaseName ());
1316
+ if (populateLookupTableEntryFromLazyIDCLoader (ctx, Table, baseName, this )) {
1317
+ updateLookupTable (LookupTable);
1318
+ } else {
1319
+ populateLookupTableEntryFromExtensions (ctx, Table, this , baseName);
1320
+ }
1321
+ Table.markLazilyComplete (baseName);
1300
1322
}
1301
1323
1302
1324
// Look for a declaration with this name.
1303
- if (auto lookup = tryCacheLookup (LookupTable, name))
1304
- return lookup.getValue ();
1305
-
1306
- if (!useNamedLazyMemberLoading) {
1307
- return { };
1308
- }
1309
-
1310
- // If we get here, we had a cache-miss and _are_ using
1311
- // NamedLazyMemberLoading. Try to populate a _single_ entry in the
1312
- // MemberLookupTable from both this nominal and all of its extensions, and
1313
- // retry.
1314
- auto &Table = *LookupTable;
1315
- if (populateLookupTableEntryFromLazyIDCLoader (ctx, Table,
1316
- name.getBaseName (), this )) {
1317
- updateLookupTable (LookupTable);
1318
- } else {
1319
- populateLookupTableEntryFromExtensions (ctx, Table, this ,
1320
- name.getBaseName ());
1321
- }
1322
-
1323
1325
return tryCacheLookup (LookupTable, name)
1324
1326
.getValueOr (TinyPtrVector<ValueDecl *>());
1325
1327
}
0 commit comments