diff options
-rw-r--r-- | src/ir/module-utils.cpp | 47 | ||||
-rw-r--r-- | test/lit/lub-bug-3843.wast | 3 | ||||
-rw-r--r-- | test/lit/nominal-chain.wast | 13 | ||||
-rw-r--r-- | test/lit/parse-nominal-types-extends.wast | 15 | ||||
-rw-r--r-- | test/lit/parse-nominal-types.wast | 15 | ||||
-rw-r--r-- | test/lit/passes/cfp.wast | 35 | ||||
-rw-r--r-- | test/lit/passes/dae-gc-refine-params.wast | 3 | ||||
-rw-r--r-- | test/lit/passes/dae-gc-refine-return.wast | 3 | ||||
-rw-r--r-- | test/lit/passes/gto-mutability.wast | 3 | ||||
-rw-r--r-- | test/lit/passes/gto-removals.wast | 11 | ||||
-rw-r--r-- | test/lit/passes/optimize-instructions-gc-iit.wast | 12 | ||||
-rw-r--r-- | test/lit/passes/signature-refining.wast | 3 | ||||
-rw-r--r-- | test/lit/passes/type-refining.wast | 24 |
13 files changed, 119 insertions, 68 deletions
diff --git a/src/ir/module-utils.cpp b/src/ir/module-utils.cpp index 7861bde54..bf1a45205 100644 --- a/src/ir/module-utils.cpp +++ b/src/ir/module-utils.cpp @@ -203,9 +203,10 @@ std::vector<HeapType> collectHeapTypes(Module& wasm) { } IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) { + TypeSystem system = getTypeSystem(); Counts counts = getHeapTypeCounts(wasm); - if (getTypeSystem() != TypeSystem::Isorecursive) { + if (system == TypeSystem::Equirecursive) { // Sort by frequency and then original insertion order. std::vector<std::pair<HeapType, size_t>> sorted(counts.begin(), counts.end()); @@ -223,9 +224,12 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) { return indexedTypes; } - // Isorecursive types have to be arranged into topologically ordered recursion - // groups. Sort the groups by average use count among their members so that - // the topological sort will place frequently used types first. + // Types have to be arranged into topologically ordered recursion groups. + // Under isorecrsive typing, the topological sort has to take all referenced + // rec groups into account but under nominal typing it only has to take + // supertypes into account. First, sort the groups by average use count among + // their members so that the later topological sort will place frequently used + // types first. struct GroupInfo { size_t index; double useCount = 0; @@ -236,7 +240,7 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) { if (useCount != other.useCount) { return useCount < other.useCount; } - return index < other.index; + return index > other.index; } }; @@ -257,20 +261,35 @@ IndexedHeapTypes getOptimizedIndexedHeapTypes(Module& wasm) { // Update the reference count. info.useCount += counts.at(type); // Collect predecessor groups. - for (auto child : type.getReferencedHeapTypes()) { - if (!child.isBasic()) { - RecGroup otherGroup = child.getRecGroup(); - if (otherGroup != group) { - info.preds.insert(otherGroup); + switch (system) { + case TypeSystem::Isorecursive: + for (auto child : type.getReferencedHeapTypes()) { + if (!child.isBasic()) { + RecGroup otherGroup = child.getRecGroup(); + if (otherGroup != group) { + info.preds.insert(otherGroup); + } + } } - } + break; + case TypeSystem::Nominal: + if (auto super = type.getSuperType()) { + info.preds.insert(super->getRecGroup()); + } + break; + case TypeSystem::Equirecursive: + WASM_UNREACHABLE( + "Equirecursive types should already have been handled"); } } // Fix up the use counts to be averages to ensure groups are used comensurate - // with the amount of index space they occupy. - for (auto& [group, info] : groupInfos) { - info.useCount /= group.size(); + // with the amount of index space they occupy. Skip this for nominal types + // since their internal group size is always 1. + if (system != TypeSystem::Nominal) { + for (auto& [group, info] : groupInfos) { + info.useCount /= group.size(); + } } // Sort the predecessors so the most used will be visited first. diff --git a/test/lit/lub-bug-3843.wast b/test/lit/lub-bug-3843.wast index 596f4a6d9..f5bb439f2 100644 --- a/test/lit/lub-bug-3843.wast +++ b/test/lit/lub-bug-3843.wast @@ -16,11 +16,12 @@ (type $B (struct_subtype (field (ref null $D)) $A)) ;; CHECK: (type $D (struct (field (mut (ref $A))) (field (mut (ref $A))))) + ;; NOMNL: (type $C (struct_subtype (field (mut (ref $A))) data)) + ;; NOMNL: (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) ;; CHECK: (type $C (struct (field (mut (ref $A))))) - ;; NOMNL: (type $C (struct_subtype (field (mut (ref $A))) data)) (type $C (struct (field (mut (ref $A))))) diff --git a/test/lit/nominal-chain.wast b/test/lit/nominal-chain.wast index 474286e6b..dda04b32c 100644 --- a/test/lit/nominal-chain.wast +++ b/test/lit/nominal-chain.wast @@ -7,18 +7,21 @@ ;; types. (module - ;; CHECK: (type $leaf (struct_subtype (field i32) (field i64) (field f32) (field f64) $twig)) - (type $leaf (struct_subtype i32 i64 f32 f64 $twig)) - ;; CHECK: (type $root (struct_subtype data)) + ;; CHECK: (type $trunk (struct_subtype (field i32) $root)) + + ;; CHECK: (type $branch (struct_subtype (field i32) (field i64) $trunk)) + ;; CHECK: (type $twig (struct_subtype (field i32) (field i64) (field f32) $branch)) + + ;; CHECK: (type $leaf (struct_subtype (field i32) (field i64) (field f32) (field f64) $twig)) + (type $leaf (struct_subtype i32 i64 f32 f64 $twig)) + (type $twig (struct_subtype i32 i64 f32 $branch)) - ;; CHECK: (type $branch (struct_subtype (field i32) (field i64) $trunk)) (type $branch (struct_subtype i32 i64 $trunk)) - ;; CHECK: (type $trunk (struct_subtype (field i32) $root)) (type $trunk (struct_subtype i32 $root)) (type $root (struct)) diff --git a/test/lit/parse-nominal-types-extends.wast b/test/lit/parse-nominal-types-extends.wast index 2077bd90f..ea9461e67 100644 --- a/test/lit/parse-nominal-types-extends.wast +++ b/test/lit/parse-nominal-types-extends.wast @@ -8,10 +8,11 @@ ;; void function type (module + ;; CHECK: (type $super (func_subtype func)) + ;; CHECK: (type $sub (func_subtype $super)) (type $sub (func) (extends $super)) - ;; CHECK: (type $super (func_subtype func)) (type $super (func)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -20,10 +21,11 @@ ;; function type with params and results (module + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) + ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) (type $sub (func (param i32) (result i32)) (extends $super)) - ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) (type $super (func (param i32) (result i32))) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -32,10 +34,11 @@ ;; empty struct type (module + ;; CHECK: (type $super (struct_subtype data)) + ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct) (extends $super)) - ;; CHECK: (type $super (struct_subtype data)) (type $super (struct)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -44,10 +47,11 @@ ;; struct type with fields (module + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) + ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) (type $sub (struct i32 (field i64)) (extends $super)) - ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) (type $super (struct (field i32) i64)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -56,10 +60,11 @@ ;; array type (module + ;; CHECK: (type $super (array_subtype i8 data)) + ;; CHECK: (type $sub (array_subtype i8 $super)) (type $sub (array i8) (extends $super)) - ;; CHECK: (type $super (array_subtype i8 data)) (type $super (array i8)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) diff --git a/test/lit/parse-nominal-types.wast b/test/lit/parse-nominal-types.wast index fb4a0cf53..db681ead9 100644 --- a/test/lit/parse-nominal-types.wast +++ b/test/lit/parse-nominal-types.wast @@ -8,10 +8,11 @@ ;; void function type (module + ;; CHECK: (type $super (func_subtype func)) + ;; CHECK: (type $sub (func_subtype $super)) (type $sub (func_subtype $super)) - ;; CHECK: (type $super (func_subtype func)) (type $super (func_subtype func)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -20,10 +21,11 @@ ;; function type with params and results (module + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) + ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) (type $sub (func_subtype (param i32) (result i32) $super)) - ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) (type $super (func_subtype (param i32) (result i32) func)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -32,10 +34,11 @@ ;; empty struct type (module + ;; CHECK: (type $super (struct_subtype data)) + ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct_subtype $super)) - ;; CHECK: (type $super (struct_subtype data)) (type $super (struct_subtype data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -44,10 +47,11 @@ ;; struct type with fields (module + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) + ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) (type $sub (struct_subtype i32 (field i64) $super)) - ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) (type $super (struct_subtype (field i32) i64 data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) @@ -56,10 +60,11 @@ ;; array type (module + ;; CHECK: (type $super (array_subtype i8 data)) + ;; CHECK: (type $sub (array_subtype i8 $super)) (type $sub (array_subtype i8 $super)) - ;; CHECK: (type $super (array_subtype i8 data)) (type $super (array_subtype i8 data)) ;; CHECK: (global $g (ref null $super) (ref.null $sub)) diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index d1eecc658..5caadf16d 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -664,10 +664,11 @@ (module ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) (type $substruct (struct_subtype i32 f64 $struct)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $create (type $none_=>_none) @@ -834,10 +835,11 @@ (module ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) (type $substruct (struct_subtype i32 f64 $struct)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) ;; CHECK: (func $create (type $none_=>_none) @@ -958,17 +960,19 @@ ;; Multi-level subtyping, check that we propagate not just to the immediate ;; supertype but all the way as needed. (module + ;; CHECK: (type $struct1 (struct_subtype (field i32) data)) + + ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1)) + ;; CHECK: (type $struct3 (struct_subtype (field i32) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype i32 f64 anyref $struct2)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - - ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1)) (type $struct2 (struct_subtype i32 f64 $struct1)) - ;; CHECK: (type $struct1 (struct_subtype (field i32) data)) (type $struct1 (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_with_rtt $struct3 @@ -1093,13 +1097,15 @@ ;; different values in the sub-most type. Create the top and bottom types, but ;; not the middle one. (module + ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data)) + + ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1)) + ;; CHECK: (type $struct3 (struct_subtype (field i32) (field i32) (field f64) (field f64) (field anyref) (field anyref) $struct2)) (type $struct3 (struct_subtype i32 i32 f64 f64 anyref anyref $struct2)) - ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data)) (type $struct1 (struct i32 i32)) - ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1)) (type $struct2 (struct_subtype i32 i32 f64 f64 $struct1)) ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) @@ -1427,10 +1433,11 @@ ;; As above, but add not just a new of the middle class with a different value ;; but also a set. That prevents all optimizations. (module + ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) + ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) (type $struct2 (struct_subtype (mut i32) f64 $struct1)) - ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) (type $struct1 (struct (mut i32))) ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) @@ -1657,21 +1664,23 @@ ;; sets, and the final subtype C has a create and a get. The set to A should ;; apply to it, preventing optimization. (module + ;; CHECK: (type $A (struct_subtype (field (mut i32)) data)) + + ;; CHECK: (type $B (struct_subtype (field (mut i32)) $A)) + ;; CHECK: (type $C (struct_subtype (field (mut i32)) $B)) (type $C (struct_subtype (mut i32) $B)) - ;; CHECK: (type $A (struct_subtype (field (mut i32)) data)) (type $A (struct (mut i32))) + (type $B (struct_subtype (mut i32) $A)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) ;; CHECK: (type $ref|$C|_=>_none (func_subtype (param (ref $C)) func)) - ;; CHECK: (type $B (struct_subtype (field (mut i32)) $A)) - (type $B (struct_subtype (mut i32) $A)) - ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_with_rtt $C diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index 767c2d716..25494d160 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -4,11 +4,12 @@ (module ;; CHECK: (type ${i32} (struct (field i32))) + ;; NOMNL: (type ${} (struct_subtype data)) + ;; NOMNL: (type ${i32} (struct_subtype (field i32) ${})) (type ${i32} (struct_subtype (field i32) ${})) ;; CHECK: (type ${} (struct )) - ;; NOMNL: (type ${} (struct_subtype data)) (type ${} (struct)) ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) diff --git a/test/lit/passes/dae-gc-refine-return.wast b/test/lit/passes/dae-gc-refine-return.wast index 15a40652d..a349fbdfd 100644 --- a/test/lit/passes/dae-gc-refine-return.wast +++ b/test/lit/passes/dae-gc-refine-return.wast @@ -12,6 +12,8 @@ ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) + ;; NOMNL: (type ${} (struct_subtype data)) + ;; NOMNL: (type ${i32} (struct_subtype (field i32) ${})) ;; NOMNL: (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) @@ -24,7 +26,6 @@ (type ${i32} (struct_subtype (field i32) ${})) ;; CHECK: (type ${} (struct )) - ;; NOMNL: (type ${} (struct_subtype data)) (type ${} (struct)) (table 1 1 funcref) diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast index 89c2a537f..4ecab4f8c 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -531,10 +531,9 @@ ;; As above, but add a write in the sub, which prevents optimization. - ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) - ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) (type $super (struct (field (mut i32)))) + ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func)) diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index 1d80b24ee..f3cbae2aa 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -645,10 +645,11 @@ ;; We can remove fields from the end if they are only used in subtypes, because ;; the subtypes can always add fields at the end (and only at the end). (module + ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) data)) + ;; CHECK: (type $child (struct_subtype (field i32) (field i64) (field f32) (field f64) (field anyref) $parent)) (type $child (struct_subtype (field i32) (field i64) (field f32) (field f64) (field anyref) $parent)) - ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) data)) (type $parent (struct_subtype (field i32) (field i64) (field f32) (field f64) data)) ;; CHECK: (type $ref|$parent|_ref|$child|_=>_none (func_subtype (param (ref $parent) (ref $child)) func)) @@ -694,10 +695,11 @@ ) (module + ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) (field (mut f32)) data)) + ;; CHECK: (type $child (struct_subtype (field i32) (field i64) (field (mut f32)) (field f64) (field anyref) $parent)) (type $child (struct_subtype (field (mut i32)) (field (mut i64)) (field (mut f32)) (field (mut f64)) (field (mut anyref)) $parent)) - ;; CHECK: (type $parent (struct_subtype (field i32) (field i64) (field (mut f32)) data)) (type $parent (struct_subtype (field (mut i32)) (field (mut i64)) (field (mut f32)) (field (mut f64)) data)) ;; CHECK: (type $ref|$parent|_ref|$child|_=>_none (func_subtype (param (ref $parent) (ref $child)) func)) @@ -774,13 +776,14 @@ ;; As above, but now the read is just of one child. We can remove the field ;; from the parent and the other child. (module + ;; CHECK: (type $parent (struct_subtype data)) + ;; CHECK: (type $child1 (struct_subtype (field i32) $parent)) (type $child1 (struct_subtype (field i32) $parent)) + (type $parent (struct_subtype (field i32) data)) ;; CHECK: (type $ref|$parent|_ref|$child1|_ref|$child2|_=>_none (func_subtype (param (ref $parent) (ref $child1) (ref $child2)) func)) - ;; CHECK: (type $parent (struct_subtype data)) - (type $parent (struct_subtype (field i32) data)) ;; CHECK: (type $child2 (struct_subtype $parent)) (type $child2 (struct_subtype (field i32) $parent)) diff --git a/test/lit/passes/optimize-instructions-gc-iit.wast b/test/lit/passes/optimize-instructions-gc-iit.wast index d0638860f..4117dce19 100644 --- a/test/lit/passes/optimize-instructions-gc-iit.wast +++ b/test/lit/passes/optimize-instructions-gc-iit.wast @@ -372,21 +372,17 @@ ;; CHECK: (type $B (struct (field (ref null $A)))) ;; CHECK: (type $A (struct )) - ;; NOMNL: (type $C (struct_subtype (field (ref null $D)) $B)) - - ;; NOMNL: (type $D (struct_subtype $A)) - ;; NOMNL: (type $A (struct_subtype data)) - ;; NOMNL-TNH: (type $C (struct_subtype (field (ref null $D)) $B)) - - ;; NOMNL-TNH: (type $D (struct_subtype $A)) - ;; NOMNL-TNH: (type $A (struct_subtype data)) (type $A (struct_subtype data)) ;; NOMNL: (type $B (struct_subtype (field (ref null $A)) $A)) ;; NOMNL-TNH: (type $B (struct_subtype (field (ref null $A)) $A)) (type $B (struct_subtype (field (ref null $A)) $A)) + ;; NOMNL: (type $C (struct_subtype (field (ref null $D)) $B)) + ;; NOMNL-TNH: (type $C (struct_subtype (field (ref null $D)) $B)) (type $C (struct_subtype (field (ref null $D)) $B)) + ;; NOMNL: (type $D (struct_subtype $A)) + ;; NOMNL-TNH: (type $D (struct_subtype $A)) (type $D (struct_subtype $A)) ;; CHECK: (func $test (param $C (ref $B)) (result anyref) diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast index a6d4ba53f..c67e04917 100644 --- a/test/lit/passes/signature-refining.wast +++ b/test/lit/passes/signature-refining.wast @@ -123,13 +123,14 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype data)) + ;; CHECK: (type $struct-sub1 (struct_subtype $struct)) (type $struct-sub1 (struct_subtype $struct)) ;; CHECK: (type $struct-sub2 (struct_subtype $struct)) (type $struct-sub2 (struct_subtype $struct)) - ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct_subtype data)) ;; CHECK: (func $func-1 (type $sig) (param $x (ref $struct)) diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast index 7f903d64e..91e47cdb0 100644 --- a/test/lit/passes/type-refining.wast +++ b/test/lit/passes/type-refining.wast @@ -121,10 +121,11 @@ ;; As above, but all writes are of $child-A, which allows more optimization ;; up to that type. + ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child-A))) data)) + ;; CHECK: (type $child-A (struct_subtype (field (mut (ref $child-A))) $struct)) (type $child-A (struct_subtype (field (mut dataref)) $struct)) - ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child-A))) data)) (type $struct (struct_subtype (field (mut dataref)) data)) ;; CHECK: (type $ref|$struct|_ref|$child-A|_=>_none (func_subtype (param (ref $struct) (ref $child-A)) func)) @@ -205,10 +206,11 @@ (module ;; As above, but both writes are of $child, so we can optimize. + ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child))) data)) + ;; CHECK: (type $child (struct_subtype (field (mut (ref $child))) $struct)) (type $child (struct_subtype (field (mut dataref)) $struct)) - ;; CHECK: (type $struct (struct_subtype (field (mut (ref $child))) data)) (type $struct (struct_subtype (field (mut dataref)) data)) ;; CHECK: (type $ref|$struct|_ref|$child|_=>_none (func_subtype (param (ref $struct) (ref $child)) func)) @@ -435,21 +437,23 @@ ) (module + ;; CHECK: (type $X (struct_subtype data)) + ;; CHECK: (type $Y (struct_subtype $X)) (type $Y (struct_subtype $X)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $A (struct_subtype (field (ref $Y)) data)) + ;; CHECK: (type $C (struct_subtype (field (ref $Y)) $A)) (type $C (struct_subtype (field (ref $X)) $A)) ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A)) (type $B (struct_subtype (field (ref $X)) $A)) - ;; CHECK: (type $A (struct_subtype (field (ref $Y)) data)) (type $A (struct_subtype (field (ref $X)) data)) - ;; CHECK: (type $X (struct_subtype data)) (type $X (struct_subtype data)) ;; CHECK: (func $foo (type $none_=>_none) @@ -489,6 +493,8 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $A (struct_subtype (field (ref $X)) data)) + ;; CHECK: (type $C (struct_subtype (field (ref $X)) $A)) (type $C (struct_subtype (field (ref $X)) $A)) @@ -498,7 +504,6 @@ ;; CHECK: (type $Y (struct_subtype $X)) (type $Y (struct_subtype $X)) - ;; CHECK: (type $A (struct_subtype (field (ref $X)) data)) (type $A (struct_subtype (field (ref $X)) data)) ;; CHECK: (func $foo (type $none_=>_none) @@ -520,10 +525,11 @@ (type $X (struct_subtype data)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $A (struct_subtype (field (ref $X)) data)) + ;; CHECK: (type $B (struct_subtype (field (ref $Y)) $A)) (type $B (struct_subtype (field (ref $Y)) $A)) - ;; CHECK: (type $A (struct_subtype (field (ref $X)) data)) (type $A (struct_subtype (field (ref $X)) data)) ;; CHECK: (type $Y (struct_subtype $X)) @@ -784,21 +790,23 @@ ;; Root-Outer[Root-Inner] -> Leaf1-Outer[Leaf1-Inner] ;; -> Leaf2-Outer[Leaf2-Inner] + ;; CHECK: (type $Root-Inner (struct_subtype data)) + ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner)) (type $Leaf2-Inner (struct_subtype $Root-Inner)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) + ;; 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)) |