Coverage Report

Created: 2024-10-16 07:58

/rust/registry/src/index.crates.io-6f17d22bba15001f/wast-64.0.0/src/core/resolve/types.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::core::*;
2
use crate::gensym;
3
use crate::token::{Index, Span};
4
use std::collections::HashMap;
5
6
0
pub fn expand<'a>(fields: &mut Vec<ModuleField<'a>>) {
7
0
    let mut expander = Expander::default();
8
0
    expander.process(fields);
9
0
}
10
11
#[derive(Default)]
12
pub(crate) struct Expander<'a> {
13
    // Maps used to "intern" types. These maps are populated as type annotations
14
    // are seen and inline type annotations use previously defined ones if
15
    // there's a match.
16
    func_type_to_idx: HashMap<FuncKey<'a>, Index<'a>>,
17
18
    /// Fields, during processing, which should be prepended to the
19
    /// currently-being-processed field. This should always be empty after
20
    /// processing is complete.
21
    to_prepend: Vec<ModuleField<'a>>,
22
}
23
24
impl<'a> Expander<'a> {
25
0
    fn process(&mut self, fields: &mut Vec<ModuleField<'a>>) {
26
0
        // Next we expand "header" fields which are those like types and
27
0
        // imports. In this context "header" is defined by the previous
28
0
        // `process_imports_early` annotation.
29
0
        let mut cur = 0;
30
0
        while cur < fields.len() {
31
0
            self.expand_header(&mut fields[cur]);
32
0
            for item in self.to_prepend.drain(..) {
33
0
                fields.insert(cur, item);
34
0
                cur += 1;
35
0
            }
36
0
            cur += 1;
37
        }
38
39
        // Next after we've done that we expand remaining fields. Note that
40
        // after this we actually append instead of prepend. This is because
41
        // injected types are intended to come at the end of the type section
42
        // and types will be sorted before all other items processed here in the
43
        // final module anyway.
44
0
        for field in fields.iter_mut() {
45
0
            self.expand(field);
46
0
        }
47
0
        fields.append(&mut self.to_prepend);
48
0
    }
49
50
0
    fn expand_header(&mut self, item: &mut ModuleField<'a>) {
51
0
        match item {
52
0
            ModuleField::Type(ty) => {
53
0
                let id = gensym::fill(ty.span, &mut ty.id);
54
0
                match &mut ty.def {
55
0
                    TypeDef::Func(f) => {
56
0
                        f.key().insert(self, Index::Id(id));
57
0
                    }
58
0
                    TypeDef::Array(_) | TypeDef::Struct(_) => {}
59
                }
60
            }
61
0
            _ => {}
62
        }
63
0
    }
64
65
0
    fn expand(&mut self, item: &mut ModuleField<'a>) {
66
0
        match item {
67
            // This is pre-expanded above
68
0
            ModuleField::Type(_) => {}
69
0
            ModuleField::Rec(_) => {}
70
71
0
            ModuleField::Import(i) => {
72
0
                self.expand_item_sig(&mut i.item);
73
0
            }
74
0
            ModuleField::Func(f) => {
75
0
                self.expand_type_use(&mut f.ty);
76
0
                if let FuncKind::Inline { expression, .. } = &mut f.kind {
77
0
                    self.expand_expression(expression);
78
0
                }
79
            }
80
0
            ModuleField::Global(g) => {
81
0
                if let GlobalKind::Inline(expr) = &mut g.kind {
82
0
                    self.expand_expression(expr);
83
0
                }
84
            }
85
0
            ModuleField::Data(d) => {
86
0
                if let DataKind::Active { offset, .. } = &mut d.kind {
87
0
                    self.expand_expression(offset);
88
0
                }
89
            }
90
0
            ModuleField::Elem(e) => {
91
0
                if let ElemKind::Active { offset, .. } = &mut e.kind {
92
0
                    self.expand_expression(offset);
93
0
                }
94
0
                if let ElemPayload::Exprs { exprs, .. } = &mut e.payload {
95
0
                    for expr in exprs {
96
0
                        self.expand_expression(expr);
97
0
                    }
98
0
                }
99
            }
100
0
            ModuleField::Tag(t) => match &mut t.ty {
101
0
                TagType::Exception(ty) => {
102
0
                    self.expand_type_use(ty);
103
0
                }
104
            },
105
106
0
            ModuleField::Table(t) => match &mut t.kind {
107
0
                TableKind::Normal { init_expr, .. } => {
108
0
                    if let Some(expr) = init_expr {
109
0
                        self.expand_expression(expr);
110
0
                    }
111
                }
112
0
                TableKind::Import { .. } | TableKind::Inline { .. } => {}
113
            },
114
115
            ModuleField::Memory(_)
116
            | ModuleField::Start(_)
117
            | ModuleField::Export(_)
118
0
            | ModuleField::Custom(_) => {}
119
        }
120
0
    }
121
122
0
    fn expand_item_sig(&mut self, item: &mut ItemSig<'a>) {
123
0
        match &mut item.kind {
124
0
            ItemKind::Func(t) | ItemKind::Tag(TagType::Exception(t)) => {
125
0
                self.expand_type_use(t);
126
0
            }
127
0
            ItemKind::Global(_) | ItemKind::Table(_) | ItemKind::Memory(_) => {}
128
        }
129
0
    }
130
131
0
    fn expand_expression(&mut self, expr: &mut Expression<'a>) {
132
0
        for instr in expr.instrs.iter_mut() {
133
0
            self.expand_instr(instr);
134
0
        }
135
0
    }
136
137
0
    fn expand_instr(&mut self, instr: &mut Instruction<'a>) {
138
0
        match instr {
139
0
            Instruction::Block(bt)
140
0
            | Instruction::If(bt)
141
0
            | Instruction::Loop(bt)
142
0
            | Instruction::Let(LetType { block: bt, .. })
143
0
            | Instruction::Try(bt) => {
144
                // No expansion necessary, a type reference is already here.
145
                // We'll verify that it's the same as the inline type, if any,
146
                // later.
147
0
                if bt.ty.index.is_some() {
148
0
                    return;
149
0
                }
150
0
151
0
                match &bt.ty.inline {
152
                    // Only actually expand `TypeUse` with an index which appends a
153
                    // type if it looks like we need one. This way if the
154
                    // multi-value proposal isn't enabled and/or used we won't
155
                    // encode it.
156
0
                    Some(inline) => {
157
0
                        if inline.params.len() == 0 && inline.results.len() <= 1 {
158
0
                            return;
159
0
                        }
160
                    }
161
162
                    // If we didn't have either an index or an inline type
163
                    // listed then assume our block has no inputs/outputs, so
164
                    // fill in the inline type here.
165
                    //
166
                    // Do not fall through to expanding the `TypeUse` because
167
                    // this doesn't force an empty function type to go into the
168
                    // type section.
169
                    None => {
170
0
                        bt.ty.inline = Some(FunctionType::default());
171
0
                        return;
172
                    }
173
                }
174
0
                self.expand_type_use(&mut bt.ty);
175
            }
176
0
            Instruction::FuncBind(b) => {
177
0
                self.expand_type_use(&mut b.ty);
178
0
            }
179
0
            Instruction::CallIndirect(c) | Instruction::ReturnCallIndirect(c) => {
180
0
                self.expand_type_use(&mut c.ty);
181
0
            }
182
0
            _ => {}
183
        }
184
0
    }
185
186
0
    fn expand_type_use<T>(&mut self, item: &mut TypeUse<'a, T>) -> Index<'a>
187
0
    where
188
0
        T: TypeReference<'a>,
189
0
    {
190
0
        if let Some(idx) = &item.index {
191
0
            return *idx;
192
0
        }
193
0
        let key = match item.inline.as_mut() {
194
0
            Some(ty) => {
195
0
                ty.expand(self);
196
0
                ty.key()
197
            }
198
0
            None => T::default().key(),
199
        };
200
0
        let span = Span::from_offset(0); // FIXME(#613): don't manufacture
201
0
        let idx = self.key_to_idx(span, key);
202
0
        item.index = Some(idx);
203
0
        idx
204
0
    }
205
206
0
    fn key_to_idx(&mut self, span: Span, key: impl TypeKey<'a>) -> Index<'a> {
207
        // First see if this `key` already exists in the type definitions we've
208
        // seen so far...
209
0
        if let Some(idx) = key.lookup(self) {
210
0
            return idx;
211
0
        }
212
0
213
0
        // ... and failing that we insert a new type definition.
214
0
        let id = gensym::gen(span);
215
0
        self.to_prepend.push(ModuleField::Type(Type {
216
0
            span,
217
0
            id: Some(id),
218
0
            name: None,
219
0
            def: key.to_def(span),
220
0
            parent: None,
221
0
            final_type: None,
222
0
        }));
223
0
        let idx = Index::Id(id);
224
0
        key.insert(self, idx);
225
0
        idx
226
0
    }
227
}
228
229
pub(crate) trait TypeReference<'a>: Default {
230
    type Key: TypeKey<'a>;
231
    fn key(&self) -> Self::Key;
232
    fn expand(&mut self, cx: &mut Expander<'a>);
233
}
234
235
pub(crate) trait TypeKey<'a> {
236
    fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>>;
237
    fn to_def(&self, span: Span) -> TypeDef<'a>;
238
    fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>);
239
}
240
241
pub(crate) type FuncKey<'a> = (Box<[ValType<'a>]>, Box<[ValType<'a>]>);
242
243
impl<'a> TypeReference<'a> for FunctionType<'a> {
244
    type Key = FuncKey<'a>;
245
246
0
    fn key(&self) -> Self::Key {
247
0
        let params = self.params.iter().map(|p| p.2).collect();
248
0
        let results = self.results.clone();
249
0
        (params, results)
250
0
    }
251
252
0
    fn expand(&mut self, _cx: &mut Expander<'a>) {}
253
}
254
255
impl<'a> TypeKey<'a> for FuncKey<'a> {
256
0
    fn lookup(&self, cx: &Expander<'a>) -> Option<Index<'a>> {
257
0
        cx.func_type_to_idx.get(self).cloned()
258
0
    }
259
260
0
    fn to_def(&self, _span: Span) -> TypeDef<'a> {
261
0
        TypeDef::Func(FunctionType {
262
0
            params: self.0.iter().map(|t| (None, None, *t)).collect(),
263
0
            results: self.1.clone(),
264
0
        })
265
0
    }
266
267
0
    fn insert(&self, cx: &mut Expander<'a>, idx: Index<'a>) {
268
0
        cx.func_type_to_idx.entry(self.clone()).or_insert(idx);
269
0
    }
270
}