Skip to main content

baedeker_core/validate/
mod.rs

1// Copyright (C) 2026 Industrial Algebra
2// SPDX-License-Identifier: Apache-2.0
3
4//! WebAssembly validation.
5//!
6//! This module begins Phase 1 validation with a deliberately small but useful subset:
7//! - function type index resolution
8//! - local index validation
9//! - call target validation
10//! - basic structured control-flow balancing
11//! - basic operand/result typing for a small instruction subset
12//!
13//! Validation errors are reported against precise instruction byte offsets so
14//! malformed functions can be diagnosed at the failing opcode rather than only
15//! at the enclosing function body.
16
17pub mod error;
18pub mod state;
19
20use alloc::{collections::BTreeSet, vec, vec::Vec};
21
22use crate::binary::instr::{DecodedInstr, Instr, decode_instr_sequence_with_offsets};
23use crate::binary::module::Module;
24use crate::error::ByteOffset;
25use crate::types::{
26    BlockType, DataIdx, DataMode, ElemIdx, ElementInit, ElementMode, ExportDesc, FuncIdx, FuncType,
27    GlobalIdx, ImportDesc, LocalDecl, MemIdx, Mutability, RefType, TableIdx, TypeIdx, ValType,
28};
29use crate::validate::error::{ValidationError, ValidationErrorKind};
30use crate::validate::state::{ControlKind::*, OperandType, Reachability, ValidationState};
31
32pub use error::{ValidationError as Error, ValidationErrorKind as ErrorKind};
33pub use state::{
34    ControlFrame, OperandType as ValidationOperandType, Reachability as ValidationReachability,
35    TypeStack, ValidationState as FunctionValidationState,
36};
37
38impl<'a> Module<'a> {
39    /// Validate the currently decoded subset of the module.
40    pub fn validate(&self) -> Result<(), ValidationError> {
41        validate_module(self)
42    }
43}
44
45/// Validate a decoded module.
46pub fn validate_module(module: &Module<'_>) -> Result<(), ValidationError> {
47    for &type_idx in &module.functions {
48        if module.types.get(type_idx.0 as usize).is_none() {
49            return Err(ValidationError {
50                offset: ByteOffset(0),
51                function: None,
52                kind: ValidationErrorKind::UnknownTypeIdx { idx: type_idx },
53            });
54        }
55    }
56
57    validate_type_definitions(module)?;
58    validate_imports(module)?;
59    validate_tables(module)?;
60    validate_memories(module)?;
61    validate_globals(module)?;
62    validate_data_segments(module)?;
63    validate_bulk_memory(module)?;
64    validate_exports(module)?;
65    validate_elements(module)?;
66    validate_start(module)?;
67
68    for (func_idx, (type_idx, code)) in module.functions.iter().zip(module.codes()).enumerate() {
69        let ty = &module.types[type_idx.0 as usize];
70        validate_function(
71            module,
72            FuncIdx(func_idx as u32),
73            ty,
74            code.locals.as_slice(),
75            code,
76        )?;
77    }
78
79    Ok(())
80}
81
82fn validate_type_definitions(module: &Module<'_>) -> Result<(), ValidationError> {
83    let offset = module
84        .section(crate::binary::section::SectionId::Type)
85        .map(|section| section.offset)
86        .unwrap_or(0);
87
88    for (idx, ty) in module.types.iter().enumerate() {
89        validate_func_type_definition_type_indices(module, TypeIdx(idx as u32), ty, offset)?;
90    }
91
92    Ok(())
93}
94
95fn validate_imports(module: &Module<'_>) -> Result<(), ValidationError> {
96    let offset = module
97        .section(crate::binary::section::SectionId::Import)
98        .map(|section| section.offset)
99        .unwrap_or(0);
100
101    for import in module.imports() {
102        match &import.desc {
103            ImportDesc::Func(type_idx) => {
104                if module.types.get(type_idx.0 as usize).is_none() {
105                    return Err(ValidationError {
106                        offset: ByteOffset(offset),
107                        function: None,
108                        kind: ValidationErrorKind::UnknownTypeIdx { idx: *type_idx },
109                    });
110                }
111            }
112            ImportDesc::Table(table) => {
113                validate_reftype_type_indices(module, table.elem, None, offset)?;
114            }
115            ImportDesc::Global(global) => {
116                validate_valtype_type_indices(module, global.val_type, None, offset)?;
117            }
118            ImportDesc::Mem(_) => {}
119        }
120    }
121
122    Ok(())
123}
124
125fn validate_memories(module: &Module<'_>) -> Result<(), ValidationError> {
126    let offset = module
127        .section(crate::binary::section::SectionId::Memory)
128        .map(|section| section.offset)
129        .unwrap_or(0);
130
131    // Spec limits: at most 65536 pages, and min must not exceed max.
132    for import in module.imports() {
133        if let crate::types::ImportDesc::Mem(memory) = import.desc {
134            validate_memory_limits(memory.limits, offset)?;
135        }
136    }
137    for memory in &module.memories {
138        validate_memory_limits(memory.limits, offset)?;
139    }
140
141    Ok(())
142}
143
144fn validate_memory_limits(
145    limits: crate::types::Limits,
146    offset: usize,
147) -> Result<(), ValidationError> {
148    const MAX_PAGES: u32 = 65536;
149    if limits.min > MAX_PAGES || limits.max.is_some_and(|max| max > MAX_PAGES) {
150        return Err(ValidationError {
151            offset: ByteOffset(offset),
152            function: None,
153            kind: ValidationErrorKind::MemorySizeOutOfRange,
154        });
155    }
156    if limits.max.is_some_and(|max| limits.min > max) {
157        return Err(ValidationError {
158            offset: ByteOffset(offset),
159            function: None,
160            kind: ValidationErrorKind::MemoryMinExceedsMax,
161        });
162    }
163    Ok(())
164}
165
166fn validate_tables(module: &Module<'_>) -> Result<(), ValidationError> {
167    let offset = module
168        .section(crate::binary::section::SectionId::Table)
169        .map(|section| section.offset)
170        .unwrap_or(0);
171
172    for table in &module.tables {
173        validate_reftype_type_indices(module, table.elem, None, offset)?;
174        // Limits: min must not exceed max.
175        if table.limits.max.is_some_and(|max| table.limits.min > max) {
176            return Err(ValidationError {
177                offset: ByteOffset(offset),
178                function: None,
179                kind: ValidationErrorKind::MemoryMinExceedsMax,
180            });
181        }
182        // A table with a non-nullable element type needs an initializer —
183        // there is no default value to fill with.
184        if table.init.is_none()
185            && matches!(
186                table.elem,
187                crate::types::RefType::Typed {
188                    nullable: false,
189                    ..
190                }
191            )
192        {
193            return Err(ValidationError {
194                offset: ByteOffset(offset),
195                function: None,
196                kind: ValidationErrorKind::TableTypeMismatch,
197            });
198        }
199        if let Some(init) = &table.init {
200            // Table init exprs reference imported globals only (matching the
201            // global-init scope).
202            validate_const_expr(
203                module,
204                init,
205                offset,
206                normalize_valtype(module, ValType::Ref(table.elem)),
207                ConstExprGlobalScope::ImportedPlusDefined {
208                    defined_globals_available: 0,
209                },
210                ConstExprKind::GlobalInit,
211            )?;
212        }
213    }
214
215    Ok(())
216}
217
218fn validate_globals(module: &Module<'_>) -> Result<(), ValidationError> {
219    let offset = module
220        .section(crate::binary::section::SectionId::Global)
221        .map(|section| section.offset)
222        .unwrap_or(0);
223
224    for (defined_globals_available, global) in module.globals().iter().enumerate() {
225        validate_valtype_type_indices(module, global.global_type.val_type, None, offset)?;
226        validate_global_init_expr(module, global, defined_globals_available)?;
227    }
228    Ok(())
229}
230
231#[derive(Debug, Clone, Copy)]
232enum ConstExprGlobalScope {
233    ImportedPlusDefined { defined_globals_available: usize },
234    All,
235}
236
237#[derive(Debug, Clone, Copy)]
238enum ConstExprKind {
239    GlobalInit,
240    ElementExpr,
241    I32Offset,
242}
243
244fn validate_global_init_expr(
245    module: &Module<'_>,
246    global: &crate::types::Global<'_>,
247    defined_globals_available: usize,
248) -> Result<(), ValidationError> {
249    let expected = normalize_valtype(module, global.global_type.val_type);
250    validate_const_expr(
251        module,
252        global.init_expr,
253        global.init_offset,
254        expected,
255        ConstExprGlobalScope::ImportedPlusDefined {
256            defined_globals_available,
257        },
258        ConstExprKind::GlobalInit,
259    )
260}
261
262fn resolve_const_global_val_type(
263    module: &Module<'_>,
264    idx: GlobalIdx,
265    offset: usize,
266    scope: ConstExprGlobalScope,
267) -> Result<ValType, ValidationError> {
268    let imported_globals = module
269        .imports
270        .iter()
271        .filter_map(|import| match import.desc {
272            ImportDesc::Global(global) => Some(global),
273            _ => None,
274        });
275    let defined_globals = module.globals.iter().map(|global| global.global_type);
276
277    let available_globals: Vec<_> = match scope {
278        ConstExprGlobalScope::ImportedPlusDefined {
279            defined_globals_available,
280        } => imported_globals
281            .chain(defined_globals.take(defined_globals_available))
282            .collect(),
283        ConstExprGlobalScope::All => imported_globals.chain(defined_globals).collect(),
284    };
285
286    let available = available_globals.len() as u32;
287    let global_type = available_globals
288        .get(idx.0 as usize)
289        .copied()
290        .ok_or(ValidationError {
291            offset: ByteOffset(offset),
292            function: None,
293            kind: ValidationErrorKind::UnknownGlobalIdx { idx, available },
294        })?;
295
296    if global_type.mutability != Mutability::Const {
297        return Err(ValidationError {
298            offset: ByteOffset(offset),
299            function: None,
300            kind: ValidationErrorKind::MutableGlobalInInitExpr { idx },
301        });
302    }
303
304    Ok(normalize_valtype(module, global_type.val_type))
305}
306
307fn validate_data_segments(module: &Module<'_>) -> Result<(), ValidationError> {
308    if let Some(count) = module.data_count()
309        && count as usize != module.data().len()
310    {
311        return Err(ValidationError {
312            offset: ByteOffset(0),
313            function: None,
314            kind: ValidationErrorKind::UnknownDataIdx {
315                idx: DataIdx(count),
316                available: module.data().len() as u32,
317            },
318        });
319    }
320
321    for segment in module.data() {
322        if let DataMode::Active {
323            memory,
324            offset_expr,
325            offset_offset,
326        } = &segment.mode
327        {
328            resolve_memory_type(module, *memory, FuncIdx(0), *offset_offset)?;
329            validate_const_i32_expr(module, offset_expr, *offset_offset)?;
330        }
331    }
332
333    Ok(())
334}
335
336fn validate_const_i32_expr(
337    module: &Module<'_>,
338    expr: &[u8],
339    offset: usize,
340) -> Result<(), ValidationError> {
341    validate_const_expr(
342        module,
343        expr,
344        offset,
345        ValType::Num(crate::types::NumType::I32),
346        ConstExprGlobalScope::All,
347        ConstExprKind::I32Offset,
348    )
349}
350
351fn validate_const_ref_expr(
352    module: &Module<'_>,
353    expr: &[u8],
354    offset: usize,
355    expected: RefType,
356) -> Result<(), ValidationError> {
357    validate_const_expr(
358        module,
359        expr,
360        offset,
361        normalize_valtype(module, ValType::Ref(expected)),
362        ConstExprGlobalScope::All,
363        ConstExprKind::ElementExpr,
364    )
365}
366
367fn validate_const_expr(
368    module: &Module<'_>,
369    expr: &[u8],
370    offset: usize,
371    expected: ValType,
372    global_scope: ConstExprGlobalScope,
373    kind: ConstExprKind,
374) -> Result<(), ValidationError> {
375    let instrs = decode_instr_sequence_with_offsets(expr, offset).map_err(|e| ValidationError {
376        offset: e.offset,
377        function: None,
378        kind: e.into(),
379    })?;
380
381    if !matches!(
382        instrs.last().map(|decoded| &decoded.instr),
383        Some(Instr::End)
384    ) {
385        return Err(const_expr_invalid_shape_error(kind, ByteOffset(offset)));
386    }
387
388    let mut stack = Vec::new();
389    for decoded in &instrs[..instrs.len().saturating_sub(1)] {
390        validate_const_instr(module, &mut stack, decoded, global_scope, kind)?;
391    }
392
393    if stack.len() != 1 {
394        return Err(const_expr_invalid_shape_error(
395            kind,
396            instrs
397                .first()
398                .map(|decoded| decoded.offset)
399                .unwrap_or(ByteOffset(offset)),
400        ));
401    }
402
403    let found = stack.pop().expect("const expr stack length checked");
404    if !valtype_matches(found, expected) {
405        return Err(match kind {
406            ConstExprKind::GlobalInit | ConstExprKind::I32Offset => ValidationError {
407                offset: instrs
408                    .first()
409                    .map(|decoded| decoded.offset)
410                    .unwrap_or(ByteOffset(offset)),
411                function: None,
412                kind: ValidationErrorKind::GlobalInitTypeMismatch { expected, found },
413            },
414            ConstExprKind::ElementExpr => ValidationError {
415                offset: instrs
416                    .first()
417                    .map(|decoded| decoded.offset)
418                    .unwrap_or(ByteOffset(offset)),
419                function: None,
420                kind: ValidationErrorKind::ElementExprTypeMismatch { expected, found },
421            },
422        });
423    }
424
425    Ok(())
426}
427
428fn validate_const_instr(
429    module: &Module<'_>,
430    stack: &mut Vec<ValType>,
431    decoded: &DecodedInstr,
432    global_scope: ConstExprGlobalScope,
433    kind: ConstExprKind,
434) -> Result<(), ValidationError> {
435    match decoded.instr {
436        Instr::I32Const(_) if !matches!(kind, ConstExprKind::ElementExpr) => {
437            stack.push(ValType::Num(crate::types::NumType::I32));
438        }
439        Instr::I64Const(_) if !matches!(kind, ConstExprKind::ElementExpr) => {
440            stack.push(ValType::Num(crate::types::NumType::I64));
441        }
442        Instr::F32Const(_) if !matches!(kind, ConstExprKind::ElementExpr) => {
443            stack.push(ValType::Num(crate::types::NumType::F32));
444        }
445        Instr::F64Const(_) if !matches!(kind, ConstExprKind::ElementExpr) => {
446            stack.push(ValType::Num(crate::types::NumType::F64));
447        }
448        Instr::RefNull(ref_type) => {
449            validate_reftype_type_indices(module, ref_type, None, decoded.offset.0)?;
450            stack.push(normalize_valtype(module, ValType::Ref(ref_type)));
451        }
452        Instr::RefFunc(idx) => {
453            let type_idx = resolve_func_type_idx_for_module(module, idx, decoded.offset.0)?;
454            if !is_declared_function_ref(module, idx) {
455                return Err(ValidationError {
456                    offset: decoded.offset,
457                    function: None,
458                    kind: ValidationErrorKind::UndeclaredFuncRef { idx },
459                });
460            }
461            stack.push(ValType::Ref(RefType::concrete(false, type_idx)));
462        }
463        Instr::GlobalGet(idx) => stack.push(resolve_const_global_val_type(
464            module,
465            idx,
466            decoded.offset.0,
467            global_scope,
468        )?),
469        Instr::I32Add | Instr::I32Sub | Instr::I32Mul
470            if matches!(kind, ConstExprKind::GlobalInit | ConstExprKind::I32Offset) =>
471        {
472            pop_const_expect(
473                stack,
474                ValType::Num(crate::types::NumType::I32),
475                decoded.offset,
476                kind,
477            )?;
478            pop_const_expect(
479                stack,
480                ValType::Num(crate::types::NumType::I32),
481                decoded.offset,
482                kind,
483            )?;
484            stack.push(ValType::Num(crate::types::NumType::I32));
485        }
486        Instr::I64Add | Instr::I64Sub | Instr::I64Mul
487            if matches!(kind, ConstExprKind::GlobalInit) =>
488        {
489            pop_const_expect(
490                stack,
491                ValType::Num(crate::types::NumType::I64),
492                decoded.offset,
493                kind,
494            )?;
495            pop_const_expect(
496                stack,
497                ValType::Num(crate::types::NumType::I64),
498                decoded.offset,
499                kind,
500            )?;
501            stack.push(ValType::Num(crate::types::NumType::I64));
502        }
503        _ => return Err(const_expr_non_constant_error(kind, decoded.offset)),
504    }
505
506    Ok(())
507}
508
509fn pop_const_expect(
510    stack: &mut Vec<ValType>,
511    expected: ValType,
512    offset: ByteOffset,
513    kind: ConstExprKind,
514) -> Result<(), ValidationError> {
515    let Some(found) = stack.pop() else {
516        return Err(match kind {
517            ConstExprKind::ElementExpr => ValidationError {
518                offset,
519                function: None,
520                kind: ValidationErrorKind::ElementExprTypeMismatch {
521                    expected,
522                    found: expected,
523                },
524            },
525            ConstExprKind::GlobalInit | ConstExprKind::I32Offset => ValidationError {
526                offset,
527                function: None,
528                kind: ValidationErrorKind::GlobalInitTypeMismatch {
529                    expected,
530                    found: expected,
531                },
532            },
533        });
534    };
535
536    if !valtype_matches(found, expected) {
537        return Err(match kind {
538            ConstExprKind::ElementExpr => ValidationError {
539                offset,
540                function: None,
541                kind: ValidationErrorKind::ElementExprTypeMismatch { expected, found },
542            },
543            ConstExprKind::GlobalInit | ConstExprKind::I32Offset => ValidationError {
544                offset,
545                function: None,
546                kind: ValidationErrorKind::GlobalInitTypeMismatch { expected, found },
547            },
548        });
549    }
550
551    Ok(())
552}
553
554fn const_expr_non_constant_error(kind: ConstExprKind, offset: ByteOffset) -> ValidationError {
555    let kind = match kind {
556        ConstExprKind::GlobalInit | ConstExprKind::I32Offset => {
557            ValidationErrorKind::NonConstantGlobalInitExpr
558        }
559        ConstExprKind::ElementExpr => ValidationErrorKind::NonConstantElementExpr,
560    };
561    ValidationError {
562        offset,
563        function: None,
564        kind,
565    }
566}
567
568fn const_expr_invalid_shape_error(kind: ConstExprKind, offset: ByteOffset) -> ValidationError {
569    let kind = match kind {
570        ConstExprKind::GlobalInit | ConstExprKind::I32Offset => {
571            ValidationErrorKind::InvalidGlobalInitExpr
572        }
573        ConstExprKind::ElementExpr => ValidationErrorKind::InvalidElementExpr,
574    };
575    ValidationError {
576        offset,
577        function: None,
578        kind,
579    }
580}
581
582fn validate_bulk_memory(module: &Module<'_>) -> Result<(), ValidationError> {
583    if module.data_count().is_some() {
584        return Ok(());
585    }
586
587    for (func_idx, code) in module.codes().iter().enumerate() {
588        let function = FuncIdx(func_idx as u32);
589        let instrs = code
590            .instructions_with_offsets()
591            .map_err(|e| ValidationError {
592                offset: e.offset,
593                function: Some(function),
594                kind: e.into(),
595            })?;
596
597        for decoded in instrs {
598            let op = match decoded.instr {
599                Instr::MemoryInit(_, _) => Some("memory.init"),
600                Instr::DataDrop(_) => Some("data.drop"),
601                _ => None,
602            };
603
604            if let Some(op) = op {
605                return Err(ValidationError {
606                    offset: decoded.offset,
607                    function: Some(function),
608                    kind: ValidationErrorKind::MissingDataCountSection { op },
609                });
610            }
611        }
612    }
613
614    Ok(())
615}
616
617fn validate_exports(module: &Module<'_>) -> Result<(), ValidationError> {
618    let offset = module
619        .section(crate::binary::section::SectionId::Export)
620        .map(|section| section.offset)
621        .unwrap_or(0);
622    let mut names = BTreeSet::new();
623
624    for export in module.exports() {
625        if !names.insert(export.name.as_str()) {
626            return Err(ValidationError {
627                offset: ByteOffset(offset),
628                function: None,
629                kind: ValidationErrorKind::DuplicateExportName {
630                    name: export.name.clone(),
631                },
632            });
633        }
634
635        match export.desc {
636            ExportDesc::Func(idx) => {
637                let _ = resolve_func_type_for_module(module, idx, offset)?;
638            }
639            ExportDesc::Table(idx) => {
640                let _ = resolve_table_type_for_module(module, idx, offset)?;
641            }
642            ExportDesc::Mem(idx) => {
643                let _ = resolve_memory_type_for_module(module, idx, offset)?;
644            }
645            ExportDesc::Global(idx) => {
646                let _ = resolve_global_type_for_module(module, idx, offset)?;
647            }
648        }
649    }
650
651    Ok(())
652}
653
654fn validate_elements(module: &Module<'_>) -> Result<(), ValidationError> {
655    let section_offset = module
656        .section(crate::binary::section::SectionId::Element)
657        .map(|section| section.offset)
658        .unwrap_or(0);
659
660    for element in module.elements() {
661        validate_reftype_type_indices(module, element.elem_type, None, section_offset)?;
662
663        if let ElementMode::Active {
664            table,
665            offset_expr,
666            offset_offset,
667        } = &element.mode
668        {
669            let table_type = resolve_table_type_for_module(module, *table, *offset_offset)?;
670            let elem_type = normalize_reftype(module, element.elem_type);
671            // FuncIndices segments carry only `ref.func` values, which are
672            // non-null by construction, so they fit both `funcref` and
673            // non-null `(ref func)` tables. Expression segments match on
674            // their declared type.
675            let matches = match &element.init {
676                crate::types::ElementInit::FuncIndices(_) => matches!(
677                    table_type.elem,
678                    RefType::FuncRef
679                        | RefType::Typed {
680                            heap: crate::types::HeapType::Func,
681                            ..
682                        }
683                ),
684                crate::types::ElementInit::Expressions(_) => {
685                    reftype_matches(elem_type, table_type.elem)
686                }
687            };
688            if !matches {
689                return Err(ValidationError {
690                    offset: ByteOffset(*offset_offset),
691                    function: None,
692                    kind: ValidationErrorKind::ElementTableTypeMismatch {
693                        expected: table_type.elem,
694                        found: elem_type,
695                    },
696                });
697            }
698            validate_const_i32_expr(module, offset_expr, *offset_offset)?;
699        }
700
701        match &element.init {
702            ElementInit::FuncIndices(funcs) => {
703                for &func in funcs {
704                    let _ = resolve_func_type_for_module(module, func, section_offset)?;
705                }
706            }
707            ElementInit::Expressions(exprs) => {
708                for expr in exprs {
709                    validate_const_ref_expr(
710                        module,
711                        expr.expr,
712                        expr.offset,
713                        normalize_reftype(module, element.elem_type),
714                    )?;
715                }
716            }
717        }
718    }
719
720    Ok(())
721}
722
723fn validate_start(module: &Module<'_>) -> Result<(), ValidationError> {
724    let Some(start) = module.start() else {
725        return Ok(());
726    };
727
728    let offset = module
729        .section(crate::binary::section::SectionId::Start)
730        .map(|section| section.offset)
731        .unwrap_or(0);
732    let ty = resolve_func_type_for_module(module, start, offset)?;
733
734    if !ty.params.is_empty() || !ty.results.is_empty() {
735        return Err(ValidationError {
736            offset: ByteOffset(offset),
737            function: None,
738            kind: ValidationErrorKind::InvalidStartFunctionType {
739                params: ty.params.clone(),
740                results: ty.results.clone(),
741            },
742        });
743    }
744
745    Ok(())
746}
747
748fn validate_function(
749    module: &Module<'_>,
750    function: FuncIdx,
751    ty: &FuncType,
752    local_decls: &[LocalDecl],
753    code: &crate::types::CodeBody<'_>,
754) -> Result<(), ValidationError> {
755    let ty = normalize_func_type(module, ty);
756    let mut locals = ty.params.clone();
757    expand_locals(module, function, &mut locals, local_decls, code.body_offset)?;
758
759    let instrs = code
760        .instructions_with_offsets()
761        .map_err(|e| ValidationError {
762            offset: e.offset,
763            function: Some(function),
764            kind: e.into(),
765        })?;
766
767    let local_inits = initial_local_inits(&locals, ty.params.len());
768    let mut state = ValidationState::new(locals, local_inits, ty.results.clone());
769
770    for decoded in &instrs {
771        validate_instr(module, function, decoded, &mut state)?;
772    }
773
774    if state.controls.len() != 1 {
775        return Err(ValidationError {
776            offset: ByteOffset(code.body_offset),
777            function: Some(function),
778            kind: ValidationErrorKind::UnterminatedControlFrames,
779        });
780    }
781
782    if ensure_frame_end_types(
783        &state,
784        state.controls[0].outer_height,
785        &state.controls[0].end_types,
786    )
787    .is_err()
788    {
789        let full_stack = concrete_stack(&state);
790        let found_len = core::cmp::min(full_stack.len(), ty.results.len());
791        let found = full_stack[full_stack.len().saturating_sub(found_len)..].to_vec();
792        return Err(ValidationError {
793            offset: final_result_offset(code, &instrs),
794            function: Some(function),
795            kind: ValidationErrorKind::FunctionResultTypeMismatch {
796                expected: ty.results.clone(),
797                found,
798                full_stack,
799            },
800        });
801    }
802
803    Ok(())
804}
805
806fn final_result_offset(code: &crate::types::CodeBody<'_>, instrs: &[DecodedInstr]) -> ByteOffset {
807    instrs
808        .last()
809        .map(|decoded| decoded.offset)
810        .unwrap_or(ByteOffset(code.body_offset))
811}
812
813fn initial_local_inits(locals: &[ValType], param_count: usize) -> Vec<bool> {
814    locals
815        .iter()
816        .enumerate()
817        .map(|(idx, ty)| idx < param_count || valtype_is_defaultable(*ty))
818        .collect()
819}
820
821fn valtype_is_defaultable(ty: ValType) -> bool {
822    match ty {
823        ValType::Num(_) | ValType::Vec(_) => true,
824        ValType::Ref(ref_type) => ref_type.is_nullable(),
825    }
826}
827
828fn validate_instr(
829    module: &Module<'_>,
830    function: FuncIdx,
831    decoded: &DecodedInstr,
832    state: &mut ValidationState,
833) -> Result<(), ValidationError> {
834    let offset = decoded.offset.0;
835
836    match &decoded.instr {
837        Instr::Unreachable => state.enter_unreachable(),
838        Instr::Nop => {}
839        Instr::Else => {
840            let (outer_height, start_types, end_types, local_inits) = {
841                let frame = state.current_frame_mut();
842                if frame.kind != If {
843                    return Err(ValidationError {
844                        offset: ByteOffset(offset),
845                        function: Some(function),
846                        kind: ValidationErrorKind::ElseOutsideIf,
847                    });
848                }
849                if frame.has_else {
850                    return Err(ValidationError {
851                        offset: ByteOffset(offset),
852                        function: Some(function),
853                        kind: ValidationErrorKind::UnexpectedElse,
854                    });
855                }
856                frame.has_else = true;
857                (
858                    frame.outer_height,
859                    frame.start_types.clone(),
860                    frame.end_types.clone(),
861                    frame.local_inits.clone(),
862                )
863            };
864            // The then-body must have produced exactly the frame's result
865            // types before the stack resets for the else-body.
866            if let Err(found) = ensure_frame_end_types(state, outer_height, &end_types) {
867                return Err(ValidationError {
868                    offset: ByteOffset(offset),
869                    function: Some(function),
870                    kind: ValidationErrorKind::ControlResultTypeMismatch {
871                        expected: end_types.clone(),
872                        found,
873                    },
874                });
875            }
876            pop_control_result_types(function, state, &end_types, offset)?;
877            state.operands.truncate(outer_height);
878            state.local_inits = local_inits;
879            for ty in start_types {
880                state.operands.push(ty);
881            }
882            let floor = state.operands.len();
883            let frame = state.current_frame_mut();
884            frame.stack_floor = floor;
885            state.reachability = Reachability::Reachable;
886        }
887        Instr::Block(block_type) => {
888            let sig = resolve_block_type(module, function, *block_type, offset)?;
889            pop_exact(function, state, &sig.params, offset)?;
890            state.push_frame(Block, *block_type, sig.params, sig.results);
891        }
892        Instr::Loop(block_type) => {
893            let sig = resolve_block_type(module, function, *block_type, offset)?;
894            pop_exact(function, state, &sig.params, offset)?;
895            state.push_frame(Loop, *block_type, sig.params, sig.results);
896        }
897        Instr::If(block_type) => {
898            pop_expect(
899                function,
900                state,
901                ValType::Num(crate::types::NumType::I32),
902                offset,
903                "if",
904            )?;
905            let sig = resolve_block_type(module, function, *block_type, offset)?;
906            pop_exact(function, state, &sig.params, offset)?;
907            state.push_frame(If, *block_type, sig.params, sig.results);
908        }
909        Instr::End => {
910            if state.controls.len() > 1 {
911                finish_frame(function, state, offset)?;
912            }
913        }
914        Instr::Br(label) => {
915            let label_types = validate_label(function, state, *label, offset)?.to_vec();
916            pop_branch_types(function, state, *label, &label_types, offset)?;
917            state.enter_unreachable();
918        }
919        Instr::BrIf(label) => {
920            pop_expect(
921                function,
922                state,
923                ValType::Num(crate::types::NumType::I32),
924                offset,
925                "br_if",
926            )?;
927            let label_types = validate_label(function, state, *label, offset)?.to_vec();
928            pop_branch_types(function, state, *label, &label_types, offset)?;
929            for ty in label_types {
930                state.operands.push(ty);
931            }
932        }
933        Instr::BrOnNull(label) => {
934            let label_types = validate_label(function, state, *label, offset)?.to_vec();
935            let found = pop_ref_type(function, state, offset, "br_on_null")?;
936            pop_branch_types(function, state, *label, &label_types, offset)?;
937            for ty in label_types {
938                state.operands.push(ty);
939            }
940            match found {
941                Some(found) => state.operands.push(ValType::Ref(found.as_non_null())),
942                None => state.operands.push_bottom(),
943            }
944        }
945        Instr::BrOnNonNull(label) => {
946            let label_types = validate_label(function, state, *label, offset)?.to_vec();
947            let Some((ValType::Ref(expected), rest)) = label_types.split_last() else {
948                return Err(ValidationError {
949                    offset: ByteOffset(offset),
950                    function: Some(function),
951                    kind: ValidationErrorKind::InvalidBrOnNonNullTarget {
952                        label: *label,
953                        found: label_types,
954                    },
955                });
956            };
957            let found = pop_ref_type(function, state, offset, "br_on_non_null")?;
958            let expected_input = expected.as_nullable();
959            if let Some(found) = found
960                && !reftype_matches(found, expected_input)
961            {
962                return Err(ValidationError {
963                    offset: ByteOffset(offset),
964                    function: Some(function),
965                    kind: ValidationErrorKind::TypeMismatch {
966                        op: "br_on_non_null",
967                        expected: ValType::Ref(expected_input),
968                        found: ValType::Ref(found),
969                    },
970                });
971            }
972            pop_branch_types(function, state, *label, rest, offset)?;
973            for ty in rest {
974                state.operands.push(*ty);
975            }
976        }
977        Instr::BrTable { targets, default } => {
978            pop_expect(
979                function,
980                state,
981                ValType::Num(crate::types::NumType::I32),
982                offset,
983                "br_table",
984            )?;
985            let default_types = validate_label(function, state, *default, offset)?.to_vec();
986            // Every target must agree on arity; the operand must be a
987            // subtype of each target's label types (they need not be
988            // identical — the join is the operand's own type).
989            for label in targets {
990                let label_types = validate_label(function, state, *label, offset)?;
991                if label_types.len() != default_types.len() {
992                    return Err(ValidationError {
993                        offset: ByteOffset(offset),
994                        function: Some(function),
995                        kind: ValidationErrorKind::InconsistentBranchTypes {
996                            expected: default_types.clone(),
997                            found: label_types.to_vec(),
998                        },
999                    });
1000                }
1001                ensure_stack_types(state, label_types).map_err(|found| ValidationError {
1002                    offset: ByteOffset(offset),
1003                    function: Some(function),
1004                    kind: ValidationErrorKind::BranchTypeMismatch {
1005                        label: *label,
1006                        expected: label_types.to_vec(),
1007                        found,
1008                    },
1009                })?;
1010            }
1011            ensure_stack_types(state, &default_types).map_err(|found| ValidationError {
1012                offset: ByteOffset(offset),
1013                function: Some(function),
1014                kind: ValidationErrorKind::BranchTypeMismatch {
1015                    label: *default,
1016                    expected: default_types.clone(),
1017                    found,
1018                },
1019            })?;
1020            pop_exact(function, state, &default_types, offset)?;
1021            state.enter_unreachable();
1022        }
1023        Instr::Return => {
1024            let expected = state.controls[0].end_types.clone();
1025            pop_control_result_types(function, state, &expected, offset)?;
1026            state.enter_unreachable();
1027        }
1028        Instr::Call(idx) => {
1029            let ty = resolve_func_type(module, *idx, function, offset)?;
1030            pop_exact(function, state, &ty.params, offset)?;
1031            for result in &ty.results {
1032                state.operands.push(*result);
1033            }
1034        }
1035        Instr::ReturnCall(idx) => {
1036            let ty = resolve_func_type(module, *idx, function, offset)?;
1037            validate_tail_call_results(function, state, &ty.results, offset)?;
1038            pop_exact(function, state, &ty.params, offset)?;
1039            state.enter_unreachable();
1040        }
1041        Instr::CallRef(type_idx) => {
1042            let ty = resolve_type(module, *type_idx, Some(function), offset)?;
1043            pop_expect(
1044                function,
1045                state,
1046                ValType::Ref(RefType::concrete(
1047                    true,
1048                    canonicalize_func_type_idx(module, *type_idx),
1049                )),
1050                offset,
1051                "call_ref",
1052            )?;
1053            pop_exact(function, state, &ty.params, offset)?;
1054            for result in &ty.results {
1055                state.operands.push(*result);
1056            }
1057        }
1058        Instr::ReturnCallRef(type_idx) => {
1059            let ty = resolve_type(module, *type_idx, Some(function), offset)?;
1060            validate_tail_call_results(function, state, &ty.results, offset)?;
1061            pop_expect(
1062                function,
1063                state,
1064                ValType::Ref(RefType::concrete(
1065                    true,
1066                    canonicalize_func_type_idx(module, *type_idx),
1067                )),
1068                offset,
1069                "return_call_ref",
1070            )?;
1071            pop_exact(function, state, &ty.params, offset)?;
1072            state.enter_unreachable();
1073        }
1074        Instr::CallIndirect {
1075            type_idx,
1076            table_idx,
1077        } => {
1078            let table_type =
1079                resolve_table_type_with_context(module, *table_idx, Some(function), offset)?;
1080            if !reftype_matches(table_type.elem, RefType::FuncRef) {
1081                return Err(ValidationError {
1082                    offset: ByteOffset(offset),
1083                    function: Some(function),
1084                    kind: ValidationErrorKind::InvalidCallIndirectTableType {
1085                        expected: RefType::FuncRef,
1086                        found: table_type.elem,
1087                    },
1088                });
1089            }
1090            let ty = resolve_type(module, *type_idx, Some(function), offset)?;
1091            pop_expect(
1092                function,
1093                state,
1094                ValType::Num(crate::types::NumType::I32),
1095                offset,
1096                "call_indirect",
1097            )?;
1098            pop_exact(function, state, &ty.params, offset)?;
1099            for result in &ty.results {
1100                state.operands.push(*result);
1101            }
1102        }
1103        Instr::ReturnCallIndirect {
1104            type_idx,
1105            table_idx,
1106        } => {
1107            let table_type =
1108                resolve_table_type_with_context(module, *table_idx, Some(function), offset)?;
1109            if !reftype_matches(table_type.elem, RefType::FuncRef) {
1110                return Err(ValidationError {
1111                    offset: ByteOffset(offset),
1112                    function: Some(function),
1113                    kind: ValidationErrorKind::InvalidCallIndirectTableType {
1114                        expected: RefType::FuncRef,
1115                        found: table_type.elem,
1116                    },
1117                });
1118            }
1119            let ty = resolve_type(module, *type_idx, Some(function), offset)?;
1120            validate_tail_call_results(function, state, &ty.results, offset)?;
1121            pop_expect(
1122                function,
1123                state,
1124                ValType::Num(crate::types::NumType::I32),
1125                offset,
1126                "return_call_indirect",
1127            )?;
1128            pop_exact(function, state, &ty.params, offset)?;
1129            state.enter_unreachable();
1130        }
1131        Instr::Drop => {
1132            pop_any(function, state, offset, "drop")?;
1133        }
1134        Instr::Select => {
1135            pop_expect(
1136                function,
1137                state,
1138                ValType::Num(crate::types::NumType::I32),
1139                offset,
1140                "select",
1141            )?;
1142            let rhs = pop_operand_type(function, state, offset, "select")?;
1143            let lhs = pop_operand_type(function, state, offset, "select")?;
1144            match (lhs, rhs) {
1145                (OperandType::Bottom, OperandType::Bottom) => state.operands.push_bottom(),
1146                (OperandType::Bottom, OperandType::Typed(rhs))
1147                | (OperandType::Typed(rhs), OperandType::Bottom) => state.operands.push(rhs),
1148                (OperandType::Typed(lhs), OperandType::Typed(rhs)) => {
1149                    if lhs != rhs {
1150                        return Err(ValidationError {
1151                            offset: ByteOffset(offset),
1152                            function: Some(function),
1153                            kind: ValidationErrorKind::SelectOperandTypeMismatch {
1154                                expected: lhs,
1155                                found: vec![lhs, rhs],
1156                            },
1157                        });
1158                    }
1159                    // Untyped select accepts number and vector operands only
1160                    // (references require the typed form).
1161                    if !matches!(lhs, ValType::Num(_) | ValType::Vec(_)) {
1162                        return Err(ValidationError {
1163                            offset: ByteOffset(offset),
1164                            function: Some(function),
1165                            kind: ValidationErrorKind::SelectOperandTypeMismatch {
1166                                expected: ValType::Num(crate::types::NumType::I32),
1167                                found: vec![lhs, rhs],
1168                            },
1169                        });
1170                    }
1171                    state.operands.push(lhs);
1172                }
1173            }
1174        }
1175        Instr::SelectTyped(types) => {
1176            if types.len() != 1 {
1177                return Err(ValidationError {
1178                    offset: ByteOffset(offset),
1179                    function: Some(function),
1180                    kind: ValidationErrorKind::InvalidSelectResultArity { found: types.len() },
1181                });
1182            }
1183            validate_valtype_type_indices(module, types[0], Some(function), offset)?;
1184            let expected = normalize_valtype(module, types[0]);
1185            pop_expect(
1186                function,
1187                state,
1188                ValType::Num(crate::types::NumType::I32),
1189                offset,
1190                "select_typed",
1191            )?;
1192            let rhs = pop_operand_type(function, state, offset, "select_typed")?;
1193            let lhs = pop_operand_type(function, state, offset, "select_typed")?;
1194            if !operand_matches(lhs, expected) || !operand_matches(rhs, expected) {
1195                return Err(ValidationError {
1196                    offset: ByteOffset(offset),
1197                    function: Some(function),
1198                    kind: ValidationErrorKind::SelectOperandTypeMismatch {
1199                        expected,
1200                        found: vec![
1201                            operand_to_valtype(lhs, expected),
1202                            operand_to_valtype(rhs, expected),
1203                        ],
1204                    },
1205                });
1206            }
1207            state.operands.push(expected);
1208        }
1209        Instr::LocalGet(idx) => {
1210            let ty = *state.locals.get(idx.0 as usize).ok_or(ValidationError {
1211                offset: ByteOffset(offset),
1212                function: Some(function),
1213                kind: ValidationErrorKind::UnknownLocalIdx { idx: *idx },
1214            })?;
1215            if !state
1216                .local_inits
1217                .get(idx.0 as usize)
1218                .copied()
1219                .unwrap_or(false)
1220            {
1221                return Err(ValidationError {
1222                    offset: ByteOffset(offset),
1223                    function: Some(function),
1224                    kind: ValidationErrorKind::UninitializedLocal { idx: *idx },
1225                });
1226            }
1227            state.operands.push(ty);
1228        }
1229        Instr::LocalSet(idx) => {
1230            let ty = *state.locals.get(idx.0 as usize).ok_or(ValidationError {
1231                offset: ByteOffset(offset),
1232                function: Some(function),
1233                kind: ValidationErrorKind::UnknownLocalIdx { idx: *idx },
1234            })?;
1235            pop_expect(function, state, ty, offset, "local.set")?;
1236            state.local_inits[idx.0 as usize] = true;
1237        }
1238        Instr::LocalTee(idx) => {
1239            let ty = *state.locals.get(idx.0 as usize).ok_or(ValidationError {
1240                offset: ByteOffset(offset),
1241                function: Some(function),
1242                kind: ValidationErrorKind::UnknownLocalIdx { idx: *idx },
1243            })?;
1244            pop_expect(function, state, ty, offset, "local.tee")?;
1245            state.local_inits[idx.0 as usize] = true;
1246            state.operands.push(ty);
1247        }
1248        Instr::GlobalGet(idx) => {
1249            let ty = resolve_global_type(module, *idx, function, offset)?;
1250            state.operands.push(ty.val_type);
1251        }
1252        Instr::GlobalSet(idx) => {
1253            let ty = resolve_global_type(module, *idx, function, offset)?;
1254            if ty.mutability != Mutability::Var {
1255                return Err(ValidationError {
1256                    offset: ByteOffset(offset),
1257                    function: Some(function),
1258                    kind: ValidationErrorKind::ImmutableGlobalSet { idx: *idx },
1259                });
1260            }
1261            pop_expect(function, state, ty.val_type, offset, "global.set")?;
1262        }
1263        Instr::TableGet(idx) => {
1264            let ty = resolve_table_type_with_context(module, *idx, Some(function), offset)?;
1265            pop_expect(
1266                function,
1267                state,
1268                ValType::Num(crate::types::NumType::I32),
1269                offset,
1270                "table.get",
1271            )?;
1272            state.operands.push(ValType::Ref(ty.elem));
1273        }
1274        Instr::TableSet(idx) => {
1275            let ty = resolve_table_type_with_context(module, *idx, Some(function), offset)?;
1276            pop_expect(function, state, ValType::Ref(ty.elem), offset, "table.set")?;
1277            pop_expect(
1278                function,
1279                state,
1280                ValType::Num(crate::types::NumType::I32),
1281                offset,
1282                "table.set",
1283            )?;
1284        }
1285        Instr::V128Load(memarg) => validate_load(
1286            module,
1287            function,
1288            state,
1289            offset,
1290            MemLoadValidation {
1291                op: "v128.load",
1292                memory: memarg.memory,
1293                found_align: memarg.align,
1294                max_align: 4,
1295                result: ValType::Vec(crate::types::VecType::V128),
1296            },
1297        )?,
1298        Instr::V128Load8x8S(memarg) | Instr::V128Load8x8U(memarg) => validate_load(
1299            module,
1300            function,
1301            state,
1302            offset,
1303            MemLoadValidation {
1304                op: "v128.load8x8",
1305                memory: memarg.memory,
1306                found_align: memarg.align,
1307                max_align: 3,
1308                result: ValType::Vec(crate::types::VecType::V128),
1309            },
1310        )?,
1311        Instr::V128Load16x4S(memarg) | Instr::V128Load16x4U(memarg) => validate_load(
1312            module,
1313            function,
1314            state,
1315            offset,
1316            MemLoadValidation {
1317                op: "v128.load16x4",
1318                memory: memarg.memory,
1319                found_align: memarg.align,
1320                max_align: 3,
1321                result: ValType::Vec(crate::types::VecType::V128),
1322            },
1323        )?,
1324        Instr::V128Load32x2S(memarg) | Instr::V128Load32x2U(memarg) => validate_load(
1325            module,
1326            function,
1327            state,
1328            offset,
1329            MemLoadValidation {
1330                op: "v128.load32x2",
1331                memory: memarg.memory,
1332                found_align: memarg.align,
1333                max_align: 3,
1334                result: ValType::Vec(crate::types::VecType::V128),
1335            },
1336        )?,
1337        Instr::V128Load8Splat(memarg) => validate_load(
1338            module,
1339            function,
1340            state,
1341            offset,
1342            MemLoadValidation {
1343                op: "v128.load8_splat",
1344                memory: memarg.memory,
1345                found_align: memarg.align,
1346                max_align: 0,
1347                result: ValType::Vec(crate::types::VecType::V128),
1348            },
1349        )?,
1350        Instr::V128Load16Splat(memarg) => validate_load(
1351            module,
1352            function,
1353            state,
1354            offset,
1355            MemLoadValidation {
1356                op: "v128.load16_splat",
1357                memory: memarg.memory,
1358                found_align: memarg.align,
1359                max_align: 1,
1360                result: ValType::Vec(crate::types::VecType::V128),
1361            },
1362        )?,
1363        Instr::V128Load32Splat(memarg) => validate_load(
1364            module,
1365            function,
1366            state,
1367            offset,
1368            MemLoadValidation {
1369                op: "v128.load32_splat",
1370                memory: memarg.memory,
1371                found_align: memarg.align,
1372                max_align: 2,
1373                result: ValType::Vec(crate::types::VecType::V128),
1374            },
1375        )?,
1376        Instr::V128Load64Splat(memarg) => validate_load(
1377            module,
1378            function,
1379            state,
1380            offset,
1381            MemLoadValidation {
1382                op: "v128.load64_splat",
1383                memory: memarg.memory,
1384                found_align: memarg.align,
1385                max_align: 3,
1386                result: ValType::Vec(crate::types::VecType::V128),
1387            },
1388        )?,
1389        Instr::V128Load32Zero(memarg) => validate_load(
1390            module,
1391            function,
1392            state,
1393            offset,
1394            MemLoadValidation {
1395                op: "v128.load32_zero",
1396                memory: memarg.memory,
1397                found_align: memarg.align,
1398                max_align: 2,
1399                result: ValType::Vec(crate::types::VecType::V128),
1400            },
1401        )?,
1402        Instr::V128Load64Zero(memarg) => validate_load(
1403            module,
1404            function,
1405            state,
1406            offset,
1407            MemLoadValidation {
1408                op: "v128.load64_zero",
1409                memory: memarg.memory,
1410                found_align: memarg.align,
1411                max_align: 3,
1412                result: ValType::Vec(crate::types::VecType::V128),
1413            },
1414        )?,
1415        Instr::V128Store(memarg) => validate_store(
1416            module,
1417            function,
1418            state,
1419            offset,
1420            MemStoreValidation {
1421                op: "v128.store",
1422                memory: memarg.memory,
1423                found_align: memarg.align,
1424                max_align: 4,
1425                stored: ValType::Vec(crate::types::VecType::V128),
1426            },
1427        )?,
1428        Instr::V128Load8Lane { memarg, lane } => validate_simd_load_lane(
1429            module,
1430            function,
1431            state,
1432            offset,
1433            SimdLaneValidation {
1434                op: "v128.load8_lane",
1435                memory: memarg.memory,
1436                found_align: memarg.align,
1437                max_align: 0,
1438                lane: *lane,
1439                max_lane: 15,
1440            },
1441        )?,
1442        Instr::V128Load16Lane { memarg, lane } => validate_simd_load_lane(
1443            module,
1444            function,
1445            state,
1446            offset,
1447            SimdLaneValidation {
1448                op: "v128.load16_lane",
1449                memory: memarg.memory,
1450                found_align: memarg.align,
1451                max_align: 1,
1452                lane: *lane,
1453                max_lane: 7,
1454            },
1455        )?,
1456        Instr::V128Load32Lane { memarg, lane } => validate_simd_load_lane(
1457            module,
1458            function,
1459            state,
1460            offset,
1461            SimdLaneValidation {
1462                op: "v128.load32_lane",
1463                memory: memarg.memory,
1464                found_align: memarg.align,
1465                max_align: 2,
1466                lane: *lane,
1467                max_lane: 3,
1468            },
1469        )?,
1470        Instr::V128Load64Lane { memarg, lane } => validate_simd_load_lane(
1471            module,
1472            function,
1473            state,
1474            offset,
1475            SimdLaneValidation {
1476                op: "v128.load64_lane",
1477                memory: memarg.memory,
1478                found_align: memarg.align,
1479                max_align: 3,
1480                lane: *lane,
1481                max_lane: 1,
1482            },
1483        )?,
1484        Instr::V128Store8Lane { memarg, lane } => validate_simd_store_lane(
1485            module,
1486            function,
1487            state,
1488            offset,
1489            SimdLaneValidation {
1490                op: "v128.store8_lane",
1491                memory: memarg.memory,
1492                found_align: memarg.align,
1493                max_align: 0,
1494                lane: *lane,
1495                max_lane: 15,
1496            },
1497        )?,
1498        Instr::V128Store16Lane { memarg, lane } => validate_simd_store_lane(
1499            module,
1500            function,
1501            state,
1502            offset,
1503            SimdLaneValidation {
1504                op: "v128.store16_lane",
1505                memory: memarg.memory,
1506                found_align: memarg.align,
1507                max_align: 1,
1508                lane: *lane,
1509                max_lane: 7,
1510            },
1511        )?,
1512        Instr::V128Store32Lane { memarg, lane } => validate_simd_store_lane(
1513            module,
1514            function,
1515            state,
1516            offset,
1517            SimdLaneValidation {
1518                op: "v128.store32_lane",
1519                memory: memarg.memory,
1520                found_align: memarg.align,
1521                max_align: 2,
1522                lane: *lane,
1523                max_lane: 3,
1524            },
1525        )?,
1526        Instr::V128Store64Lane { memarg, lane } => validate_simd_store_lane(
1527            module,
1528            function,
1529            state,
1530            offset,
1531            SimdLaneValidation {
1532                op: "v128.store64_lane",
1533                memory: memarg.memory,
1534                found_align: memarg.align,
1535                max_align: 3,
1536                lane: *lane,
1537                max_lane: 1,
1538            },
1539        )?,
1540        Instr::I32Load(memarg) => validate_load(
1541            module,
1542            function,
1543            state,
1544            offset,
1545            MemLoadValidation {
1546                op: "i32.load",
1547                memory: memarg.memory,
1548                found_align: memarg.align,
1549                max_align: 2,
1550                result: ValType::Num(crate::types::NumType::I32),
1551            },
1552        )?,
1553        Instr::I64Load(memarg) => validate_load(
1554            module,
1555            function,
1556            state,
1557            offset,
1558            MemLoadValidation {
1559                op: "i64.load",
1560                memory: memarg.memory,
1561                found_align: memarg.align,
1562                max_align: 3,
1563                result: ValType::Num(crate::types::NumType::I64),
1564            },
1565        )?,
1566        Instr::F32Load(memarg) => validate_load(
1567            module,
1568            function,
1569            state,
1570            offset,
1571            MemLoadValidation {
1572                op: "f32.load",
1573                memory: memarg.memory,
1574                found_align: memarg.align,
1575                max_align: 2,
1576                result: ValType::Num(crate::types::NumType::F32),
1577            },
1578        )?,
1579        Instr::F64Load(memarg) => validate_load(
1580            module,
1581            function,
1582            state,
1583            offset,
1584            MemLoadValidation {
1585                op: "f64.load",
1586                memory: memarg.memory,
1587                found_align: memarg.align,
1588                max_align: 3,
1589                result: ValType::Num(crate::types::NumType::F64),
1590            },
1591        )?,
1592        Instr::I32Load8S(memarg) | Instr::I32Load8U(memarg) => validate_load(
1593            module,
1594            function,
1595            state,
1596            offset,
1597            MemLoadValidation {
1598                op: "i32.load8",
1599                memory: memarg.memory,
1600                found_align: memarg.align,
1601                max_align: 0,
1602                result: ValType::Num(crate::types::NumType::I32),
1603            },
1604        )?,
1605        Instr::I32Load16S(memarg) | Instr::I32Load16U(memarg) => validate_load(
1606            module,
1607            function,
1608            state,
1609            offset,
1610            MemLoadValidation {
1611                op: "i32.load16",
1612                memory: memarg.memory,
1613                found_align: memarg.align,
1614                max_align: 1,
1615                result: ValType::Num(crate::types::NumType::I32),
1616            },
1617        )?,
1618        Instr::I64Load8S(memarg) | Instr::I64Load8U(memarg) => validate_load(
1619            module,
1620            function,
1621            state,
1622            offset,
1623            MemLoadValidation {
1624                op: "i64.load8",
1625                memory: memarg.memory,
1626                found_align: memarg.align,
1627                max_align: 0,
1628                result: ValType::Num(crate::types::NumType::I64),
1629            },
1630        )?,
1631        Instr::I64Load16S(memarg) | Instr::I64Load16U(memarg) => validate_load(
1632            module,
1633            function,
1634            state,
1635            offset,
1636            MemLoadValidation {
1637                op: "i64.load16",
1638                memory: memarg.memory,
1639                found_align: memarg.align,
1640                max_align: 1,
1641                result: ValType::Num(crate::types::NumType::I64),
1642            },
1643        )?,
1644        Instr::I64Load32S(memarg) | Instr::I64Load32U(memarg) => validate_load(
1645            module,
1646            function,
1647            state,
1648            offset,
1649            MemLoadValidation {
1650                op: "i64.load32",
1651                memory: memarg.memory,
1652                found_align: memarg.align,
1653                max_align: 2,
1654                result: ValType::Num(crate::types::NumType::I64),
1655            },
1656        )?,
1657        Instr::I32Store(memarg) => validate_store(
1658            module,
1659            function,
1660            state,
1661            offset,
1662            MemStoreValidation {
1663                op: "i32.store",
1664                memory: memarg.memory,
1665                found_align: memarg.align,
1666                max_align: 2,
1667                stored: ValType::Num(crate::types::NumType::I32),
1668            },
1669        )?,
1670        Instr::I64Store(memarg) => validate_store(
1671            module,
1672            function,
1673            state,
1674            offset,
1675            MemStoreValidation {
1676                op: "i64.store",
1677                memory: memarg.memory,
1678                found_align: memarg.align,
1679                max_align: 3,
1680                stored: ValType::Num(crate::types::NumType::I64),
1681            },
1682        )?,
1683        Instr::F32Store(memarg) => validate_store(
1684            module,
1685            function,
1686            state,
1687            offset,
1688            MemStoreValidation {
1689                op: "f32.store",
1690                memory: memarg.memory,
1691                found_align: memarg.align,
1692                max_align: 2,
1693                stored: ValType::Num(crate::types::NumType::F32),
1694            },
1695        )?,
1696        Instr::F64Store(memarg) => validate_store(
1697            module,
1698            function,
1699            state,
1700            offset,
1701            MemStoreValidation {
1702                op: "f64.store",
1703                memory: memarg.memory,
1704                found_align: memarg.align,
1705                max_align: 3,
1706                stored: ValType::Num(crate::types::NumType::F64),
1707            },
1708        )?,
1709        Instr::I32Store8(memarg) => validate_store(
1710            module,
1711            function,
1712            state,
1713            offset,
1714            MemStoreValidation {
1715                op: "i32.store8",
1716                memory: memarg.memory,
1717                found_align: memarg.align,
1718                max_align: 0,
1719                stored: ValType::Num(crate::types::NumType::I32),
1720            },
1721        )?,
1722        Instr::I32Store16(memarg) => validate_store(
1723            module,
1724            function,
1725            state,
1726            offset,
1727            MemStoreValidation {
1728                op: "i32.store16",
1729                memory: memarg.memory,
1730                found_align: memarg.align,
1731                max_align: 1,
1732                stored: ValType::Num(crate::types::NumType::I32),
1733            },
1734        )?,
1735        Instr::I64Store8(memarg) => validate_store(
1736            module,
1737            function,
1738            state,
1739            offset,
1740            MemStoreValidation {
1741                op: "i64.store8",
1742                memory: memarg.memory,
1743                found_align: memarg.align,
1744                max_align: 0,
1745                stored: ValType::Num(crate::types::NumType::I64),
1746            },
1747        )?,
1748        Instr::I64Store16(memarg) => validate_store(
1749            module,
1750            function,
1751            state,
1752            offset,
1753            MemStoreValidation {
1754                op: "i64.store16",
1755                memory: memarg.memory,
1756                found_align: memarg.align,
1757                max_align: 1,
1758                stored: ValType::Num(crate::types::NumType::I64),
1759            },
1760        )?,
1761        Instr::I64Store32(memarg) => validate_store(
1762            module,
1763            function,
1764            state,
1765            offset,
1766            MemStoreValidation {
1767                op: "i64.store32",
1768                memory: memarg.memory,
1769                found_align: memarg.align,
1770                max_align: 2,
1771                stored: ValType::Num(crate::types::NumType::I64),
1772            },
1773        )?,
1774        Instr::MemoryInit(data_idx, mem_idx) => {
1775            resolve_data_segment(module, *data_idx, function, offset)?;
1776            resolve_memory_type(module, *mem_idx, function, offset)?;
1777            pop_expect(
1778                function,
1779                state,
1780                ValType::Num(crate::types::NumType::I32),
1781                offset,
1782                "memory.init",
1783            )?;
1784            pop_expect(
1785                function,
1786                state,
1787                ValType::Num(crate::types::NumType::I32),
1788                offset,
1789                "memory.init",
1790            )?;
1791            pop_expect(
1792                function,
1793                state,
1794                ValType::Num(crate::types::NumType::I32),
1795                offset,
1796                "memory.init",
1797            )?;
1798        }
1799        Instr::DataDrop(data_idx) => {
1800            resolve_data_segment(module, *data_idx, function, offset)?;
1801        }
1802        Instr::MemoryCopy { dst, src } => {
1803            resolve_memory_type(module, *dst, function, offset)?;
1804            resolve_memory_type(module, *src, function, offset)?;
1805            pop_expect(
1806                function,
1807                state,
1808                ValType::Num(crate::types::NumType::I32),
1809                offset,
1810                "memory.copy",
1811            )?;
1812            pop_expect(
1813                function,
1814                state,
1815                ValType::Num(crate::types::NumType::I32),
1816                offset,
1817                "memory.copy",
1818            )?;
1819            pop_expect(
1820                function,
1821                state,
1822                ValType::Num(crate::types::NumType::I32),
1823                offset,
1824                "memory.copy",
1825            )?;
1826        }
1827        Instr::MemoryFill(mem_idx) => {
1828            resolve_memory_type(module, *mem_idx, function, offset)?;
1829            pop_expect(
1830                function,
1831                state,
1832                ValType::Num(crate::types::NumType::I32),
1833                offset,
1834                "memory.fill",
1835            )?;
1836            pop_expect(
1837                function,
1838                state,
1839                ValType::Num(crate::types::NumType::I32),
1840                offset,
1841                "memory.fill",
1842            )?;
1843            pop_expect(
1844                function,
1845                state,
1846                ValType::Num(crate::types::NumType::I32),
1847                offset,
1848                "memory.fill",
1849            )?;
1850        }
1851        Instr::TableInit {
1852            elem_idx,
1853            table_idx,
1854        } => {
1855            let elem = resolve_element_segment(module, *elem_idx, function, offset)?;
1856            let elem_type = normalize_reftype(module, elem.elem_type);
1857            let table =
1858                resolve_table_type_with_context(module, *table_idx, Some(function), offset)?;
1859            if !reftype_matches(elem_type, table.elem) {
1860                return Err(ValidationError {
1861                    offset: ByteOffset(offset),
1862                    function: Some(function),
1863                    kind: ValidationErrorKind::ElementTableTypeMismatch {
1864                        expected: table.elem,
1865                        found: elem_type,
1866                    },
1867                });
1868            }
1869            pop_expect(
1870                function,
1871                state,
1872                ValType::Num(crate::types::NumType::I32),
1873                offset,
1874                "table.init",
1875            )?;
1876            pop_expect(
1877                function,
1878                state,
1879                ValType::Num(crate::types::NumType::I32),
1880                offset,
1881                "table.init",
1882            )?;
1883            pop_expect(
1884                function,
1885                state,
1886                ValType::Num(crate::types::NumType::I32),
1887                offset,
1888                "table.init",
1889            )?;
1890        }
1891        Instr::ElemDrop(elem_idx) => {
1892            let _ = resolve_element_segment(module, *elem_idx, function, offset)?;
1893        }
1894        Instr::TableCopy { dst, src } => {
1895            let dst_ty = resolve_table_type_with_context(module, *dst, Some(function), offset)?;
1896            let src_ty = resolve_table_type_with_context(module, *src, Some(function), offset)?;
1897            if !reftype_matches(src_ty.elem, dst_ty.elem)
1898                || !reftype_matches(dst_ty.elem, src_ty.elem)
1899            {
1900                return Err(ValidationError {
1901                    offset: ByteOffset(offset),
1902                    function: Some(function),
1903                    kind: ValidationErrorKind::ElementTableTypeMismatch {
1904                        expected: dst_ty.elem,
1905                        found: src_ty.elem,
1906                    },
1907                });
1908            }
1909            pop_expect(
1910                function,
1911                state,
1912                ValType::Num(crate::types::NumType::I32),
1913                offset,
1914                "table.copy",
1915            )?;
1916            pop_expect(
1917                function,
1918                state,
1919                ValType::Num(crate::types::NumType::I32),
1920                offset,
1921                "table.copy",
1922            )?;
1923            pop_expect(
1924                function,
1925                state,
1926                ValType::Num(crate::types::NumType::I32),
1927                offset,
1928                "table.copy",
1929            )?;
1930        }
1931        Instr::TableGrow(idx) => {
1932            let ty = resolve_table_type_with_context(module, *idx, Some(function), offset)?;
1933            pop_expect(
1934                function,
1935                state,
1936                ValType::Num(crate::types::NumType::I32),
1937                offset,
1938                "table.grow",
1939            )?;
1940            pop_expect(function, state, ValType::Ref(ty.elem), offset, "table.grow")?;
1941            state
1942                .operands
1943                .push(ValType::Num(crate::types::NumType::I32));
1944        }
1945        Instr::TableSize(idx) => {
1946            let _ = resolve_table_type_with_context(module, *idx, Some(function), offset)?;
1947            state
1948                .operands
1949                .push(ValType::Num(crate::types::NumType::I32));
1950        }
1951        Instr::TableFill(idx) => {
1952            let ty = resolve_table_type_with_context(module, *idx, Some(function), offset)?;
1953            pop_expect(
1954                function,
1955                state,
1956                ValType::Num(crate::types::NumType::I32),
1957                offset,
1958                "table.fill",
1959            )?;
1960            pop_expect(function, state, ValType::Ref(ty.elem), offset, "table.fill")?;
1961            pop_expect(
1962                function,
1963                state,
1964                ValType::Num(crate::types::NumType::I32),
1965                offset,
1966                "table.fill",
1967            )?;
1968        }
1969        Instr::MemorySize(idx) => {
1970            resolve_memory_type(module, *idx, function, offset)?;
1971            state
1972                .operands
1973                .push(ValType::Num(crate::types::NumType::I32));
1974        }
1975        Instr::MemoryGrow(idx) => {
1976            resolve_memory_type(module, *idx, function, offset)?;
1977            pop_expect(
1978                function,
1979                state,
1980                ValType::Num(crate::types::NumType::I32),
1981                offset,
1982                "memory.grow",
1983            )?;
1984            state
1985                .operands
1986                .push(ValType::Num(crate::types::NumType::I32));
1987        }
1988        Instr::I32Const(_) => state
1989            .operands
1990            .push(ValType::Num(crate::types::NumType::I32)),
1991        Instr::I64Const(_) => state
1992            .operands
1993            .push(ValType::Num(crate::types::NumType::I64)),
1994        Instr::F32Const(_) => state
1995            .operands
1996            .push(ValType::Num(crate::types::NumType::F32)),
1997        Instr::F64Const(_) => state
1998            .operands
1999            .push(ValType::Num(crate::types::NumType::F64)),
2000        Instr::RefNull(ref_type) => {
2001            validate_reftype_type_indices(module, *ref_type, Some(function), offset)?;
2002            state
2003                .operands
2004                .push(normalize_valtype(module, ValType::Ref(*ref_type)));
2005        }
2006        Instr::RefIsNull => validate_ref_is_null(function, state, offset)?,
2007        Instr::RefAsNonNull => validate_ref_as_non_null(function, state, offset)?,
2008        Instr::RefFunc(idx) => {
2009            let type_idx = resolve_func_type_idx(module, *idx, function, offset)?;
2010            if !is_declared_function_ref(module, *idx) {
2011                return Err(ValidationError {
2012                    offset: ByteOffset(offset),
2013                    function: Some(function),
2014                    kind: ValidationErrorKind::UndeclaredFuncRef { idx: *idx },
2015                });
2016            }
2017            state
2018                .operands
2019                .push(ValType::Ref(RefType::concrete(false, type_idx)));
2020        }
2021        Instr::V128Const(_) => state
2022            .operands
2023            .push(ValType::Vec(crate::types::VecType::V128)),
2024        Instr::I8x16Splat => validate_numeric_unary(
2025            function,
2026            state,
2027            offset,
2028            "i8x16.splat",
2029            ValType::Num(crate::types::NumType::I32),
2030            ValType::Vec(crate::types::VecType::V128),
2031        )?,
2032        Instr::I16x8Splat => validate_numeric_unary(
2033            function,
2034            state,
2035            offset,
2036            "i16x8.splat",
2037            ValType::Num(crate::types::NumType::I32),
2038            ValType::Vec(crate::types::VecType::V128),
2039        )?,
2040        Instr::I32x4Splat => validate_numeric_unary(
2041            function,
2042            state,
2043            offset,
2044            "i32x4.splat",
2045            ValType::Num(crate::types::NumType::I32),
2046            ValType::Vec(crate::types::VecType::V128),
2047        )?,
2048        Instr::I64x2Splat => validate_numeric_unary(
2049            function,
2050            state,
2051            offset,
2052            "i64x2.splat",
2053            ValType::Num(crate::types::NumType::I64),
2054            ValType::Vec(crate::types::VecType::V128),
2055        )?,
2056        Instr::F32x4Splat => validate_numeric_unary(
2057            function,
2058            state,
2059            offset,
2060            "f32x4.splat",
2061            ValType::Num(crate::types::NumType::F32),
2062            ValType::Vec(crate::types::VecType::V128),
2063        )?,
2064        Instr::F64x2Splat => validate_numeric_unary(
2065            function,
2066            state,
2067            offset,
2068            "f64x2.splat",
2069            ValType::Num(crate::types::NumType::F64),
2070            ValType::Vec(crate::types::VecType::V128),
2071        )?,
2072        Instr::I32x4ExtractLane(_) => validate_numeric_unary(
2073            function,
2074            state,
2075            offset,
2076            "i32x4.extract_lane",
2077            ValType::Vec(crate::types::VecType::V128),
2078            ValType::Num(crate::types::NumType::I32),
2079        )?,
2080        Instr::F32x4ExtractLane(_) => validate_numeric_unary(
2081            function,
2082            state,
2083            offset,
2084            "f32x4.extract_lane",
2085            ValType::Vec(crate::types::VecType::V128),
2086            ValType::Num(crate::types::NumType::F32),
2087        )?,
2088        Instr::I32x4ReplaceLane(_) => {
2089            pop_expect(
2090                function,
2091                state,
2092                ValType::Num(crate::types::NumType::I32),
2093                offset,
2094                "i32x4.replace_lane",
2095            )?;
2096            pop_expect(
2097                function,
2098                state,
2099                ValType::Vec(crate::types::VecType::V128),
2100                offset,
2101                "i32x4.replace_lane",
2102            )?;
2103            state
2104                .operands
2105                .push(ValType::Vec(crate::types::VecType::V128));
2106        }
2107        Instr::F32x4ReplaceLane(_) => {
2108            pop_expect(
2109                function,
2110                state,
2111                ValType::Num(crate::types::NumType::F32),
2112                offset,
2113                "f32x4.replace_lane",
2114            )?;
2115            pop_expect(
2116                function,
2117                state,
2118                ValType::Vec(crate::types::VecType::V128),
2119                offset,
2120                "f32x4.replace_lane",
2121            )?;
2122            state
2123                .operands
2124                .push(ValType::Vec(crate::types::VecType::V128));
2125        }
2126        Instr::V128Not => validate_numeric_unary(
2127            function,
2128            state,
2129            offset,
2130            "v128.not",
2131            ValType::Vec(crate::types::VecType::V128),
2132            ValType::Vec(crate::types::VecType::V128),
2133        )?,
2134        Instr::V128And | Instr::V128Or | Instr::V128Xor => validate_numeric_binary(
2135            function,
2136            state,
2137            offset,
2138            "v128.bitwise",
2139            ValType::Vec(crate::types::VecType::V128),
2140            ValType::Vec(crate::types::VecType::V128),
2141        )?,
2142        Instr::I8x16Add
2143        | Instr::I8x16Sub
2144        | Instr::I16x8Add
2145        | Instr::I16x8Sub
2146        | Instr::I32x4Add
2147        | Instr::I32x4Sub
2148        | Instr::I32x4Mul
2149        | Instr::I64x2Add
2150        | Instr::I64x2Sub
2151        | Instr::F32x4Add
2152        | Instr::F32x4Sub
2153        | Instr::F32x4Mul
2154        | Instr::F32x4Div
2155        | Instr::F64x2Add
2156        | Instr::F64x2Sub
2157        | Instr::F64x2Mul
2158        | Instr::F64x2Div => validate_numeric_binary(
2159            function,
2160            state,
2161            offset,
2162            "simd.arithmetic",
2163            ValType::Vec(crate::types::VecType::V128),
2164            ValType::Vec(crate::types::VecType::V128),
2165        )?,
2166        Instr::I32Eqz => validate_numeric_unary(
2167            function,
2168            state,
2169            offset,
2170            "i32.eqz",
2171            ValType::Num(crate::types::NumType::I32),
2172            ValType::Num(crate::types::NumType::I32),
2173        )?,
2174        Instr::I32Eq
2175        | Instr::I32Ne
2176        | Instr::I32LtS
2177        | Instr::I32LtU
2178        | Instr::I32GtS
2179        | Instr::I32GtU
2180        | Instr::I32LeS
2181        | Instr::I32LeU
2182        | Instr::I32GeS
2183        | Instr::I32GeU => validate_numeric_binary(
2184            function,
2185            state,
2186            offset,
2187            "i32.compare",
2188            ValType::Num(crate::types::NumType::I32),
2189            ValType::Num(crate::types::NumType::I32),
2190        )?,
2191        Instr::I64Eqz => validate_numeric_unary(
2192            function,
2193            state,
2194            offset,
2195            "i64.eqz",
2196            ValType::Num(crate::types::NumType::I64),
2197            ValType::Num(crate::types::NumType::I32),
2198        )?,
2199        Instr::I64Eq
2200        | Instr::I64Ne
2201        | Instr::I64LtS
2202        | Instr::I64LtU
2203        | Instr::I64GtS
2204        | Instr::I64GtU
2205        | Instr::I64LeS
2206        | Instr::I64LeU
2207        | Instr::I64GeS
2208        | Instr::I64GeU => validate_numeric_binary(
2209            function,
2210            state,
2211            offset,
2212            "i64.compare",
2213            ValType::Num(crate::types::NumType::I64),
2214            ValType::Num(crate::types::NumType::I32),
2215        )?,
2216        Instr::F32Eq | Instr::F32Ne | Instr::F32Lt | Instr::F32Gt | Instr::F32Le | Instr::F32Ge => {
2217            validate_numeric_binary(
2218                function,
2219                state,
2220                offset,
2221                "f32.compare",
2222                ValType::Num(crate::types::NumType::F32),
2223                ValType::Num(crate::types::NumType::I32),
2224            )?
2225        }
2226        Instr::F64Eq | Instr::F64Ne | Instr::F64Lt | Instr::F64Gt | Instr::F64Le | Instr::F64Ge => {
2227            validate_numeric_binary(
2228                function,
2229                state,
2230                offset,
2231                "f64.compare",
2232                ValType::Num(crate::types::NumType::F64),
2233                ValType::Num(crate::types::NumType::I32),
2234            )?
2235        }
2236        Instr::I32Clz | Instr::I32Ctz | Instr::I32Popcnt => validate_numeric_unary(
2237            function,
2238            state,
2239            offset,
2240            "i32.unary",
2241            ValType::Num(crate::types::NumType::I32),
2242            ValType::Num(crate::types::NumType::I32),
2243        )?,
2244        Instr::I32Add
2245        | Instr::I32Sub
2246        | Instr::I32Mul
2247        | Instr::I32DivS
2248        | Instr::I32DivU
2249        | Instr::I32RemS
2250        | Instr::I32RemU
2251        | Instr::I32And
2252        | Instr::I32Or
2253        | Instr::I32Xor
2254        | Instr::I32Shl
2255        | Instr::I32ShrS
2256        | Instr::I32ShrU
2257        | Instr::I32Rotl
2258        | Instr::I32Rotr => validate_numeric_binary(
2259            function,
2260            state,
2261            offset,
2262            "i32.binary",
2263            ValType::Num(crate::types::NumType::I32),
2264            ValType::Num(crate::types::NumType::I32),
2265        )?,
2266        Instr::I64Clz | Instr::I64Ctz | Instr::I64Popcnt => validate_numeric_unary(
2267            function,
2268            state,
2269            offset,
2270            "i64.unary",
2271            ValType::Num(crate::types::NumType::I64),
2272            ValType::Num(crate::types::NumType::I64),
2273        )?,
2274        Instr::I64Add
2275        | Instr::I64Sub
2276        | Instr::I64Mul
2277        | Instr::I64DivS
2278        | Instr::I64DivU
2279        | Instr::I64RemS
2280        | Instr::I64RemU
2281        | Instr::I64And
2282        | Instr::I64Or
2283        | Instr::I64Xor
2284        | Instr::I64Shl
2285        | Instr::I64ShrS
2286        | Instr::I64ShrU
2287        | Instr::I64Rotl
2288        | Instr::I64Rotr => validate_numeric_binary(
2289            function,
2290            state,
2291            offset,
2292            "i64.binary",
2293            ValType::Num(crate::types::NumType::I64),
2294            ValType::Num(crate::types::NumType::I64),
2295        )?,
2296        Instr::F32Abs
2297        | Instr::F32Neg
2298        | Instr::F32Ceil
2299        | Instr::F32Floor
2300        | Instr::F32Trunc
2301        | Instr::F32Nearest
2302        | Instr::F32Sqrt => validate_numeric_unary(
2303            function,
2304            state,
2305            offset,
2306            "f32.unary",
2307            ValType::Num(crate::types::NumType::F32),
2308            ValType::Num(crate::types::NumType::F32),
2309        )?,
2310        Instr::F32Add
2311        | Instr::F32Sub
2312        | Instr::F32Mul
2313        | Instr::F32Div
2314        | Instr::F32Min
2315        | Instr::F32Max
2316        | Instr::F32Copysign => validate_numeric_binary(
2317            function,
2318            state,
2319            offset,
2320            "f32.binary",
2321            ValType::Num(crate::types::NumType::F32),
2322            ValType::Num(crate::types::NumType::F32),
2323        )?,
2324        Instr::F64Abs
2325        | Instr::F64Neg
2326        | Instr::F64Ceil
2327        | Instr::F64Floor
2328        | Instr::F64Trunc
2329        | Instr::F64Nearest
2330        | Instr::F64Sqrt => validate_numeric_unary(
2331            function,
2332            state,
2333            offset,
2334            "f64.unary",
2335            ValType::Num(crate::types::NumType::F64),
2336            ValType::Num(crate::types::NumType::F64),
2337        )?,
2338        Instr::F64Add
2339        | Instr::F64Sub
2340        | Instr::F64Mul
2341        | Instr::F64Div
2342        | Instr::F64Min
2343        | Instr::F64Max
2344        | Instr::F64Copysign => validate_numeric_binary(
2345            function,
2346            state,
2347            offset,
2348            "f64.binary",
2349            ValType::Num(crate::types::NumType::F64),
2350            ValType::Num(crate::types::NumType::F64),
2351        )?,
2352        Instr::I32WrapI64 => validate_numeric_conversion(
2353            function,
2354            state,
2355            offset,
2356            "i32.wrap_i64",
2357            ValType::Num(crate::types::NumType::I64),
2358            ValType::Num(crate::types::NumType::I32),
2359        )?,
2360        Instr::I32TruncF32S | Instr::I32TruncF32U => validate_numeric_conversion(
2361            function,
2362            state,
2363            offset,
2364            "i32.trunc_f32",
2365            ValType::Num(crate::types::NumType::F32),
2366            ValType::Num(crate::types::NumType::I32),
2367        )?,
2368        Instr::I32TruncF64S | Instr::I32TruncF64U => validate_numeric_conversion(
2369            function,
2370            state,
2371            offset,
2372            "i32.trunc_f64",
2373            ValType::Num(crate::types::NumType::F64),
2374            ValType::Num(crate::types::NumType::I32),
2375        )?,
2376        Instr::I64ExtendI32S | Instr::I64ExtendI32U => validate_numeric_conversion(
2377            function,
2378            state,
2379            offset,
2380            "i64.extend_i32",
2381            ValType::Num(crate::types::NumType::I32),
2382            ValType::Num(crate::types::NumType::I64),
2383        )?,
2384        Instr::I64TruncF32S | Instr::I64TruncF32U => validate_numeric_conversion(
2385            function,
2386            state,
2387            offset,
2388            "i64.trunc_f32",
2389            ValType::Num(crate::types::NumType::F32),
2390            ValType::Num(crate::types::NumType::I64),
2391        )?,
2392        Instr::I64TruncF64S | Instr::I64TruncF64U => validate_numeric_conversion(
2393            function,
2394            state,
2395            offset,
2396            "i64.trunc_f64",
2397            ValType::Num(crate::types::NumType::F64),
2398            ValType::Num(crate::types::NumType::I64),
2399        )?,
2400        Instr::F32ConvertI32S | Instr::F32ConvertI32U => validate_numeric_conversion(
2401            function,
2402            state,
2403            offset,
2404            "f32.convert_i32",
2405            ValType::Num(crate::types::NumType::I32),
2406            ValType::Num(crate::types::NumType::F32),
2407        )?,
2408        Instr::F32ConvertI64S | Instr::F32ConvertI64U => validate_numeric_conversion(
2409            function,
2410            state,
2411            offset,
2412            "f32.convert_i64",
2413            ValType::Num(crate::types::NumType::I64),
2414            ValType::Num(crate::types::NumType::F32),
2415        )?,
2416        Instr::F32DemoteF64 => validate_numeric_conversion(
2417            function,
2418            state,
2419            offset,
2420            "f32.demote_f64",
2421            ValType::Num(crate::types::NumType::F64),
2422            ValType::Num(crate::types::NumType::F32),
2423        )?,
2424        Instr::F64ConvertI32S | Instr::F64ConvertI32U => validate_numeric_conversion(
2425            function,
2426            state,
2427            offset,
2428            "f64.convert_i32",
2429            ValType::Num(crate::types::NumType::I32),
2430            ValType::Num(crate::types::NumType::F64),
2431        )?,
2432        Instr::F64ConvertI64S | Instr::F64ConvertI64U => validate_numeric_conversion(
2433            function,
2434            state,
2435            offset,
2436            "f64.convert_i64",
2437            ValType::Num(crate::types::NumType::I64),
2438            ValType::Num(crate::types::NumType::F64),
2439        )?,
2440        Instr::F64PromoteF32 => validate_numeric_conversion(
2441            function,
2442            state,
2443            offset,
2444            "f64.promote_f32",
2445            ValType::Num(crate::types::NumType::F32),
2446            ValType::Num(crate::types::NumType::F64),
2447        )?,
2448        Instr::I32ReinterpretF32 => validate_numeric_conversion(
2449            function,
2450            state,
2451            offset,
2452            "i32.reinterpret_f32",
2453            ValType::Num(crate::types::NumType::F32),
2454            ValType::Num(crate::types::NumType::I32),
2455        )?,
2456        Instr::I64ReinterpretF64 => validate_numeric_conversion(
2457            function,
2458            state,
2459            offset,
2460            "i64.reinterpret_f64",
2461            ValType::Num(crate::types::NumType::F64),
2462            ValType::Num(crate::types::NumType::I64),
2463        )?,
2464        Instr::F32ReinterpretI32 => validate_numeric_conversion(
2465            function,
2466            state,
2467            offset,
2468            "f32.reinterpret_i32",
2469            ValType::Num(crate::types::NumType::I32),
2470            ValType::Num(crate::types::NumType::F32),
2471        )?,
2472        Instr::F64ReinterpretI64 => validate_numeric_conversion(
2473            function,
2474            state,
2475            offset,
2476            "f64.reinterpret_i64",
2477            ValType::Num(crate::types::NumType::I64),
2478            ValType::Num(crate::types::NumType::F64),
2479        )?,
2480        Instr::I32Extend8S | Instr::I32Extend16S => validate_numeric_conversion(
2481            function,
2482            state,
2483            offset,
2484            "i32.sign_extend",
2485            ValType::Num(crate::types::NumType::I32),
2486            ValType::Num(crate::types::NumType::I32),
2487        )?,
2488        Instr::I64Extend8S | Instr::I64Extend16S | Instr::I64Extend32S => {
2489            validate_numeric_conversion(
2490                function,
2491                state,
2492                offset,
2493                "i64.sign_extend",
2494                ValType::Num(crate::types::NumType::I64),
2495                ValType::Num(crate::types::NumType::I64),
2496            )?
2497        }
2498        Instr::I32TruncSatF32S | Instr::I32TruncSatF32U => validate_numeric_conversion(
2499            function,
2500            state,
2501            offset,
2502            "i32.trunc_sat_f32",
2503            ValType::Num(crate::types::NumType::F32),
2504            ValType::Num(crate::types::NumType::I32),
2505        )?,
2506        Instr::I32TruncSatF64S | Instr::I32TruncSatF64U => validate_numeric_conversion(
2507            function,
2508            state,
2509            offset,
2510            "i32.trunc_sat_f64",
2511            ValType::Num(crate::types::NumType::F64),
2512            ValType::Num(crate::types::NumType::I32),
2513        )?,
2514        Instr::I64TruncSatF32S | Instr::I64TruncSatF32U => validate_numeric_conversion(
2515            function,
2516            state,
2517            offset,
2518            "i64.trunc_sat_f32",
2519            ValType::Num(crate::types::NumType::F32),
2520            ValType::Num(crate::types::NumType::I64),
2521        )?,
2522        Instr::I64TruncSatF64S | Instr::I64TruncSatF64U => validate_numeric_conversion(
2523            function,
2524            state,
2525            offset,
2526            "i64.trunc_sat_f64",
2527            ValType::Num(crate::types::NumType::F64),
2528            ValType::Num(crate::types::NumType::I64),
2529        )?,
2530    }
2531
2532    Ok(())
2533}
2534
2535fn validate_numeric_unary(
2536    function: FuncIdx,
2537    state: &mut ValidationState,
2538    offset: usize,
2539    op: &'static str,
2540    input: ValType,
2541    result: ValType,
2542) -> Result<(), ValidationError> {
2543    pop_expect(function, state, input, offset, op)?;
2544    state.operands.push(result);
2545    Ok(())
2546}
2547
2548fn validate_numeric_binary(
2549    function: FuncIdx,
2550    state: &mut ValidationState,
2551    offset: usize,
2552    op: &'static str,
2553    input: ValType,
2554    result: ValType,
2555) -> Result<(), ValidationError> {
2556    pop_expect(function, state, input, offset, op)?;
2557    pop_expect(function, state, input, offset, op)?;
2558    state.operands.push(result);
2559    Ok(())
2560}
2561
2562fn validate_numeric_conversion(
2563    function: FuncIdx,
2564    state: &mut ValidationState,
2565    offset: usize,
2566    op: &'static str,
2567    input: ValType,
2568    result: ValType,
2569) -> Result<(), ValidationError> {
2570    pop_expect(function, state, input, offset, op)?;
2571    state.operands.push(result);
2572    Ok(())
2573}
2574
2575fn validate_ref_is_null(
2576    function: FuncIdx,
2577    state: &mut ValidationState,
2578    offset: usize,
2579) -> Result<(), ValidationError> {
2580    let _ = pop_ref_type(function, state, offset, "ref.is_null")?;
2581    state
2582        .operands
2583        .push(ValType::Num(crate::types::NumType::I32));
2584    Ok(())
2585}
2586
2587fn validate_ref_as_non_null(
2588    function: FuncIdx,
2589    state: &mut ValidationState,
2590    offset: usize,
2591) -> Result<(), ValidationError> {
2592    let found = pop_ref_type(function, state, offset, "ref.as_non_null")?;
2593    match found {
2594        Some(found) => state.operands.push(ValType::Ref(found.as_non_null())),
2595        None => state.operands.push_bottom(),
2596    }
2597    Ok(())
2598}
2599
2600struct MemLoadValidation {
2601    op: &'static str,
2602    memory: MemIdx,
2603    found_align: u32,
2604    max_align: u32,
2605    result: ValType,
2606}
2607
2608struct MemStoreValidation {
2609    op: &'static str,
2610    memory: MemIdx,
2611    found_align: u32,
2612    max_align: u32,
2613    stored: ValType,
2614}
2615
2616struct SimdLaneValidation {
2617    op: &'static str,
2618    memory: MemIdx,
2619    found_align: u32,
2620    max_align: u32,
2621    lane: u8,
2622    max_lane: u8,
2623}
2624
2625fn validate_load(
2626    module: &Module<'_>,
2627    function: FuncIdx,
2628    state: &mut ValidationState,
2629    offset: usize,
2630    load: MemLoadValidation,
2631) -> Result<(), ValidationError> {
2632    validate_memarg_align(function, offset, load.op, load.found_align, load.max_align)?;
2633    resolve_memory_type(module, load.memory, function, offset)?;
2634    pop_expect(
2635        function,
2636        state,
2637        ValType::Num(crate::types::NumType::I32),
2638        offset,
2639        load.op,
2640    )?;
2641    state.operands.push(load.result);
2642    Ok(())
2643}
2644
2645fn validate_store(
2646    module: &Module<'_>,
2647    function: FuncIdx,
2648    state: &mut ValidationState,
2649    offset: usize,
2650    store: MemStoreValidation,
2651) -> Result<(), ValidationError> {
2652    validate_memarg_align(
2653        function,
2654        offset,
2655        store.op,
2656        store.found_align,
2657        store.max_align,
2658    )?;
2659    resolve_memory_type(module, store.memory, function, offset)?;
2660    pop_expect(function, state, store.stored, offset, store.op)?;
2661    pop_expect(
2662        function,
2663        state,
2664        ValType::Num(crate::types::NumType::I32),
2665        offset,
2666        store.op,
2667    )?;
2668    Ok(())
2669}
2670
2671fn validate_simd_load_lane(
2672    module: &Module<'_>,
2673    function: FuncIdx,
2674    state: &mut ValidationState,
2675    offset: usize,
2676    lane: SimdLaneValidation,
2677) -> Result<(), ValidationError> {
2678    validate_memarg_align(function, offset, lane.op, lane.found_align, lane.max_align)?;
2679    validate_simd_lane_idx(function, offset, lane.op, lane.lane, lane.max_lane)?;
2680    resolve_memory_type(module, lane.memory, function, offset)?;
2681    pop_expect(
2682        function,
2683        state,
2684        ValType::Vec(crate::types::VecType::V128),
2685        offset,
2686        lane.op,
2687    )?;
2688    pop_expect(
2689        function,
2690        state,
2691        ValType::Num(crate::types::NumType::I32),
2692        offset,
2693        lane.op,
2694    )?;
2695    state
2696        .operands
2697        .push(ValType::Vec(crate::types::VecType::V128));
2698    Ok(())
2699}
2700
2701fn validate_simd_store_lane(
2702    module: &Module<'_>,
2703    function: FuncIdx,
2704    state: &mut ValidationState,
2705    offset: usize,
2706    lane: SimdLaneValidation,
2707) -> Result<(), ValidationError> {
2708    validate_memarg_align(function, offset, lane.op, lane.found_align, lane.max_align)?;
2709    validate_simd_lane_idx(function, offset, lane.op, lane.lane, lane.max_lane)?;
2710    resolve_memory_type(module, lane.memory, function, offset)?;
2711    pop_expect(
2712        function,
2713        state,
2714        ValType::Vec(crate::types::VecType::V128),
2715        offset,
2716        lane.op,
2717    )?;
2718    pop_expect(
2719        function,
2720        state,
2721        ValType::Num(crate::types::NumType::I32),
2722        offset,
2723        lane.op,
2724    )?;
2725    Ok(())
2726}
2727
2728fn validate_memarg_align(
2729    function: FuncIdx,
2730    offset: usize,
2731    op: &'static str,
2732    found: u32,
2733    max: u32,
2734) -> Result<(), ValidationError> {
2735    if found > max {
2736        return Err(ValidationError {
2737            offset: ByteOffset(offset),
2738            function: Some(function),
2739            kind: ValidationErrorKind::InvalidMemArgAlign { op, max, found },
2740        });
2741    }
2742
2743    Ok(())
2744}
2745
2746fn validate_simd_lane_idx(
2747    function: FuncIdx,
2748    offset: usize,
2749    op: &'static str,
2750    found: u8,
2751    max: u8,
2752) -> Result<(), ValidationError> {
2753    if found > max {
2754        return Err(ValidationError {
2755            offset: ByteOffset(offset),
2756            function: Some(function),
2757            kind: ValidationErrorKind::InvalidSimdLaneIdx { op, max, found },
2758        });
2759    }
2760
2761    Ok(())
2762}
2763
2764fn resolve_block_type(
2765    module: &Module<'_>,
2766    function: FuncIdx,
2767    block_type: BlockType,
2768    offset: usize,
2769) -> Result<FuncType, ValidationError> {
2770    match block_type {
2771        BlockType::Empty => Ok(FuncType {
2772            params: Vec::new(),
2773            results: Vec::new(),
2774        }),
2775        BlockType::Val(val) => {
2776            validate_valtype_type_indices(module, val, Some(function), offset)?;
2777            Ok(FuncType {
2778                params: Vec::new(),
2779                results: vec![normalize_valtype(module, val)],
2780            })
2781        }
2782        BlockType::TypeIdx(idx) => module
2783            .types
2784            .get(idx as usize)
2785            .map(|ty| normalize_func_type(module, ty))
2786            .ok_or(ValidationError {
2787                offset: ByteOffset(offset),
2788                function: Some(function),
2789                kind: ValidationErrorKind::InvalidBlockType { block_type },
2790            }),
2791    }
2792}
2793
2794fn resolve_type(
2795    module: &Module<'_>,
2796    idx: TypeIdx,
2797    function: Option<FuncIdx>,
2798    offset: usize,
2799) -> Result<FuncType, ValidationError> {
2800    let idx = canonicalize_func_type_idx(module, idx);
2801    module
2802        .types
2803        .get(idx.0 as usize)
2804        .map(|ty| normalize_func_type(module, ty))
2805        .ok_or(ValidationError {
2806            offset: ByteOffset(offset),
2807            function,
2808            kind: ValidationErrorKind::UnknownTypeIdx { idx },
2809        })
2810}
2811
2812fn resolve_func_type(
2813    module: &Module<'_>,
2814    idx: FuncIdx,
2815    function: FuncIdx,
2816    offset: usize,
2817) -> Result<FuncType, ValidationError> {
2818    let type_idx = resolve_func_type_idx_with_context(module, idx, Some(function), offset)?;
2819    resolve_type(module, type_idx, Some(function), offset)
2820}
2821
2822fn contains_ref_func_expr(
2823    _module: &Module<'_>,
2824    expr: &[u8],
2825    offset: usize,
2826    target: FuncIdx,
2827) -> bool {
2828    decode_instr_sequence_with_offsets(expr, offset)
2829        .ok()
2830        .is_some_and(|instrs| {
2831            instrs
2832                .into_iter()
2833                .any(|instr| matches!(instr.instr, Instr::RefFunc(idx) if idx == target))
2834        })
2835}
2836
2837fn is_declared_function_ref(module: &Module<'_>, target: FuncIdx) -> bool {
2838    if module
2839        .exports()
2840        .iter()
2841        .any(|export| matches!(export.desc, ExportDesc::Func(idx) if idx == target))
2842    {
2843        return true;
2844    }
2845
2846    if module
2847        .globals()
2848        .iter()
2849        .any(|global| contains_ref_func_expr(module, global.init_expr, global.init_offset, target))
2850    {
2851        return true;
2852    }
2853
2854    if module.tables.iter().any(|table| {
2855        table
2856            .init
2857            .as_ref()
2858            .is_some_and(|init| contains_ref_func_expr(module, init, 0, target))
2859    }) {
2860        return true;
2861    }
2862
2863    module.elements().iter().any(|element| match &element.init {
2864        ElementInit::FuncIndices(funcs) => funcs.contains(&target),
2865        ElementInit::Expressions(exprs) => exprs
2866            .iter()
2867            .any(|expr| contains_ref_func_expr(module, expr.expr, expr.offset, target)),
2868    })
2869}
2870
2871fn resolve_func_type_idx_for_module(
2872    module: &Module<'_>,
2873    idx: FuncIdx,
2874    offset: usize,
2875) -> Result<TypeIdx, ValidationError> {
2876    resolve_func_type_idx_with_context(module, idx, None, offset)
2877        .map(|idx| canonicalize_func_type_idx(module, idx))
2878}
2879
2880fn resolve_func_type_idx(
2881    module: &Module<'_>,
2882    idx: FuncIdx,
2883    function: FuncIdx,
2884    offset: usize,
2885) -> Result<TypeIdx, ValidationError> {
2886    resolve_func_type_idx_with_context(module, idx, Some(function), offset)
2887        .map(|idx| canonicalize_func_type_idx(module, idx))
2888}
2889
2890fn resolve_func_type_for_module<'m>(
2891    module: &'m Module<'_>,
2892    idx: FuncIdx,
2893    offset: usize,
2894) -> Result<&'m FuncType, ValidationError> {
2895    resolve_func_type_with_context(module, idx, None, offset)
2896}
2897
2898fn resolve_func_type_with_context<'m>(
2899    module: &'m Module<'_>,
2900    idx: FuncIdx,
2901    function: Option<FuncIdx>,
2902    offset: usize,
2903) -> Result<&'m FuncType, ValidationError> {
2904    let type_idx = resolve_func_type_idx_with_context(module, idx, function, offset)?;
2905
2906    module
2907        .types
2908        .get(type_idx.0 as usize)
2909        .ok_or(ValidationError {
2910            offset: ByteOffset(offset),
2911            function,
2912            kind: ValidationErrorKind::UnknownTypeIdx { idx: type_idx },
2913        })
2914}
2915
2916fn resolve_func_type_idx_with_context(
2917    module: &Module<'_>,
2918    idx: FuncIdx,
2919    function: Option<FuncIdx>,
2920    offset: usize,
2921) -> Result<TypeIdx, ValidationError> {
2922    let imported_funcs = module
2923        .imports
2924        .iter()
2925        .filter_map(|import| match import.desc {
2926            ImportDesc::Func(type_idx) => Some(type_idx),
2927            _ => None,
2928        });
2929    let defined_funcs = module.functions.iter().copied();
2930
2931    imported_funcs
2932        .chain(defined_funcs)
2933        .nth(idx.0 as usize)
2934        .ok_or(ValidationError {
2935            offset: ByteOffset(offset),
2936            function,
2937            kind: ValidationErrorKind::UnknownFuncIdx { idx },
2938        })
2939}
2940
2941fn resolve_global_type(
2942    module: &Module<'_>,
2943    idx: GlobalIdx,
2944    function: FuncIdx,
2945    offset: usize,
2946) -> Result<crate::types::GlobalType, ValidationError> {
2947    resolve_global_type_with_context(module, idx, Some(function), offset)
2948}
2949
2950fn resolve_global_type_for_module(
2951    module: &Module<'_>,
2952    idx: GlobalIdx,
2953    offset: usize,
2954) -> Result<crate::types::GlobalType, ValidationError> {
2955    resolve_global_type_with_context(module, idx, None, offset)
2956}
2957
2958fn resolve_global_type_with_context(
2959    module: &Module<'_>,
2960    idx: GlobalIdx,
2961    function: Option<FuncIdx>,
2962    offset: usize,
2963) -> Result<crate::types::GlobalType, ValidationError> {
2964    let imported_count = module
2965        .imports
2966        .iter()
2967        .filter(|import| matches!(import.desc, ImportDesc::Global(_)))
2968        .count();
2969    let defined_count = module.globals.len();
2970    let available = (imported_count + defined_count) as u32;
2971
2972    let imported = module
2973        .imports
2974        .iter()
2975        .filter_map(|import| match import.desc {
2976            ImportDesc::Global(global) => Some(global),
2977            _ => None,
2978        });
2979    let defined = module.globals.iter().map(|global| global.global_type);
2980
2981    imported
2982        .chain(defined)
2983        .nth(idx.0 as usize)
2984        .map(|global| normalize_global_type(module, global))
2985        .ok_or(ValidationError {
2986            offset: ByteOffset(offset),
2987            function,
2988            kind: ValidationErrorKind::UnknownGlobalIdx { idx, available },
2989        })
2990}
2991
2992fn resolve_table_type_for_module(
2993    module: &Module<'_>,
2994    idx: TableIdx,
2995    offset: usize,
2996) -> Result<crate::types::TableType, ValidationError> {
2997    resolve_table_type_with_context(module, idx, None, offset)
2998}
2999
3000fn resolve_table_type_with_context(
3001    module: &Module<'_>,
3002    idx: TableIdx,
3003    function: Option<FuncIdx>,
3004    offset: usize,
3005) -> Result<crate::types::TableType, ValidationError> {
3006    let imported_count = module
3007        .imports
3008        .iter()
3009        .filter(|import| matches!(import.desc, ImportDesc::Table(_)))
3010        .count();
3011    let defined_count = module.tables.len();
3012    let available = (imported_count + defined_count) as u32;
3013
3014    let imported = module
3015        .imports
3016        .iter()
3017        .filter_map(|import| match &import.desc {
3018            ImportDesc::Table(table) => Some(table),
3019            _ => None,
3020        });
3021    let defined = module.tables.iter();
3022
3023    imported
3024        .chain(defined)
3025        .nth(idx.0 as usize)
3026        .map(|table| normalize_table_type(module, table.clone()))
3027        .ok_or(ValidationError {
3028            offset: ByteOffset(offset),
3029            function,
3030            kind: ValidationErrorKind::UnknownTableIdx { idx, available },
3031        })
3032}
3033
3034fn resolve_data_segment<'a>(
3035    module: &'a Module<'a>,
3036    idx: DataIdx,
3037    function: FuncIdx,
3038    offset: usize,
3039) -> Result<&'a crate::types::DataSegment<'a>, ValidationError> {
3040    let available = module.data().len() as u32;
3041    module.data().get(idx.0 as usize).ok_or(ValidationError {
3042        offset: ByteOffset(offset),
3043        function: Some(function),
3044        kind: ValidationErrorKind::UnknownDataIdx { idx, available },
3045    })
3046}
3047
3048fn resolve_element_segment<'a>(
3049    module: &'a Module<'a>,
3050    idx: ElemIdx,
3051    function: FuncIdx,
3052    offset: usize,
3053) -> Result<&'a crate::types::ElementSegment<'a>, ValidationError> {
3054    let available = module.elements().len() as u32;
3055    module
3056        .elements()
3057        .get(idx.0 as usize)
3058        .ok_or(ValidationError {
3059            offset: ByteOffset(offset),
3060            function: Some(function),
3061            kind: ValidationErrorKind::UnknownElemIdx { idx, available },
3062        })
3063}
3064
3065fn resolve_memory_type(
3066    module: &Module<'_>,
3067    idx: MemIdx,
3068    function: FuncIdx,
3069    offset: usize,
3070) -> Result<crate::types::MemType, ValidationError> {
3071    resolve_memory_type_with_context(module, idx, Some(function), offset)
3072}
3073
3074fn resolve_memory_type_for_module(
3075    module: &Module<'_>,
3076    idx: MemIdx,
3077    offset: usize,
3078) -> Result<crate::types::MemType, ValidationError> {
3079    resolve_memory_type_with_context(module, idx, None, offset)
3080}
3081
3082fn resolve_memory_type_with_context(
3083    module: &Module<'_>,
3084    idx: MemIdx,
3085    function: Option<FuncIdx>,
3086    offset: usize,
3087) -> Result<crate::types::MemType, ValidationError> {
3088    let imported_count = module
3089        .imports
3090        .iter()
3091        .filter(|import| matches!(import.desc, ImportDesc::Mem(_)))
3092        .count();
3093    let defined_count = module.memories.len();
3094    let available = (imported_count + defined_count) as u32;
3095
3096    let imported = module
3097        .imports
3098        .iter()
3099        .filter_map(|import| match import.desc {
3100            ImportDesc::Mem(memory) => Some(memory),
3101            _ => None,
3102        });
3103    let defined = module.memories.iter().copied();
3104
3105    imported
3106        .chain(defined)
3107        .nth(idx.0 as usize)
3108        .ok_or(ValidationError {
3109            offset: ByteOffset(offset),
3110            function,
3111            kind: ValidationErrorKind::UnknownMemIdx { idx, available },
3112        })
3113}
3114
3115fn validate_label(
3116    function: FuncIdx,
3117    state: &ValidationState,
3118    label: crate::types::LabelIdx,
3119    offset: usize,
3120) -> Result<&[ValType], ValidationError> {
3121    state.current_label_types(label.0).ok_or(ValidationError {
3122        offset: ByteOffset(offset),
3123        function: Some(function),
3124        kind: ValidationErrorKind::UnknownLabelIdx { idx: label },
3125    })
3126}
3127
3128fn finish_frame(
3129    function: FuncIdx,
3130    state: &mut ValidationState,
3131    offset: usize,
3132) -> Result<(), ValidationError> {
3133    let frame = state.current_frame().clone();
3134
3135    if frame.kind == Function {
3136        return Err(ValidationError {
3137            offset: ByteOffset(offset),
3138            function: Some(function),
3139            kind: ValidationErrorKind::UnexpectedEnd,
3140        });
3141    }
3142
3143    // An `if` without `else` is valid only when the if's parameter and
3144    // result types are identical (the implicit else is the identity).
3145    if frame.kind == If && !frame.has_else && frame.start_types != frame.end_types {
3146        return Err(ValidationError {
3147            offset: ByteOffset(offset),
3148            function: Some(function),
3149            kind: ValidationErrorKind::MissingElseForResult,
3150        });
3151    }
3152
3153    if let Err(found) = ensure_frame_end_types(state, frame.outer_height, &frame.end_types) {
3154        return Err(ValidationError {
3155            offset: ByteOffset(offset),
3156            function: Some(function),
3157            kind: ValidationErrorKind::ControlResultTypeMismatch {
3158                expected: frame.end_types.clone(),
3159                found,
3160            },
3161        });
3162    }
3163
3164    pop_control_result_types(function, state, &frame.end_types, offset)?;
3165    let _closed = state.pop_frame().ok_or(ValidationError {
3166        offset: ByteOffset(offset),
3167        function: Some(function),
3168        kind: ValidationErrorKind::UnexpectedEnd,
3169    })?;
3170    state.operands.truncate(frame.outer_height);
3171    state.local_inits = frame.local_inits;
3172    for ty in frame.end_types {
3173        state.operands.push(ty);
3174    }
3175    state.reachability = Reachability::Reachable;
3176    Ok(())
3177}
3178
3179fn canonicalize_func_type_idx(module: &Module<'_>, idx: TypeIdx) -> TypeIdx {
3180    if module.types.get(idx.0 as usize).is_none() {
3181        return idx;
3182    }
3183
3184    for candidate in 0..idx.0 {
3185        let candidate = TypeIdx(candidate);
3186        if func_type_indices_equivalent(module, candidate, idx) {
3187            return candidate;
3188        }
3189    }
3190
3191    idx
3192}
3193
3194fn func_type_indices_equivalent(module: &Module<'_>, lhs: TypeIdx, rhs: TypeIdx) -> bool {
3195    let mut seen = BTreeSet::new();
3196    func_type_indices_equivalent_inner(module, lhs, rhs, &mut seen)
3197}
3198
3199fn func_type_indices_equivalent_inner(
3200    module: &Module<'_>,
3201    lhs: TypeIdx,
3202    rhs: TypeIdx,
3203    seen: &mut BTreeSet<(u32, u32)>,
3204) -> bool {
3205    let key = if lhs.0 <= rhs.0 {
3206        (lhs.0, rhs.0)
3207    } else {
3208        (rhs.0, lhs.0)
3209    };
3210    if !seen.insert(key) {
3211        return true;
3212    }
3213
3214    let Some(lhs_ty) = module.types.get(lhs.0 as usize) else {
3215        return false;
3216    };
3217    let Some(rhs_ty) = module.types.get(rhs.0 as usize) else {
3218        return false;
3219    };
3220
3221    lhs_ty.params.len() == rhs_ty.params.len()
3222        && lhs_ty.results.len() == rhs_ty.results.len()
3223        && lhs_ty
3224            .params
3225            .iter()
3226            .zip(&rhs_ty.params)
3227            .all(|(lhs, rhs)| valtype_equivalent_inner(module, *lhs, *rhs, seen))
3228        && lhs_ty
3229            .results
3230            .iter()
3231            .zip(&rhs_ty.results)
3232            .all(|(lhs, rhs)| valtype_equivalent_inner(module, *lhs, *rhs, seen))
3233}
3234
3235fn valtype_equivalent_inner(
3236    module: &Module<'_>,
3237    lhs: ValType,
3238    rhs: ValType,
3239    seen: &mut BTreeSet<(u32, u32)>,
3240) -> bool {
3241    match (lhs, rhs) {
3242        (ValType::Ref(lhs), ValType::Ref(rhs)) => reftype_equivalent_inner(module, lhs, rhs, seen),
3243        _ => lhs == rhs,
3244    }
3245}
3246
3247fn reftype_equivalent_inner(
3248    module: &Module<'_>,
3249    lhs: RefType,
3250    rhs: RefType,
3251    seen: &mut BTreeSet<(u32, u32)>,
3252) -> bool {
3253    lhs.is_nullable() == rhs.is_nullable()
3254        && match (lhs.heap_type(), rhs.heap_type()) {
3255            (crate::types::HeapType::Type(lhs), crate::types::HeapType::Type(rhs)) => {
3256                func_type_indices_equivalent_inner(module, lhs, rhs, seen)
3257            }
3258            (lhs, rhs) => lhs == rhs,
3259        }
3260}
3261
3262fn validate_func_type_definition_type_indices(
3263    module: &Module<'_>,
3264    current_type: TypeIdx,
3265    ty: &FuncType,
3266    offset: usize,
3267) -> Result<(), ValidationError> {
3268    for &param in &ty.params {
3269        validate_valtype_type_indices_in_type_definition(module, current_type, param, offset)?;
3270    }
3271    for &result in &ty.results {
3272        validate_valtype_type_indices_in_type_definition(module, current_type, result, offset)?;
3273    }
3274    Ok(())
3275}
3276
3277fn validate_valtype_type_indices(
3278    module: &Module<'_>,
3279    ty: ValType,
3280    function: Option<FuncIdx>,
3281    offset: usize,
3282) -> Result<(), ValidationError> {
3283    if let ValType::Ref(ref_type) = ty {
3284        validate_reftype_type_indices(module, ref_type, function, offset)?;
3285    }
3286    Ok(())
3287}
3288
3289fn validate_valtype_type_indices_in_type_definition(
3290    module: &Module<'_>,
3291    current_type: TypeIdx,
3292    ty: ValType,
3293    offset: usize,
3294) -> Result<(), ValidationError> {
3295    if let ValType::Ref(ref_type) = ty {
3296        validate_reftype_type_indices_in_type_definition(module, current_type, ref_type, offset)?;
3297    }
3298    Ok(())
3299}
3300
3301fn validate_reftype_type_indices(
3302    module: &Module<'_>,
3303    ty: RefType,
3304    function: Option<FuncIdx>,
3305    offset: usize,
3306) -> Result<(), ValidationError> {
3307    if let crate::types::HeapType::Type(idx) = ty.heap_type()
3308        && module.types.get(idx.0 as usize).is_none()
3309    {
3310        return Err(ValidationError {
3311            offset: ByteOffset(offset),
3312            function,
3313            kind: ValidationErrorKind::UnknownTypeIdx { idx },
3314        });
3315    }
3316
3317    Ok(())
3318}
3319
3320fn validate_reftype_type_indices_in_type_definition(
3321    module: &Module<'_>,
3322    current_type: TypeIdx,
3323    ty: RefType,
3324    offset: usize,
3325) -> Result<(), ValidationError> {
3326    if let crate::types::HeapType::Type(idx) = ty.heap_type()
3327        && (idx.0 > current_type.0 || module.types.get(idx.0 as usize).is_none())
3328    {
3329        return Err(ValidationError {
3330            offset: ByteOffset(offset),
3331            function: None,
3332            kind: ValidationErrorKind::UnknownTypeIdx { idx },
3333        });
3334    }
3335
3336    Ok(())
3337}
3338
3339fn normalize_reftype(module: &Module<'_>, ty: RefType) -> RefType {
3340    match ty.heap_type() {
3341        crate::types::HeapType::Type(idx) => RefType::from_parts(
3342            ty.is_nullable(),
3343            crate::types::HeapType::Type(canonicalize_func_type_idx(module, idx)),
3344        ),
3345        _ => ty,
3346    }
3347}
3348
3349fn normalize_valtype(module: &Module<'_>, ty: ValType) -> ValType {
3350    match ty {
3351        ValType::Ref(ref_type) => ValType::Ref(normalize_reftype(module, ref_type)),
3352        _ => ty,
3353    }
3354}
3355
3356fn normalize_func_type(module: &Module<'_>, ty: &FuncType) -> FuncType {
3357    FuncType {
3358        params: ty
3359            .params
3360            .iter()
3361            .copied()
3362            .map(|ty| normalize_valtype(module, ty))
3363            .collect(),
3364        results: ty
3365            .results
3366            .iter()
3367            .copied()
3368            .map(|ty| normalize_valtype(module, ty))
3369            .collect(),
3370    }
3371}
3372
3373fn normalize_global_type(
3374    module: &Module<'_>,
3375    ty: crate::types::GlobalType,
3376) -> crate::types::GlobalType {
3377    crate::types::GlobalType {
3378        val_type: normalize_valtype(module, ty.val_type),
3379        mutability: ty.mutability,
3380    }
3381}
3382
3383fn normalize_table_type(
3384    module: &Module<'_>,
3385    ty: crate::types::TableType,
3386) -> crate::types::TableType {
3387    crate::types::TableType {
3388        elem: normalize_reftype(module, ty.elem),
3389        limits: ty.limits,
3390        init: ty.init.clone(),
3391    }
3392}
3393
3394fn reftype_matches(found: RefType, expected: RefType) -> bool {
3395    found.is_subtype_of(expected)
3396}
3397
3398fn valtype_matches(found: ValType, expected: ValType) -> bool {
3399    found.is_subtype_of(expected)
3400}
3401
3402fn valtype_vec_matches(found: &[ValType], expected: &[ValType]) -> bool {
3403    found.len() == expected.len()
3404        && found
3405            .iter()
3406            .zip(expected)
3407            .all(|(found, expected)| valtype_matches(*found, *expected))
3408}
3409
3410fn is_stack_polymorphic(state: &ValidationState) -> bool {
3411    state.reachability == Reachability::Unreachable
3412        && state.operands.len() == state.current_frame().outer_height
3413}
3414
3415fn operand_matches(found: OperandType, expected: ValType) -> bool {
3416    match found {
3417        OperandType::Typed(found) => valtype_matches(found, expected),
3418        OperandType::Bottom => true,
3419    }
3420}
3421
3422fn operand_to_valtype(found: OperandType, fallback: ValType) -> ValType {
3423    match found {
3424        OperandType::Typed(found) => found,
3425        OperandType::Bottom => fallback,
3426    }
3427}
3428
3429fn concrete_stack(state: &ValidationState) -> Vec<ValType> {
3430    state
3431        .operands
3432        .as_slice()
3433        .iter()
3434        .filter_map(|operand| match operand {
3435            OperandType::Typed(ty) => Some(*ty),
3436            OperandType::Bottom => None,
3437        })
3438        .collect()
3439}
3440
3441fn stack_found(actual: &[OperandType], expected: &[ValType]) -> Vec<ValType> {
3442    let expected_start = expected.len().saturating_sub(actual.len());
3443    actual
3444        .iter()
3445        .enumerate()
3446        .filter_map(|(idx, operand)| match operand {
3447            OperandType::Typed(ty) => Some(*ty),
3448            OperandType::Bottom => expected.get(expected_start + idx).copied(),
3449        })
3450        .collect()
3451}
3452
3453fn ensure_frame_end_types(
3454    state: &ValidationState,
3455    outer_height: usize,
3456    expected: &[ValType],
3457) -> Result<(), Vec<ValType>> {
3458    let operands = state.operands.as_slice();
3459    if operands.len() < outer_height {
3460        return Err(Vec::new());
3461    }
3462    let actual = &operands[outer_height..];
3463    let found = stack_found(actual, expected);
3464
3465    if actual.len() > expected.len() {
3466        return Err(found);
3467    }
3468
3469    let expected_suffix = &expected[expected.len().saturating_sub(actual.len())..];
3470    if actual
3471        .iter()
3472        .zip(expected_suffix)
3473        .all(|(found, expected)| operand_matches(*found, *expected))
3474        && (state.reachability == Reachability::Unreachable || actual.len() == expected.len())
3475    {
3476        Ok(())
3477    } else {
3478        Err(found)
3479    }
3480}
3481
3482fn pop_operand(
3483    function: FuncIdx,
3484    state: &mut ValidationState,
3485    offset: usize,
3486    op: &'static str,
3487    expected: &[ValType],
3488) -> Result<OperandType, ValidationError> {
3489    if is_stack_polymorphic(state) {
3490        return Ok(OperandType::Bottom);
3491    }
3492
3493    match state.operands.pop() {
3494        Some(found) => Ok(found),
3495        None => Err(underflow_error(function, state, op, expected, offset)),
3496    }
3497}
3498
3499fn underflow_error(
3500    function: FuncIdx,
3501    state: &ValidationState,
3502    op: &'static str,
3503    expected: &[ValType],
3504    offset: usize,
3505) -> ValidationError {
3506    ValidationError {
3507        offset: ByteOffset(offset),
3508        function: Some(function),
3509        kind: ValidationErrorKind::StackUnderflow {
3510            op,
3511            expected: expected.to_vec(),
3512            available: concrete_stack(state),
3513        },
3514    }
3515}
3516
3517fn pop_expect(
3518    function: FuncIdx,
3519    state: &mut ValidationState,
3520    expected: ValType,
3521    offset: usize,
3522    op: &'static str,
3523) -> Result<(), ValidationError> {
3524    let found = pop_operand(function, state, offset, op, &[expected])?;
3525    if !operand_matches(found, expected) {
3526        return Err(ValidationError {
3527            offset: ByteOffset(offset),
3528            function: Some(function),
3529            kind: ValidationErrorKind::TypeMismatch {
3530                op,
3531                expected,
3532                found: operand_to_valtype(found, expected),
3533            },
3534        });
3535    }
3536    Ok(())
3537}
3538
3539fn pop_exact(
3540    function: FuncIdx,
3541    state: &mut ValidationState,
3542    expected: &[ValType],
3543    offset: usize,
3544) -> Result<(), ValidationError> {
3545    for expected_ty in expected.iter().rev() {
3546        pop_expect(function, state, *expected_ty, offset, "stack")?;
3547    }
3548    Ok(())
3549}
3550
3551fn validate_tail_call_results(
3552    function: FuncIdx,
3553    state: &ValidationState,
3554    found: &[ValType],
3555    offset: usize,
3556) -> Result<(), ValidationError> {
3557    let expected = &state.controls[0].end_types;
3558    if !valtype_vec_matches(found, expected) {
3559        return Err(ValidationError {
3560            offset: ByteOffset(offset),
3561            function: Some(function),
3562            kind: ValidationErrorKind::ResultTypeMismatch {
3563                expected: expected.clone(),
3564                found: found.to_vec(),
3565            },
3566        });
3567    }
3568
3569    Ok(())
3570}
3571
3572fn pop_branch_types(
3573    function: FuncIdx,
3574    state: &mut ValidationState,
3575    label: crate::types::LabelIdx,
3576    expected: &[ValType],
3577    offset: usize,
3578) -> Result<(), ValidationError> {
3579    ensure_stack_types(state, expected).map_err(|found| ValidationError {
3580        offset: ByteOffset(offset),
3581        function: Some(function),
3582        kind: ValidationErrorKind::BranchTypeMismatch {
3583            label,
3584            expected: expected.to_vec(),
3585            found,
3586        },
3587    })?;
3588    pop_exact(function, state, expected, offset)
3589}
3590
3591fn pop_control_result_types(
3592    function: FuncIdx,
3593    state: &mut ValidationState,
3594    expected: &[ValType],
3595    offset: usize,
3596) -> Result<(), ValidationError> {
3597    ensure_stack_types(state, expected).map_err(|found| ValidationError {
3598        offset: ByteOffset(offset),
3599        function: Some(function),
3600        kind: ValidationErrorKind::ControlResultTypeMismatch {
3601            expected: expected.to_vec(),
3602            found,
3603        },
3604    })?;
3605    pop_exact(function, state, expected, offset)
3606}
3607
3608fn ensure_stack_types(state: &ValidationState, expected: &[ValType]) -> Result<(), Vec<ValType>> {
3609    if is_stack_polymorphic(state) {
3610        return Ok(());
3611    }
3612
3613    let operands = state.operands.as_slice();
3614    let found_len = core::cmp::min(operands.len(), expected.len());
3615    let found = &operands[operands.len().saturating_sub(found_len)..];
3616    let expected_suffix = &expected[expected.len() - found_len..];
3617
3618    if (state.reachability == Reachability::Reachable && operands.len() < expected.len())
3619        || !found
3620            .iter()
3621            .zip(expected_suffix)
3622            .all(|(found, expected)| operand_matches(*found, *expected))
3623    {
3624        return Err(found
3625            .iter()
3626            .zip(expected_suffix)
3627            .map(|(found, expected)| operand_to_valtype(*found, *expected))
3628            .collect());
3629    }
3630
3631    Ok(())
3632}
3633
3634fn pop_operand_type(
3635    function: FuncIdx,
3636    state: &mut ValidationState,
3637    offset: usize,
3638    op: &'static str,
3639) -> Result<OperandType, ValidationError> {
3640    pop_operand(function, state, offset, op, &[])
3641}
3642
3643fn pop_ref_type(
3644    function: FuncIdx,
3645    state: &mut ValidationState,
3646    offset: usize,
3647    op: &'static str,
3648) -> Result<Option<RefType>, ValidationError> {
3649    let found = pop_operand_type(function, state, offset, op)?;
3650    match found {
3651        OperandType::Bottom => Ok(None),
3652        OperandType::Typed(ValType::Ref(ref_type)) => Ok(Some(ref_type)),
3653        OperandType::Typed(found) => Err(ValidationError {
3654            offset: ByteOffset(offset),
3655            function: Some(function),
3656            kind: ValidationErrorKind::TypeMismatch {
3657                op,
3658                expected: ValType::Ref(RefType::ExternRef),
3659                found,
3660            },
3661        }),
3662    }
3663}
3664
3665fn pop_any(
3666    function: FuncIdx,
3667    state: &mut ValidationState,
3668    offset: usize,
3669    op: &'static str,
3670) -> Result<(), ValidationError> {
3671    pop_operand(function, state, offset, op, &[]).map(|_| ())
3672}
3673
3674fn expand_locals(
3675    module: &Module<'_>,
3676    function: FuncIdx,
3677    locals: &mut Vec<ValType>,
3678    local_decls: &[LocalDecl],
3679    offset: usize,
3680) -> Result<(), ValidationError> {
3681    for decl in local_decls {
3682        validate_valtype_type_indices(module, decl.val_type, Some(function), offset)?;
3683        for _ in 0..decl.count {
3684            locals.push(normalize_valtype(module, decl.val_type));
3685        }
3686    }
3687    Ok(())
3688}
3689
3690#[cfg(test)]
3691mod tests {
3692    use super::*;
3693    use crate::binary::module::Module;
3694    use crate::types::{LabelIdx, LocalIdx};
3695
3696    #[test]
3697    fn validate_simple_add_module() {
3698        let bytes = [
3699            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01, 0x60, 0x02, 0x7F,
3700            0x7F, 0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00,
3701            0x20, 0x01, 0x6A, 0x0B,
3702        ];
3703        let module = Module::decode(&bytes).unwrap();
3704        module.validate().unwrap();
3705    }
3706
3707    #[test]
3708    fn reject_unknown_local_index() {
3709        let bytes = [
3710            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
3711            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0B,
3712        ];
3713        let module = Module::decode(&bytes).unwrap();
3714        let err = module.validate().unwrap_err();
3715        assert!(matches!(
3716            err.kind,
3717            ValidationErrorKind::UnknownLocalIdx { .. }
3718        ));
3719        assert_eq!(err.offset, ByteOffset(24));
3720    }
3721
3722    #[test]
3723    fn validate_forward_mutual_recursion() {
3724        let bytes =
3725            include_bytes!("../../../baedeker-testdata/spec/valid/forward-mutual-recursion.wasm");
3726        let module = Module::decode(bytes).unwrap();
3727        module.validate().unwrap();
3728    }
3729
3730    #[test]
3731    fn validate_local_get_after_set_for_non_defaultable_local() {
3732        let bytes =
3733            include_bytes!("../../../baedeker-testdata/spec/valid/local-init-get-after-set.wasm");
3734        let module = Module::decode(bytes).unwrap();
3735        module.validate().unwrap();
3736    }
3737
3738    #[test]
3739    fn validate_local_get_after_tee_for_non_defaultable_local() {
3740        let bytes =
3741            include_bytes!("../../../baedeker-testdata/spec/valid/local-init-get-after-tee.wasm");
3742        let module = Module::decode(bytes).unwrap();
3743        module.validate().unwrap();
3744    }
3745
3746    #[test]
3747    fn validate_local_get_in_block_after_set_for_non_defaultable_local() {
3748        let bytes = include_bytes!(
3749            "../../../baedeker-testdata/spec/valid/local-init-get-in-block-after-set.wasm",
3750        );
3751        let module = Module::decode(bytes).unwrap();
3752        module.validate().unwrap();
3753    }
3754
3755    #[test]
3756    fn validate_local_tee_init_official_case() {
3757        let bytes =
3758            include_bytes!("../../../baedeker-testdata/spec/valid/local-init-tee-init.wasm");
3759        let module = Module::decode(bytes).unwrap();
3760        module.validate().unwrap();
3761    }
3762
3763    #[test]
3764    fn reject_uninitialized_non_defaultable_local() {
3765        let bytes = include_bytes!(
3766            "../../../baedeker-testdata/spec/invalid-validate/local-init-uninitialized-local.wasm",
3767        );
3768        let module = Module::decode(bytes).unwrap();
3769        let err = module.validate().unwrap_err();
3770        assert_eq!(err.offset, ByteOffset(26));
3771        assert!(matches!(
3772            err.kind,
3773            ValidationErrorKind::UninitializedLocal { idx: LocalIdx(0) }
3774        ));
3775    }
3776
3777    #[test]
3778    fn reject_non_defaultable_local_initialized_only_inside_block() {
3779        let bytes = include_bytes!(
3780            "../../../baedeker-testdata/spec/invalid-validate/local-init-uninitialized-after-end.wasm",
3781        );
3782        let module = Module::decode(bytes).unwrap();
3783        let err = module.validate().unwrap_err();
3784        assert_eq!(err.offset, ByteOffset(40));
3785        assert!(matches!(
3786            err.kind,
3787            ValidationErrorKind::UninitializedLocal { idx: LocalIdx(1) }
3788        ));
3789    }
3790
3791    #[test]
3792    fn reject_non_defaultable_local_get_in_else_without_prior_init() {
3793        let bytes = include_bytes!(
3794            "../../../baedeker-testdata/spec/invalid-validate/local-init-uninitialized-in-else.wasm",
3795        );
3796        let module = Module::decode(bytes).unwrap();
3797        let err = module.validate().unwrap_err();
3798        assert_eq!(err.offset, ByteOffset(37));
3799        assert!(matches!(
3800            err.kind,
3801            ValidationErrorKind::UninitializedLocal { idx: LocalIdx(1) }
3802        ));
3803    }
3804
3805    #[test]
3806    fn reject_non_defaultable_local_init_not_escaping_if() {
3807        let bytes = include_bytes!(
3808            "../../../baedeker-testdata/spec/invalid-validate/local-init-uninitialized-from-if.wasm",
3809        );
3810        let module = Module::decode(bytes).unwrap();
3811        let err = module.validate().unwrap_err();
3812        assert_eq!(err.offset, ByteOffset(42));
3813        assert!(matches!(
3814            err.kind,
3815            ValidationErrorKind::UninitializedLocal { idx: LocalIdx(1) }
3816        ));
3817    }
3818
3819    #[test]
3820    fn validate_unreached_call_ref() {
3821        let bytes = include_bytes!("../../../baedeker-testdata/spec/valid/unreached-call-ref.wasm");
3822        let module = Module::decode(bytes).unwrap();
3823        module.validate().unwrap();
3824    }
3825
3826    #[test]
3827    fn validate_select_after_unreachable_with_bottom_operands() {
3828        let bytes = include_bytes!(
3829            "../../../baedeker-testdata/spec/valid/unreached-valid-select-after-unreachable.wasm",
3830        );
3831        let module = Module::decode(bytes).unwrap();
3832        module.validate().unwrap();
3833    }
3834
3835    #[test]
3836    fn validate_unreached_core_stack_polymorphism_cases() {
3837        let bytes =
3838            include_bytes!("../../../baedeker-testdata/spec/valid/unreached-valid-core.wasm");
3839        let module = Module::decode(bytes).unwrap();
3840        module.validate().unwrap();
3841    }
3842
3843    #[test]
3844    fn validate_unreached_bottom_heap_type_cases() {
3845        let bytes =
3846            include_bytes!("../../../baedeker-testdata/spec/valid/unreached-bottom-heap-type.wasm");
3847        let module = Module::decode(bytes).unwrap();
3848        module.validate().unwrap();
3849    }
3850
3851    #[test]
3852    fn validate_unreached_meet_bottom_br_table() {
3853        let bytes =
3854            include_bytes!("../../../baedeker-testdata/spec/valid/unreached-meet-bottom.wasm");
3855        let module = Module::decode(bytes).unwrap();
3856        module.validate().unwrap();
3857    }
3858
3859    #[test]
3860    fn validate_unreached_select_i64_result_official_case() {
3861        let bytes = include_bytes!(
3862            "../../../baedeker-testdata/spec/valid/unreached-valid-select-i64-result.wasm",
3863        );
3864        let module = Module::decode(bytes).unwrap();
3865        module.validate().unwrap();
3866    }
3867
3868    #[test]
3869    fn reject_unreached_select_result_mismatch() {
3870        let bytes = include_bytes!(
3871            "../../../baedeker-testdata/spec/invalid-validate/unreached-select-result-mismatch.wasm",
3872        );
3873        let module = Module::decode(bytes).unwrap();
3874        let err = module.validate().unwrap_err();
3875        assert_eq!(err.offset, ByteOffset(30));
3876        assert!(matches!(
3877            err.kind,
3878            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
3879                if expected == vec![ValType::Num(crate::types::NumType::I32)]
3880                    && found == vec![ValType::Num(crate::types::NumType::I64)]
3881        ));
3882    }
3883
3884    #[test]
3885    fn reject_unreached_unconsumed_const() {
3886        let bytes = include_bytes!(
3887            "../../../baedeker-testdata/spec/invalid-validate/unreached-unconsumed-const.wasm",
3888        );
3889        let module = Module::decode(bytes).unwrap();
3890        let err = module.validate().unwrap_err();
3891        assert_eq!(err.offset, ByteOffset(26));
3892        assert!(matches!(
3893            err.kind,
3894            ValidationErrorKind::FunctionResultTypeMismatch { expected, .. }
3895                if expected.is_empty()
3896        ));
3897    }
3898
3899    #[test]
3900    fn reject_unknown_local_index_in_unreachable_code() {
3901        let bytes = include_bytes!(
3902            "../../../baedeker-testdata/spec/invalid-validate/unreached-unknown-local-index.wasm",
3903        );
3904        let module = Module::decode(bytes).unwrap();
3905        let err = module.validate().unwrap_err();
3906        assert_eq!(err.offset, ByteOffset(24));
3907        assert!(matches!(
3908            err.kind,
3909            ValidationErrorKind::UnknownLocalIdx { idx: LocalIdx(0) }
3910        ));
3911    }
3912
3913    #[test]
3914    fn reject_unknown_global_index_in_unreachable_code() {
3915        let bytes = include_bytes!(
3916            "../../../baedeker-testdata/spec/invalid-validate/unreached-unknown-global-index.wasm",
3917        );
3918        let module = Module::decode(bytes).unwrap();
3919        let err = module.validate().unwrap_err();
3920        assert_eq!(err.offset, ByteOffset(24));
3921        assert!(matches!(
3922            err.kind,
3923            ValidationErrorKind::UnknownGlobalIdx {
3924                idx: GlobalIdx(0),
3925                available: 0,
3926            }
3927        ));
3928    }
3929
3930    #[test]
3931    fn reject_unknown_function_index_in_unreachable_code() {
3932        let bytes = include_bytes!(
3933            "../../../baedeker-testdata/spec/invalid-validate/unreached-unknown-function-index.wasm",
3934        );
3935        let module = Module::decode(bytes).unwrap();
3936        let err = module.validate().unwrap_err();
3937        assert_eq!(err.offset, ByteOffset(24));
3938        assert!(matches!(
3939            err.kind,
3940            ValidationErrorKind::UnknownFuncIdx { idx: FuncIdx(1) }
3941        ));
3942    }
3943
3944    #[test]
3945    fn reject_unknown_label_index_in_unreachable_code() {
3946        let bytes = include_bytes!(
3947            "../../../baedeker-testdata/spec/invalid-validate/unreached-unknown-label-index.wasm",
3948        );
3949        let module = Module::decode(bytes).unwrap();
3950        let err = module.validate().unwrap_err();
3951        assert_eq!(err.offset, ByteOffset(24));
3952        assert!(matches!(
3953            err.kind,
3954            ValidationErrorKind::UnknownLabelIdx { idx: LabelIdx(1) }
3955        ));
3956    }
3957
3958    #[test]
3959    fn validate_unreachable_function_end_with_result_type() {
3960        let bytes = [
3961            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
3962            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x05, 0x01, 0x03, 0x00, 0x00, 0x0B,
3963        ];
3964        let module = Module::decode(&bytes).unwrap();
3965        module.validate().unwrap();
3966    }
3967
3968    #[test]
3969    fn report_stack_underflow_with_operation_context() {
3970        let bytes = [
3971            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
3972            0x03, 0x02, 0x01, 0x00, 0x0A, 0x05, 0x01, 0x03, 0x00, 0x6A, 0x0B,
3973        ];
3974        let module = Module::decode(&bytes).unwrap();
3975        let err = module.validate().unwrap_err();
3976        assert_eq!(err.offset, ByteOffset(23));
3977        assert!(matches!(
3978            err.kind,
3979            ValidationErrorKind::StackUnderflow { op, expected, available }
3980                if op == "i32.binary"
3981                    && expected == vec![ValType::Num(crate::types::NumType::I32)]
3982                    && available.is_empty()
3983        ));
3984    }
3985
3986    #[test]
3987    fn report_type_mismatch_with_operation_context() {
3988        let bytes = [
3989            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
3990            0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x42, 0x01, 0x41, 0x02, 0x6A,
3991            0x0B,
3992        ];
3993        let module = Module::decode(&bytes).unwrap();
3994        let err = module.validate().unwrap_err();
3995        assert_eq!(err.offset, ByteOffset(27));
3996        assert!(matches!(
3997            err.kind,
3998            ValidationErrorKind::TypeMismatch { op, expected, found }
3999                if op == "i32.binary"
4000                    && expected == ValType::Num(crate::types::NumType::I32)
4001                    && found == ValType::Num(crate::types::NumType::I64)
4002        ));
4003    }
4004
4005    #[test]
4006    fn report_precise_offset_for_later_instruction() {
4007        let bytes = [
4008            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F,
4009            0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20,
4010            0x01, 0x6A, 0x0B,
4011        ];
4012        let module = Module::decode(&bytes).unwrap();
4013        let err = module.validate().unwrap_err();
4014        assert!(matches!(
4015            err.kind,
4016            ValidationErrorKind::UnknownLocalIdx { .. }
4017        ));
4018        assert_eq!(err.offset, ByteOffset(27));
4019    }
4020
4021    #[test]
4022    fn reject_unknown_function_type_index() {
4023        let bytes = [
4024            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x02, 0x01,
4025            0x01, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
4026        ];
4027        let module = Module::decode(&bytes).unwrap();
4028        let err = module.validate().unwrap_err();
4029        assert!(matches!(
4030            err.kind,
4031            ValidationErrorKind::UnknownTypeIdx { .. }
4032        ));
4033    }
4034
4035    #[test]
4036    fn reject_import_with_unknown_type_index() {
4037        let bytes = [
4038            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
4039            0x7F, 0x02, 0x0D, 0x01, 0x04, b't', b'e', b's', b't', 0x04, b'f', b'u', b'n', b'c',
4040            0x00, 0x01,
4041        ];
4042        let module = Module::decode(&bytes).unwrap();
4043        let err = module.validate().unwrap_err();
4044        assert!(matches!(
4045            err.kind,
4046            ValidationErrorKind::UnknownTypeIdx {
4047                idx: crate::types::TypeIdx(1)
4048            }
4049        ));
4050    }
4051
4052    #[test]
4053    fn reject_typed_function_type_with_unknown_concrete_type_idx() {
4054        let bytes = [
4055            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x63,
4056            0x01, 0x00, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0x20, 0x00, 0x1A,
4057            0x0B,
4058        ];
4059        let module = Module::decode(&bytes).unwrap();
4060        let err = module.validate().unwrap_err();
4061        assert_eq!(err.offset, ByteOffset(10));
4062        assert!(matches!(
4063            err.kind,
4064            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4065        ));
4066    }
4067
4068    #[test]
4069    fn reject_imported_typed_global_with_unknown_concrete_type_idx() {
4070        let bytes = [
4071            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4072            0x02, 0x0B, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x63, 0x01, 0x00,
4073        ];
4074        let module = Module::decode(&bytes).unwrap();
4075        let err = module.validate().unwrap_err();
4076        assert_eq!(err.offset, ByteOffset(16));
4077        assert!(matches!(
4078            err.kind,
4079            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4080        ));
4081    }
4082
4083    #[test]
4084    fn reject_typed_table_with_unknown_concrete_type_idx() {
4085        let bytes = [
4086            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4087            0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x01,
4088        ];
4089        let module = Module::decode(&bytes).unwrap();
4090        let err = module.validate().unwrap_err();
4091        assert_eq!(err.offset, ByteOffset(16));
4092        assert!(matches!(
4093            err.kind,
4094            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4095        ));
4096    }
4097
4098    #[test]
4099    fn reject_typed_element_with_unknown_concrete_type_idx() {
4100        let bytes = [
4101            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4102            0x09, 0x08, 0x01, 0x05, 0x63, 0x01, 0x01, 0xD0, 0x01, 0x0B,
4103        ];
4104        let module = Module::decode(&bytes).unwrap();
4105        let err = module.validate().unwrap_err();
4106        assert_eq!(err.offset, ByteOffset(16));
4107        assert!(matches!(
4108            err.kind,
4109            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4110        ));
4111    }
4112
4113    #[test]
4114    fn reject_typed_local_with_unknown_concrete_type_idx() {
4115        let bytes = [
4116            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4117            0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x01, 0x01, 0x63, 0x01, 0x0B,
4118        ];
4119        let module = Module::decode(&bytes).unwrap();
4120        let err = module.validate().unwrap_err();
4121        assert_eq!(err.offset, ByteOffset(26));
4122        assert!(matches!(
4123            err.kind,
4124            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4125        ));
4126    }
4127
4128    #[test]
4129    fn reject_ref_null_with_unknown_concrete_type_idx() {
4130        let bytes = [
4131            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4132            0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xD0, 0x01, 0x1A, 0x0B,
4133        ];
4134        let module = Module::decode(&bytes).unwrap();
4135        let err = module.validate().unwrap_err();
4136        assert_eq!(err.offset, ByteOffset(23));
4137        assert!(matches!(
4138            err.kind,
4139            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4140        ));
4141    }
4142
4143    #[test]
4144    fn reject_block_result_with_unknown_concrete_type_idx() {
4145        let bytes = [
4146            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4147            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0B, 0x01, 0x09, 0x00, 0x02, 0x63, 0x01, 0xD0, 0x01,
4148            0x1A, 0x0B, 0x0B,
4149        ];
4150        let module = Module::decode(&bytes).unwrap();
4151        let err = module.validate().unwrap_err();
4152        assert_eq!(err.offset, ByteOffset(23));
4153        assert!(matches!(
4154            err.kind,
4155            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4156        ));
4157    }
4158
4159    #[test]
4160    fn reject_forward_type_reference_outside_rec_group() {
4161        let bytes = include_bytes!(
4162            "../../../baedeker-testdata/spec/invalid-validate/type-forward-ref-outside-rec-group.wasm",
4163        );
4164        let module = Module::decode(bytes).unwrap();
4165        let err = module.validate().unwrap_err();
4166        assert_eq!(err.offset, ByteOffset(10));
4167        assert!(matches!(
4168            err.kind,
4169            ValidationErrorKind::UnknownTypeIdx { idx: TypeIdx(1) }
4170        ));
4171    }
4172
4173    #[test]
4174    fn report_function_result_stack_suffix() {
4175        let bytes = [
4176            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
4177            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0x41, 0x01, 0x41, 0x02,
4178            0x0B,
4179        ];
4180        let module = Module::decode(&bytes).unwrap();
4181        let err = module.validate().unwrap_err();
4182        assert_eq!(err.offset, ByteOffset(28));
4183        assert!(matches!(
4184            err.kind,
4185            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, full_stack }
4186                if expected == vec![ValType::Num(crate::types::NumType::I32)]
4187                    && found == vec![ValType::Num(crate::types::NumType::I32)]
4188                    && full_stack == vec![
4189                        ValType::Num(crate::types::NumType::I32),
4190                        ValType::Num(crate::types::NumType::I32),
4191                    ]
4192        ));
4193    }
4194
4195    #[test]
4196    fn validate_unreachable_stack_polymorphism_after_br() {
4197        let bytes = [
4198            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4199            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0A, 0x01, 0x08, 0x00, 0x02, 0x40, 0x0C, 0x00, 0x1A,
4200            0x0B, 0x0B,
4201        ];
4202        let module = Module::decode(&bytes).unwrap();
4203        module.validate().unwrap();
4204    }
4205
4206    #[test]
4207    fn validate_typed_unreachable_block_dead_ref_with_equivalent_signature() {
4208        let bytes = [
4209            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
4210            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
4211            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x10, 0x02, 0x04,
4212            0x00, 0x20, 0x00, 0x0b, 0x09, 0x00, 0x02, 0x63, 0x01, 0x00, 0xd2, 0x00, 0x0b, 0x0b,
4213        ];
4214        let module = Module::decode(&bytes).unwrap();
4215        module.validate().unwrap();
4216    }
4217
4218    #[test]
4219    fn reject_typed_unreachable_block_dead_ref_with_wrong_concrete_type() {
4220        let bytes = [
4221            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7e,
4222            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
4223            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x10, 0x02, 0x04,
4224            0x00, 0x20, 0x00, 0x0b, 0x09, 0x00, 0x02, 0x63, 0x01, 0x00, 0xd2, 0x00, 0x0b, 0x0b,
4225        ];
4226        let module = Module::decode(&bytes).unwrap();
4227        let err = module.validate().unwrap_err();
4228        assert_eq!(err.offset, ByteOffset(54));
4229        assert!(matches!(
4230            err.kind,
4231            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
4232                if expected == vec![ValType::Ref(RefType::Typed {
4233                    nullable: true,
4234                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4235                })] && found == vec![ValType::Ref(RefType::Typed {
4236                    nullable: false,
4237                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4238                })]
4239        ));
4240    }
4241
4242    #[test]
4243    fn validate_typed_br_dead_ref_with_equivalent_signature() {
4244        let bytes = [
4245            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
4246            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03,
4247            0x02, 0x01, 0x02, 0x07, 0x06, 0x01, 0x02, 0x66, 0x31, 0x00, 0x00, 0x0a, 0x13, 0x02,
4248            0x04, 0x00, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x02, 0x63, 0x00, 0xd2, 0x00, 0x0c, 0x00,
4249            0xd0, 0x01, 0x0b, 0x0b,
4250        ];
4251        let module = Module::decode(&bytes).unwrap();
4252        module.validate().unwrap();
4253    }
4254
4255    #[test]
4256    fn reject_typed_br_dead_ref_with_wrong_concrete_type() {
4257        let bytes = include_bytes!(
4258            "../../../baedeker-testdata/spec/invalid-validate/typed-br-dead-ref-wrong-concrete-type.wasm",
4259        );
4260        let module = Module::decode(bytes).unwrap();
4261        let err = module.validate().unwrap_err();
4262        assert_eq!(err.offset, ByteOffset(58));
4263        assert!(matches!(
4264            err.kind,
4265            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
4266                if expected == vec![ValType::Ref(RefType::Typed {
4267                    nullable: true,
4268                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4269                })] && found == vec![ValType::Ref(RefType::Typed {
4270                    nullable: true,
4271                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4272                })]
4273        ));
4274    }
4275
4276    #[test]
4277    fn validate_typed_select_to_br_nullable_official_case() {
4278        let bytes = include_bytes!(
4279            "../../../baedeker-testdata/spec/valid/typed-select-to-br-nullable.wasm",
4280        );
4281        let module = Module::decode(bytes).unwrap();
4282        module.validate().unwrap();
4283    }
4284
4285    #[test]
4286    fn reject_typed_select_to_br_nullability_mismatch() {
4287        let bytes = include_bytes!(
4288            "../../../baedeker-testdata/spec/invalid-validate/typed-select-to-br-nullability-mismatch.wasm",
4289        );
4290        let module = Module::decode(bytes).unwrap();
4291        let err = module.validate().unwrap_err();
4292        assert_eq!(err.offset, ByteOffset(57));
4293        assert!(matches!(
4294            err.kind,
4295            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
4296                if label == crate::types::LabelIdx(0)
4297                    && expected == vec![ValType::Ref(RefType::Typed {
4298                        nullable: false,
4299                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4300                    })]
4301                    && found == vec![ValType::Ref(RefType::Typed {
4302                        nullable: true,
4303                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4304                    })]
4305        ));
4306    }
4307
4308    #[test]
4309    fn validate_typed_table_init_to_br_nullable_official_case() {
4310        let bytes = include_bytes!(
4311            "../../../baedeker-testdata/spec/valid/typed-table-init-to-br-nullable.wasm",
4312        );
4313        let module = Module::decode(bytes).unwrap();
4314        module.validate().unwrap();
4315    }
4316
4317    #[test]
4318    fn reject_typed_table_init_to_br_nullability_mismatch() {
4319        let bytes = include_bytes!(
4320            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-to-br-nullability-mismatch.wasm",
4321        );
4322        let module = Module::decode(bytes).unwrap();
4323        let err = module.validate().unwrap_err();
4324        assert_eq!(err.offset, ByteOffset(86));
4325        assert!(matches!(
4326            err.kind,
4327            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
4328                if label == crate::types::LabelIdx(0)
4329                    && expected == vec![ValType::Ref(RefType::Typed {
4330                        nullable: false,
4331                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4332                    })]
4333                    && found == vec![ValType::Ref(RefType::Typed {
4334                        nullable: true,
4335                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4336                    })]
4337        ));
4338    }
4339
4340    #[test]
4341    fn validate_typed_table_init_shared_source_to_br_nullable_official_case() {
4342        let bytes = include_bytes!(
4343            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-br-nullable.wasm",
4344        );
4345        let module = Module::decode(bytes).unwrap();
4346        module.validate().unwrap();
4347    }
4348
4349    #[test]
4350    fn reject_typed_table_init_shared_source_to_br_nullability_mismatch() {
4351        let bytes = include_bytes!(
4352            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-br-nullability-mismatch.wasm",
4353        );
4354        let module = Module::decode(bytes).unwrap();
4355        let err = module.validate().unwrap_err();
4356        assert_eq!(err.offset, ByteOffset(97));
4357        assert!(matches!(
4358            err.kind,
4359            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
4360                if label == crate::types::LabelIdx(0)
4361                    && expected == vec![ValType::Ref(RefType::Typed {
4362                        nullable: false,
4363                        heap: crate::types::HeapType::Type(TypeIdx(1)),
4364                    })]
4365                    && found == vec![ValType::Ref(RefType::Typed {
4366                        nullable: true,
4367                        heap: crate::types::HeapType::Type(TypeIdx(1)),
4368                    })]
4369        ));
4370    }
4371
4372    #[test]
4373    fn validate_imported_global_get_and_set() {
4374        let bytes = [
4375            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4376            0x02, 0x0A, 0x01, 0x03, b'e', b'n', b'v', 0x01, b'g', 0x03, 0x7F, 0x01, 0x03, 0x02,
4377            0x01, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0x23, 0x00, 0x24, 0x00, 0x0B,
4378        ];
4379        let module = Module::decode(&bytes).unwrap();
4380        module.validate().unwrap();
4381    }
4382
4383    #[test]
4384    fn reject_global_set_on_immutable_global() {
4385        let bytes = [
4386            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4387            0x03, 0x02, 0x01, 0x00, 0x06, 0x09, 0x01, 0x7D, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00,
4388            0x0B, 0x0A, 0x0B, 0x01, 0x09, 0x00, 0x43, 0x00, 0x00, 0x80, 0x3F, 0x24, 0x00, 0x0B,
4389        ];
4390        let module = Module::decode(&bytes).unwrap();
4391        let err = module.validate().unwrap_err();
4392        assert!(matches!(
4393            err.kind,
4394            ValidationErrorKind::ImmutableGlobalSet { idx: GlobalIdx(0) }
4395        ));
4396        assert_eq!(err.offset.0, 39);
4397    }
4398
4399    #[test]
4400    fn validate_defined_global_get() {
4401        let bytes = [
4402            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
4403            0x7F, 0x03, 0x02, 0x01, 0x00, 0x06, 0x06, 0x01, 0x7F, 0x00, 0x41, 0x2A, 0x0B, 0x0A,
4404            0x06, 0x01, 0x04, 0x00, 0x23, 0x00, 0x0B,
4405        ];
4406        let module = Module::decode(&bytes).unwrap();
4407        module.validate().unwrap();
4408    }
4409
4410    #[test]
4411    fn validate_ref_is_null() {
4412        let bytes = [
4413            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
4414            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xD0, 0x6F, 0xD1, 0x0B,
4415        ];
4416        let module = Module::decode(&bytes).unwrap();
4417        module.validate().unwrap();
4418    }
4419
4420    #[test]
4421    fn reject_ref_is_null_on_non_ref() {
4422        let bytes = [
4423            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
4424            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0x41, 0x00, 0xD1, 0x0B,
4425        ];
4426        let module = Module::decode(&bytes).unwrap();
4427        let err = module.validate().unwrap_err();
4428        assert_eq!(err.offset, ByteOffset(26));
4429        assert!(matches!(
4430            err.kind,
4431            ValidationErrorKind::TypeMismatch {
4432                op: "ref.is_null",
4433                found: ValType::Num(crate::types::NumType::I32),
4434                ..
4435            }
4436        ));
4437    }
4438
4439    #[test]
4440    fn validate_ref_as_non_null() {
4441        let bytes = [
4442            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x00, 0x01,
4443            0x7F, 0x60, 0x01, 0x63, 0x00, 0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x01, 0x07, 0x05,
4444            0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x0E, 0x02, 0x04, 0x00, 0x41, 0x07, 0x0B, 0x07,
4445            0x00, 0x20, 0x00, 0xD4, 0x14, 0x00, 0x0B,
4446        ];
4447        let module = Module::decode(&bytes).unwrap();
4448        module.validate().unwrap();
4449    }
4450
4451    #[test]
4452    fn validate_ref_as_non_null_after_unreachable_official_case() {
4453        let bytes = include_bytes!(
4454            "../../../baedeker-testdata/spec/valid/ref-as-non-null-unreachable.wasm"
4455        );
4456        let module = Module::decode(bytes).unwrap();
4457        module.validate().unwrap();
4458    }
4459
4460    #[test]
4461    fn validate_ref_as_non_null_direct_call_ref_func_official_case() {
4462        let bytes = include_bytes!(
4463            "../../../baedeker-testdata/spec/valid/ref-as-non-null-direct-call-ref-func.wasm",
4464        );
4465        let module = Module::decode(bytes).unwrap();
4466        module.validate().unwrap();
4467    }
4468
4469    #[test]
4470    fn reject_ref_as_non_null_on_non_ref() {
4471        let bytes = [
4472            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4473            0x03, 0x02, 0x01, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0x41, 0x00, 0xD4, 0x1A, 0x0B,
4474        ];
4475        let module = Module::decode(&bytes).unwrap();
4476        let err = module.validate().unwrap_err();
4477        assert_eq!(err.offset, ByteOffset(25));
4478        assert!(matches!(
4479            err.kind,
4480            ValidationErrorKind::TypeMismatch {
4481                op: "ref.as_non_null",
4482                expected: ValType::Ref(RefType::ExternRef),
4483                found: ValType::Num(crate::types::NumType::I32),
4484            }
4485        ));
4486    }
4487
4488    #[test]
4489    fn reject_ref_as_non_null_null_to_nonnull_call_official_case() {
4490        let bytes = include_bytes!(
4491            "../../../baedeker-testdata/spec/invalid-validate/ref-as-non-null-null-to-nonnull-call.wasm",
4492        );
4493        let module = Module::decode(bytes).unwrap();
4494        let err = module.validate().unwrap_err();
4495        assert_eq!(err.offset, ByteOffset(42));
4496        assert!(matches!(
4497            err.kind,
4498            ValidationErrorKind::TypeMismatch { op, expected, found }
4499                if op == "stack"
4500                    && expected == ValType::Ref(RefType::Typed {
4501                        nullable: false,
4502                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4503                    })
4504                    && found == ValType::Ref(RefType::Typed {
4505                        nullable: true,
4506                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4507                    })
4508        ));
4509    }
4510
4511    #[test]
4512    fn validate_typed_ref_as_non_null_global_set_with_equivalent_signature() {
4513        let bytes = include_bytes!(
4514            "../../../baedeker-testdata/spec/valid/typed-ref-as-non-null-global-set-equivalent-signature.wasm",
4515        );
4516        let module = Module::decode(bytes).unwrap();
4517        module.validate().unwrap();
4518    }
4519
4520    #[test]
4521    fn reject_typed_ref_as_non_null_global_set_with_wrong_concrete_type() {
4522        let bytes = include_bytes!(
4523            "../../../baedeker-testdata/spec/invalid-validate/typed-ref-as-non-null-global-set-wrong-concrete-type.wasm",
4524        );
4525        let module = Module::decode(bytes).unwrap();
4526        let err = module.validate().unwrap_err();
4527        assert_eq!(err.offset, ByteOffset(51));
4528        assert!(matches!(
4529            err.kind,
4530            ValidationErrorKind::TypeMismatch { op, expected, found }
4531                if op == "global.set"
4532                    && expected == ValType::Ref(RefType::Typed {
4533                        nullable: true,
4534                        heap: crate::types::HeapType::Type(TypeIdx(1)),
4535                    })
4536                    && found == ValType::Ref(RefType::Typed {
4537                        nullable: false,
4538                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4539                    })
4540        ));
4541    }
4542
4543    #[test]
4544    fn validate_typed_ref_as_non_null_if_join_with_equivalent_signature() {
4545        let bytes = include_bytes!(
4546            "../../../baedeker-testdata/spec/valid/typed-ref-as-non-null-if-join-equivalent-signature.wasm",
4547        );
4548        let module = Module::decode(bytes).unwrap();
4549        module.validate().unwrap();
4550    }
4551
4552    #[test]
4553    fn reject_typed_ref_as_non_null_if_join_with_wrong_concrete_type() {
4554        let bytes = include_bytes!(
4555            "../../../baedeker-testdata/spec/invalid-validate/typed-ref-as-non-null-if-join-wrong-concrete-type.wasm",
4556        );
4557        let module = Module::decode(bytes).unwrap();
4558        let err = module.validate().unwrap_err();
4559        assert_eq!(err.offset, ByteOffset(46));
4560        assert!(matches!(
4561            err.kind,
4562            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
4563                if expected == vec![ValType::Ref(RefType::Typed {
4564                    nullable: true,
4565                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4566                })] && found == vec![ValType::Ref(RefType::Typed {
4567                    nullable: false,
4568                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4569                })]
4570        ));
4571    }
4572
4573    #[test]
4574    fn reject_typed_ref_as_non_null_function_result_wrong_concrete_type() {
4575        let bytes = include_bytes!(
4576            "../../../baedeker-testdata/spec/invalid-validate/typed-ref-as-non-null-function-result-wrong-concrete-type.wasm",
4577        );
4578        let module = Module::decode(bytes).unwrap();
4579        let err = module.validate().unwrap_err();
4580        assert_eq!(err.offset, ByteOffset(40));
4581        assert!(matches!(
4582            err.kind,
4583            ValidationErrorKind::FunctionResultTypeMismatch {
4584                expected,
4585                found,
4586                ..
4587            } if expected == vec![ValType::Ref(RefType::Typed {
4588                    nullable: false,
4589                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4590                })] && found == vec![ValType::Ref(RefType::Typed {
4591                    nullable: false,
4592                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4593                })]
4594        ));
4595    }
4596
4597    #[test]
4598    fn validate_typed_br_if_to_loop_param_nullable_official_case() {
4599        let bytes = include_bytes!(
4600            "../../../baedeker-testdata/spec/valid/typed-br-if-to-loop-param-nullable.wasm",
4601        );
4602        let module = Module::decode(bytes).unwrap();
4603        module.validate().unwrap();
4604    }
4605
4606    #[test]
4607    fn reject_typed_br_if_to_loop_param_nullability_mismatch() {
4608        let bytes = include_bytes!(
4609            "../../../baedeker-testdata/spec/invalid-validate/typed-br-if-to-loop-param-nullability-mismatch.wasm",
4610        );
4611        let module = Module::decode(bytes).unwrap();
4612        let err = module.validate().unwrap_err();
4613        assert_eq!(err.offset, ByteOffset(72));
4614        assert!(matches!(
4615            err.kind,
4616            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
4617                if label == crate::types::LabelIdx(0)
4618                    && expected == vec![ValType::Ref(RefType::Typed {
4619                        nullable: false,
4620                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4621                    })]
4622                    && found == vec![ValType::Ref(RefType::Typed {
4623                        nullable: true,
4624                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4625                    })]
4626        ));
4627    }
4628
4629    #[test]
4630    fn validate_br_on_null() {
4631        let bytes = [
4632            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x6F,
4633            0x01, 0x6F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0E, 0x01, 0x0C, 0x00, 0x02, 0x40, 0x20,
4634            0x00, 0xD5, 0x00, 0x0F, 0x0B, 0xD0, 0x6F, 0x0B,
4635        ];
4636        let module = Module::decode(&bytes).unwrap();
4637        module.validate().unwrap();
4638    }
4639
4640    #[test]
4641    fn reject_br_on_null_with_non_ref_input() {
4642        let bytes = [
4643            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x01, 0x7F,
4644            0x00, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0xD5, 0x00,
4645            0x1A, 0x0B,
4646        ];
4647        let module = Module::decode(&bytes).unwrap();
4648        let err = module.validate().unwrap_err();
4649        assert_eq!(err.offset, ByteOffset(26));
4650        assert!(matches!(
4651            err.kind,
4652            ValidationErrorKind::TypeMismatch {
4653                op: "br_on_null",
4654                expected: ValType::Ref(RefType::ExternRef),
4655                found: ValType::Num(crate::types::NumType::I32),
4656            }
4657        ));
4658    }
4659
4660    #[test]
4661    fn validate_typed_br_on_null_fallthrough_to_call_ref_with_equivalent_signature() {
4662        let bytes = include_bytes!(
4663            "../../../baedeker-testdata/spec/valid/typed-br-on-null-call-ref-equivalent-signature.wasm",
4664        );
4665        let module = Module::decode(bytes).unwrap();
4666        module.validate().unwrap();
4667    }
4668
4669    #[test]
4670    fn validate_br_on_null_unreachable_official_case() {
4671        let bytes =
4672            include_bytes!("../../../baedeker-testdata/spec/valid/br-on-null-unreachable.wasm",);
4673        let module = Module::decode(bytes).unwrap();
4674        module.validate().unwrap();
4675    }
4676
4677    #[test]
4678    fn reject_typed_br_on_null_fallthrough_to_call_ref_with_wrong_concrete_type() {
4679        let bytes = include_bytes!(
4680            "../../../baedeker-testdata/spec/invalid-validate/typed-br-on-null-call-ref-wrong-concrete-type.wasm",
4681        );
4682        let module = Module::decode(bytes).unwrap();
4683        let err = module.validate().unwrap_err();
4684        assert_eq!(err.offset, ByteOffset(60));
4685        assert!(matches!(
4686            err.kind,
4687            ValidationErrorKind::TypeMismatch { op, expected, found }
4688                if op == "call_ref"
4689                    && expected == ValType::Ref(RefType::Typed {
4690                        nullable: true,
4691                        heap: crate::types::HeapType::Type(TypeIdx(1)),
4692                    })
4693                    && found == ValType::Ref(RefType::Typed {
4694                        nullable: false,
4695                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4696                    })
4697        ));
4698    }
4699
4700    #[test]
4701    fn reject_br_on_null_stack_mismatch_official_case() {
4702        let bytes = include_bytes!(
4703            "../../../baedeker-testdata/spec/invalid-validate/br-on-null-stack-mismatch.wasm",
4704        );
4705        let module = Module::decode(bytes).unwrap();
4706        let err = module.validate().unwrap_err();
4707        assert_eq!(err.offset, ByteOffset(47));
4708        assert!(matches!(
4709            err.kind,
4710            ValidationErrorKind::TypeMismatch { op, expected, found }
4711                if op == "stack"
4712                    && expected == ValType::Ref(RefType::Typed {
4713                        nullable: true,
4714                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4715                    })
4716                    && found == ValType::Ref(RefType::FuncRef)
4717        ));
4718    }
4719
4720    #[test]
4721    fn reject_typed_br_on_null_block_result_wrong_concrete_type() {
4722        let bytes = include_bytes!(
4723            "../../../baedeker-testdata/spec/invalid-validate/typed-br-on-null-block-result-wrong-concrete-type.wasm",
4724        );
4725        let module = Module::decode(bytes).unwrap();
4726        let err = module.validate().unwrap_err();
4727        assert_eq!(err.offset, ByteOffset(57));
4728        assert!(matches!(
4729            err.kind,
4730            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
4731                if expected == vec![ValType::Ref(RefType::Typed {
4732                    nullable: true,
4733                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4734                })] && found == vec![ValType::Ref(RefType::Typed {
4735                    nullable: true,
4736                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4737                })]
4738        ));
4739    }
4740
4741    #[test]
4742    fn validate_br_on_non_null() {
4743        let bytes = [
4744            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x6F,
4745            0x01, 0x6F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0F, 0x01, 0x0D, 0x00, 0x02, 0x64, 0x6F,
4746            0x20, 0x00, 0xD6, 0x00, 0xD0, 0x6F, 0x0F, 0x0B, 0x0B,
4747        ];
4748        let module = Module::decode(&bytes).unwrap();
4749        module.validate().unwrap();
4750    }
4751
4752    #[test]
4753    fn reject_br_on_non_null_with_non_ref_target() {
4754        let bytes = [
4755            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x01, 0x6F,
4756            0x00, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0D, 0x01, 0x0B, 0x00, 0x02, 0x7F, 0x20, 0x00,
4757            0xD6, 0x00, 0x41, 0x00, 0x0B, 0x0B,
4758        ];
4759        let module = Module::decode(&bytes).unwrap();
4760        let err = module.validate().unwrap_err();
4761        assert_eq!(err.offset, ByteOffset(28));
4762        assert!(matches!(
4763            err.kind,
4764            ValidationErrorKind::InvalidBrOnNonNullTarget {
4765                label: crate::types::LabelIdx(0),
4766                found,
4767            } if found == vec![ValType::Num(crate::types::NumType::I32)]
4768        ));
4769    }
4770
4771    #[test]
4772    fn validate_typed_br_on_non_null_branch_to_call_ref_with_equivalent_signature() {
4773        let bytes = include_bytes!(
4774            "../../../baedeker-testdata/spec/valid/typed-br-on-non-null-call-ref-equivalent-signature.wasm",
4775        );
4776        let module = Module::decode(bytes).unwrap();
4777        module.validate().unwrap();
4778    }
4779
4780    #[test]
4781    fn validate_br_on_non_null_ref_as_non_null_official_case() {
4782        let bytes = include_bytes!(
4783            "../../../baedeker-testdata/spec/valid/br-on-non-null-ref-as-non-null.wasm",
4784        );
4785        let module = Module::decode(bytes).unwrap();
4786        module.validate().unwrap();
4787    }
4788
4789    #[test]
4790    fn validate_br_on_non_null_unreachable_official_case() {
4791        let bytes = include_bytes!(
4792            "../../../baedeker-testdata/spec/valid/br-on-non-null-unreachable.wasm",
4793        );
4794        let module = Module::decode(bytes).unwrap();
4795        module.validate().unwrap();
4796    }
4797
4798    #[test]
4799    fn reject_typed_br_on_non_null_branch_to_call_ref_with_wrong_concrete_type() {
4800        let bytes = include_bytes!(
4801            "../../../baedeker-testdata/spec/invalid-validate/typed-br-on-non-null-call-ref-wrong-concrete-type.wasm",
4802        );
4803        let module = Module::decode(bytes).unwrap();
4804        let err = module.validate().unwrap_err();
4805        assert_eq!(err.offset, ByteOffset(53));
4806        assert!(matches!(
4807            err.kind,
4808            ValidationErrorKind::TypeMismatch { op, expected, found }
4809                if op == "br_on_non_null"
4810                    && expected == ValType::Ref(RefType::Typed {
4811                        nullable: true,
4812                        heap: crate::types::HeapType::Type(TypeIdx(1)),
4813                    })
4814                    && found == ValType::Ref(RefType::Typed {
4815                        nullable: true,
4816                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4817                    })
4818        ));
4819    }
4820
4821    #[test]
4822    fn reject_br_on_non_null_stack_mismatch_official_case() {
4823        let bytes = include_bytes!(
4824            "../../../baedeker-testdata/spec/invalid-validate/br-on-non-null-stack-mismatch.wasm",
4825        );
4826        let module = Module::decode(bytes).unwrap();
4827        let err = module.validate().unwrap_err();
4828        assert_eq!(err.offset, ByteOffset(47));
4829        assert!(matches!(
4830            err.kind,
4831            ValidationErrorKind::TypeMismatch { op, expected, found }
4832                if op == "stack"
4833                    && expected == ValType::Ref(RefType::Typed {
4834                        nullable: true,
4835                        heap: crate::types::HeapType::Type(TypeIdx(0)),
4836                    })
4837                    && found == ValType::Ref(RefType::FuncRef)
4838        ));
4839    }
4840
4841    #[test]
4842    fn reject_typed_br_on_non_null_block_result_wrong_concrete_type() {
4843        let bytes = include_bytes!(
4844            "../../../baedeker-testdata/spec/invalid-validate/typed-br-on-non-null-block-result-wrong-concrete-type.wasm",
4845        );
4846        let module = Module::decode(bytes).unwrap();
4847        let err = module.validate().unwrap_err();
4848        assert_eq!(err.offset, ByteOffset(63));
4849        assert!(matches!(
4850            err.kind,
4851            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
4852                if expected == vec![ValType::Ref(RefType::Typed {
4853                    nullable: false,
4854                    heap: crate::types::HeapType::Type(TypeIdx(1)),
4855                })] && found == vec![ValType::Ref(RefType::Typed {
4856                    nullable: false,
4857                    heap: crate::types::HeapType::Type(TypeIdx(0)),
4858                })]
4859        ));
4860    }
4861
4862    #[test]
4863    fn validate_global_init_expr_from_imported_const_global() {
4864        let bytes = [
4865            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, b'e', b'n',
4866            b'v', 0x01, b'g', 0x03, 0x7F, 0x00, 0x06, 0x06, 0x01, 0x7F, 0x00, 0x23, 0x00, 0x0B,
4867        ];
4868        let module = Module::decode(&bytes).unwrap();
4869        module.validate().unwrap();
4870    }
4871
4872    #[test]
4873    fn validate_global_init_expr_from_defined_const_global() {
4874        let bytes = [
4875            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x06, 0x0B, 0x02, 0x7F, 0x00, 0x41,
4876            0x00, 0x0B, 0x7F, 0x00, 0x23, 0x00, 0x0B,
4877        ];
4878        let module = Module::decode(&bytes).unwrap();
4879        module.validate().unwrap();
4880    }
4881
4882    #[test]
4883    fn validate_global_init_expr_with_extended_const_arithmetic() {
4884        let bytes = [
4885            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, 0x65, 0x6E,
4886            0x76, 0x01, 0x67, 0x03, 0x7F, 0x00, 0x06, 0x09, 0x01, 0x7F, 0x00, 0x23, 0x00, 0x41,
4887            0x2A, 0x6A, 0x0B,
4888        ];
4889        let module = Module::decode(&bytes).unwrap();
4890        module.validate().unwrap();
4891    }
4892
4893    #[test]
4894    fn validate_reference_global_init_exprs() {
4895        let bytes = [
4896            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4897            0x03, 0x02, 0x01, 0x00, 0x06, 0x0B, 0x02, 0x6F, 0x00, 0xD0, 0x6F, 0x0B, 0x70, 0x00,
4898            0xD2, 0x00, 0x0B, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
4899        ];
4900        let module = Module::decode(&bytes).unwrap();
4901        module.validate().unwrap();
4902    }
4903
4904    #[test]
4905    fn validate_ref_func_declared_by_exported_import() {
4906        let bytes = [
4907            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4908            0x02, 0x09, 0x01, 0x03, b'e', b'n', b'v', 0x01, b'f', 0x00, 0x00, 0x03, 0x02, 0x01,
4909            0x00, 0x07, 0x05, 0x01, 0x01, b'f', 0x00, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xD2,
4910            0x00, 0x1A, 0x0B,
4911        ];
4912        let module = Module::decode(&bytes).unwrap();
4913        module.validate().unwrap();
4914    }
4915
4916    #[test]
4917    fn validate_ref_func_declared_by_declarative_element() {
4918        let bytes = [
4919            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4920            0x03, 0x03, 0x02, 0x00, 0x00, 0x09, 0x05, 0x01, 0x03, 0x00, 0x01, 0x00, 0x0A, 0x0A,
4921            0x02, 0x02, 0x00, 0x0B, 0x05, 0x00, 0xD2, 0x00, 0x1A, 0x0B,
4922        ];
4923        let module = Module::decode(&bytes).unwrap();
4924        module.validate().unwrap();
4925    }
4926
4927    #[test]
4928    fn reject_undeclared_ref_func_self_reference() {
4929        let bytes = [
4930            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4931            0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xD2, 0x00, 0x1A, 0x0B,
4932        ];
4933        let module = Module::decode(&bytes).unwrap();
4934        let err = module.validate().unwrap_err();
4935        assert!(matches!(
4936            err.kind,
4937            ValidationErrorKind::UndeclaredFuncRef {
4938                idx: crate::types::FuncIdx(0)
4939            }
4940        ));
4941    }
4942
4943    #[test]
4944    fn reject_ref_func_when_start_is_only_declaration_source() {
4945        let bytes = [
4946            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
4947            0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xD2, 0x00,
4948            0x1A, 0x0B,
4949        ];
4950        let module = Module::decode(&bytes).unwrap();
4951        let err = module.validate().unwrap_err();
4952        assert!(matches!(
4953            err.kind,
4954            ValidationErrorKind::UndeclaredFuncRef {
4955                idx: crate::types::FuncIdx(0)
4956            }
4957        ));
4958    }
4959
4960    #[test]
4961    fn reject_global_init_expr_from_mutable_imported_global() {
4962        let bytes = [
4963            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, b'e', b'n',
4964            b'v', 0x01, b'g', 0x03, 0x7F, 0x01, 0x06, 0x06, 0x01, 0x7F, 0x00, 0x23, 0x00, 0x0B,
4965        ];
4966        let module = Module::decode(&bytes).unwrap();
4967        let err = module.validate().unwrap_err();
4968        assert_eq!(err.offset, ByteOffset(25));
4969        assert!(matches!(
4970            err.kind,
4971            ValidationErrorKind::MutableGlobalInInitExpr {
4972                idx: crate::types::GlobalIdx(0)
4973            }
4974        ));
4975    }
4976
4977    #[test]
4978    fn reject_global_init_expr_type_mismatch() {
4979        let bytes = [
4980            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x06, 0x06, 0x01, 0x7E, 0x00, 0x41,
4981            0x2A, 0x0B,
4982        ];
4983        let module = Module::decode(&bytes).unwrap();
4984        let err = module.validate().unwrap_err();
4985        assert_eq!(err.offset, ByteOffset(13));
4986        assert!(matches!(
4987            err.kind,
4988            ValidationErrorKind::GlobalInitTypeMismatch {
4989                expected: ValType::Num(crate::types::NumType::I64),
4990                found: ValType::Num(crate::types::NumType::I32),
4991            }
4992        ));
4993    }
4994
4995    #[test]
4996    fn reject_non_constant_global_init_expr() {
4997        let bytes = [
4998            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x06, 0x08, 0x01, 0x7F, 0x00, 0x41,
4999            0x01, 0x41, 0x02, 0x0B,
5000        ];
5001        let module = Module::decode(&bytes).unwrap();
5002        let err = module.validate().unwrap_err();
5003        assert_eq!(err.offset, ByteOffset(13));
5004        assert!(matches!(
5005            err.kind,
5006            ValidationErrorKind::InvalidGlobalInitExpr
5007        ));
5008    }
5009
5010    #[test]
5011    fn validate_active_data_offset_from_imported_const_global() {
5012        let bytes = [
5013            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, b'e', b'n',
5014            b'v', 0x01, b'g', 0x03, 0x7F, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x07, 0x01,
5015            0x00, 0x23, 0x00, 0x0B, 0x01, 0xAA,
5016        ];
5017        let module = Module::decode(&bytes).unwrap();
5018        module.validate().unwrap();
5019    }
5020
5021    #[test]
5022    fn validate_active_data_offset_from_defined_const_global() {
5023        let bytes = [
5024            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06,
5025            0x06, 0x01, 0x7F, 0x00, 0x41, 0x00, 0x0B, 0x0B, 0x07, 0x01, 0x00, 0x23, 0x00, 0x0B,
5026            0x01, 0x61,
5027        ];
5028        let module = Module::decode(&bytes).unwrap();
5029        module.validate().unwrap();
5030    }
5031
5032    #[test]
5033    fn validate_active_data_offset_with_extended_const_arithmetic() {
5034        let bytes = [
5035            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, 0x65, 0x6E,
5036            0x76, 0x01, 0x67, 0x03, 0x7F, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0B, 0x10, 0x01,
5037            0x00, 0x41, 0x02, 0x23, 0x00, 0x41, 0x01, 0x6B, 0x41, 0x02, 0x6A, 0x6C, 0x0B, 0x01,
5038            0x61,
5039        ];
5040        let module = Module::decode(&bytes).unwrap();
5041        module.validate().unwrap();
5042    }
5043
5044    #[test]
5045    fn validate_element_expr_from_imported_const_ref_global() {
5046        let bytes = [
5047            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x01, 0x03, b'e', b'n',
5048            b'v', 0x01, b'g', 0x03, 0x6F, 0x00, 0x04, 0x04, 0x01, 0x6F, 0x00, 0x01, 0x09, 0x0B,
5049            0x01, 0x06, 0x00, 0x41, 0x00, 0x0B, 0x6F, 0x01, 0x23, 0x00, 0x0B,
5050        ];
5051        let module = Module::decode(&bytes).unwrap();
5052        module.validate().unwrap();
5053    }
5054
5055    #[test]
5056    fn validate_active_element_offset_from_defined_const_global() {
5057        let bytes = [
5058            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5059            0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01, 0x06, 0x06, 0x01, 0x7F,
5060            0x00, 0x41, 0x00, 0x0B, 0x09, 0x07, 0x01, 0x00, 0x23, 0x00, 0x0B, 0x01, 0x00, 0x0A,
5061            0x04, 0x01, 0x02, 0x00, 0x0B,
5062        ];
5063        let module = Module::decode(&bytes).unwrap();
5064        module.validate().unwrap();
5065    }
5066
5067    #[test]
5068    fn validate_active_element_offset_with_extended_const_arithmetic() {
5069        let bytes = [
5070            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5071            0x02, 0x0A, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x7F, 0x00, 0x03, 0x02,
5072            0x01, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x08, 0x09, 0x14, 0x01, 0x06, 0x00, 0x41,
5073            0x02, 0x23, 0x00, 0x41, 0x01, 0x6B, 0x41, 0x02, 0x6A, 0x6C, 0x0B, 0x70, 0x01, 0xD2,
5074            0x00, 0x0B, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
5075        ];
5076        let module = Module::decode(&bytes).unwrap();
5077        module.validate().unwrap();
5078    }
5079
5080    #[test]
5081    fn validate_memory_size_and_grow_for_imported_memory() {
5082        let bytes = [
5083            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5084            0x7F, 0x02, 0x0C, 0x01, 0x03, b'e', b'n', b'v', 0x03, b'm', b'e', b'm', 0x02, 0x00,
5085            0x01, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0B, 0x01, 0x09, 0x00, 0x41, 0x01, 0x40, 0x00,
5086            0x1A, 0x3F, 0x00, 0x0B,
5087        ];
5088        let module = Module::decode(&bytes).unwrap();
5089        module.validate().unwrap();
5090    }
5091
5092    #[test]
5093    fn validate_memory_size_and_grow_for_defined_memory() {
5094        let bytes = [
5095            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5096            0x7F, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0B, 0x01, 0x09,
5097            0x00, 0x41, 0x01, 0x40, 0x00, 0x1A, 0x3F, 0x00, 0x0B,
5098        ];
5099        let module = Module::decode(&bytes).unwrap();
5100        module.validate().unwrap();
5101    }
5102
5103    #[test]
5104    fn validate_memory_size_and_grow_for_nonzero_memory_index() {
5105        let bytes = [
5106            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5107            0x7F, 0x02, 0x0C, 0x01, 0x03, b'e', b'n', b'v', 0x03, b'm', b'e', b'm', 0x02, 0x00,
5108            0x01, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0B, 0x01, 0x09,
5109            0x00, 0x41, 0x01, 0x40, 0x01, 0x1A, 0x3F, 0x01, 0x0B,
5110        ];
5111        let module = Module::decode(&bytes).unwrap();
5112        module.validate().unwrap();
5113    }
5114
5115    #[test]
5116    fn validate_i32_load_and_store_for_defined_memory() {
5117        let bytes = [
5118            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5119            0x7F, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x10, 0x01, 0x0E,
5120            0x00, 0x41, 0x00, 0x41, 0x2A, 0x36, 0x02, 0x00, 0x41, 0x00, 0x28, 0x02, 0x00, 0x0B,
5121        ];
5122        let module = Module::decode(&bytes).unwrap();
5123        module.validate().unwrap();
5124    }
5125
5126    #[test]
5127    fn validate_i32_load_and_store_for_nonzero_memory_index() {
5128        let bytes = [
5129            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
5130            0x7F, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x05, 0x05, 0x02, 0x00, 0x01,
5131            0x00, 0x01, 0x0A, 0x15, 0x02, 0x08, 0x00, 0x41, 0x00, 0x28, 0x42, 0x01, 0x00, 0x0B,
5132            0x0A, 0x00, 0x41, 0x00, 0x41, 0x01, 0x36, 0x42, 0x01, 0x00, 0x0B,
5133        ];
5134        let module = Module::decode(&bytes).unwrap();
5135        module.validate().unwrap();
5136    }
5137
5138    #[test]
5139    fn validate_narrow_memory_ops_for_defined_memory() {
5140        let bytes = [
5141            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60, 0x00, 0x01,
5142            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x03, 0x03, 0x02, 0x00, 0x01, 0x05, 0x03, 0x01, 0x00,
5143            0x01, 0x0A, 0x1D, 0x02, 0x0D, 0x00, 0x41, 0x00, 0x2C, 0x00, 0x00, 0x1A, 0x41, 0x00,
5144            0x2F, 0x01, 0x00, 0x0B, 0x0D, 0x00, 0x41, 0x00, 0x30, 0x00, 0x00, 0x1A, 0x41, 0x00,
5145            0x35, 0x02, 0x00, 0x0B,
5146        ];
5147        let module = Module::decode(&bytes).unwrap();
5148        module.validate().unwrap();
5149    }
5150
5151    #[test]
5152    fn validate_narrow_memory_stores_for_defined_memory() {
5153        let bytes = [
5154            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5155            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x27, 0x01, 0x25, 0x00,
5156            0x41, 0x00, 0x41, 0x7F, 0x3A, 0x00, 0x00, 0x41, 0x00, 0x41, 0x7F, 0x3B, 0x01, 0x00,
5157            0x41, 0x00, 0x42, 0x01, 0x3C, 0x00, 0x00, 0x41, 0x00, 0x42, 0x01, 0x3D, 0x01, 0x00,
5158            0x41, 0x00, 0x42, 0x01, 0x3E, 0x02, 0x00, 0x0B,
5159        ];
5160        let module = Module::decode(&bytes).unwrap();
5161        module.validate().unwrap();
5162    }
5163
5164    #[test]
5165    fn validate_v128_load_and_store_for_defined_memory() {
5166        let bytes = [
5167            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
5168            0x7B, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01,
5169            0x0A, 0x25, 0x02, 0x08, 0x00, 0x41, 0x00, 0xFD, 0x00, 0x04, 0x00, 0x0B, 0x1A, 0x00,
5170            0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5171            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0B, 0x04, 0x00, 0x0B,
5172        ];
5173        let module = Module::decode(&bytes).unwrap();
5174        module.validate().unwrap();
5175    }
5176
5177    #[test]
5178    fn validate_v128_load_and_store_for_nonzero_memory_index() {
5179        let bytes = [
5180            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
5181            0x7B, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x05, 0x05, 0x02, 0x00, 0x01,
5182            0x00, 0x01, 0x0A, 0x27, 0x02, 0x09, 0x00, 0x41, 0x00, 0xFD, 0x00, 0x44, 0x01, 0x00,
5183            0x0B, 0x1B, 0x00, 0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5184            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x0B, 0x44, 0x01, 0x00,
5185            0x0B,
5186        ];
5187        let module = Module::decode(&bytes).unwrap();
5188        module.validate().unwrap();
5189    }
5190
5191    #[test]
5192    fn validate_data_segments_and_bulk_memory_ops() {
5193        let bytes = [
5194            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5195            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x24, 0x01, 0x22, 0x00,
5196            0x41, 0x00, 0x41, 0x00, 0x41, 0x02, 0xFC, 0x08, 0x00, 0x00, 0xFC, 0x09, 0x00, 0x41,
5197            0x00, 0x41, 0x00, 0x41, 0x02, 0xFC, 0x0A, 0x00, 0x00, 0x41, 0x00, 0x41, 0x7F, 0x41,
5198            0x02, 0xFC, 0x0B, 0x00, 0x0B, 0x0B, 0x08, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x02, 0xAA,
5199            0xBB, 0x0C, 0x01, 0x01,
5200        ];
5201        let module = Module::decode(&bytes).unwrap();
5202        module.validate().unwrap();
5203    }
5204
5205    #[test]
5206    fn reject_unknown_data_index_in_memory_init() {
5207        let bytes = [
5208            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5209            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0E, 0x01, 0x0C, 0x00,
5210            0x41, 0x00, 0x41, 0x00, 0x41, 0x01, 0xFC, 0x08, 0x00, 0x00, 0x0B, 0x0C, 0x01, 0x00,
5211        ];
5212        let module = Module::decode(&bytes).unwrap();
5213        let err = module.validate().unwrap_err();
5214        assert!(matches!(
5215            err.kind,
5216            ValidationErrorKind::UnknownDataIdx {
5217                idx: crate::types::DataIdx(0),
5218                available: 0,
5219            }
5220        ));
5221    }
5222
5223    #[test]
5224    fn validate_v128_lane_memory_ops() {
5225        let bytes = [
5226            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5227            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x37, 0x01, 0x35, 0x00,
5228            0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5229            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x54, 0x00, 0x00, 0x0F, 0x1A, 0x41, 0x00,
5230            0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5231            0x00, 0x00, 0x00, 0x00, 0xFD, 0x58, 0x00, 0x00, 0x0F, 0x0B,
5232        ];
5233        let module = Module::decode(&bytes).unwrap();
5234        module.validate().unwrap();
5235    }
5236
5237    #[test]
5238    fn reject_v128_load16_lane_with_invalid_lane_index() {
5239        let bytes = [
5240            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5241            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x1E, 0x01, 0x1C, 0x00,
5242            0x41, 0x00, 0xFD, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5243            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x55, 0x01, 0x00, 0x08, 0x1A, 0x0B,
5244        ];
5245        let module = Module::decode(&bytes).unwrap();
5246        let err = module.validate().unwrap_err();
5247        assert!(matches!(
5248            err.kind,
5249            ValidationErrorKind::InvalidSimdLaneIdx {
5250                op: "v128.load16_lane",
5251                max: 7,
5252                found: 8,
5253            }
5254        ));
5255    }
5256
5257    #[test]
5258    fn reject_i64_load32_with_invalid_memarg_align() {
5259        let bytes = [
5260            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5261            0x7E, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0A, 0x01, 0x08,
5262            0x00, 0x41, 0x00, 0x35, 0x03, 0x00, 0x1A, 0x0B,
5263        ];
5264        let module = Module::decode(&bytes).unwrap();
5265        let err = module.validate().unwrap_err();
5266        assert!(matches!(
5267            err.kind,
5268            ValidationErrorKind::InvalidMemArgAlign {
5269                op: "i64.load32",
5270                max: 2,
5271                found: 3,
5272            }
5273        ));
5274    }
5275
5276    #[test]
5277    fn reject_i64_store32_with_wrong_value_type() {
5278        let bytes = [
5279            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5280            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0B, 0x01, 0x09, 0x00,
5281            0x41, 0x00, 0x41, 0x01, 0x3E, 0x02, 0x00, 0x0B,
5282        ];
5283        let module = Module::decode(&bytes).unwrap();
5284        let err = module.validate().unwrap_err();
5285        assert!(matches!(
5286            err.kind,
5287            ValidationErrorKind::TypeMismatch {
5288                op: "i64.store32",
5289                expected: ValType::Num(crate::types::NumType::I64),
5290                found: ValType::Num(crate::types::NumType::I32),
5291            }
5292        ));
5293    }
5294
5295    #[test]
5296    fn reject_i32_load_with_invalid_memarg_align() {
5297        let bytes = [
5298            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5299            0x7F, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0C, 0x01, 0x0A,
5300            0x00, 0x41, 0x00, 0x28, 0x03, 0x00, 0x1A, 0x41, 0x00, 0x0B,
5301        ];
5302        let module = Module::decode(&bytes).unwrap();
5303        let err = module.validate().unwrap_err();
5304        assert!(matches!(
5305            err.kind,
5306            ValidationErrorKind::InvalidMemArgAlign {
5307                op: "i32.load",
5308                max: 2,
5309                found: 3,
5310            }
5311        ));
5312    }
5313
5314    #[test]
5315    fn reject_i32_store_with_wrong_value_type() {
5316        let bytes = [
5317            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5318            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0B, 0x01, 0x09, 0x00,
5319            0x41, 0x00, 0x42, 0x01, 0x36, 0x02, 0x00, 0x0B,
5320        ];
5321        let module = Module::decode(&bytes).unwrap();
5322        let err = module.validate().unwrap_err();
5323        assert!(matches!(
5324            err.kind,
5325            ValidationErrorKind::TypeMismatch {
5326                op: "i32.store",
5327                expected: ValType::Num(crate::types::NumType::I32),
5328                found: ValType::Num(crate::types::NumType::I64),
5329            }
5330        ));
5331    }
5332
5333    #[test]
5334    fn reject_unknown_imported_global_index() {
5335        let bytes = [
5336            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5337            0x03, 0x02, 0x01, 0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x23, 0x00, 0x0B,
5338        ];
5339        let module = Module::decode(&bytes).unwrap();
5340        let err = module.validate().unwrap_err();
5341        assert!(matches!(
5342            err.kind,
5343            ValidationErrorKind::UnknownGlobalIdx {
5344                idx: crate::types::GlobalIdx(0),
5345                available: 0,
5346            }
5347        ));
5348    }
5349
5350    #[test]
5351    fn reject_unknown_imported_memory_index() {
5352        let bytes = [
5353            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5354            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x3F, 0x00, 0x0B,
5355        ];
5356        let module = Module::decode(&bytes).unwrap();
5357        let err = module.validate().unwrap_err();
5358        assert!(matches!(
5359            err.kind,
5360            ValidationErrorKind::UnknownMemIdx {
5361                idx: crate::types::MemIdx(0),
5362                available: 0,
5363            }
5364        ));
5365    }
5366
5367    #[test]
5368    fn validate_i64_add() {
5369        let bytes = [
5370            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
5371            0x7E, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x42, 0x01, 0x42, 0x02,
5372            0x7C, 0x0B,
5373        ];
5374        let module = Module::decode(&bytes).unwrap();
5375        module.validate().unwrap();
5376    }
5377
5378    #[test]
5379    fn reject_if_result_without_else() {
5380        let bytes = [
5381            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5382            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0C, 0x01, 0x0A, 0x00, 0x41, 0x01, 0x04, 0x7F, 0x41,
5383            0x02, 0x0B, 0x1A, 0x0B,
5384        ];
5385        let module = Module::decode(&bytes).unwrap();
5386        let err = module.validate().unwrap_err();
5387        assert!(matches!(
5388            err.kind,
5389            ValidationErrorKind::MissingElseForResult
5390        ));
5391    }
5392
5393    #[test]
5394    fn map_unknown_opcode_into_validation_error() {
5395        let bytes = [
5396            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5397            0x03, 0x02, 0x01, 0x00, 0x0A, 0x05, 0x01, 0x03, 0x00, 0xFF, 0x0B,
5398        ];
5399        let module = Module::decode(&bytes).unwrap();
5400        let err = module.validate().unwrap_err();
5401        assert_eq!(err.offset, ByteOffset(23));
5402        assert!(matches!(
5403            err.kind,
5404            ValidationErrorKind::Decode {
5405                context: crate::error::DecodeContext::CodeSection,
5406                kind: crate::error::DecodeErrorKind::UnknownOpcode { byte: 0xFF },
5407            }
5408        ));
5409    }
5410
5411    #[test]
5412    fn map_unterminated_body_into_validation_error() {
5413        let bytes = [
5414            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5415            0x03, 0x02, 0x01, 0x00, 0x0A, 0x05, 0x01, 0x03, 0x00, 0x20, 0x00,
5416        ];
5417        let module = Module::decode(&bytes).unwrap();
5418        let err = module.validate().unwrap_err();
5419        assert_eq!(err.offset, ByteOffset(25));
5420        assert!(matches!(
5421            err.kind,
5422            ValidationErrorKind::Decode {
5423                context: crate::error::DecodeContext::CodeSection,
5424                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5425            }
5426        ));
5427    }
5428
5429    #[test]
5430    fn map_truncated_call_ref_immediate_into_validation_error() {
5431        let bytes = include_bytes!(
5432            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-call-ref-typeidx.wasm",
5433        );
5434        let module = Module::decode(bytes).unwrap();
5435        let err = module.validate().unwrap_err();
5436        assert_eq!(err.offset, ByteOffset(24));
5437        assert!(matches!(
5438            err.kind,
5439            ValidationErrorKind::Decode {
5440                context: crate::error::DecodeContext::CodeSection,
5441                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5442            }
5443        ));
5444    }
5445
5446    #[test]
5447    fn map_truncated_return_call_ref_immediate_into_validation_error() {
5448        let bytes = include_bytes!(
5449            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-return-call-ref-typeidx.wasm",
5450        );
5451        let module = Module::decode(bytes).unwrap();
5452        let err = module.validate().unwrap_err();
5453        assert_eq!(err.offset, ByteOffset(24));
5454        assert!(matches!(
5455            err.kind,
5456            ValidationErrorKind::Decode {
5457                context: crate::error::DecodeContext::CodeSection,
5458                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5459            }
5460        ));
5461    }
5462
5463    #[test]
5464    fn map_truncated_br_on_null_immediate_into_validation_error() {
5465        let bytes = include_bytes!(
5466            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-br-on-null-labelidx.wasm",
5467        );
5468        let module = Module::decode(bytes).unwrap();
5469        let err = module.validate().unwrap_err();
5470        assert_eq!(err.offset, ByteOffset(24));
5471        assert!(matches!(
5472            err.kind,
5473            ValidationErrorKind::Decode {
5474                context: crate::error::DecodeContext::CodeSection,
5475                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5476            }
5477        ));
5478    }
5479
5480    #[test]
5481    fn map_truncated_br_on_non_null_immediate_into_validation_error() {
5482        let bytes = include_bytes!(
5483            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-br-on-non-null-labelidx.wasm",
5484        );
5485        let module = Module::decode(bytes).unwrap();
5486        let err = module.validate().unwrap_err();
5487        assert_eq!(err.offset, ByteOffset(24));
5488        assert!(matches!(
5489            err.kind,
5490            ValidationErrorKind::Decode {
5491                context: crate::error::DecodeContext::CodeSection,
5492                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5493            }
5494        ));
5495    }
5496
5497    #[test]
5498    fn map_truncated_ref_null_heaptype_into_validation_error() {
5499        let bytes = include_bytes!(
5500            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-ref-null-heaptype.wasm",
5501        );
5502        let module = Module::decode(bytes).unwrap();
5503        let err = module.validate().unwrap_err();
5504        assert_eq!(err.offset, ByteOffset(24));
5505        assert!(matches!(
5506            err.kind,
5507            ValidationErrorKind::Decode {
5508                context: crate::error::DecodeContext::CodeSection,
5509                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5510            }
5511        ));
5512    }
5513
5514    #[test]
5515    fn map_truncated_typed_block_result_heaptype_into_validation_error() {
5516        let bytes = include_bytes!(
5517            "../../../baedeker-testdata/spec/invalid-validate/body-decode-truncated-block-result-heaptype.wasm",
5518        );
5519        let module = Module::decode(bytes).unwrap();
5520        let err = module.validate().unwrap_err();
5521        assert_eq!(err.offset, ByteOffset(25));
5522        assert!(matches!(
5523            err.kind,
5524            ValidationErrorKind::Decode {
5525                context: crate::error::DecodeContext::CodeSection,
5526                kind: crate::error::DecodeErrorKind::UnexpectedEof,
5527            }
5528        ));
5529    }
5530
5531    #[test]
5532    fn report_branch_type_mismatch_with_label_types() {
5533        let bytes = [
5534            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5535            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0C, 0x01, 0x0A, 0x00, 0x02, 0x7F, 0x42, 0x00, 0x0C,
5536            0x00, 0x0B, 0x1A, 0x0B,
5537        ];
5538        let module = Module::decode(&bytes).unwrap();
5539        let err = module.validate().unwrap_err();
5540        assert_eq!(err.offset, ByteOffset(27));
5541        assert!(matches!(
5542            err.kind,
5543            ValidationErrorKind::BranchTypeMismatch {
5544                label: crate::types::LabelIdx(0),
5545                expected,
5546                found,
5547            } if expected == vec![ValType::Num(crate::types::NumType::I32)]
5548                && found == vec![ValType::Num(crate::types::NumType::I64)]
5549        ));
5550    }
5551
5552    #[test]
5553    fn report_control_result_type_mismatch_at_end() {
5554        let bytes = [
5555            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5556            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0A, 0x01, 0x08, 0x00, 0x02, 0x7F, 0x42, 0x00, 0x0B,
5557            0x1A, 0x0B,
5558        ];
5559        let module = Module::decode(&bytes).unwrap();
5560        let err = module.validate().unwrap_err();
5561        assert_eq!(err.offset, ByteOffset(27));
5562        assert!(matches!(
5563            err.kind,
5564            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
5565                if expected == vec![ValType::Num(crate::types::NumType::I32)]
5566                    && found == vec![ValType::Num(crate::types::NumType::I64)]
5567        ));
5568    }
5569
5570    #[test]
5571    fn reject_block_end_with_extra_operand() {
5572        let bytes = [
5573            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5574            0x03, 0x02, 0x01, 0x00, 0x0A, 0x10, 0x01, 0x0E, 0x00, 0x02, 0x40, 0x43, 0x00, 0x00,
5575            0x00, 0x00, 0x41, 0x01, 0x0D, 0x00, 0x0B, 0x0B,
5576        ];
5577        let module = Module::decode(&bytes).unwrap();
5578        let err = module.validate().unwrap_err();
5579        assert_eq!(err.offset, ByteOffset(34));
5580        assert!(matches!(
5581            err.kind,
5582            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
5583                if expected.is_empty()
5584                    && found == vec![ValType::Num(crate::types::NumType::F32)]
5585        ));
5586    }
5587
5588    #[test]
5589    fn reject_block_end_after_consuming_outer_operand() {
5590        let bytes = [
5591            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5592            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x00, 0x0A, 0x0D, 0x01, 0x0B, 0x00,
5593            0x41, 0x00, 0x02, 0x40, 0x28, 0x00, 0x00, 0x1A, 0x0B, 0x0B,
5594        ];
5595        let module = Module::decode(&bytes).unwrap();
5596        let err = module.validate().unwrap_err();
5597        assert_eq!(err.offset, ByteOffset(36));
5598        assert!(matches!(
5599            err.kind,
5600            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
5601                if expected.is_empty() && found.is_empty()
5602        ));
5603    }
5604
5605    #[test]
5606    fn reject_folded_syntax_equivalent_br_if_operand_use() {
5607        let bytes = [
5608            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
5609            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0D, 0x01, 0x0B, 0x00, 0x02, 0x40, 0x41, 0x01, 0x0D,
5610            0x00, 0x8C, 0x01, 0x0B, 0x0B,
5611        ];
5612        let module = Module::decode(&bytes).unwrap();
5613        let err = module.validate().unwrap_err();
5614        assert_eq!(err.offset, ByteOffset(29));
5615        assert!(matches!(
5616            err.kind,
5617            ValidationErrorKind::StackUnderflow { op, expected, .. }
5618                if op == "f32.unary"
5619                    && expected == vec![ValType::Num(crate::types::NumType::F32)]
5620        ));
5621    }
5622
5623    #[test]
5624    fn validate_call_as_call_all_operands_official_case() {
5625        let bytes =
5626            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-call-all-operands.wasm",);
5627        let module = Module::decode(bytes).unwrap();
5628        module.validate().unwrap();
5629    }
5630
5631    #[test]
5632    fn validate_call_as_br_table_last_official_case() {
5633        let bytes =
5634            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-br-table-last.wasm");
5635        let module = Module::decode(bytes).unwrap();
5636        module.validate().unwrap();
5637    }
5638
5639    #[test]
5640    fn validate_call_as_call_indirect_last_official_case() {
5641        let bytes = include_bytes!(
5642            "../../../baedeker-testdata/spec/valid/call-as-call-indirect-last.wasm",
5643        );
5644        let module = Module::decode(bytes).unwrap();
5645        module.validate().unwrap();
5646    }
5647
5648    #[test]
5649    fn validate_call_as_memory_grow_value_official_case() {
5650        let bytes =
5651            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-memory-grow-value.wasm",);
5652        let module = Module::decode(bytes).unwrap();
5653        module.validate().unwrap();
5654    }
5655
5656    #[test]
5657    fn validate_call_as_local_tee_value_official_case() {
5658        let bytes =
5659            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-local-tee-value.wasm",);
5660        let module = Module::decode(bytes).unwrap();
5661        module.validate().unwrap();
5662    }
5663
5664    #[test]
5665    fn validate_call_as_load_operand_official_case() {
5666        let bytes =
5667            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-load-operand.wasm");
5668        let module = Module::decode(bytes).unwrap();
5669        module.validate().unwrap();
5670    }
5671
5672    #[test]
5673    fn validate_call_as_compare_right_official_case() {
5674        let bytes =
5675            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-compare-right.wasm",);
5676        let module = Module::decode(bytes).unwrap();
5677        module.validate().unwrap();
5678    }
5679
5680    #[test]
5681    fn validate_call_as_convert_operand_official_case() {
5682        let bytes =
5683            include_bytes!("../../../baedeker-testdata/spec/valid/call-as-convert-operand.wasm",);
5684        let module = Module::decode(bytes).unwrap();
5685        module.validate().unwrap();
5686    }
5687
5688    #[test]
5689    fn validate_unreachable_as_func_mid_official_case() {
5690        let bytes =
5691            include_bytes!("../../../baedeker-testdata/spec/valid/unreachable-as-func-mid.wasm");
5692        let module = Module::decode(bytes).unwrap();
5693        module.validate().unwrap();
5694    }
5695
5696    #[test]
5697    fn validate_unreachable_as_block_value_official_case() {
5698        let bytes = include_bytes!(
5699            "../../../baedeker-testdata/spec/valid/unreachable-as-block-value.wasm",
5700        );
5701        let module = Module::decode(bytes).unwrap();
5702        module.validate().unwrap();
5703    }
5704
5705    #[test]
5706    fn validate_unreachable_as_br_table_value_index_official_case() {
5707        let bytes = include_bytes!(
5708            "../../../baedeker-testdata/spec/valid/unreachable-as-br-table-value-index.wasm",
5709        );
5710        let module = Module::decode(bytes).unwrap();
5711        module.validate().unwrap();
5712    }
5713
5714    #[test]
5715    fn validate_unreachable_as_if_then_no_else_official_case() {
5716        let bytes = include_bytes!(
5717            "../../../baedeker-testdata/spec/valid/unreachable-as-if-then-no-else.wasm",
5718        );
5719        let module = Module::decode(bytes).unwrap();
5720        module.validate().unwrap();
5721    }
5722
5723    #[test]
5724    fn validate_unreachable_as_call_indirect_first_official_case() {
5725        let bytes = include_bytes!(
5726            "../../../baedeker-testdata/spec/valid/unreachable-as-call-indirect-first.wasm",
5727        );
5728        let module = Module::decode(bytes).unwrap();
5729        module.validate().unwrap();
5730    }
5731
5732    #[test]
5733    fn validate_unreachable_as_local_tee_value_official_case() {
5734        let bytes = include_bytes!(
5735            "../../../baedeker-testdata/spec/valid/unreachable-as-local-tee-value.wasm",
5736        );
5737        let module = Module::decode(bytes).unwrap();
5738        module.validate().unwrap();
5739    }
5740
5741    #[test]
5742    fn validate_unreachable_as_store_n_value_official_case() {
5743        let bytes = include_bytes!(
5744            "../../../baedeker-testdata/spec/valid/unreachable-as-storeN-value.wasm",
5745        );
5746        let module = Module::decode(bytes).unwrap();
5747        module.validate().unwrap();
5748    }
5749
5750    #[test]
5751    fn validate_unreachable_as_convert_operand_official_case() {
5752        let bytes = include_bytes!(
5753            "../../../baedeker-testdata/spec/valid/unreachable-as-convert-operand.wasm",
5754        );
5755        let module = Module::decode(bytes).unwrap();
5756        module.validate().unwrap();
5757    }
5758
5759    #[test]
5760    fn validate_call_indirect_as_select_last_official_case() {
5761        let bytes = include_bytes!(
5762            "../../../baedeker-testdata/spec/valid/call-indirect-as-select-last.wasm",
5763        );
5764        let module = Module::decode(bytes).unwrap();
5765        module.validate().unwrap();
5766    }
5767
5768    #[test]
5769    fn validate_call_indirect_as_br_if_first_official_case() {
5770        let bytes = include_bytes!(
5771            "../../../baedeker-testdata/spec/valid/call-indirect-as-br-if-first.wasm",
5772        );
5773        let module = Module::decode(bytes).unwrap();
5774        module.validate().unwrap();
5775    }
5776
5777    #[test]
5778    fn validate_call_indirect_as_store_last_official_case() {
5779        let bytes = include_bytes!(
5780            "../../../baedeker-testdata/spec/valid/call-indirect-as-store-last.wasm",
5781        );
5782        let module = Module::decode(bytes).unwrap();
5783        module.validate().unwrap();
5784    }
5785
5786    #[test]
5787    fn validate_call_indirect_as_memory_grow_value_official_case() {
5788        let bytes = include_bytes!(
5789            "../../../baedeker-testdata/spec/valid/call-indirect-as-memory-grow-value.wasm",
5790        );
5791        let module = Module::decode(bytes).unwrap();
5792        module.validate().unwrap();
5793    }
5794
5795    #[test]
5796    fn validate_call_indirect_as_local_tee_value_official_case() {
5797        let bytes = include_bytes!(
5798            "../../../baedeker-testdata/spec/valid/call-indirect-as-local-tee-value.wasm",
5799        );
5800        let module = Module::decode(bytes).unwrap();
5801        module.validate().unwrap();
5802    }
5803
5804    #[test]
5805    fn validate_call_indirect_as_load_operand_official_case() {
5806        let bytes = include_bytes!(
5807            "../../../baedeker-testdata/spec/valid/call-indirect-as-load-operand.wasm",
5808        );
5809        let module = Module::decode(bytes).unwrap();
5810        module.validate().unwrap();
5811    }
5812
5813    #[test]
5814    fn validate_call_indirect_as_compare_right_official_case() {
5815        let bytes = include_bytes!(
5816            "../../../baedeker-testdata/spec/valid/call-indirect-as-compare-right.wasm",
5817        );
5818        let module = Module::decode(bytes).unwrap();
5819        module.validate().unwrap();
5820    }
5821
5822    #[test]
5823    fn validate_call_indirect_as_convert_operand_official_case() {
5824        let bytes = include_bytes!(
5825            "../../../baedeker-testdata/spec/valid/call-indirect-as-convert-operand.wasm",
5826        );
5827        let module = Module::decode(bytes).unwrap();
5828        module.validate().unwrap();
5829    }
5830
5831    #[test]
5832    fn validate_block_as_select_cond_official_case() {
5833        let bytes =
5834            include_bytes!("../../../baedeker-testdata/spec/valid/block-as-select-cond.wasm");
5835        let module = Module::decode(bytes).unwrap();
5836        module.validate().unwrap();
5837    }
5838
5839    #[test]
5840    fn validate_block_as_load_address_official_case() {
5841        let bytes =
5842            include_bytes!("../../../baedeker-testdata/spec/valid/block-as-load-address.wasm");
5843        let module = Module::decode(bytes).unwrap();
5844        module.validate().unwrap();
5845    }
5846
5847    #[test]
5848    fn validate_if_as_call_indirect_last_official_case() {
5849        let bytes =
5850            include_bytes!("../../../baedeker-testdata/spec/valid/if-as-call-indirect-last.wasm",);
5851        let module = Module::decode(bytes).unwrap();
5852        module.validate().unwrap();
5853    }
5854
5855    #[test]
5856    fn validate_if_as_memory_grow_size_official_case() {
5857        let bytes =
5858            include_bytes!("../../../baedeker-testdata/spec/valid/if-as-memory-grow-size.wasm");
5859        let module = Module::decode(bytes).unwrap();
5860        module.validate().unwrap();
5861    }
5862
5863    #[test]
5864    fn validate_loop_as_local_tee_value_official_case() {
5865        let bytes =
5866            include_bytes!("../../../baedeker-testdata/spec/valid/loop-as-local-tee-value.wasm");
5867        let module = Module::decode(bytes).unwrap();
5868        module.validate().unwrap();
5869    }
5870
5871    #[test]
5872    fn validate_loop_as_memory_grow_size_official_case() {
5873        let bytes =
5874            include_bytes!("../../../baedeker-testdata/spec/valid/loop-as-memory-grow-size.wasm",);
5875        let module = Module::decode(bytes).unwrap();
5876        module.validate().unwrap();
5877    }
5878
5879    #[test]
5880    fn validate_return_as_call_value_official_case() {
5881        let bytes =
5882            include_bytes!("../../../baedeker-testdata/spec/valid/return-as-call-value.wasm");
5883        let module = Module::decode(bytes).unwrap();
5884        module.validate().unwrap();
5885    }
5886
5887    #[test]
5888    fn validate_return_as_br_value_official_case() {
5889        let bytes = include_bytes!("../../../baedeker-testdata/spec/valid/return-as-br-value.wasm");
5890        let module = Module::decode(bytes).unwrap();
5891        module.validate().unwrap();
5892    }
5893
5894    #[test]
5895    fn validate_br_as_br_if_value_cond_official_case() {
5896        let bytes =
5897            include_bytes!("../../../baedeker-testdata/spec/valid/br-as-br-if-value-cond.wasm");
5898        let module = Module::decode(bytes).unwrap();
5899        module.validate().unwrap();
5900    }
5901
5902    #[test]
5903    fn validate_br_as_select_all_official_case() {
5904        let bytes = include_bytes!("../../../baedeker-testdata/spec/valid/br-as-select-all.wasm");
5905        let module = Module::decode(bytes).unwrap();
5906        module.validate().unwrap();
5907    }
5908
5909    #[test]
5910    fn validate_br_as_call_indirect_all_official_case() {
5911        let bytes =
5912            include_bytes!("../../../baedeker-testdata/spec/valid/br-as-call-indirect-all.wasm",);
5913        let module = Module::decode(bytes).unwrap();
5914        module.validate().unwrap();
5915    }
5916
5917    #[test]
5918    fn validate_br_as_local_tee_value_official_case() {
5919        let bytes =
5920            include_bytes!("../../../baedeker-testdata/spec/valid/br-as-local-tee-value.wasm");
5921        let module = Module::decode(bytes).unwrap();
5922        module.validate().unwrap();
5923    }
5924
5925    #[test]
5926    fn validate_br_as_load_address_official_case() {
5927        let bytes = include_bytes!("../../../baedeker-testdata/spec/valid/br-as-load-address.wasm");
5928        let module = Module::decode(bytes).unwrap();
5929        module.validate().unwrap();
5930    }
5931
5932    #[test]
5933    fn validate_br_as_store_n_value_official_case() {
5934        let bytes = include_bytes!("../../../baedeker-testdata/spec/valid/br-as-storeN-value.wasm");
5935        let module = Module::decode(bytes).unwrap();
5936        module.validate().unwrap();
5937    }
5938
5939    #[test]
5940    fn validate_br_as_memory_grow_size_official_case() {
5941        let bytes =
5942            include_bytes!("../../../baedeker-testdata/spec/valid/br-as-memory-grow-size.wasm",);
5943        let module = Module::decode(bytes).unwrap();
5944        module.validate().unwrap();
5945    }
5946
5947    #[test]
5948    fn validate_br_if_as_br_if_value_cond_official_case() {
5949        let bytes =
5950            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-br-if-value-cond.wasm",);
5951        let module = Module::decode(bytes).unwrap();
5952        module.validate().unwrap();
5953    }
5954
5955    #[test]
5956    fn validate_br_if_as_select_cond_official_case() {
5957        let bytes =
5958            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-select-cond.wasm");
5959        let module = Module::decode(bytes).unwrap();
5960        module.validate().unwrap();
5961    }
5962
5963    #[test]
5964    fn validate_br_if_as_call_indirect_last_official_case() {
5965        let bytes = include_bytes!(
5966            "../../../baedeker-testdata/spec/valid/br-if-as-call-indirect-last.wasm",
5967        );
5968        let module = Module::decode(bytes).unwrap();
5969        module.validate().unwrap();
5970    }
5971
5972    #[test]
5973    fn validate_br_if_as_local_tee_value_official_case() {
5974        let bytes =
5975            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-local-tee-value.wasm",);
5976        let module = Module::decode(bytes).unwrap();
5977        module.validate().unwrap();
5978    }
5979
5980    #[test]
5981    fn validate_br_if_as_load_address_official_case() {
5982        let bytes =
5983            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-load-address.wasm");
5984        let module = Module::decode(bytes).unwrap();
5985        module.validate().unwrap();
5986    }
5987
5988    #[test]
5989    fn validate_br_if_as_store_n_value_official_case() {
5990        let bytes =
5991            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-storeN-value.wasm");
5992        let module = Module::decode(bytes).unwrap();
5993        module.validate().unwrap();
5994    }
5995
5996    #[test]
5997    fn validate_br_if_as_memory_grow_size_official_case() {
5998        let bytes =
5999            include_bytes!("../../../baedeker-testdata/spec/valid/br-if-as-memory-grow-size.wasm",);
6000        let module = Module::decode(bytes).unwrap();
6001        module.validate().unwrap();
6002    }
6003
6004    #[test]
6005    fn validate_br_table_with_matching_label_types() {
6006        let bytes = [
6007            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
6008            0x03, 0x02, 0x01, 0x00, 0x0A, 0x10, 0x01, 0x0E, 0x00, 0x02, 0x7F, 0x41, 0x01, 0x41,
6009            0x00, 0x0E, 0x01, 0x00, 0x00, 0x0B, 0x1A, 0x0B,
6010        ];
6011        let module = Module::decode(&bytes).unwrap();
6012        module.validate().unwrap();
6013    }
6014
6015    #[test]
6016    fn validate_br_table_type_f64_value_official_case() {
6017        let bytes =
6018            include_bytes!("../../../baedeker-testdata/spec/valid/br-table-type-f64-value.wasm");
6019        let module = Module::decode(bytes).unwrap();
6020        module.validate().unwrap();
6021    }
6022
6023    #[test]
6024    fn validate_br_table_as_br_if_value_cond_official_case() {
6025        let bytes = include_bytes!(
6026            "../../../baedeker-testdata/spec/valid/br-table-as-br-if-value-cond.wasm",
6027        );
6028        let module = Module::decode(bytes).unwrap();
6029        module.validate().unwrap();
6030    }
6031
6032    #[test]
6033    fn validate_br_table_as_call_indirect_func_official_case() {
6034        let bytes = include_bytes!(
6035            "../../../baedeker-testdata/spec/valid/br-table-as-call-indirect-func.wasm",
6036        );
6037        let module = Module::decode(bytes).unwrap();
6038        module.validate().unwrap();
6039    }
6040
6041    #[test]
6042    fn validate_br_table_as_local_set_value_official_case() {
6043        let bytes = include_bytes!(
6044            "../../../baedeker-testdata/spec/valid/br-table-as-local-set-value.wasm",
6045        );
6046        let module = Module::decode(bytes).unwrap();
6047        module.validate().unwrap();
6048    }
6049
6050    #[test]
6051    fn validate_br_table_as_load_address_official_case() {
6052        let bytes =
6053            include_bytes!("../../../baedeker-testdata/spec/valid/br-table-as-load-address.wasm");
6054        let module = Module::decode(bytes).unwrap();
6055        module.validate().unwrap();
6056    }
6057
6058    #[test]
6059    fn validate_br_table_as_store_value_official_case() {
6060        let bytes =
6061            include_bytes!("../../../baedeker-testdata/spec/valid/br-table-as-store-value.wasm");
6062        let module = Module::decode(bytes).unwrap();
6063        module.validate().unwrap();
6064    }
6065
6066    #[test]
6067    fn validate_br_table_as_compare_left_official_case() {
6068        let bytes =
6069            include_bytes!("../../../baedeker-testdata/spec/valid/br-table-as-compare-left.wasm");
6070        let module = Module::decode(bytes).unwrap();
6071        module.validate().unwrap();
6072    }
6073
6074    #[test]
6075    fn validate_br_table_as_memory_grow_size_official_case() {
6076        let bytes = include_bytes!(
6077            "../../../baedeker-testdata/spec/valid/br-table-as-memory-grow-size.wasm",
6078        );
6079        let module = Module::decode(bytes).unwrap();
6080        module.validate().unwrap();
6081    }
6082
6083    #[test]
6084    fn validate_official_labels_block_case() {
6085        let bytes =
6086            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-block.wasm",);
6087        let module = Module::decode(bytes).unwrap();
6088        module.validate().unwrap();
6089    }
6090
6091    #[test]
6092    fn validate_official_labels_loop1_case() {
6093        let bytes =
6094            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop1.wasm",);
6095        let module = Module::decode(bytes).unwrap();
6096        module.validate().unwrap();
6097    }
6098
6099    #[test]
6100    fn validate_official_labels_loop2_case() {
6101        let bytes =
6102            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop2.wasm",);
6103        let module = Module::decode(bytes).unwrap();
6104        module.validate().unwrap();
6105    }
6106
6107    #[test]
6108    fn validate_official_labels_loop3_case() {
6109        let bytes =
6110            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop3.wasm",);
6111        let module = Module::decode(bytes).unwrap();
6112        module.validate().unwrap();
6113    }
6114
6115    #[test]
6116    fn validate_official_labels_loop4_case() {
6117        let bytes =
6118            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop4.wasm",);
6119        let module = Module::decode(bytes).unwrap();
6120        module.validate().unwrap();
6121    }
6122
6123    #[test]
6124    fn validate_official_labels_if_case() {
6125        let bytes =
6126            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-if.wasm",);
6127        let module = Module::decode(bytes).unwrap();
6128        module.validate().unwrap();
6129    }
6130
6131    #[test]
6132    fn validate_official_labels_if2_case() {
6133        let bytes =
6134            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-if2.wasm",);
6135        let module = Module::decode(bytes).unwrap();
6136        module.validate().unwrap();
6137    }
6138
6139    #[test]
6140    fn validate_official_labels_return_case() {
6141        let bytes =
6142            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-return.wasm",);
6143        let module = Module::decode(bytes).unwrap();
6144        module.validate().unwrap();
6145    }
6146
6147    #[test]
6148    fn validate_official_labels_br_if0_case() {
6149        let bytes =
6150            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-br-if0.wasm",);
6151        let module = Module::decode(bytes).unwrap();
6152        module.validate().unwrap();
6153    }
6154
6155    #[test]
6156    fn validate_official_labels_br_case() {
6157        let bytes =
6158            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-br.wasm",);
6159        let module = Module::decode(bytes).unwrap();
6160        module.validate().unwrap();
6161    }
6162
6163    #[test]
6164    fn validate_official_switch_stmt_case() {
6165        let bytes =
6166            include_bytes!("../../../baedeker-testdata/spec/valid/official-switch-stmt.wasm",);
6167        let module = Module::decode(bytes).unwrap();
6168        module.validate().unwrap();
6169    }
6170
6171    #[test]
6172    fn validate_official_switch_expr_case() {
6173        let bytes =
6174            include_bytes!("../../../baedeker-testdata/spec/valid/official-switch-expr.wasm",);
6175        let module = Module::decode(bytes).unwrap();
6176        module.validate().unwrap();
6177    }
6178
6179    #[test]
6180    fn validate_official_switch_arg_case() {
6181        let bytes =
6182            include_bytes!("../../../baedeker-testdata/spec/valid/official-switch-arg.wasm",);
6183        let module = Module::decode(bytes).unwrap();
6184        module.validate().unwrap();
6185    }
6186
6187    #[test]
6188    fn validate_official_ref_typed_syntax_case() {
6189        let bytes =
6190            include_bytes!("../../../baedeker-testdata/spec/valid/official-ref-typed-syntax.wasm",);
6191        let module = Module::decode(bytes).unwrap();
6192        module.validate().unwrap();
6193    }
6194
6195    #[test]
6196    fn validate_official_labels_loop5_case() {
6197        let bytes =
6198            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop5.wasm",);
6199        let module = Module::decode(bytes).unwrap();
6200        module.validate().unwrap();
6201    }
6202
6203    #[test]
6204    fn validate_official_labels_loop6_case() {
6205        let bytes =
6206            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-loop6.wasm",);
6207        let module = Module::decode(bytes).unwrap();
6208        module.validate().unwrap();
6209    }
6210
6211    #[test]
6212    fn validate_official_labels_br_if1_case() {
6213        let bytes =
6214            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-br-if1.wasm",);
6215        let module = Module::decode(bytes).unwrap();
6216        module.validate().unwrap();
6217    }
6218
6219    #[test]
6220    fn validate_official_labels_br_if2_case() {
6221        let bytes =
6222            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-br-if2.wasm",);
6223        let module = Module::decode(bytes).unwrap();
6224        module.validate().unwrap();
6225    }
6226
6227    #[test]
6228    fn validate_official_labels_br_if3_case() {
6229        let bytes =
6230            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-br-if3.wasm",);
6231        let module = Module::decode(bytes).unwrap();
6232        module.validate().unwrap();
6233    }
6234
6235    #[test]
6236    fn validate_official_labels_shadowing_case() {
6237        let bytes =
6238            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-shadowing.wasm",);
6239        let module = Module::decode(bytes).unwrap();
6240        module.validate().unwrap();
6241    }
6242
6243    #[test]
6244    fn validate_official_labels_redefinition_case() {
6245        let bytes = include_bytes!(
6246            "../../../baedeker-testdata/spec/valid/official-labels-redefinition.wasm",
6247        );
6248        let module = Module::decode(bytes).unwrap();
6249        module.validate().unwrap();
6250    }
6251
6252    #[test]
6253    fn validate_official_labels_switch_case() {
6254        let bytes =
6255            include_bytes!("../../../baedeker-testdata/spec/valid/official-labels-switch.wasm",);
6256        let module = Module::decode(bytes).unwrap();
6257        module.validate().unwrap();
6258    }
6259
6260    #[test]
6261    fn validate_official_switch_corner_case() {
6262        let bytes =
6263            include_bytes!("../../../baedeker-testdata/spec/valid/official-switch-corner.wasm",);
6264        let module = Module::decode(bytes).unwrap();
6265        module.validate().unwrap();
6266    }
6267
6268    #[test]
6269    fn validate_typed_br_if_with_equivalent_signature() {
6270        let bytes = [
6271            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7f,
6272            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
6273            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x13, 0x02,
6274            0x04, 0x00, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x02, 0x63, 0x01, 0xd2, 0x00, 0x20, 0x00,
6275            0x0d, 0x00, 0x0b, 0x0b,
6276        ];
6277        let module = Module::decode(&bytes).unwrap();
6278        module.validate().unwrap();
6279    }
6280
6281    #[test]
6282    fn reject_typed_br_if_with_wrong_concrete_type() {
6283        let bytes = [
6284            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7e,
6285            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
6286            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x13, 0x02,
6287            0x04, 0x00, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x02, 0x63, 0x01, 0xd2, 0x00, 0x20, 0x00,
6288            0x0d, 0x00, 0x0b, 0x0b,
6289        ];
6290        let module = Module::decode(&bytes).unwrap();
6291        let err = module.validate().unwrap_err();
6292        assert_eq!(err.offset, ByteOffset(56));
6293        assert!(matches!(
6294            err.kind,
6295            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6296                if label == crate::types::LabelIdx(0)
6297                    && expected == vec![ValType::Ref(RefType::Typed {
6298                        nullable: true,
6299                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6300                    })]
6301                    && found == vec![ValType::Ref(RefType::Typed {
6302                        nullable: false,
6303                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6304                    })]
6305        ));
6306    }
6307
6308    #[test]
6309    fn validate_typed_select_to_br_if_nullable_official_case() {
6310        let bytes = include_bytes!(
6311            "../../../baedeker-testdata/spec/valid/typed-select-to-br-if-nullable.wasm",
6312        );
6313        let module = Module::decode(bytes).unwrap();
6314        module.validate().unwrap();
6315    }
6316
6317    #[test]
6318    fn reject_typed_select_to_br_if_nullability_mismatch() {
6319        let bytes = include_bytes!(
6320            "../../../baedeker-testdata/spec/invalid-validate/typed-select-to-br-if-nullability-mismatch.wasm",
6321        );
6322        let module = Module::decode(bytes).unwrap();
6323        let err = module.validate().unwrap_err();
6324        assert_eq!(err.offset, ByteOffset(60));
6325        assert!(matches!(
6326            err.kind,
6327            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6328                if label == crate::types::LabelIdx(0)
6329                    && expected == vec![ValType::Ref(RefType::Typed {
6330                        nullable: false,
6331                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6332                    })]
6333                    && found == vec![ValType::Ref(RefType::Typed {
6334                        nullable: true,
6335                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6336                    })]
6337        ));
6338    }
6339
6340    #[test]
6341    fn validate_typed_table_init_to_br_if_nullable_official_case() {
6342        let bytes = include_bytes!(
6343            "../../../baedeker-testdata/spec/valid/typed-table-init-to-br-if-nullable.wasm",
6344        );
6345        let module = Module::decode(bytes).unwrap();
6346        module.validate().unwrap();
6347    }
6348
6349    #[test]
6350    fn reject_typed_table_init_to_br_if_nullability_mismatch() {
6351        let bytes = include_bytes!(
6352            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-to-br-if-nullability-mismatch.wasm",
6353        );
6354        let module = Module::decode(bytes).unwrap();
6355        let err = module.validate().unwrap_err();
6356        assert_eq!(err.offset, ByteOffset(89));
6357        assert!(matches!(
6358            err.kind,
6359            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6360                if label == crate::types::LabelIdx(0)
6361                    && expected == vec![ValType::Ref(RefType::Typed {
6362                        nullable: false,
6363                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6364                    })]
6365                    && found == vec![ValType::Ref(RefType::Typed {
6366                        nullable: true,
6367                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6368                    })]
6369        ));
6370    }
6371
6372    #[test]
6373    fn validate_typed_table_init_shared_source_to_br_if_nullable_official_case() {
6374        let bytes = include_bytes!(
6375            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-br-if-nullable.wasm",
6376        );
6377        let module = Module::decode(bytes).unwrap();
6378        module.validate().unwrap();
6379    }
6380
6381    #[test]
6382    fn reject_typed_table_init_shared_source_to_br_if_nullability_mismatch() {
6383        let bytes = include_bytes!(
6384            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-br-if-nullability-mismatch.wasm",
6385        );
6386        let module = Module::decode(bytes).unwrap();
6387        let err = module.validate().unwrap_err();
6388        assert_eq!(err.offset, ByteOffset(100));
6389        assert!(matches!(
6390            err.kind,
6391            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6392                if label == crate::types::LabelIdx(0)
6393                    && expected == vec![ValType::Ref(RefType::Typed {
6394                        nullable: false,
6395                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6396                    })]
6397                    && found == vec![ValType::Ref(RefType::Typed {
6398                        nullable: true,
6399                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6400                    })]
6401        ));
6402    }
6403
6404    #[test]
6405    fn validate_typed_br_to_loop_param_with_equivalent_signature() {
6406        let bytes = [
6407            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7f,
6408            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x00, 0x60, 0x01,
6409            0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x07, 0x05, 0x01, 0x01,
6410            0x66, 0x00, 0x00, 0x0a, 0x17, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x10, 0x00, 0x02,
6411            0x63, 0x00, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x0c, 0x00, 0x0b, 0x0b, 0x0b,
6412        ];
6413        let module = Module::decode(&bytes).unwrap();
6414        module.validate().unwrap();
6415    }
6416
6417    #[test]
6418    fn reject_typed_br_to_loop_param_with_wrong_concrete_type() {
6419        let bytes = [
6420            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7e,
6421            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x00, 0x60, 0x01,
6422            0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x07, 0x05, 0x01, 0x01,
6423            0x66, 0x00, 0x00, 0x0a, 0x17, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x10, 0x00, 0x02,
6424            0x63, 0x00, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x0c, 0x00, 0x0b, 0x0b, 0x0b,
6425        ];
6426        let module = Module::decode(&bytes).unwrap();
6427        let err = module.validate().unwrap_err();
6428        assert_eq!(err.offset, ByteOffset(65));
6429        assert!(matches!(
6430            err.kind,
6431            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6432                if label == crate::types::LabelIdx(0)
6433                    && expected == vec![ValType::Ref(RefType::Typed {
6434                        nullable: true,
6435                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6436                    })]
6437                    && found == vec![ValType::Ref(RefType::Typed {
6438                        nullable: false,
6439                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6440                    })]
6441        ));
6442    }
6443
6444    #[test]
6445    fn validate_typed_br_to_loop_param_nullable_official_case() {
6446        let bytes = include_bytes!(
6447            "../../../baedeker-testdata/spec/valid/typed-br-to-loop-param-nullable.wasm",
6448        );
6449        let module = Module::decode(bytes).unwrap();
6450        module.validate().unwrap();
6451    }
6452
6453    #[test]
6454    fn reject_typed_br_to_loop_param_nullability_mismatch() {
6455        let bytes = include_bytes!(
6456            "../../../baedeker-testdata/spec/invalid-validate/typed-br-to-loop-param-nullability-mismatch.wasm",
6457        );
6458        let module = Module::decode(bytes).unwrap();
6459        let err = module.validate().unwrap_err();
6460        assert_eq!(err.offset, ByteOffset(69));
6461        assert!(matches!(
6462            err.kind,
6463            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6464                if label == crate::types::LabelIdx(0)
6465                    && expected == vec![ValType::Ref(RefType::Typed {
6466                        nullable: false,
6467                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6468                    })]
6469                    && found == vec![ValType::Ref(RefType::Typed {
6470                        nullable: true,
6471                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6472                    })]
6473        ));
6474    }
6475
6476    #[test]
6477    fn validate_typed_br_if_to_loop_param_with_equivalent_signature() {
6478        let bytes = [
6479            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7f,
6480            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x00, 0x60, 0x01,
6481            0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x07, 0x05, 0x01, 0x01,
6482            0x66, 0x00, 0x00, 0x0a, 0x19, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x12, 0x00, 0x02,
6483            0x63, 0x00, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x41, 0x01, 0x0d, 0x00, 0x0b,
6484            0x0b, 0x0b,
6485        ];
6486        let module = Module::decode(&bytes).unwrap();
6487        module.validate().unwrap();
6488    }
6489
6490    #[test]
6491    fn reject_typed_br_if_to_loop_param_with_wrong_concrete_type() {
6492        let bytes = [
6493            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7e,
6494            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x00, 0x60, 0x01,
6495            0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x07, 0x05, 0x01, 0x01,
6496            0x66, 0x00, 0x00, 0x0a, 0x19, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x12, 0x00, 0x02,
6497            0x63, 0x00, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x41, 0x01, 0x0d, 0x00, 0x0b,
6498            0x0b, 0x0b,
6499        ];
6500        let module = Module::decode(&bytes).unwrap();
6501        let err = module.validate().unwrap_err();
6502        assert_eq!(err.offset, ByteOffset(67));
6503        assert!(matches!(
6504            err.kind,
6505            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6506                if label == crate::types::LabelIdx(0)
6507                    && expected == vec![ValType::Ref(RefType::Typed {
6508                        nullable: true,
6509                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6510                    })]
6511                    && found == vec![ValType::Ref(RefType::Typed {
6512                        nullable: false,
6513                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6514                    })]
6515        ));
6516    }
6517
6518    #[test]
6519    fn validate_typed_br_table_with_equivalent_signature() {
6520        let bytes = [
6521            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
6522            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
6523            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x15, 0x02, 0x04,
6524            0x00, 0x20, 0x00, 0x0b, 0x0e, 0x00, 0x02, 0x63, 0x01, 0xd2, 0x00, 0x41, 0x00, 0x0e,
6525            0x01, 0x00, 0x00, 0x0b, 0x0b,
6526        ];
6527        let module = Module::decode(&bytes).unwrap();
6528        module.validate().unwrap();
6529    }
6530
6531    #[test]
6532    fn reject_typed_br_table_with_wrong_concrete_type() {
6533        let bytes = [
6534            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7e,
6535            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
6536            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x15, 0x02, 0x04,
6537            0x00, 0x20, 0x00, 0x0b, 0x0e, 0x00, 0x02, 0x63, 0x01, 0xd2, 0x00, 0x41, 0x00, 0x0e,
6538            0x01, 0x00, 0x00, 0x0b, 0x0b,
6539        ];
6540        let module = Module::decode(&bytes).unwrap();
6541        let err = module.validate().unwrap_err();
6542        assert_eq!(err.offset, ByteOffset(55));
6543        assert!(matches!(
6544            err.kind,
6545            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6546                if label == crate::types::LabelIdx(0)
6547                    && expected == vec![ValType::Ref(RefType::Typed {
6548                        nullable: true,
6549                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6550                    })]
6551                    && found == vec![ValType::Ref(RefType::Typed {
6552                        nullable: false,
6553                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6554                    })]
6555        ));
6556    }
6557
6558    #[test]
6559    fn validate_typed_select_to_br_table_nullable_official_case() {
6560        let bytes = include_bytes!(
6561            "../../../baedeker-testdata/spec/valid/typed-select-to-br-table-nullable.wasm",
6562        );
6563        let module = Module::decode(bytes).unwrap();
6564        module.validate().unwrap();
6565    }
6566
6567    #[test]
6568    fn reject_typed_select_to_br_table_nullability_mismatch() {
6569        let bytes = include_bytes!(
6570            "../../../baedeker-testdata/spec/invalid-validate/typed-select-to-br-table-nullability-mismatch.wasm",
6571        );
6572        let module = Module::decode(bytes).unwrap();
6573        let err = module.validate().unwrap_err();
6574        assert_eq!(err.offset, ByteOffset(59));
6575        assert!(matches!(
6576            err.kind,
6577            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6578                if label == crate::types::LabelIdx(0)
6579                    && expected == vec![ValType::Ref(RefType::Typed {
6580                        nullable: false,
6581                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6582                    })]
6583                    && found == vec![ValType::Ref(RefType::Typed {
6584                        nullable: true,
6585                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6586                    })]
6587        ));
6588    }
6589
6590    #[test]
6591    fn validate_typed_table_init_to_br_table_nullable_official_case() {
6592        let bytes = include_bytes!(
6593            "../../../baedeker-testdata/spec/valid/typed-table-init-to-br-table-nullable.wasm",
6594        );
6595        let module = Module::decode(bytes).unwrap();
6596        module.validate().unwrap();
6597    }
6598
6599    #[test]
6600    fn reject_typed_table_init_to_br_table_nullability_mismatch() {
6601        let bytes = include_bytes!(
6602            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-to-br-table-nullability-mismatch.wasm",
6603        );
6604        let module = Module::decode(bytes).unwrap();
6605        let err = module.validate().unwrap_err();
6606        assert_eq!(err.offset, ByteOffset(88));
6607        assert!(matches!(
6608            err.kind,
6609            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6610                if label == crate::types::LabelIdx(0)
6611                    && expected == vec![ValType::Ref(RefType::Typed {
6612                        nullable: false,
6613                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6614                    })]
6615                    && found == vec![ValType::Ref(RefType::Typed {
6616                        nullable: true,
6617                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6618                    })]
6619        ));
6620    }
6621
6622    #[test]
6623    fn validate_typed_table_init_shared_source_to_br_table_nullable_official_case() {
6624        let bytes = include_bytes!(
6625            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-br-table-nullable.wasm",
6626        );
6627        let module = Module::decode(bytes).unwrap();
6628        module.validate().unwrap();
6629    }
6630
6631    #[test]
6632    fn reject_typed_table_init_shared_source_to_br_table_nullability_mismatch() {
6633        let bytes = include_bytes!(
6634            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-br-table-nullability-mismatch.wasm",
6635        );
6636        let module = Module::decode(bytes).unwrap();
6637        let err = module.validate().unwrap_err();
6638        assert_eq!(err.offset, ByteOffset(99));
6639        assert!(matches!(
6640            err.kind,
6641            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6642                if label == crate::types::LabelIdx(0)
6643                    && expected == vec![ValType::Ref(RefType::Typed {
6644                        nullable: false,
6645                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6646                    })]
6647                    && found == vec![ValType::Ref(RefType::Typed {
6648                        nullable: true,
6649                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6650                    })]
6651        ));
6652    }
6653
6654    /// Nullability-differing br_table targets are VALID when the operand is
6655    /// a subtype of both: (ref $t0) branches to (ref $t0) and
6656    /// (ref null $t0) labels alike (the join is the operand's own type).
6657    #[test]
6658    fn validate_typed_br_table_nullability_targets_join() {
6659        let bytes = include_bytes!(
6660            "../../../baedeker-testdata/spec/valid/typed-br-table-nullability-targets-join.wasm",
6661        );
6662        let module = Module::decode(bytes).unwrap();
6663        module.validate().unwrap();
6664    }
6665
6666    #[test]
6667    fn validate_typed_select() {
6668        let bytes = [
6669            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
6670            0x7E, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0D, 0x01, 0x0B, 0x00, 0x42, 0x01, 0x42, 0x02,
6671            0x41, 0x00, 0x1C, 0x01, 0x7E, 0x0B,
6672        ];
6673        let module = Module::decode(&bytes).unwrap();
6674        module.validate().unwrap();
6675    }
6676
6677    #[test]
6678    fn validate_select_as_br_table_last_official_case() {
6679        let bytes =
6680            include_bytes!("../../../baedeker-testdata/spec/valid/select-as-br-table-last.wasm");
6681        let module = Module::decode(bytes).unwrap();
6682        module.validate().unwrap();
6683    }
6684
6685    #[test]
6686    fn validate_select_as_call_indirect_last_official_case() {
6687        let bytes = include_bytes!(
6688            "../../../baedeker-testdata/spec/valid/select-as-call-indirect-last.wasm",
6689        );
6690        let module = Module::decode(bytes).unwrap();
6691        module.validate().unwrap();
6692    }
6693
6694    #[test]
6695    fn validate_select_as_memory_grow_value_official_case() {
6696        let bytes = include_bytes!(
6697            "../../../baedeker-testdata/spec/valid/select-as-memory-grow-value.wasm",
6698        );
6699        let module = Module::decode(bytes).unwrap();
6700        module.validate().unwrap();
6701    }
6702
6703    #[test]
6704    fn validate_select_as_global_set_value_official_case() {
6705        let bytes = include_bytes!(
6706            "../../../baedeker-testdata/spec/valid/select-as-global-set-value.wasm",
6707        );
6708        let module = Module::decode(bytes).unwrap();
6709        module.validate().unwrap();
6710    }
6711
6712    #[test]
6713    fn validate_select_as_convert_operand_official_case() {
6714        let bytes =
6715            include_bytes!("../../../baedeker-testdata/spec/valid/select-as-convert-operand.wasm",);
6716        let module = Module::decode(bytes).unwrap();
6717        module.validate().unwrap();
6718    }
6719
6720    #[test]
6721    fn validate_select_as_if_condition_official_case() {
6722        let bytes =
6723            include_bytes!("../../../baedeker-testdata/spec/valid/select-as-if-condition.wasm");
6724        let module = Module::decode(bytes).unwrap();
6725        module.validate().unwrap();
6726    }
6727
6728    #[test]
6729    fn validate_typed_select_with_equivalent_concrete_type() {
6730        let bytes = [
6731            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7F,
6732            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x63, 0x01, 0x03,
6733            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x13, 0x02,
6734            0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00, 0xD2, 0x00, 0xD0, 0x01, 0x20, 0x00, 0x1C,
6735            0x01, 0x63, 0x01, 0x0B,
6736        ];
6737        let module = Module::decode(&bytes).unwrap();
6738        module.validate().unwrap();
6739    }
6740
6741    #[test]
6742    fn reject_typed_select_wrong_operand_types() {
6743        let bytes = [
6744            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
6745            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0E, 0x01, 0x0C, 0x00, 0x41, 0x01, 0x41, 0x02, 0x41,
6746            0x00, 0x1C, 0x01, 0x7E, 0x1A, 0x0B,
6747        ];
6748        let module = Module::decode(&bytes).unwrap();
6749        let err = module.validate().unwrap_err();
6750        assert_eq!(err.offset, ByteOffset(29));
6751        assert!(matches!(
6752            err.kind,
6753            ValidationErrorKind::SelectOperandTypeMismatch { expected, found }
6754                if expected == ValType::Num(crate::types::NumType::I64)
6755                    && found == vec![
6756                        ValType::Num(crate::types::NumType::I32),
6757                        ValType::Num(crate::types::NumType::I32),
6758                    ]
6759        ));
6760    }
6761
6762    #[test]
6763    fn reject_typed_select_with_invalid_result_arity() {
6764        let bytes = [
6765            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
6766            0x03, 0x02, 0x01, 0x00, 0x0A, 0x0D, 0x01, 0x0B, 0x00, 0x41, 0x01, 0x41, 0x02, 0x41,
6767            0x00, 0x1C, 0x00, 0x1A, 0x0B,
6768        ];
6769        let module = Module::decode(&bytes).unwrap();
6770        let err = module.validate().unwrap_err();
6771        assert_eq!(err.offset, ByteOffset(29));
6772        assert!(matches!(
6773            err.kind,
6774            ValidationErrorKind::InvalidSelectResultArity { found: 0 }
6775        ));
6776    }
6777
6778    #[test]
6779    fn reject_typed_select_with_wrong_concrete_type() {
6780        let bytes = [
6781            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7F,
6782            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x60, 0x01, 0x7F, 0x01, 0x63, 0x01, 0x03,
6783            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x13, 0x02,
6784            0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00, 0xD2, 0x00, 0xD0, 0x01, 0x20, 0x00, 0x1C,
6785            0x01, 0x63, 0x01, 0x0B,
6786        ];
6787        let module = Module::decode(&bytes).unwrap();
6788        let err = module.validate().unwrap_err();
6789        assert_eq!(err.offset, ByteOffset(55));
6790        assert!(matches!(
6791            err.kind,
6792            ValidationErrorKind::SelectOperandTypeMismatch { expected, found }
6793                if expected == ValType::Ref(RefType::Typed {
6794                    nullable: true,
6795                    heap: crate::types::HeapType::Type(TypeIdx(1)),
6796                }) && found == vec![
6797                    ValType::Ref(RefType::Typed {
6798                        nullable: false,
6799                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6800                    }),
6801                    ValType::Ref(RefType::Typed {
6802                        nullable: true,
6803                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6804                    }),
6805                ]
6806        ));
6807    }
6808
6809    #[test]
6810    fn reject_typed_select_nullability_mismatch() {
6811        let bytes = include_bytes!(
6812            "../../../baedeker-testdata/spec/invalid-validate/typed-select-nullability-mismatch.wasm",
6813        );
6814        let module = Module::decode(bytes).unwrap();
6815        let err = module.validate().unwrap_err();
6816        assert_eq!(err.offset, ByteOffset(50));
6817        assert!(matches!(
6818            err.kind,
6819            ValidationErrorKind::SelectOperandTypeMismatch { expected, found }
6820                if expected == ValType::Ref(RefType::Typed {
6821                    nullable: false,
6822                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6823                }) && found == vec![
6824                    ValType::Ref(RefType::Typed {
6825                        nullable: false,
6826                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6827                    }),
6828                    ValType::Ref(RefType::Typed {
6829                        nullable: true,
6830                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6831                    }),
6832                ]
6833        ));
6834    }
6835
6836    #[test]
6837    fn reject_typed_select_function_result_wrong_concrete_type() {
6838        let bytes = include_bytes!(
6839            "../../../baedeker-testdata/spec/invalid-validate/typed-select-function-result-wrong-concrete-type.wasm",
6840        );
6841        let module = Module::decode(bytes).unwrap();
6842        let err = module.validate().unwrap_err();
6843        assert_eq!(err.offset, ByteOffset(59));
6844        assert!(matches!(
6845            err.kind,
6846            ValidationErrorKind::FunctionResultTypeMismatch {
6847                expected,
6848                found,
6849                ..
6850            } if expected == vec![ValType::Ref(RefType::Typed {
6851                    nullable: true,
6852                    heap: crate::types::HeapType::Type(TypeIdx(1)),
6853                })] && found == vec![ValType::Ref(RefType::Typed {
6854                    nullable: true,
6855                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6856                })]
6857        ));
6858    }
6859
6860    #[test]
6861    fn reject_typed_select_block_result_wrong_concrete_type() {
6862        let bytes = include_bytes!(
6863            "../../../baedeker-testdata/spec/invalid-validate/typed-select-block-result-wrong-concrete-type.wasm",
6864        );
6865        let module = Module::decode(bytes).unwrap();
6866        let err = module.validate().unwrap_err();
6867        assert_eq!(err.offset, ByteOffset(62));
6868        assert!(matches!(
6869            err.kind,
6870            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
6871                if expected == vec![ValType::Ref(RefType::Typed {
6872                    nullable: true,
6873                    heap: crate::types::HeapType::Type(TypeIdx(1)),
6874                })] && found == vec![ValType::Ref(RefType::Typed {
6875                    nullable: true,
6876                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6877                })]
6878        ));
6879    }
6880
6881    #[test]
6882    fn reject_typed_select_if_result_wrong_concrete_type() {
6883        let bytes = include_bytes!(
6884            "../../../baedeker-testdata/spec/invalid-validate/typed-select-if-result-wrong-concrete-type.wasm",
6885        );
6886        let module = Module::decode(bytes).unwrap();
6887        let err = module.validate().unwrap_err();
6888        assert_eq!(err.offset, ByteOffset(64));
6889        assert!(matches!(
6890            err.kind,
6891            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
6892                if expected == vec![ValType::Ref(RefType::Typed {
6893                    nullable: true,
6894                    heap: crate::types::HeapType::Type(TypeIdx(1)),
6895                })] && found == vec![ValType::Ref(RefType::Typed {
6896                    nullable: true,
6897                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6898                })]
6899        ));
6900    }
6901
6902    #[test]
6903    fn reject_typed_select_function_result_nullability_mismatch() {
6904        let bytes = include_bytes!(
6905            "../../../baedeker-testdata/spec/invalid-validate/typed-select-function-result-nullability-mismatch.wasm",
6906        );
6907        let module = Module::decode(bytes).unwrap();
6908        let err = module.validate().unwrap_err();
6909        assert_eq!(err.offset, ByteOffset(54));
6910        assert!(matches!(
6911            err.kind,
6912            ValidationErrorKind::FunctionResultTypeMismatch {
6913                expected,
6914                found,
6915                ..
6916            } if expected == vec![ValType::Ref(RefType::Typed {
6917                    nullable: false,
6918                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6919                })] && found == vec![ValType::Ref(RefType::Typed {
6920                    nullable: true,
6921                    heap: crate::types::HeapType::Type(TypeIdx(0)),
6922                })]
6923        ));
6924    }
6925
6926    #[test]
6927    fn reject_br_table_with_inconsistent_target_types() {
6928        let bytes = [
6929            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
6930            0x03, 0x02, 0x01, 0x00, 0x0A, 0x10, 0x01, 0x0E, 0x00, 0x02, 0x7F, 0x02, 0x7E, 0x41,
6931            0x00, 0x0E, 0x01, 0x00, 0x01, 0x0B, 0x0B, 0x0B,
6932        ];
6933        let module = Module::decode(&bytes).unwrap();
6934        let err = module.validate().unwrap_err();
6935        assert_eq!(err.offset, ByteOffset(29));
6936        // Label types may differ under the join rule, but the (empty) stack
6937        // cannot supply an i64 to label 0.
6938        assert!(matches!(
6939            err.kind,
6940            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6941                if label == crate::types::LabelIdx(0)
6942                    && expected == vec![ValType::Num(crate::types::NumType::I64)]
6943                    && found.is_empty()
6944        ));
6945    }
6946
6947    #[test]
6948    fn validate_typed_br_table_multi_block_targets_with_equivalent_signature() {
6949        let bytes = [
6950            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7f,
6951            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
6952            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x1a, 0x02,
6953            0x04, 0x00, 0x20, 0x00, 0x0b, 0x13, 0x00, 0x02, 0x63, 0x01, 0x02, 0x63, 0x00, 0xd2,
6954            0x00, 0x20, 0x00, 0x0e, 0x02, 0x00, 0x01, 0x01, 0x0b, 0x0b, 0x0b,
6955        ];
6956        let module = Module::decode(&bytes).unwrap();
6957        module.validate().unwrap();
6958    }
6959
6960    #[test]
6961    fn reject_typed_br_table_multi_block_targets_with_wrong_concrete_type() {
6962        let bytes = [
6963            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7e,
6964            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
6965            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x1a, 0x02,
6966            0x04, 0x00, 0x20, 0x00, 0x0b, 0x13, 0x00, 0x02, 0x63, 0x01, 0x02, 0x63, 0x00, 0xd2,
6967            0x00, 0x20, 0x00, 0x0e, 0x02, 0x00, 0x01, 0x01, 0x0b, 0x0b, 0x0b,
6968        ];
6969        let module = Module::decode(&bytes).unwrap();
6970        let err = module.validate().unwrap_err();
6971        assert_eq!(err.offset, ByteOffset(59));
6972        // The (ref $t0) operand satisfies label 0 (ref null $t0) but not
6973        // label 1 (ref null $t1).
6974        assert!(matches!(
6975            err.kind,
6976            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
6977                if label == crate::types::LabelIdx(1)
6978                    && expected == vec![ValType::Ref(RefType::Typed {
6979                        nullable: true,
6980                        heap: crate::types::HeapType::Type(TypeIdx(1)),
6981                    })]
6982                    && found == vec![ValType::Ref(RefType::Typed {
6983                        nullable: false,
6984                        heap: crate::types::HeapType::Type(TypeIdx(0)),
6985                    })]
6986        ));
6987    }
6988
6989    #[test]
6990    fn validate_typed_br_table_multi_loop_block_targets_with_equivalent_signature() {
6991        let bytes = [
6992            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x18, 0x04, 0x60, 0x01, 0x7f,
6993            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x60,
6994            0x01, 0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01,
6995            0x01, 0x66, 0x00, 0x00, 0x0a, 0x1e, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x17, 0x00,
6996            0x02, 0x63, 0x01, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x20, 0x00, 0x0e, 0x02,
6997            0x00, 0x01, 0x01, 0xd0, 0x00, 0x0b, 0x0b, 0x0b,
6998        ];
6999        let module = Module::decode(&bytes).unwrap();
7000        module.validate().unwrap();
7001    }
7002
7003    #[test]
7004    fn reject_typed_br_table_multi_loop_block_targets_with_wrong_concrete_type() {
7005        let bytes = [
7006            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x18, 0x04, 0x60, 0x01, 0x7e,
7007            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x60,
7008            0x01, 0x63, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01,
7009            0x01, 0x66, 0x00, 0x00, 0x0a, 0x1e, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x17, 0x00,
7010            0x02, 0x63, 0x01, 0xd0, 0x00, 0x03, 0x03, 0x1a, 0xd2, 0x00, 0x20, 0x00, 0x0e, 0x02,
7011            0x00, 0x01, 0x01, 0xd0, 0x00, 0x0b, 0x0b, 0x0b,
7012        ];
7013        let module = Module::decode(&bytes).unwrap();
7014        let err = module.validate().unwrap_err();
7015        assert_eq!(err.offset, ByteOffset(68));
7016        // The (ref $t0) operand satisfies the loop's (ref null $t0) param
7017        // but not the block's (ref null $t1) result.
7018        assert!(matches!(
7019            err.kind,
7020            ValidationErrorKind::BranchTypeMismatch { label, expected, found }
7021                if label == crate::types::LabelIdx(1)
7022                    && expected == vec![ValType::Ref(RefType::Typed {
7023                        nullable: true,
7024                        heap: crate::types::HeapType::Type(TypeIdx(1)),
7025                    })]
7026                    && found == vec![ValType::Ref(RefType::Typed {
7027                        nullable: false,
7028                        heap: crate::types::HeapType::Type(TypeIdx(0)),
7029                    })]
7030        ));
7031    }
7032
7033    #[test]
7034    fn validate_start_function_with_empty_signature() {
7035        let bytes = [
7036            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
7037            0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x00, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
7038        ];
7039        let module = Module::decode(&bytes).unwrap();
7040        module.validate().unwrap();
7041    }
7042
7043    #[test]
7044    fn reject_unknown_start_function_index() {
7045        let bytes = [
7046            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00,
7047        ];
7048        let module = Module::decode(&bytes).unwrap();
7049        let err = module.validate().unwrap_err();
7050        assert_eq!(err.offset, ByteOffset(10));
7051        assert!(matches!(
7052            err.kind,
7053            ValidationErrorKind::UnknownFuncIdx {
7054                idx: crate::types::FuncIdx(0)
7055            }
7056        ));
7057    }
7058
7059    #[test]
7060    fn reject_start_function_with_params() {
7061        let bytes = [
7062            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x01, 0x7F,
7063            0x00, 0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x00, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
7064        ];
7065        let module = Module::decode(&bytes).unwrap();
7066        let err = module.validate().unwrap_err();
7067        assert_eq!(err.offset, ByteOffset(21));
7068        assert!(matches!(
7069            err.kind,
7070            ValidationErrorKind::InvalidStartFunctionType { params, results }
7071                if params == vec![ValType::Num(crate::types::NumType::I32)]
7072                    && results.is_empty()
7073        ));
7074    }
7075
7076    #[test]
7077    fn reject_start_function_with_results() {
7078        let bytes = [
7079            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
7080            0x7F, 0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x00, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
7081        ];
7082        let module = Module::decode(&bytes).unwrap();
7083        let err = module.validate().unwrap_err();
7084        assert_eq!(err.offset, ByteOffset(21));
7085        assert!(matches!(
7086            err.kind,
7087            ValidationErrorKind::InvalidStartFunctionType { params, results }
7088                if params.is_empty()
7089                    && results == vec![ValType::Num(crate::types::NumType::I32)]
7090        ));
7091    }
7092
7093    #[test]
7094    fn validate_element_expression_initializers() {
7095        let bytes = [
7096            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
7097            0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01, 0x09, 0x0A, 0x01, 0x05,
7098            0x70, 0x02, 0xD0, 0x70, 0x0B, 0xD2, 0x00, 0x0B, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
7099        ];
7100        let module = Module::decode(&bytes).unwrap();
7101        module.validate().unwrap();
7102    }
7103
7104    #[test]
7105    fn reject_element_expr_type_mismatch() {
7106        let bytes = [
7107            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x6F, 0x00, 0x01,
7108            0x09, 0x07, 0x01, 0x05, 0x6F, 0x01, 0xD0, 0x70, 0x0B,
7109        ];
7110        let module = Module::decode(&bytes).unwrap();
7111        let err = module.validate().unwrap_err();
7112        assert!(matches!(
7113            err.kind,
7114            ValidationErrorKind::ElementExprTypeMismatch {
7115                expected: ValType::Ref(RefType::ExternRef),
7116                found: ValType::Ref(RefType::FuncRef),
7117            }
7118        ));
7119    }
7120
7121    #[test]
7122    fn reject_non_constant_element_expr() {
7123        let bytes = [
7124            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01,
7125            0x09, 0x07, 0x01, 0x05, 0x70, 0x01, 0x41, 0x00, 0x0B,
7126        ];
7127        let module = Module::decode(&bytes).unwrap();
7128        let err = module.validate().unwrap_err();
7129        assert!(matches!(
7130            err.kind,
7131            ValidationErrorKind::NonConstantElementExpr
7132        ));
7133    }
7134
7135    #[test]
7136    fn reject_memory_init_without_data_count_section() {
7137        let bytes = [
7138            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
7139            0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x0A, 0x0E, 0x01, 0x0C, 0x00,
7140            0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0xFC, 0x08, 0x00, 0x00, 0x0B, 0x0B, 0x03, 0x01,
7141            0x01, 0x00,
7142        ];
7143        let module = Module::decode(&bytes).unwrap();
7144        let err = module.validate().unwrap_err();
7145        assert!(matches!(
7146            err.kind,
7147            ValidationErrorKind::MissingDataCountSection { op: "memory.init" }
7148        ));
7149    }
7150
7151    #[test]
7152    fn reject_data_drop_without_data_count_section() {
7153        let bytes = [
7154            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
7155            0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0xFC, 0x09, 0x00, 0x0B,
7156        ];
7157        let module = Module::decode(&bytes).unwrap();
7158        let err = module.validate().unwrap_err();
7159        assert!(matches!(
7160            err.kind,
7161            ValidationErrorKind::MissingDataCountSection { op: "data.drop" }
7162        ));
7163    }
7164
7165    #[test]
7166    fn reject_active_element_table_type_mismatch() {
7167        let bytes = [
7168            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x6F, 0x00, 0x01,
7169            0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00,
7170        ];
7171        let module = Module::decode(&bytes).unwrap();
7172        let err = module.validate().unwrap_err();
7173        assert!(matches!(
7174            err.kind,
7175            ValidationErrorKind::ElementTableTypeMismatch {
7176                expected: RefType::ExternRef,
7177                found: RefType::FuncRef,
7178            }
7179        ));
7180    }
7181
7182    #[test]
7183    fn validate_active_element_table_type_match_for_imported_table() {
7184        let bytes = [
7185            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x01, 0x03, b'e', b'n',
7186            b'v', 0x01, b't', 0x01, 0x6F, 0x00, 0x01, 0x09, 0x0B, 0x01, 0x06, 0x00, 0x41, 0x00,
7187            0x0B, 0x6F, 0x01, 0xD0, 0x6F, 0x0B,
7188        ];
7189        let module = Module::decode(&bytes).unwrap();
7190        module.validate().unwrap();
7191    }
7192
7193    #[test]
7194    fn validate_multiple_tables_across_imports_and_definitions() {
7195        let bytes = [
7196            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x01, 0x03, b'e', b'n',
7197            b'v', 0x01, b't', 0x01, 0x70, 0x00, 0x01, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01,
7198        ];
7199        let module = Module::decode(&bytes).unwrap();
7200        module.validate().unwrap();
7201    }
7202
7203    #[test]
7204    fn validate_multiple_memories_across_imports_and_definitions() {
7205        let bytes = [
7206            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x02, 0x0C, 0x01, 0x03, b'e', b'n',
7207            b'v', 0x03, b'm', b'e', b'm', 0x02, 0x00, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01,
7208        ];
7209        let module = Module::decode(&bytes).unwrap();
7210        module.validate().unwrap();
7211    }
7212
7213    #[test]
7214    fn reject_duplicate_export_names() {
7215        let bytes = [
7216            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
7217            0x03, 0x02, 0x01, 0x00, 0x07, 0x0D, 0x02, 0x03, b'd', b'u', b'p', 0x00, 0x00, 0x03,
7218            b'd', b'u', b'p', 0x00, 0x00, 0x0A, 0x04, 0x01, 0x02, 0x00, 0x0B,
7219        ];
7220        let module = Module::decode(&bytes).unwrap();
7221        let err = module.validate().unwrap_err();
7222        assert!(matches!(
7223            err.kind,
7224            ValidationErrorKind::DuplicateExportName { name } if name == "dup"
7225        ));
7226    }
7227
7228    #[test]
7229    fn validate_exports_and_elements_indices() {
7230        let bytes = [
7231            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x00,
7232            0x60, 0x01, 0x7F, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x04, 0x04, 0x01, 0x70, 0x00,
7233            0x02, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x06, 0x01, 0x7F, 0x00, 0x41, 0x00, 0x0B,
7234            0x07, 0x11, 0x04, 0x01, b'f', 0x00, 0x00, 0x01, b't', 0x01, 0x00, 0x01, b'm', 0x02,
7235            0x00, 0x01, b'g', 0x03, 0x00, 0x09, 0x08, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x02, 0x00,
7236            0x01, 0x0A, 0x07, 0x02, 0x02, 0x00, 0x0B, 0x02, 0x00, 0x0B,
7237        ];
7238        let module = Module::decode(&bytes).unwrap();
7239        module.validate().unwrap();
7240    }
7241
7242    #[test]
7243    fn reject_unknown_export_table_index() {
7244        let bytes = [
7245            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x01, b't', 0x01,
7246            0x00,
7247        ];
7248        let module = Module::decode(&bytes).unwrap();
7249        let err = module.validate().unwrap_err();
7250        assert_eq!(err.offset, ByteOffset(10));
7251        assert!(matches!(
7252            err.kind,
7253            ValidationErrorKind::UnknownTableIdx {
7254                idx: crate::types::TableIdx(0),
7255                available: 0,
7256            }
7257        ));
7258    }
7259
7260    #[test]
7261    fn reject_unknown_export_memory_index() {
7262        let bytes = [
7263            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x01, b'm', 0x02,
7264            0x00,
7265        ];
7266        let module = Module::decode(&bytes).unwrap();
7267        let err = module.validate().unwrap_err();
7268        assert_eq!(err.offset, ByteOffset(10));
7269        assert!(matches!(
7270            err.kind,
7271            ValidationErrorKind::UnknownMemIdx {
7272                idx: crate::types::MemIdx(0),
7273                available: 0,
7274            }
7275        ));
7276    }
7277
7278    #[test]
7279    fn reject_unknown_export_global_index() {
7280        let bytes = [
7281            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x01, b'g', 0x03,
7282            0x00,
7283        ];
7284        let module = Module::decode(&bytes).unwrap();
7285        let err = module.validate().unwrap_err();
7286        assert_eq!(err.offset, ByteOffset(10));
7287        assert!(matches!(
7288            err.kind,
7289            ValidationErrorKind::UnknownGlobalIdx {
7290                idx: crate::types::GlobalIdx(0),
7291                available: 0,
7292            }
7293        ));
7294    }
7295
7296    #[test]
7297    fn reject_unknown_element_table_index() {
7298        let bytes = [
7299            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x09, 0x09, 0x01, 0x02, 0x00, 0x41,
7300            0x00, 0x0B, 0x00, 0x01, 0x00,
7301        ];
7302        let module = Module::decode(&bytes).unwrap();
7303        let err = module.validate().unwrap_err();
7304        assert_eq!(err.offset, ByteOffset(13));
7305        assert!(matches!(
7306            err.kind,
7307            ValidationErrorKind::UnknownTableIdx {
7308                idx: crate::types::TableIdx(0),
7309                available: 0,
7310            }
7311        ));
7312    }
7313
7314    #[test]
7315    fn reject_unknown_function_index_in_element_init() {
7316        let bytes = [
7317            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01,
7318            0x09, 0x07, 0x01, 0x00, 0x41, 0x00, 0x0B, 0x01, 0x00,
7319        ];
7320        let module = Module::decode(&bytes).unwrap();
7321        let err = module.validate().unwrap_err();
7322        assert_eq!(err.offset, ByteOffset(16));
7323        assert!(matches!(
7324            err.kind,
7325            ValidationErrorKind::UnknownFuncIdx {
7326                idx: crate::types::FuncIdx(0)
7327            }
7328        ));
7329    }
7330
7331    #[test]
7332    fn validate_call_indirect_with_funcref_table() {
7333        let bytes = [
7334            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60, 0x01, 0x7F,
7335            0x01, 0x7F, 0x60, 0x00, 0x00, 0x02, 0x0D, 0x01, 0x03, b'e', b'n', b'v', 0x03, b't',
7336            b'a', b'b', 0x01, 0x70, 0x00, 0x01, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0B, 0x01, 0x09,
7337            0x00, 0x20, 0x00, 0x41, 0x00, 0x11, 0x00, 0x00, 0x0B,
7338        ];
7339        let module = Module::decode(&bytes).unwrap();
7340        module.validate().unwrap();
7341    }
7342
7343    #[test]
7344    fn validate_typed_block_result_to_call_indirect_ref_param_with_equivalent_signature() {
7345        let bytes = include_bytes!(
7346            "../../../baedeker-testdata/spec/valid/typed-block-to-call-indirect-ref-param-equivalent-signature.wasm",
7347        );
7348        let module = Module::decode(bytes).unwrap();
7349        module.validate().unwrap();
7350    }
7351
7352    #[test]
7353    fn reject_typed_block_result_to_call_indirect_ref_param_with_wrong_concrete_type() {
7354        let bytes = include_bytes!(
7355            "../../../baedeker-testdata/spec/invalid-validate/typed-block-to-call-indirect-ref-param-wrong-concrete-type.wasm",
7356        );
7357        let module = Module::decode(bytes).unwrap();
7358        let err = module.validate().unwrap_err();
7359        assert_eq!(err.offset, ByteOffset(88));
7360        assert!(matches!(
7361            err.kind,
7362            ValidationErrorKind::TypeMismatch { op, expected, found }
7363                if op == "stack"
7364                    && expected == ValType::Ref(RefType::Typed {
7365                        nullable: true,
7366                        heap: crate::types::HeapType::Type(TypeIdx(1)),
7367                    })
7368                    && found == ValType::Ref(RefType::Typed {
7369                        nullable: true,
7370                        heap: crate::types::HeapType::Type(TypeIdx(0)),
7371                    })
7372        ));
7373    }
7374
7375    #[test]
7376    fn validate_return_call() {
7377        let bytes = [
7378            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
7379            0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x0A, 0x0B, 0x02, 0x04, 0x00, 0x41, 0x00, 0x0B,
7380            0x04, 0x00, 0x12, 0x00, 0x0B,
7381        ];
7382        let module = Module::decode(&bytes).unwrap();
7383        module.validate().unwrap();
7384    }
7385
7386    #[test]
7387    fn reject_return_call_result_mismatch() {
7388        let bytes = [
7389            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60, 0x00, 0x01,
7390            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x03, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0B, 0x02, 0x04,
7391            0x00, 0x42, 0x00, 0x0B, 0x04, 0x00, 0x12, 0x00, 0x0B,
7392        ];
7393        let module = Module::decode(&bytes).unwrap();
7394        let err = module.validate().unwrap_err();
7395        assert_eq!(err.offset, ByteOffset(34));
7396        assert!(matches!(
7397            err.kind,
7398            ValidationErrorKind::ResultTypeMismatch {
7399                expected,
7400                found,
7401            } if expected == vec![ValType::Num(crate::types::NumType::I32)]
7402                && found == vec![ValType::Num(crate::types::NumType::I64)]
7403        ));
7404    }
7405
7406    #[test]
7407    fn validate_return_call_indirect_with_funcref_table() {
7408        let bytes = [
7409            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F,
7410            0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x01, 0x0A,
7411            0x10, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x09, 0x00, 0x20, 0x00, 0x41, 0x00, 0x13,
7412            0x00, 0x00, 0x0B,
7413        ];
7414        let module = Module::decode(&bytes).unwrap();
7415        module.validate().unwrap();
7416    }
7417
7418    #[test]
7419    fn validate_typed_table_init_to_return_call_indirect_result_nullable_official_case() {
7420        let bytes = include_bytes!(
7421            "../../../baedeker-testdata/spec/valid/typed-table-init-to-return-call-indirect-result-nullable.wasm",
7422        );
7423        let module = Module::decode(bytes).unwrap();
7424        module.validate().unwrap();
7425    }
7426
7427    #[test]
7428    fn validate_typed_if_result_to_return_call_indirect_ref_param_with_equivalent_signature() {
7429        let bytes = include_bytes!(
7430            "../../../baedeker-testdata/spec/valid/typed-if-to-return-call-indirect-ref-param-equivalent-signature.wasm",
7431        );
7432        let module = Module::decode(bytes).unwrap();
7433        module.validate().unwrap();
7434    }
7435
7436    #[test]
7437    fn reject_typed_if_result_to_return_call_indirect_ref_param_with_wrong_concrete_type() {
7438        let bytes = include_bytes!(
7439            "../../../baedeker-testdata/spec/invalid-validate/typed-if-to-return-call-indirect-ref-param-wrong-concrete-type.wasm",
7440        );
7441        let module = Module::decode(bytes).unwrap();
7442        let err = module.validate().unwrap_err();
7443        assert_eq!(err.offset, ByteOffset(89));
7444        assert!(matches!(
7445            err.kind,
7446            ValidationErrorKind::TypeMismatch { op, expected, found }
7447                if op == "stack"
7448                    && expected == ValType::Ref(RefType::Typed {
7449                        nullable: true,
7450                        heap: crate::types::HeapType::Type(TypeIdx(1)),
7451                    })
7452                    && found == ValType::Ref(RefType::Typed {
7453                        nullable: true,
7454                        heap: crate::types::HeapType::Type(TypeIdx(0)),
7455                    })
7456        ));
7457    }
7458
7459    #[test]
7460    fn reject_typed_table_init_to_return_call_indirect_result_nullability_mismatch() {
7461        let bytes = include_bytes!(
7462            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-to-return-call-indirect-result-nullability-mismatch.wasm",
7463        );
7464        let module = Module::decode(bytes).unwrap();
7465        let err = module.validate().unwrap_err();
7466        assert_eq!(err.offset, ByteOffset(81));
7467        assert!(matches!(
7468            err.kind,
7469            ValidationErrorKind::ResultTypeMismatch { expected, found }
7470                if expected == vec![ValType::Ref(RefType::Typed {
7471                    nullable: false,
7472                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7473                })] && found == vec![ValType::Ref(RefType::Typed {
7474                    nullable: true,
7475                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7476                })]
7477        ));
7478    }
7479
7480    #[test]
7481    fn validate_typed_table_init_shared_source_to_return_call_indirect_result_nullable_official_case()
7482     {
7483        let bytes = include_bytes!(
7484            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-return-call-indirect-result-nullable.wasm",
7485        );
7486        let module = Module::decode(bytes).unwrap();
7487        module.validate().unwrap();
7488    }
7489
7490    #[test]
7491    fn reject_typed_table_init_shared_source_to_return_call_indirect_result_nullability_mismatch() {
7492        let bytes = include_bytes!(
7493            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-return-call-indirect-result-nullability-mismatch.wasm",
7494        );
7495        let module = Module::decode(bytes).unwrap();
7496        let err = module.validate().unwrap_err();
7497        assert_eq!(err.offset, ByteOffset(130));
7498        assert!(matches!(
7499            err.kind,
7500            ValidationErrorKind::ResultTypeMismatch { expected, found }
7501                if expected == vec![ValType::Ref(RefType::Typed {
7502                    nullable: false,
7503                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7504                })] && found == vec![ValType::Ref(RefType::Typed {
7505                    nullable: true,
7506                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7507                })]
7508        ));
7509    }
7510
7511    #[test]
7512    fn validate_call_ref() {
7513        let bytes = [
7514            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F,
7515            0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00,
7516            0x0A, 0x0F, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x08, 0x00, 0x41, 0x07, 0xD2, 0x00,
7517            0x14, 0x00, 0x0B,
7518        ];
7519        let module = Module::decode(&bytes).unwrap();
7520        module.validate().unwrap();
7521    }
7522
7523    #[test]
7524    fn validate_call_ref_with_equivalent_concrete_type() {
7525        let bytes = [
7526            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7527            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x05,
7528            0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x0F, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x08,
7529            0x00, 0x20, 0x00, 0xD2, 0x00, 0x14, 0x01, 0x0B,
7530        ];
7531        let module = Module::decode(&bytes).unwrap();
7532        module.validate().unwrap();
7533    }
7534
7535    #[test]
7536    fn validate_typed_block_result_to_call_ref_with_equivalent_signature() {
7537        let bytes = include_bytes!(
7538            "../../../baedeker-testdata/spec/valid/typed-block-to-call-ref-equivalent-signature.wasm",
7539        );
7540        let module = Module::decode(bytes).unwrap();
7541        module.validate().unwrap();
7542    }
7543
7544    #[test]
7545    fn validate_typed_call_ref_if_nullable_official_case() {
7546        let bytes = include_bytes!(
7547            "../../../baedeker-testdata/spec/valid/typed-call-ref-if-nullable.wasm",
7548        );
7549        let module = Module::decode(bytes).unwrap();
7550        module.validate().unwrap();
7551    }
7552
7553    #[test]
7554    fn reject_typed_call_ref_if_abstract_nullability_mismatch() {
7555        let bytes = include_bytes!(
7556            "../../../baedeker-testdata/spec/invalid-validate/typed-call-ref-if-abstract-nullability-mismatch.wasm",
7557        );
7558        let module = Module::decode(bytes).unwrap();
7559        let err = module.validate().unwrap_err();
7560        assert_eq!(err.offset, ByteOffset(56));
7561        assert!(matches!(
7562            err.kind,
7563            ValidationErrorKind::TypeMismatch { op, expected, found }
7564                if op == "call_ref"
7565                    && expected == ValType::Ref(RefType::Typed {
7566                        nullable: true,
7567                        heap: crate::types::HeapType::Type(TypeIdx(0)),
7568                    })
7569                    && found == ValType::Ref(RefType::FuncRef)
7570        ));
7571    }
7572
7573    #[test]
7574    fn validate_call_ref_run_nested_official_case() {
7575        let bytes =
7576            include_bytes!("../../../baedeker-testdata/spec/valid/call-ref-run-nested.wasm");
7577        let module = Module::decode(bytes).unwrap();
7578        module.validate().unwrap();
7579    }
7580
7581    #[test]
7582    fn validate_call_ref_unreachable_ref_func_official_case() {
7583        let bytes = include_bytes!(
7584            "../../../baedeker-testdata/spec/valid/call-ref-unreachable-ref-func.wasm",
7585        );
7586        let module = Module::decode(bytes).unwrap();
7587        module.validate().unwrap();
7588    }
7589
7590    #[test]
7591    fn validate_call_ref_unreachable_call_drop_official_case() {
7592        let bytes = include_bytes!(
7593            "../../../baedeker-testdata/spec/valid/call-ref-unreachable-call-drop.wasm",
7594        );
7595        let module = Module::decode(bytes).unwrap();
7596        module.validate().unwrap();
7597    }
7598
7599    #[test]
7600    fn reject_typed_call_ref_function_result_wrong_concrete_type() {
7601        let bytes = include_bytes!(
7602            "../../../baedeker-testdata/spec/invalid-validate/typed-call-ref-function-result-wrong-concrete-type.wasm",
7603        );
7604        let module = Module::decode(bytes).unwrap();
7605        let err = module.validate().unwrap_err();
7606        assert_eq!(err.offset, ByteOffset(57));
7607        assert!(matches!(
7608            err.kind,
7609            ValidationErrorKind::FunctionResultTypeMismatch {
7610                expected,
7611                found,
7612                ..
7613            } if expected == vec![ValType::Ref(RefType::Typed {
7614                    nullable: true,
7615                    heap: crate::types::HeapType::Type(TypeIdx(1)),
7616                })] && found == vec![ValType::Ref(RefType::Typed {
7617                    nullable: true,
7618                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7619                })]
7620        ));
7621    }
7622
7623    #[test]
7624    fn reject_typed_call_ref_block_result_wrong_concrete_type() {
7625        let bytes = include_bytes!(
7626            "../../../baedeker-testdata/spec/invalid-validate/typed-call-ref-block-result-wrong-concrete-type.wasm",
7627        );
7628        let module = Module::decode(bytes).unwrap();
7629        let err = module.validate().unwrap_err();
7630        assert_eq!(err.offset, ByteOffset(60));
7631        assert!(matches!(
7632            err.kind,
7633            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
7634                if expected == vec![ValType::Ref(RefType::Typed {
7635                    nullable: true,
7636                    heap: crate::types::HeapType::Type(TypeIdx(1)),
7637                })] && found == vec![ValType::Ref(RefType::Typed {
7638                    nullable: true,
7639                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7640                })]
7641        ));
7642    }
7643
7644    #[test]
7645    fn reject_typed_call_ref_if_result_wrong_concrete_type() {
7646        let bytes = include_bytes!(
7647            "../../../baedeker-testdata/spec/invalid-validate/typed-call-ref-if-result-wrong-concrete-type.wasm",
7648        );
7649        let module = Module::decode(bytes).unwrap();
7650        let err = module.validate().unwrap_err();
7651        assert_eq!(err.offset, ByteOffset(63));
7652        assert!(matches!(
7653            err.kind,
7654            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
7655                if expected == vec![ValType::Ref(RefType::Typed {
7656                    nullable: true,
7657                    heap: crate::types::HeapType::Type(TypeIdx(1)),
7658                })] && found == vec![ValType::Ref(RefType::Typed {
7659                    nullable: true,
7660                    heap: crate::types::HeapType::Type(TypeIdx(0)),
7661                })]
7662        ));
7663    }
7664
7665    #[test]
7666    fn reject_typed_block_result_to_call_ref_with_wrong_concrete_type() {
7667        let bytes = include_bytes!(
7668            "../../../baedeker-testdata/spec/invalid-validate/typed-block-to-call-ref-wrong-concrete-type.wasm",
7669        );
7670        let module = Module::decode(bytes).unwrap();
7671        let err = module.validate().unwrap_err();
7672        assert_eq!(err.offset, ByteOffset(51));
7673        assert!(matches!(
7674            err.kind,
7675            ValidationErrorKind::TypeMismatch { op, expected, found }
7676                if op == "call_ref"
7677                    && expected == ValType::Ref(RefType::Typed {
7678                        nullable: true,
7679                        heap: crate::types::HeapType::Type(TypeIdx(1)),
7680                    })
7681                    && found == ValType::Ref(RefType::Typed {
7682                        nullable: true,
7683                        heap: crate::types::HeapType::Type(TypeIdx(0)),
7684                    })
7685        ));
7686    }
7687
7688    #[test]
7689    fn validate_typed_ref_global_init_from_ref_func() {
7690        let bytes = [
7691            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F,
7692            0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x06, 0x07, 0x01, 0x63, 0x00, 0x00, 0xD2, 0x00,
7693            0x0B, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x20,
7694            0x00, 0x0B,
7695        ];
7696        let module = Module::decode(&bytes).unwrap();
7697        module.validate().unwrap();
7698    }
7699
7700    #[test]
7701    fn validate_typed_ref_global_init_from_equivalent_ref_func() {
7702        let bytes = [
7703            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7704            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x06, 0x07, 0x01,
7705            0x63, 0x01, 0x00, 0xD2, 0x00, 0x0B, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A,
7706            0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0B,
7707        ];
7708        let module = Module::decode(&bytes).unwrap();
7709        module.validate().unwrap();
7710    }
7711
7712    #[test]
7713    fn validate_typed_ref_global_init_from_imported_typed_global_with_equivalent_signature() {
7714        let bytes = [
7715            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7716            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x02, 0x0B, 0x01, 0x03, 0x65, 0x6E, 0x76,
7717            0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x06, 0x07, 0x01, 0x63, 0x01, 0x00, 0x23, 0x00,
7718            0x0B,
7719        ];
7720        let module = Module::decode(&bytes).unwrap();
7721        module.validate().unwrap();
7722    }
7723
7724    #[test]
7725    fn validate_typed_ref_global_init_from_defined_typed_global_with_equivalent_signature() {
7726        let bytes = [
7727            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7728            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x06, 0x0D, 0x02,
7729            0x63, 0x00, 0x00, 0xD2, 0x00, 0x0B, 0x63, 0x01, 0x00, 0x23, 0x00, 0x0B, 0x07, 0x05,
7730            0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0B,
7731        ];
7732        let module = Module::decode(&bytes).unwrap();
7733        module.validate().unwrap();
7734    }
7735
7736    #[test]
7737    fn validate_ref_func_to_imported_mut_typed_global_with_equivalent_signature() {
7738        let bytes = [
7739            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x03, 0x60, 0x01, 0x7F,
7740            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x00, 0x02, 0x0B, 0x01, 0x03,
7741            0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x63, 0x01, 0x01, 0x03, 0x03, 0x02, 0x00, 0x02,
7742            0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x0D, 0x02, 0x04, 0x00, 0x20, 0x00,
7743            0x0B, 0x06, 0x00, 0xD2, 0x00, 0x24, 0x00, 0x0B,
7744        ];
7745        let module = Module::decode(&bytes).unwrap();
7746        module.validate().unwrap();
7747    }
7748
7749    #[test]
7750    fn validate_typed_table_get_to_defined_mut_global_with_equivalent_signature() {
7751        let bytes = include_bytes!(
7752            "../../../baedeker-testdata/spec/valid/typed-table-to-defined-mut-global-equivalent-signature.wasm",
7753        );
7754        let module = Module::decode(bytes).unwrap();
7755        module.validate().unwrap();
7756    }
7757
7758    #[test]
7759    fn validate_imported_typed_table_get_to_defined_mut_global_with_equivalent_signature() {
7760        let bytes = include_bytes!(
7761            "../../../baedeker-testdata/spec/valid/imported-typed-table-to-defined-mut-global-equivalent-signature.wasm",
7762        );
7763        let module = Module::decode(bytes).unwrap();
7764        module.validate().unwrap();
7765    }
7766
7767    #[test]
7768    fn validate_typed_local_set_if_nullable_official_case() {
7769        let bytes = include_bytes!(
7770            "../../../baedeker-testdata/spec/valid/typed-local-set-if-nullable.wasm",
7771        );
7772        let module = Module::decode(bytes).unwrap();
7773        module.validate().unwrap();
7774    }
7775
7776    #[test]
7777    fn validate_typed_local_if_nullable_to_call_ref_official_case() {
7778        let bytes = include_bytes!(
7779            "../../../baedeker-testdata/spec/valid/typed-local-if-nullable-to-call-ref.wasm",
7780        );
7781        let module = Module::decode(bytes).unwrap();
7782        module.validate().unwrap();
7783    }
7784
7785    #[test]
7786    fn validate_typed_global_set_if_nullable_official_case() {
7787        let bytes = include_bytes!(
7788            "../../../baedeker-testdata/spec/valid/typed-global-set-if-nullable.wasm",
7789        );
7790        let module = Module::decode(bytes).unwrap();
7791        module.validate().unwrap();
7792    }
7793
7794    #[test]
7795    fn validate_typed_table_init_shared_source_to_global_set_nullable_official_case() {
7796        let bytes = include_bytes!(
7797            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-global-set-nullable.wasm",
7798        );
7799        let module = Module::decode(bytes).unwrap();
7800        module.validate().unwrap();
7801    }
7802
7803    #[test]
7804    fn validate_typed_global_if_nullable_to_call_ref_official_case() {
7805        let bytes = include_bytes!(
7806            "../../../baedeker-testdata/spec/valid/typed-global-if-nullable-to-call-ref.wasm",
7807        );
7808        let module = Module::decode(bytes).unwrap();
7809        module.validate().unwrap();
7810    }
7811
7812    #[test]
7813    fn validate_typed_table_set_if_nullable_official_case() {
7814        let bytes = include_bytes!(
7815            "../../../baedeker-testdata/spec/valid/typed-table-set-if-nullable.wasm",
7816        );
7817        let module = Module::decode(bytes).unwrap();
7818        module.validate().unwrap();
7819    }
7820
7821    #[test]
7822    fn validate_typed_table_if_nullable_to_call_ref_official_case() {
7823        let bytes = include_bytes!(
7824            "../../../baedeker-testdata/spec/valid/typed-table-if-nullable-to-call-ref.wasm",
7825        );
7826        let module = Module::decode(bytes).unwrap();
7827        module.validate().unwrap();
7828    }
7829
7830    #[test]
7831    fn validate_typed_passive_element_nullable_from_nonnull_official_case() {
7832        let bytes = include_bytes!(
7833            "../../../baedeker-testdata/spec/valid/typed-passive-element-nullable-from-nonnull.wasm",
7834        );
7835        let module = Module::decode(bytes).unwrap();
7836        module.validate().unwrap();
7837    }
7838
7839    #[test]
7840    fn validate_typed_defined_nonnull_global_passive_element_nullable_official_case() {
7841        let bytes = include_bytes!(
7842            "../../../baedeker-testdata/spec/valid/typed-defined-nonnull-global-passive-element-nullable.wasm",
7843        );
7844        let module = Module::decode(bytes).unwrap();
7845        module.validate().unwrap();
7846    }
7847
7848    #[test]
7849    fn validate_typed_table_init_nullable_to_call_ref_official_case() {
7850        let bytes = include_bytes!(
7851            "../../../baedeker-testdata/spec/valid/typed-table-init-nullable-to-call-ref.wasm",
7852        );
7853        let module = Module::decode(bytes).unwrap();
7854        module.validate().unwrap();
7855    }
7856
7857    #[test]
7858    fn validate_typed_defined_global_passive_element_table_init_nullable_to_call_ref_official_case()
7859    {
7860        let bytes = include_bytes!(
7861            "../../../baedeker-testdata/spec/valid/typed-defined-global-passive-element-table-init-nullable-to-call-ref.wasm",
7862        );
7863        let module = Module::decode(bytes).unwrap();
7864        module.validate().unwrap();
7865    }
7866
7867    #[test]
7868    fn validate_typed_imported_global_passive_element_table_init_nullable_to_call_ref_official_case()
7869     {
7870        let bytes = include_bytes!(
7871            "../../../baedeker-testdata/spec/valid/typed-imported-global-passive-element-table-init-nullable-to-call-ref.wasm",
7872        );
7873        let module = Module::decode(bytes).unwrap();
7874        module.validate().unwrap();
7875    }
7876
7877    #[test]
7878    fn validate_typed_imported_nonnull_global_passive_element_table_init_nullable_to_call_ref_official_case()
7879     {
7880        let bytes = include_bytes!(
7881            "../../../baedeker-testdata/spec/valid/typed-imported-nonnull-global-passive-element-table-init-nullable-to-call-ref.wasm",
7882        );
7883        let module = Module::decode(bytes).unwrap();
7884        module.validate().unwrap();
7885    }
7886
7887    #[test]
7888    fn validate_typed_table_set_get() {
7889        let bytes = [
7890            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7891            0x01, 0x7F, 0x60, 0x00, 0x01, 0x63, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x04, 0x05,
7892            0x01, 0x63, 0x00, 0x00, 0x01, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x13,
7893            0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00, 0x41, 0x00, 0xD2, 0x00, 0x26, 0x00,
7894            0x41, 0x00, 0x25, 0x00, 0x0B,
7895        ];
7896        let module = Module::decode(&bytes).unwrap();
7897        module.validate().unwrap();
7898    }
7899
7900    #[test]
7901    fn validate_typed_table_set_get_with_equivalent_concrete_type() {
7902        let bytes = [
7903            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F,
7904            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
7905            0x02, 0x00, 0x02, 0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x01, 0x07, 0x05, 0x01, 0x01,
7906            0x66, 0x00, 0x00, 0x0A, 0x13, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00, 0x41,
7907            0x00, 0xD2, 0x00, 0x26, 0x00, 0x41, 0x00, 0x25, 0x00, 0x0B,
7908        ];
7909        let module = Module::decode(&bytes).unwrap();
7910        module.validate().unwrap();
7911    }
7912
7913    #[test]
7914    fn validate_imported_typed_global_to_defined_table_with_equivalent_signature() {
7915        let bytes = [
7916            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F,
7917            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x01, 0x63, 0x01, 0x02, 0x0B,
7918            0x01, 0x03, 0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x03, 0x02, 0x01,
7919            0x02, 0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x01, 0x0A, 0x0E, 0x01, 0x0C, 0x00, 0x41,
7920            0x00, 0x23, 0x00, 0x26, 0x00, 0x41, 0x00, 0x25, 0x00, 0x0B,
7921        ];
7922        let module = Module::decode(&bytes).unwrap();
7923        module.validate().unwrap();
7924    }
7925
7926    #[test]
7927    fn validate_imported_typed_global_to_imported_table_with_equivalent_signature() {
7928        let bytes = [
7929            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F,
7930            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x01, 0x63, 0x01, 0x02, 0x16,
7931            0x02, 0x03, 0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E,
7932            0x76, 0x01, 0x74, 0x01, 0x63, 0x01, 0x00, 0x01, 0x03, 0x02, 0x01, 0x02, 0x0A, 0x0E,
7933            0x01, 0x0C, 0x00, 0x41, 0x00, 0x23, 0x00, 0x26, 0x00, 0x41, 0x00, 0x25, 0x00, 0x0B,
7934        ];
7935        let module = Module::decode(&bytes).unwrap();
7936        module.validate().unwrap();
7937    }
7938
7939    #[test]
7940    fn validate_typed_element_expr_from_imported_typed_global_with_equivalent_signature() {
7941        let bytes = [
7942            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7943            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x02, 0x0B, 0x01, 0x03, 0x65, 0x6E, 0x76,
7944            0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x01, 0x09,
7945            0x0C, 0x01, 0x06, 0x00, 0x41, 0x00, 0x0B, 0x63, 0x01, 0x01, 0x23, 0x00, 0x0B,
7946        ];
7947        let module = Module::decode(&bytes).unwrap();
7948        module.validate().unwrap();
7949    }
7950
7951    #[test]
7952    fn validate_typed_passive_element_from_equivalent_ref_func() {
7953        let bytes = [
7954            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
7955            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01,
7956            0x01, 0x66, 0x00, 0x00, 0x09, 0x08, 0x01, 0x05, 0x63, 0x01, 0x01, 0xD2, 0x00, 0x0B,
7957            0x0A, 0x06, 0x01, 0x04, 0x00, 0x20, 0x00, 0x0B,
7958        ];
7959        let module = Module::decode(&bytes).unwrap();
7960        module.validate().unwrap();
7961    }
7962
7963    #[test]
7964    fn validate_typed_passive_element_from_defined_typed_global_with_equivalent_signature() {
7965        let bytes = include_bytes!(
7966            "../../../baedeker-testdata/spec/valid/defined-typed-global-passive-element-equivalent-signature.wasm",
7967        );
7968        let module = Module::decode(bytes).unwrap();
7969        module.validate().unwrap();
7970    }
7971
7972    #[test]
7973    fn validate_typed_passive_element_from_imported_typed_global_with_equivalent_signature() {
7974        let bytes = include_bytes!(
7975            "../../../baedeker-testdata/spec/valid/imported-typed-global-passive-element-equivalent-signature.wasm",
7976        );
7977        let module = Module::decode(bytes).unwrap();
7978        module.validate().unwrap();
7979    }
7980
7981    #[test]
7982    fn validate_typed_table_init_from_defined_typed_global_passive_element_with_equivalent_signature()
7983     {
7984        let bytes = include_bytes!(
7985            "../../../baedeker-testdata/spec/valid/defined-typed-global-passive-element-table-init-equivalent-signature.wasm",
7986        );
7987        let module = Module::decode(bytes).unwrap();
7988        module.validate().unwrap();
7989    }
7990
7991    #[test]
7992    fn validate_typed_table_init_from_imported_typed_global_passive_element_with_equivalent_signature()
7993     {
7994        let bytes = include_bytes!(
7995            "../../../baedeker-testdata/spec/valid/imported-typed-global-passive-element-table-init-equivalent-signature.wasm",
7996        );
7997        let module = Module::decode(bytes).unwrap();
7998        module.validate().unwrap();
7999    }
8000
8001    #[test]
8002    fn validate_table_init_with_equivalent_typed_element_segment() {
8003        let bytes = [
8004            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x03, 0x60, 0x01, 0x7F,
8005            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00,
8006            0x02, 0x04, 0x05, 0x01, 0x63, 0x00, 0x00, 0x04, 0x07, 0x0C, 0x02, 0x01, 0x66, 0x00,
8007            0x00, 0x04, 0x69, 0x6E, 0x69, 0x74, 0x00, 0x01, 0x09, 0x08, 0x01, 0x05, 0x63, 0x01,
8008            0x01, 0xD2, 0x00, 0x0B, 0x0A, 0x13, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00,
8009            0x41, 0x00, 0x41, 0x00, 0x41, 0x01, 0xFC, 0x0C, 0x00, 0x00, 0x0B,
8010        ];
8011        let module = Module::decode(&bytes).unwrap();
8012        module.validate().unwrap();
8013    }
8014
8015    #[test]
8016    fn validate_typed_block_result_with_equivalent_signature() {
8017        let bytes = [
8018            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F,
8019            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8020            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x13, 0x02, 0x04,
8021            0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00, 0x02, 0x63, 0x01, 0xD2, 0x00, 0x0C, 0x00, 0xD0,
8022            0x01, 0x0B, 0x0B,
8023        ];
8024        let module = Module::decode(&bytes).unwrap();
8025        module.validate().unwrap();
8026    }
8027
8028    #[test]
8029    fn validate_typed_block_result_nullable_from_nonnull_official_case() {
8030        let bytes = include_bytes!(
8031            "../../../baedeker-testdata/spec/valid/typed-block-result-nullable-from-nonnull.wasm",
8032        );
8033        let module = Module::decode(bytes).unwrap();
8034        module.validate().unwrap();
8035    }
8036
8037    #[test]
8038    fn reject_typed_block_result_nullability_mismatch() {
8039        let bytes = include_bytes!(
8040            "../../../baedeker-testdata/spec/invalid-validate/typed-block-result-nullability-mismatch.wasm",
8041        );
8042        let module = Module::decode(bytes).unwrap();
8043        let err = module.validate().unwrap_err();
8044        assert_eq!(err.offset, ByteOffset(35));
8045        assert!(matches!(
8046            err.kind,
8047            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8048                if expected == vec![ValType::Ref(RefType::Typed {
8049                    nullable: false,
8050                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8051                })] && found == vec![ValType::Ref(RefType::Typed {
8052                    nullable: true,
8053                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8054                })]
8055        ));
8056    }
8057
8058    #[test]
8059    fn validate_typed_block_result_feeds_loop_param_with_equivalent_signature() {
8060        let bytes = [
8061            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7f,
8062            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x60, 0x01,
8063            0x63, 0x01, 0x01, 0x63, 0x01, 0x03, 0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01,
8064            0x66, 0x00, 0x00, 0x0a, 0x12, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x0b, 0x00, 0x02,
8065            0x63, 0x00, 0xd2, 0x00, 0x0b, 0x03, 0x03, 0x0b, 0x0b,
8066        ];
8067        let module = Module::decode(&bytes).unwrap();
8068        module.validate().unwrap();
8069    }
8070
8071    #[test]
8072    fn reject_typed_block_result_feeds_loop_param_with_wrong_concrete_type() {
8073        let bytes = [
8074            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x17, 0x04, 0x60, 0x01, 0x7e,
8075            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x60, 0x01,
8076            0x63, 0x01, 0x01, 0x63, 0x01, 0x03, 0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01,
8077            0x66, 0x00, 0x00, 0x0a, 0x12, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0b, 0x0b, 0x00, 0x02,
8078            0x63, 0x00, 0xd2, 0x00, 0x0b, 0x03, 0x03, 0x0b, 0x0b,
8079        ];
8080        let module = Module::decode(&bytes).unwrap();
8081        let err = module.validate().unwrap_err();
8082        assert_eq!(err.offset, ByteOffset(61));
8083        assert!(matches!(
8084            err.kind,
8085            ValidationErrorKind::TypeMismatch { op, expected, found }
8086                if op == "stack"
8087                    && expected == ValType::Ref(RefType::Typed {
8088                        nullable: true,
8089                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8090                    })
8091                    && found == ValType::Ref(RefType::Typed {
8092                        nullable: true,
8093                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8094                    })
8095        ));
8096    }
8097
8098    #[test]
8099    fn validate_typed_loop_result_feeds_block_result_with_equivalent_signature() {
8100        let bytes = [
8101            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
8102            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8103            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x13, 0x02, 0x04,
8104            0x00, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x02, 0x63, 0x01, 0x03, 0x63, 0x00, 0xd2, 0x00,
8105            0x0b, 0x0b, 0x0b,
8106        ];
8107        let module = Module::decode(&bytes).unwrap();
8108        module.validate().unwrap();
8109    }
8110
8111    #[test]
8112    fn reject_typed_loop_result_feeds_block_result_with_wrong_concrete_type() {
8113        let bytes = [
8114            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7e,
8115            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8116            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x13, 0x02, 0x04,
8117            0x00, 0x20, 0x00, 0x0b, 0x0c, 0x00, 0x02, 0x63, 0x01, 0x03, 0x63, 0x00, 0xd2, 0x00,
8118            0x0b, 0x0b, 0x0b,
8119        ];
8120        let module = Module::decode(&bytes).unwrap();
8121        let err = module.validate().unwrap_err();
8122        assert_eq!(err.offset, ByteOffset(57));
8123        assert!(matches!(
8124            err.kind,
8125            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8126                if expected == vec![ValType::Ref(RefType::Typed {
8127                    nullable: true,
8128                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8129                })] && found == vec![ValType::Ref(RefType::Typed {
8130                    nullable: true,
8131                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8132                })]
8133        ));
8134    }
8135
8136    #[test]
8137    fn validate_typed_if_result_with_equivalent_signature() {
8138        let bytes = [
8139            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7F,
8140            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x63, 0x01, 0x03,
8141            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x14, 0x02,
8142            0x04, 0x00, 0x20, 0x00, 0x0B, 0x0D, 0x00, 0x20, 0x00, 0x04, 0x63, 0x01, 0xD2, 0x00,
8143            0x05, 0xD0, 0x01, 0x0B, 0x0B,
8144        ];
8145        let module = Module::decode(&bytes).unwrap();
8146        module.validate().unwrap();
8147    }
8148
8149    #[test]
8150    fn validate_typed_if_result_nullable_from_join_official_case() {
8151        let bytes = include_bytes!(
8152            "../../../baedeker-testdata/spec/valid/typed-if-result-nullable-from-join.wasm",
8153        );
8154        let module = Module::decode(bytes).unwrap();
8155        module.validate().unwrap();
8156    }
8157
8158    #[test]
8159    fn reject_typed_if_result_nullability_mismatch() {
8160        let bytes = include_bytes!(
8161            "../../../baedeker-testdata/spec/invalid-validate/typed-if-result-nullability-mismatch.wasm",
8162        );
8163        let module = Module::decode(bytes).unwrap();
8164        let err = module.validate().unwrap_err();
8165        assert_eq!(err.offset, ByteOffset(54));
8166        assert!(matches!(
8167            err.kind,
8168            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8169                if expected == vec![ValType::Ref(RefType::Typed {
8170                    nullable: false,
8171                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8172                })] && found == vec![ValType::Ref(RefType::Typed {
8173                    nullable: true,
8174                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8175                })]
8176        ));
8177    }
8178
8179    #[test]
8180    fn validate_typed_if_with_return_in_then_and_equivalent_signature() {
8181        let bytes = [
8182            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7f,
8183            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
8184            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x15, 0x02,
8185            0x04, 0x00, 0x20, 0x00, 0x0b, 0x0e, 0x00, 0x20, 0x00, 0x04, 0x63, 0x01, 0xd2, 0x00,
8186            0x0f, 0x05, 0xd0, 0x01, 0x0b, 0x0b,
8187        ];
8188        let module = Module::decode(&bytes).unwrap();
8189        module.validate().unwrap();
8190    }
8191
8192    #[test]
8193    fn reject_typed_if_with_return_in_then_and_wrong_concrete_type() {
8194        let bytes = [
8195            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7e,
8196            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x63, 0x01, 0x03,
8197            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x15, 0x02,
8198            0x04, 0x00, 0x20, 0x00, 0x0b, 0x0e, 0x00, 0x20, 0x00, 0x04, 0x63, 0x01, 0xd2, 0x00,
8199            0x0f, 0x05, 0xd0, 0x01, 0x0b, 0x0b,
8200        ];
8201        let module = Module::decode(&bytes).unwrap();
8202        let err = module.validate().unwrap_err();
8203        assert_eq!(err.offset, ByteOffset(56));
8204        assert!(matches!(
8205            err.kind,
8206            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8207                if expected == vec![ValType::Ref(RefType::Typed {
8208                    nullable: true,
8209                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8210                })] && found == vec![ValType::Ref(RefType::Typed {
8211                    nullable: false,
8212                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8213                })]
8214        ));
8215    }
8216
8217    #[test]
8218    fn validate_typed_return_with_equivalent_signature() {
8219        let bytes = [
8220            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
8221            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8222            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x0e, 0x02, 0x04,
8223            0x00, 0x20, 0x00, 0x0b, 0x07, 0x00, 0xd2, 0x00, 0x0f, 0xd0, 0x01, 0x0b,
8224        ];
8225        let module = Module::decode(&bytes).unwrap();
8226        module.validate().unwrap();
8227    }
8228
8229    #[test]
8230    fn reject_typed_return_with_wrong_concrete_type() {
8231        let bytes = [
8232            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7e,
8233            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8234            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x0e, 0x02, 0x04,
8235            0x00, 0x20, 0x00, 0x0b, 0x07, 0x00, 0xd2, 0x00, 0x0f, 0xd0, 0x01, 0x0b,
8236        ];
8237        let module = Module::decode(&bytes).unwrap();
8238        let err = module.validate().unwrap_err();
8239        assert_eq!(err.offset, ByteOffset(50));
8240        assert!(matches!(
8241            err.kind,
8242            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8243                if expected == vec![ValType::Ref(RefType::Typed {
8244                    nullable: true,
8245                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8246                })] && found == vec![ValType::Ref(RefType::Typed {
8247                    nullable: false,
8248                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8249                })]
8250        ));
8251    }
8252
8253    #[test]
8254    fn validate_typed_loop_result_with_equivalent_signature() {
8255        let bytes = [
8256            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7f,
8257            0x01, 0x7f, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8258            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x0f, 0x02, 0x04,
8259            0x00, 0x20, 0x00, 0x0b, 0x08, 0x00, 0x03, 0x63, 0x01, 0xd2, 0x00, 0x0b, 0x0b,
8260        ];
8261        let module = Module::decode(&bytes).unwrap();
8262        module.validate().unwrap();
8263    }
8264
8265    #[test]
8266    fn validate_typed_loop_result_nullable_from_nonnull_official_case() {
8267        let bytes = include_bytes!(
8268            "../../../baedeker-testdata/spec/valid/typed-loop-result-nullable-from-nonnull.wasm",
8269        );
8270        let module = Module::decode(bytes).unwrap();
8271        module.validate().unwrap();
8272    }
8273
8274    #[test]
8275    fn reject_typed_loop_result_nullability_mismatch() {
8276        let bytes = include_bytes!(
8277            "../../../baedeker-testdata/spec/invalid-validate/typed-loop-result-nullability-mismatch.wasm",
8278        );
8279        let module = Module::decode(bytes).unwrap();
8280        let err = module.validate().unwrap_err();
8281        assert_eq!(err.offset, ByteOffset(35));
8282        assert!(matches!(
8283            err.kind,
8284            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8285                if expected == vec![ValType::Ref(RefType::Typed {
8286                    nullable: false,
8287                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8288                })] && found == vec![ValType::Ref(RefType::Typed {
8289                    nullable: true,
8290                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8291                })]
8292        ));
8293    }
8294
8295    #[test]
8296    fn reject_typed_loop_result_with_wrong_concrete_type() {
8297        let bytes = [
8298            0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7e,
8299            0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x63, 0x01, 0x03, 0x03,
8300            0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0a, 0x0f, 0x02, 0x04,
8301            0x00, 0x20, 0x00, 0x0b, 0x08, 0x00, 0x03, 0x63, 0x01, 0xd2, 0x00, 0x0b, 0x0b,
8302        ];
8303        let module = Module::decode(&bytes).unwrap();
8304        let err = module.validate().unwrap_err();
8305        assert_eq!(err.offset, ByteOffset(53));
8306        assert!(matches!(
8307            err.kind,
8308            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8309                if expected == vec![ValType::Ref(RefType::Typed {
8310                    nullable: true,
8311                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8312                })] && found == vec![ValType::Ref(RefType::Typed {
8313                    nullable: false,
8314                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8315                })]
8316        ));
8317    }
8318
8319    #[test]
8320    fn validate_typed_return_if_nullable_official_case() {
8321        let bytes =
8322            include_bytes!("../../../baedeker-testdata/spec/valid/typed-return-if-nullable.wasm",);
8323        let module = Module::decode(bytes).unwrap();
8324        module.validate().unwrap();
8325    }
8326
8327    #[test]
8328    fn reject_typed_return_if_nullability_mismatch() {
8329        let bytes = include_bytes!(
8330            "../../../baedeker-testdata/spec/invalid-validate/typed-return-if-nullability-mismatch.wasm",
8331        );
8332        let module = Module::decode(bytes).unwrap();
8333        let err = module.validate().unwrap_err();
8334        assert_eq!(err.offset, ByteOffset(55));
8335        assert!(matches!(
8336            err.kind,
8337            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8338                if expected == vec![ValType::Ref(RefType::Typed {
8339                    nullable: false,
8340                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8341                })] && found == vec![ValType::Ref(RefType::Typed {
8342                    nullable: true,
8343                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8344                })]
8345        ));
8346    }
8347
8348    #[test]
8349    fn validate_typed_table_init_shared_source_to_return_nullable_official_case() {
8350        let bytes = include_bytes!(
8351            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-return-nullable.wasm",
8352        );
8353        let module = Module::decode(bytes).unwrap();
8354        module.validate().unwrap();
8355    }
8356
8357    #[test]
8358    fn reject_typed_table_init_shared_source_to_return_nullability_mismatch() {
8359        let bytes = include_bytes!(
8360            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-return-nullability-mismatch.wasm",
8361        );
8362        let module = Module::decode(bytes).unwrap();
8363        let err = module.validate().unwrap_err();
8364        assert_eq!(err.offset, ByteOffset(94));
8365        assert!(matches!(
8366            err.kind,
8367            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
8368                if expected == vec![ValType::Ref(RefType::Typed {
8369                    nullable: false,
8370                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8371                })] && found == vec![ValType::Ref(RefType::Typed {
8372                    nullable: true,
8373                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8374                })]
8375        ));
8376    }
8377
8378    #[test]
8379    fn validate_return_call_ref() {
8380        let bytes = [
8381            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60, 0x01, 0x7F,
8382            0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00,
8383            0x0A, 0x0F, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x08, 0x00, 0x20, 0x00, 0xD2, 0x00,
8384            0x15, 0x00, 0x0B,
8385        ];
8386        let module = Module::decode(&bytes).unwrap();
8387        module.validate().unwrap();
8388    }
8389
8390    #[test]
8391    fn validate_return_call_ref_with_equivalent_concrete_type() {
8392        let bytes = [
8393            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
8394            0x01, 0x7F, 0x60, 0x01, 0x7F, 0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x05,
8395            0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x0F, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x08,
8396            0x00, 0x20, 0x00, 0xD2, 0x00, 0x15, 0x01, 0x0B,
8397        ];
8398        let module = Module::decode(&bytes).unwrap();
8399        module.validate().unwrap();
8400    }
8401
8402    #[test]
8403    fn validate_typed_if_result_to_return_call_ref_with_equivalent_signature() {
8404        let bytes = include_bytes!(
8405            "../../../baedeker-testdata/spec/valid/typed-if-to-return-call-ref-equivalent-signature.wasm",
8406        );
8407        let module = Module::decode(bytes).unwrap();
8408        module.validate().unwrap();
8409    }
8410
8411    #[test]
8412    fn validate_return_call_ref_count_official_case() {
8413        let bytes =
8414            include_bytes!("../../../baedeker-testdata/spec/valid/return-call-ref-count.wasm");
8415        let module = Module::decode(bytes).unwrap();
8416        module.validate().unwrap();
8417    }
8418
8419    #[test]
8420    fn validate_typed_table_init_to_return_call_ref_result_nullable_official_case() {
8421        let bytes = include_bytes!(
8422            "../../../baedeker-testdata/spec/valid/typed-table-init-to-return-call-ref-result-nullable.wasm",
8423        );
8424        let module = Module::decode(bytes).unwrap();
8425        module.validate().unwrap();
8426    }
8427
8428    #[test]
8429    fn validate_typed_table_init_shared_source_to_return_call_ref_nullable_official_case() {
8430        let bytes = include_bytes!(
8431            "../../../baedeker-testdata/spec/valid/typed-table-init-shared-source-to-return-call-ref-nullable.wasm",
8432        );
8433        let module = Module::decode(bytes).unwrap();
8434        module.validate().unwrap();
8435    }
8436
8437    #[test]
8438    fn reject_typed_return_call_ref_result_wrong_concrete_type() {
8439        let bytes = include_bytes!(
8440            "../../../baedeker-testdata/spec/invalid-validate/typed-return-call-ref-result-wrong-concrete-type.wasm",
8441        );
8442        let module = Module::decode(bytes).unwrap();
8443        let err = module.validate().unwrap_err();
8444        assert_eq!(err.offset, ByteOffset(55));
8445        assert!(matches!(
8446            err.kind,
8447            ValidationErrorKind::ResultTypeMismatch { expected, found }
8448                if expected == vec![ValType::Ref(RefType::Typed {
8449                    nullable: true,
8450                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8451                })] && found == vec![ValType::Ref(RefType::Typed {
8452                    nullable: true,
8453                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8454                })]
8455        ));
8456    }
8457
8458    #[test]
8459    fn reject_typed_return_call_ref_result_nullability_mismatch() {
8460        let bytes = include_bytes!(
8461            "../../../baedeker-testdata/spec/invalid-validate/typed-return-call-ref-result-nullability-mismatch.wasm",
8462        );
8463        let module = Module::decode(bytes).unwrap();
8464        let err = module.validate().unwrap_err();
8465        assert_eq!(err.offset, ByteOffset(50));
8466        assert!(matches!(
8467            err.kind,
8468            ValidationErrorKind::ResultTypeMismatch { expected, found }
8469                if expected == vec![ValType::Ref(RefType::Typed {
8470                    nullable: false,
8471                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8472                })] && found == vec![ValType::Ref(RefType::Typed {
8473                    nullable: true,
8474                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8475                })]
8476        ));
8477    }
8478
8479    #[test]
8480    fn reject_typed_if_result_to_return_call_ref_with_wrong_concrete_type() {
8481        let bytes = include_bytes!(
8482            "../../../baedeker-testdata/spec/invalid-validate/typed-if-to-return-call-ref-wrong-concrete-type.wasm",
8483        );
8484        let module = Module::decode(bytes).unwrap();
8485        let err = module.validate().unwrap_err();
8486        assert_eq!(err.offset, ByteOffset(62));
8487        assert!(matches!(
8488            err.kind,
8489            ValidationErrorKind::TypeMismatch { op, expected, found }
8490                if op == "return_call_ref"
8491                    && expected == ValType::Ref(RefType::Typed {
8492                        nullable: true,
8493                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8494                    })
8495                    && found == ValType::Ref(RefType::Typed {
8496                        nullable: true,
8497                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8498                    })
8499        ));
8500    }
8501
8502    #[test]
8503    fn reject_typed_table_init_to_return_call_ref_result_nullability_mismatch() {
8504        let bytes = include_bytes!(
8505            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-to-return-call-ref-result-nullability-mismatch.wasm",
8506        );
8507        let module = Module::decode(bytes).unwrap();
8508        let err = module.validate().unwrap_err();
8509        assert_eq!(err.offset, ByteOffset(98));
8510        assert!(matches!(
8511            err.kind,
8512            ValidationErrorKind::ResultTypeMismatch { expected, found }
8513                if expected == vec![ValType::Ref(RefType::Typed {
8514                    nullable: false,
8515                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8516                })] && found == vec![ValType::Ref(RefType::Typed {
8517                    nullable: true,
8518                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8519                })]
8520        ));
8521    }
8522
8523    #[test]
8524    fn reject_typed_table_init_shared_source_to_return_call_ref_nullability_mismatch() {
8525        let bytes = include_bytes!(
8526            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-return-call-ref-nullability-mismatch.wasm",
8527        );
8528        let module = Module::decode(bytes).unwrap();
8529        let err = module.validate().unwrap_err();
8530        assert_eq!(err.offset, ByteOffset(94));
8531        assert!(matches!(
8532            err.kind,
8533            ValidationErrorKind::ResultTypeMismatch { expected, found }
8534                if expected == vec![ValType::Ref(RefType::Typed {
8535                    nullable: false,
8536                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8537                })] && found == vec![ValType::Ref(RefType::Typed {
8538                    nullable: true,
8539                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8540                })]
8541        ));
8542    }
8543
8544    #[test]
8545    fn reject_call_ref_with_non_funcref_reference() {
8546        let bytes = [
8547            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
8548            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0xD0, 0x6F, 0x14, 0x00,
8549            0x0B,
8550        ];
8551        let module = Module::decode(&bytes).unwrap();
8552        let err = module.validate().unwrap_err();
8553        assert_eq!(err.offset, ByteOffset(26));
8554        assert!(matches!(
8555            err.kind,
8556            ValidationErrorKind::TypeMismatch {
8557                op: "call_ref",
8558                expected: ValType::Ref(RefType::Typed {
8559                    nullable: true,
8560                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8561                }),
8562                found: ValType::Ref(RefType::ExternRef),
8563            }
8564        ));
8565    }
8566
8567    #[test]
8568    fn reject_call_ref_non_funcref_externref_official_case() {
8569        let bytes = include_bytes!(
8570            "../../../baedeker-testdata/spec/invalid-validate/call-ref-non-funcref-externref.wasm",
8571        );
8572        let module = Module::decode(bytes).unwrap();
8573        let err = module.validate().unwrap_err();
8574        assert_eq!(err.offset, ByteOffset(29));
8575        assert!(matches!(
8576            err.kind,
8577            ValidationErrorKind::TypeMismatch { op, expected, found }
8578                if op == "call_ref"
8579                    && expected == ValType::Ref(RefType::Typed {
8580                        nullable: true,
8581                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8582                    })
8583                    && found == ValType::Ref(RefType::ExternRef)
8584        ));
8585    }
8586
8587    #[test]
8588    fn reject_call_ref_non_funcref_funcref_official_case() {
8589        let bytes = include_bytes!(
8590            "../../../baedeker-testdata/spec/invalid-validate/call-ref-non-funcref-funcref.wasm",
8591        );
8592        let module = Module::decode(bytes).unwrap();
8593        let err = module.validate().unwrap_err();
8594        assert_eq!(err.offset, ByteOffset(29));
8595        assert!(matches!(
8596            err.kind,
8597            ValidationErrorKind::TypeMismatch { op, expected, found }
8598                if op == "call_ref"
8599                    && expected == ValType::Ref(RefType::Typed {
8600                        nullable: true,
8601                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8602                    })
8603                    && found == ValType::Ref(RefType::FuncRef)
8604        ));
8605    }
8606
8607    #[test]
8608    fn reject_return_call_ref_non_funcref_externref_official_case() {
8609        let bytes = include_bytes!(
8610            "../../../baedeker-testdata/spec/invalid-validate/return-call-ref-non-funcref-externref.wasm",
8611        );
8612        let module = Module::decode(bytes).unwrap();
8613        let err = module.validate().unwrap_err();
8614        assert_eq!(err.offset, ByteOffset(29));
8615        assert!(matches!(
8616            err.kind,
8617            ValidationErrorKind::TypeMismatch { op, expected, found }
8618                if op == "return_call_ref"
8619                    && expected == ValType::Ref(RefType::Typed {
8620                        nullable: true,
8621                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8622                    })
8623                    && found == ValType::Ref(RefType::ExternRef)
8624        ));
8625    }
8626
8627    #[test]
8628    fn reject_return_call_ref_non_funcref_funcref_official_case() {
8629        let bytes = include_bytes!(
8630            "../../../baedeker-testdata/spec/invalid-validate/return-call-ref-non-funcref-funcref.wasm",
8631        );
8632        let module = Module::decode(bytes).unwrap();
8633        let err = module.validate().unwrap_err();
8634        assert_eq!(err.offset, ByteOffset(29));
8635        assert!(matches!(
8636            err.kind,
8637            ValidationErrorKind::TypeMismatch { op, expected, found }
8638                if op == "return_call_ref"
8639                    && expected == ValType::Ref(RefType::Typed {
8640                        nullable: true,
8641                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8642                    })
8643                    && found == ValType::Ref(RefType::FuncRef)
8644        ));
8645    }
8646
8647    #[test]
8648    fn reject_return_call_ref_multi_result_official_case() {
8649        let bytes = include_bytes!(
8650            "../../../baedeker-testdata/spec/invalid-validate/return-call-ref-multi-result.wasm",
8651        );
8652        let module = Module::decode(bytes).unwrap();
8653        let err = module.validate().unwrap_err();
8654        assert_eq!(err.offset, ByteOffset(33));
8655        assert!(matches!(
8656            err.kind,
8657            ValidationErrorKind::ResultTypeMismatch { expected, found }
8658                if expected == vec![ValType::Num(crate::types::NumType::I32)]
8659                    && found == vec![
8660                        ValType::Num(crate::types::NumType::I32),
8661                        ValType::Num(crate::types::NumType::I32),
8662                    ]
8663        ));
8664    }
8665
8666    #[test]
8667    fn reject_return_call_ref_result_mismatch() {
8668        let bytes = [
8669            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60, 0x00, 0x01,
8670            0x7E, 0x60, 0x00, 0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x01, 0x07, 0x05, 0x01, 0x01,
8671            0x66, 0x00, 0x00, 0x0A, 0x0D, 0x02, 0x04, 0x00, 0x42, 0x00, 0x0B, 0x06, 0x00, 0xD2,
8672            0x00, 0x15, 0x00, 0x0B,
8673        ];
8674        let module = Module::decode(&bytes).unwrap();
8675        let err = module.validate().unwrap_err();
8676        assert_eq!(err.offset, ByteOffset(43));
8677        assert!(matches!(
8678            err.kind,
8679            ValidationErrorKind::ResultTypeMismatch {
8680                expected,
8681                found,
8682            } if expected == vec![ValType::Num(crate::types::NumType::I32)]
8683                && found == vec![ValType::Num(crate::types::NumType::I64)]
8684        ));
8685    }
8686
8687    #[test]
8688    fn reject_call_ref_with_wrong_concrete_type() {
8689        let bytes = [
8690            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
8691            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7F, 0x03, 0x03, 0x02, 0x00, 0x01, 0x07, 0x05,
8692            0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x0F, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x08,
8693            0x00, 0x42, 0x00, 0xD2, 0x00, 0x14, 0x01, 0x0B,
8694        ];
8695        let module = Module::decode(&bytes).unwrap();
8696        let err = module.validate().unwrap_err();
8697        assert_eq!(err.offset, ByteOffset(47));
8698        assert!(matches!(
8699            err.kind,
8700            ValidationErrorKind::TypeMismatch {
8701                op: "call_ref",
8702                expected: ValType::Ref(RefType::Typed {
8703                    nullable: true,
8704                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8705                }),
8706                found: ValType::Ref(RefType::Typed {
8707                    nullable: false,
8708                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8709                }),
8710            }
8711        ));
8712    }
8713
8714    #[test]
8715    fn reject_typed_ref_global_init_from_imported_typed_global_with_wrong_concrete_type() {
8716        let bytes = [
8717            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
8718            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x02, 0x0B, 0x01, 0x03, 0x65, 0x6E, 0x76,
8719            0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x06, 0x07, 0x01, 0x63, 0x01, 0x00, 0x23, 0x00,
8720            0x0B,
8721        ];
8722        let module = Module::decode(&bytes).unwrap();
8723        let err = module.validate().unwrap_err();
8724        assert_eq!(err.offset, ByteOffset(40));
8725        assert!(matches!(
8726            err.kind,
8727            ValidationErrorKind::GlobalInitTypeMismatch {
8728                expected: ValType::Ref(RefType::Typed {
8729                    nullable: true,
8730                    heap: crate::types::HeapType::Type(TypeIdx(1)),
8731                }),
8732                found: ValType::Ref(RefType::Typed {
8733                    nullable: true,
8734                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8735                }),
8736            }
8737        ));
8738    }
8739
8740    #[test]
8741    fn reject_typed_table_get_to_defined_mut_global_with_wrong_concrete_type() {
8742        let bytes = include_bytes!(
8743            "../../../baedeker-testdata/spec/invalid-validate/typed-table-to-defined-mut-global-wrong-concrete-type.wasm",
8744        );
8745        let module = Module::decode(bytes).unwrap();
8746        let err = module.validate().unwrap_err();
8747        assert_eq!(err.offset, ByteOffset(74));
8748        assert!(matches!(
8749            err.kind,
8750            ValidationErrorKind::TypeMismatch { op, expected, found }
8751                if op == "global.set"
8752                    && expected == ValType::Ref(RefType::Typed {
8753                        nullable: true,
8754                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8755                    })
8756                    && found == ValType::Ref(RefType::Typed {
8757                        nullable: true,
8758                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8759                    })
8760        ));
8761    }
8762
8763    #[test]
8764    fn reject_imported_typed_table_get_to_defined_mut_global_with_wrong_concrete_type() {
8765        let bytes = include_bytes!(
8766            "../../../baedeker-testdata/spec/invalid-validate/imported-typed-table-to-defined-mut-global-wrong-concrete-type.wasm",
8767        );
8768        let module = Module::decode(bytes).unwrap();
8769        let err = module.validate().unwrap_err();
8770        assert_eq!(err.offset, ByteOffset(62));
8771        assert!(matches!(
8772            err.kind,
8773            ValidationErrorKind::TypeMismatch { op, expected, found }
8774                if op == "global.set"
8775                    && expected == ValType::Ref(RefType::Typed {
8776                        nullable: true,
8777                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8778                    })
8779                    && found == ValType::Ref(RefType::Typed {
8780                        nullable: true,
8781                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8782                    })
8783        ));
8784    }
8785
8786    #[test]
8787    fn reject_typed_local_set_if_nullability_mismatch() {
8788        let bytes = include_bytes!(
8789            "../../../baedeker-testdata/spec/invalid-validate/typed-local-set-if-nullability-mismatch.wasm",
8790        );
8791        let module = Module::decode(bytes).unwrap();
8792        let err = module.validate().unwrap_err();
8793        assert_eq!(err.offset, ByteOffset(56));
8794        assert!(matches!(
8795            err.kind,
8796            ValidationErrorKind::TypeMismatch { op, expected, found }
8797                if op == "local.set"
8798                    && expected == ValType::Ref(RefType::Typed {
8799                        nullable: false,
8800                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8801                    })
8802                    && found == ValType::Ref(RefType::Typed {
8803                        nullable: true,
8804                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8805                    })
8806        ));
8807    }
8808
8809    #[test]
8810    fn reject_typed_local_if_to_return_nullability_mismatch() {
8811        let bytes = include_bytes!(
8812            "../../../baedeker-testdata/spec/invalid-validate/typed-local-if-to-return-nullability-mismatch.wasm",
8813        );
8814        let module = Module::decode(bytes).unwrap();
8815        let err = module.validate().unwrap_err();
8816        assert_eq!(err.offset, ByteOffset(62));
8817        assert!(matches!(
8818            err.kind,
8819            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
8820                if expected == vec![ValType::Ref(RefType::Typed {
8821                    nullable: false,
8822                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8823                })] && found == vec![ValType::Ref(RefType::Typed {
8824                    nullable: true,
8825                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8826                })]
8827        ));
8828    }
8829
8830    #[test]
8831    fn reject_typed_global_set_if_nullability_mismatch() {
8832        let bytes = include_bytes!(
8833            "../../../baedeker-testdata/spec/invalid-validate/typed-global-set-if-nullability-mismatch.wasm",
8834        );
8835        let module = Module::decode(bytes).unwrap();
8836        let err = module.validate().unwrap_err();
8837        assert_eq!(err.offset, ByteOffset(62));
8838        assert!(matches!(
8839            err.kind,
8840            ValidationErrorKind::TypeMismatch { op, expected, found }
8841                if op == "global.set"
8842                    && expected == ValType::Ref(RefType::Typed {
8843                        nullable: false,
8844                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8845                    })
8846                    && found == ValType::Ref(RefType::Typed {
8847                        nullable: true,
8848                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8849                    })
8850        ));
8851    }
8852
8853    #[test]
8854    fn reject_typed_table_init_shared_source_to_global_set_nullability_mismatch() {
8855        let bytes = include_bytes!(
8856            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-shared-source-to-global-set-nullability-mismatch.wasm",
8857        );
8858        let module = Module::decode(bytes).unwrap();
8859        let err = module.validate().unwrap_err();
8860        assert_eq!(err.offset, ByteOffset(98));
8861        assert!(matches!(
8862            err.kind,
8863            ValidationErrorKind::TypeMismatch { op, expected, found }
8864                if op == "global.set"
8865                    && expected == ValType::Ref(RefType::Typed {
8866                        nullable: false,
8867                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8868                    })
8869                    && found == ValType::Ref(RefType::Typed {
8870                        nullable: true,
8871                        heap: crate::types::HeapType::Type(TypeIdx(1)),
8872                    })
8873        ));
8874    }
8875
8876    #[test]
8877    fn reject_typed_global_if_to_return_nullability_mismatch() {
8878        let bytes = include_bytes!(
8879            "../../../baedeker-testdata/spec/invalid-validate/typed-global-if-to-return-nullability-mismatch.wasm",
8880        );
8881        let module = Module::decode(bytes).unwrap();
8882        let err = module.validate().unwrap_err();
8883        assert_eq!(err.offset, ByteOffset(68));
8884        assert!(matches!(
8885            err.kind,
8886            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
8887                if expected == vec![ValType::Ref(RefType::Typed {
8888                    nullable: false,
8889                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8890                })] && found == vec![ValType::Ref(RefType::Typed {
8891                    nullable: true,
8892                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8893                })]
8894        ));
8895    }
8896
8897    #[test]
8898    fn reject_typed_table_set_if_nullability_mismatch() {
8899        let bytes = include_bytes!(
8900            "../../../baedeker-testdata/spec/invalid-validate/typed-table-set-if-nullability-mismatch.wasm",
8901        );
8902        let module = Module::decode(bytes).unwrap();
8903        let err = module.validate().unwrap_err();
8904        assert_eq!(err.offset, ByteOffset(67));
8905        assert!(matches!(
8906            err.kind,
8907            ValidationErrorKind::TypeMismatch { op, expected, found }
8908                if op == "table.set"
8909                    && expected == ValType::Ref(RefType::Typed {
8910                        nullable: false,
8911                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8912                    })
8913                    && found == ValType::Ref(RefType::Typed {
8914                        nullable: true,
8915                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8916                    })
8917        ));
8918    }
8919
8920    #[test]
8921    fn reject_typed_table_if_to_return_nullability_mismatch() {
8922        let bytes = include_bytes!(
8923            "../../../baedeker-testdata/spec/invalid-validate/typed-table-if-to-return-nullability-mismatch.wasm",
8924        );
8925        let module = Module::decode(bytes).unwrap();
8926        let err = module.validate().unwrap_err();
8927        assert_eq!(err.offset, ByteOffset(70));
8928        assert!(matches!(
8929            err.kind,
8930            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
8931                if expected == vec![ValType::Ref(RefType::Typed {
8932                    nullable: false,
8933                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8934                })] && found == vec![ValType::Ref(RefType::Typed {
8935                    nullable: true,
8936                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8937                })]
8938        ));
8939    }
8940
8941    #[test]
8942    fn reject_typed_passive_element_nullability_mismatch() {
8943        let bytes = include_bytes!(
8944            "../../../baedeker-testdata/spec/invalid-validate/typed-passive-element-nullability-mismatch.wasm",
8945        );
8946        let module = Module::decode(bytes).unwrap();
8947        let err = module.validate().unwrap_err();
8948        assert_eq!(err.offset, ByteOffset(32));
8949        assert!(matches!(
8950            err.kind,
8951            ValidationErrorKind::ElementExprTypeMismatch { expected, found }
8952                if expected == ValType::Ref(RefType::Typed {
8953                    nullable: false,
8954                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8955                })
8956                    && found == ValType::Ref(RefType::Typed {
8957                        nullable: true,
8958                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8959                    })
8960        ));
8961    }
8962
8963    #[test]
8964    fn reject_typed_table_init_nullability_mismatch() {
8965        let bytes = include_bytes!(
8966            "../../../baedeker-testdata/spec/invalid-validate/typed-table-init-nullability-mismatch.wasm",
8967        );
8968        let module = Module::decode(bytes).unwrap();
8969        let err = module.validate().unwrap_err();
8970        assert_eq!(err.offset, ByteOffset(76));
8971        assert!(matches!(
8972            err.kind,
8973            ValidationErrorKind::ElementTableTypeMismatch { expected, found }
8974                if expected == RefType::Typed {
8975                    nullable: false,
8976                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8977                }
8978                    && found == RefType::Typed {
8979                        nullable: true,
8980                        heap: crate::types::HeapType::Type(TypeIdx(0)),
8981                    }
8982        ));
8983    }
8984
8985    #[test]
8986    fn reject_typed_defined_global_passive_element_table_init_to_return_nullability_mismatch() {
8987        let bytes = include_bytes!(
8988            "../../../baedeker-testdata/spec/invalid-validate/typed-defined-global-passive-element-table-init-to-return-nullability-mismatch.wasm",
8989        );
8990        let module = Module::decode(bytes).unwrap();
8991        let err = module.validate().unwrap_err();
8992        assert_eq!(err.offset, ByteOffset(83));
8993        assert!(matches!(
8994            err.kind,
8995            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
8996                if expected == vec![ValType::Ref(RefType::Typed {
8997                    nullable: false,
8998                    heap: crate::types::HeapType::Type(TypeIdx(0)),
8999                })] && found == vec![ValType::Ref(RefType::Typed {
9000                    nullable: true,
9001                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9002                })]
9003        ));
9004    }
9005
9006    #[test]
9007    fn reject_typed_imported_global_passive_element_table_init_to_return_nullability_mismatch() {
9008        let bytes = include_bytes!(
9009            "../../../baedeker-testdata/spec/invalid-validate/typed-imported-global-passive-element-table-init-to-return-nullability-mismatch.wasm",
9010        );
9011        let module = Module::decode(bytes).unwrap();
9012        let err = module.validate().unwrap_err();
9013        assert_eq!(err.offset, ByteOffset(74));
9014        assert!(matches!(
9015            err.kind,
9016            ValidationErrorKind::FunctionResultTypeMismatch { expected, found, .. }
9017                if expected == vec![ValType::Ref(RefType::Typed {
9018                    nullable: false,
9019                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9020                })] && found == vec![ValType::Ref(RefType::Typed {
9021                    nullable: true,
9022                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9023                })]
9024        ));
9025    }
9026
9027    #[test]
9028    fn reject_typed_defined_global_passive_element_table_init_to_global_set_nullability_mismatch() {
9029        let bytes = include_bytes!(
9030            "../../../baedeker-testdata/spec/invalid-validate/typed-defined-global-passive-element-table-init-to-global-set-nullability-mismatch.wasm",
9031        );
9032        let module = Module::decode(bytes).unwrap();
9033        let err = module.validate().unwrap_err();
9034        assert_eq!(err.offset, ByteOffset(87));
9035        assert!(matches!(
9036            err.kind,
9037            ValidationErrorKind::TypeMismatch { op, expected, found }
9038                if op == "global.set"
9039                    && expected == ValType::Ref(RefType::Typed {
9040                        nullable: false,
9041                        heap: crate::types::HeapType::Type(TypeIdx(0)),
9042                    })
9043                    && found == ValType::Ref(RefType::Typed {
9044                        nullable: true,
9045                        heap: crate::types::HeapType::Type(TypeIdx(0)),
9046                    })
9047        ));
9048    }
9049
9050    #[test]
9051    fn reject_typed_imported_global_passive_element_table_init_nullability_mismatch() {
9052        let bytes = include_bytes!(
9053            "../../../baedeker-testdata/spec/invalid-validate/typed-imported-global-passive-element-table-init-nullability-mismatch.wasm",
9054        );
9055        let module = Module::decode(bytes).unwrap();
9056        let err = module.validate().unwrap_err();
9057        assert_eq!(err.offset, ByteOffset(79));
9058        // The table's element type is (ref $t1) (its init expr references
9059        // the module's only function, of type 1); the passive segment
9060        // provides (ref null $t0) values — still a mismatch.
9061        assert!(matches!(
9062            err.kind,
9063            ValidationErrorKind::ElementTableTypeMismatch { expected, found }
9064                if expected == RefType::Typed {
9065                    nullable: false,
9066                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9067                }
9068                    && found == RefType::Typed {
9069                        nullable: true,
9070                        heap: crate::types::HeapType::Type(TypeIdx(0)),
9071                    }
9072        ));
9073    }
9074
9075    #[test]
9076    fn reject_typed_element_expr_from_imported_typed_global_with_wrong_concrete_type() {
9077        let bytes = [
9078            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x02, 0x60, 0x01, 0x7F,
9079            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x02, 0x0B, 0x01, 0x03, 0x65, 0x6E, 0x76,
9080            0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x01, 0x09,
9081            0x0C, 0x01, 0x06, 0x00, 0x41, 0x00, 0x0B, 0x63, 0x01, 0x01, 0x23, 0x00, 0x0B,
9082        ];
9083        let module = Module::decode(&bytes).unwrap();
9084        let err = module.validate().unwrap_err();
9085        assert_eq!(err.offset, ByteOffset(52));
9086        assert!(matches!(
9087            err.kind,
9088            ValidationErrorKind::ElementExprTypeMismatch {
9089                expected: ValType::Ref(RefType::Typed {
9090                    nullable: true,
9091                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9092                }),
9093                found: ValType::Ref(RefType::Typed {
9094                    nullable: true,
9095                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9096                }),
9097            }
9098        ));
9099    }
9100
9101    #[test]
9102    fn reject_imported_typed_global_to_imported_table_with_wrong_concrete_type() {
9103        let bytes = [
9104            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x03, 0x60, 0x01, 0x7F,
9105            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x60, 0x00, 0x01, 0x63, 0x01, 0x02, 0x16,
9106            0x02, 0x03, 0x65, 0x6E, 0x76, 0x01, 0x67, 0x03, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E,
9107            0x76, 0x01, 0x74, 0x01, 0x63, 0x01, 0x00, 0x01, 0x03, 0x02, 0x01, 0x02, 0x0A, 0x0E,
9108            0x01, 0x0C, 0x00, 0x41, 0x00, 0x23, 0x00, 0x26, 0x00, 0x41, 0x00, 0x25, 0x00, 0x0B,
9109        ];
9110        let module = Module::decode(&bytes).unwrap();
9111        let err = module.validate().unwrap_err();
9112        assert_eq!(err.offset, ByteOffset(63));
9113        assert!(matches!(
9114            err.kind,
9115            ValidationErrorKind::TypeMismatch {
9116                op: "table.set",
9117                expected: ValType::Ref(RefType::Typed {
9118                    nullable: true,
9119                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9120                }),
9121                found: ValType::Ref(RefType::Typed {
9122                    nullable: true,
9123                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9124                }),
9125            }
9126        ));
9127    }
9128
9129    #[test]
9130    fn reject_typed_passive_element_from_defined_typed_global_with_wrong_concrete_type() {
9131        let bytes = include_bytes!(
9132            "../../../baedeker-testdata/spec/invalid-validate/defined-typed-global-passive-element-wrong-concrete-type.wasm",
9133        );
9134        let module = Module::decode(bytes).unwrap();
9135        let err = module.validate().unwrap_err();
9136        assert_eq!(err.offset, ByteOffset(48));
9137        assert!(matches!(
9138            err.kind,
9139            ValidationErrorKind::ElementExprTypeMismatch { expected, found }
9140                if expected == ValType::Ref(RefType::Typed {
9141                    nullable: true,
9142                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9143                })
9144                    && found == ValType::Ref(RefType::Typed {
9145                        nullable: true,
9146                        heap: crate::types::HeapType::Type(TypeIdx(0)),
9147                    })
9148        ));
9149    }
9150
9151    #[test]
9152    fn reject_typed_passive_element_from_imported_typed_global_with_wrong_concrete_type() {
9153        let bytes = include_bytes!(
9154            "../../../baedeker-testdata/spec/invalid-validate/imported-typed-global-passive-element-wrong-concrete-type.wasm",
9155        );
9156        let module = Module::decode(bytes).unwrap();
9157        let err = module.validate().unwrap_err();
9158        assert_eq!(err.offset, ByteOffset(41));
9159        assert!(matches!(
9160            err.kind,
9161            ValidationErrorKind::ElementExprTypeMismatch { expected, found }
9162                if expected == ValType::Ref(RefType::Typed {
9163                    nullable: true,
9164                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9165                })
9166                    && found == ValType::Ref(RefType::Typed {
9167                        nullable: true,
9168                        heap: crate::types::HeapType::Type(TypeIdx(0)),
9169                    })
9170        ));
9171    }
9172
9173    #[test]
9174    fn reject_typed_if_result_with_wrong_concrete_type() {
9175        let bytes = [
9176            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x03, 0x60, 0x01, 0x7F,
9177            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x60, 0x01, 0x7F, 0x01, 0x63, 0x01, 0x03,
9178            0x03, 0x02, 0x00, 0x02, 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00, 0x0A, 0x14, 0x02,
9179            0x04, 0x00, 0x20, 0x00, 0x0B, 0x0D, 0x00, 0x20, 0x00, 0x04, 0x63, 0x01, 0xD2, 0x00,
9180            0x05, 0xD0, 0x01, 0x0B, 0x0B,
9181        ];
9182        let module = Module::decode(&bytes).unwrap();
9183        let err = module.validate().unwrap_err();
9184        assert_eq!(err.offset, ByteOffset(56));
9185        assert!(matches!(
9186            err.kind,
9187            ValidationErrorKind::ControlResultTypeMismatch { expected, found }
9188                if expected == vec![ValType::Ref(RefType::Typed {
9189                    nullable: true,
9190                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9191                })] && found == vec![ValType::Ref(RefType::Typed {
9192                    nullable: false,
9193                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9194                })]
9195        ));
9196    }
9197
9198    #[test]
9199    fn reject_table_init_with_incompatible_typed_element_segment() {
9200        let bytes = [
9201            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0E, 0x03, 0x60, 0x01, 0x7F,
9202            0x01, 0x7F, 0x60, 0x01, 0x7E, 0x01, 0x7E, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00,
9203            0x02, 0x04, 0x05, 0x01, 0x63, 0x01, 0x00, 0x04, 0x07, 0x0C, 0x02, 0x01, 0x66, 0x00,
9204            0x00, 0x04, 0x69, 0x6E, 0x69, 0x74, 0x00, 0x01, 0x09, 0x08, 0x01, 0x05, 0x63, 0x00,
9205            0x01, 0xD2, 0x00, 0x0B, 0x0A, 0x13, 0x02, 0x04, 0x00, 0x20, 0x00, 0x0B, 0x0C, 0x00,
9206            0x41, 0x00, 0x41, 0x00, 0x41, 0x01, 0xFC, 0x0C, 0x00, 0x00, 0x0B,
9207        ];
9208        let module = Module::decode(&bytes).unwrap();
9209        let err = module.validate().unwrap_err();
9210        assert_eq!(err.offset, ByteOffset(76));
9211        assert!(matches!(
9212            err.kind,
9213            ValidationErrorKind::ElementTableTypeMismatch {
9214                expected: RefType::Typed {
9215                    nullable: true,
9216                    heap: crate::types::HeapType::Type(TypeIdx(1)),
9217                },
9218                found: RefType::Typed {
9219                    nullable: true,
9220                    heap: crate::types::HeapType::Type(TypeIdx(0)),
9221                },
9222            }
9223        ));
9224    }
9225
9226    #[test]
9227    fn reject_return_call_indirect_result_mismatch() {
9228        let bytes = [
9229            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x09, 0x02, 0x60, 0x00, 0x01,
9230            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00,
9231            0x01, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x41, 0x00, 0x13, 0x01, 0x00, 0x0B,
9232        ];
9233        let module = Module::decode(&bytes).unwrap();
9234        let err = module.validate().unwrap_err();
9235        assert_eq!(err.offset, ByteOffset(36));
9236        assert!(matches!(
9237            err.kind,
9238            ValidationErrorKind::ResultTypeMismatch {
9239                expected,
9240                found,
9241            } if expected == vec![ValType::Num(crate::types::NumType::I32)]
9242                && found == vec![ValType::Num(crate::types::NumType::I64)]
9243        ));
9244    }
9245
9246    #[test]
9247    fn reject_call_indirect_with_non_funcref_table() {
9248        let bytes = [
9249            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
9250            0x02, 0x0D, 0x01, 0x03, b'e', b'n', b'v', 0x03, b't', b'a', b'b', 0x01, 0x6F, 0x00,
9251            0x01, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x09, 0x01, 0x07, 0x00, 0x41, 0x00, 0x11, 0x00,
9252            0x00, 0x0B,
9253        ];
9254        let module = Module::decode(&bytes).unwrap();
9255        let err = module.validate().unwrap_err();
9256        assert!(matches!(
9257            err.kind,
9258            ValidationErrorKind::InvalidCallIndirectTableType {
9259                expected: RefType::FuncRef,
9260                found: RefType::ExternRef,
9261            }
9262        ));
9263    }
9264
9265    #[test]
9266    fn reject_return_call_indirect_with_non_funcref_table() {
9267        let bytes = [
9268            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
9269            0x7F, 0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x6F, 0x00, 0x01, 0x0A, 0x09, 0x01,
9270            0x07, 0x00, 0x41, 0x00, 0x13, 0x00, 0x00, 0x0B,
9271        ];
9272        let module = Module::decode(&bytes).unwrap();
9273        let err = module.validate().unwrap_err();
9274        assert_eq!(err.offset, ByteOffset(32));
9275        assert!(matches!(
9276            err.kind,
9277            ValidationErrorKind::InvalidCallIndirectTableType {
9278                expected: RefType::FuncRef,
9279                found: RefType::ExternRef,
9280            }
9281        ));
9282    }
9283
9284    #[test]
9285    fn validate_table_get_set_size_and_grow() {
9286        let bytes = [
9287            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
9288            0x7F, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x04, 0x04, 0x01, 0x70, 0x00,
9289            0x01, 0x0A, 0x1D, 0x02, 0x0A, 0x00, 0x41, 0x00, 0x25, 0x00, 0x1A, 0xFC, 0x10, 0x00,
9290            0x0B, 0x10, 0x00, 0x41, 0x00, 0xD0, 0x70, 0x26, 0x00, 0xD0, 0x70, 0x41, 0x01, 0xFC,
9291            0x0F, 0x00, 0x1A, 0x0B,
9292        ];
9293        let module = Module::decode(&bytes).unwrap();
9294        module.validate().unwrap();
9295    }
9296
9297    #[test]
9298    fn validate_table_get_set_size_and_grow_on_nonzero_table() {
9299        let bytes = [
9300            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x00, 0x01,
9301            0x7F, 0x60, 0x00, 0x00, 0x03, 0x03, 0x02, 0x00, 0x01, 0x04, 0x07, 0x02, 0x70, 0x00,
9302            0x01, 0x70, 0x00, 0x01, 0x0A, 0x1D, 0x02, 0x0A, 0x00, 0x41, 0x00, 0x25, 0x01, 0x1A,
9303            0xFC, 0x10, 0x01, 0x0B, 0x10, 0x00, 0x41, 0x00, 0xD0, 0x70, 0x26, 0x01, 0xD0, 0x70,
9304            0x41, 0x01, 0xFC, 0x0F, 0x01, 0x1A, 0x0B,
9305        ];
9306        let module = Module::decode(&bytes).unwrap();
9307        module.validate().unwrap();
9308    }
9309
9310    #[test]
9311    fn validate_broader_numeric_operators() {
9312        let bytes = [
9313            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x04, 0x60, 0x00, 0x01,
9314            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x60, 0x00, 0x01, 0x7D, 0x60, 0x00, 0x01, 0x7C, 0x03,
9315            0x05, 0x04, 0x00, 0x01, 0x02, 0x03, 0x0A, 0x26, 0x04, 0x08, 0x00, 0x41, 0x03, 0x41,
9316            0x01, 0x6B, 0x45, 0x0B, 0x05, 0x00, 0x42, 0x05, 0x79, 0x0B, 0x08, 0x00, 0x43, 0x00,
9317            0x00, 0x80, 0x3F, 0x8B, 0x0B, 0x0C, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9318            0xF0, 0x3F, 0x99, 0x0B,
9319        ];
9320        let module = Module::decode(&bytes).unwrap();
9321        module.validate().unwrap();
9322    }
9323
9324    #[test]
9325    fn reject_broader_numeric_operator_type_mismatch() {
9326        let bytes = [
9327            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
9328            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x0A, 0x01, 0x08, 0x00, 0x43, 0x00, 0x00, 0x80,
9329            0x3F, 0x67, 0x0B,
9330        ];
9331        let module = Module::decode(&bytes).unwrap();
9332        let err = module.validate().unwrap_err();
9333        assert_eq!(err.offset, ByteOffset(29));
9334        assert!(matches!(
9335            err.kind,
9336            ValidationErrorKind::TypeMismatch {
9337                op: "i32.unary",
9338                expected: ValType::Num(crate::types::NumType::I32),
9339                found: ValType::Num(crate::types::NumType::F32),
9340            }
9341        ));
9342    }
9343
9344    #[test]
9345    fn validate_conversions_and_reinterpretations() {
9346        let bytes = [
9347            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x14, 0x05, 0x60, 0x00, 0x01,
9348            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x60, 0x00, 0x01, 0x7D, 0x60, 0x00, 0x01, 0x7C, 0x60,
9349            0x00, 0x00, 0x03, 0x06, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x0A, 0x2A, 0x05, 0x05,
9350            0x00, 0x42, 0x2A, 0xA7, 0x0B, 0x0C, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9351            0xF0, 0x3F, 0xBD, 0x0B, 0x05, 0x00, 0x41, 0x7F, 0xBE, 0x0B, 0x08, 0x00, 0x43, 0x00,
9352            0x00, 0x40, 0x40, 0xBB, 0x0B, 0x06, 0x00, 0x42, 0x7F, 0xC4, 0x1A, 0x0B,
9353        ];
9354        let module = Module::decode(&bytes).unwrap();
9355        module.validate().unwrap();
9356    }
9357
9358    #[test]
9359    fn reject_conversion_type_mismatch() {
9360        let bytes = [
9361            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
9362            0x7F, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x07, 0x01, 0x05, 0x00, 0x41, 0x01, 0xA8, 0x0B,
9363        ];
9364        let module = Module::decode(&bytes).unwrap();
9365        let err = module.validate().unwrap_err();
9366        assert_eq!(err.offset, ByteOffset(26));
9367        assert!(matches!(
9368            err.kind,
9369            ValidationErrorKind::TypeMismatch {
9370                op: "i32.trunc_f32",
9371                expected: ValType::Num(crate::types::NumType::F32),
9372                found: ValType::Num(crate::types::NumType::I32),
9373            }
9374        ));
9375    }
9376
9377    #[test]
9378    fn validate_saturating_truncation_variants() {
9379        let bytes = [
9380            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x04, 0x60, 0x00, 0x01,
9381            0x7F, 0x60, 0x00, 0x01, 0x7E, 0x60, 0x00, 0x01, 0x7D, 0x60, 0x00, 0x01, 0x7C, 0x03,
9382            0x05, 0x04, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x31, 0x04, 0x09, 0x00, 0x43, 0x00, 0x00,
9383            0x80, 0x3F, 0xFC, 0x00, 0x0B, 0x0D, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9384            0xF0, 0x3F, 0xFC, 0x07, 0x0B, 0x09, 0x00, 0x43, 0x00, 0x00, 0x80, 0x3F, 0xFC, 0x04,
9385            0x0B, 0x0D, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0xFC, 0x02,
9386            0x0B,
9387        ];
9388        let module = Module::decode(&bytes).unwrap();
9389        module.validate().unwrap();
9390    }
9391
9392    #[test]
9393    fn reject_saturating_truncation_type_mismatch() {
9394        let bytes = [
9395            0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01,
9396            0x7E, 0x03, 0x02, 0x01, 0x00, 0x0A, 0x08, 0x01, 0x06, 0x00, 0x42, 0x00, 0xFC, 0x04,
9397            0x0B,
9398        ];
9399        let module = Module::decode(&bytes).unwrap();
9400        let err = module.validate().unwrap_err();
9401        assert_eq!(err.offset, ByteOffset(26));
9402        assert!(matches!(
9403            err.kind,
9404            ValidationErrorKind::TypeMismatch {
9405                op: "i64.trunc_sat_f32",
9406                expected: ValType::Num(crate::types::NumType::F32),
9407                found: ValType::Num(crate::types::NumType::I64),
9408            }
9409        ));
9410    }
9411}