diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index fa5ca469d..3a2c683f8 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -179,7 +179,7 @@ let vectype s = let heaptype s = let pos = pos s in either [ - (fun s -> UseHT (typeuse s33 s)); + (fun s -> UseHT (Inexact, typeuse s33 s)); (fun s -> match s7 s with | -0x0c -> NoExnHT @@ -194,7 +194,7 @@ let heaptype s = | -0x15 -> StructHT | -0x16 -> ArrayHT | -0x17 -> ExnHT - | -0x1e -> ExactHT (typeuse s32 s) + | -0x1e -> UseHT (Exact, typeuse s32 s) | _ -> error s pos "malformed heap type" ) ] s @@ -652,13 +652,19 @@ let rec instr s = | 0x15l -> let ht = heaptype s in ref_test (Null, ht) | 0x16l -> let ht = heaptype s in ref_cast (NoNull, ht) | 0x17l -> let ht = heaptype s in ref_cast (Null, ht) - | 0x18l | 0x19l as opcode -> + | 0x18l | 0x19l | 0x25l | 0x26l as opcode -> let flags = byte s in require (flags land 0xfc = 0) s (pos + 2) "malformed br_on_cast flags"; let x = at idx s in let rt1 = ((if bit 0 flags then Null else NoNull), heaptype s) in let rt2 = ((if bit 1 flags then Null else NoNull), heaptype s) in - (if opcode = 0x18l then br_on_cast else br_on_cast_fail) x rt1 rt2 + (match opcode with + | 0x18l -> br_on_cast x rt1 rt2 + | 0x19l -> br_on_cast_fail x rt1 rt2 + | 0x25l -> br_on_cast_desc x rt1 rt2 + | 0x26l -> br_on_cast_desc_fail x rt1 rt2 + | _ -> assert false + ) | 0x1al -> any_convert_extern | 0x1bl -> extern_convert_any @@ -667,6 +673,10 @@ let rec instr s = | 0x1dl -> i31_get_s | 0x1el -> i31_get_u + | 0x22l -> let x = at idx s in ref_get_desc x + | 0x23l -> let ht = heaptype s in ref_cast_desc (NoNull, ht) + | 0x24l -> let ht = heaptype s in ref_cast_desc (Null, ht) + | n -> illegal2 s pos b n ) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 19163e3db..0ac7cb8af 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -131,8 +131,8 @@ struct | NoExnHT -> s7 (-0x0c) | ExternHT -> s7 (-0x11) | NoExternHT -> s7 (-0x0e) - | UseHT ut -> typeuse s33 ut - | ExactHT ut -> s7 (-0x1e); typeuse u32 ut + | UseHT (Inexact, ut) -> typeuse s33 ut + | UseHT (Exact, ut) -> s7 (-0x1e); typeuse u32 ut | BotHT -> assert false let reftype = function @@ -276,6 +276,12 @@ struct | BrOnCastFail (x, (nul1, t1), (nul2, t2)) -> let flags = bit 0 (nul1 = Null) + bit 1 (nul2 = Null) in op 0xfb; op 0x19; byte flags; idx x; heaptype t1; heaptype t2 + | BrOnCastDesc (x, (nul1, t1), (nul2, t2)) -> + let flags = bit 0 (nul1 = Null) + bit 1 (nul2 = Null) in + op 0xfb; op 0x25; byte flags; idx x; heaptype t1; heaptype t2 + | BrOnCastDescFail (x, (nul1, t1), (nul2, t2)) -> + let flags = bit 0 (nul1 = Null) + bit 1 (nul2 = Null) in + op 0xfb; op 0x26; byte flags; idx x; heaptype t1; heaptype t2 | Return -> op 0x0f | Call x -> op 0x10; idx x | CallRef x -> op 0x14; idx x @@ -429,6 +435,10 @@ struct | RefTest (Null, t) -> op 0xfb; op 0x15; heaptype t | RefCast (NoNull, t) -> op 0xfb; op 0x16; heaptype t | RefCast (Null, t) -> op 0xfb; op 0x17; heaptype t + | RefCastDesc (NoNull, t) -> op 0xfb; op 0x23; heaptype t + | RefCastDesc (Null, t) -> op 0xfb; op 0x24; heaptype t + + | RefGetDesc x -> op 0xfb; op 0x22; idx x | RefI31 -> op 0xfb; op 0x1c | I31Get S -> op 0xfb; op 0x1d diff --git a/interpreter/runtime/aggr.ml b/interpreter/runtime/aggr.ml index 54ef49909..a72083c84 100644 --- a/interpreter/runtime/aggr.ml +++ b/interpreter/runtime/aggr.ml @@ -58,8 +58,8 @@ let type_of_array (Array (dt, _)) = dt let () = let type_of_ref' = !Value.type_of_ref' in Value.type_of_ref' := function - | StructRef s -> UseHT (Def (type_of_struct s)) - | ArrayRef a -> UseHT (Def (type_of_array a)) + | StructRef s -> UseHT (Exact, Def (type_of_struct s)) + | ArrayRef a -> UseHT (Exact, Def (type_of_array a)) | r -> type_of_ref' r let string_of_field = function diff --git a/interpreter/runtime/exn.ml b/interpreter/runtime/exn.ml index bd341469b..bff5726ae 100644 --- a/interpreter/runtime/exn.ml +++ b/interpreter/runtime/exn.ml @@ -28,7 +28,7 @@ let () = let () = let type_of_ref' = !Value.type_of_ref' in Value.type_of_ref' := function - | ExnRef e -> UseHT (Def (type_of e)) + | ExnRef e -> UseHT (Exact, (Def (type_of e))) | r -> type_of_ref' r let () = diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index ddb1a885d..d02542bec 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -45,7 +45,7 @@ let () = let () = let type_of_ref' = !Value.type_of_ref' in Value.type_of_ref' := function - | FuncRef f -> UseHT (Def (Func.type_of f)) + | FuncRef f -> UseHT (Exact, (Def (Func.type_of f))) | r -> type_of_ref' r let () = diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 38d1c0fc6..7710a0bee 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -298,9 +298,9 @@ let rec statify_typeuse rts = function | ht -> rts, ht and statify_heaptype rts = function - | UseHT ut -> + | UseHT (exact, ut) -> let rts', ut' = statify_typeuse rts ut in - rts', UseHT ut' + rts', UseHT (exact, ut') | ht -> rts, ht and statify_reftype rts = function diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 6686c41dc..25e8da979 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -181,6 +181,8 @@ and instr' = | BrOnNonNull of labelidx (* break on type inverted *) | BrOnCast of labelidx * reftype * reftype (* break on type *) | BrOnCastFail of labelidx * reftype * reftype (* break on type inverted *) + | BrOnCastDesc of labelidx * reftype * reftype (* break on descriptor cast *) + | BrOnCastDescFail of labelidx * reftype * reftype (* break on descriptor cast inverted *) | Return (* break from function body *) | Call of funcidx (* call function *) | CallRef of typeidx (* call function through reference *) @@ -222,6 +224,8 @@ and instr' = | RefAsNonNull (* type cast *) | RefTest of reftype (* type test *) | RefCast of reftype (* type cast *) + | RefCastDesc of reftype (* descriptor type cast *) + | RefGetDesc of typeidx (* read descriptor *) | RefEq (* reference equality *) | RefI31 (* scalar reference *) | I31Get of sx (* read scalar *) diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 229d76e9a..ddc76a95b 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -82,8 +82,7 @@ and heaptype = function | FuncHT | NoFuncHT -> empty | ExnHT | NoExnHT -> empty | ExternHT | NoExternHT -> empty - | UseHT x -> typeuse x - | ExactHT x -> typeuse x + | UseHT (_, x) -> typeuse x | BotHT -> empty and reftype = function @@ -143,7 +142,8 @@ let rec instr (e : instr) = | Block (bt, es) | Loop (bt, es) -> blocktype bt ++ block es | If (bt, es1, es2) -> blocktype bt ++ block es1 ++ block es2 | Br x | BrIf x | BrOnNull x | BrOnNonNull x -> labels (idx x) - | BrOnCast (x, t1, t2) | BrOnCastFail (x, t1, t2) -> + | BrOnCast (x, t1, t2) | BrOnCastFail (x, t1, t2) + | BrOnCastDesc (x, t1, t2) | BrOnCastDescFail (x, t1, t2) -> labels (idx x) ++ reftype t1 ++ reftype t2 | BrTable (xs, x) -> list (fun x -> labels (idx x)) (x::xs) | Return -> empty @@ -169,7 +169,8 @@ let rec instr (e : instr) = | MemoryInit (x, y) -> memories (idx x) ++ datas (idx y) | DataDrop x -> datas (idx x) | RefIsNull | RefAsNonNull -> empty - | RefTest t | RefCast t -> reftype t + | RefTest t | RefCast t | RefCastDesc t -> reftype t + | RefGetDesc x -> types (idx x) | RefEq -> empty | RefNull t -> heaptype t | RefFunc x -> funcs (idx x) diff --git a/interpreter/syntax/mnemonics.ml b/interpreter/syntax/mnemonics.ml index aa2151958..d2aaecfda 100644 --- a/interpreter/syntax/mnemonics.ml +++ b/interpreter/syntax/mnemonics.ml @@ -35,6 +35,8 @@ let br_on_null x = BrOnNull x let br_on_non_null x = BrOnNonNull x let br_on_cast x t1 t2 = BrOnCast (x, t1, t2) let br_on_cast_fail x t1 t2 = BrOnCastFail (x, t1, t2) +let br_on_cast_desc x t1 t2 = BrOnCastDesc (x, t1, t2) +let br_on_cast_desc_fail x t1 t2 = BrOnCastDescFail (x, t1, t2) let catch x1 x2 = Catch (x1, x2) let catch_ref x1 x2 = CatchRef (x1, x2) @@ -173,6 +175,8 @@ let ref_is_null = RefIsNull let ref_as_non_null = RefAsNonNull let ref_test t = RefTest t let ref_cast t = RefCast t +let ref_cast_desc t = RefCastDesc t +let ref_get_desc x = RefGetDesc x let ref_eq = RefEq let ref_i31 = RefI31 diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 548cc83f6..cb8ee9537 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -5,6 +5,7 @@ type localidx = int32 type name = Utf8.unicode type null = NoNull | Null +type exact = Exact | Inexact type mut = Cons | Var type init = Set | Unset type final = NoFinal | Final @@ -18,7 +19,7 @@ and vectype = V128T and heaptype = | AnyHT | NoneHT | EqHT | I31HT | StructHT | ArrayHT | FuncHT | NoFuncHT | ExnHT | NoExnHT | ExternHT | NoExternHT - | UseHT of typeuse | ExactHT of typeuse | BotHT + | UseHT of exact * typeuse | BotHT and reftype = null * heaptype and valtype = NumT of numtype | VecT of vectype | RefT of reftype | BotT @@ -173,8 +174,7 @@ and subst_heaptype s = function | NoExnHT -> NoExnHT | ExternHT -> ExternHT | NoExternHT -> NoExternHT - | UseHT t -> UseHT (subst_typeuse s t) - | ExactHT t -> ExactHT (subst_typeuse s t) + | UseHT (exact, t) -> UseHT (exact, subst_typeuse s t) | BotHT -> BotHT and subst_reftype s = function @@ -282,9 +282,12 @@ let unroll_deftype (dt : deftype) : subtype = let RecT sts = unroll_rectype rt in Lib.List32.nth sts i -(* TODO: consider returning a desctype here. *) +let expand_deftype_to_desctype (dt : deftype) : desctype = + let SubT (_, _, dt) = unroll_deftype dt in + dt + let expand_deftype (dt : deftype) : comptype = - let SubT (_, _, DescT (_, _, st)) = unroll_deftype dt in + let DescT (_, _, st) = expand_deftype_to_desctype dt in st @@ -350,8 +353,8 @@ and string_of_heaptype = function | NoExnHT -> "noexn" | ExternHT -> "extern" | NoExternHT -> "noextern" - | UseHT ut -> string_of_typeuse ut - | ExactHT ut -> "(exact " ^ (string_of_typeuse ut) ^ ")" + | UseHT (Inexact, ut) -> string_of_typeuse ut + | UseHT (Exact, ut) -> "(exact " ^ (string_of_typeuse ut) ^ ")" | BotHT -> "something" and string_of_reftype = function diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 5bc9b59ec..80649fb7b 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -513,6 +513,10 @@ let rec instr e = "br_on_cast " ^ idx x, [Atom (reftype t1); Atom (reftype t2)] | BrOnCastFail (x, t1, t2) -> "br_on_cast_fail " ^ idx x, [Atom (reftype t1); Atom (reftype t2)] + | BrOnCastDesc (x, t1, t2) -> + "br_on_cast_desc " ^ idx x, [Atom (reftype t1); Atom (reftype t2)] + | BrOnCastDescFail (x, t1, t2) -> + "br_on_cast_desc_fail " ^ idx x, [Atom (reftype t1); Atom (reftype t2)] | Return -> "return", [] | Call x -> "call " ^ idx x, [] | CallRef x -> "call_ref " ^ idx x, [] @@ -557,6 +561,8 @@ let rec instr e = | RefAsNonNull -> "ref.as_non_null", [] | RefTest t -> "ref.test", [Atom (reftype t)] | RefCast t -> "ref.cast", [Atom (reftype t)] + | RefCastDesc t -> "ref.cast_desc", [Atom (reftype t)] + | RefGetDesc x -> "ref.get_desc " ^ idx x, [] | RefEq -> "ref.eq", [] | RefI31 -> "ref.i31", [] | I31Get sx -> "i31.get" ^ ext sx, [] diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index 8cbbac371..ffbe55b74 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -204,6 +204,8 @@ rule token = parse | "br_on_non_null" -> BR_ON_NULL br_on_non_null | "br_on_cast" -> BR_ON_CAST br_on_cast | "br_on_cast_fail" -> BR_ON_CAST br_on_cast_fail + | "br_on_cast_desc" -> BR_ON_CAST br_on_cast_desc + | "br_on_cast_desc_fail" -> BR_ON_CAST br_on_cast_desc_fail | "return" -> RETURN | "if" -> IF | "then" -> THEN @@ -338,6 +340,8 @@ rule token = parse | "ref.as_non_null" -> REF_AS_NON_NULL | "ref.test" -> REF_TEST | "ref.cast" -> REF_CAST + | "ref.cast_desc" -> REF_CAST_DESC + | "ref.get_desc" -> REF_GET_DESC | "ref.eq" -> REF_EQ | "ref.i31" -> REF_I31 diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index c14fa34b1..05c5180a7 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -304,7 +304,7 @@ let parse_annots (m : module_) : Custom.section list = %token Ast.instr' * Value.num> CONST %token UNARY BINARY TEST COMPARE CONVERT %token REF_NULL REF_FUNC REF_I31 REF_STRUCT REF_ARRAY REF_EXN REF_EXTERN REF_HOST -%token REF_EQ REF_IS_NULL REF_AS_NON_NULL REF_TEST REF_CAST +%token REF_EQ REF_IS_NULL REF_AS_NON_NULL REF_TEST REF_CAST REF_CAST_DESC REF_GET_DESC %token I31_GET %token Ast.instr'> STRUCT_NEW ARRAY_NEW ARRAY_GET %token STRUCT_SET @@ -376,8 +376,8 @@ heaptype : | NOEXN { fun c -> NoExnHT } | EXTERN { fun c -> ExternHT } | NOEXTERN { fun c -> NoExternHT } - | idx { fun c -> UseHT (Idx ($1 c type_).it) } - | LPAR EXACT idx RPAR { fun c -> ExactHT (Idx ($3 c type_).it) } + | idx { fun c -> UseHT (Inexact, Idx ($1 c type_).it) } + | LPAR EXACT idx RPAR { fun c -> UseHT (Exact, Idx ($3 c type_).it) } reftype : | LPAR REF null_opt heaptype RPAR { fun c -> ($3, $4 c) } @@ -633,6 +633,8 @@ plaininstr : | REF_AS_NON_NULL { fun c -> ref_as_non_null } | REF_TEST reftype { fun c -> ref_test ($2 c) } | REF_CAST reftype { fun c -> ref_cast ($2 c) } + | REF_CAST_DESC reftype { fun c -> ref_cast_desc ($2 c) } + | REF_GET_DESC idx { fun c -> ref_get_desc ($2 c type_) } | REF_EQ { fun c -> ref_eq } | REF_I31 { fun c -> ref_i31 } | I31_GET { fun c -> $1 } diff --git a/interpreter/valid/match.ml b/interpreter/valid/match.ml index 1aeb1d88d..3fdc1e0e1 100644 --- a/interpreter/valid/match.ml +++ b/interpreter/valid/match.ml @@ -27,8 +27,7 @@ and top_of_heaptype c = function | FuncHT | NoFuncHT -> FuncHT | ExnHT | NoExnHT -> ExnHT | ExternHT | NoExternHT -> ExternHT - | UseHT ut -> top_of_typeuse c ut - | ExactHT ut -> top_of_typeuse c ut + | UseHT (_, ut) -> top_of_typeuse c ut | BotHT -> assert false let top_of_valtype c = function @@ -50,8 +49,7 @@ and bot_of_heaptype c = function | FuncHT | NoFuncHT -> NoFuncHT | ExnHT | NoExnHT -> NoExnHT | ExternHT | NoExternHT -> NoExternHT - | UseHT ut -> bot_of_typeuse c ut - | ExactHT ut -> bot_of_typeuse c ut + | UseHT (_, ut) -> bot_of_typeuse c ut | BotHT -> assert false @@ -89,10 +87,14 @@ let rec match_heaptype c t1 t2 = | NoFuncHT, t -> match_heaptype c t FuncHT | NoExnHT, t -> match_heaptype c t ExnHT | NoExternHT, t -> match_heaptype c t ExternHT - | UseHT (Idx x1), _ -> match_heaptype c (UseHT (Def (lookup c x1))) t2 - | _, UseHT (Idx x2) -> match_heaptype c t1 (UseHT (Def (lookup c x2))) - | UseHT (Def dt1), UseHT (Def dt2) -> match_deftype c dt1 dt2 - | UseHT (Def dt), t -> + | UseHT (exact, Idx x1), _ -> + match_heaptype c (UseHT (exact, Def (lookup c x1))) t2 + | _, UseHT (exact, Idx x2) -> + match_heaptype c t1 (UseHT (exact, Def (lookup c x2))) + | UseHT (_, Def dt1), UseHT (Inexact, Def dt2) -> match_deftype c dt1 dt2 + | UseHT (Exact, Def dt1), UseHT (Exact, Def dt2) -> + match_deftype c dt1 dt2 && match_deftype c dt2 dt1 + | UseHT (_, Def dt), t -> (match expand_deftype dt, t with | StructT _, AnyHT -> true | StructT _, EqHT -> true @@ -103,13 +105,6 @@ let rec match_heaptype c t1 t2 = | FuncT _, FuncHT -> true | _ -> false ) - | ExactHT (Idx x1), _ -> - match_heaptype c (ExactHT (Def (lookup c x1))) t2 - | _, ExactHT (Idx x2) -> - match_heaptype c t1 (ExactHT (Def (lookup c x2))) - | ExactHT (Def dt1), ExactHT (Def dt2) -> - match_deftype c dt1 dt2 && match_deftype c dt2 dt1 - | ExactHT (Def dt1), _ -> match_heaptype c (UseHT (Def dt1)) t2 | BotHT, _ -> true | _, _ -> t1 = t2 @@ -160,8 +155,10 @@ and match_comptype c ct1 ct2 = and match_deftype c dt1 dt2 = dt1 == dt2 || (* optimisation *) let s = subst_of c in subst_deftype s dt1 = subst_deftype s dt2 || - let SubT (_fin, uts1, _st) = unroll_deftype dt1 in - List.exists (fun ut1 -> match_heaptype c (UseHT ut1) (UseHT (Def dt2))) uts1 + let SubT (_fin, uts1, _dt) = unroll_deftype dt1 in + List.exists (fun ut1 -> + match_heaptype c (UseHT (Inexact, ut1)) (UseHT (Inexact, (Def dt2))) + ) uts1 let match_tagtype c (TagT ut1) (TagT ut2) = match ut1, ut2 with diff --git a/interpreter/valid/match.mli b/interpreter/valid/match.mli index 279cc4f7c..f3f20962f 100644 --- a/interpreter/valid/match.mli +++ b/interpreter/valid/match.mli @@ -18,6 +18,7 @@ val bot_of_comptype : context -> comptype -> heaptype (* Subtyping *) val match_numtype : context -> numtype -> numtype -> bool +val match_heaptype : context -> heaptype -> heaptype -> bool val match_reftype : context -> reftype -> reftype -> bool val match_valtype : context -> valtype -> valtype -> bool diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 7042b4778..e9c216495 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -121,8 +121,7 @@ let check_heaptype (c : context) (t : heaptype) at = | FuncHT | NoFuncHT | ExnHT | NoExnHT | ExternHT | NoExternHT -> () - | UseHT ut -> check_typeuse c ut at - | ExactHT ut -> check_typeuse c ut at + | UseHT (_, ut) -> check_typeuse c ut at | BotHT -> () let check_reftype (c : context) (t : reftype) at = @@ -367,6 +366,19 @@ let type_externop op = | Internalize -> ExternHT, AnyHT | Externalize -> AnyHT, ExternHT +let desc_cast_ref c rt at = + let (_, ht) = rt in + let exact, x = match ht with + | UseHT (exact, Idx x) -> exact, x + | _ -> + error at ("type " ^ string_of_heaptype ht ^ " does not have a descriptor") + in + let DescT (_, ut', _) = expand_deftype_to_desctype (type_ c (x @@ at)) in + match ut' with + | Some ut' -> (Null, UseHT (exact, ut')) + | None -> + error at ("type " ^ string_of_heaptype ht ^ " does not have a descriptor") + (* Expressions *) @@ -501,10 +513,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins | BrOnCast (x, rt1, rt2) -> check_reftype c rt1 e.at; check_reftype c rt2 e.at; + let (_, ht1), (_, ht2) = rt1, rt2 in require - (match_reftype c.types rt2 rt1) e.at - ("type mismatch on cast: type " ^ string_of_reftype rt2 ^ - " does not match " ^ string_of_reftype rt1); + (top_of_heaptype c.types ht1 = top_of_heaptype c.types ht2) e.at + ("type mismatch on cast: type " ^ string_of_heaptype ht1 ^ + " has a different top type than type " ^ string_of_heaptype ht2); require (label c x <> []) e.at ("type mismatch: instruction requires type " ^ string_of_reftype rt2 ^ " but label has " ^ string_of_resulttype (label c x)); @@ -518,10 +531,11 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins check_reftype c rt1 e.at; check_reftype c rt2 e.at; let rt1' = diff_reftype rt1 rt2 in + let (_, ht1), (_, ht2) = rt1, rt2 in require - (match_reftype c.types rt2 rt1) e.at - ("type mismatch on cast: type " ^ string_of_reftype rt2 ^ - " does not match " ^ string_of_reftype rt1); + (top_of_heaptype c.types ht1 = top_of_heaptype c.types ht2) e.at + ("type mismatch on cast: type " ^ string_of_heaptype ht1 ^ + " has a different top type than type " ^ string_of_heaptype ht2); require (label c x <> []) e.at ("type mismatch: instruction requires type " ^ string_of_reftype rt1' ^ " but label has " ^ string_of_resulttype (label c x)); @@ -531,6 +545,43 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins " but label has " ^ string_of_resulttype (label c x)); (ts0 @ [RefT rt1]) --> (ts0 @ [RefT rt2]), [] + | BrOnCastDesc (x, rt1, rt2) -> + check_reftype c rt1 e.at; + check_reftype c rt2 e.at; + let (_, ht1), (_, ht2) = rt1, rt2 in + require + (top_of_heaptype c.types ht1 = top_of_heaptype c.types ht2) e.at + ("type mismatch on cast: type " ^ string_of_heaptype ht1 ^ + " has a different top type than type " ^ string_of_heaptype ht2); + require (label c x <> []) e.at + ("type mismatch: instruction requires type " ^ string_of_reftype rt2 ^ + " but label has " ^ string_of_resulttype (label c x)); + let ts0, t1 = Lib.List.split_last (label c x) in + require (match_valtype c.types (RefT rt2) t1) e.at + ("type mismatch: instruction requires type " ^ string_of_reftype rt2 ^ + " but label has " ^ string_of_resulttype (label c x)); + let rt = desc_cast_ref c rt2 e.at in + (ts0 @ [RefT rt1; RefT rt]) --> (ts0 @ [RefT (diff_reftype rt1 rt2)]), [] + + | BrOnCastDescFail (x, rt1, rt2) -> + check_reftype c rt1 e.at; + check_reftype c rt2 e.at; + let rt1' = diff_reftype rt1 rt2 in + let (_, ht1), (_, ht2) = rt1, rt2 in + require + (top_of_heaptype c.types ht1 = top_of_heaptype c.types ht2) e.at + ("type mismatch on cast: type " ^ string_of_heaptype ht1 ^ + " has a different top type than type " ^ string_of_heaptype ht2); + require (label c x <> []) e.at + ("type mismatch: instruction requires type " ^ string_of_reftype rt1' ^ + " but label has " ^ string_of_resulttype (label c x)); + let ts0, t1 = Lib.List.split_last (label c x) in + require (match_valtype c.types (RefT rt1') t1) e.at + ("type mismatch: instruction requires type " ^ string_of_reftype rt1' ^ + " but label has " ^ string_of_resulttype (label c x)); + let rt = desc_cast_ref c rt2 e.at in + (ts0 @ [RefT rt1; RefT rt]) --> (ts0 @ [RefT rt2]), [] + | Return -> c.results -->... [], [] @@ -540,7 +591,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins | CallRef x -> let (ts1, ts2) = func_type c x in - (ts1 @ [RefT (Null, UseHT (Def (type_ c x)))]) --> ts2, [] + (ts1 @ [RefT (Null, UseHT (Inexact, Def (type_ c x)))]) --> ts2, [] | CallIndirect (x, y) -> let TableT (at, _lim, t) = table c x in @@ -564,7 +615,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins ("type mismatch: current function requires result type " ^ string_of_resulttype c.results ^ " but callee returns " ^ string_of_resulttype ts2); - (ts1 @ [RefT (Null, UseHT (Def (type_ c x)))]) -->... [], [] + (ts1 @ [RefT (Null, UseHT (Inexact, Def (type_ c x)))]) -->... [], [] | ReturnCallIndirect (x, y) -> let TableT (at, _lim, t) = table c x in @@ -728,7 +779,8 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins | RefFunc x -> let dt = func c x in refer_func c x; - [] --> [RefT (NoNull, UseHT (Def dt))], [] + (* TODO: Exact function references *) + [] --> [RefT (NoNull, UseHT (Inexact, Def dt))], [] | RefIsNull -> let (_nul, ht) = peek_ref 0 s e.at in @@ -748,6 +800,25 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins check_reftype c rt e.at; [RefT (Null, top_of_heaptype c.types ht)] --> [RefT (nul, ht)], [] + | RefCastDesc rt -> + let (nul, ht) = rt in + check_reftype c rt e.at; + let rt' = desc_cast_ref c rt e.at in + [RefT (Null, top_of_heaptype c.types ht); RefT rt'] --> [RefT (nul, ht)], [] + + | RefGetDesc x -> + let DescT (_, ut, _) = expand_deftype_to_desctype (type_ c x) in + let dt = match ut with + | Some ut -> deftype_of_typeuse ut + | None -> error e.at ("type without descriptor " ^ I32.to_string_u x.it) + in + let (_, ht) = peek_ref 0 s e.at in + let exact = + if match_heaptype c.types ht (UseHT (Exact, Def (type_ c x))) + then Exact else Inexact + in + [RefT (Null, UseHT (exact, Def (type_ c x)))] --> [RefT (NoNull, UseHT (exact, Def dt))], [] + | RefEq -> [RefT (Null, EqHT); RefT (Null, EqHT)] --> [NumT I32T], [] @@ -764,7 +835,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins defaultable (unpacked_fieldtype ft)) fts ) x.at "field type is not defaultable"; let ts = if initop = Implicit then [] else List.map unpacked_fieldtype fts in - ts --> [RefT (NoNull, UseHT (Def (type_ c x)))], [] + ts --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] | StructGet (x, i, exto) -> let fts = struct_type c x in @@ -774,7 +845,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins require ((exto <> None) == is_packed_storagetype st) e.at ("field is " ^ (if exto = None then "packed" else "unpacked")); let t = unpacked_storagetype st in - [RefT (Null, UseHT (Def (type_ c x)))] --> [t], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x)))] --> [t], [] | StructSet (x, i) -> let fts = struct_type c x in @@ -783,7 +854,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins let FieldT (mut, st) = Lib.List32.nth fts i in require (mut == Var) e.at "field is immutable"; let t = unpacked_storagetype st in - [RefT (Null, UseHT (Def (type_ c x))); t] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); t] --> [], [] | ArrayNew (x, initop) -> let ft = array_type c x in @@ -791,12 +862,12 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins (initop = Explicit || defaultable (unpacked_fieldtype ft)) x.at "array type is not defaultable"; let ts = if initop = Implicit then [] else [unpacked_fieldtype ft] in - (ts @ [NumT I32T]) --> [RefT (NoNull, UseHT (Def (type_ c x)))], [] + (ts @ [NumT I32T]) --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] | ArrayNewFixed (x, n) -> let ft = array_type c x in let ts = Lib.List32.make n (unpacked_fieldtype ft) in - ts --> [RefT (NoNull, UseHT (Def (type_ c x)))], [] + ts --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] | ArrayNewElem (x, y) -> let ft = array_type c x in @@ -804,7 +875,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins require (match_valtype c.types (RefT rt) (unpacked_fieldtype ft)) x.at ("type mismatch: element segment's type " ^ string_of_reftype rt ^ " does not match array's field type " ^ string_of_fieldtype ft); - [NumT I32T; NumT I32T] --> [RefT (NoNull, UseHT (Def (type_ c x)))], [] + [NumT I32T; NumT I32T] --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] | ArrayNewData (x, y) -> let ft = array_type c x in @@ -812,20 +883,20 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins let t = unpacked_fieldtype ft in require (is_numtype t || is_vectype t) x.at "array type is not numeric or vector"; - [NumT I32T; NumT I32T] --> [RefT (NoNull, UseHT (Def (type_ c x)))], [] + [NumT I32T; NumT I32T] --> [RefT (NoNull, UseHT (Exact, Def (type_ c x)))], [] | ArrayGet (x, exto) -> let FieldT (_mut, st) = array_type c x in require ((exto <> None) == is_packed_storagetype st) e.at ("array is " ^ (if exto = None then "packed" else "unpacked")); let t = unpacked_storagetype st in - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T] --> [t], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T] --> [t], [] | ArraySet x -> let FieldT (mut, st) = array_type c x in require (mut == Var) e.at "array is immutable"; let t = unpacked_storagetype st in - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T; t] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T; t] --> [], [] | ArrayLen -> [RefT (Null, ArrayHT)] --> [NumT I32T], [] @@ -835,13 +906,13 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins let FieldT (_muts, sts) = array_type c y in require (mutd = Var) e.at "array is immutable"; require (match_storagetype c.types sts std) e.at "array types do not match"; - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T; RefT (Null, UseHT (Def (type_ c y))); NumT I32T; NumT I32T] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T; RefT (Null, UseHT (Inexact, Def (type_ c y))); NumT I32T; NumT I32T] --> [], [] | ArrayFill x -> let FieldT (mut, st) = array_type c x in require (mut = Var) e.at "array is immutable"; let t = unpacked_storagetype st in - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T; t; NumT I32T] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T; t; NumT I32T] --> [], [] | ArrayInitData (x, y) -> let FieldT (mut, st) = array_type c x in @@ -850,7 +921,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins let t = unpacked_storagetype st in require (is_numtype t || is_vectype t) x.at "array type is not numeric or vector"; - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T; NumT I32T; NumT I32T] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T; NumT I32T; NumT I32T] --> [], [] | ArrayInitElem (x, y) -> let FieldT (mut, st) = array_type c x in @@ -859,7 +930,7 @@ let rec check_instr (c : context) (e : instr) (s : infer_resulttype) : infer_ins require (match_valtype c.types (RefT rt) (unpacked_storagetype st)) x.at ("type mismatch: element segment's type " ^ string_of_reftype rt ^ " does not match array's field type " ^ string_of_fieldtype (FieldT (mut, st))); - [RefT (Null, UseHT (Def (type_ c x))); NumT I32T; NumT I32T; NumT I32T] --> [], [] + [RefT (Null, UseHT (Inexact, Def (type_ c x))); NumT I32T; NumT I32T; NumT I32T] --> [], [] | ExternConvert op -> let ht1, ht2 = type_externop op in diff --git a/test/core/custom-descriptors/array_new_exact.wast b/test/core/custom-descriptors/array_new_exact.wast new file mode 100644 index 000000000..af9f21925 --- /dev/null +++ b/test/core/custom-descriptors/array_new_exact.wast @@ -0,0 +1,24 @@ +(module + (type $a1 (array i8)) + (type $a2 (array (mut (ref null func)))) + + (data "abc") + (elem funcref) + + + (func (result (ref (exact $a1))) + (array.new $a1 (i32.const 0) (i32.const 0)) + ) + (func (result (ref (exact $a1))) + (array.new_default $a1 (i32.const 0)) + ) + (func (result (ref (exact $a1))) + (array.new_fixed $a1 3 (i32.const 0) (i32.const 1) (i32.const 2)) + ) + (func (result (ref (exact $a1))) + (array.new_data $a1 0 (i32.const 0) (i32.const 0)) + ) + (func (result (ref (exact $a2))) + (array.new_elem $a2 0 (i32.const 0) (i32.const 0)) + ) +) diff --git a/test/core/custom-descriptors/br_on_cast_desc.wast b/test/core/custom-descriptors/br_on_cast_desc.wast new file mode 100644 index 000000000..e5853f68d --- /dev/null +++ b/test/core/custom-descriptors/br_on_cast_desc.wast @@ -0,0 +1,1114 @@ +;; Validation + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + + ;; All nullness combinations + (func (param (ref null any) (ref null $b)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null $b)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $b)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $b)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $b)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $b)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $b)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $b)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; All nullness combinations with subtype descriptor + (func (param (ref null any) (ref null $d)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null $d)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $d)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $d)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $d)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $d)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $d)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $d)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; All nullness combinations with exact subtype descriptor + (func (param (ref null any) (ref null (exact $d))) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $d))) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $d))) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $d))) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; All nullness combinations with exact casts. + (func (param (ref null any) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $b))) (result (ref (exact $a))) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref (exact $a))) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $b))) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $b))) (result (ref (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Unreachable descriptor + (func (param (ref null any)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref (exact $a))) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + + ;; Null descriptor + (func (param (ref null any)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref $a)) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref (exact $a))) + (block (result (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref null (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref any) (ref (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) +) + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (descriptor $e) (struct))) + (type $e (describes $d) (struct)) + ) + + ;; Cast to self + (func (param (ref null $a) (ref null $b)) (result (ref null $a)) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null $a) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $a) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null $a) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to unrelated type + (func (param (ref null i31) (ref null $b)) (result (ref null $a)) + (block (result (ref i31)) + (br_on_cast_desc 1 (ref null i31) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null i31) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref i31)) + (br_on_cast_desc 1 (ref null i31) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from defined type to unrelated type + (func (param (ref null $e) (ref null $b)) (result (ref null $a)) + (block (result (ref $e)) + (br_on_cast_desc 1 (ref null $e) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $e) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref $e)) + (br_on_cast_desc 1 (ref null $e) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact defined type to unrelated type + (func (param (ref null (exact $e)) (ref null $b)) (result (ref null $a)) + (block (result (ref (exact $e))) + (br_on_cast_desc 1 (ref null (exact $e)) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $e)) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref (exact $e))) + (br_on_cast_desc 1 (ref null (exact $e)) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to supertype + (func (param (ref null $c) (ref null $b)) (result (ref null $a)) + (block (result (ref $c)) + (br_on_cast_desc 1 (ref null $c) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null $c) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref $c)) + (br_on_cast_desc 1 (ref null $c) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact to supertype + (func (param (ref null (exact $c)) (ref null $b)) (result (ref null $a)) + (block (result (ref (exact $c))) + (br_on_cast_desc 1 (ref null (exact $c)) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null (exact $c)) (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref (exact $c))) + (br_on_cast_desc 1 (ref null (exact $c)) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to subtype + (func (param (ref null $a) (ref null $d)) (result (ref null $c)) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null $a) (ref null $c) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $a) (ref null (exact $d))) (result (ref null (exact $c))) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null $a) (ref null (exact $c)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact to subtype + (func (param (ref null (exact $a)) (ref null $d)) (result (ref null $c)) + (block (result (ref (exact $a))) + (br_on_cast_desc 1 (ref null (exact $a)) (ref null $c) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $a)) (ref null (exact $d))) (result (ref null (exact $c))) + (block (result (ref (exact $a))) + (br_on_cast_desc 1 (ref null (exact $a)) (ref null (exact $c)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from null + (func (param (ref null $b)) (result (ref null $a)) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null none) (ref null $a) + (ref.null none) + (local.get 0) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref $a)) + (br_on_cast_desc 1 (ref null none) (ref null (exact $a)) + (ref.null none) + (local.get 0) + ) + ) + (unreachable) + ) + + ;; Cast from unreachable + (func (param (ref null $b)) (result (ref null $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (unreachable) + (local.get 0) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $b))) (result (ref null (exact $a))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $a)) + (unreachable) + (local.get 0) + ) + ) + (unreachable) + ) + + ;; Cast to descriptor type + (func (param (ref null any) (ref null $e)) (result (ref null $d)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $d) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $e))) (result (ref null (exact $d))) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null (exact $d)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) +) + +(assert_invalid + (module + ;; Type must exist. + (func (result anyref) + (br_on_cast_desc 0 anyref (ref 1) + (unreachable) + ) + ) + ) + "unknown type" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc 0 anyref anyref + (unreachable) + ) + ) + ) + "type any does not have a descriptor" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc 0 anyref nullref + (unreachable) + ) + ) + ) + "type none does not have a descriptor" +) + +(assert_invalid + (module + (type $a (struct)) + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc 0 anyref (ref $a) + (unreachable) + ) + ) + ) + "type 0 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast to descriptor without its own descriptor. + (func (result anyref) + (br_on_cast_desc 0 anyref (ref $b) (unreachable)) + ) + ) + "type 1 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must have expected type. + (func (param (ref null any) (ref null struct)) (result (ref null any)) + (br_on_cast_desc 0 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact. + (func (param (ref null any) (ref $b)) (result (ref null any)) + (br_on_cast_desc 0 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact, even if the descriptor is null. + (func (param (ref null any)) (result (ref null any)) + (br_on_cast_desc 0 (ref null any) (ref (exact $a)) + (local.get 0) + (ref.null $b) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; An exact reference to a subtype of the descriptor does not cut it. + (func (param (ref null any) (ref (exact $d))) (result (ref null any)) + (br_on_cast_desc 0 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast across hierarchies. + (func (param (ref null func) (ref $b)) (result (ref null any)) + (br_on_cast_desc 0 (ref null func) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast across hierarchies even with unreachable input. + (func (result (ref null any)) + (br_on_cast_desc 0 (ref null func) (ref $a) + (unreachable) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Ouput type is determined by immediate, not actual input. + (func (param (ref $c) (ref $d)) (result (ref null $c)) + (br_on_cast_desc 0 (ref $c) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but with an exact reference to the descriptor subtype. + (func (param (ref $c) (ref (exact $d))) (result (ref null $c)) + (br_on_cast_desc 0 (ref $c) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are both null. + (func (result (ref null $c)) + (br_on_cast_desc 0 (ref null none) (ref $a) + (ref.null none) + (ref.null none) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are bottom. + (func (result (ref null $c)) + (br_on_cast_desc 0 (ref none) (ref $a) + (unreachable) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Fallthough type should be nullable. + (func (param (ref null any) (ref null $b)) (result (ref $a)) + (block (result (ref any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Invalid in constant expression. + (global (ref $a) (br_on_cast_desc 0 (ref null any) (ref null $a) (ref.null none) (ref.null none))) + ) + "constant expression required" +) + +;; Sent values + +(module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + + ;; One extra value. + (func (param (ref null any) (ref null $b)) (result i32 (ref null $a)) + (block (result i32 (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (i32.const 42) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Two extra values. + (func (param (ref null any) (ref null $b)) (result i32 i64 (ref null $a)) + (block (result i32 i64 (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (i32.const 42) + (i64.const 1337) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Extra reference value. + (func (param (ref null any) (ref null $b)) (result (ref null eq) (ref null $a)) + (block (result (ref null any) (ref any)) + (br_on_cast_desc 1 (ref null any) (ref null $a) + (local.get 1) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; No types at label. + (func + (br_on_cast_desc 0 (ref null any) (ref $a) + (unreachable) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Too many types at label. + (func (param (ref null any) (ref null $b)) (result i32 (ref $a)) + (br_on_cast_desc 0 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Mismatched types at label. + (func (param (ref null any) (ref null $b)) (result (ref null eq) (ref $a)) + (br_on_cast_desc 0 (ref null any) (ref $a) + (local.get 0) + (local.get 0) + (local.get 1) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; No types at fallthrough. + (func (result (ref $a)) + (block + (br_on_cast_desc 1 (ref null any) (ref $a) + (unreachable) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Too many types at fallthrough. + (func (result (ref $a)) + (block (result i32 (ref $a)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (unreachable) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Label types do not match fallthrough types. + (func (result (ref null any) (ref $a)) + (block (result (ref null eq) (ref null any)) + (br_on_cast_desc 1 (ref null any) (ref $a) + (unreachable) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +;; TODO: execution diff --git a/test/core/custom-descriptors/br_on_cast_desc_fail.wast b/test/core/custom-descriptors/br_on_cast_desc_fail.wast new file mode 100644 index 000000000..977cce8bf --- /dev/null +++ b/test/core/custom-descriptors/br_on_cast_desc_fail.wast @@ -0,0 +1,1100 @@ +;; Validation + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + + ;; All nullness combinations + (func (param (ref null any) (ref null $b)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null $b)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null any) (ref $b)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $b)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref null $b)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $b)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref $b)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $b)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + + ;; All nullness combinations with subtype descriptor + (func (param (ref null any) (ref null $d)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null $d)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null any) (ref $d)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref $d)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref null $d)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null $d)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref $d)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref $d)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + + ;; All nullness combinations with exact subtype descriptor + (func (param (ref null any) (ref null (exact $d))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $d))) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref (exact $d))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $d))) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + + ;; All nullness combinations with exact casts. + (func (param (ref null any) (ref null (exact $b))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $b))) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + (func (param (ref any) (ref (exact $b))) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref any) (ref (exact $b))) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + + ;; Unreachable descriptor + (func (param (ref null any)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (unreachable) + ) + ) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (unreachable) + ) + ) + ) + (func (param (ref null any)) (result (ref any)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null any)) + (block (result (ref (exact $a))) + (br_on_cast_desc_fail 1 (ref null any) (ref (exact $a)) + (local.get 0) + (unreachable) + ) + ) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref any) (ref null (exact $a)) + (local.get 0) + (unreachable) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref (exact $a))) + (br_on_cast_desc_fail 1 (ref any) (ref (exact $a)) + (local.get 0) + (unreachable) + ) + ) + ) + + ;; Null descriptor + (func (param (ref null any)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (ref.null none) + ) + ) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref any) (ref null $a) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref any) (ref $a) + (local.get 0) + (ref.null none) + ) + ) + ) + (func (param (ref null any)) (result (ref any)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref null any)) (result (ref null any)) + (block (result (ref (exact $a))) + (br_on_cast_desc_fail 1 (ref null any) (ref (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref any) (ref null (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + (unreachable) + ) + (func (param (ref any)) (result (ref any)) + (block (result (ref (exact $a))) + (br_on_cast_desc_fail 1 (ref any) (ref (exact $a)) + (local.get 0) + (ref.null none) + ) + ) + ) +) + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (descriptor $e) (struct))) + (type $e (describes $d) (struct)) + ) + + ;; Cast to self + (func (param (ref null $a) (ref null $b)) (result (ref $a)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null $a) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $a) (ref null (exact $b))) (result (ref $a)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null $a) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to unrelated type + (func (param (ref null i31) (ref null $b)) (result (ref i31)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null i31) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null i31) (ref null (exact $b))) (result (ref i31)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null i31) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from defined type to unrelated type + (func (param (ref null $e) (ref null $b)) (result (ref $e)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null $e) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $e) (ref null (exact $b))) (result (ref $e)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null $e) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact defined type to unrelated type + (func (param (ref null (exact $e)) (ref null $b)) (result (ref (exact $e))) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null (exact $e)) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $e)) (ref null (exact $b))) (result (ref (exact $e))) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null (exact $e)) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to supertype + (func (param (ref null $c) (ref null $b)) (result (ref $c)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null $c) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $c) (ref null (exact $b))) (result (ref $c)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null $c) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact to supertype + (func (param (ref null (exact $c)) (ref null $b)) (result (ref $c)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null (exact $c)) (ref null $a) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $c)) (ref null (exact $b))) (result (ref $c)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null (exact $c)) (ref null (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast to subtype + (func (param (ref null $a) (ref null $d)) (result (ref $a)) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref null $a) (ref null $c) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null $a) (ref null (exact $d))) (result (ref $a)) + (block (result (ref null (exact $c))) + (br_on_cast_desc_fail 1 (ref null $a) (ref null (exact $c)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from exact to subtype + (func (param (ref null (exact $a)) (ref null $d)) (result (ref (exact $a))) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref null (exact $a)) (ref null $c) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $a)) (ref null (exact $d))) (result (ref (exact $a))) + (block (result (ref null (exact $c))) + (br_on_cast_desc_fail 1 (ref null (exact $a)) (ref null (exact $c)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Cast from null + (func (param (ref null $b)) (result (ref $a)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null none) (ref null $a) + (ref.null none) + (local.get 0) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $b))) (result (ref $a)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null none) (ref null (exact $a)) + (ref.null none) + (local.get 0) + ) + ) + (unreachable) + ) + + ;; Cast from unreachable + (func (param (ref null $b)) (result (ref any)) + (block (result (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (unreachable) + (local.get 0) + ) + ) + (unreachable) + ) + (func (param (ref null (exact $b))) (result (ref any)) + (block (result (ref null (exact $a))) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $a)) + (unreachable) + (local.get 0) + ) + ) + (unreachable) + ) + + ;; Cast to descriptor type + (func (param (ref null any) (ref null $e)) (result (ref any)) + (block (result (ref null $d)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $d) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + (func (param (ref null any) (ref null (exact $e))) (result (ref any)) + (block (result (ref null (exact $d))) + (br_on_cast_desc_fail 1 (ref null any) (ref null (exact $d)) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) +) + +(assert_invalid + (module + ;; Type must exist. + (func (result anyref) + (br_on_cast_desc_fail 0 anyref (ref 1) + (unreachable) + ) + ) + ) + "unknown type" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc_fail 0 anyref anyref + (unreachable) + ) + ) + ) + "type any does not have a descriptor" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc_fail 0 anyref nullref + (unreachable) + ) + ) + ) + "type none does not have a descriptor" +) + +(assert_invalid + (module + (type $a (struct)) + ;; Type must have a descriptor. + (func (result anyref) + (br_on_cast_desc_fail 0 anyref (ref $a) + (unreachable) + ) + ) + ) + "type 0 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast to descriptor without its own descriptor. + (func (result anyref) + (br_on_cast_desc_fail 0 anyref (ref $b) (unreachable)) + ) + ) + "type 1 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must have expected type. + (func (param (ref null any) (ref null struct)) (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact. + (func (param (ref null any) (ref $b)) (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact, even if the descriptor is null. + (func (param (ref null any)) (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref (exact $a)) + (local.get 0) + (ref.null $b) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; An exact reference to a subtype of the descriptor does not cut it. + (func (param (ref null any) (ref (exact $d))) (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref (exact $a)) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast across hierarchies. + (func (param (ref null func) (ref $b)) (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null func) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast across hierarchies even with unreachable input. + (func (result (ref null any)) + (br_on_cast_desc_fail 0 (ref null func) (ref $a) + (unreachable) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Ouput type is determined by immediate, not actual input. + (func (param (ref $c) (ref $d)) (result (ref null any)) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref $c) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but with an exact reference to the descriptor subtype. + (func (param (ref $c) (ref (exact $d))) (result (ref null any)) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref $c) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are both null. + (func (result (ref null any)) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref null none) (ref $a) + (ref.null none) + (ref.null none) + ) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are bottom. + (func (result (ref null any)) + (block (result (ref null $c)) + (br_on_cast_desc_fail 1 (ref none) (ref $a) + (unreachable) + ) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Branch type should be nullable. + (func (param (ref null any) (ref null $b)) (result (ref any)) + (block (result (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + ) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Invalid in constant expression. + (global (ref $a) (br_on_cast_desc_fail 0 (ref null any) (ref null $a) (ref.null none) (ref.null none))) + ) + "constant expression required" +) + +;; Sent values + +(module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + + ;; One extra value. + (func (param (ref null any) (ref null $b)) (result i32 (ref any)) + (block (result i32 (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (i32.const 42) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Two extra values. + (func (param (ref null any) (ref null $b)) (result i32 i64 (ref any)) + (block (result i32 i64 (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (i32.const 42) + (i64.const 1337) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) + + ;; Extra reference value. + (func (param (ref null any) (ref null $b)) (result (ref null eq) (ref any)) + (block (result (ref null any) (ref null $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref null $a) + (local.get 1) + (local.get 0) + (local.get 1) + ) + ) + (unreachable) + ) +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; No types at label. + (func + (br_on_cast_desc_fail 0 (ref null any) (ref $a) + (unreachable) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Too many types at label. + (func (param (ref null any) (ref null $b)) (result i32 (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref $a) + (local.get 0) + (local.get 1) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Mismatched types at label. + (func (param (ref null any) (ref null $b)) (result (ref null eq) (ref null any)) + (br_on_cast_desc_fail 0 (ref null any) (ref $a) + (local.get 0) + (local.get 0) + (local.get 1) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; No types at fallthrough. + (func (result (ref null any)) + (block + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (unreachable) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Too many types at fallthrough. + (func (result (ref null any)) + (block (result i32 (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (ref.null none) + (ref.null none) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Label types do not match fallthrough types. + (func (result (ref null any) (ref null any)) + (block (result (ref null eq) (ref $a)) + (br_on_cast_desc_fail 1 (ref null any) (ref $a) + (unreachable) + ) + ) + (unreachable) + ) + ) + "type mismatch" +) + +;; TODO: execution diff --git a/test/core/custom-descriptors/ref_cast_desc.wast b/test/core/custom-descriptors/ref_cast_desc.wast new file mode 100644 index 000000000..b4c4edd0e --- /dev/null +++ b/test/core/custom-descriptors/ref_cast_desc.wast @@ -0,0 +1,485 @@ +;; Validation + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + + ;; All nullness combinations + (func (param (ref null any) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref null $b)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref $b)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null $b)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref $b)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + + ;; All nullness combinations with subtype descriptors + (func (param (ref null any) (ref null $d)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref null $d)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref $d)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref $d)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null $d)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null $d)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref $d)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref $d)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + + ;; All nullness combinations with exact subtype descriptors + (func (param (ref null any) (ref null (exact $d))) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref null (exact $d))) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref (exact $d))) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null (exact $d))) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref (exact $d))) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref (exact $d))) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + + ;; All nullness combinations with exact casts + (func (param (ref null any) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref null (exact $b))) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref (exact $b))) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref null (exact $b))) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + (func (param (ref any) (ref (exact $b))) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Unreachable descriptor + (func (param (ref null any)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (unreachable)) + ) + (func (param (ref null any)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (unreachable)) + ) + (func (param (ref any)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (unreachable)) + ) + (func (param (ref any)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (unreachable)) + ) + (func (param (ref null any)) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (unreachable)) + ) + (func (param (ref null any)) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (unreachable)) + ) + (func (param (ref any)) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (unreachable)) + ) + (func (param (ref any)) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (unreachable)) + ) + + ;; Null descriptor + (func (param (ref null any)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (ref.null none)) + ) + (func (param (ref null any)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (ref.null none)) + ) + (func (param (ref any)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (ref.null none)) + ) + (func (param (ref any)) (result (ref $a)) + (ref.cast_desc (ref $a) (local.get 0) (ref.null none)) + ) + (func (param (ref null any)) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (ref.null none)) + ) + (func (param (ref null any)) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (ref.null none)) + ) + (func (param (ref any)) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (ref.null none)) + ) + (func (param (ref any)) (result (ref (exact $a))) + (ref.cast_desc (ref (exact $a)) (local.get 0) (ref.null none)) + ) +) + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (descriptor $e) (struct))) + (type $e (describes $d) (struct)) + ) + + ;; Cast to self + (func (param (ref null $a) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null $a) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast to unrelated type + (func (param (ref null i31) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null i31) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast from defined type to unrelated type + (func (param (ref null $e) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null $e) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast from exact defined type to unrelated type + (func (param (ref null (exact $e)) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null (exact $e)) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast to supertype + (func (param (ref null $c) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null $c) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast from exact to supertype + (func (param (ref null (exact $c)) (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (local.get 0) (local.get 1)) + ) + (func (param (ref null (exact $c)) (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (local.get 0) (local.get 1)) + ) + + ;; Cast to subtype + (func (param (ref null $a) (ref null $d)) (result (ref null $c)) + (ref.cast_desc (ref null $c) (local.get 0) (local.get 1)) + ) + (func (param (ref null $a) (ref null (exact $d))) (result (ref null (exact $c))) + (ref.cast_desc (ref null (exact $c)) (local.get 0) (local.get 1)) + ) + + ;; Cast from exact to subtype + (func (param (ref null (exact $a)) (ref null $d)) (result (ref null $c)) + (ref.cast_desc (ref null $c) (local.get 0) (local.get 1)) + ) + (func (param (ref null (exact $a)) (ref null (exact $d))) (result (ref null (exact $c))) + (ref.cast_desc (ref null (exact $c)) (local.get 0) (local.get 1)) + ) + + ;; Cast from null + (func (param (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (ref.null none) (local.get 0)) + ) + (func (param (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (ref.null none) (local.get 0)) + ) + + ;; Cast from unreachable + (func (param (ref null $b)) (result (ref null $a)) + (ref.cast_desc (ref null $a) (unreachable) (local.get 0)) + ) + (func (param (ref null (exact $b))) (result (ref null (exact $a))) + (ref.cast_desc (ref null (exact $a)) (unreachable) (local.get 0)) + ) + + ;; Cast to descriptor type + (func (param (ref null any) (ref null $e)) (result (ref null $d)) + (ref.cast_desc (ref null $d) (local.get 0) (local.get 1)) + ) + (func (param (ref null any) (ref null (exact $e))) (result (ref null (exact $d))) + (ref.cast_desc (ref null (exact $d)) (local.get 0) (local.get 1)) + ) +) + +(assert_invalid + (module + ;; Type must exist. + (func (result anyref) + (ref.cast_desc (ref 1) (unreachable)) + ) + ) + "unknown type" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result anyref) + (ref.cast_desc (ref any) (unreachable)) + ) + ) + "type any does not have a descriptor" +) + +(assert_invalid + (module + ;; Type must have a descriptor. + (func (result nullref) + (ref.cast_desc (ref null none) (unreachable)) + ) + ) + "type none does not have a descriptor" +) + +(assert_invalid + (module + (type $a (struct)) + ;; Type must have a descriptor. + (func (result anyref) + (ref.cast_desc (ref $a) (unreachable)) + ) + ) + "type 0 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast to descriptor without its own descriptor. + (func (result anyref) + (ref.cast_desc (ref $b) (unreachable)) + ) + ) + "type 1 does not have a descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must have expected type. + (func (param (ref null any) (ref null struct)) (result (ref null any)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact. + (func (param (ref null any) (ref $b)) (result (ref null any)) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Descriptor must be exact when cast is exact, even if the descriptor is null. + (func (param (ref null any)) (result (ref null any)) + (ref.cast_desc (ref (exact $a)) (local.get 0) (ref.null $b)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; An exact reference to a subtype of the descriptor does not cut it. + (func (param (ref null any) (ref (exact $d))) (result (ref null any)) + (ref.cast_desc (ref (exact $a)) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Cannot cast across hierarchies. + (func (param (ref null func) (ref $b)) (result (ref null any)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Ouput type is determined by immediate, not actual input. + (func (param (ref $c) (ref $d)) (result (ref null $c)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but with an exact reference to the descriptor subtype. + (func (param (ref $c) (ref (exact $d))) (result (ref null $c)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but with an exact reference to the expected descriptor type. + (func (param (ref $c) (ref (exact $b))) (result (ref null $c)) + (ref.cast_desc (ref $a) (local.get 0) (local.get 1)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are both null. + (func (result (ref null $c)) + (ref.cast_desc (ref $a) (ref.null none) (ref.null none)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same, but now the cast value and descriptor are bottom. + (func (result (ref null $c)) + (ref.cast_desc (ref $a) (unreachable)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Invalid in constant expression. + (global (ref $a) (ref.cast_desc (ref null $a) (ref.null none) (ref.null none))) + ) + "constant expression required" +) + +;; TODO: Execution diff --git a/test/core/custom-descriptors/ref_get_desc.wast b/test/core/custom-descriptors/ref_get_desc.wast new file mode 100644 index 000000000..8d6faa847 --- /dev/null +++ b/test/core/custom-descriptors/ref_get_desc.wast @@ -0,0 +1,291 @@ +;; Validation + +(module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + + (func (param (ref $a)) (result (ref $b)) + (ref.get_desc $a (local.get 0)) + ) + (func (param (ref null $a)) (result (ref $b)) + (ref.get_desc $a (local.get 0)) + ) + (func (param (ref (exact $a))) (result (ref (exact $b))) + (ref.get_desc $a (local.get 0)) + ) + (func (param (ref null (exact $a))) (result (ref (exact $b))) + (ref.get_desc $a (local.get 0)) + ) + + (func (result (ref (exact $b))) + (ref.get_desc $a (unreachable)) + ) + (func (result (ref (exact $b))) + (ref.get_desc $a (ref.null none)) + ) + (func (result (ref (exact $b))) + (ref.get_desc $a (ref.null (exact $a))) + ) + (func (result (ref $b)) + (ref.get_desc $a (ref.null $a)) + ) +) + +;; Same, but now get a descriptor of a descriptor. +(module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (descriptor $c) (struct)) + (type $c (describes $b) (struct)) + ) + + (func (param (ref $b)) (result (ref $c)) + (ref.get_desc $b (local.get 0)) + ) + (func (param (ref null $b)) (result (ref $c)) + (ref.get_desc $b (local.get 0)) + ) + (func (param (ref (exact $b))) (result (ref (exact $c))) + (ref.get_desc $b (local.get 0)) + ) + (func (param (ref null (exact $b))) (result (ref (exact $c))) + (ref.get_desc $b (local.get 0)) + ) + + (func (result (ref (exact $c))) + (ref.get_desc $b (unreachable)) + ) + (func (result (ref (exact $c))) + (ref.get_desc $b (ref.null none)) + ) + (func (result (ref (exact $c))) + (ref.get_desc $b (ref.null (exact $b))) + ) + (func (result (ref $c)) + (ref.get_desc $b (ref.null $b)) + ) +) + +(assert_invalid + (module + ;; Type must exist. + (func (result anyref) + (ref.get_desc 1 (unreachable)) + ) + ) + "unknown type" +) + +(assert_invalid + (module + ;; Cannot get the described type from a type that does not have one. + (type $a (struct)) + (func (param (ref $a)) (result anyref) + (ref.get_desc $a (local.get 0)) + ) + ) + "type without descriptor" +) + +(assert_invalid + (module + ;; Same, but now the type is a function type. + (type $a (func)) + (func (param (ref $a)) (result anyref) + (ref.get_desc $a (local.get 0)) + ) + ) + "type without descriptor" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + ) + ;; Cannot get the described type from the descriptor. + (func (param (ref $b)) (result (ref $a)) + (ref.get_desc $b (local.get 0)) + ) + ) + "type without descriptor" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Operand must have expected type. + (func (param (ref any)) (result (ref $b)) + (ref.get_desc $a (local.get 0)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Only exact inputs produce exact outputs. + (func (param (ref $a)) (result (ref (exact $b))) + (ref.get_desc $a (local.get 0)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Only exact inputs produce exact outputs, even for nulls. + (func (result (ref (exact $b))) + (ref.get_desc $a (ref.null $a)) + ) + ) + "type mismatch" +) + +(module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Subtyping works. + (func (param (ref (exact $c))) (result (ref $b)) + (ref.get_desc $a (local.get 0)) + ) + (func (param (ref $c)) (result (ref $b)) + (ref.get_desc $a (local.get 0)) + ) +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Only exact inputs of the inspected type produce exact outputs. + (func (param (ref (exact $c))) (result (ref (exact $b))) + (ref.get_desc $a (local.get 0)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same as above, but with a null. + (func (result (ref (exact $b))) + (ref.get_desc $a (ref.null (exact $c))) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; The output describes the expected input, not the actual input. + (func (param (ref (exact $c))) (result (ref $d)) + (ref.get_desc $a (local.get 0)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (sub (descriptor $b) (struct))) + (type $b (sub (describes $a) (struct))) + (type $c (sub $a (descriptor $d) (struct))) + (type $d (sub $b (describes $c) (struct))) + ) + ;; Same as above, but now the input is not exact. + (func (param (ref $c)) (result (ref $d)) + (ref.get_desc $a (local.get 0)) + ) + ) + "type mismatch" +) + +(assert_invalid + (module + (rec + (type $a (descriptor $b) (struct)) + (type $b (describes $a) (struct)) + ) + ;; Invalid in constant expression. + (global (ref $b) (ref.get_desc $a (ref.null none))) + ) + "constant expression required" +) + +;; Binary format + +(module binary + "\00asm" "\01\00\00\00" + "\01" ;; Type section id + "\12" ;; Type section length + "\02" ;; Types vector length + "\4e" ;; Recursion group + "\02" ;; Rec group size + "\4d" ;; Descriptor + "\01" ;; Descriptor type index + "\5f" ;; Struct + "\00" ;; Number of fields + "\4c" ;; Describes + "\00" ;; Describes type index + "\5f" ;; Struct + "\00" ;; Number of fields + "\60" ;; Func + "\01" ;; Number of params + "\63" ;; Ref null + "\00" ;; Type index + "\01" ;; Number of results + "\64" ;; Ref + "\01" ;; Type index + "\03" ;; Function section id + "\02" ;; Function section length + "\01" ;; Functions vector length + "\02" ;; Type index + "\0a" ;; Code section id + "\09" ;; Code section length + "\01" ;; Code vector length + "\07" ;; Code length + "\00" ;; Number of locals + "\20" ;; local.get + "\00" ;; Local index + "\fb\22" ;; ref.get_desc + "\00" ;; Type index + "\0b" ;; end +) + +;; TODO: Execution diff --git a/test/core/gc/br_on_cast.wast b/test/core/gc/br_on_cast.wast index 3c895c071..f6b35b4f2 100644 --- a/test/core/gc/br_on_cast.wast +++ b/test/core/gc/br_on_cast.wast @@ -217,9 +217,19 @@ (func (param (ref null any)) (result (ref $t)) (block (result (ref null any)) (br_on_cast 1 (ref null any) (ref $t) (local.get 0))) (unreachable) ) + (func (param (ref any)) (result (ref null $t)) + (block (result (ref any)) (br_on_cast 1 (ref any) (ref null $t) (local.get 0))) (unreachable) + ) (func (param (ref null any)) (result (ref null $t)) (block (result (ref null any)) (br_on_cast 1 (ref null any) (ref null $t) (local.get 0))) (unreachable) ) + + (func (result anyref) + (br_on_cast 0 eqref anyref (unreachable)) + ) + (func (result anyref) + (br_on_cast 0 structref arrayref (unreachable)) + ) ) (assert_invalid @@ -231,15 +241,6 @@ ) "type mismatch" ) -(assert_invalid - (module - (type $t (struct)) - (func (param (ref any)) (result (ref null $t)) - (block (result (ref any)) (br_on_cast 1 (ref any) (ref null $t) (local.get 0))) (unreachable) - ) - ) - "type mismatch" -) (assert_invalid (module (type $t (struct)) @@ -251,16 +252,18 @@ ) (assert_invalid (module - (func (result anyref) - (br_on_cast 0 eqref anyref (unreachable)) + (func (param (ref null any)) (result (ref null func)) + (br_on_cast 0 (ref null any) (ref null func) (local.get 0)) + (unreachable) ) ) "type mismatch" ) (assert_invalid (module - (func (result anyref) - (br_on_cast 0 structref arrayref (unreachable)) + (func (param (ref func)) (result (ref any)) + (br_on_cast 0 (ref func) (ref any) (local.get 0)) + (unreachable) ) ) "type mismatch" diff --git a/test/core/gc/br_on_cast_fail.wast b/test/core/gc/br_on_cast_fail.wast index db6db11b0..905fa6fcd 100644 --- a/test/core/gc/br_on_cast_fail.wast +++ b/test/core/gc/br_on_cast_fail.wast @@ -232,25 +232,26 @@ (func (param (ref null any)) (result (ref null any)) (block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref $t) (local.get 0))) ) + (func (param (ref any)) (result (ref any)) + (block (result (ref null $t)) (br_on_cast_fail 1 (ref any) (ref null $t) (local.get 0))) (ref.as_non_null) + ) (func (param (ref null any)) (result (ref null any)) (block (result (ref null $t)) (br_on_cast_fail 1 (ref null any) (ref null $t) (local.get 0))) ) -) -(assert_invalid - (module - (type $t (struct)) - (func (param (ref any)) (result (ref any)) - (block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref null $t) (local.get 0))) - ) + (func (result anyref) + (br_on_cast_fail 0 eqref anyref (unreachable)) + ) + (func (result anyref) + (br_on_cast_fail 0 structref arrayref (unreachable)) ) - "type mismatch" ) + (assert_invalid (module (type $t (struct)) (func (param (ref any)) (result (ref any)) - (block (result (ref null $t)) (br_on_cast_fail 1 (ref any) (ref null $t) (local.get 0))) (ref.as_non_null) + (block (result (ref $t)) (br_on_cast_fail 1 (ref null any) (ref null $t) (local.get 0))) ) ) "type mismatch" @@ -266,16 +267,16 @@ ) (assert_invalid (module - (func (result anyref) - (br_on_cast_fail 0 eqref anyref (unreachable)) + (func (param (ref null any)) (result (ref null func)) + (block (result (ref null func)) (br_on_cast_fail 1 (ref null any) (ref null func) (local.get 0) (unreachable))) ) ) "type mismatch" ) (assert_invalid (module - (func (result anyref) - (br_on_cast_fail 0 structref arrayref (unreachable)) + (func (param (ref func)) (result (ref any)) + (block (result (ref any)) (br_on_cast_fail 1 (ref func) (ref any) (local.get 0) (unreachable))) ) ) "type mismatch"