如何理解Wasm递归类型及两段代码的差异与报错问题
WebAssembly GC:非rec包裹类型与rec包裹类型的差异及类型验证报错解析
一、两段基础代码的差异
WebAssembly GC规范中,rec块的核心作用是声明互递归/自递归的类型组——当一组类型之间存在互相引用(比如A引用B、B同时引用A),或者单个类型自引用时,必须用rec包裹,让这些类型处于同一个作用域中,解决引用顺序的问题。
第一段代码(无rec):
(module (type $f1 (func)) (type (struct (field (ref $f1)))) )这是顺序依赖声明:
$f1先定义,后面的struct类型仅引用已经存在的$f1,不存在反向引用或递归,完全符合规范的非递归类型声明规则,因此Binaryen可以正常编译。第二段代码(有rec):
(module (rec (type $f1 (func)) (type (struct (field (ref $f1)))) ) )这里用
rec包裹两个类型,虽然实际不存在互递归,但规范允许rec包裹非递归的类型组(只是没必要)——rec块内的所有类型会被视为同时定义、互相可见,因此这段代码同样合法,可正常编译。
二、报错代码的问题原因
报错的核心是引用类型不匹配,和rec本身的语法无关:
(module (type $f1 (func)) (type (struct (field (ref $f1)))) (rec (type $f2 (func)) (type (struct (field (ref $f2))))) (func $f (type $f2)) (global (ref $f1) (ref.func $f)) )
$f1和$f2是两个独立的函数类型定义:即使它们的结构完全相同(都是无参无返回的函数类型),在WebAssembly的类型系统中,它们是不同的名义类型,对应的ref $f1和ref $f2是两种不兼容的引用类型。func $f的类型是$f2,因此(ref.func $f)生成的值的类型是ref $f2,但全局变量声明的类型是ref $f1,类型不匹配,触发验证错误:global init must have correct type。
简言之,你试图把ref $f2类型的函数引用赋值给要求ref $f1类型的全局变量,二者类型不兼容导致报错。
内容的提问来源于stack exchange,提问作者Jason Yu
相关产品推荐
相关产品推荐

