Skip to content

Commit 35f8e17

Browse files
authored
[Serialization] Drop extensions whose base type can't be deserialized. (#11323)
This shows up with swift_wrapper typedefs, which get imported into Swift as structs. If someone makes an extension of a swift_wrapper type, but the swift_wrapper is only applied in Swift 4 mode, that extension will break any Swift 3 clients. Recover by just dropping the extension entirely. There's still more complexity around extensions---what if a requirement can't be deserialized? what if something's depending on the protocol conformance provided by the extension?---but the missing base type case should be pretty safe. If you can't see the type at all, things that depend on its conformances are already in trouble. rdar://problem/33636733
1 parent d046f3f commit 35f8e17

File tree

6 files changed

+121
-16
lines changed

6 files changed

+121
-16
lines changed

include/swift/Serialization/ModuleFormat.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 354; // Last change: special destructor names
57+
const uint16_t VERSION_MINOR = 355; // Last change: extension dependencies
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;
@@ -1038,7 +1038,8 @@ namespace decls_block {
10381038
BCFixed<1>, // implicit flag
10391039
GenericEnvironmentIDField, // generic environment
10401040
BCVBR<4>, // # of protocol conformances
1041-
BCArray<TypeIDField> // inherited types
1041+
BCVBR<4>, // number of inherited types
1042+
BCArray<TypeIDField> // inherited types, followed by TypeID dependencies
10421043
// Trailed by the generic parameter lists, members record, and then
10431044
// conformance info (if any).
10441045
>;

lib/Serialization/Deserialization.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ const char OverrideError::ID = '\0';
124124
void OverrideError::anchor() {}
125125
const char TypeError::ID = '\0';
126126
void TypeError::anchor() {}
127+
const char ExtensionError::ID = '\0';
128+
void ExtensionError::anchor() {}
127129

128130
LLVM_NODISCARD
129131
static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
@@ -3472,14 +3474,24 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
34723474
DeclContextID contextID;
34733475
bool isImplicit;
34743476
GenericEnvironmentID genericEnvID;
3475-
unsigned numConformances;
3476-
ArrayRef<uint64_t> rawInheritedIDs;
3477+
unsigned numConformances, numInherited;
3478+
ArrayRef<uint64_t> inheritedAndDependencyIDs;
34773479

34783480
decls_block::ExtensionLayout::readRecord(scratch, baseID, contextID,
34793481
isImplicit, genericEnvID,
3480-
numConformances, rawInheritedIDs);
3482+
numConformances, numInherited,
3483+
inheritedAndDependencyIDs);
34813484

34823485
auto DC = getDeclContext(contextID);
3486+
3487+
for (TypeID dependencyID : inheritedAndDependencyIDs.slice(numInherited)) {
3488+
auto dependency = getTypeChecked(dependencyID);
3489+
if (!dependency) {
3490+
return llvm::make_error<ExtensionError>(
3491+
takeErrorInfo(dependency.takeError()));
3492+
}
3493+
}
3494+
34833495
if (declOrOffset.isComplete())
34843496
return declOrOffset;
34853497

@@ -3505,8 +3517,8 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
35053517
if (isImplicit)
35063518
extension->setImplicit();
35073519

3508-
auto inheritedTypes = ctx.Allocate<TypeLoc>(rawInheritedIDs.size());
3509-
for_each(inheritedTypes, rawInheritedIDs,
3520+
auto inheritedTypes = ctx.Allocate<TypeLoc>(numInherited);
3521+
for_each(inheritedTypes, inheritedAndDependencyIDs.slice(0, numInherited),
35103522
[this](TypeLoc &tl, uint64_t rawID) {
35113523
tl = TypeLoc::withoutLoc(getType(rawID));
35123524
});

lib/Serialization/DeserializationErrors.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,30 @@ class TypeError : public llvm::ErrorInfo<TypeError, DeclDeserializationError> {
318318
}
319319
};
320320

