Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/validator/component_validator.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
//===-- component_validator.cpp - Component definition validation ---------===//
5
//
6
// The component-model validation entry point and the per-section rules.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "common/errinfo.h"
11
#include "common/spdlog.h"
12
#include "validator/component_value_decode.h"
13
#include "validator/validator.h"
14
15
#include <optional>
16
#include <string>
17
#include <unordered_set>
18
#include <variant>
19
20
namespace WasmEdge {
21
namespace Validator {
22
23
using namespace std::literals;
24
25
Expect<void>
26
7.37k
Validator::validate(const AST::Component::Component &Comp) noexcept {
27
7.37k
  CompCtx.reset();
28
7.37k
  DeferredModules.clear();
29
7.37k
  EXPECTED_TRY(validate(Comp, *CompCtx.addShape()));
30
  // Deferred function-body validation on the checker state saved per module.
31
4.77k
  for (auto &[Mod, Saved] : DeferredModules) {
32
4.77k
    Checker = std::move(Saved);
33
4.77k
    EXPECTED_TRY(validate(Mod->getCodeSection()).map_error([](auto E) {
34
4.76k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
35
4.76k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
36
4.76k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
37
4.76k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
38
4.76k
      return E;
39
4.76k
    }));
40
4.76k
    const_cast<AST::Module &>(*Mod).setIsValidated();
41
4.76k
  }
42
3.52k
  const_cast<AST::Component::Component &>(Comp).setIsValidated();
43
3.52k
  return {};
44
3.53k
}
45
46
Expect<void> Validator::validate(const AST::Component::Component &Comp,
47
71.5k
                                 Component::Shape &Out) noexcept {
48
  // Walk the sections in binary order; a reference sees only earlier entries.
49
71.5k
  auto &S = CompCtx.pushScope(Component::ScopeKind::Component);
50
71.5k
  Out.DeclScope = &S;
51
52
71.5k
  auto ReportError = [](auto E) {
53
3.39k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
54
3.39k
    return E;
55
3.39k
  };
56
13.1M
  for (const auto &Sec : Comp.getSections()) {
57
13.1M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
13.1M
      using T = std::decay_t<decltype(Section)>;
59
13.1M
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
4.12M
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
110k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
110k
        return validate(Section, Out).map_error(ReportError);
65
8.90M
      } else {
66
8.90M
        return validate(Section).map_error(ReportError);
67
8.90M
      }
68
13.1M
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::CustomSection const&>(WasmEdge::AST::CustomSection const&) const
Line
Count
Source
57
4.12M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
4.12M
      using T = std::decay_t<decltype(Section)>;
59
4.12M
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
4.12M
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
      } else {
66
        return validate(Section).map_error(ReportError);
67
      }
68
4.12M
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreModuleSection const&>(WasmEdge::AST::Component::CoreModuleSection const&) const
Line
Count
Source
57
6.59k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
6.59k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
6.59k
      } else {
66
6.59k
        return validate(Section).map_error(ReportError);
67
6.59k
      }
68
6.59k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreInstanceSection const&>(WasmEdge::AST::Component::CoreInstanceSection const&) const
Line
Count
Source
57
84.4k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
84.4k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
84.4k
      } else {
66
84.4k
        return validate(Section).map_error(ReportError);
67
84.4k
      }
68
84.4k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CoreTypeSection const&>(WasmEdge::AST::Component::CoreTypeSection const&) const
Line
Count
Source
57
188k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
188k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
188k
      } else {
66
188k
        return validate(Section).map_error(ReportError);
67
188k
      }
68
188k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ComponentSection const&>(WasmEdge::AST::Component::ComponentSection const&) const
Line
Count
Source
57
64.1k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
64.1k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
64.1k
      } else {
66
64.1k
        return validate(Section).map_error(ReportError);
67
64.1k
      }
68
64.1k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::InstanceSection const&>(WasmEdge::AST::Component::InstanceSection const&) const
Line
Count
Source
57
2.12M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
2.12M
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
2.12M
      } else {
66
2.12M
        return validate(Section).map_error(ReportError);
67
2.12M
      }
68
2.12M
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::AliasSection const&>(WasmEdge::AST::Component::AliasSection const&) const
Line
Count
Source
57
69.4k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
69.4k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
69.4k
      } else {
66
69.4k
        return validate(Section).map_error(ReportError);
67
69.4k
      }
68
69.4k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::TypeSection const&>(WasmEdge::AST::Component::TypeSection const&) const
Line
Count
Source
57
6.07M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
6.07M
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
6.07M
      } else {
66
6.07M
        return validate(Section).map_error(ReportError);
67
6.07M
      }
68
6.07M
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::CanonSection const&>(WasmEdge::AST::Component::CanonSection const&) const
Line
Count
Source
57
272k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
272k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
272k
      } else {
66
272k
        return validate(Section).map_error(ReportError);
67
272k
      }
68
272k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::StartSection const&>(WasmEdge::AST::Component::StartSection const&) const
Line
Count
Source
57
674
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
674
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
674
      } else {
66
674
        return validate(Section).map_error(ReportError);
67
674
      }
68
674
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ImportSection const&>(WasmEdge::AST::Component::ImportSection const&) const
Line
Count
Source
57
97.8k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
97.8k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
97.8k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
97.8k
        return validate(Section, Out).map_error(ReportError);
65
      } else {
66
        return validate(Section).map_error(ReportError);
67
      }
68
97.8k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ExportSection const&>(WasmEdge::AST::Component::ExportSection const&) const
Line
Count
Source
57
13.0k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
13.0k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
13.0k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
13.0k
        return validate(Section, Out).map_error(ReportError);
65
      } else {
66
        return validate(Section).map_error(ReportError);
67
      }
68
13.0k
    };
component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validate(WasmEdge::AST::Component::Component const&, WasmEdge::Validator::Component::Shape&)::$_0::operator()<WasmEdge::AST::Component::ValueSection const&>(WasmEdge::AST::Component::ValueSection const&) const
Line
Count
Source
57
13.9k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
13.9k
      using T = std::decay_t<decltype(Section)>;
59
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
        return validate(Section, Out).map_error(ReportError);
65
13.9k
      } else {
66
13.9k
        return validate(Section).map_error(ReportError);
67
13.9k
      }
68
13.9k
    };
69
13.1M
    EXPECTED_TRY(std::visit(Visitor, Sec));
70
13.1M
  }
71
  // Value linearity. Every value must have exactly one consumer.
72
68.1k
  const auto &Values = S.Values;
73
68.2k
  for (uint32_t I = 0; I < Values.size(); ++I) {
74
484
    if (!Values[I].Consumed) {
75
448
      spdlog::error(ErrCode::Value::ComponentValueNotConsumed);
76
448
      spdlog::error("    Value index {} was not consumed before the end of the "
77
448
                    "component."sv,
78
448
                    I);
79
448
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
80
448
      return Unexpect(ErrCode::Value::ComponentValueNotConsumed);
81
448
    }
82
484
  }
