Skip to content

Commit

Permalink
[Serialization] Look for cross-ref errors inside type errors (#33271)
Browse files Browse the repository at this point in the history
In #30614, we started consuming XRefNonLoadedModuleErrors while loading
conformances, since a conformance to a type we cannot load usually
indicates we're trying to load a protocol that was declared in an
@_implementationOnly imported module.

We should also consume TypeErrors that we see where the underlying reason
is an XRefNonLoadedModuleError, since they're likely indicators of the
same thing.
  • Loading branch information
harlanhaskins committed Aug 4, 2020
1 parent 7e60a73 commit d67d7eb
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 9 deletions.
41 changes: 32 additions & 9 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5951,6 +5951,33 @@ void ModuleFile::loadAllMembers(Decl *container, uint64_t contextData) {
}
}

static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
// Missing module errors are most likely caused by an
// implementation-only import hiding types and decls.
// rdar://problem/60291019
if (error.isA<XRefNonLoadedModuleError>()) {
consumeError(std::move(error));
return llvm::Error::success();
}

// Some of these errors may manifest as a TypeError with an
// XRefNonLoadedModuleError underneath. Catch those as well.
// rdar://66491720
if (error.isA<TypeError>()) {
auto errorInfo = takeErrorInfo(std::move(error));
auto *TE = static_cast<TypeError*>(errorInfo.get());

if (TE->underlyingReasonIsA<XRefNonLoadedModuleError>()) {
consumeError(std::move(errorInfo));
return llvm::Error::success();
}

return std::move(errorInfo);
}

return std::move(error);
}

void
ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData,
SmallVectorImpl<ProtocolConformance*> &conformances) {
Expand All @@ -5968,15 +5995,11 @@ ModuleFile::loadAllConformances(const Decl *D, uint64_t contextData,
auto conformance = readConformanceChecked(DeclTypeCursor);

if (!conformance) {
// Missing module errors are most likely caused by an
// implementation-only import hiding types and decls.
// rdar://problem/60291019
if (conformance.errorIsA<XRefNonLoadedModuleError>()) {
consumeError(conformance.takeError());
return;
}
else
fatal(conformance.takeError());
auto unconsumedError =
consumeErrorIfXRefNonLoadedModule(conformance.takeError());
if (unconsumedError)
fatal(std::move(unconsumedError));
return;
}

if (conformance.get().isConcrete())
Expand Down
7 changes: 7 additions & 0 deletions lib/Serialization/DeserializationErrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,13 @@ class TypeError : public llvm::ErrorInfo<TypeError, DeclDeserializationError> {
this->numVTableEntries = numVTableEntries;
}

template <typename UnderlyingErrorT>
bool underlyingReasonIsA() const {
if (!underlyingReason)
return false;
return underlyingReason->isA<UnderlyingErrorT>();
}

void log(raw_ostream &OS) const override {
OS << "could not deserialize type for '" << name << "'";
if (underlyingReason) {
Expand Down
13 changes: 13 additions & 0 deletions test/Serialization/Recovery/implementation-only-missing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,24 @@ struct StructWithOverride: HiddenProtocolWithOverride {
func hiddenOverride() {}
}

internal protocol RefinesHiddenProtocol: HiddenProtocol {

}

public struct PublicStructConformsToHiddenProtocol: RefinesHiddenProtocol {
public typealias Value = Int

public init() { }
}

#elseif CLIENT_APP

import public_lib

var s = PublicStruct()
print(s.nonWrappedVar)

var p = PublicStructConformsToHiddenProtocol()
print(p)

#endif

0 comments on commit d67d7eb

Please sign in to comment.