| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. |
| |
| ;; RUN: foreach %s %t wasm-opt -all --closed-world --preserve-type-order \ |
| ;; RUN: --unsubtyping --remove-unused-types -all -S -o - | filecheck %s |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (func))) |
| (type $super (sub (func))) |
| ;; CHECK: (type $sub (sub $super (func))) |
| (type $sub (sub $super (func))) |
| ;; CHECK: (type $cont (cont $super)) |
| (type $cont (cont $super)) |
| |
| ;; CHECK: (elem declare func $cont-new) |
| |
| ;; CHECK: (func $cont-new (type $sub) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (cont.new $cont |
| ;; CHECK-NEXT: (ref.func $cont-new) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $cont-new (type $sub) |
| (drop |
| ;; This requires $sub <: $super. |
| (cont.new $cont |
| (ref.func $cont-new) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $one (func (param (ref $super)))) |
| (type $one (func (param (ref $super)))) |
| ;; CHECK: (type $none (func)) |
| (type $none (func)) |
| |
| ;; CHECK: (type $cont-one (cont $one)) |
| (type $cont-one (cont $one)) |
| ;; CHECK: (type $cont-none (cont $none)) |
| (type $cont-none (cont $none)) |
| |
| ;; CHECK: (func $cont-bind (type $none) |
| ;; CHECK-NEXT: (local $one (ref null $cont-one)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (cont.bind $cont-one $cont-none |
| ;; CHECK-NEXT: (struct.new_default $sub) |
| ;; CHECK-NEXT: (local.get $one) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $cont-bind |
| (local $one (ref null $cont-one)) |
| (drop |
| ;; This requires $sub <: $super. |
| (cont.bind $cont-one $cont-none |
| (struct.new $sub) |
| (local.get $one) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $2 (func (param (ref null $super)))) |
| |
| ;; CHECK: (type $3 (func)) |
| |
| ;; CHECK: (tag $e (type $2) (param (ref null $super))) |
| (tag $e (param (ref null $super))) |
| |
| ;; CHECK: (func $suspend (type $3) |
| ;; CHECK-NEXT: (suspend $e |
| ;; CHECK-NEXT: (struct.new_default $sub) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $suspend |
| ;; This requires $sub <: $super. |
| (suspend $e |
| (struct.new $sub) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func (param (ref null $super)))) |
| (type $f (func (param (ref null $super)))) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (func $resume-param (type $4) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (resume $cont |
| ;; CHECK-NEXT: (struct.new_default $sub) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-param |
| (local $cont (ref null $cont)) |
| ;; This requires $sub <: $super. |
| (resume $cont |
| (struct.new $sub) |
| (local.get $cont) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func)) |
| (type $f (func)) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $4 (func (param (ref null $sub)))) |
| |
| ;; CHECK: (type $5 (func (result (ref null $super) (ref null $cont)))) |
| |
| ;; CHECK: (tag $e (type $4) (param (ref null $sub))) |
| (tag $e (param (ref null $sub))) |
| |
| ;; CHECK: (func $resume-label (type $f) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (tuple.drop 2 |
| ;; CHECK-NEXT: (block $l (type $5) (result (ref null $super) (ref null $cont)) |
| ;; CHECK-NEXT: (resume $cont (on $e $l) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-label |
| (local $cont (ref null $cont)) |
| (tuple.drop 2 |
| (block $l (result (ref null $super) (ref null $cont)) |
| ;; Sending the tag parameter to the block requires $sub <: $super. |
| (resume $cont (on $e $l) |
| (local.get $cont) |
| ) |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func)) |
| (type $f (func)) |
| ;; CHECK: (type $next-f (func (param (ref null $sub)))) |
| (type $next-f (func (param (ref null $sub)))) |
| |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| ;; CHECK: (type $next-cont (cont $next-f)) |
| (type $next-cont (cont $next-f)) |
| |
| ;; CHECK: (type $6 (func (result (ref null $super)))) |
| |
| ;; CHECK: (tag $e (type $6) (result (ref null $super))) |
| (tag $e (result (ref null $super))) |
| |
| ;; CHECK: (func $resume-tag (type $f) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block $l (result (ref null $next-cont)) |
| ;; CHECK-NEXT: (resume $cont (on $e $l) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.null nocont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-tag |
| (local $cont (ref null $cont)) |
| (drop |
| (block $l (result (ref null $next-cont)) |
| ;; Based on the tag, the continuation expects a $super back. Based on |
| ;; the type we give the next continuation, we will send it a $sub back. |
| ;; This requires $sub <: $super. |
| (resume $cont (on $e $l) |
| (local.get $cont) |
| ) |
| (ref.null nocont) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func (result (ref null $sub)))) |
| (type $f (func (result (ref null $sub)))) |
| ;; CHECK: (type $next-f (func (result (ref null $super)))) |
| (type $next-f (func (result (ref null $super)))) |
| |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| ;; CHECK: (type $next-cont (cont $next-f)) |
| (type $next-cont (cont $next-f)) |
| |
| ;; CHECK: (type $6 (func)) |
| |
| ;; CHECK: (tag $e (type $6)) |
| (tag $e) |
| |
| ;; CHECK: (func $resume-result (type $6) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block $l (result (ref null $next-cont)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (resume $cont (on $e $l) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.null nocont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-result |
| (local $cont (ref null $cont)) |
| (drop |
| (block $l (result (ref null $next-cont)) |
| (drop |
| ;; The continuation we're resuming returns a $sub. In the next type we |
| ;; give it, it returns a $super. This requires $sub <: $super. |
| (resume $cont (on $e $l) |
| (local.get $cont) |
| ) |
| ) |
| (ref.null nocont) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func)) |
| (type $f (func)) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $4 (func (param (ref null $super)))) |
| |
| ;; CHECK: (tag $e (type $4) (param (ref null $super))) |
| (tag $e (param (ref null $super))) |
| |
| ;; CHECK: (func $resume-throw-param (type $f) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (resume_throw $cont $e |
| ;; CHECK-NEXT: (struct.new_default $sub) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-throw-param |
| (local $cont (ref null $cont)) |
| ;; This requires $sub <: $super |
| (resume_throw $cont $e |
| (struct.new $sub) |
| (local.get $cont) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func)) |
| (type $f (func)) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $4 (func (param (ref null $sub)))) |
| |
| ;; CHECK: (type $5 (func (result (ref null $super) (ref null $cont)))) |
| |
| ;; CHECK: (tag $e (type $4) (param (ref null $sub))) |
| (tag $e (param (ref null $sub))) |
| |
| ;; CHECK: (func $resume-throw-label (type $f) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (tuple.drop 2 |
| ;; CHECK-NEXT: (block $l (type $5) (result (ref null $super) (ref null $cont)) |
| ;; CHECK-NEXT: (resume_throw $cont $e (on $e $l) |
| ;; CHECK-NEXT: (ref.null none) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-throw-label |
| (local $cont (ref null $cont)) |
| (tuple.drop 2 |
| (block $l (result (ref null $super) (ref null $cont)) |
| ;; Sending the tag parameter to the block requires $sub <: $super. |
| (resume_throw $cont $e (on $e $l) |
| (ref.null none) |
| (local.get $cont) |
| ) |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| (rec |
| ;; CHECK: (type $f (func (param (ref null $super) (ref null $ret-cont)))) |
| (type $f (func (param (ref null $super) (ref null $ret-cont)))) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $ret-f (func)) |
| (type $ret-f (func)) |
| ;; CHECK: (type $ret-cont (cont $ret-f)) |
| (type $ret-cont (cont $ret-f)) |
| ) |
| |
| ;; CHECK: (type $6 (func)) |
| |
| ;; CHECK: (tag $e (type $6)) |
| (tag $e) |
| |
| ;; CHECK: (func $switch-param (type $6) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (switch $cont $e |
| ;; CHECK-NEXT: (struct.new_default $sub) |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $switch-param |
| (local $cont (ref null $cont)) |
| ;; The continuation expects a $super, but we send it a $sub. This requires |
| ;; $sub <: $super. |
| (switch $cont $e |
| (struct.new $sub) |
| (local.get $cont) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| (rec |
| ;; CHECK: (type $f (func (param (ref null $ret-cont)) (result (ref null $sub)))) |
| (type $f (func (param (ref null $ret-cont)) (result (ref null $sub)))) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $ret-f (func (result (ref null $super)))) |
| (type $ret-f (func (result (ref null $super)))) |
| ;; CHECK: (type $ret-cont (cont $ret-f)) |
| (type $ret-cont (cont $ret-f)) |
| ) |
| |
| ;; CHECK: (type $6 (func (result (ref null $super)))) |
| |
| ;; CHECK: (type $7 (func)) |
| |
| ;; CHECK: (tag $e (type $6) (result (ref null $super))) |
| (tag $e (result (ref null $super))) |
| |
| ;; CHECK: (func $switch-target-result (type $7) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (switch $cont $e |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $switch-target-result |
| (local $cont (ref null $cont)) |
| ;; The current continuation returns a $super (as indicated in the tag) and |
| ;; the target continuation will return a $sub. This requires $sub <: $super. |
| (switch $cont $e |
| (local.get $cont) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| (rec |
| ;; CHECK: (type $f (func (param (ref null $ret-cont)) (result (ref null $sub)))) |
| (type $f (func (param (ref null $ret-cont)) (result (ref null $sub)))) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; CHECK: (type $ret-f (func (result (ref null $super)))) |
| (type $ret-f (func (result (ref null $super)))) |
| ;; CHECK: (type $ret-cont (cont $ret-f)) |
| (type $ret-cont (cont $ret-f)) |
| ) |
| |
| ;; CHECK: (type $6 (func (result (ref null $sub)))) |
| |
| ;; CHECK: (type $7 (func)) |
| |
| ;; CHECK: (tag $e (type $6) (result (ref null $sub))) |
| (tag $e (result (ref null $sub))) |
| |
| ;; CHECK: (func $switch-return-result (type $7) |
| ;; CHECK-NEXT: (local $cont (ref null $cont)) |
| ;; CHECK-NEXT: (switch $cont $e |
| ;; CHECK-NEXT: (local.get $cont) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $switch-return-result |
| (local $cont (ref null $cont)) |
| ;; The current continuation returns a $sub (as indicated in the tag) and |
| ;; after the switch it will be given the return continuation type returning |
| ;; $super. This requires $sub <: $super. |
| (switch $cont $e |
| (local.get $cont) |
| ) |
| ) |
| ) |
| |
| ;; Test we do not error on resume_throw_ref. It adds no subtyping constraints |
| ;; between declared types besides those from the handlers. |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $f (func)) |
| |
| ;; CHECK: (type $k (cont $f)) |
| |
| ;; CHECK: (elem declare func $no_handler) |
| |
| ;; CHECK: (tag $e0 (type $f)) |
| (tag $e0) |
| |
| (type $f (func)) |
| (type $k (cont $f)) |
| |
| ;; CHECK: (func $no_handler (type $f) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $no_handler |
| (unreachable) |
| ) |
| |
| ;; CHECK: (func $throw_unhandled_ref (type $f) |
| ;; CHECK-NEXT: (resume_throw_ref $k |
| ;; CHECK-NEXT: (block $h (result (ref exn)) |
| ;; CHECK-NEXT: (try_table (catch_ref $e0 $h) |
| ;; CHECK-NEXT: (throw $e0) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (cont.new $k |
| ;; CHECK-NEXT: (ref.func $no_handler) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $throw_unhandled_ref |
| (block $h (result exnref) |
| (try_table (catch_ref $e0 $h) (throw $e0)) |
| (unreachable) |
| ) |
| (resume_throw_ref $k (cont.new $k (ref.func $no_handler))) |
| ) |
| ) |
| |
| ;; Test that processResumeHandlers correctly iterates handler tag parameters |
| ;; using the inner loop variable. With two handlers where handler 1 has multiple |
| ;; parameters, the subtyping constraint at param index 0 of handler 1 must be |
| ;; noted (not the constraint at param index 1 repeated). |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (struct))) |
| (type $super (sub (struct))) |
| ;; CHECK: (type $sub (sub $super (struct))) |
| (type $sub (sub $super (struct))) |
| |
| ;; CHECK: (type $f (func)) |
| (type $f (func)) |
| ;; CHECK: (type $cont (cont $f)) |
| (type $cont (cont $f)) |
| |
| ;; First tag has 1 param; second tag has 2 params with $sub at index 0. |
| ;; CHECK: (type $4 (func (param i32))) |
| |
| ;; CHECK: (type $5 (func (param (ref null $sub) i32))) |
| |
| ;; CHECK: (type $6 (func (result (ref null $super) i32 (ref null $cont)))) |
| |
| ;; CHECK: (type $7 (func (result i32 (ref null $cont)))) |
| |
| ;; CHECK: (tag $e0 (type $4) (param i32)) |
| (tag $e0 (param i32)) |
| ;; CHECK: (tag $e1 (type $5) (param (ref null $sub) i32)) |
| (tag $e1 (param (ref null $sub) i32)) |
| |
| ;; CHECK: (func $resume-handler-multi-param (type $f) |
| ;; CHECK-NEXT: (local $c (ref null $cont)) |
| ;; CHECK-NEXT: (tuple.drop 2 |
| ;; CHECK-NEXT: (block $l0 (type $7) (result i32 (ref null $cont)) |
| ;; CHECK-NEXT: (tuple.drop 3 |
| ;; CHECK-NEXT: (block $l1 (type $6) (result (ref null $super) i32 (ref null $cont)) |
| ;; CHECK-NEXT: (resume $cont (on $e0 $l0) (on $e1 $l1) |
| ;; CHECK-NEXT: (local.get $c) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $resume-handler-multi-param |
| (local $c (ref null $cont)) |
| (tuple.drop 2 |
| (block $l0 (result i32 (ref null $cont)) |
| (tuple.drop 3 |
| (block $l1 (result (ref null $super) i32 (ref null $cont)) |
| ;; Handler 1 sends (ref null $sub, i32) to $l1 which expects |
| ;; (ref null $super, i32, ref null $cont). This requires |
| ;; $sub <: $super at param index 0 of handler 1. |
| (resume $cont (on $e0 $l0) (on $e1 $l1) |
| (local.get $c) |
| ) |
| (unreachable) |
| ) |
| ) |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (func))) |
| (type $super (sub (func))) |
| ;; CHECK: (type $sub (sub $super (func))) |
| (type $sub (sub $super (func))) |
| ;; CHECK: (type $cont-super (sub (cont $super))) |
| (type $cont-super (sub (cont $super))) |
| ;; CHECK: (type $cont-sub (sub $cont-super (cont $sub))) |
| (type $cont-sub (sub $cont-super (cont $sub))) |
| |
| ;; CHECK: (type $4 (func (param (ref $cont-sub)) (result (ref $cont-super)))) |
| |
| ;; CHECK: (func $cont-new (type $4) (param $sub (ref $cont-sub)) (result (ref $cont-super)) |
| ;; CHECK-NEXT: (local.get $sub) |
| ;; CHECK-NEXT: ) |
| (func $cont-new (param $sub (ref $cont-sub)) (result (ref $cont-super)) |
| ;; This requires $cont-sub <: $cont-super and $sub <: $super. |
| (local.get $sub) |
| ) |
| ) |
| |
| (module |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (func))) |
| (type $super (sub (func))) |
| ;; CHECK: (type $sub (sub (func))) |
| (type $sub (sub $super (func))) |
| ;; CHECK: (type $cont-super (sub (cont $super))) |
| (type $cont-super (sub (cont $super))) |
| ;; CHECK: (type $cont-sub (sub (cont $sub))) |
| (type $cont-sub (sub $cont-super (cont $sub))) |
| |
| ;; CHECK: (type $4 (func (param (ref $cont-sub)) (result (ref $cont-sub)))) |
| |
| ;; CHECK: (func $cont-new (type $4) (param $sub (ref $cont-sub)) (result (ref $cont-sub)) |
| ;; CHECK-NEXT: (local $keepalive (ref $cont-super)) |
| ;; CHECK-NEXT: (local.get $sub) |
| ;; CHECK-NEXT: ) |
| (func $cont-new (param $sub (ref $cont-sub)) (result (ref $cont-sub)) |
| (local $keepalive (ref $cont-super)) |
| ;; As above, but now we return the subtype, so there is no constraint. We |
| ;; can unsubtype both the continuations and the funcs. |
| (local.get $sub) |
| ) |
| ) |
| |