83
67.7k
  CompCtx.popScope();
84
67.7k
  return {};
85
68.1k
}
86
87
Expect<void>
88
6.59k
Validator::validate(const AST::Component::CoreModuleSection &ModSec) noexcept {
89
  // Validate every section but the function bodies, which defer to the end.
90
6.59k
  const auto &Mod = ModSec.getContent();
91
6.59k
  Checker.reset(true);
92
72.1k
  auto ReportError = [](ASTNodeAttr Attr) {
93
72.1k
    return [Attr](auto E) {
94
67
      spdlog::error(ErrInfo::InfoAST(Attr));
95
67
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
96
67
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
97
67
      return E;
98
67
    };
99
72.1k
  };
100
6.59k
  EXPECTED_TRY(validate(Mod.getTypeSection())
101
6.59k
                   .map_error(ReportError(ASTNodeAttr::Sec_Type)));
102
6.59k
  EXPECTED_TRY(validate(Mod.getImportSection())
103
6.57k
                   .map_error(ReportError(ASTNodeAttr::Sec_Import)));
104
6.57k
  EXPECTED_TRY(validate(Mod.getFunctionSection())
105
6.57k
                   .map_error(ReportError(ASTNodeAttr::Sec_Function)));
106
6.57k
  EXPECTED_TRY(validate(Mod.getTableSection())
107
6.55k
                   .map_error(ReportError(ASTNodeAttr::Sec_Table)));
108
6.55k
  EXPECTED_TRY(validate(Mod.getMemorySection())
109
6.55k
                   .map_error(ReportError(ASTNodeAttr::Sec_Memory)));
110
6.55k
  EXPECTED_TRY(validate(Mod.getGlobalSection())
111
6.54k
                   .map_error(ReportError(ASTNodeAttr::Sec_Global)));
112
6.54k
  EXPECTED_TRY(validate(Mod.getTagSection())
113
6.54k
                   .map_error(ReportError(ASTNodeAttr::Sec_Tag)));
114
6.54k
  EXPECTED_TRY(validate(Mod.getExportSection())
115
6.54k
                   .map_error(ReportError(ASTNodeAttr::Sec_Export)));
116
6.54k
  EXPECTED_TRY(validate(Mod.getStartSection())
117
6.53k
                   .map_error(ReportError(ASTNodeAttr::Sec_Start)));
118
6.53k
  EXPECTED_TRY(validate(Mod.getElementSection())
119
6.53k
                   .map_error(ReportError(ASTNodeAttr::Sec_Element)));
120
6.53k
  EXPECTED_TRY(validate(Mod.getDataSection())
121
6.53k
                   .map_error(ReportError(ASTNodeAttr::Sec_Data)));
122
6.53k
  if (Checker.getTables().size() > 1 &&
123
1.56k
      !Conf.hasProposal(Proposal::ReferenceTypes)) {
124
0
    spdlog::error(ErrCode::Value::MultiTables);
125
0
    spdlog::error(ErrInfo::InfoProposal(Proposal::ReferenceTypes));
126
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
127
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
128
0
    return Unexpect(ErrCode::Value::MultiTables);
129
0
  }
130
6.53k
  if (Checker.getMemories().size() > 1 &&
131
1.07k
      !Conf.hasProposal(Proposal::MultiMemories)) {
132
0
    spdlog::error(ErrCode::Value::MultiMemories);
133
0
    spdlog::error(ErrInfo::InfoProposal(Proposal::MultiMemories));
134
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
135
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
136
0
    return Unexpect(ErrCode::Value::MultiMemories);
137
0
  }
138
6.53k
  DeferredModules.emplace_back(&Mod, Checker);
139
6.53k
  auto *Shape = CompCtx.addCoreShape();
140
6.53k
  EXPECTED_TRY(validate(Mod, *Shape));
141
6.52k
  CompCtx.getTop().addCoreModule(Shape);
142
6.52k
  return {};
143
6.53k
}
144
145
// External view of an inline core module: its imports and export types.
146
Expect<void> Validator::validate(const AST::Module &Mod,
147
6.53k
                                 Component::CoreShape &Out) noexcept {
148
6.53k
  const auto &ModTypes = Mod.getTypeSection().getContent();
149
150
6.53k
  auto GetSubType = [&ModTypes](uint32_t Idx) noexcept -> const AST::SubType * {
151
2.32k
    return Idx < ModTypes.size() ? &ModTypes[Idx] : nullptr;
152
2.32k
  };
153
154
  // Core index spaces: imports first, then definitions.
155
6.53k
  std::vector<Component::CoreExternInfo> Funcs, Tables, Memories, Globals, Tags;
156
6.53k
  for (const auto &Imp : Mod.getImportSection().getContent()) {
157
1.90k
    Component::CoreExternInfo Ext;
158
1.90k
    switch (Imp.getExternalType()) {
159
404
    case ExternalType::Function:
160
404
      Ext = Component::CoreExternInfo(ExternalType::Function,
161
404
                                      GetSubType(Imp.getExternalFuncTypeIdx()));
162
404
      Funcs.push_back(Ext);
163
404
      break;
164
26
    case ExternalType::Table:
165
26
      Ext = Component::CoreExternInfo(&Imp.getExternalTableType());
166
26
      Tables.push_back(Ext);
167
26
      break;
168
1.23k
    case ExternalType::Memory:
169
1.23k
      Ext = Component::CoreExternInfo(&Imp.getExternalMemoryType());
170
1.23k
      Memories.push_back(Ext);
171
1.23k
      break;
172
156
    case ExternalType::Global:
173
156
      Ext = Component::CoreExternInfo(&Imp.getExternalGlobalType());
174
156
      Globals.push_back(Ext);
175
156
      break;
176
85
    case ExternalType::Tag:
177
85
      Ext = Component::CoreExternInfo(
178
85
          ExternalType::Tag, GetSubType(Imp.getExternalTagType().getTypeIdx()));
179
85
      Tags.push_back(Ext);
180
85
      break;
181
0
    default:
182
0
      break;
183
1.90k
    }
184
1.90k
    for (const auto &[ModName, Name, Prev] : Out.Imports) {
185
641
      if (ModName == Imp.getModuleName() && Name == Imp.getExternalName()) {
186
10
        spdlog::error(ErrCode::Value::ComponentDuplicateImportName);
187
10
        spdlog::error("    Module import '{}'.'{}' name conflict."sv, ModName,
188
10
                      Name);
189
10
        return Unexpect(ErrCode::Value::ComponentDuplicateImportName);
190
10
      }
191
641
    }
192
1.89k
    Out.Imports.emplace_back(std::string(Imp.getModuleName()),
193
1.89k
                             std::string(Imp.getExternalName()), Ext);
194
1.89k
  }
195
6.52k
  for (const auto TIdx : Mod.getFunctionSection().getContent()) {
196
122
    Funcs.emplace_back(ExternalType::Function, GetSubType(TIdx));
197
122
  }
198
6.52k
  for (const auto &Seg : Mod.getTableSection().getContent()) {
199
3.26k
    Tables.emplace_back(&Seg.getTableType());
200
3.26k
  }
201
6.52k
  for (const auto &MT : Mod.getMemorySection().getContent()) {
202
2.68k
    Memories.emplace_back(&MT);
203
2.68k
  }
204
6.52k
  for (const auto &Seg : Mod.getGlobalSection().getContent()) {
205
613
    Globals.emplace_back(&Seg.getGlobalType());
206
613
  }
207
6.52k
  for (const auto &TT : Mod.getTagSection().getContent()) {
208
1.71k
    Tags.emplace_back(ExternalType::Tag, GetSubType(TT.getTypeIdx()));
209
1.71k
  }
210
211
6.52k
  for (const auto &Exp : Mod.getExportSection().getContent()) {
212
73
    const uint32_t Idx = Exp.getExternalIndex();
213
73
    Component::CoreExternInfo Ext;
214
73
    switch (Exp.getExternalType()) {
215
0
    case ExternalType::Function:
216
0
      if (Idx >= Funcs.size()) {
217
0
        continue;
218
0
      }
219
0
      Ext = Funcs[Idx];
220
0
      break;
221
0
    case ExternalType::Table:
222
0
      if (Idx >= Tables.size()) {
223
0
        continue;
224
0
      }
225
0
      Ext = Tables[Idx];
226
0
      break;
227
0
    case ExternalType::Memory:
228
0
      if (Idx >= Memories.size()) {
229
0
        continue;
230
0
      }
231
0
      Ext = Memories[Idx];
232
0
      break;
233
73
    case ExternalType::Global:
234
73
      if (Idx >= Globals.size()) {
235
0
        continue;
236
0
      }
237
73
      Ext = Globals[Idx];
238
73
      break;
239
0
    case ExternalType::Tag:
240
0
      if (Idx >= Tags.size()) {
241
0
        continue;
242
0
      }
243
0
      Ext = Tags[Idx];
244
0
      break;
245
0
    default:
246
0
      continue;
247
73
    }
248
73
    Out.Exports.emplace(std::string(Exp.getExternalName()), Ext);
249
73
  }
250
6.52k
  return {};
251
6.52k
}
252
253
Expect<void> Validator::validate(
254
84.4k
    const AST::Component::CoreInstanceSection &InstSec) noexcept {
255
84.4k
  for (const auto &Inst : InstSec.getContent()) {
256
82.3k
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
257
82.3k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreInstance));
258
82.3k
      return E;
