|
26 | 26 | #include "swift/AST/SourceFile.h"
|
27 | 27 | #include "swift/AST/TypeCheckRequests.h"
|
28 | 28 | #include "swift/AST/Types.h"
|
| 29 | +#include "swift/AST/DiagnosticsSema.h" |
29 | 30 | #include "swift/Basic/Assertions.h"
|
30 | 31 | #include "swift/Basic/SourceManager.h"
|
31 | 32 | #include "swift/Basic/Statistic.h"
|
@@ -1174,6 +1175,145 @@ void IterableDeclContext::loadAllMembers() const {
|
1174 | 1175 | --s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts;
|
1175 | 1176 | }
|
1176 | 1177 |
|
| 1178 | +// Checks whether members of this decl and their respective members |
| 1179 | +// (recursively) were deserialized correctly and emits a diagnostic |
| 1180 | +// if deserialization failed. Requires accessing module and this decl's |
| 1181 | +// module are in the same package, and this decl's module has package |
| 1182 | +// optimization enabled. |
| 1183 | +void IterableDeclContext::checkDeserializeMemberErrorInPackage(ModuleDecl *accessingModule) { |
| 1184 | + // Only check if accessing module is in the same package as this |
| 1185 | + // decl's module, which has package optimization enabled. |
| 1186 | + if (!getDecl()->getModuleContext()->inSamePackage(accessingModule) || |
| 1187 | + !getDecl()->getModuleContext()->isResilient() || |
| 1188 | + !getDecl()->getModuleContext()->serializePackageEnabled()) |
| 1189 | + return; |
| 1190 | + // Bail if already checked for an error. |
| 1191 | + if (checkedForDeserializeMemberError()) |
| 1192 | + return; |
| 1193 | + // If members were not deserialized, force load here. |
| 1194 | + if (!didDeserializeMembers()) { |
| 1195 | + // This needs to be set to force load all members if not done already. |
| 1196 | + setHasLazyMembers(true); |
| 1197 | + // Calling getMembers actually loads the members. |
| 1198 | + auto members = getMembers(); |
| 1199 | + assert(!hasLazyMembers()); |
| 1200 | + assert(didDeserializeMembers()); |
| 1201 | + } |
| 1202 | + // Members could have been deserialized from other flows. Check |
| 1203 | + // for an error here. First mark this decl 'checked' to prevent |
| 1204 | + // infinite recursion in case of self-referencing members. |
| 1205 | + setCheckedForDeserializeMemberError(true); |
| 1206 | + |
| 1207 | + // If members are already loaded above or by other flows, |
| 1208 | + // calling getMembers here should be inexpensive. |
| 1209 | + auto memberList = getMembers(); |
| 1210 | + |
| 1211 | + // This decl contains a member deserialization error; emit a diag. |
| 1212 | + if (hasDeserializeMemberError()) { |
| 1213 | + auto containerID = Identifier(); |
| 1214 | + if (auto container = dyn_cast<NominalTypeDecl>(getDecl())) { |
| 1215 | + containerID = container->getBaseIdentifier(); |
| 1216 | + } |
| 1217 | + |
| 1218 | + auto foundMissing = false; |
| 1219 | + for (auto member: memberList) { |
| 1220 | + // Only storage vars can affect memory layout so |
| 1221 | + // look up pattern binding decl or var decl. |
| 1222 | + if (auto *PBD = dyn_cast<PatternBindingDecl>(member)) { |
| 1223 | + // If this pattern binding decl is empty, we have |
| 1224 | + // a missing member. |
| 1225 | + if (PBD->getNumPatternEntries() == 0) |
| 1226 | + foundMissing = true; |
| 1227 | + } |
| 1228 | + // Check if a member can be cast to MissingMemberDecl. |
| 1229 | + if (auto missingMember = dyn_cast<MissingMemberDecl>(member)) { |
| 1230 | + if (!missingMember->getName().getBaseName().isSpecial() && |
| 1231 | + foundMissing) { |
| 1232 | + foundMissing = false; |
| 1233 | + auto missingMemberID = missingMember->getName().getBaseIdentifier(); |
| 1234 | + getASTContext().Diags.diagnose(member->getLoc(), |
| 1235 | + diag::cannot_bypass_resilience_due_to_missing_member, |
| 1236 | + missingMemberID, |
| 1237 | + missingMemberID.empty(), |
| 1238 | + containerID, |
| 1239 | + getDecl()->getModuleContext()->getBaseIdentifier(), |
| 1240 | + accessingModule->getBaseIdentifier()); |
| 1241 | + continue; |
| 1242 | + } |
| 1243 | + } |
| 1244 | + // If not handled above, emit a diag here. |
| 1245 | + if (foundMissing) { |
| 1246 | + getASTContext().Diags.diagnose(getDecl()->getLoc(), |
| 1247 | + diag::cannot_bypass_resilience_due_to_missing_member, |
| 1248 | + Identifier(), |
| 1249 | + true, |
| 1250 | + containerID, |
| 1251 | + getDecl()->getModuleContext()->getBaseIdentifier(), |
| 1252 | + accessingModule->getBaseIdentifier()); |
| 1253 | + } |
| 1254 | + } |
| 1255 | + } else { |
| 1256 | + // This decl does not contain a member deserialization error. |
| 1257 | + // Check for members of this decl's members recursively to |
| 1258 | + // see if a member deserialization failed. |
| 1259 | + for (auto member: memberList) { |
| 1260 | + // Only storage vars can affect memory layout so |
| 1261 | + // look up pattern binding decl or var decl. |
| 1262 | + if (auto *PBD = dyn_cast<PatternBindingDecl>(member)) { |
| 1263 | + for (auto i : range(PBD->getNumPatternEntries())) { |
| 1264 | + auto pattern = PBD->getPattern(i); |
| 1265 | + pattern->forEachVariable([&](const VarDecl *VD) { |
| 1266 | + // Bail if the var is static or has no storage |
| 1267 | + if (VD->isStatic() || |
| 1268 | + !VD->hasStorageOrWrapsStorage()) |
| 1269 | + return; |
| 1270 | + // Unwrap in case this var is optional. |
| 1271 | + auto varType = VD->getInterfaceType()->getCanonicalType(); |
| 1272 | + if (auto unwrapped = varType->getCanonicalType()->getOptionalObjectType()) { |
| 1273 | + varType = unwrapped->getCanonicalType(); |
| 1274 | + } |
| 1275 | + // Handle BoundGenericType, e.g. [Foo: Bar], Dictionary<Foo, Bar>. |
| 1276 | + // Check for its arguments types, i.e. Foo, Bar. |
| 1277 | + if (auto boundGeneric = varType->getAs<BoundGenericType>()) { |
| 1278 | + for (auto arg : boundGeneric->getGenericArgs()) { |
| 1279 | + if (auto argNominal = arg->getNominalOrBoundGenericNominal()) { |
| 1280 | + if (auto argIDC = dyn_cast<IterableDeclContext>(argNominal)) { |
| 1281 | + argIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); |
| 1282 | + if (argIDC->hasDeserializeMemberError()) { |
| 1283 | + setHasDeserializeMemberError(true); |
| 1284 | + break; |
| 1285 | + } |
| 1286 | + } |
| 1287 | + } |
| 1288 | + } |
| 1289 | + } else if (auto tupleType = varType->getAs<TupleType>()) { |
| 1290 | + // Handle TupleType, e.g. (Foo, Var). |
| 1291 | + for (auto element : tupleType->getElements()) { |
| 1292 | + if (auto elementNominal = element.getType()->getNominalOrBoundGenericNominal()) { |
| 1293 | + if (auto elementIDC = dyn_cast<IterableDeclContext>(elementNominal)) { |
| 1294 | + elementIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); |
| 1295 | + if (elementIDC->hasDeserializeMemberError()) { |
| 1296 | + setHasDeserializeMemberError(true); |
| 1297 | + break; |
| 1298 | + } |
| 1299 | + } |
| 1300 | + } |
| 1301 | + } |
| 1302 | + } else if (auto varNominal = varType->getNominalOrBoundGenericNominal()) { |
| 1303 | + if (auto varIDC = dyn_cast<IterableDeclContext>(varNominal)) { |
| 1304 | + varIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); |
| 1305 | + if (varIDC->hasDeserializeMemberError()) { |
| 1306 | + setHasDeserializeMemberError(true); |
| 1307 | + } |
| 1308 | + } |
| 1309 | + } |
| 1310 | + }); |
| 1311 | + } |
| 1312 | + } |
| 1313 | + } |
| 1314 | + } |
| 1315 | +} |
| 1316 | + |
1177 | 1317 | bool IterableDeclContext::wasDeserialized() const {
|
1178 | 1318 | const DeclContext *DC = getAsGenericContext();
|
1179 | 1319 | if (auto F = dyn_cast<FileUnit>(DC->getModuleScopeContext())) {
|
|
0 commit comments