use crate::ast::*;
use crate::resolve::Ns;
use crate::Error;
use std::collections::{HashMap, HashSet};
pub fn resolve<'a>(
id: Option<Id<'a>>,
fields: &mut Vec<ModuleField<'a>>,
) -> Result<Resolver<'a>, Error> {
let mut names = HashMap::new();
let mut parents = Parents {
prev: None,
cur_id: id,
depth: 0,
names: &mut names,
};
let mut resolver = Resolver::default();
resolver.process(&mut parents, fields)?;
Ok(resolver)
}
#[derive(Default)]
pub struct Resolver<'a> {
funcs: Namespace<'a>,
globals: Namespace<'a>,
tables: Namespace<'a>,
memories: Namespace<'a>,
types: Namespace<'a>,
events: Namespace<'a>,
modules: Namespace<'a>,
instances: Namespace<'a>,
datas: Namespace<'a>,
elems: Namespace<'a>,
fields: Namespace<'a>,
type_info: Vec<TypeInfo<'a>>,
implicit_instances: HashSet<&'a str>,
}
impl<'a> Resolver<'a> {
fn process(
&mut self,
parents: &mut Parents<'a, '_>,
fields: &mut Vec<ModuleField<'a>>,
) -> Result<(), Error> {
for field in fields.iter_mut() {
self.register(field)?;
}
for field in fields.iter_mut() {
self.resolve_field(field, parents)?;
}
Ok(())
}
fn register(&mut self, item: &ModuleField<'a>) -> Result<(), Error> {
match item {
ModuleField::Import(i) => {
if i.field.is_some() {
if self.implicit_instances.insert(i.module) {
self.instances.register(None, "instance")?;
}
}
match &i.item.kind {
ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?,
ItemKind::Memory(_) => self.memories.register(i.item.id, "memory")?,
ItemKind::Table(_) => self.tables.register(i.item.id, "table")?,
ItemKind::Global(_) => self.globals.register(i.item.id, "global")?,
ItemKind::Event(_) => self.events.register(i.item.id, "event")?,
ItemKind::Module(_) => self.modules.register(i.item.id, "module")?,
ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?,
}
}
ModuleField::Global(i) => self.globals.register(i.id, "global")?,
ModuleField::Memory(i) => self.memories.register(i.id, "memory")?,
ModuleField::Func(i) => self.funcs.register(i.id, "func")?,
ModuleField::Table(i) => self.tables.register(i.id, "table")?,
ModuleField::NestedModule(m) => self.modules.register(m.id, "module")?,
ModuleField::Instance(i) => self.instances.register(i.id, "instance")?,
ModuleField::Type(i) => {
match &i.def {
TypeDef::Struct(r#struct) => {
for (i, field) in r#struct.fields.iter().enumerate() {
if let Some(id) = field.id {
self.fields.register_specific(id, i as u32, "field")?;
}
}
}
TypeDef::Instance(_)
| TypeDef::Array(_)
| TypeDef::Func(_)
| TypeDef::Module(_) => {}
}
match &i.def {
TypeDef::Func(f) => {
let params = f.params.iter().map(|p| p.2).collect();
let results = f.results.clone();
self.type_info.push(TypeInfo::Func { params, results });
}
_ => self.type_info.push(TypeInfo::Other),
}
self.types.register(i.id, "type")?
}
ModuleField::Elem(e) => self.elems.register(e.id, "elem")?,
ModuleField::Data(d) => self.datas.register(d.id, "data")?,
ModuleField::Event(e) => self.events.register(e.id, "event")?,
ModuleField::Alias(a) => match a.kind {
ExportKind::Func => self.funcs.register(a.id, "func")?,
ExportKind::Table => self.tables.register(a.id, "table")?,
ExportKind::Memory => self.memories.register(a.id, "memory")?,
ExportKind::Global => self.globals.register(a.id, "global")?,
ExportKind::Instance => self.instances.register(a.id, "instance")?,
ExportKind::Module => self.modules.register(a.id, "module")?,
ExportKind::Event => self.events.register(a.id, "event")?,
ExportKind::Type => {
self.type_info.push(TypeInfo::Other);
self.types.register(a.id, "type")?
}
},
ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => {
return Ok(())
}
};
Ok(())
}
fn resolve_field(
&self,
field: &mut ModuleField<'a>,
parents: &mut Parents<'a, '_>,
) -> Result<(), Error> {
match field {
ModuleField::Import(i) => {
self.resolve_item_sig(&mut i.item)?;
Ok(())
}
ModuleField::Type(ty) => {
match &mut ty.def {
TypeDef::Func(func) => func.resolve(self)?,
TypeDef::Struct(struct_) => {
for field in &mut struct_.fields {
self.resolve_storagetype(&mut field.ty)?;
}
}
TypeDef::Array(array) => self.resolve_storagetype(&mut array.ty)?,
TypeDef::Module(m) => m.resolve(self)?,
TypeDef::Instance(i) => i.resolve(self)?,
}
Ok(())
}
ModuleField::Func(f) => {
let (idx, inline) = self.resolve_type_use(&mut f.ty)?;
let n = match idx {
Index::Num(n, _) => *n,
Index::Id(_) => panic!("expected `Num`"),
};
if let FuncKind::Inline { locals, expression } = &mut f.kind {
for local in locals.iter_mut() {
self.resolve_valtype(&mut local.ty)?;
}
let mut scope = Namespace::default();
if let Some(inline) = &inline {
for (id, _, _) in inline.params.iter() {
scope.register(*id, "local")?;
}
} else if let Some(TypeInfo::Func { params, .. }) =
self.type_info.get(n as usize)
{
for _ in 0..params.len() {
scope.register(None, "local")?;
}
}
for local in locals {
scope.register(local.id, "local")?;
}
let mut resolver = ExprResolver::new(self, scope);
resolver.resolve(expression)?;
f.ty.inline = inline;
}
Ok(())
}
ModuleField::Elem(e) => {
match &mut e.kind {
ElemKind::Active { table, offset } => {
self.resolve_item_ref(table)?;
self.resolve_expr(offset)?;
}
ElemKind::Passive { .. } | ElemKind::Declared { .. } => {}
}
match &mut e.payload {
ElemPayload::Indices(elems) => {
for idx in elems {
self.resolve_item_ref(idx)?;
}
}
ElemPayload::Exprs { exprs, ty } => {
for funcref in exprs {
if let Some(idx) = funcref {
self.resolve_item_ref(idx)?;
}
}
self.resolve_heaptype(&mut ty.heap)?;
}
}
Ok(())
}
ModuleField::Data(d) => {
if let DataKind::Active { memory, offset } = &mut d.kind {
self.resolve_item_ref(memory)?;
self.resolve_expr(offset)?;
}
Ok(())
}
ModuleField::Start(i) => {
self.resolve_item_ref(i)?;
Ok(())
}
ModuleField::Export(e) => {
self.resolve_item_ref(&mut e.index)?;
Ok(())
}
ModuleField::Global(g) => {
self.resolve_valtype(&mut g.ty.ty)?;
if let GlobalKind::Inline(expr) = &mut g.kind {
self.resolve_expr(expr)?;
}
Ok(())
}
ModuleField::Event(e) => {
match &mut e.ty {
EventType::Exception(ty) => {
self.resolve_type_use(ty)?;
}
}
Ok(())
}
ModuleField::Instance(i) => {
if let InstanceKind::Inline { module, args } = &mut i.kind {
self.resolve_item_ref(module)?;
for arg in args {
self.resolve_item_ref(&mut arg.index)?;
}
}
Ok(())
}
ModuleField::NestedModule(m) => {
let fields = match &mut m.kind {
NestedModuleKind::Inline { fields } => fields,
NestedModuleKind::Import { .. } => panic!("should only be inline"),
};
Resolver::default().process(&mut parents.push(self, m.id), fields)?;
Ok(())
}
ModuleField::Table(t) => {
if let TableKind::Normal(t) = &mut t.kind {
self.resolve_heaptype(&mut t.elem.heap)?;
}
Ok(())
}
ModuleField::Alias(a) => {
match &mut a.source {
AliasSource::InstanceExport { instance, .. } => {
self.resolve_item_ref(instance)?;
}
AliasSource::Outer { module, index } => {
match (index, module) {
(Index::Num(..), Index::Num(..)) => {}
(index, module) => {
parents
.resolve(module)?
.resolve(index, Ns::from_export(&a.kind))?;
}
}
}
}
Ok(())
}
ModuleField::Memory(_) | ModuleField::Custom(_) => Ok(()),
}
}
fn resolve_valtype(&self, ty: &mut ValType<'a>) -> Result<(), Error> {
match ty {
ValType::Ref(ty) => self.resolve_heaptype(&mut ty.heap)?,
ValType::Rtt(_d, i) => {
self.resolve(i, Ns::Type)?;
}
_ => {}
}
Ok(())
}
fn resolve_heaptype(&self, ty: &mut HeapType<'a>) -> Result<(), Error> {
match ty {
HeapType::Index(i) => {
self.resolve(i, Ns::Type)?;
}
_ => {}
}
Ok(())
}
fn resolve_storagetype(&self, ty: &mut StorageType<'a>) -> Result<(), Error> {
match ty {
StorageType::Val(ty) => self.resolve_valtype(ty)?,
_ => {}
}
Ok(())
}
fn resolve_item_sig(&self, item: &mut ItemSig<'a>) -> Result<(), Error> {
match &mut item.kind {
ItemKind::Func(t) | ItemKind::Event(EventType::Exception(t)) => {
self.resolve_type_use(t)?;
}
ItemKind::Global(t) => self.resolve_valtype(&mut t.ty)?,
ItemKind::Instance(t) => {
self.resolve_type_use(t)?;
}
ItemKind::Module(m) => {
self.resolve_type_use(m)?;
}
ItemKind::Table(t) => {
self.resolve_heaptype(&mut t.elem.heap)?;
}
ItemKind::Memory(_) => {}
}
Ok(())
}
fn resolve_type_use<'b, T>(
&self,
ty: &'b mut TypeUse<'a, T>,
) -> Result<(&'b Index<'a>, Option<T>), Error>
where
T: TypeReference<'a>,
{
let idx = ty.index.as_mut().unwrap();
let idx = self.resolve_item_ref(idx)?;
if let Some(inline) = &mut ty.inline {
inline.resolve(self)?;
inline.check_matches(idx, self)?;
}
Ok((idx, ty.inline.take()))
}
fn resolve_expr(&self, expr: &mut Expression<'a>) -> Result<(), Error> {
ExprResolver::new(self, Namespace::default()).resolve(expr)
}
pub fn resolve(&self, idx: &mut Index<'a>, ns: Ns) -> Result<u32, Error> {
match ns {
Ns::Func => self.funcs.resolve(idx, "func"),
Ns::Table => self.tables.resolve(idx, "table"),
Ns::Global => self.globals.resolve(idx, "global"),
Ns::Memory => self.memories.resolve(idx, "memory"),
Ns::Instance => self.instances.resolve(idx, "instance"),
Ns::Module => self.modules.resolve(idx, "module"),
Ns::Event => self.events.resolve(idx, "event"),
Ns::Type => self.types.resolve(idx, "type"),
}
}
fn resolve_item_ref<'b, K>(&self, item: &'b mut ItemRef<'a, K>) -> Result<&'b Index<'a>, Error>
where
K: Into<ExportKind> + Copy,
{
match item {
ItemRef::Item { idx, kind, exports } => {
debug_assert!(exports.len() == 0);
self.resolve(
idx,
match (*kind).into() {
ExportKind::Func => Ns::Func,
ExportKind::Table => Ns::Table,
ExportKind::Global => Ns::Global,
ExportKind::Memory => Ns::Memory,
ExportKind::Instance => Ns::Instance,
ExportKind::Module => Ns::Module,
ExportKind::Event => Ns::Event,
ExportKind::Type => Ns::Type,
},
)?;
Ok(idx)
}
ItemRef::Outer { .. } => unreachable!(),
}
}
}
#[derive(Default)]
pub struct Namespace<'a> {
names: HashMap<Id<'a>, u32>,
count: u32,
}
impl<'a> Namespace<'a> {
fn register(&mut self, name: Option<Id<'a>>, desc: &str) -> Result<u32, Error> {
let index = self.alloc();
if let Some(name) = name {
if let Some(_prev) = self.names.insert(name, index) {
if desc != "elem" && desc != "data" {
return Err(Error::new(
name.span(),
format!("duplicate {} identifier", desc),
));
}
}
}
Ok(index)
}
fn alloc(&mut self) -> u32 {
let index = self.count;
self.count += 1;
return index;
}
fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> {
if let Some(_prev) = self.names.insert(name, index) {
return Err(Error::new(
name.span(),
format!("duplicate identifier for {}", desc),
));
}
Ok(())
}
fn resolve(&self, idx: &mut Index<'a>, desc: &str) -> Result<u32, Error> {
let id = match idx {
Index::Num(n, _) => return Ok(*n),
Index::Id(id) => id,
};
if let Some(&n) = self.names.get(id) {
*idx = Index::Num(n, id.span());
return Ok(n);
}
Err(resolve_error(*id, desc))
}
}
fn resolve_error(id: Id<'_>, ns: &str) -> Error {
assert!(
!id.is_gensym(),
"symbol generated by `wast` itself cannot be resolved {:?}",
id
);
Error::new(
id.span(),
format!("failed to find {} named `${}`", ns, id.name()),
)
}
#[derive(Debug, Clone)]
struct ExprBlock<'a> {
label: Option<Id<'a>>,
pushed_scope: bool,
}
struct ExprResolver<'a, 'b> {
resolver: &'b Resolver<'a>,
scopes: Vec<Namespace<'a>>,
blocks: Vec<ExprBlock<'a>>,
}
impl<'a, 'b> ExprResolver<'a, 'b> {
fn new(resolver: &'b Resolver<'a>, initial_scope: Namespace<'a>) -> ExprResolver<'a, 'b> {
ExprResolver {
resolver,
scopes: vec![initial_scope],
blocks: Vec::new(),
}
}
fn resolve(&mut self, expr: &mut Expression<'a>) -> Result<(), Error> {
for instr in expr.instrs.iter_mut() {
self.resolve_instr(instr)?;
}
Ok(())
}
fn resolve_block_type(&mut self, bt: &mut BlockType<'a>) -> Result<(), Error> {
if bt.ty.index.is_some() {
let (ty, _) = self.resolver.resolve_type_use(&mut bt.ty)?;
let n = match ty {
Index::Num(n, _) => *n,
Index::Id(_) => panic!("expected `Num`"),
};
let ty = match self.resolver.type_info.get(n as usize) {
Some(TypeInfo::Func { params, results }) => (params, results),
_ => return Ok(()),
};
if ty.0.len() == 0 && ty.1.len() <= 1 {
let mut inline = FunctionType::default();
inline.results = ty.1.clone();
bt.ty.inline = Some(inline);
bt.ty.index = None;
}
}
if let Some(inline) = &mut bt.ty.inline {
inline.resolve(self.resolver)?;
}
Ok(())
}
fn resolve_instr(&mut self, instr: &mut Instruction<'a>) -> Result<(), Error> {
use crate::ast::Instruction::*;
if let Some(m) = instr.memarg_mut() {
self.resolver.resolve_item_ref(&mut m.memory)?;
}
match instr {
MemorySize(i) | MemoryGrow(i) | MemoryFill(i) => {
self.resolver.resolve_item_ref(&mut i.mem)?;
}
MemoryInit(i) => {
self.resolver.datas.resolve(&mut i.data, "data")?;
self.resolver.resolve_item_ref(&mut i.mem)?;
}
MemoryCopy(i) => {
self.resolver.resolve_item_ref(&mut i.src)?;
self.resolver.resolve_item_ref(&mut i.dst)?;
}
DataDrop(i) => {
self.resolver.datas.resolve(i, "data")?;
}
TableInit(i) => {
self.resolver.elems.resolve(&mut i.elem, "elem")?;
self.resolver.resolve_item_ref(&mut i.table)?;
}
ElemDrop(i) => {
self.resolver.elems.resolve(i, "elem")?;
}
TableCopy(i) => {
self.resolver.resolve_item_ref(&mut i.dst)?;
self.resolver.resolve_item_ref(&mut i.src)?;
}
TableFill(i) | TableSet(i) | TableGet(i) | TableSize(i) | TableGrow(i) => {
self.resolver.resolve_item_ref(&mut i.dst)?;
}
GlobalSet(i) | GlobalGet(i) => {
self.resolver.resolve_item_ref(&mut i.0)?;
}
LocalSet(i) | LocalGet(i) | LocalTee(i) => {
assert!(self.scopes.len() > 0);
for (depth, scope) in self.scopes.iter().enumerate().rev() {
if let Err(e) = scope.resolve(i, "local") {
if depth == 0 {
return Err(e);
}
} else {
break;
}
}
assert!(i.is_resolved());
}
Call(i) | RefFunc(i) | ReturnCall(i) => {
self.resolver.resolve_item_ref(&mut i.0)?;
}
CallIndirect(c) | ReturnCallIndirect(c) => {
self.resolver.resolve_item_ref(&mut c.table)?;
self.resolver.resolve_type_use(&mut c.ty)?;
}
FuncBind(b) => {
self.resolver.resolve_type_use(&mut b.ty)?;
}
Let(t) => {
for local in &mut t.locals {
self.resolver.resolve_valtype(&mut local.ty)?;
}
let mut scope = Namespace::default();
for local in &t.locals {
scope.register(local.id, "local")?;
}
self.scopes.push(scope);
self.blocks.push(ExprBlock {
label: t.block.label,
pushed_scope: true,
});
self.resolve_block_type(&mut t.block)?;
}
Block(bt) | If(bt) | Loop(bt) | Try(bt) => {
self.blocks.push(ExprBlock {
label: bt.label,
pushed_scope: false,
});
self.resolve_block_type(bt)?;
}
Else(_) | End(_) => {
let (matching_block, label) = match &instr {
Else(label) => (self.blocks.last().cloned(), label),
End(label) => (self.blocks.pop(), label),
_ => unreachable!(),
};
let matching_block = match matching_block {
Some(l) => l,
None => return Ok(()),
};
if matching_block.pushed_scope {
if let End(_) = instr {
self.scopes.pop();
}
}
let label = match label {
Some(l) => l,
None => return Ok(()),
};
if Some(*label) == matching_block.label {
return Ok(());
}
return Err(Error::new(
label.span(),
"mismatching labels between end and block".to_string(),
));
}
Br(i) | BrIf(i) | BrOnNull(i) | Delegate(i) => {
self.resolve_label(i)?;
}
BrTable(i) => {
for label in i.labels.iter_mut() {
self.resolve_label(label)?;
}
self.resolve_label(&mut i.default)?;
}
Throw(i) => {
self.resolver.resolve(i, Ns::Event)?;
}
Rethrow(i) => {
self.resolve_label(i)?;
}
Catch(i) => {
self.resolver.resolve(i, Ns::Event)?;
}
BrOnCast(l) | BrOnFunc(l) | BrOnData(l) | BrOnI31(l) => {
self.resolve_label(l)?;
}
Select(s) => {
if let Some(list) = &mut s.tys {
for ty in list {
self.resolver.resolve_valtype(ty)?;
}
}
}
StructNew(i)
| StructNewWithRtt(i)
| StructNewDefaultWithRtt(i)
| ArrayNewWithRtt(i)
| ArrayNewDefaultWithRtt(i)
| ArrayGet(i)
| ArrayGetS(i)
| ArrayGetU(i)
| ArraySet(i)
| ArrayLen(i) => {
self.resolver.resolve(i, Ns::Type)?;
}
RTTCanon(i) => {
self.resolver.resolve(i, Ns::Type)?;
}
RTTSub(i) => {
self.resolver.resolve(i, Ns::Type)?;
}
StructSet(s) | StructGet(s) | StructGetS(s) | StructGetU(s) => {
self.resolver.resolve(&mut s.r#struct, Ns::Type)?;
self.resolver.fields.resolve(&mut s.field, "field")?;
}
RefNull(ty) => self.resolver.resolve_heaptype(ty)?,
_ => {}
}
Ok(())
}
fn resolve_label(&self, label: &mut Index<'a>) -> Result<(), Error> {
let id = match label {
Index::Num(..) => return Ok(()),
Index::Id(id) => *id,
};
let idx = self
.blocks
.iter()
.rev()
.enumerate()
.filter_map(|(i, b)| b.label.map(|l| (i, l)))
.find(|(_, l)| *l == id);
match idx {
Some((idx, _)) => {
*label = Index::Num(idx as u32, id.span());
Ok(())
}
None => Err(resolve_error(id, "label")),
}
}
}
struct Parents<'a, 'b> {
prev: Option<ParentNode<'a, 'b>>,
cur_id: Option<Id<'a>>,
depth: usize,
names: &'b mut HashMap<Id<'a>, usize>,
}
struct ParentNode<'a, 'b> {
resolver: &'b Resolver<'a>,
id: Option<Id<'a>>,
prev: Option<&'b ParentNode<'a, 'b>>,
prev_depth: Option<usize>,
}
impl<'a, 'b> Parents<'a, 'b> {
fn push<'c>(&'c mut self, resolver: &'c Resolver<'a>, id: Option<Id<'a>>) -> Parents<'a, 'c>
where
'b: 'c,
{
let prev_depth = if let Some(id) = self.cur_id {
self.names.insert(id, self.depth)
} else {
None
};
Parents {
prev: Some(ParentNode {
prev: self.prev.as_ref(),
resolver,
id: self.cur_id,
prev_depth,
}),
cur_id: id,
depth: self.depth + 1,
names: &mut *self.names,
}
}
fn resolve(&self, index: &mut Index<'a>) -> Result<&'b Resolver<'a>, Error> {
let mut i = match *index {
Index::Num(n, _) => n,
Index::Id(id) => match self.names.get(&id) {
Some(idx) => (self.depth - *idx - 1) as u32,
None => return Err(resolve_error(id, "parent module")),
},
};
*index = Index::Num(i, index.span());
let mut cur = match self.prev.as_ref() {
Some(n) => n,
None => {
return Err(Error::new(
index.span(),
"cannot use `outer` alias in root module".to_string(),
))
}
};
while i > 0 {
cur = match cur.prev {
Some(n) => n,
None => {
return Err(Error::new(
index.span(),
"alias to `outer` module index too large".to_string(),
))
}
};
i -= 1;
}
Ok(cur.resolver)
}
}
impl<'a, 'b> Drop for Parents<'a, 'b> {
fn drop(&mut self) {
let (id, prev_depth) = match &self.prev {
Some(n) => (n.id, n.prev_depth),
None => return,
};
if let Some(id) = id {
match prev_depth {
Some(i) => {
self.names.insert(id, i);
}
None => {
self.names.remove(&id);
}
}
}
}
}
enum TypeInfo<'a> {
Func {
params: Box<[ValType<'a>]>,
results: Box<[ValType<'a>]>,
},
Other,
}
trait TypeReference<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error>;
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error>;
}
impl<'a> TypeReference<'a> for FunctionType<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> {
let n = match idx {
Index::Num(n, _) => *n,
Index::Id(_) => panic!("expected `Num`"),
};
let (params, results) = match cx.type_info.get(n as usize) {
Some(TypeInfo::Func { params, results }) => (params, results),
_ => return Ok(()),
};
let types_not_equal = |a: &ValType, b: &ValType| {
let mut a = a.clone();
let mut b = b.clone();
drop(cx.resolve_valtype(&mut a));
drop(cx.resolve_valtype(&mut b));
a != b
};
let not_equal = params.len() != self.params.len()
|| results.len() != self.results.len()
|| params
.iter()
.zip(self.params.iter())
.any(|(a, (_, _, b))| types_not_equal(a, b))
|| results
.iter()
.zip(self.results.iter())
.any(|(a, b)| types_not_equal(a, b));
if not_equal {
return Err(Error::new(
idx.span(),
format!("inline function type doesn't match type reference"),
));
}
Ok(())
}
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
for param in self.params.iter_mut() {
cx.resolve_valtype(&mut param.2)?;
}
for result in self.results.iter_mut() {
cx.resolve_valtype(result)?;
}
Ok(())
}
}
impl<'a> TypeReference<'a> for InstanceType<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> {
drop(cx);
Err(Error::new(
idx.span(),
format!("cannot specify instance type as a reference and inline"),
))
}
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
for export in self.exports.iter_mut() {
cx.resolve_item_sig(&mut export.item)?;
}
Ok(())
}
}
impl<'a> TypeReference<'a> for ModuleType<'a> {
fn check_matches(&mut self, idx: &Index<'a>, cx: &Resolver<'a>) -> Result<(), Error> {
drop(cx);
Err(Error::new(
idx.span(),
format!("cannot specify module type as a reference and inline"),
))
}
fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
for i in self.imports.iter_mut() {
cx.resolve_item_sig(&mut i.item)?;
}
for e in self.exports.iter_mut() {
cx.resolve_item_sig(&mut e.item)?;
}
Ok(())
}
}