259
82.3k
    }));
260
82.3k
  }
261
84.3k
  return {};
262
84.4k
}
263
264
Expect<void>
265
82.3k
Validator::validate(const AST::Component::CoreInstance &Inst) noexcept {
266
82.3k
  auto &S = CompCtx.getTop();
267
82.3k
  if (Inst.isInstantiateModule()) {
268
688
    const auto *Mod = S.getCoreModule(Inst.getModuleIndex());
269
688
    if (Mod == nullptr) {
270
22
      spdlog::error(ErrCode::Value::ComponentUnknownModule);
271
22
      spdlog::error("    Core module index {} out of bounds (size {})."sv,
272
22
                    Inst.getModuleIndex(), S.CoreModules.size());
273
22
      return Unexpect(ErrCode::Value::ComponentUnknownModule);
274
22
    }
275
    // Collect the named argument instances.
276
666
    std::unordered_map<std::string_view, const Component::CoreShape *> Args;
277
666
    for (const auto &Arg : Inst.getInstantiateArgs()) {
278
0
      const auto *AI = S.getCoreInstance(Arg.getIndex());
279
0
      if (AI == nullptr) {
280
0
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
281
0
        spdlog::error("    Core instance index {} out of bounds (size {})."sv,
282
0
                      Arg.getIndex(), S.CoreInstances.size());
283
0
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
284
0
      }
285
0
      if (!Args.emplace(Arg.getName(), AI).second) {
286
0
        spdlog::error(ErrCode::Value::ComponentDuplicateModuleArg);
287
0
        spdlog::error("    Duplicate instantiation argument '{}'."sv,
288
0
                      Arg.getName());
289
0
        return Unexpect(ErrCode::Value::ComponentDuplicateModuleArg);
290
0
      }
291
0
    }
292
    // Every module import must be satisfied by the matching argument.
293
666
    for (const auto &[ModName, Name, Required] : Mod->Imports) {
294
0
      auto It = Args.find(ModName);
295
0
      if (It == Args.end()) {
296
0
        spdlog::error(ErrCode::Value::ComponentMissingModuleArg);
297
0
        spdlog::error("    Missing instantiation argument '{}'."sv, ModName);
298
0
        return Unexpect(ErrCode::Value::ComponentMissingModuleArg);
299
0
      }
300
0
      auto ExpIt = It->second->Exports.find(Name);
301
0
      if (ExpIt == It->second->Exports.end()) {
302
0
        spdlog::error(ErrCode::Value::ComponentUnknownExport);
303
0
        spdlog::error(
304
0
            "    Instance argument '{}' does not export '{}' required by "
305
0
            "the module."sv,
306
0
            ModName, Name);
307
0
        return Unexpect(ErrCode::Value::ComponentUnknownExport);
308
0
      }
309
0
      const auto &Provided = ExpIt->second;
310
0
      if (Provided.Kind != Required.Kind) {
311
0
        ErrCode::Value Code = ErrCode::Value::ArgTypeMismatch;
312
0
        if (Required.Kind == ExternalType::Global) {
313
0
          Code = ErrCode::Value::ComponentExpectedGlobal;
314
0
        } else if (Required.Kind == ExternalType::Function) {
315
0
          Code = ErrCode::Value::ComponentExpectedFunc;
316
0
        }
317
0
        spdlog::error(Code);
318
0
        spdlog::error("    Import '{}'.'{}' kind mismatch."sv, ModName, Name);
319
0
        return Unexpect(Code);
320
0
      }
321
0
      if (!Component::Matcher::matchCoreExtern(Provided, Required)) {
322
        // Distinguish the mismatch class for diagnostics.
323
0
        ErrCode::Value Code = ErrCode::Value::ArgTypeMismatch;
324
0
        switch (Required.Kind) {
325
0
        case ExternalType::Function:
326
          // A trivial expected signature is reported as `expected: (func)`.
327
0
          if (Required.Func != nullptr &&
328
0
              Required.Func->getCompositeType().isFunc() &&
329
0
              Required.Func->getCompositeType()
330
0
                  .getFuncType()
331
0
                  .getParamTypes()
332
0
                  .empty() &&
333
0
              Required.Func->getCompositeType()
334
0
                  .getFuncType()
335
0
                  .getReturnTypes()
336
0
                  .empty()) {
337
0
            Code = ErrCode::Value::ComponentExpectedFuncParen;
338
0
          }
339
0
          break;
340
0
        case ExternalType::Memory:
341
0
          if (Provided.Memory != nullptr && Required.Memory != nullptr) {
342
0
            const auto &LP = Provided.Memory->getLimit();
343
0
            const auto &LR = Required.Memory->getLimit();
344
0
            if (LP.isShared() != LR.isShared()) {
345
0
              Code = ErrCode::Value::ComponentMemorySharedMismatch;
346
0
            } else if (LP.is64() != LR.is64()) {
347
0
              Code = ErrCode::Value::ComponentMemoryIndexTypeMismatch;
348
0
            } else {
349
0
              Code = ErrCode::Value::ComponentMemoryLimitsMismatch;
350
0
            }
351
0
          }
352
0
          break;
353
0
        case ExternalType::Global:
354
0
          Code = ErrCode::Value::ArgTypeMismatch;
355
0
          break;
356
0
        case ExternalType::Table:
357
0
          if (Provided.Table != nullptr && Required.Table != nullptr &&
358
0
              !(Provided.Table->getRefType() == Required.Table->getRefType())) {
359
0
            Code = ErrCode::Value::ArgTypeMismatch;
360
0
          } else {
361
0
            Code = ErrCode::Value::ComponentTableLimitsMismatch;
362
0
          }
363
0
          break;
364
0
        default:
365
0
          break;
366
0
        }
367
0
        spdlog::error(Code);
368
0
        spdlog::error("    Import '{}'.'{}' type mismatch."sv, ModName, Name);
369
0
        return Unexpect(Code);
370
0
      }
371
0
    }
372
    // The new core instance exposes the module's exports.
373
666
    auto *Result = CompCtx.addCoreShape();
374
666
    Result->Exports = Mod->Exports;
375
666
    S.addCoreInstance(Result);
376
666
    return {};
377
666
  }
378
379
  // Inline exports project index-space entries into a fresh core instance.
380
81.6k
  auto *Result = CompCtx.addCoreShape();
381
81.6k
  for (const auto &Exp : Inst.getInlineExports()) {
382
3.46k
    const auto &SI = Exp.getSortIdx();
383
3.46k
    const uint32_t Idx = SI.getIdx();
384
3.46k
    if (!SI.getSort().isCore()) {
385
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
386
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
387
0
    }
388
3.46k
    Component::CoreExternInfo Ext;
389
3.46k
    switch (SI.getSort().getCoreSortType()) {
390
3.40k
    case AST::Component::Sort::CoreSortType::Func: {
391
3.40k
      const auto *F = S.getCoreFunc(Idx);
392
3.40k
      if (F == nullptr) {
393
33
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
394
33
        spdlog::error("    Core function index {} out of bounds."sv, Idx);
395
33
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
396
33
      }
397
3.37k
      Ext = Component::CoreExternInfo(ExternalType::Function, F);
398
3.37k
      break;
399
3.40k
    }
400
4
    case AST::Component::Sort::CoreSortType::Table: {
401
4
      if (Idx >= S.CoreTables.size()) {
402
4
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
403
4
        spdlog::error("    Core table index {} out of bounds."sv, Idx);
404
4
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
405
4
      }
406
0
      Ext = Component::CoreExternInfo(S.CoreTables[Idx]);
407
0
      break;
408
4
    }
409
13
    case AST::Component::Sort::CoreSortType::Memory: {
410
13
      if (Idx >= S.CoreMemories.size()) {
411
13
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
412
13
        spdlog::error("    Core memory index {} out of bounds."sv, Idx);
413
13
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
414
13
      }
415
0
      Ext = Component::CoreExternInfo(S.CoreMemories[Idx]);
416
0
      break;
417
13
    }
418
20
    case AST::Component::Sort::CoreSortType::Global: {
419
20
      if (Idx >= S.CoreGlobals.size()) {
420
20
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
421
20
        spdlog::error("    Core global index {} out of bounds."sv, Idx);
422
20
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
423
20
      }
424
0
      Ext = Component::CoreExternInfo(S.CoreGlobals[Idx]);
425
0
      break;
426
20
    }
427
21
    case AST::Component::Sort::CoreSortType::Tag: {
428
21
      if (Idx >= S.CoreTags.size()) {
429
21
        spdlog::error(ErrCode::Value::UnknownCoreTag);
430
21
        spdlog::error("    Core tag index {} out of bounds."sv, Idx);
431
21
        return Unexpect(ErrCode::Value::UnknownCoreTag);
432
21
      }
433
0
      Ext = Component::CoreExternInfo(ExternalType::Tag, S.CoreTags[Idx]);
434
0
      break;
435
21
    }
436
2
    default:
437
2
      spdlog::error(ErrCode::Value::InvalidTypeReference);
438
2
      spdlog::error(
439
2
          "    Core instances can only export functions, tables, memories, "
440
2
          "globals, and tags."sv);
441
2
      return Unexpect(ErrCode::Value::InvalidTypeReference);
442
3.46k
    }
443
3.37k
    if (!Result->Exports.emplace(std::string(Exp.getName()), Ext).second) {
444
13
      spdlog::error(ErrCode::Value::DupExportName);
445
13
      spdlog::error("    Duplicate inline export name '{}'."sv, Exp.getName());
446
13
      return Unexpect(ErrCode::Value::DupExportName);
447
13
    }
448
3.37k
  }
449
81.5k
  S.addCoreInstance(Result);
450
81.5k
  return {};
451
81.6k
}
452
453
Expect<void>
454
188k
Validator::validate(const AST::Component::CoreTypeSection &TypeSec) noexcept {
455
188k
  for (const auto &Type : TypeSec.getContent()) {
456
142k
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
457
142k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreType));
458
142k
      return E;
