Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  names.rs   Sprache: unbekannt

 
use crate::core::resolve::Ns;
use crate::core::*;
use crate::names::{resolve_error, Namespace};
use crate::token::{Id, Index};
use crate::Error;
use std::collections::HashMap;

pub fn resolve<'a>(fields: &mut Vec<ModuleField<'a>>) -> Result<Resolver<'a>, Error> {
    let mut resolver = Resolver::default();
    resolver.process(fields)?;
    Ok(resolver)
}

/// Context structure used to perform name resolution.
#[derive(Default)]
pub struct 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(&mut self, 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(())
    }

    fn register_type(&mut self, ty: &Type<'a>) -> Result<(), Error> {
        let type_index = self.types.register(ty.id, "type")?;

        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() {
                    if let Some(id) = field.id {
                        self.fields
                            .entry(type_index)
                            .or_insert(Namespace::default())
                            .register_specific(id, i as u32, "field")?;
                    }
                }
            }

            InnerTypeKind::Array(_) | InnerTypeKind::Func(_) | InnerTypeKind::Cont(_) => {}
        }

        // 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),
        }

        Ok(())
    }

    fn register(&mut self, item: &ModuleField<'a>) -> Result<(), Error> {
        match item {
            ModuleField::Import(i) => 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::Tag(_) => self.tags.register(i.item.id, "tag")?,
            },
            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::Type(i) => {
                return self.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`"),
                };
                if let 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
                    let mut scope = Namespace::default();

                    // Parameters come first in the scope...
                    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")?;
                        }
                    }

                    // .. followed by locals themselves
                    for local in locals.iter() {
                        scope.register(local.id, "local")?;
                    }

                    // Initialize the expression resolver with this scope
                    let mut 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(())
            }

            ModuleField::Elem(e) => {
                match &mut e.kind {
                    ElemKind::Active { table, offset } => {
                        if let Some(table) = table {
                            self.resolve(table, Ns::Table)?;
                        }
                        self.resolve_expr(offset)?;
                    }
                    ElemKind::Passive { .. } | ElemKind::Declared { .. } => {}
                }
                match &mut e.payload {
                    ElemPayload::Indices(elems) => {
                        for idx in elems {
                            self.resolve(idx, Ns::Func)?;
                        }
                    }
                    ElemPayload::Exprs { exprs, ty } => {
                        for expr in exprs {
                            self.resolve_expr(expr)?;
                        }
                        self.resolve_heaptype(&mut ty.heap)?;
                    }
                }
                Ok(())
            }

            ModuleField::Data(d) => {
                if let DataKind::Active { memory, offset } = &mut d.kind {
                    self.resolve(memory, Ns::Memory)?;
                    self.resolve_expr(offset)?;
                }
                Ok(())
            }

            ModuleField::Start(i) => {
                self.resolve(i, Ns::Func)?;
                Ok(())
            }

            ModuleField::Export(e) => {
                self.resolve(
                    &mut e.item,
                    match e.kind {
                        ExportKind::Func => Ns::Func,
                        ExportKind::Table => Ns::Table,
                        ExportKind::Memory => Ns::Memory,
                        ExportKind::Global => Ns::Global,
                        ExportKind::Tag => Ns::Tag,
                    },
                )?;
                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::Tag(t) => {
                match &mut t.ty {
                    TagType::Exception(ty) => {
                        self.resolve_type_use(ty)?;
                    }
                }
                Ok(())
            }

            ModuleField::Table(t) => {
                if let TableKind::Normal { ty, init_expr } = &mut t.kind {
                    self.resolve_heaptype(&mut ty.elem.heap)?;
                    if let Some(init_expr) = init_expr {
                        self.resolve_expr(init_expr)?;
                    }
                }
                Ok(())
            }

            ModuleField::Memory(_) | ModuleField::Custom(_) => Ok(()),
        }
    }

    fn resolve_item_sig(&self, item: &mut ItemSig<'a>) -> Result<(), Error> {
        match &mut item.kind {
            ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => {
                self.resolve_type_use(t)?;
            }
            ItemKind::Global(t) => self.resolve_valtype(&mut t.ty)?,
            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();
        self.resolve(idx, Ns::Type)?;

        // 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.
        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::Tag => self.tags.resolve(idx, "tag"),
            Ns::Type => self.types.resolve(idx, "type"),
        }
    }

    fn resolve_type(&self, ty: &mut Type<'a>) -> Result<(), Error> {
        ResolveCoreType::resolve_type(&mut &*self, ty)
    }

    fn resolve_valtype(&self, ty: &mut ValType<'a>) -> Result<(), Error> {
        ResolveCoreType::resolve_valtype(&mut &*self, ty)
    }

    fn resolve_heaptype(&self, ty: &mut HeapType<'a>) -> Result<(), Error> {
        ResolveCoreType::resolve_heaptype(&mut &*self, ty)
    }
}

#[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>>,
}

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 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)?;
        } else 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 Instruction::*;

        if let Some(m) = instr.memarg_mut() {
            self.resolver.resolve(&mut m.memory, Ns::Memory)?;
        }

        match instr {
            MemorySize(i) | MemoryGrow(i) | MemoryFill(i) | MemoryDiscard(i) => {
                self.resolver.resolve(&mut i.mem, Ns::Memory)?;
            }
            MemoryInit(i) => {
                self.resolver.datas.resolve(&mut i.data, "data")?;
                self.resolver.resolve(&mut i.mem, Ns::Memory)?;
            }
            MemoryCopy(i) => {
                self.resolver.resolve(&mut i.src, Ns::Memory)?;
                self.resolver.resolve(&mut i.dst, Ns::Memory)?;
            }
            DataDrop(i) => {
                self.resolver.datas.resolve(i, "data")?;
            }

            TableInit(i) => {
                self.resolver.elems.resolve(&mut i.elem, "elem")?;
                self.resolver.resolve(&mut i.table, Ns::Table)?;
            }
            ElemDrop(i) => {
                self.resolver.elems.resolve(i, "elem")?;
            }

            TableCopy(i) => {
                self.resolver.resolve(&mut i.dst, Ns::Table)?;
                self.resolver.resolve(&mut i.src, Ns::Table)?;
            }

            TableFill(i) | TableSet(i) | TableGet(i) | TableSize(i) | TableGrow(i) => {
                self.resolver.resolve(&mut i.dst, Ns::Table)?;
            }

            TableAtomicGet(i)
            | TableAtomicSet(i)
            | TableAtomicRmwXchg(i)
            | TableAtomicRmwCmpxchg(i) => {
                self.resolver.resolve(&mut i.inner.dst, Ns::Table)?;
            }

            GlobalSet(i) | GlobalGet(i) => {
                self.resolver.resolve(i, Ns::Global)?;
            }

            GlobalAtomicSet(i)
            | GlobalAtomicGet(i)
            | GlobalAtomicRmwAdd(i)
            | GlobalAtomicRmwSub(i)
            | GlobalAtomicRmwAnd(i)
            | GlobalAtomicRmwOr(i)
            | GlobalAtomicRmwXor(i)
            | GlobalAtomicRmwXchg(i)
            | GlobalAtomicRmwCmpxchg(i) => {
                self.resolver.resolve(&mut i.inner, Ns::Global)?;
            }

            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) in self.scopes.iter().enumerate().rev() {
                    if let 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());
            }

            Call(i) | RefFunc(i) | ReturnCall(i) => {
                self.resolver.resolve(i, Ns::Func)?;
            }

            CallIndirect(c) | ReturnCallIndirect(c) => {
                self.resolver.resolve(&mut c.table, Ns::Table)?;
                self.resolver.resolve_type_use(&mut c.ty)?;
            }

            CallRef(i) | ReturnCallRef(i) => {
                self.resolver.resolve(i, Ns::Type)?;
            }

            Block(bt) | If(bt) | Loop(bt) | Try(bt) => {
                self.blocks.push(ExprBlock {
                    label: bt.label,
                    pushed_scope: false,
                });
                self.resolve_block_type(bt)?;
            }
            TryTable(try_table) => {
                self.resolve_block_type(&mut try_table.block)?;
                for catch in &mut try_table.catches {
                    if let Some(tag) = catch.kind.tag_index_mut() {
                        self.resolver.resolve(tag, Ns::Tag)?;
                    }
                    self.resolve_label(&mut catch.label)?;
                }
                self.blocks.push(ExprBlock {
                    label: try_table.block.label,
                    pushed_scope: false,
                });
            }

            // 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 {
                    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) | BrOnNonNull(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) | Catch(i) => {
                self.resolver.resolve(i, Ns::Tag)?;
            }

            Rethrow(i) => {
                self.resolve_label(i)?;
            }

            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) => {
                if let Some(list) = &mut s.tys {
                    for ty in list {
                        self.resolver.resolve_valtype(ty)?;
                    }
                }
            }

            RefTest(i) => {
                self.resolver.resolve_reftype(&mut i.r#type)?;
            }
            RefCast(i) => {
                self.resolver.resolve_reftype(&mut i.r#type)?;
            }
            BrOnCast(i) => {
                self.resolve_label(&mut i.label)?;
                self.resolver.resolve_reftype(&mut i.to_type)?;
                self.resolver.resolve_reftype(&mut i.from_type)?;
            }
            BrOnCastFail(i) => {
                self.resolve_label(&mut i.label)?;
                self.resolver.resolve_reftype(&mut i.to_type)?;
                self.resolver.resolve_reftype(&mut i.from_type)?;
            }

            StructNew(i) | StructNewDefault(i) | ArrayNew(i) | ArrayNewDefault(i) | ArrayGet(i)
            | ArrayGetS(i) | ArrayGetU(i) | ArraySet(i) => {
                self.resolver.resolve(i, Ns::Type)?;
            }

            StructSet(s) | StructGet(s) | StructGetS(s) | StructGetU(s) => {
                self.resolve_field(s)?;
            }

            StructAtomicGet(s)
            | StructAtomicGetS(s)
            | StructAtomicGetU(s)
            | StructAtomicSet(s)
            | StructAtomicRmwAdd(s)
            | StructAtomicRmwSub(s)
            | StructAtomicRmwAnd(s)
            | StructAtomicRmwOr(s)
            | StructAtomicRmwXor(s)
            | StructAtomicRmwXchg(s)
            | StructAtomicRmwCmpxchg(s) => {
                self.resolve_field(&mut s.inner)?;
            }

            ArrayNewFixed(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
            }
            ArrayNewData(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
                self.resolver.datas.resolve(&mut a.data_idx, "data")?;
            }
            ArrayNewElem(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
                self.resolver.elems.resolve(&mut a.elem_idx, "elem")?;
            }
            ArrayFill(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
            }
            ArrayCopy(a) => {
                self.resolver.resolve(&mut a.dest_array, Ns::Type)?;
                self.resolver.resolve(&mut a.src_array, Ns::Type)?;
            }
            ArrayInitData(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
                self.resolver.datas.resolve(&mut a.segment, "data")?;
            }
            ArrayInitElem(a) => {
                self.resolver.resolve(&mut a.array, Ns::Type)?;
                self.resolver.elems.resolve(&mut a.segment, "elem")?;
            }

            ArrayAtomicGet(i)
            | ArrayAtomicGetS(i)
            | ArrayAtomicGetU(i)
            | ArrayAtomicSet(i)
            | ArrayAtomicRmwAdd(i)
            | ArrayAtomicRmwSub(i)
            | ArrayAtomicRmwAnd(i)
            | ArrayAtomicRmwOr(i)
            | ArrayAtomicRmwXor(i)
            | ArrayAtomicRmwXchg(i)
            | ArrayAtomicRmwCmpxchg(i) => {
                self.resolver.resolve(&mut i.inner, Ns::Type)?;
            }

            RefNull(ty) => self.resolver.resolve_heaptype(ty)?,

            ContNew(ty) => {
                self.resolver.resolve(ty, Ns::Type)?;
            }
            ContBind(cb) => {
                self.resolver.resolve(&mut cb.argument_index, Ns::Type)?;
                self.resolver.resolve(&mut cb.result_index, Ns::Type)?;
            }
            Suspend(ty) => {
                self.resolver.resolve(ty, Ns::Tag)?;
            }
            Resume(r) => {
                self.resolver.resolve(&mut r.type_index, Ns::Type)?;
                self.resolve_resume_table(&mut r.table)?;
            }
            ResumeThrow(rt) => {
                self.resolver.resolve(&mut rt.type_index, Ns::Type)?;
                self.resolver.resolve(&mut rt.tag_index, Ns::Tag)?;
                self.resolve_resume_table(&mut rt.table)?;
            }
            Switch(s) => {
                self.resolver.resolve(&mut s.type_index, Ns::Type)?;
                self.resolver.resolve(&mut s.tag_index, Ns::Tag)?;
            }

            _ => {}
        }
        Ok(())
    }

    fn resolve_resume_table(&self, table: &mut ResumeTable<'a>) -> Result<(), Error> {
        for handle in &mut table.handlers {
            match handle {
                Handle::OnLabel {
                    ref mut tag,
                    ref mut label,
                } => {
                    self.resolver.resolve(tag, Ns::Tag)?;
                    self.resolve_label(label)?;
                }
                Handle::OnSwitch { ref mut tag } => {
                    self.resolver.resolve(tag, Ns::Tag)?;
                }
            }
        }
        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")),
        }
    }

    fn resolve_field(&self, s: &mut StructAccess<'a>) -> Result<(), Error> {
        let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?;
        if let 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(())
    }
}

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(()),
        };

        // 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| {
            let mut a = *a;
            let mut 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"),
            ));
        }

        Ok(())
    }

    fn resolve(&mut self, cx: &Resolver<'a>) -> Result<(), Error> {
        (&mut &*cx).resolve_type_func(self)
    }
}

pub(crate) trait ResolveCoreType<'a> {
    fn resolve_type_name(&mut self, name: &mut Index<'a>) -> Result<u32, Error>;

    fn resolve_type(&mut self, ty: &mut Type<'a>) -> Result<(), Error> {
        self.resolve_type_def(&mut ty.def)?;
        Ok(())
    }

    fn resolve_type_def(&mut self, ty: &mut TypeDef<'a>) -> Result<(), Error> {
        if let Some(parent) = &mut ty.parent {
            self.resolve_type_name(parent)?;
        }
        match &mut ty.kind {
            InnerTypeKind::Func(func) => self.resolve_type_func(func),
            InnerTypeKind::Struct(struct_) => {
                for field in &mut struct_.fields {
                    self.resolve_storagetype(&mut field.ty)?;
                }
                Ok(())
            }
            InnerTypeKind::Array(array) => self.resolve_storagetype(&mut array.ty),
            InnerTypeKind::Cont(cont) => {
                self.resolve_type_name(&mut cont.0)?;
                Ok(())
            }
        }
    }

    fn resolve_type_func(&mut self, ty: &mut FunctionType<'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(())
    }

    fn resolve_valtype(&mut self, ty: &mut ValType<'a>) -> Result<(), Error> {
        match ty {
            ValType::Ref(ty) => self.resolve_reftype(ty),
            ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => Ok(()),
        }
    }

    fn resolve_reftype(&mut self, ty: &mut RefType<'a>) -> Result<(), Error> {
        self.resolve_heaptype(&mut ty.heap)
    }

    fn resolve_heaptype(&mut self, ty: &mut HeapType<'a>) -> Result<(), Error> {
        match ty {
            HeapType::Concrete(i) => {
                self.resolve_type_name(i)?;
            }
            HeapType::Abstract { .. } => {}
        }
        Ok(())
    }

    fn resolve_storagetype(&mut self, ty: &mut StorageType<'a>) -> Result<(), Error> {
        match ty {
            StorageType::Val(ty) => self.resolve_valtype(ty),
            StorageType::I8 | StorageType::I16 => Ok(()),
        }
    }
}

impl<'a> ResolveCoreType<'a> for &Resolver<'a> {
    fn resolve_type_name(&mut self, name: &mut Index<'a>) -> Result<u32, Error> {
        self.resolve(name, Ns::Type)
    }
}

[ Dauer der Verarbeitung: 0.40 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge