Skip to content

Commit 60f0eac

Browse files
committed
Fix canSerialize logic
1 parent 6676288 commit 60f0eac

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
203203
for (Type replType : Subs.getReplacementTypes()) {
204204
switch (mode) {
205205
case VisitMode::DetectSerializableInst:
206-
CMS.canSerializeType(replType->getCanonicalType());
206+
if (!CMS.canSerializeType(replType->getCanonicalType()))
207+
isInstSerializable = false;
207208
break;
208209
case VisitMode::SerializeInst:
209210
/// Ensure that all replacement types of \p Subs are usable from serialized
@@ -667,16 +668,17 @@ bool CrossModuleOptimization::canSerializeType(CanType type) {
667668
if (iter != canTypesChecked.end())
668669
return iter->getSecond();
669670

670-
bool success = type.findIf(
671+
bool success = !type.findIf(
671672
[this](Type rawSubType) {
672673
CanType subType = rawSubType->getCanonicalType();
673674
if (auto nominal = subType->getNominalOrBoundGenericNominal()) {
674-
return canSerializeDecl(nominal);
675+
return !canSerializeDecl(nominal);
675676
}
676-
// If reached here, the type is a Builtin type or similar,
677-
// e.g. Builtin.Int64, Builtin.Word, Builtin.NativeObject, etc.
678-
return true;
679-
});
677+
// Types that might not have nominal include Builtin types (e.g. Builtin.Int64),
678+
// generic parameter types (e.g. T as in Foo<T>), SIL function result types
679+
// (e.g. @convention(method) (Int, @thin Hasher.Type) -> Hasher), etc.
680+
return false;
681+
});
680682

681683
canTypesChecked[type] = success;
682684
return success;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module -wmo -enable-default-cmo -parse-as-library %t/Lib.swift -emit-module-path=%t/Lib.swiftmodule -module-name=Lib -enable-testing -I%t
5+
6+
/// TEST: Deserializing Lib module should not cause an assert fail.
7+
// RUN: %target-swift-frontend -emit-sil -sil-verify-all %t/Client.swift -I%t
8+
9+
// REQUIRES: swift_in_compiler
10+
// REQUIRES: asserts
11+
12+
//--- Client.swift
13+
14+
@testable import Lib
15+
16+
17+
//--- Lib.swift
18+
19+
public class PubKlass {
20+
var field = InternalStruct()
21+
/// This function should not be serialized as it returns an opaque type that isn't cast to a concrete nominal type.
22+
func run(from arg: PubStruct) -> some Sequence<InternalStruct.Klass> {
23+
field.run(from: arg)
24+
}
25+
}
26+
27+
public struct PubStruct: Hashable { }
28+
29+
struct InternalStruct: Hashable {
30+
class Klass: Hashable {
31+
let data: PubStruct
32+
init(_ arg: PubStruct) {
33+
self.data = arg
34+
}
35+
func hash(into hasher: inout Hasher) {
36+
hasher.combine(data)
37+
}
38+
static func == (lhs: Klass, rhs: Klass) -> Bool {
39+
return lhs.data == rhs.data
40+
}
41+
}
42+
43+
var entities: [PubStruct: Klass] = [:]
44+
45+
func run(from arg: PubStruct) -> some Sequence<Klass> {
46+
IteratorSequence(EntityIterator(from: arg))
47+
.lazy.map { entities[$0]! }
48+
}
49+
}
50+
51+
52+
private struct EntityIterator<T: Hashable>: IteratorProtocol {
53+
private var list: [T]
54+
init(from start: T) {
55+
self.list = [start]
56+
}
57+
private mutating func pop() -> T? {
58+
return nil
59+
}
60+
mutating func next() -> T? {
61+
return nil
62+
}
63+
}
64+
65+

0 commit comments

Comments
 (0)