459
142k
    }));
460
142k
  }
461
188k
  return {};
462
188k
}
463
464
Expect<void>
465
64.1k
Validator::validate(const AST::Component::ComponentSection &CompSec) noexcept {
466
64.1k
  auto *Shape = CompCtx.addShape();
467
64.1k
  EXPECTED_TRY(validate(CompSec.getContent(), *Shape).map_error([](auto E) {
468
64.1k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Component));
469
64.1k
    return E;
470
64.1k
  }));
471
64.1k
  CompCtx.getTop().addComponent(Shape);
472
64.1k
  return {};
473
64.1k
}
474
475
Expect<void>
476
2.12M
Validator::validate(const AST::Component::InstanceSection &InstSec) noexcept {
477
2.12M
  for (const auto &Inst : InstSec.getContent()) {
478
2.12M
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
479
2.12M
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Instance));
480
2.12M
      return E;
481
2.12M
    }));
482
2.12M
  }
483
2.12M
  return {};
484
2.12M
}
485
486
Expect<void>
487
2.12M
Validator::validate(const AST::Component::Instance &Inst) noexcept {
488
2.12M
  auto &S = CompCtx.getTop();
489
2.12M
  if (Inst.isInstantiateModule()) {
490
1.16M
    const auto *CI = S.getComponent(Inst.getComponentIndex());
491
1.16M
    if (CI == nullptr) {
492
45
      spdlog::error(ErrCode::Value::ComponentUnknownComponent);
493
45
      spdlog::error("    Component index {} out of bounds (size {})."sv,
494
45
                    Inst.getComponentIndex(), S.Components.size());
495
45
      return Unexpect(ErrCode::Value::ComponentUnknownComponent);
496
45
    }
497
1.16M
    EXPECTED_TRY(const auto *Result, CompCtx.instantiateComponentShape(
498
1.16M
                                         *CI, Inst.getInstantiateArgs()));
499
1.16M
    CompCtx.getTop().addInstance(Result);
500
1.16M
    return {};
501
1.16M
  }
502
503
  // Inline exports. Index validity is checked before the export name.
504
960k
  auto *Result = CompCtx.addShape();
505
960k
  Result->DeclScope = &S;
506
960k
  std::vector<Component::NameRecord> Names;
507
960k
  for (const auto &Exp : Inst.getInlineExports()) {
508
    // Function indices get their own diagnostic here.
509
567
    if (!Exp.getSortIdx().getSort().isCore() &&
510
562
        Exp.getSortIdx().getSort().getSortType() ==
511
562
            AST::Component::Sort::SortType::Func &&
512
93
        S.getFunc(Exp.getSortIdx().getIdx()) == nullptr) {
513
12
      spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
514
12
      spdlog::error("    Function index {} out of bounds (size {})."sv,
515
12
                    Exp.getSortIdx().getIdx(), S.Funcs.size());
516
12
      return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
517
12
    }
518
1.09k
    EXPECTED_TRY(auto Info, CompCtx.getExtern(Exp.getSortIdx()));
519
1.09k
    EXPECTED_TRY(Component::ExternName CN,
520
516
                 CompCtx.parseExternName(Exp.getName(), false));
521
516
    EXPECTED_TRY(
522
516
        CompCtx.addUniqueName(Names, Component::NameRecord(CN), false));
523
516
    EXPECTED_TRY(CompCtx.checkAnnotatedName(CN, Info, false));
524
511
    EXPECTED_TRY(CompCtx.checkNameAttributes(
525
510
        CN, Exp.getImplements(), Exp.getVersionSuffixes(),
526
510
        Info.Kind == Component::ExternKind::InstanceType));
527
510
    if (!Exp.getSortIdx().getSort().isCore() &&
528
510
        Exp.getSortIdx().getSort().getSortType() ==
529
510
            AST::Component::Sort::SortType::Value) {
530
28
      EXPECTED_TRY(CompCtx.getTop().consumeValue(Exp.getSortIdx().getIdx()));
531
28
    }
532
507
    Result->Exports.emplace(std::string(Exp.getName()), Info);
533
507
    Result->ExportOrder.emplace_back(Exp.getName());
534
507
  }
535
  // An inline instance nests re-exported shapes, so it is bounded like a type.
536
960k
  Component::ExternInfo Probe;
537
960k
  Probe.Kind = Component::ExternKind::InstanceType;
538
960k
  Probe.Shape = Result;
539
960k
  EXPECTED_TRY(CompCtx.checkTypeLimits(Probe));
540
960k
  CompCtx.getTop().addInstance(Result);
541
960k
  return {};
542
960k
}
543
544
Expect<void>
545
69.4k
Validator::validate(const AST::Component::AliasSection &AliasSec) noexcept {
546
69.4k
  for (const auto &Alias : AliasSec.getContent()) {
547
64.9k
    EXPECTED_TRY(validate(Alias).map_error([](auto E) {
548
64.9k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Alias));
549
64.9k
      return E;
550
64.9k
    }));
