/// Context structure used to perform name resolution. #[derive(Default)] pubstruct Resolver<'a> { // Namespaces within each module. Note that each namespace carries with it // information about the signature of the item in that namespace. The // signature is later used to synthesize the type of a module and inject // type annotations if necessary.
funcs: Namespace<'a>,
globals: Namespace<'a>,
tables: Namespace<'a>,
memories: Namespace<'a>,
types: Namespace<'a>,
tags: Namespace<'a>,
datas: Namespace<'a>,
elems: Namespace<'a>,
fields: HashMap<u32, Namespace<'a>>,
type_info: Vec<TypeInfo<'a>>,
}
impl<'a> Resolver<'a> { fn process(&mutself, fields: &mut Vec<ModuleField<'a>>) -> Result<(), Error> { // Number everything in the module, recording what names correspond to // what indices. for field in fields.iter_mut() { self.register(field)?;
}
// Then we can replace all our `Index::Id` instances with `Index::Num` // in the AST. Note that this also recurses into nested modules. for field in fields.iter_mut() { self.resolve_field(field)?;
}
Ok(())
}
match &ty.def.kind { // For GC structure types we need to be sure to populate the // field namespace here as well. // // The field namespace is relative to the struct fields are defined in
InnerTypeKind::Struct(r#struct) => { for (i, field) in r#struct.fields.iter().enumerate() { iflet Some(id) = field.id { self.fields
.entry(type_index)
.or_insert(Namespace::default())
.register_specific(id, i as u32, "field")?;
}
}
}
// Record function signatures as we see them to so we can // generate errors for mismatches in references such as // `call_indirect`. match &ty.def.kind {
InnerTypeKind::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),
}
ModuleField::Type(i) => { returnself.register_type(i);
}
ModuleField::Rec(i) => { for ty in &i.types { self.register_type(ty)?;
} return Ok(());
}
ModuleField::Elem(e) => self.elems.register(e.id, "elem")?,
ModuleField::Data(d) => self.datas.register(d.id, "data")?,
ModuleField::Tag(t) => self.tags.register(t.id, "tag")?,
// These fields don't define any items in any index space.
ModuleField::Export(_) | ModuleField::Start(_) | ModuleField::Custom(_) => { return Ok(())
}
};
Ok(())
}
fn resolve_field(&self, field: &mut ModuleField<'a>) -> Result<(), Error> { match field {
ModuleField::Import(i) => { self.resolve_item_sig(&mut i.item)?;
Ok(())
}
ModuleField::Type(ty) => self.resolve_type(ty),
ModuleField::Rec(rec) => { for ty in &mut rec.types { self.resolve_type(ty)?;
}
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`"),
}; iflet FuncKind::Inline { locals, expression } = &mut f.kind { // Resolve (ref T) in locals for local in locals.iter_mut() { self.resolve_valtype(&mut local.ty)?;
}
// Build a scope with a local namespace for the function // body letmut scope = Namespace::default();
// Parameters come first in the scope... iflet Some(inline) = &inline { for (id, _, _) in inline.params.iter() {
scope.register(*id, "local")?;
}
} elseiflet Some(TypeInfo::Func { params, .. }) = self.type_info.get(n as usize)
{ for _ in0..params.len() {
scope.register(None, "local")?;
}
}
// .. followed by locals themselves for local in locals.iter() {
scope.register(local.id, "local")?;
}
// Initialize the expression resolver with this scope letmut resolver = ExprResolver::new(self, scope);
// and then we can resolve the expression!
resolver.resolve(expression)?;
// specifically save the original `sig`, if it was present, // because that's what we're using for local names.
f.ty.inline = inline;
}
Ok(())
}
// If the type was listed inline *and* it was specified via a type index // we need to assert they're the same. // // Note that we resolve the type first to transform all names to // indices to ensure that all the indices line up. iflet Some(inline) = &mut ty.inline {
inline.resolve(self)?;
inline.check_matches(idx, self)?;
}
#[derive(Debug, Clone)] struct ExprBlock<'a> { // The label of the block
label: Option<Id<'a>>, // Whether this block pushed a new scope for resolving locals
pushed_scope: bool,
}
struct ExprResolver<'a, 'b> {
resolver: &'b Resolver<'a>, // Scopes tracks the local namespace and dynamically grows as we enter/exit // `let` blocks
scopes: Vec<Namespace<'a>>,
blocks: Vec<ExprBlock<'a>>,
}
fn resolve(&mutself, expr: &mut Expression<'a>) -> Result<(), Error> { for instr in expr.instrs.iter_mut() { self.resolve_instr(instr)?;
}
Ok(())
}
fn resolve_block_type(&mutself, bt: &mut BlockType<'a>) -> Result<(), Error> { // If the index is specified on this block type then that's the source // of resolution and the resolver step here will verify the inline type // matches. Note that indexes may come from the source text itself but // may also come from being injected as part of the type expansion phase // of resolution. // // If no type is present then that means that the inline type is not // present or has 0-1 results. In that case the nested value types are // resolved, if they're there, to get encoded later on. if bt.ty.index.is_some() { self.resolver.resolve_type_use(&mut bt.ty)?;
} elseiflet Some(inline) = &mut bt.ty.inline {
inline.resolve(self.resolver)?;
}
LocalSet(i) | LocalGet(i) | LocalTee(i) => {
assert!(self.scopes.len() > 0); // Resolve a local by iterating over scopes from most recent // to less recent. This allows locals added by `let` blocks to // shadow less recent locals. for (depth, scope) inself.scopes.iter().enumerate().rev() { iflet Err(e) = scope.resolve(i, "local") { if depth == 0 { // There are no more scopes left, report this as // the result return Err(e);
}
} else { break;
}
} // We must have taken the `break` and resolved the local
assert!(i.is_resolved());
}
// On `End` instructions we pop a label from the stack, and for both // `End` and `Else` instructions if they have labels listed we // verify that they match the label at the beginning of the block. 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(()),
};
// Reset the local scopes to before this block was entered if matching_block.pushed_scope { iflet 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(),
));
}
Delegate(i) => { // Since a delegate starts counting one layer out from the // current try-delegate block, we pop before we resolve labels. self.blocks.pop(); self.resolve_label(i)?;
}
Select(s) => { iflet Some(list) = &mut s.tys { for ty in list { self.resolver.resolve_valtype(ty)?;
}
}
}
fn resolve_field(&self, s: &mut StructAccess<'a>) -> Result<(), Error> { let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?; iflet Index::Id(field_id) = s.field { self.resolver
.fields
.get(&type_index)
.ok_or(Error::new(field_id.span(), format!("accessing a named field `{}` in a struct without named fields, type index {}", field_id.name(), type_index)))?
.resolve(&mut s.field, "field")?;
}
Ok(())
}
}
impl<'a> TypeReference<'a> for FunctionType<'a> { fn check_matches(&mutself, 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(()),
};
// Here we need to check that the inline type listed (ourselves) matches // what was listed in the module itself (the `params` and `results` // above). The listed values in `types` are not resolved yet, although // we should be resolved. In any case we do name resolution // opportunistically here to see if the values are equal.
let types_not_equal = |a: &ValType, b: &ValType| { letmut a = *a; letmut b = *b;
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"),
));
}
fn resolve_type_func(&mutself, ty: &mutFunctionType<'a>) -> Result<(), Error> { // Resolve the (ref T) value types in the final function type for param in ty.params.iter_mut() { self.resolve_valtype(&mut param.2)?;
} for result in ty.results.iter_mut() { self.resolve_valtype(result)?;
}
Ok(())
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.