diff --git a/document/core/appendix/algorithm.rst b/document/core/appendix/algorithm.rst index 42fc8696..df1165a8 100644 --- a/document/core/appendix/algorithm.rst +++ b/document/core/appendix/algorithm.rst @@ -26,7 +26,7 @@ Types are representable as a set of enumerations. .. code-block:: pseudo type num_type = I32 | I64 | F32 | F64 - type heap_type = Def(idx : nat) | Func | Extern + type heap_type = Def(idx : nat) | Func | Extern | Bot type ref_type = Ref(heap : heap_type, null : bool) type val_type = num_type | ref_type | Bot @@ -52,6 +52,8 @@ Equivalence and subtyping checks can be defined on these types. return eq_def(n1, n2) case (Def(_), Func) return true + case (Bot, _) + return true case (_, _) return t1 = t2 @@ -111,9 +113,10 @@ However, these variables are not manipulated directly by the main checking funct error_if(not is_num(actual)) return actual - func pop_ref() : ref_type | Bot = + func pop_ref() : ref_type = let actual = pop_val() error_if(not is_ref(actual)) + if actual = Bot then return Ref(Bot, false) return actual func pop_val(expect : val_type) : val_type = @@ -228,9 +231,9 @@ Other instructions are checked in a similar manner. pop_ref() push_val(I32) - case (ref.as_non_null ht) - pop_ref() - push_val(Ref(ht, false)) + case (ref.as_non_null) + let rt = pop_ref() + push_val(Ref(rt.heap, false))    case (unreachable)       unreachable() @@ -279,16 +282,16 @@ Other instructions are checked in a similar manner.       pop_vals(label_types(ctrls[m]))       unreachable() - case (br_on_null n ht) + case (br_on_null n)      error_if(ctrls.size() < n) - pop_ref() + let rt = pop_ref()       pop_vals(label_types(ctrls[n]))       push_vals(label_types(ctrls[n])) - push_val(Ref(ht, false)) + push_val(Ref(rt.heap, false)) case (call_ref) let rt = pop_ref() - if (rt =/= Bot) + if (rt.heap =/= Bot) error_if(not is_def(rt.heap)) let t1*->t2* = lookup_def(rt.heap.def) // TODO pop_vals(t1*) diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index dbb1350d..149fc79b 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -495,11 +495,8 @@ let rec instr s = | 0xd0 -> ref_null (heap_type s) | 0xd1 -> ref_is_null | 0xd2 -> ref_func (at var s) - | 0xd3 -> ref_as_non_null (heap_type s) - | 0xd4 -> - let x = at var s in - let t = heap_type s in - br_on_null x t + | 0xd3 -> ref_as_non_null + | 0xd4 -> br_on_null (at var s) | 0xfc as b1 -> (match op s with diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index a75c407f..5b6db8d6 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -102,6 +102,7 @@ let encode m = | ExternHeapType -> vs7 (-0x11) | DefHeapType (SynVar x) -> vs33 x | DefHeapType (SemVar _) -> assert false + | BotHeapType -> assert false let ref_type = function | (Nullable, FuncHeapType) -> vs32 (-0x10l) @@ -181,7 +182,7 @@ let encode m = | Br x -> op 0x0c; var x | BrIf x -> op 0x0d; var x | BrTable (xs, x) -> op 0x0e; vec var xs; var x - | BrOnNull (x, t) -> op 0xd4; var x; heap_type t + | BrOnNull x -> op 0xd4; var x | Return -> op 0x0f | Call x -> op 0x10; var x | CallRef -> op 0x14 @@ -258,7 +259,7 @@ let encode m = | RefNull t -> op 0xd0; heap_type t | RefIsNull -> op 0xd1 - | RefAsNonNull t -> op 0xd3; heap_type t + | RefAsNonNull -> op 0xd3 | RefFunc x -> op 0xd2; var x | Const {it = I32 c; _} -> op 0x41; vs32 c diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index fd01c322..76bb1a84 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -209,7 +209,7 @@ let rec step (c : config) : config = else vs', [Plain (Br (Lib.List32.nth xs i)) @@ e.at] - | BrOnNull (x, _), Ref r :: vs' -> + | BrOnNull x, Ref r :: vs' -> (match r with | NullRef _ -> vs', [Plain (Br x) @@ e.at] @@ -492,7 +492,7 @@ let rec step (c : config) : config = Num (I32 0l) :: vs', [] ) - | RefAsNonNull _, Ref r :: vs' -> + | RefAsNonNull, Ref r :: vs' -> (match r with | NullRef _ -> vs', [Trapping "null reference" @@ e.at] diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 400fdea2..fd137081 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -330,14 +330,15 @@ let assert_return ress ts at = | FuncHeapType -> is_funcref_idx | ExternHeapType -> is_externref_idx | DefHeapType _ -> is_funcref_idx + | BotHeapType -> assert false in [ Call (is_ref_idx @@ at) @@ at; Test (I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | NullResult -> (match t with - | RefType (_, t') -> - [ BrOnNull (0l @@ at, t') @@ at ] + | RefType _ -> + [ BrOnNull (0l @@ at) @@ at ] | _ -> [ Br (0l @@ at) @@ at ] ) diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 325a7f90..10831548 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -87,7 +87,7 @@ and instr' = | Br of idx (* break to n-th surrounding label *) | BrIf of idx (* conditional break *) | BrTable of idx list * idx (* indexed break *) - | BrOnNull of idx * heap_type (* break on null *) + | BrOnNull of idx (* break on null *) | Return (* break from function body *) | Call of idx (* call function *) | CallRef (* call function through reference *) @@ -117,7 +117,7 @@ and instr' = | DataDrop of idx (* drop passive data segment *) | RefNull of heap_type (* null reference *) | RefIsNull (* null test *) - | RefAsNonNull of heap_type (* null cast *) + | RefAsNonNull (* null cast *) | RefFunc of idx (* function reference *) | Const of num (* constant *) | Test of testop (* numeric test *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 76d80052..8b99f1aa 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -69,7 +69,7 @@ let num_type = function | I32Type | I64Type | F32Type | F64Type -> empty let heap_type = function - | FuncHeapType | ExternHeapType -> empty + | FuncHeapType | ExternHeapType | BotHeapType -> empty | DefHeapType x -> var_type x let ref_type = function @@ -97,8 +97,8 @@ let rec instr (e : instr) = match e.it with | Unreachable | Nop | Drop -> empty | Select tso -> list value_type (Lib.Option.get tso []) - | RefIsNull -> empty - | RefNull t | RefAsNonNull t -> heap_type t + | RefIsNull | RefAsNonNull -> empty + | RefNull t -> heap_type t | RefFunc x -> funcs (idx x) | Const _ | Test _ | Compare _ | Unary _ | Binary _ | Convert _ -> empty | Block (bt, es) | Loop (bt, es) -> block_type bt ++ block es @@ -106,9 +106,8 @@ let rec instr (e : instr) = | Let (bt, ts, es) -> let free = block_type bt ++ block es in {free with locals = Lib.Fun.repeat (List.length ts) shift free.locals} - | Br x | BrIf x -> labels (idx x) + | Br x | BrIf x | BrOnNull x -> labels (idx x) | BrTable (xs, x) -> list (fun x -> labels (idx x)) (x::xs) - | BrOnNull (x, t) -> labels (idx x) ++ heap_type t | Return | CallRef | ReturnCallRef -> empty | Call x -> funcs (idx x) | CallIndirect (x, y) -> tables (idx x) ++ types (idx y) diff --git a/interpreter/syntax/operators.ml b/interpreter/syntax/operators.ml index 10a4b690..b38d61ab 100644 --- a/interpreter/syntax/operators.ml +++ b/interpreter/syntax/operators.ml @@ -11,7 +11,7 @@ let f64_const n = Const (F64 n.it @@ n.at) let ref_func x = RefFunc x let ref_null t = RefNull t let ref_is_null = RefIsNull -let ref_as_non_null t = RefAsNonNull t +let ref_as_non_null = RefAsNonNull let unreachable = Unreachable let nop = Nop @@ -26,7 +26,7 @@ let let_ bt ts es = Let (bt, ts, es) let br x = Br x let br_if x = BrIf x let br_table xs x = BrTable (xs, x) -let br_on_null x t = BrOnNull (x, t) +let br_on_null x = BrOnNull x let return = Return let call x = Call x diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 8cfb3b36..d37ddbea 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -9,7 +9,8 @@ and var = SynVar of syn_var | SemVar of sem_var and nullability = NonNullable | Nullable and num_type = I32Type | I64Type | F32Type | F64Type and ref_type = nullability * heap_type -and heap_type = FuncHeapType | ExternHeapType | DefHeapType of var +and heap_type = + FuncHeapType | ExternHeapType | DefHeapType of var | BotHeapType and value_type = NumType of num_type | RefType of ref_type | BotType and stack_type = value_type list @@ -113,6 +114,7 @@ let sem_heap_type c = function | FuncHeapType -> FuncHeapType | ExternHeapType -> ExternHeapType | DefHeapType x -> DefHeapType (sem_var_type c x) + | BotHeapType -> BotHeapType let sem_ref_type c = function | (nul, t) -> (nul, sem_heap_type c t) @@ -206,6 +208,7 @@ and string_of_heap_type = function | FuncHeapType -> "func" | ExternHeapType -> "extern" | DefHeapType x -> "(type " ^ string_of_var x ^ ")" + | BotHeapType -> "unreachable" and string_of_ref_type = function | (nul, t) -> diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index b4bb80ad..87f1f461 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -249,7 +249,7 @@ let rec instr e = | BrIf x -> "br_if " ^ var x, [] | BrTable (xs, x) -> "br_table " ^ String.concat " " (list var (xs @ [x])), [] - | BrOnNull (x, t) -> "br_on_null " ^ var x, [Atom (heap_type t)] + | BrOnNull x -> "br_on_null " ^ var x, [] | Return -> "return", [] | Call x -> "call " ^ var x, [] | CallRef -> "call_ref", [] @@ -280,7 +280,7 @@ let rec instr e = | DataDrop x -> "data.drop " ^ var x, [] | RefNull t -> "ref.null", [Atom (heap_type t)] | RefIsNull -> "ref.is_null", [] - | RefAsNonNull t -> "ref.as_non_null", [Atom (heap_type t)] + | RefAsNonNull -> "ref.as_non_null", [] | RefFunc x -> "ref.func " ^ var x, [] | Const n -> constop n ^ " " ^ num n, [] | Test op -> testop op, [] diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index abaafbe0..91b824b2 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -370,7 +370,7 @@ plain_instr : | BR_TABLE var var_list { fun c -> let xs, x = Lib.List.split_last ($2 c label :: $3 c label) in br_table xs x } - | BR_ON_NULL var heap_type { fun c -> br_on_null ($2 c label) ($3 c) } + | BR_ON_NULL var { fun c -> br_on_null ($2 c label) } | RETURN { fun c -> return } | CALL var { fun c -> call ($2 c func) } | CALL_REF { fun c -> call_ref } @@ -407,7 +407,7 @@ plain_instr : | DATA_DROP var { fun c -> data_drop ($2 c data) } | REF_NULL heap_type { fun c -> ref_null ($2 c) } | REF_IS_NULL { fun c -> ref_is_null } - | REF_AS_NON_NULL heap_type { fun c -> ref_as_non_null ($2 c) } + | REF_AS_NON_NULL { fun c -> ref_as_non_null } | REF_FUNC var { fun c -> ref_func ($2 c func) } | CONST num { fun c -> fst (num $1 $2) } | TEST { fun c -> $1 } diff --git a/interpreter/valid/match.ml b/interpreter/valid/match.ml index b41b919e..ab1912f6 100644 --- a/interpreter/valid/match.ml +++ b/interpreter/valid/match.ml @@ -106,6 +106,7 @@ and match_heap_type c a t1 t2 = | FuncDefType _ -> true ) | DefHeapType x1, DefHeapType x2 -> match_var_type c a x1 x2 + | BotHeapType, _ -> true | _, _ -> eq_heap_type c [] t1 t2 and match_ref_type c a t1 t2 = diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index afeadda9..ac7b2743 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -83,7 +83,7 @@ let check_heap_type (c : context) (t : heap_type) at = match t with | FuncHeapType | ExternHeapType -> () | DefHeapType (SynVar x) -> ignore (func_type c (x @@ at)) - | DefHeapType (SemVar _) -> assert false + | DefHeapType (SemVar _) | BotHeapType -> assert false let check_ref_type (c : context) (t : ref_type) at = match t with @@ -166,6 +166,22 @@ let push c (ell1, ts1) (ell2, ts2) = let peek i (ell, ts) = try List.nth (List.rev ts) i with Failure _ -> BotType +let peek_num i (ell, ts) at = + let t = peek i (ell, ts) in + require (is_num_type t) at + ("type mismatch: instruction requires numeric type" ^ + " but stack has " ^ string_of_value_type t); + t + +let peek_ref i (ell, ts) at = + match peek i (ell, ts) with + | RefType rt -> rt + | BotType -> (NonNullable, BotHeapType) + | t -> + error at + ("type mismatch: instruction requires reference type" ^ + " but stack has " ^ string_of_value_type t) + (* Type Synthesis *) @@ -280,10 +296,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [peek 0 s] --> [] | Select None -> - let t = peek 1 s in - require (is_num_type t) e.at - ("type mismatch: instruction requires numeric type" ^ - " but stack has " ^ string_of_value_type t); + let t = peek_num 1 s e.at in [t; t; NumType I32Type] --> [t] | Select (Some ts) -> @@ -331,8 +344,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = List.iter (fun x' -> check_stack c ts (label c x') x'.at) xs; (ts @ [NumType I32Type]) -->... [] - | BrOnNull (x, t) -> - check_heap_type c t e.at; + | BrOnNull x -> + let (_, t) = peek_ref 0 s e.at in (label c x @ [RefType (Nullable, t)]) --> (label c x @ [RefType (NonNullable, t)]) @@ -344,16 +357,13 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = ts1 --> ts2 | CallRef -> - (match peek 0 s with - | RefType (nul, DefHeapType (SynVar x)) -> + (match peek_ref 0 s e.at with + | (nul, DefHeapType (SynVar x)) -> let FuncType (ts1, ts2) = func_type c (x @@ e.at) in (ts1 @ [RefType (nul, DefHeapType (SynVar x))]) --> ts2 - | BotType -> + | (_, BotHeapType) -> [] -->... [] - | t -> - error e.at - ("type mismatch: instruction requires numeric type" ^ - " but stack has " ^ string_of_value_type t); + | _ -> assert false ) | CallIndirect (x, y) -> @@ -365,25 +375,22 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = (ts1 @ [NumType I32Type]) --> ts2 | ReturnCallRef -> - (match peek 0 s with - | RefType (nul, DefHeapType (SynVar x)) -> + (match peek_ref 0 s e.at with + | (nul, DefHeapType (SynVar x)) -> let FuncType (ts1, ts2) = func_type c (x @@ e.at) in require (match_stack_type c.types [] ts2 c.results) e.at ("type mismatch: current function requires result type " ^ string_of_stack_type c.results ^ " but callee returns " ^ string_of_stack_type ts2); (ts1 @ [RefType (nul, DefHeapType (SynVar x))]) -->... [] - | BotType -> + | (_, BotHeapType) -> [] -->... [] - | t -> - error e.at - ("type mismatch: instruction requires function reference" ^ - " but stack has " ^ string_of_value_type t); + | _ -> assert false ) | FuncBind x -> - (match peek 0 s with - | RefType (nul, DefHeapType (SynVar y)) -> + (match peek_ref 0 s e.at with + | (nul, DefHeapType (SynVar y)) -> let FuncType (ts1, ts2) = func_type c (y @@ e.at) in let FuncType (ts1', _) as ft' = func_type c x in require (List.length ts1 >= List.length ts1') x.at @@ -393,12 +400,9 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = "type mismatch in function type"; (ts11 @ [RefType (nul, DefHeapType (SynVar y))]) --> [RefType (NonNullable, DefHeapType (SynVar x.it))] - | BotType -> + | (_, BotHeapType) -> [] -->... [RefType (NonNullable, DefHeapType (SynVar x.it))] - | t -> - error e.at - ("type mismatch: instruction requires function reference" ^ - " but stack has " ^ string_of_value_type t); + | _ -> assert false ) | LocalGet x -> @@ -497,14 +501,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_stack_type) : op_type = [] --> [RefType (Nullable, t)] | RefIsNull -> - let t = peek 0 s in - require (is_ref_type t) e.at - ("type mismatch: instruction requires reference type" ^ - " but stack has " ^ string_of_value_type t); - [t] --> [NumType I32Type] + let rt = peek_ref 0 s e.at in + [RefType rt] --> [NumType I32Type] - | RefAsNonNull t -> - check_heap_type c t e.at; + | RefAsNonNull -> + let (_, t) = peek_ref 0 s e.at in [RefType (Nullable, t)] --> [RefType (NonNullable, t)] | RefFunc x -> diff --git a/proposals/function-references/Overview.md b/proposals/function-references/Overview.md index 0b460833..66a3f3d0 100644 --- a/proposals/function-references/Overview.md +++ b/proposals/function-references/Overview.md @@ -224,13 +224,13 @@ The following rules, now defined in terms of heap types, replace and extend the - `ref.null ht: [] -> [(ref null ht)]` - iff `ht ok` -* `ref.as_non_null ` converts a nullable reference to a non-null one - - `ref.as_non_null ht: [(ref null ht)] -> [(ref ht)]` +* `ref.as_non_null` converts a nullable reference to a non-null one + - `ref.as_non_null : [(ref null ht)] -> [(ref ht)]` - iff `ht ok` - traps on `null` -* `br_on_null $l ` checks for null and branches - - `br_on_null $l ht : [t* (ref null ht)] -> [t* (ref ht)]` +* `br_on_null $l` checks for null and branches + - `br_on_null $l : [t* (ref null ht)] -> [t* (ref ht)]` - iff `$l : [t*]` - and `ht ok` - branches to `$l` on `null`, otherwise returns operand as non-null @@ -298,8 +298,8 @@ The opcode for heap types is encoded as an `s33`. | 0x15 | `return_call_ref` | | | 0x16 | `func.bind (type $t)` | `$t : u32` | | 0x17 | `let ` | `bt : blocktype, locals : (as in functions)` | -| 0xd3 | `ref.as_non_null ht` | ht : heaptype | -| 0xd4 | `br_on_null $l ht` | `$l : u32`, ht : heaptype | +| 0xd3 | `ref.as_non_null` | | +| 0xd4 | `br_on_null $l` | `$l : u32` | ### Tables diff --git a/test/core/br_on_null.wast b/test/core/br_on_null.wast index 933f0a83..7750ae24 100644 --- a/test/core/br_on_null.wast +++ b/test/core/br_on_null.wast @@ -3,13 +3,13 @@ (func $nn (param $r (ref $t)) (result i32) (block $l - (return (call_ref (br_on_null $l (type $t) (local.get $r)))) + (return (call_ref (br_on_null $l (local.get $r)))) ) (i32.const -1) ) (func $n (param $r (ref null $t)) (result i32) (block $l - (return (call_ref (br_on_null $l (type $t) (local.get $r)))) + (return (call_ref (br_on_null $l (local.get $r)))) ) (i32.const -1) ) @@ -23,7 +23,7 @@ (func (export "unreachable") (result i32) (block $l - (return (call_ref (br_on_null $l (type $t) (unreachable)))) + (return (call_ref (br_on_null $l (unreachable)))) ) (i32.const -1) ) @@ -38,7 +38,7 @@ (assert_invalid (module (type $t (func (result i32))) - (func $g (param $r (ref $t)) (drop (br_on_null 0 (type $t) (local.get $r)))) + (func $g (param $r (ref $t)) (drop (br_on_null 0 (local.get $r)))) (func (call $g (ref.null (type $t)))) ) "type mismatch" @@ -46,9 +46,9 @@ (module (type $t (func)) - (func (param $r (ref $t)) (drop (br_on_null 0 (type $t) (local.get $r)))) - (func (param $r (ref func)) (drop (br_on_null 0 func (local.get $r)))) - (func (param $r (ref extern)) (drop (br_on_null 0 extern (local.get $r)))) + (func (param $r (ref $t)) (drop (br_on_null 0 (local.get $r)))) + (func (param $r (ref func)) (drop (br_on_null 0 (local.get $r)))) + (func (param $r (ref extern)) (drop (br_on_null 0 (local.get $r)))) ) @@ -59,7 +59,7 @@ (func $a (param $n i32) (param $r (ref null (type $t))) (result i32) (block $l (result i32) - (return (call_ref (br_on_null $l (type $t) (local.get $n) (local.get $r)))) + (return (call_ref (br_on_null $l (local.get $n) (local.get $r)))) ) ) diff --git a/test/core/ref_as_non_null.wast b/test/core/ref_as_non_null.wast index 09e915ad..c679db45 100644 --- a/test/core/ref_as_non_null.wast +++ b/test/core/ref_as_non_null.wast @@ -2,10 +2,10 @@ (type $t (func (result i32))) (func $nn (param $r (ref $t)) (result i32) - (call_ref (ref.as_non_null (type $t) (local.get $r))) + (call_ref (ref.as_non_null (local.get $r))) ) (func $n (param $r (ref null $t)) (result i32) - (call_ref (ref.as_non_null (type $t) (local.get $r))) + (call_ref (ref.as_non_null (local.get $r))) ) (elem func $f) @@ -17,7 +17,7 @@ (func (export "unreachable") (result i32) (unreachable) - (ref.as_non_null (type $t)) + (ref.as_non_null) (call $nn) ) ) @@ -31,7 +31,7 @@ (assert_invalid (module (type $t (func (result i32))) - (func $g (param $r (ref $t)) (drop (ref.as_non_null (type $t) (local.get $r)))) + (func $g (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) (func (call $g (ref.null (type $t)))) ) "type mismatch" @@ -40,7 +40,7 @@ (module (type $t (func)) - (func (param $r (ref $t)) (drop (ref.as_non_null (type $t) (local.get $r)))) - (func (param $r (ref func)) (drop (ref.as_non_null func (local.get $r)))) - (func (param $r (ref extern)) (drop (ref.as_non_null extern (local.get $r)))) + (func (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) + (func (param $r (ref func)) (drop (ref.as_non_null (local.get $r)))) + (func (param $r (ref extern)) (drop (ref.as_non_null (local.get $r)))) ) diff --git a/test/core/unreached-invalid.wast b/test/core/unreached-invalid.wast index 3ddd7738..51965639 100644 --- a/test/core/unreached-invalid.wast +++ b/test/core/unreached-invalid.wast @@ -686,10 +686,21 @@ (assert_invalid (module (func $type-br_if-after-unreachable (result i64) - unreachable - br_if 0 - i64.extend_i32_u + (unreachable) + (br_if 0) + (i64.extend_i32_u) ) ) "type mismatch" ) + +(assert_invalid + (module + (func $type-after-ref.as_non_null + (unreachable) + (ref.as_non_null) + (f32.abs) + ) + ) + "type mismatch" +)