551
64.9k
  }
552
69.3k
  return {};
553
69.4k
}
554
555
66.0k
Expect<void> Validator::validate(const AST::Component::Alias &Alias) noexcept {
556
66.0k
  auto &S = CompCtx.getTop();
557
66.0k
  const auto &Sort = Alias.getSort();
558
66.0k
  const bool InTypeDecl = S.Kind == Component::ScopeKind::ComponentType ||
559
65.5k
                          S.Kind == Component::ScopeKind::InstanceType;
560
561
66.0k
  switch (Alias.getTargetType()) {
562
36
  case AST::Component::Alias::TargetType::Export: {
563
36
    if (Sort.isCore() &&
564
11
        Sort.getCoreSortType() != AST::Component::Sort::CoreSortType::Module) {
565
6
      spdlog::error(ErrCode::Value::MalformedAliasTarget);
566
6
      return Unexpect(ErrCode::Value::MalformedAliasTarget);
567
6
    }
568
30
    const bool WantCoreModule = Sort.isCore();
569
30
    if (InTypeDecl &&
570
7
        (WantCoreModule ||
571
6
         (Sort.getSortType() != AST::Component::Sort::SortType::Type &&
572
4
          Sort.getSortType() != AST::Component::Sort::SortType::Instance))) {
573
4
      spdlog::error(ErrCode::Value::InvalidTypeReference);
574
4
      spdlog::error("    Aliases in a component or instance type may only "
575
4
                    "refer to types or instances."sv);
576
4
      return Unexpect(ErrCode::Value::InvalidTypeReference);
577
4
    }
578
26
    const auto &[InstIdx, Name] = Alias.getExport();
579
26
    const auto *Inst = S.getInstance(InstIdx);
580
26
    if (Inst == nullptr) {
581
8
      spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
582
8
      spdlog::error("    Instance index {} out of bounds (size {})."sv, InstIdx,
583
8
                    S.Instances.size());
584
8
      return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
585
8
    }
586
18
    auto It = Inst->Exports.find(Name);
587
18
    if (WantCoreModule) {
588
      // Core-module exports of component instances.
589
3
      if (It == Inst->Exports.end() ||
590
3
          It->second.Kind != Component::ExternKind::CoreType) {
591
3
        spdlog::error(ErrCode::Value::ComponentExportNotAModule);
592
3
        spdlog::error("    Export '{}' of instance {} is not a core module."sv,
593
3
                      Name, InstIdx);
594
3
        return Unexpect(ErrCode::Value::ComponentExportNotAModule);
595
3
      }
596
0
      CompCtx.addExtern(It->second);
597
0
      return {};
598
3
    }
599
15
    if (It == Inst->Exports.end()) {
600
15
      spdlog::error(ErrCode::Value::ComponentUnknownExport);
601
15
      spdlog::error("    Instance {} has no export named '{}'."sv, InstIdx,
602
15
                    Name);
603
15
      return Unexpect(ErrCode::Value::ComponentUnknownExport);
604
15
    }
605
0
    const auto ST = Sort.getSortType();
606
0
    const auto &Info = It->second;
607
0
    const bool KindOk = (ST == AST::Component::Sort::SortType::Func &&
608
0
                         Info.Kind == Component::ExternKind::FuncType) ||
609
0
                        (ST == AST::Component::Sort::SortType::Value &&
610
0
                         Info.Kind == Component::ExternKind::ValueBound) ||
611
0
                        (ST == AST::Component::Sort::SortType::Type &&
612
0
                         Info.Kind == Component::ExternKind::TypeBound) ||
613
0
                        (ST == AST::Component::Sort::SortType::Component &&
614
0
                         Info.Kind == Component::ExternKind::ComponentType) ||
615
0
                        (ST == AST::Component::Sort::SortType::Instance &&
616
0
                         Info.Kind == Component::ExternKind::InstanceType);
617
0
    if (!KindOk) {
618
0
      spdlog::error(ErrCode::Value::ComponentUnknownExport);
619
0
      spdlog::error("    Export '{}' of instance {} does not match the "
620
0
                    "alias sort."sv,
621
0
                    Name, InstIdx);
622
0
      return Unexpect(ErrCode::Value::ComponentUnknownExport);
623
0
    }
624
0
    CompCtx.addExtern(Info);
625
0
    return {};
626
0
  }
627
330
  case AST::Component::Alias::TargetType::CoreExport: {
628
330
    if (!Sort.isCore()) {
629
2
      spdlog::error(ErrCode::Value::MalformedAliasTarget);
630
2
      return Unexpect(ErrCode::Value::MalformedAliasTarget);
631
2
    }
632
328
    if (InTypeDecl) {
633
1
      spdlog::error(ErrCode::Value::InvalidTypeReference);
634
1
      spdlog::error("    Aliases in a component or instance type may only "
635
1
                    "refer to types or instances."sv);
636
1
      return Unexpect(ErrCode::Value::InvalidTypeReference);
637
1
    }
638
327
    const auto &[InstIdx, Name] = Alias.getExport();
639
327
    const auto *Inst = S.getCoreInstance(InstIdx);
640
327
    if (Inst == nullptr) {
641
1
      spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
642
1
      spdlog::error("    Core instance index {} out of bounds (size {})."sv,
643
1
                    InstIdx, S.CoreInstances.size());
644
1
      return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
645
1
    }
646
326
    auto It = Inst->Exports.find(Name);
647
326
    const auto CS = Sort.getCoreSortType();
648
326
    if (It == Inst->Exports.end()) {
649
10
      const auto Code = CS == AST::Component::Sort::CoreSortType::Tag
650
10
                            ? ErrCode::Value::UnknownCoreTag
651
10
                            : ErrCode::Value::ComponentUnknownExport;
652
10
      spdlog::error(Code);
653
10
      spdlog::error("    Core instance {} has no export named '{}'."sv, InstIdx,
654
10
                    Name);
655
10
      return Unexpect(Code);
656
10
    }
657
316
    const auto &Ext = It->second;
658
316
    const bool KindOk = (CS == AST::Component::Sort::CoreSortType::Func &&
659
308
                         Ext.Kind == ExternalType::Function) ||
660
8
                        (CS == AST::Component::Sort::CoreSortType::Table &&
661
1
                         Ext.Kind == ExternalType::Table) ||
662
8
                        (CS == AST::Component::Sort::CoreSortType::Memory &&
663
1
                         Ext.Kind == ExternalType::Memory) ||
664
8
                        (CS == AST::Component::Sort::CoreSortType::Global &&
665
1
                         Ext.Kind == ExternalType::Global) ||
666
8
                        (CS == AST::Component::Sort::CoreSortType::Tag &&
667
1
                         Ext.Kind == ExternalType::Tag);
668
316
    if (!KindOk) {
669
8
      const auto Code = CS == AST::Component::Sort::CoreSortType::Tag
670
8
                            ? ErrCode::Value::UnknownCoreTag
671
8
                            : ErrCode::Value::InvalidTypeReference;
672
8
      spdlog::error(Code);
673
8
      spdlog::error("    Core export '{}' does not match the alias sort."sv,
674
8
                    Name);
675
8
      return Unexpect(Code);
676
8
    }
677
308
    S.addCoreExtern(Ext);
678
308
    return {};
679
316
  }
680
65.7k
  case AST::Component::Alias::TargetType::Outer: {
681
65.7k
    const auto &[Ct, Idx] = Alias.getOuter();
682
65.7k
    auto *Target = CompCtx.getScope(Ct);
683
65.7k
    if (Target == nullptr) {
684
31
      spdlog::error(ErrCode::Value::ComponentInvalidOuterAliasCount);
685
31
      spdlog::error("    Outer alias count {} exceeds enclosing scopes."sv, Ct);
686
31
      return Unexpect(ErrCode::Value::ComponentInvalidOuterAliasCount);
687
31
    }
688
65.6k
    if (Sort.isCore()) {
689
61.7k
      switch (Sort.getCoreSortType()) {
690
60.5k
      case AST::Component::Sort::CoreSortType::Module: {
691
60.5k
        if (InTypeDecl) {
692
1
          spdlog::error(ErrCode::Value::InvalidTypeReference);
693
1
          spdlog::error("    Aliases in a component or instance type may "
694
1
                        "only refer to types or instances."sv);
695
1
          return Unexpect(ErrCode::Value::InvalidTypeReference);
696
1
        }
697
60.5k
        const auto *Mod = Target->getCoreModule(Idx);
698
60.5k
        if (Mod == nullptr) {
699
21
          spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
700
21
          spdlog::error("    Aliased core module index {} out of bounds."sv,
701
21
                        Idx);
702
21
          return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
703
21
        }
704
60.5k
        S.addCoreModule(Mod);
705
60.5k
        return {};
706
60.5k
      }
707
1.19k
      case AST::Component::Sort::CoreSortType::Type: {
708
1.19k
        const auto *Entry = Target->getCoreType(Idx);
709
1.19k
        if (Entry == nullptr) {
710
21
          spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds);
711
21
          spdlog::error("    Aliased core type index {} out of bounds."sv, Idx);
712
21
          return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds);
713
21
        }
714
1.17k
        S.addCoreType(*Entry);
715
1.17k
        return {};
716
1.19k
      }
717
0
      default:
718
0
        spdlog::error(ErrCode::Value::MalformedAliasTarget);
719
0
        spdlog::error(
720
0
            "    Outer aliases may only target module, type, component."sv);
721
0
        return Unexpect(ErrCode::Value::MalformedAliasTarget);
722
61.7k
      }
723
61.7k
    }
724
3.90k
    switch (Sort.getSortType()) {
725
3.28k
    case AST::Component::Sort::SortType::Type: {
726
3.28k
      const auto *Entry = Target->getType(Idx);
727
3.28k
      if (Entry == nullptr) {
728
5
        spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds);
729
5
        spdlog::error("    Aliased type index {} out of bounds."sv, Idx);
730
5
        return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds);
731
5
      }
732
      // A type crossing a component boundary must carry no free resource id.
733
3.28k
      const auto *Inside = Ct == 0 ? nullptr : CompCtx.getScope(Ct - 1);
734
3.28k
      if (Inside != nullptr &&
735
955
          Inside->Kind == Component::ScopeKind::Component) {
736
0
        std::unordered_set<uint32_t> Ids;
737
0
        Component::ExternInfo Probe;
738
0
        Probe.Kind = Component::ExternKind::TypeBound;
739
0
        Probe.Type = *Entry;
740
0
        CompCtx.collectResources(Probe, Ids);
741
        // Ids bound by the aliased type itself are not free.
742
0
        const Component::Scope *Binder = nullptr;
743
0
        if (Entry->Inst != nullptr) {
744
0
          Binder = Entry->Inst->DeclScope;
745
0
        } else if (Entry->Comp != nullptr) {
746
0
          Binder = Entry->Comp->DeclScope;
747
0
        }
748
0
        bool HasFree = false;
749
0
        for (const uint32_t Id : Ids) {
750
0
          if (Binder == nullptr || !CompCtx.isDeclaredIn(Id, *Binder)) {
751
0
            HasFree = true;
752
0
            break;
753
0
          }
754
0
        }
755
0
        if (HasFree) {
756
0
          spdlog::error(ErrCode::Value::ComponentAliasResourceLeak);
757
0
          spdlog::error(
758
0
              "    Cannot alias an outer type which transitively refers to "
759
0
              "resources not defined in the current component."sv);
760
0
          return Unexpect(ErrCode::Value::ComponentAliasResourceLeak);
761
0
        }
762
0
      }
763
3.28k
      S.addType(*Entry);
764
3.28k
      return {};
765
3.28k
    }
