mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Serialization] Drop decls whose types can't be deserialized.
Proof-of-concept for the above. This shouldn't be common---renames are far more likely, and those we can track---but occurs when the swift_wrapper attribute (the implementation of NS_STRING_ENUM) is active in Swift 4 but not in Swift 3. Note that this only checks the canonical interface type of the declaration, because the non-canonical type may contain references to the declaration's generic parameters.
This commit is contained in:
@@ -44,7 +44,7 @@ const unsigned char MODULE_DOC_SIGNATURE[] = { 0xE2, 0x9C, 0xA8, 0x07 };
|
||||
|
||||
/// Serialized module format major version number.
|
||||
///
|
||||
/// Always 0 for Swift 1.x - 3.x.
|
||||
/// Always 0 for Swift 1.x - 4.x.
|
||||
const uint16_t VERSION_MAJOR = 0;
|
||||
|
||||
/// Serialized module format minor version number.
|
||||
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
|
||||
/// in source control, you should also update the comment to briefly
|
||||
/// describe what change you made. The content of this comment isn't important;
|
||||
/// it just ensures a conflict if two people change the module format.
|
||||
const uint16_t VERSION_MINOR = 338; // Last change: OPERAND_WITH_ATTR format.
|
||||
const uint16_t VERSION_MINOR = 339; // Last change: member canonical types
|
||||
|
||||
using DeclID = PointerEmbeddedInt<unsigned, 31>;
|
||||
using DeclIDField = BCFixed<31>;
|
||||
@@ -858,7 +858,8 @@ namespace decls_block {
|
||||
BCFixed<1>, // throws?
|
||||
CtorInitializerKindField, // initializer kind
|
||||
GenericEnvironmentIDField, // generic environment
|
||||
TypeIDField, // type (interface)
|
||||
TypeIDField, // interface type
|
||||
TypeIDField, // canonical interface type
|
||||
DeclIDField, // overridden decl
|
||||
AccessibilityKindField, // accessibility
|
||||
BCArray<IdentifierIDField> // argument names
|
||||
@@ -877,6 +878,7 @@ namespace decls_block {
|
||||
BCFixed<1>, // HasNonPatternBindingInit?
|
||||
StorageKindField, // StorageKind
|
||||
TypeIDField, // interface type
|
||||
TypeIDField, // canonical interface type
|
||||
DeclIDField, // getter
|
||||
DeclIDField, // setter
|
||||
DeclIDField, // materializeForSet
|
||||
@@ -911,6 +913,7 @@ namespace decls_block {
|
||||
BCVBR<5>, // number of parameter patterns
|
||||
GenericEnvironmentIDField, // generic environment
|
||||
TypeIDField, // interface type
|
||||
TypeIDField, // canonical interface type
|
||||
DeclIDField, // operator decl
|
||||
DeclIDField, // overridden function
|
||||
DeclIDField, // AccessorStorageDecl
|
||||
@@ -982,6 +985,7 @@ namespace decls_block {
|
||||
StorageKindField, // StorageKind
|
||||
GenericEnvironmentIDField, // generic environment
|
||||
TypeIDField, // interface type
|
||||
TypeIDField, // canonical interface type
|
||||
DeclIDField, // getter
|
||||
DeclIDField, // setter
|
||||
DeclIDField, // materializeForSet
|
||||
|
||||
@@ -127,6 +127,18 @@ const char XRefError::ID = '\0';
|
||||
void XRefError::anchor() {}
|
||||
const char OverrideError::ID = '\0';
|
||||
void OverrideError::anchor() {}
|
||||
const char TypeError::ID = '\0';
|
||||
void TypeError::anchor() {}
|
||||
|
||||
LLVM_NODISCARD
|
||||
static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
|
||||
std::unique_ptr<llvm::ErrorInfoBase> result;
|
||||
llvm::handleAllErrors(std::move(error),
|
||||
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
|
||||
result = std::move(info);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// Skips a single record in the bitstream.
|
||||
@@ -2492,7 +2504,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
bool isImplicit, isObjC, hasStubImplementation, throws;
|
||||
GenericEnvironmentID genericEnvID;
|
||||
uint8_t storedInitKind, rawAccessLevel;
|
||||
TypeID interfaceID;
|
||||
TypeID interfaceID, canonicalTypeID;
|
||||
DeclID overriddenID;
|
||||
ArrayRef<uint64_t> argNameIDs;
|
||||
|
||||
@@ -2501,8 +2513,8 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
isObjC, hasStubImplementation,
|
||||
throws, storedInitKind,
|
||||
genericEnvID, interfaceID,
|
||||
overriddenID, rawAccessLevel,
|
||||
argNameIDs);
|
||||
canonicalTypeID, overriddenID,
|
||||
rawAccessLevel, argNameIDs);
|
||||
|
||||
// Resolve the name ids.
|
||||
SmallVector<Identifier, 2> argNames;
|
||||
@@ -2595,15 +2607,15 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
DeclContextID contextID;
|
||||
bool isImplicit, isObjC, isStatic, isLet, hasNonPatternBindingInit;
|
||||
uint8_t storageKind, rawAccessLevel, rawSetterAccessLevel;
|
||||
TypeID interfaceTypeID;
|
||||
TypeID interfaceTypeID, canonicalTypeID;
|
||||
DeclID getterID, setterID, materializeForSetID, willSetID, didSetID;
|
||||
DeclID addressorID, mutableAddressorID, overriddenID;
|
||||
|
||||
decls_block::VarLayout::readRecord(scratch, nameID, contextID,
|
||||
isImplicit, isObjC, isStatic, isLet,
|
||||
hasNonPatternBindingInit, storageKind,
|
||||
interfaceTypeID, getterID,
|
||||
setterID, materializeForSetID,
|
||||
interfaceTypeID, canonicalTypeID,
|
||||
getterID, setterID, materializeForSetID,
|
||||
addressorID, mutableAddressorID,
|
||||
willSetID, didSetID, overriddenID,
|
||||
rawAccessLevel, rawSetterAccessLevel);
|
||||
@@ -2616,6 +2628,10 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
return llvm::make_error<OverrideError>(name);
|
||||
}
|
||||
|
||||
auto canonicalType = getTypeChecked(canonicalTypeID);
|
||||
if (!canonicalType)
|
||||
return llvm::make_error<TypeError>(name, takeErrorInfo(canonicalType.takeError()));
|
||||
|
||||
auto DC = ForcedContext ? *ForcedContext : getDeclContext(contextID);
|
||||
if (declOrOffset.isComplete())
|
||||
return declOrOffset;
|
||||
@@ -2703,7 +2719,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
bool isObjC, isMutating, hasDynamicSelf, throws;
|
||||
unsigned numParamPatterns;
|
||||
GenericEnvironmentID genericEnvID;
|
||||
TypeID interfaceTypeID;
|
||||
TypeID interfaceTypeID, canonicalTypeID;
|
||||
DeclID associatedDeclID;
|
||||
DeclID overriddenID;
|
||||
DeclID accessorStorageDeclID;
|
||||
@@ -2714,10 +2730,11 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
isStatic, rawStaticSpelling, isObjC,
|
||||
isMutating, hasDynamicSelf, throws,
|
||||
numParamPatterns, genericEnvID,
|
||||
interfaceTypeID, associatedDeclID,
|
||||
overriddenID, accessorStorageDeclID,
|
||||
hasCompoundName, rawAddressorKind,
|
||||
rawAccessLevel, nameIDs);
|
||||
interfaceTypeID, canonicalTypeID,
|
||||
associatedDeclID, overriddenID,
|
||||
accessorStorageDeclID, hasCompoundName,
|
||||
rawAddressorKind, rawAccessLevel,
|
||||
nameIDs);
|
||||
|
||||
// Resolve the name ids.
|
||||
SmallVector<Identifier, 2> names;
|
||||
@@ -3237,7 +3254,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
DeclContextID contextID;
|
||||
bool isImplicit, isObjC;
|
||||
GenericEnvironmentID genericEnvID;
|
||||
TypeID interfaceTypeID;
|
||||
TypeID interfaceTypeID, canonicalTypeID;
|
||||
DeclID getterID, setterID, materializeForSetID;
|
||||
DeclID addressorID, mutableAddressorID, willSetID, didSetID;
|
||||
DeclID overriddenID;
|
||||
@@ -3248,7 +3265,7 @@ ModuleFile::getDeclChecked(DeclID DID, Optional<DeclContext *> ForcedContext) {
|
||||
decls_block::SubscriptLayout::readRecord(scratch, contextID,
|
||||
isImplicit, isObjC, rawStorageKind,
|
||||
genericEnvID,
|
||||
interfaceTypeID,
|
||||
interfaceTypeID, canonicalTypeID,
|
||||
getterID, setterID,
|
||||
materializeForSetID,
|
||||
addressorID, mutableAddressorID,
|
||||
@@ -3587,17 +3604,20 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
|
||||
TypeID canonicalTypeID;
|
||||
decls_block::NameAliasTypeLayout::readRecord(scratch, underlyingID,
|
||||
canonicalTypeID);
|
||||
auto alias = dyn_cast_or_null<TypeAliasDecl>(getDecl(underlyingID));
|
||||
if (!alias) {
|
||||
error();
|
||||
return nullptr;
|
||||
}
|
||||
auto aliasOrError = getDeclChecked(underlyingID);
|
||||
if (!aliasOrError)
|
||||
return aliasOrError.takeError();
|
||||
auto alias = dyn_cast<TypeAliasDecl>(aliasOrError.get());
|
||||
|
||||
if (ctx.LangOpts.EnableDeserializationRecovery) {
|
||||
if (Type expectedType = getType(canonicalTypeID)) {
|
||||
if (!alias->getDeclaredInterfaceType()->isEqual(expectedType)) {
|
||||
Expected<Type> expectedType = getTypeChecked(canonicalTypeID);
|
||||
if (!expectedType)
|
||||
return expectedType.takeError();
|
||||
if (expectedType.get()) {
|
||||
if (!alias ||
|
||||
!alias->getDeclaredInterfaceType()->isEqual(expectedType.get())) {
|
||||
// Fall back to the canonical type.
|
||||
typeOrOffset = expectedType;
|
||||
typeOrOffset = expectedType.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3619,12 +3639,22 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
|
||||
TypeID parentID;
|
||||
decls_block::NominalTypeLayout::readRecord(scratch, declID, parentID);
|
||||
|
||||
Type parentTy = getType(parentID);
|
||||
Expected<Type> parentTy = getTypeChecked(parentID);
|
||||
if (!parentTy)
|
||||
return parentTy.takeError();
|
||||
|
||||
// Record the type as soon as possible. Members of a nominal type often
|
||||
// try to refer back to the type.
|
||||
auto nominal = cast<NominalTypeDecl>(getDecl(declID));
|
||||
typeOrOffset = NominalType::get(nominal, parentTy, ctx);
|
||||
auto nominalOrError = getDeclChecked(declID);
|
||||
if (!nominalOrError)
|
||||
return nominalOrError.takeError();
|
||||
|
||||
auto nominal = dyn_cast<NominalTypeDecl>(nominalOrError.get());
|
||||
if (!nominal) {
|
||||
XRefTracePath tinyTrace{*nominalOrError.get()->getModuleContext()};
|
||||
tinyTrace.addValue(cast<ValueDecl>(nominalOrError.get())->getName());
|
||||
return llvm::make_error<XRefError>("declaration is not a nominal type",
|
||||
tinyTrace);
|
||||
}
|
||||
typeOrOffset = NominalType::get(nominal, parentTy.get(), ctx);
|
||||
|
||||
assert(typeOrOffset.isComplete());
|
||||
break;
|
||||
|
||||
@@ -248,6 +248,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TypeError : public llvm::ErrorInfo<TypeError, DeclDeserializationError> {
|
||||
friend ErrorInfo;
|
||||
static const char ID;
|
||||
void anchor() override;
|
||||
|
||||
DeclName name;
|
||||
std::unique_ptr<ErrorInfoBase> underlyingReason;
|
||||
public:
|
||||
explicit TypeError(DeclName name, std::unique_ptr<ErrorInfoBase> reason)
|
||||
: name(name), underlyingReason(std::move(reason)) {}
|
||||
|
||||
void log(raw_ostream &OS) const override {
|
||||
OS << "could not deserialize type for '" << name << "'";
|
||||
if (underlyingReason) {
|
||||
OS << ": ";
|
||||
underlyingReason->log(OS);
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code convertToErrorCode() const override {
|
||||
return llvm::inconvertibleErrorCode();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace serialization
|
||||
} // end namespace swift
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/Serialization/ModuleFile.h"
|
||||
#include "DeserializationErrors.h"
|
||||
#include "swift/Serialization/ModuleFormat.h"
|
||||
#include "swift/Subsystems.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
@@ -31,6 +32,7 @@
|
||||
using namespace swift;
|
||||
using namespace swift::serialization;
|
||||
using namespace llvm::support;
|
||||
using llvm::Expected;
|
||||
|
||||
static bool checkModuleSignature(llvm::BitstreamCursor &cursor) {
|
||||
for (unsigned char byte : MODULE_SIGNATURE)
|
||||
@@ -1310,20 +1312,20 @@ void ModuleFile::lookupValue(DeclName name,
|
||||
// serialized.
|
||||
auto iter = TopLevelDecls->find(name.getBaseName());
|
||||
if (iter != TopLevelDecls->end()) {
|
||||
if (name.isSimpleName()) {
|
||||
for (auto item : *iter) {
|
||||
auto VD = cast<ValueDecl>(getDecl(item.second));
|
||||
results.push_back(VD);
|
||||
Expected<Decl *> declOrError = getDeclChecked(item.second);
|
||||
if (!declOrError) {
|
||||
if (!getContext().LangOpts.EnableDeserializationRecovery)
|
||||
fatal(declOrError.takeError());
|
||||
llvm::consumeError(declOrError.takeError());
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
for (auto item : *iter) {
|
||||
auto VD = cast<ValueDecl>(getDecl(item.second));
|
||||
if (VD->getFullName().matchesRef(name))
|
||||
auto VD = cast<ValueDecl>(declOrError.get());
|
||||
if (name.isSimpleName() || VD->getFullName().matchesRef(name))
|
||||
results.push_back(VD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the name is an operator name, also look for operator methods.
|
||||
if (name.isOperator() && OperatorMethodDecls) {
|
||||
@@ -1503,21 +1505,32 @@ void ModuleFile::lookupVisibleDecls(ModuleDecl::AccessPathTy accessPath,
|
||||
if (!TopLevelDecls)
|
||||
return;
|
||||
|
||||
auto tryImport = [this, &consumer](DeclID ID) {
|
||||
Expected<Decl *> declOrError = getDeclChecked(ID);
|
||||
if (!declOrError) {
|
||||
if (!getContext().LangOpts.EnableDeserializationRecovery)
|
||||
fatal(declOrError.takeError());
|
||||
llvm::consumeError(declOrError.takeError());
|
||||
return;
|
||||
}
|
||||
consumer.foundDecl(cast<ValueDecl>(declOrError.get()),
|
||||
DeclVisibilityKind::VisibleAtTopLevel);
|
||||
};
|
||||
|
||||
if (!accessPath.empty()) {
|
||||
auto iter = TopLevelDecls->find(accessPath.front().first);
|
||||
if (iter == TopLevelDecls->end())
|
||||
return;
|
||||
|
||||
for (auto item : *iter)
|
||||
consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)),
|
||||
DeclVisibilityKind::VisibleAtTopLevel);
|
||||
tryImport(item.second);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto entry : TopLevelDecls->data()) {
|
||||
for (auto item : entry)
|
||||
consumer.foundDecl(cast<ValueDecl>(getDecl(item.second)),
|
||||
DeclVisibilityKind::VisibleAtTopLevel);
|
||||
tryImport(item.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1711,8 +1724,16 @@ void ModuleFile::getTopLevelDecls(SmallVectorImpl<Decl *> &results) {
|
||||
|
||||
if (TopLevelDecls) {
|
||||
for (auto entry : TopLevelDecls->data()) {
|
||||
for (auto item : entry)
|
||||
results.push_back(getDecl(item.second));
|
||||
for (auto item : entry) {
|
||||
Expected<Decl *> declOrError = getDeclChecked(item.second);
|
||||
if (!declOrError) {
|
||||
if (!getContext().LangOpts.EnableDeserializationRecovery)
|
||||
fatal(declOrError.takeError());
|
||||
llvm::consumeError(declOrError.takeError());
|
||||
continue;
|
||||
}
|
||||
results.push_back(declOrError.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2761,6 +2761,7 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
if (var->isSettable(nullptr))
|
||||
rawSetterAccessLevel =
|
||||
getRawStableAccessibility(var->getSetterAccessibility());
|
||||
Type ty = var->getInterfaceType();
|
||||
|
||||
unsigned abbrCode = DeclTypeAbbrCodes[VarLayout::Code];
|
||||
VarLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
@@ -2772,7 +2773,8 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
var->isLet(),
|
||||
var->hasNonPatternBindingInit(),
|
||||
(unsigned) accessors.Kind,
|
||||
addTypeRef(var->getInterfaceType()),
|
||||
addTypeRef(ty),
|
||||
addTypeRef(ty->getCanonicalType()),
|
||||
addDeclRef(accessors.Get),
|
||||
addDeclRef(accessors.Set),
|
||||
addDeclRef(accessors.MaterializeForSet),
|
||||
@@ -2824,6 +2826,7 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
getRawStableAccessibility(fn->getFormalAccess());
|
||||
uint8_t rawAddressorKind =
|
||||
getRawStableAddressorKind(fn->getAddressorKind());
|
||||
Type ty = fn->getInterfaceType();
|
||||
|
||||
FuncLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
contextID,
|
||||
@@ -2838,7 +2841,8 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
fn->getParameterLists().size(),
|
||||
addGenericEnvironmentRef(
|
||||
fn->getGenericEnvironment()),
|
||||
addTypeRef(fn->getInterfaceType()),
|
||||
addTypeRef(ty),
|
||||
addTypeRef(ty->getCanonicalType()),
|
||||
addDeclRef(fn->getOperatorDecl()),
|
||||
addDeclRef(fn->getOverriddenDecl()),
|
||||
addDeclRef(fn->getAccessorStorageDecl()),
|
||||
@@ -2906,6 +2910,7 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
if (subscript->isSettable())
|
||||
rawSetterAccessLevel =
|
||||
getRawStableAccessibility(subscript->getSetterAccessibility());
|
||||
Type ty = subscript->getInterfaceType();
|
||||
|
||||
unsigned abbrCode = DeclTypeAbbrCodes[SubscriptLayout::Code];
|
||||
SubscriptLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
@@ -2915,7 +2920,8 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
(unsigned) accessors.Kind,
|
||||
addGenericEnvironmentRef(
|
||||
subscript->getGenericEnvironment()),
|
||||
addTypeRef(subscript->getInterfaceType()),
|
||||
addTypeRef(ty),
|
||||
addTypeRef(ty->getCanonicalType()),
|
||||
addDeclRef(accessors.Get),
|
||||
addDeclRef(accessors.Set),
|
||||
addDeclRef(accessors.MaterializeForSet),
|
||||
@@ -2946,6 +2952,7 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
|
||||
uint8_t rawAccessLevel =
|
||||
getRawStableAccessibility(ctor->getFormalAccess());
|
||||
Type ty = ctor->getInterfaceType();
|
||||
|
||||
unsigned abbrCode = DeclTypeAbbrCodes[ConstructorLayout::Code];
|
||||
ConstructorLayout::emitRecord(Out, ScratchRecord, abbrCode,
|
||||
@@ -2960,7 +2967,8 @@ void Serializer::writeDecl(const Decl *D) {
|
||||
ctor->getInitKind()),
|
||||
addGenericEnvironmentRef(
|
||||
ctor->getGenericEnvironment()),
|
||||
addTypeRef(ctor->getInterfaceType()),
|
||||
addTypeRef(ty),
|
||||
addTypeRef(ty->getCanonicalType()),
|
||||
addDeclRef(ctor->getOverriddenDecl()),
|
||||
rawAccessLevel,
|
||||
nameComponents);
|
||||
|
||||
@@ -9,3 +9,11 @@ struct ImportedType {
|
||||
};
|
||||
|
||||
typedef MysteryTypedef ImportedTypeAssoc __attribute__((swift_name("ImportedType.Assoc")));
|
||||
|
||||
#if !BAD
|
||||
typedef int WrappedInt __attribute__((swift_wrapper(struct)));
|
||||
typedef int UnwrappedInt;
|
||||
#else
|
||||
typedef int WrappedInt;
|
||||
typedef int UnwrappedInt __attribute__((swift_wrapper(struct)));
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules | %FileCheck %s
|
||||
|
||||
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -enable-experimental-deserialization-recovery | %FileCheck -check-prefix CHECK-RECOVERY %s
|
||||
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -enable-experimental-deserialization-recovery > %t.txt
|
||||
// RUN: %FileCheck -check-prefix CHECK-RECOVERY %s < %t.txt
|
||||
// RUN: %FileCheck -check-prefix CHECK-RECOVERY-NEGATIVE %s < %t.txt
|
||||
|
||||
// RUN: %target-swift-frontend -typecheck -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -DTEST -enable-experimental-deserialization-recovery -DVERIFY %s -verify
|
||||
// RUN: %target-swift-frontend -emit-silgen -I %t -I %S/Inputs/custom-modules -Xcc -DBAD -DTEST -enable-experimental-deserialization-recovery %s | %FileCheck -check-prefix CHECK-SIL %s
|
||||
@@ -30,6 +32,9 @@ let _: Int32? = useAssoc(ImportedType.self)
|
||||
let _: String = useAssoc(AnotherType.self) // expected-error {{cannot convert call result type '_.Assoc?' to expected type 'String'}}
|
||||
let _: Bool? = useAssoc(AnotherType.self) // expected-error {{cannot convert value of type 'AnotherType.Assoc?' (aka 'Optional<Int32>') to specified type 'Bool?'}}
|
||||
let _: Int32? = useAssoc(AnotherType.self)
|
||||
|
||||
let _ = wrapped // expected-error {{use of unresolved identifier 'wrapped'}}
|
||||
let _ = unwrapped // okay
|
||||
#endif // VERIFY
|
||||
|
||||
#else // TEST
|
||||
@@ -59,4 +64,12 @@ public let usesAssoc = useAssoc(ImportedType.self)
|
||||
// CHECK-RECOVERY-DAG: let usesAssoc2: AnotherType.Assoc?
|
||||
public let usesAssoc2 = useAssoc(AnotherType.self)
|
||||
|
||||
|
||||
// CHECK-DAG: let wrapped: WrappedInt
|
||||
// CHECK-RECOVERY-NEGATIVE-NOT: let wrapped:
|
||||
public let wrapped = WrappedInt(0)
|
||||
// CHECK-DAG: let unwrapped: UnwrappedInt
|
||||
// CHECK-RECOVERY-DAG: let unwrapped: Int32
|
||||
public let unwrapped: UnwrappedInt = 0
|
||||
|
||||
#endif // TEST
|
||||
|
||||
Reference in New Issue
Block a user