summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/TypeMerging.cpp18
-rw-r--r--test/lit/passes/type-merging.wast19
2 files changed, 32 insertions, 5 deletions
diff --git a/src/passes/TypeMerging.cpp b/src/passes/TypeMerging.cpp
index 206addd2f..22c2352f2 100644
--- a/src/passes/TypeMerging.cpp
+++ b/src/passes/TypeMerging.cpp
@@ -504,11 +504,19 @@ std::vector<HeapType> TypeMerging::getPublicChildren(HeapType type) {
DFA::State<HeapType> TypeMerging::makeDFAState(HeapType type) {
std::vector<HeapType> succs;
- for (auto child : type.getHeapTypeChildren()) {
- // Both private and public heap type children participate in the DFA and are
- // eligible to be successors.
- if (!child.isBasic()) {
- succs.push_back(getMerged(child));
+ // Both private and public heap type children participate in the DFA and are
+ // eligible to be successors, except that public types are terminal states
+ // that do not have successors. This is sufficient because public types are
+ // always in their own singleton partitions, so they already differentiate
+ // types that reach them without needing to consider their children. In the
+ // other direction, including the children is not necessary to differentiate
+ // types reached by the public types because all such reachable types are also
+ // public and not eligible to be merged.
+ if (privateTypes.count(type)) {
+ for (auto child : type.getHeapTypeChildren()) {
+ if (!child.isBasic()) {
+ succs.push_back(getMerged(child));
+ }
}
}
return {type, std::move(succs)};
diff --git a/test/lit/passes/type-merging.wast b/test/lit/passes/type-merging.wast
index b8d602863..5d0c4bc5e 100644
--- a/test/lit/passes/type-merging.wast
+++ b/test/lit/passes/type-merging.wast
@@ -985,6 +985,25 @@
(global $g2 (ref $C') (struct.new_default $D2'))
)
+;; Regression test for a bug where public types not directly reachable from
+;; private types were included as successors but not given states in the DFA.
+(module
+ ;; CHECK: (type $public-child (struct))
+ (type $public-child (struct))
+ ;; CHECK: (type $public (struct (field (ref $public-child))))
+ (type $public (struct (ref $public-child)))
+ ;; CHECK: (type $private (struct (field (ref $public))))
+ (type $private (struct (ref $public)))
+
+ ;; CHECK: (global $public (ref null $public) (ref.null none))
+ (global $public (ref null $public) (ref.null none))
+ ;; CHECK: (global $private (ref null $private) (ref.null none))
+ (global $private (ref null $private) (ref.null none))
+
+ ;; CHECK: (export "public" (global $public))
+ (export "public" (global $public))
+)
+
;; Check that a ref.test inhibits merging (ref.cast is already checked above).
(module
;; CHECK: (rec