766
613
    case AST::Component::Sort::SortType::Component: {
767
613
      if (InTypeDecl) {
768
1
        spdlog::error(ErrCode::Value::InvalidTypeReference);
769
1
        spdlog::error("    Aliases in a component or instance type may only "
770
1
                      "refer to types or instances."sv);
771
1
        return Unexpect(ErrCode::Value::InvalidTypeReference);
772
1
      }
773
612
      const auto *Comp = Target->getComponent(Idx);
774
612
      if (Comp == nullptr) {
775
26
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
776
26
        spdlog::error("    Aliased component index {} out of bounds."sv, Idx);
777
26
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
778
26
      }
779
586
      S.addComponent(Comp);
780
586
      return {};
781
612
    }
782
0
    default:
783
0
      spdlog::error(ErrCode::Value::MalformedAliasTarget);
784
0
      spdlog::error(
785
0
          "    Outer aliases may only target module, type, component."sv);
786
0
      return Unexpect(ErrCode::Value::MalformedAliasTarget);
787
3.90k
    }
788
3.90k
  }
789
0
  default:
790
0
    spdlog::error(ErrCode::Value::MalformedAliasTarget);
791
0
    return Unexpect(ErrCode::Value::MalformedAliasTarget);
792
66.0k
  }
793
66.0k
}
794
795
Expect<void>
796
6.07M
Validator::validate(const AST::Component::TypeSection &TypeSec) noexcept {
797
6.07M
  for (const auto &Type : TypeSec.getContent()) {
798
5.80M
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
799
5.80M
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Type));
800
5.80M
      return E;
