Skip to content

Commit 3ee8e84

Browse files
committed
[Serialization] Propagate errors through compound types.
If there's an error deserializing part of a type, just propagate it out. Also add support for bound generic types. This isn't meant to be full coverage of possible failures, just ones that are likely to come up through the C/ObjC importer. Still to do: - Generic function types (only show up on functions) - Unbound generic types (only show up on typealiases, which I may not even tackle)
1 parent 1168cac commit 3ee8e84

File tree

5 files changed

+208
-32
lines changed

5 files changed

+208
-32
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3665,8 +3665,13 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
36653665
bool isVariadic, isAutoClosure, isEscaping;
36663666
decls_block::ParenTypeLayout::readRecord(scratch, underlyingID, isVariadic,
36673667
isAutoClosure, isEscaping);
3668+
3669+
auto underlyingTy = getTypeChecked(underlyingID);
3670+
if (!underlyingTy)
3671+
return underlyingTy.takeError();
3672+
36683673
typeOrOffset = ParenType::get(
3669-
ctx, getType(underlyingID),
3674+
ctx, underlyingTy.get(),
36703675
ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping));
36713676
break;
36723677
}
@@ -3691,8 +3696,12 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
36913696
decls_block::TupleTypeEltLayout::readRecord(
36923697
scratch, nameID, typeID, isVariadic, isAutoClosure, isEscaping);
36933698

3699+
auto elementTy = getTypeChecked(typeID);
3700+
if (!elementTy)
3701+
return elementTy.takeError();
3702+
36943703
elements.emplace_back(
3695-
getType(typeID), getIdentifier(nameID),
3704+
elementTy.get(), getIdentifier(nameID),
36963705
ParameterTypeFlags(isVariadic, isAutoClosure, isEscaping));
36973706
}
36983707

@@ -3717,12 +3726,17 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
37173726
return nullptr;
37183727
}
37193728

3720-
auto Info = FunctionType::ExtInfo(*representation,
3721-
autoClosure, noescape,
3722-
throws);
3723-
3724-
typeOrOffset = FunctionType::get(getType(inputID), getType(resultID),
3725-
Info);
3729+
auto info = FunctionType::ExtInfo(*representation, autoClosure, noescape,
3730+
throws);
3731+
3732+
auto inputTy = getTypeChecked(inputID);
3733+
if (!inputTy)
3734+
return inputTy.takeError();
3735+
auto resultTy = getTypeChecked(resultID);
3736+
if (!resultTy)
3737+
return resultTy.takeError();
3738+
3739+
typeOrOffset = FunctionType::get(inputTy.get(), resultTy.get(), info);
37263740
break;
37273741
}
37283742

@@ -3731,23 +3745,26 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
37313745
uint8_t repr;
37323746
decls_block::ExistentialMetatypeTypeLayout::readRecord(scratch,
37333747
instanceID, repr);
3748+
auto instanceType = getTypeChecked(instanceID);
3749+
if (!instanceType)
3750+
return instanceType.takeError();
37343751

37353752
switch (repr) {
37363753
case serialization::MetatypeRepresentation::MR_None:
3737-
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID));
3754+
typeOrOffset = ExistentialMetatypeType::get(instanceType.get());
37383755
break;
37393756

37403757
case serialization::MetatypeRepresentation::MR_Thin:
37413758
error();
37423759
break;
37433760

37443761
case serialization::MetatypeRepresentation::MR_Thick:
3745-
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID),
3762+
typeOrOffset = ExistentialMetatypeType::get(instanceType.get(),
37463763
MetatypeRepresentation::Thick);
37473764
break;
37483765