321+
class ExtensionError : public llvm::ErrorInfo<ExtensionError> {
322+
friend ErrorInfo;
323+
static const char ID;
324+
void anchor() override;
325+
326+
std::unique_ptr<ErrorInfoBase> underlyingReason;
327+
328+
public:
329+
explicit ExtensionError(std::unique_ptr<ErrorInfoBase> reason)
330+
: underlyingReason(std::move(reason)) {}
331+
332+
void log(raw_ostream &OS) const override {
333+
OS << "could not deserialize extension";
334+
if (underlyingReason) {
335+
OS << ": ";
336+
underlyingReason->log(OS);
337+
}
338+
}
339+
340+
std::error_code convertToErrorCode() const override {
341+
return llvm::inconvertibleErrorCode();
342+
}
343+
};
344+
321345
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
322346
const char *Action;
323347
const ModuleFile &MF;

lib/Serialization/ModuleFile.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,15 +1564,27 @@ void ModuleFile::loadExtensions(NominalTypeDecl *nominal) {
15641564
if (nominal->getParent()->isModuleScopeContext()) {
15651565
Identifier moduleName = nominal->getParentModule()->getName();
15661566
for (auto item : *iter) {
1567-
if (item.first == moduleName.str())
1568-
(void)getDecl(item.second);
1567+
if (item.first != moduleName.str())
1568+
continue;
1569+
Expected<Decl *> declOrError = getDeclChecked(item.second);
1570+
if (!declOrError) {
1571+
if (!getContext().LangOpts.EnableDeserializationRecovery)
1572+
fatal(declOrError.takeError());
1573+
llvm::consumeError(declOrError.takeError());
1574+
}
15691575
}
15701576
} else {
15711577
std::string mangledName =
15721578
Mangle::ASTMangler().mangleNominalType(nominal);
15731579
for (auto item : *iter) {
1574-
if (item.first == mangledName)
1575-
(void)getDecl(item.second);
1580+
if (item.first != mangledName)
1581+
continue;
1582+
Expected<Decl *> declOrError = getDeclChecked(item.second);
1583+
if (!declOrError) {
1584+
if (!getContext().LangOpts.EnableDeserializationRecovery)
1585+
fatal(declOrError.takeError());
1586+
llvm::consumeError(declOrError.takeError());
1587+
}
15761588
}
15771589
}
15781590
}
@@ -1751,8 +1763,16 @@ void ModuleFile::getTopLevelDecls(SmallVectorImpl<Decl *> &results) {
17511763

17521764
if (ExtensionDecls) {
17531765
for (auto entry : ExtensionDecls->data()) {
1754-
for (auto item : entry)
1755-
results.push_back(getDecl(item.second));
1766+
for (auto item : entry) {
1767+
Expected<Decl *> declOrError = getDeclChecked(item.second);
1768+
if (!declOrError) {
1769+
if (!getContext().LangOpts.EnableDeserializationRecovery)
1770+
fatal(declOrError.takeError());
1771+
llvm::consumeError(declOrError.takeError());
1772+
continue;
1773+
}
1774+
results.push_back(declOrError.get());
1775+
}
17561776
}
17571777
}
17581778
}

lib/Serialization/Serialization.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2482,9 +2482,17 @@ void Serializer::writeDecl(const Decl *D) {
24822482
ConformanceLookupKind::All,
24832483
nullptr, /*sorted=*/true);
24842484

2485-
SmallVector<TypeID, 8> inheritedTypes;
2485+
SmallVector<TypeID, 8> inheritedAndDependencyTypes;
24862486
for (auto inherited : extension->getInherited())
2487-
inheritedTypes.push_back(addTypeRef(inherited.getType()));
2487+
inheritedAndDependencyTypes.push_back(addTypeRef(inherited.getType()));
2488+
size_t numInherited = inheritedAndDependencyTypes.size();
2489+
2490+
// FIXME: Figure out what to do with requirements and such, which the
2491+
// extension also depends on. Right now just do what is safe to drop, which
2492+
// is the base declaration.
2493+
auto dependencies = collectDependenciesFromType(baseTy);
2494+
for (auto dependencyTy : dependencies)
2495+
inheritedAndDependencyTypes.push_back(addTypeRef(dependencyTy));
24882496