801
5.80M
    }));
802
5.80M
  }
803
6.07M
  return {};
804
6.07M
}
805
806
Expect<void>
807
272k
Validator::validate(const AST::Component::CanonSection &CanonSec) noexcept {
808
275k
  for (const auto &Canon : CanonSec.getContent()) {
809
275k
    EXPECTED_TRY(validate(Canon).map_error([](auto E) {
810
275k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Canon));
811
275k
      return E;
812
275k
    }));
813
275k
  }
814
271k
  return {};
815
272k
}
816
817
Expect<void>
818
674
Validator::validate(const AST::Component::StartSection &StartSec) noexcept {
819
674
  const auto &Start = StartSec.getContent();
820
674
  auto &S = CompCtx.getTop();
821
674
  const auto *FI = S.getFunc(Start.getFunctionIndex());
822
674
  if (FI == nullptr || FI->FT == nullptr) {
823
20
    spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
824
20
    spdlog::error("    Start function index {} out of bounds (size {})."sv,
825
20
                  Start.getFunctionIndex(), S.Funcs.size());
826
20
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
827
20
    return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
828
20
  }
829
654
  const auto Params = FI->FT->getParamList();
830
654
  const auto Args = Start.getArguments();
831
654
  if (Params.size() != Args.size()) {
832
1
    spdlog::error(ErrCode::Value::ArgTypeMismatch);
833
1
    spdlog::error("    Start takes {} arguments but the function has {} "
834
1
                  "parameters."sv,
835
1
                  Args.size(), Params.size());
836
1
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
837
1
    return Unexpect(ErrCode::Value::ArgTypeMismatch);
838
1
  }
839
653
  for (size_t I = 0; I < Args.size(); ++I) {
840
0
    const uint32_t ValIdx = Args[I];
841
0
    if (ValIdx >= S.Values.size()) {
842
0
      spdlog::error(ErrCode::Value::InvalidIndex);
843
0
      spdlog::error("    Start argument value index {} out of bounds."sv,
844
0
                    ValIdx);
845
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
846
0
      return Unexpect(ErrCode::Value::InvalidIndex);
847
0
    }
848
0
    EXPECTED_TRY(S.consumeValue(ValIdx).map_error([ValIdx](auto E) {
849
0
      spdlog::error("    Start argument value {} was already consumed."sv,
850
0
                    ValIdx);
851
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
852
0
      return E;
853
0
    }));
854
0
    Component::ResourceMap Subst;
855
0
    if (!Component::Matcher::matchValType(
856
0
            CompCtx, S.Values[ValIdx].Type,
857
0
            {Params[I].getValType(), FI->Home, FI->Remap}, Subst)) {
858
0
      spdlog::error(ErrCode::Value::ArgTypeMismatch);
859
0
      spdlog::error("    Start argument {} type mismatch."sv, I);
860
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
861
0
      return Unexpect(ErrCode::Value::ArgTypeMismatch);
862
0
    }
863
0
  }
864
653
  const auto &Result = FI->FT->getResult();
865
653
  if (Start.getResult() != FI->FT->getResultArity()) {
866
4
    spdlog::error(ErrCode::Value::ArgTypeMismatch);
867
4
    spdlog::error("    Start declares {} results but the function has {}."sv,
868
4
                  Start.getResult(), FI->FT->getResultArity());
869
4
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
870
4
    return Unexpect(ErrCode::Value::ArgTypeMismatch);
871
4
  }
872
649
  if (Result.has_value()) {
873
330
    S.addValue({*Result, FI->Home, FI->Remap});
874
330
  }
875
649
  return {};
876
653
}
877
878
Expect<void> Validator::validate(const AST::Component::ImportSection &ImpSec,
879
97.8k
                                 Component::Shape &Out) noexcept {
880
97.8k
  for (const auto &Import : ImpSec.getContent()) {
881
8.27k
    EXPECTED_TRY(validate(Import, Out).map_error([](auto E) {
882
8.27k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Import));
883
8.27k
      return E;
884
8.27k
    }));
885
8.27k
  }
886
97.5k
  return {};
