summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/type-refining.wast87
1 files changed, 87 insertions, 0 deletions
diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast
index eb33f058a..7f903d64e 100644
--- a/test/lit/passes/type-refining.wast
+++ b/test/lit/passes/type-refining.wast
@@ -768,3 +768,90 @@
)
)
)
+
+(module
+ ;; There are two parallel type hierarchies here: "Outer", which are objects
+ ;; that have fields, that contain the "Inner" objects.
+ ;;
+ ;; Root-Outer -> Leaf1-Outer
+ ;; -> Leaf2-Outer
+ ;;
+ ;; Root-Inner -> Leaf1-Inner
+ ;; -> Leaf2-Inner
+ ;;
+ ;; Adding their contents, where X[Y] means X has a field of type Y:
+ ;;
+ ;; Root-Outer[Root-Inner] -> Leaf1-Outer[Leaf1-Inner]
+ ;; -> Leaf2-Outer[Leaf2-Inner]
+
+ ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner))
+ (type $Leaf2-Inner (struct_subtype $Root-Inner))
+
+ ;; CHECK: (type $none_=>_none (func_subtype func))
+
+ ;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+ (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer))
+
+ ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+ (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer))
+
+ ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data))
+ (type $Root-Outer (struct_subtype (field (ref $Root-Inner)) data))
+
+ ;; CHECK: (type $Root-Inner (struct_subtype data))
+ (type $Root-Inner (struct_subtype data))
+
+ (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner))
+
+ ;; CHECK: (func $func (type $none_=>_none)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.null $Leaf1-Outer)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $Leaf2-Outer
+ ;; CHECK-NEXT: (struct.new_default $Leaf2-Inner)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $func
+ (drop
+ ;; The situation here is that we have only a get for some types, and no
+ ;; other constraints. As we ignore gets, we work under no constraints at
+ ;; We then have to pick some type, so we pick the one used by our
+ ;; supertype - and the supertype might have picked up a type from another
+ ;; branch of the type tree, which is not a subtype of ours.
+ ;;
+ ;; In more detail, we never create an instance of $Leaf1-Outer, and we
+ ;; only have a get of its field. This optimization ignores the get (to not
+ ;; be limited by it). It will then optimize $Leaf1-Outer's field of
+ ;; $Leaf1-Inner (another struct for which we have no creation, and only a
+ ;; get) into $Leaf2-Inner, which is driven by the fact that we do have a
+ ;; creation of $Leaf2-Inner. But then this struct.get $Leaf1-Inner on field
+ ;; 0 is no longer valid, as we turn $Leaf1-Inner => $Leaf2-Inner, and
+ ;; $Leaf2-Inner has no field 0. To keep the module validating, we must not
+ ;; emit that. Instead, since there can be no instance of $Leaf1-Inner (as
+ ;; mentioned before, it is never created, nor anything that can be cast to
+ ;; it), we know this code is logically unreachable, and can emit an
+ ;; unreachable here.
+ (struct.get $Leaf1-Inner 0
+ (struct.get $Leaf1-Outer 0
+ (ref.null $Leaf1-Outer)
+ )
+ )
+ )
+ (drop
+ (struct.new $Leaf2-Outer
+ (struct.new_default $Leaf2-Inner)
+ )
+ )
+ )
+)