Skip to content

Commit 96e8d56

Browse files
committed
[Serialization] Add recovery for structs with non-loadable constraints
That is, if a struct's generic requirements can't be deserialized, drop the struct. This is the same logic that's already in play for enums and (as of the previous commit) classes, so it should be pretty well tested by now. (Hence the sole test I'm adding here, snuck into superclass.swift because it's a superclass /constraint/ being tested.) I don't know of any outstanding issues caused by this, but it was weird to have it for enums and classes but not structs, so here we are.
1 parent ff7c6f6 commit 96e8d56

File tree

4 files changed

+41
-17
lines changed

4 files changed

+41
-17
lines changed

include/swift/Serialization/ModuleFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 492; // dependency types for classes
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 493; // dependency types for structs
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -948,7 +948,8 @@ namespace decls_block {
948948
GenericEnvironmentIDField, // generic environment
949949
AccessLevelField, // access level
950950
BCVBR<4>, // number of conformances
951-
BCArray<TypeIDField> // inherited types
951+
BCVBR<4>, // number of inherited types
952+
BCArray<TypeIDField> // inherited types, followed by dependency types
952953
// Trailed by the generic parameters (if any), the members record, and
953954
// finally conformance info (if any).
954955
>;

lib/Serialization/Deserialization.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,14 +2488,25 @@ class swift::DeclDeserializer {
24882488
bool isObjC;
24892489
GenericEnvironmentID genericEnvID;
24902490
uint8_t rawAccessLevel;
2491-
unsigned numConformances;
2492-
ArrayRef<uint64_t> rawInheritedIDs;
2491+
unsigned numConformances, numInheritedTypes;
2492+
ArrayRef<uint64_t> rawInheritedAndDependencyIDs;
24932493

24942494
decls_block::StructLayout::readRecord(scratch, nameID, contextID,
24952495
isImplicit, isObjC, genericEnvID,
24962496
rawAccessLevel,
2497-
numConformances,
2498-
rawInheritedIDs);
2497+
numConformances, numInheritedTypes,
2498+
rawInheritedAndDependencyIDs);
2499+
2500+
Identifier name = MF.getIdentifier(nameID);
2501+
2502+
for (TypeID dependencyID :
2503+
rawInheritedAndDependencyIDs.slice(numInheritedTypes)) {
2504+
auto dependency = MF.getTypeChecked(dependencyID);
2505+
if (!dependency) {
2506+
return llvm::make_error<TypeError>(
2507+
name, takeErrorInfo(dependency.takeError()));
2508+
}
2509+
}
24992510

25002511
auto DC = MF.getDeclContext(contextID);
25012512
if (declOrOffset.isComplete())
@@ -2505,10 +2516,8 @@ class swift::DeclDeserializer {
25052516
if (declOrOffset.isComplete())
25062517
return declOrOffset;
25072518

2508-
auto theStruct = MF.createDecl<StructDecl>(SourceLoc(),
2509-
MF.getIdentifier(nameID),
2510-
SourceLoc(), None, genericParams,
2511-
DC);
2519+
auto theStruct = MF.createDecl<StructDecl>(SourceLoc(), name, SourceLoc(),
2520+
None, genericParams, DC);
25122521
declOrOffset = theStruct;
25132522

25142523
// Read the generic environment.
@@ -2528,7 +2537,8 @@ class swift::DeclDeserializer {
25282537

25292538
theStruct->computeType();
25302539

2531-
handleInherited(theStruct, rawInheritedIDs);
2540+
handleInherited(theStruct,
2541+
rawInheritedAndDependencyIDs.slice(0, numInheritedTypes));
25322542

25332543
theStruct->setMemberLoader(&MF, MF.DeclTypeCursor.GetCurrentBitNo());
25342544
skipRecord(MF.DeclTypeCursor, decls_block::MEMBERS);

lib/Serialization/Serialization.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,12 +3145,20 @@ void Serializer::writeDecl(const Decl *D) {
31453145
auto conformances = theStruct->getLocalConformances(
31463146
ConformanceLookupKind::All, nullptr);
31473147

3148-
SmallVector<TypeID, 4> inheritedTypes;
3148+
SmallVector<TypeID, 4> inheritedAndDependencyTypes;
31493149
for (auto inherited : theStruct->getInherited()) {
31503150
assert(!inherited.getType()->hasArchetype());
3151-
inheritedTypes.push_back(addTypeRef(inherited.getType()));
3151+
inheritedAndDependencyTypes.push_back(addTypeRef(inherited.getType()));
31523152
}
31533153

3154+
llvm::SmallSetVector<Type, 4> dependencyTypes;
3155+
for (Requirement req : theStruct->getGenericRequirements()) {
3156+
collectDependenciesFromRequirement(dependencyTypes, req,
3157+
/*excluding*/nullptr);
3158+
}
3159+
for (Type ty : dependencyTypes)
3160+
inheritedAndDependencyTypes.push_back(addTypeRef(ty));
3161+
31543162
uint8_t rawAccessLevel =
31553163
getRawStableAccessLevel(theStruct->getFormalAccess());
31563164

@@ -3164,7 +3172,8 @@ void Serializer::writeDecl(const Decl *D) {
31643172
theStruct->getGenericEnvironment()),
31653173
rawAccessLevel,
31663174
conformances.size(),
3167-
inheritedTypes);
3175+
theStruct->getInherited().size(),
3176+
inheritedAndDependencyTypes);
31683177

31693178

31703179
writeGenericParams(theStruct->getGenericParams());

test/Serialization/Recovery/superclass.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ public class A1_Sub: DisappearingSuperclass {}
3030
// CHECK-RECOVERY-NOT: class A2_Grandchild
3131
public class A2_Grandchild: A1_Sub {}
3232

33-
// CHECK-LABEL: class B_ConstrainedGeneric<T> where T : DisappearingSuperclass {
34-
// CHECK-RECOVERY-NOT: class B_ConstrainedGeneric
35-
public class B_ConstrainedGeneric<T> where T: DisappearingSuperclass {}
33+
// CHECK-LABEL: class B1_ConstrainedGeneric<T> where T : DisappearingSuperclass {
34+
// CHECK-RECOVERY-NOT: class B1_ConstrainedGeneric
35+
public class B1_ConstrainedGeneric<T> where T: DisappearingSuperclass {}
36+
37+
// CHECK-LABEL: struct B2_ConstrainedGeneric<T> where T : DisappearingSuperclass {
38+
// CHECK-RECOVERY-NOT: struct B2_ConstrainedGeneric
39+
public struct B2_ConstrainedGeneric<T> where T: DisappearingSuperclass {}
3640

3741
// CHECK-ALWAYS-LABEL: class C1_GenericBase<T> {
3842
public class C1_GenericBase<T> {}

0 commit comments

Comments
 (0)