887
97.8k
}
888
889
Expect<void> Validator::validate(const AST::Component::Import &Im,
890
8.27k
                                 Component::Shape &Out) noexcept {
891
  // The descriptor is checked before the import name.
892
8.27k
  Component::ExternInfo Resolved;
893
8.27k
  EXPECTED_TRY(validate(Im.getDesc(), true, Resolved));
894
8.16k
  EXPECTED_TRY(auto Info,
895
7.92k
               CompCtx.addImport(Im.getName(), Resolved, Im.getImplements(),
896
7.92k
                                 Im.getVersionSuffixes()));
897
7.92k
  Out.Imports.emplace_back(std::string(Im.getName()), Info);
898
7.92k
  return {};
899
8.16k
}
900
901
Expect<void> Validator::validate(const AST::Component::ExportSection &ExpSec,
902
13.0k
                                 Component::Shape &Out) noexcept {
903
13.0k
  for (const auto &Export : ExpSec.getContent()) {
904
3.01k
    EXPECTED_TRY(validate(Export, Out).map_error([](auto E) {
905
3.01k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Export));
906
3.01k
      return E;
907
3.01k
    }));
908
3.01k
  }
909
12.5k
  return {};
910
13.0k
}
911
912
Expect<void> Validator::validate(const AST::Component::Export &Ex,
913
3.01k
                                 Component::Shape &Out) noexcept {
914
3.01k
  auto &S = CompCtx.getTop();
915
  // Index bounds are diagnosed before the name; a valid name refines the code.
916
3.01k
  {
917
3.01k
    const auto &SI = Ex.getSortIndex();
918
3.01k
    Component::ExternName CN;
919
3.01k
    const bool NameOk = CN.parse(Ex.getName()).has_value();
920
3.01k
    const uint32_t Idx = SI.getIdx();
921
3.01k
    bool OOB = false;
922
3.01k
    ErrCode::Value Code = ErrCode::Value::DefTypeIndexOutOfBounds;
923
3.01k
    if (SI.getSort().isCore()) {
924
25
      if (SI.getSort().getCoreSortType() ==
925
25
              AST::Component::Sort::CoreSortType::Module &&
926
22
          S.getCoreModule(Idx) == nullptr) {
927
22
        OOB = true;
928
22
        if (NameOk) {
929
1
          Code = ErrCode::Value::ComponentModuleIndexOutOfBounds;
930
1
        }
931
22
      }
932
2.99k
    } else {
933
2.99k
      switch (SI.getSort().getSortType()) {
934
117
      case AST::Component::Sort::SortType::Func:
935
117
        if (S.getFunc(Idx) == nullptr) {
936
40
          OOB = true;
937
40
          if (NameOk) {
938
7
            Code = ErrCode::Value::ComponentFunctionIndexOutOfBounds;
939
7
          }
940
40
        }
941
117
        break;
942
401
      case AST::Component::Sort::SortType::Instance:
943
401
        if (S.getInstance(Idx) == nullptr) {
944
110
          OOB = true;
945
110
          if (NameOk) {
946
8
            Code = ErrCode::Value::ComponentInstanceIndexOutOfBounds;
947
8
          }
948
110
        }
949
401
        break;
950
2.47k
      default:
951
2.47k
        break;
952
2.99k
      }
953
2.99k
    }
954
3.01k
    if (OOB) {
955
172
      spdlog::error(Code);
956
172
      spdlog::error("    Export index {} out of bounds."sv, Idx);
957
172
      return Unexpect(Code);
958
172
    }
959
3.01k
  }
960
5.55k
  EXPECTED_TRY(auto Inferred, CompCtx.getExtern(Ex.getSortIndex()));
961
  // Exporting a value consumes it.
962
5.55k
  if (!Ex.getSortIndex().getSort().isCore() &&
963
2.71k
      Ex.getSortIndex().getSort().getSortType() ==
964
2.71k
          AST::Component::Sort::SortType::Value) {
965
77
    const uint32_t ValIdx = Ex.getSortIndex().getIdx();
966
77
    EXPECTED_TRY(S.consumeValue(ValIdx).map_error([ValIdx](auto E) {
967
76
      spdlog::error("    Exported value {} was already consumed."sv, ValIdx);
968
76
      return E;
969
76
    }));
970
    // Exported values must not transitively contain borrow handles.
971
76
    if (CompCtx.hasBorrow(S.Values[ValIdx].Type)) {
972
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
973
0
      spdlog::error("    Exported value types cannot contain borrows."sv);
974
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
975
0
    }
976
76
  }
977
5.25k
  EXPECTED_TRY(Component::ExternName CN,
978
5.25k
               CompCtx.registerExportName(
979
5.25k
                   Ex.getName(),
980
5.25k
                   Inferred.Kind == Component::ExternKind::InstanceType,
981
5.25k
                   Ex.getImplements(), Ex.getVersionSuffixes()));
982
5.25k
  std::optional<Component::ExternInfo> Ascribed;
983
5.25k
  if (Ex.getDesc().has_value()) {
984
82
    EXPECTED_TRY(validate(*Ex.getDesc(), false, Ascribed.emplace()));
985
82
  }
986
2.54k
  EXPECTED_TRY(auto Result, CompCtx.addExport(CN, Inferred, Ascribed));
987
  // The re-exported value index is born consumed.
988
2.49k
  if (Result.Kind == Component::ExternKind::ValueBound) {
989
14
    CompCtx.getTop().Values.back().Consumed = true;
990
14
  }
991
2.49k
  Out.Exports.emplace(std::string(Ex.getName()), Result);
992
2.49k
  return {};
993
2.54k
}
994
995
Expect<void>
996
13.9k
Validator::validate(const AST::Component::ValueSection &ValSec) noexcept {
997
14.6k
  for (const auto &Value : ValSec.getContent()) {
998
14.6k
    EXPECTED_TRY(CompCtx.validate(Value.getType()).map_error([](auto E) {
999
14.6k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1000
14.6k
      return E;
1001
14.6k
    }));
1002
14.6k
    if (CompCtx.hasHandle({Value.getType(), &CompCtx.getTop(), nullptr})) {
1003
8
      spdlog::error(ErrCode::Value::ComponentValueHandleType);
1004
8
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1005
8
      return Unexpect(ErrCode::Value::ComponentValueHandleType);
1006
8
    }
1007
14.6k
    Component::ValueDecoder Decoder(Value.getData(), CompCtx.getTop());
1008
14.6k
    auto Decoded = Decoder.decode(Value.getType());
1009
14.6k
    if (!Decoded) {
1010
956
      spdlog::error(ErrCode::Value::ComponentMalformedValue);
1011
956
      spdlog::error("    Value definition payload does not match its type."sv);
1012
956
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1013
956
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
1014
956
    }
1015
13.6k
    Value.setDecoded(std::move(*Decoded));
1016
13.6k
    CompCtx.getTop().addValue({Value.getType(), &CompCtx.getTop(), nullptr});
1017
13.6k
  }
1018
12.9k
  return {};
1019
13.9k
}
1020
1021
} // namespace Validator
1022
} // namespace WasmEdge