24892497
unsigned abbrCode = DeclTypeAbbrCodes[ExtensionLayout::Code];
24902498
ExtensionLayout::emitRecord(Out, ScratchRecord, abbrCode,
@@ -2494,7 +2502,8 @@ void Serializer::writeDecl(const Decl *D) {
24942502
addGenericEnvironmentRef(
24952503
extension->getGenericEnvironment()),
24962504
conformances.size(),
2497-
inheritedTypes);
2505+
numInherited,
2506+
inheritedAndDependencyTypes);
24982507

24992508
bool isClassExtension = false;
25002509
if (baseNominal) {

test/Serialization/Recovery/typedefs.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ let _ = unwrapped // okay
5252
_ = usesWrapped(nil) // expected-error {{use of unresolved identifier 'usesWrapped'}}
5353
_ = usesUnwrapped(nil) // expected-error {{nil is not compatible with expected argument type 'Int32'}}
5454

55+
func testExtensions(wrapped: WrappedInt, unwrapped: UnwrappedInt) {
56+
wrapped.wrappedMethod() // expected-error {{value of type 'WrappedInt' (aka 'Int32') has no member 'wrappedMethod'}}
57+
unwrapped.unwrappedMethod() // expected-error {{value of type 'UnwrappedInt' has no member 'unwrappedMethod'}}
58+
59+
***wrapped // This one works because of the UnwrappedInt extension.
60+
***unwrapped // expected-error {{cannot convert value of type 'UnwrappedInt' to expected argument type 'Int32'}}
61+
62+
let _: WrappedProto = wrapped // expected-error {{value of type 'WrappedInt' (aka 'Int32') does not conform to specified type 'WrappedProto'}}
63+
let _: UnwrappedProto = unwrapped // expected-error {{value of type 'UnwrappedInt' does not conform to specified type 'UnwrappedProto'}}
64+
}
65+
5566
public class UserDynamicSub: UserDynamic {
5667
override init() {}
5768
}
@@ -72,6 +83,31 @@ public class UserSub : User {} // expected-error {{cannot inherit from class 'Us
7283

7384
import Typedefs
7485

86+
prefix operator ***
87+
88+
// CHECK-LABEL: extension WrappedInt : WrappedProto {
89+
// CHECK-NEXT: func wrappedMethod()
90+
// CHECK-NEXT: prefix static func ***(x: WrappedInt)
91+
// CHECK-NEXT: }
92+
// CHECK-RECOVERY-NEGATIVE-NOT: extension WrappedInt
93+
extension WrappedInt: WrappedProto {
94+
public func wrappedMethod() {}
95+
public static prefix func ***(x: WrappedInt) {}
96+
}
97+
// CHECK-LABEL: extension Int32 : UnwrappedProto {
98+
// CHECK-NEXT: func unwrappedMethod()
99+
// CHECK-NEXT: prefix static func ***(x: UnwrappedInt)
100+
// CHECK-NEXT: }
101+
// CHECK-RECOVERY-LABEL: extension Int32 : UnwrappedProto {
102+
// CHECK-RECOVERY-NEXT: func unwrappedMethod()
103+
// CHECK-RECOVERY-NEXT: prefix static func ***(x: Int32)
104+
// CHECK-RECOVERY-NEXT: }
105+
// CHECK-RECOVERY-NEGATIVE-NOT: extension UnwrappedInt
106+
extension UnwrappedInt: UnwrappedProto {
107+
public func unwrappedMethod() {}
108+
public static prefix func ***(x: UnwrappedInt) {}
109+
}
110+
75111
// CHECK-LABEL: class User {
76112
// CHECK-RECOVERY-LABEL: class User {
77113
open class User {
@@ -305,4 +341,7 @@ public func returnsWrapped() -> WrappedInt { fatalError() }
305341
// CHECK-RECOVERY-NEGATIVE-NOT: func returnsWrappedGeneric<
306342
public func returnsWrappedGeneric<T>(_: T.Type) -> WrappedInt { fatalError() }
307343

344+
public protocol WrappedProto {}
345+
public protocol UnwrappedProto {}
346+
308347
#endif // TEST

0 commit comments

Comments
 (0)