Note subtyping for tuple instructions in Unsubtyping Unsubtyping uses the subtype-exprs.h utility to collect subtyping constraints from the module, but that utility did not properly note subtyping in tuple instructions. Normally this is not a problem because the tuple.make operand types exactly match the elements of the result tuple type, but it is also possible for the operands to be more refined, in which case this missing logic can lead to bugs. Fixes #7087.
diff --git a/test/lit/passes/issue-7087.wast b/test/lit/passes/issue-7087.wast new file mode 100644 index 0000000..f775c12 --- /dev/null +++ b/test/lit/passes/issue-7087.wast
@@ -0,0 +1,33 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; Regression test for an interesting double bug between TypeSSA and +;; Unsubtyping. TypeSSA creates a new subtype, $t_1, for use in the struct.new +;; in the global initializer, but then only runs ReFinalize on function code, +;; not on module-level code. As a result, the tuple.make result type still uses +;; $t instead of $t_1 after TypeSSA. + +;; The second part of the bug was that unsubtyping did not properly note that +;; tuple.make operands had to remain subtypes of the corresponding tuple element +;; types. As a result, Unsubtyping made $t_1 a sibling of $t rather than keeping +;; it a subtype of $t, breaking validation for tuple.make. + +;; RUN: wasm-opt %s -all --type-ssa --unsubtyping -S -o - | filecheck %s + +(module + ;; CHECK: (rec + ;; CHECK-NEXT: (type $t (sub (struct))) + (type $t (sub (struct))) + + ;; CHECK: (type $t_1 (sub $t (struct))) + + ;; CHECK: (global $g (tuple i32 (ref null $t)) (tuple.make 2 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (struct.new_default $t_1) + ;; CHECK-NEXT: )) + (global $g (tuple i32 (ref null $t)) + (tuple.make 2 + (i32.const 0) + (struct.new $t) + ) + ) +)