37493766
case serialization::MetatypeRepresentation::MR_ObjC:
3750-
typeOrOffset = ExistentialMetatypeType::get(getType(instanceID),
3767+
typeOrOffset = ExistentialMetatypeType::get(instanceType.get(),
37513768
MetatypeRepresentation::ObjC);
37523769
break;
37533770

@@ -3763,23 +3780,27 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
37633780
uint8_t repr;
37643781
decls_block::MetatypeTypeLayout::readRecord(scratch, instanceID, repr);
37653782

3783+
auto instanceType = getTypeChecked(instanceID);
3784+
if (!instanceType)
3785+
return instanceType.takeError();
3786+
37663787
switch (repr) {
37673788
case serialization::MetatypeRepresentation::MR_None:
3768-
typeOrOffset = MetatypeType::get(getType(instanceID));
3789+
typeOrOffset = MetatypeType::get(instanceType.get());
37693790
break;
37703791

37713792
case serialization::MetatypeRepresentation::MR_Thin:
3772-
typeOrOffset = MetatypeType::get(getType(instanceID),
3793+
typeOrOffset = MetatypeType::get(instanceType.get(),
37733794
MetatypeRepresentation::Thin);
37743795
break;
37753796

37763797
case serialization::MetatypeRepresentation::MR_Thick:
3777-
typeOrOffset = MetatypeType::get(getType(instanceID),
3798+
typeOrOffset = MetatypeType::get(instanceType.get(),
37783799
MetatypeRepresentation::Thick);
37793800
break;
37803801

37813802
case serialization::MetatypeRepresentation::MR_ObjC:
3782-
typeOrOffset = MetatypeType::get(getType(instanceID),
3803+
typeOrOffset = MetatypeType::get(instanceType.get(),
37833804
MetatypeRepresentation::ObjC);
37843805
break;
37853806

@@ -3806,15 +3827,20 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
38063827
case decls_block::INOUT_TYPE: {
38073828
TypeID objectTypeID;
38083829
decls_block::LValueTypeLayout::readRecord(scratch, objectTypeID);
3809-
typeOrOffset = InOutType::get(getType(objectTypeID));
3830+
3831+
auto objectTy = getTypeChecked(objectTypeID);
3832+
if (!objectTy)
3833+
return objectTy.takeError();
3834+
3835+
typeOrOffset = InOutType::get(objectTy.get());
38103836
break;
38113837
}
38123838

38133839
case decls_block::REFERENCE_STORAGE_TYPE: {
38143840
uint8_t rawOwnership;
3815-
TypeID referentTypeID;
3841+
TypeID objectTypeID;
38163842
decls_block::ReferenceStorageTypeLayout::readRecord(scratch, rawOwnership,
3817-
referentTypeID);
3843+
objectTypeID);
38183844

38193845
auto ownership =
38203846
getActualOwnership((serialization::Ownership) rawOwnership);
@@ -3823,7 +3849,11 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
38233849
break;
38243850
}
38253851

3826-
typeOrOffset = ReferenceStorageType::get(getType(referentTypeID),
3852+
auto objectTy = getTypeChecked(objectTypeID);
3853+
if (!objectTy)
3854+
return objectTy.takeError();
3855+
3856+
typeOrOffset = ReferenceStorageType::get(objectTy.get(),
38273857
ownership.getValue(), ctx);
38283858
break;
38293859
}
@@ -3899,8 +3929,12 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
38993929
hasExplicitAnyObject,
39003930
rawProtocolIDs);
39013931
SmallVector<Type, 4> protocols;
3902-
for (TypeID protoID : rawProtocolIDs)
3903-
protocols.push_back(getType(protoID));
3932+
for (TypeID protoID : rawProtocolIDs) {
3933+
auto protoTy = getTypeChecked(protoID);
3934+
if (!protoTy)
3935+
return protoTy.takeError();
3936+
protocols.push_back(protoTy.get());
3937+
}
39043938

39053939
typeOrOffset = ProtocolCompositionType::get(ctx, protocols,
39063940
hasExplicitAnyObject);
@@ -3927,12 +3961,22 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
39273961
decls_block::BoundGenericTypeLayout::readRecord(scratch, declID, parentID,
39283962
rawArgumentIDs);
39293963

3930-
auto nominal = cast<NominalTypeDecl>(getDecl(declID));
3964+
auto nominalOrError = getDeclChecked(declID);
3965+
if (!nominalOrError)
3966+
return nominalOrError.takeError();
3967+
auto nominal = cast<NominalTypeDecl>(nominalOrError.get());
3968+
3969+
// FIXME: Check this?
39313970
auto parentTy = getType(parentID);
39323971

39333972
SmallVector<Type, 8> genericArgs;
3934-
for (TypeID type : rawArgumentIDs)
3935-
genericArgs.push_back(getType(type));
3973+
for (TypeID ID : rawArgumentIDs) {
3974+
auto argTy = getTypeChecked(ID);
3975+
if (!argTy)
3976+
return argTy.takeError();
3977+
3978+
genericArgs.push_back(argTy.get());
3979+
}
39363980

39373981
auto boundTy = BoundGenericType::get(nominal, parentTy, genericArgs);
39383982
typeOrOffset = boundTy;
@@ -4169,35 +4213,51 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
41694213
TypeID baseID;
41704214
decls_block::ArraySliceTypeLayout::readRecord(scratch, baseID);
41714215

4172-
auto sliceTy = ArraySliceType::get(getType(baseID));
4173-
typeOrOffset = sliceTy;
4216+
auto baseTy = getTypeChecked(baseID);
4217+
if (!baseTy)
4218+
return baseTy.takeError();
4219+
4220+
typeOrOffset = ArraySliceType::get(baseTy.get());
41744221
break;
41754222
}
41764223

41774224
case decls_block::DICTIONARY_TYPE: {
41784225
TypeID keyID, valueID;
41794226
decls_block::DictionaryTypeLayout::readRecord(scratch, keyID, valueID);
41804227

4181-
auto dictTy = DictionaryType::get(getType(keyID), getType(valueID));
4182-
typeOrOffset = dictTy;
4228+
auto keyTy = getTypeChecked(keyID);
4229+
if (!keyTy)
4230+
return keyTy.takeError();
4231+
4232+
auto valueTy = getTypeChecked(valueID);
4233+
if (!valueTy)
4234+
return valueTy.takeError();
4235+
4236+
typeOrOffset = DictionaryType::get(keyTy.get(), valueTy.get());
41834237
break;
41844238
}
41854239

41864240
case decls_block::OPTIONAL_TYPE: {
41874241
TypeID baseID;
41884242
decls_block::OptionalTypeLayout::readRecord(scratch, baseID);
41894243

4190-
auto optionalTy = OptionalType::get(getType(baseID));
4191-
typeOrOffset = optionalTy;
4244+
auto baseTy = getTypeChecked(baseID);
4245+
if (!baseTy)
4246+
return baseTy.takeError();
4247+
4248+
typeOrOffset = OptionalType::get(baseTy.get());
41924249
break;
41934250
}
41944251

41954252
case decls_block::UNCHECKED_OPTIONAL_TYPE: {
41964253
TypeID baseID;
41974254
decls_block::ImplicitlyUnwrappedOptionalTypeLayout::readRecord(scratch, baseID);
41984255

4199-
auto optionalTy = ImplicitlyUnwrappedOptionalType::get(getType(baseID));
4200-
typeOrOffset = optionalTy;
4256+
auto baseTy = getTypeChecked(baseID);
4257+
if (!baseTy)
4258+
return baseTy.takeError();
4259+
4260+
typeOrOffset = ImplicitlyUnwrappedOptionalType::get(baseTy.get());
42014261
break;
42024262
}
42034263

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@protocol AProto
2+
@end
3+
4+
#if !BAD
5+
__attribute__((objc_root_class))
6+
@interface Base
7+
- (instancetype)init;
8+
@end
9+
10+
@interface Generic<T>: Base
11+
@end
12+
13+
@protocol SomeProto
14+
@end
15+
#endif
16+
17+
@protocol ZProto
18+
@end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module Overrides { header "Overrides.h" }
22
module Typedefs { header "Typedefs.h" }
3+
module TypeRemovalObjC { header "TypeRemovalObjC.h" }
34
module Types { header "Types.h" }
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: rm -rf %t && mkdir -p %t
2+
// RUN: %target-swift-frontend -emit-module -o %t -module-name Lib -I %S/Inputs/custom-modules %s
3+
4+
// RUN: %target-swift-ide-test -source-filename=x -print-module -module-to-print Lib -I %t -I %S/Inputs/custom-modules | %FileCheck %s
5+
6+
// 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
7+
// RUN: %FileCheck -check-prefix CHECK-RECOVERY %s < %t.txt
8+
// RUN: %FileCheck -check-prefix CHECK-RECOVERY-NEGATIVE %s < %t.txt
9+
10+
// REQUIRES: objc_interop
11+
12+
import TypeRemovalObjC
13+
14+
// CHECK-DAG: let simple: AnyObject?
15+
// CHECK-RECOVERY-DAG: let simple: AnyObject?
16+
public let simple: AnyObject? = nil
17+
18+
// CHECK-DAG: let someObject: Base?
19+
// CHECK-RECOVERY-NEGATIVE-NOT: let someObject:
20+
public let someObject: Base? = nil
21+
// CHECK-DAG: let someGenericObject: Generic<AnyObject>?
22+
// CHECK-RECOVERY-NEGATIVE-NOT: let someGenericObject:
23+
public let someGenericObject: Generic<AnyObject>? = nil
24+
// CHECK-DAG: let someProtoValue: SomeProto?
25+
// CHECK-RECOVERY-NEGATIVE-NOT: let someProtoValue:
26+
public let someProtoValue: SomeProto? = nil
27+
// CHECK-DAG: let someProtoType: SomeProto.Type?
28+
// CHECK-RECOVERY-NEGATIVE-NOT: let someProtoType:
29+
public let someProtoType: SomeProto.Type? = nil
30+
// CHECK-DAG: let someProtoCompositionValue: (AProto & SomeProto)?
31+
// CHECK-RECOVERY-NEGATIVE-NOT: let someProtoCompositionValue:
32+
public let someProtoCompositionValue: (AProto & SomeProto)? = nil
33+
// CHECK-DAG: let someProtoCompositionValue2: (SomeProto & ZProto)?
34+
// CHECK-RECOVERY-NEGATIVE-NOT: let someProtoCompositionValue2:
35+
public let someProtoCompositionValue2: (SomeProto & ZProto)? = nil
36+
37+
// CHECK-DAG: unowned var someUnownedObject: @sil_unowned Base
38+
// CHECK-RECOVERY-NEGATIVE-NOT: var someUnownedObject:
39+
public unowned var someUnownedObject: Base = Base()
40+
// CHECK-DAG: unowned(unsafe) var someUnownedUnsafeObject: @sil_unmanaged Base
41+
// CHECK-RECOVERY-NEGATIVE-NOT: var someUnownedUnsafeObject:
42+
public unowned(unsafe) var someUnownedUnsafeObject: Base = Base()
43+
// CHECK-DAG: weak var someWeakObject: @sil_weak Base
44+
// CHECK-RECOVERY-NEGATIVE-NOT: var someWeakObject:
45+
public weak var someWeakObject: Base? = nil

test/Serialization/Recovery/typedefs.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ let _: Int32? = useAssoc(AnotherType.self)
3535

3636
let _ = wrapped // expected-error {{use of unresolved identifier 'wrapped'}}
3737
let _ = unwrapped // okay
38+
3839
#endif // VERIFY
3940

4041
#else // TEST
@@ -72,4 +73,55 @@ public let wrapped = WrappedInt(0)
7273
// CHECK-RECOVERY-DAG: let unwrapped: Int32
7374
public let unwrapped: UnwrappedInt = 0
7475

76+
// CHECK-DAG: let wrappedMetatype: WrappedInt.Type
77+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedMetatype:
78+
public let wrappedMetatype = WrappedInt.self
79+
// CHECK-DAG: let wrappedOptional: WrappedInt?
80+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedOptional:
81+
public let wrappedOptional: WrappedInt? = nil
82+
// CHECK-DAG: let wrappedIUO: WrappedInt!
83+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedIUO:
84+
public let wrappedIUO: WrappedInt! = nil
85+
// CHECK-DAG: let wrappedArray: [WrappedInt]
86+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedArray:
87+
public let wrappedArray: [WrappedInt] = []
88+
// CHECK-DAG: let wrappedDictionary: [Int : WrappedInt]
89+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedDictionary:
90+
public let wrappedDictionary: [Int: WrappedInt] = [:]
91+
// CHECK-DAG: let wrappedTuple: (WrappedInt, Int)?
92+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedTuple:
93+
public let wrappedTuple: (WrappedInt, Int)? = nil
94+
// CHECK-DAG: let wrappedTuple2: (Int, WrappedInt)?
95+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedTuple2:
96+
public let wrappedTuple2: (Int, WrappedInt)? = nil
97+
// CHECK-DAG: let wrappedClosure: ((WrappedInt) -> Void)?
98+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedClosure:
99+
public let wrappedClosure: ((WrappedInt) -> Void)? = nil
100+
// CHECK-DAG: let wrappedClosure2: (() -> WrappedInt)?
101+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedClosure2:
102+
public let wrappedClosure2: (() -> WrappedInt)? = nil
103+
// CHECK-DAG: let wrappedClosure3: ((Int, WrappedInt) -> Void)?
104+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedClosure3:
105+
public let wrappedClosure3: ((Int, WrappedInt) -> Void)? = nil
106+
// CHECK-DAG: let wrappedClosureInout: ((inout WrappedInt) -> Void)?
107+
// CHECK-RECOVERY-NEGATIVE-NOT: let wrappedClosureInout:
108+
public let wrappedClosureInout: ((inout WrappedInt) -> Void)? = nil
109+
110+
111+
// CHECK-DAG: var wrappedFirst: WrappedInt?
112+
// CHECK-DAG: var normalSecond: Int?
113+
// CHECK-RECOVERY-NEGATIVE-NOT: var wrappedFirst:
114+
// CHECK-RECOVERY-DAG: var normalSecond: Int?
115+
public var wrappedFirst: WrappedInt?, normalSecond: Int?
116+
// CHECK-DAG: var normalFirst: Int?
117+
// CHECK-DAG: var wrappedSecond: WrappedInt?
118+
// CHECK-RECOVERY-DAG: var normalFirst: Int?
119+
// CHECK-RECOVERY-NEGATIVE-NOT: var wrappedSecond:
120+
public var normalFirst: Int?, wrappedSecond: WrappedInt?
121+
// CHECK-DAG: var wrappedThird: WrappedInt?
122+
// CHECK-DAG: var wrappedFourth: WrappedInt?
123+
// CHECK-RECOVERY-NEGATIVE-NOT: var wrappedThird:
124+
// CHECK-RECOVERY-NEGATIVE-NOT: var wrappedFourth:
125+
public var wrappedThird, wrappedFourth: WrappedInt?
126+
75127
#endif // TEST

0 commit comments

Comments
 (0)