forked from WebAssembly/spec
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[abstypes] simplify and expand test cases, with brief comments about …
…WIP cases
- Loading branch information
Showing
1 changed file
with
193 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,209 @@ | ||
;; Abstract Types | ||
|
||
(module $MOD_1 | ||
(abstype_new $Token i32) | ||
(type (;0;) (func (param i32) (result (abstype_new_ref $Token)))) | ||
(type (;1;) (func (param (abstype_new_ref $Token)))) | ||
(global $favToken (mut (abstype_new_ref $Token)) (i32.const 0)) | ||
(global $sum (mut i32) (i32.const 0)) | ||
(func $createToken (type 0) | ||
(local.get 0) | ||
(module $Mf | ||
(abstype_new $a i32) | ||
(export "a" (abstype_new_ref $a)) | ||
(func (export "out") (result (abstype_new_ref $a)) (i32.const 42)) | ||
(func (export "in") (param (abstype_new_ref $a))) | ||
) | ||
(register "Mf" $Mf) | ||
|
||
(assert_unlinkable | ||
(module (import "Mf" "out" (func $out (result i32)))) | ||
"incompatible import type" | ||
) | ||
|
||
(assert_unlinkable | ||
(module (import "Mf" "in" (func $in (param i32)))) | ||
"incompatible import type" | ||
) | ||
|
||
|
||
|
||
(module | ||
(import "Mf" "a" (abstype_sealed $a)) | ||
(import "Mf" "out" (func $out (result (abstype_sealed_ref $a)))) | ||
(import "Mf" "in" (func $in (param (abstype_sealed_ref $a)))) | ||
) | ||
|
||
(assert_invalid | ||
(module | ||
(import "Mf" "a" (abstype_sealed $a)) | ||
(import "Mf" "out" (func $out (result (abstype_sealed_ref $a)))) | ||
(func $invalid_call | ||
(i32.add (i32.const 17) (call $out))) | ||
) | ||
(func $useToken (type 1) | ||
(local.get 0) | ||
(global.get $sum) | ||
(i32.add) | ||
(global.set $sum) | ||
"type mismatch: operator requires [i32 i32] but stack has [i32 abs{0}]" | ||
) | ||
|
||
(assert_invalid | ||
(module | ||
(import "Mf" "a" (abstype_sealed $a)) | ||
(import "Mf" "in" (func $in (param (abstype_sealed_ref $a)))) | ||
(func $invalid_call | ||
(call $in (i32.const 0))) | ||
) | ||
;; TODO disallow exporting a new abstype twice | ||
(export "Token" (abstype_new_ref $Token)) | ||
(export "favToken" (global $favToken)) | ||
(export "createToken" (func $createToken)) | ||
(export "useToken" (func $useToken)) | ||
"type mismatch: operator requires [abs{0}] but stack has [i32]" | ||
) | ||
(register "MOD_1" $MOD_1) | ||
|
||
(module | ||
(import "MOD_1" "Token" (abstype_sealed $Token)) | ||
(abstype_new $Coin i32) | ||
(type (;0;) (func (param i32) (result (abstype_sealed_ref $Token)))) | ||
(type (;1;) (func (param (abstype_sealed_ref $Token)))) ;; SealedAbsType 0 | ||
(type (;2;) (func (result (abstype_new_ref $Coin)))) ;; i32 | ||
(import "MOD_1" "createToken" (func $mod1_createToken (type 0))) | ||
(import "MOD_1" "useToken" (func $mod1_useToken (type 1))) | ||
(func $f (type 2) | ||
(i32.const 42) | ||
(call $mod1_createToken) | ||
(call $mod1_useToken) | ||
(i32.const 1) | ||
) | ||
(export "Coin" (abstype_new_ref $Coin)) | ||
(export "f" (func $f)) | ||
(import "Mf" "a" (abstype_sealed $a)) | ||
(import "Mf" "out" (func $out (result (abstype_sealed_ref $a)))) | ||
(import "Mf" "in" (func $in (param (abstype_sealed_ref $a)))) | ||
(func $call | ||
(call $in (call $out))) | ||
) | ||
|
||
|
||
|
||
(module $Nf | ||
(import "Mf" "a" (abstype_sealed $a)) | ||
(func (export "use_a") (param (abstype_sealed_ref $a))) | ||
) | ||
(register "Nf" $Nf) | ||
|
||
(assert_unlinkable | ||
(module (import "Nf" "use_a" (func $use_a (param i32)))) | ||
"incompatible import type" | ||
) | ||
|
||
(module | ||
(import "Mf" "a" (abstype_sealed $_a)) | ||
(import "Nf" "use_a" (func $use_a (param (abstype_sealed_ref $_a)))) | ||
) | ||
|
||
|
||
|
||
;; NOTICE: sealed abstract types can't be exported; i.e. abstypes can't be reexported (to | ||
;; simplify resolving abstype references for equality checks; see notes in extern_types.ml | ||
;; about how abstract types are tied to module instances). | ||
;; | ||
;; (module $reexport_a | ||
;; (import "Mf" "a" (abstype_sealed $a)) | ||
;; (export "a2" (abstype_sealed_ref $a)) | ||
;; ) | ||
;; | ||
;; (module | ||
;; (import "Mf" "a" (abstype_sealed $a)) | ||
;; (import "reexport_a" "a2" (abstype_sealed $a2)) | ||
;; (import "Mf" "out" (func $out (result (abstype_sealed_ref $a)))) | ||
;; (import "Mf" "in" (func $in (param (abstype_sealed_ref $a2)))) | ||
;; (func $call | ||
;; (call $in (call $out))) | ||
;; ) | ||
|
||
|
||
|
||
;; FIXME: 3rd-party modules are able to use double-sealed abstract types | ||
;; as if they are the original sealed abstract type, and visa-versa. | ||
;; | ||
;; (module $Mf_wrapped | ||
;; (import "Mf" "a" (abstype_sealed $a)) | ||
;; (abstype_new $a_w (abstype_sealed_ref $a)) | ||
;; (export "a_w" (abstype_new_ref $a_w)) | ||
;; (import "Mf" "out" (func $Mf_out (result (abstype_sealed_ref $a)))) | ||
;; (import "Mf" "in" (func $Mf_in (param (abstype_sealed_ref $a)))) | ||
;; (func (export "out_w") (result (abstype_sealed_ref $a)) (call $Mf_out)) | ||
;; (func (export "in_w") (param (abstype_sealed_ref $a)) (call $Mf_in (local.get 0))) | ||
;; ) | ||
;; (register "Mf_wrapped" $Mf_wrapped) | ||
;; | ||
;; (assert_unlinkable | ||
;; (module | ||
;; (import "Mf_wrapped" "out_w" (func $out (result i32))) | ||
;; ) | ||
;; "incompatible import type" | ||
;; ) | ||
;; | ||
;; (assert_unlinkable | ||
;; (module | ||
;; (import "Mf_wrapped" "a_w" (abstype_sealed $a_w)) | ||
;; (import "Mf" "out" (func $out (result (abstype_sealed_ref $a_w)))) | ||
;; ) | ||
;; "incompatible import type" | ||
;; ) | ||
;; | ||
;; (assert_unlinkable | ||
;; (module | ||
;; (import "Mf" "a" (abstype_sealed $a)) | ||
;; (import "Mf_wrapped" "out_w" (func $out (result (abstype_sealed_ref $a)))) | ||
;; ) | ||
;; "incompatible import type" | ||
;; ) | ||
|
||
|
||
|
||
(module $M2f | ||
(abstype_new $a i32) | ||
(export "a1" (abstype_new_ref $a)) | ||
(export "a2" (abstype_new_ref $a)) | ||
(func (export "out") (result (abstype_new_ref $a)) (i32.const 42)) | ||
(func (export "in") (param (abstype_new_ref $a))) | ||
) | ||
(register "M2f" $M2f) | ||
|
||
;; TODO: should abstypes depend on imports or should they resolve be fully resolved to | ||
;; their (Module Instance * abstype_new) declarations before being compared? If the latter, | ||
;; then this test module would not be invalid. | ||
(assert_invalid | ||
(module | ||
(import "MOD_1" "Token" (abstype_sealed $Token)) | ||
(type (;0;) (func (param (abstype_sealed_ref $Token)))) | ||
(func $useToken (import "MOD_1" "useToken") (type 0)) | ||
(func $f | ||
(i32.const 42) | ||
(call $useToken) | ||
) | ||
(import "M2f" "a1" (abstype_sealed $a1)) | ||
(import "M2f" "a2" (abstype_sealed $a2)) | ||
(import "M2f" "out" (func $M2f_out (result (abstype_sealed_ref $a1)))) | ||
(import "M2f" "in" (func $M2f_in (param (abstype_sealed_ref $a2)))) | ||
(func (call $M2f_in (call $M2f_out))) | ||
) | ||
"type mismatch" | ||
"type mismatch: operator requires [abs{1}] but stack has [abs{0}]" | ||
) | ||
|
||
;; TODO test call_indirect w/ abstypes | ||
;; TODO test invoke | ||
|
||
|
||
(module $Mt | ||
(abstype_new $a i32) | ||
(export "a" (abstype_new_ref $a)) | ||
(type $f_abs (func (result (abstype_new_ref $a)))) | ||
(func $out (type $f_abs) (i32.const 42)) | ||
(table (export "table") 10 funcref) | ||
(elem (i32.const 0) $out) | ||
) | ||
(register "Mt" $Mt) | ||
|
||
(module $Mt_no_abs | ||
(type $f_raw (func (result i32))) | ||
(table (import "Mt" "table") 10 funcref) | ||
(func (export "call") (result i32) | ||
(call_indirect (type $f_raw) (i32.const 0))) | ||
) | ||
|
||
(assert_trap (invoke $Mt_no_abs "call") "indirect call type mismatch") | ||
|
||
;; FIXME: the runtime is not enforcing abstraction for stack values coming into | ||
;; a call_indirect operation. In the following test, the type checker will | ||
;; incorrectly unwrap (abstype_sealed_ref $a) into an "i32" (which can be | ||
;; confirmed by changing `(i32.const 0)` to `(f32.const 0.0)` which then | ||
;; reports "type mismatch: operator requires [i32] but stack has [f32]"). | ||
;; | ||
;; (module $Mt_abs | ||
;; (import "Mt" "a" (abstype_sealed $a)) | ||
;; (type $f_abs (func (result (abstype_sealed_ref $a)))) | ||
;; (table (import "Mt" "table") 10 funcref) | ||
;; (func (export "call") (result (abstype_sealed_ref $a)) | ||
;; (call_indirect (type $f_abs) (i32.const 0))) | ||
;; ) | ||
;; | ||
;; (assert_trap (invoke $Mt_abs "call") "indirect call type mismatch") | ||
|
||
|
||
|
||
;; FIXME: global imports aren't enforcing abstract types. | ||
;; | ||
;; (module $Mg | ||
;; (abstype_new $a1 i32) | ||
;; (global $g1 (export "g1") (abstype_new_ref $a1) (i32.const 0)) | ||
;; ) | ||
;; (register "Mg" $Mg) | ||
;; | ||
;; (assert_unlinkable | ||
;; (module (global $Mg_g1 (import "Mg" "g1") i32)) | ||
;; "incompatible import type" | ||
;; ) |