Coverage Report

Created: 2026-11-09 06:49

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
6.53k
Validator::validate(const AST::Component::Component &Comp) noexcept {
27
6.53k
  CompCtx.reset();
28
6.53k
  DeferredModules.clear();
29
6.53k
  EXPECTED_TRY(validate(Comp, *CompCtx.addShape()));
30
  // Deferred function-body validation on the checker state saved per module.
31
4.04k
  for (auto &[Mod, Saved] : DeferredModules) {
32
4.04k
    Checker = std::move(Saved);
33
4.04k
    EXPECTED_TRY(validate(Mod->getCodeSection()).map_error([](auto E) {
34
4.03k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Code));
35
4.03k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
36
4.03k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
37
4.03k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
38
4.03k
      return E;
39
4.03k
    }));
40
4.03k
    const_cast<AST::Module &>(*Mod).setIsValidated();
41
4.03k
  }
42
2.89k
  const_cast<AST::Component::Component &>(Comp).setIsValidated();
43
2.89k
  return {};
44
2.90k
}
45
46
Expect<void> Validator::validate(const AST::Component::Component &Comp,
47
79.0k
                                 Component::Shape &Out) noexcept {
48
  // Walk the sections in binary order; a reference sees only earlier entries.
49
79.0k
  auto &S = CompCtx.pushScope(Component::ScopeKind::Component);
50
79.0k
  Out.DeclScope = &S;
51
52
79.0k
  auto ReportError = [](auto E) {
53
3.24k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
54
3.24k
    return E;
55
3.24k
  };
56
14.9M
  for (const auto &Sec : Comp.getSections()) {
57
14.9M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
14.9M
      using T = std::decay_t<decltype(Section)>;
59
14.9M
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
5.52M
        return {};
61
      } else if constexpr (std::is_same_v<T, AST::Component::ImportSection> ||
62
115k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
115k
        return validate(Section, Out).map_error(ReportError);
65
9.34M
      } else {
66
9.34M
        return validate(Section).map_error(ReportError);
67
9.34M
      }
68
14.9M
    };
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
5.52M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
5.52M
      using T = std::decay_t<decltype(Section)>;
59
5.52M
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
60
5.52M
        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
5.52M
    };
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
5.72k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
5.72k
      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
5.72k
      } else {
66
5.72k
        return validate(Section).map_error(ReportError);
67
5.72k
      }
68
5.72k
    };
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
121k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
121k
      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
121k
      } else {
66
121k
        return validate(Section).map_error(ReportError);
67
121k
      }
68
121k
    };
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
233k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
233k
      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
233k
      } else {
66
233k
        return validate(Section).map_error(ReportError);
67
233k
      }
68
233k
    };
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
72.5k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
72.5k
      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
72.5k
      } else {
66
72.5k
        return validate(Section).map_error(ReportError);
67
72.5k
      }
68
72.5k
    };
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.13M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
2.13M
      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.13M
      } else {
66
2.13M
        return validate(Section).map_error(ReportError);
67
2.13M
      }
68
2.13M
    };
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
82.5k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
82.5k
      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
82.5k
      } else {
66
82.5k
        return validate(Section).map_error(ReportError);
67
82.5k
      }
68
82.5k
    };
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.43M
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
6.43M
      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.43M
      } else {
66
6.43M
        return validate(Section).map_error(ReportError);
67
6.43M
      }
68
6.43M
    };
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
247k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
247k
      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
247k
      } else {
66
247k
        return validate(Section).map_error(ReportError);
67
247k
      }
68
247k
    };
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
753
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
753
      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
753
      } else {
66
753
        return validate(Section).map_error(ReportError);
67
753
      }
68
753
    };
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
104k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
104k
      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
104k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
104k
        return validate(Section, Out).map_error(ReportError);
65
      } else {
66
        return validate(Section).map_error(ReportError);
67
      }
68
104k
    };
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
11.2k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
11.2k
      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
11.2k
                           std::is_same_v<T, AST::Component::ExportSection>) {
63
        // These two accumulate into the component's own external type.
64
11.2k
        return validate(Section, Out).map_error(ReportError);
65
      } else {
66
        return validate(Section).map_error(ReportError);
67
      }
68
11.2k
    };
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
14.4k
    auto Visitor = [&](auto &&Section) -> Expect<void> {
58
14.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
14.4k
      } else {
66
14.4k
        return validate(Section).map_error(ReportError);
67
14.4k
      }
68
14.4k
    };
69
14.9M
    EXPECTED_TRY(std::visit(Visitor, Sec));
70
14.9M
  }
71
  // Value linearity. Every value must have exactly one consumer.
72
75.8k
  const auto &Values = S.Values;
73
75.8k
  for (uint32_t I = 0; I < Values.size(); ++I) {
74
428
    if (!Values[I].Consumed) {
75
391
      spdlog::error(ErrCode::Value::ComponentValueNotConsumed);
76
391
      spdlog::error("    Value index {} was not consumed before the end of the "
77
391
                    "component."sv,
78
391
                    I);
79
391
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
80
391
      return Unexpect(ErrCode::Value::ComponentValueNotConsumed);
81
391
    }
82
428
  }
83
75.4k
  CompCtx.popScope();
84
75.4k
  return {};
85
75.8k
}
86
87
Expect<void>
88
5.72k
Validator::validate(const AST::Component::CoreModuleSection &ModSec) noexcept {
89
  // Validate every section but the function bodies, which defer to the end.
90
5.72k
  const auto &Mod = ModSec.getContent();
91
5.72k
  Checker.reset(true);
92
62.5k
  auto ReportError = [](ASTNodeAttr Attr) {
93
62.5k
    return [Attr](auto E) {
94
69
      spdlog::error(ErrInfo::InfoAST(Attr));
95
69
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Module));
96
69
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
97
69
      return E;
98
69
    };
99
62.5k
  };
100
5.72k
  EXPECTED_TRY(validate(Mod.getTypeSection())
101
5.71k
                   .map_error(ReportError(ASTNodeAttr::Sec_Type)));
102
5.71k
  EXPECTED_TRY(validate(Mod.getImportSection())
103
5.70k
                   .map_error(ReportError(ASTNodeAttr::Sec_Import)));
104
5.70k
  EXPECTED_TRY(validate(Mod.getFunctionSection())
105
5.70k
                   .map_error(ReportError(ASTNodeAttr::Sec_Function)));
106
5.70k
  EXPECTED_TRY(validate(Mod.getTableSection())
107
5.68k
                   .map_error(ReportError(ASTNodeAttr::Sec_Table)));
108
5.68k
  EXPECTED_TRY(validate(Mod.getMemorySection())
109
5.68k
                   .map_error(ReportError(ASTNodeAttr::Sec_Memory)));
110
5.68k
  EXPECTED_TRY(validate(Mod.getGlobalSection())
111
5.67k
                   .map_error(ReportError(ASTNodeAttr::Sec_Global)));
112
5.67k
  EXPECTED_TRY(validate(Mod.getTagSection())
113
5.66k
                   .map_error(ReportError(ASTNodeAttr::Sec_Tag)));
114
5.66k
  EXPECTED_TRY(validate(Mod.getExportSection())
115
5.66k
                   .map_error(ReportError(ASTNodeAttr::Sec_Export)));
116
5.66k
  EXPECTED_TRY(validate(Mod.getStartSection())
117
5.66k
                   .map_error(ReportError(ASTNodeAttr::Sec_Start)));
118
5.66k
  EXPECTED_TRY(validate(Mod.getElementSection())
119
5.65k
                   .map_error(ReportError(ASTNodeAttr::Sec_Element)));
120
5.65k
  EXPECTED_TRY(validate(Mod.getDataSection())
121
5.65k
                   .map_error(ReportError(ASTNodeAttr::Sec_Data)));
122
5.65k
  if (Checker.getTables().size() > 1 &&
123
1.72k
      !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
5.65k
  if (Checker.getMemories().size() > 1 &&
131
682
      !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
5.65k
  DeferredModules.emplace_back(&Mod, Checker);
139
5.65k
  auto *Shape = CompCtx.addCoreShape();
140
5.65k
  EXPECTED_TRY(validate(Mod, *Shape));
141
5.65k
  CompCtx.getTop().addCoreModule(Shape);
142
5.65k
  return {};
143
5.65k
}
144
145
// External view of an inline core module: its imports and export types.
146
Expect<void> Validator::validate(const AST::Module &Mod,
147
5.65k
                                 Component::CoreShape &Out) noexcept {
148
5.65k
  const auto &ModTypes = Mod.getTypeSection().getContent();
149
150
5.65k
  auto GetSubType = [&ModTypes](uint32_t Idx) noexcept -> const AST::SubType * {
151
2.52k
    return Idx < ModTypes.size() ? &ModTypes[Idx] : nullptr;
152
2.52k
  };
153
154
  // Core index spaces: imports first, then definitions.
155
5.65k
  std::vector<Component::CoreExternInfo> Funcs, Tables, Memories, Globals, Tags;
156
5.65k
  for (const auto &Imp : Mod.getImportSection().getContent()) {
157
1.80k
    Component::CoreExternInfo Ext;
158
1.80k
    switch (Imp.getExternalType()) {
159
545
    case ExternalType::Function:
160
545
      Ext = Component::CoreExternInfo(ExternalType::Function,
161
545
                                      GetSubType(Imp.getExternalFuncTypeIdx()));
162
545
      Funcs.push_back(Ext);
163
545
      break;
164
27
    case ExternalType::Table:
165
27
      Ext = Component::CoreExternInfo(&Imp.getExternalTableType());
166
27
      Tables.push_back(Ext);
167
27
      break;
168
1.05k
    case ExternalType::Memory:
169
1.05k
      Ext = Component::CoreExternInfo(&Imp.getExternalMemoryType());
170
1.05k
      Memories.push_back(Ext);
171
1.05k
      break;
172
101
    case ExternalType::Global:
173
101
      Ext = Component::CoreExternInfo(&Imp.getExternalGlobalType());
174
101
      Globals.push_back(Ext);
175
101
      break;
176
76
    case ExternalType::Tag:
177
76
      Ext = Component::CoreExternInfo(
178
76
          ExternalType::Tag, GetSubType(Imp.getExternalTagType().getTypeIdx()));
179
76
      Tags.push_back(Ext);
180
76
      break;
181
0
    default:
182
0
      break;
183
1.80k
    }
184
1.80k
    for (const auto &[ModName, Name, Prev] : Out.Imports) {
185
545
      if (ModName == Imp.getModuleName() && Name == Imp.getExternalName()) {
186
5
        spdlog::error(ErrCode::Value::ComponentDuplicateImportName);
187
5
        spdlog::error("    Module import '{}'.'{}' name conflict."sv, ModName,
188
5
                      Name);
189
5
        return Unexpect(ErrCode::Value::ComponentDuplicateImportName);
190
5
      }
191
545
    }
192
1.79k
    Out.Imports.emplace_back(std::string(Imp.getModuleName()),
193
1.79k
                             std::string(Imp.getExternalName()), Ext);
194
1.79k
  }
195
5.65k
  for (const auto TIdx : Mod.getFunctionSection().getContent()) {
196
83
    Funcs.emplace_back(ExternalType::Function, GetSubType(TIdx));
197
83
  }
198
5.65k
  for (const auto &Seg : Mod.getTableSection().getContent()) {
199
3.53k
    Tables.emplace_back(&Seg.getTableType());
200
3.53k
  }
201
5.65k
  for (const auto &MT : Mod.getMemorySection().getContent()) {
202
1.44k
    Memories.emplace_back(&MT);
203
1.44k
  }
204
5.65k
  for (const auto &Seg : Mod.getGlobalSection().getContent()) {
205
418
    Globals.emplace_back(&Seg.getGlobalType());
206
418
  }
207
5.65k
  for (const auto &TT : Mod.getTagSection().getContent()) {
208
1.82k
    Tags.emplace_back(ExternalType::Tag, GetSubType(TT.getTypeIdx()));
209
1.82k
  }
210
211
5.65k
  for (const auto &Exp : Mod.getExportSection().getContent()) {
212
69
    const uint32_t Idx = Exp.getExternalIndex();
213
69
    Component::CoreExternInfo Ext;
214
69
    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
69
    case ExternalType::Global:
234
69
      if (Idx >= Globals.size()) {
235
0
        continue;
236
0
      }
237
69
      Ext = Globals[Idx];
238
69
      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
69
    }
248
69
    Out.Exports.emplace(std::string(Exp.getExternalName()), Ext);
249
69
  }
250
5.65k
  return {};
251
5.65k
}
252
253
Expect<void> Validator::validate(
254
121k
    const AST::Component::CoreInstanceSection &InstSec) noexcept {
255
121k
  for (const auto &Inst : InstSec.getContent()) {
256
117k
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
257
117k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreInstance));
258
117k
      return E;
259
117k
    }));
260
117k
  }
261
121k
  return {};
262
121k
}
263
264
Expect<void>
265
117k
Validator::validate(const AST::Component::CoreInstance &Inst) noexcept {
266
117k
  auto &S = CompCtx.getTop();
267
117k
  if (Inst.isInstantiateModule()) {
268
442
    const auto *Mod = S.getCoreModule(Inst.getModuleIndex());
269
442
    if (Mod == nullptr) {
270
17
      spdlog::error(ErrCode::Value::ComponentUnknownModule);
271
17
      spdlog::error("    Core module index {} out of bounds (size {})."sv,
272
17
                    Inst.getModuleIndex(), S.CoreModules.size());
273
17
      return Unexpect(ErrCode::Value::ComponentUnknownModule);
274
17
    }
275
    // Collect the named argument instances.
276
425
    std::unordered_map<std::string_view, const Component::CoreShape *> Args;
277
425
    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
425
    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
425
    auto *Result = CompCtx.addCoreShape();
374
425
    Result->Exports = Mod->Exports;
375
425
    S.addCoreInstance(Result);
376
425
    return {};
377
425
  }
378
379
  // Inline exports project index-space entries into a fresh core instance.
380
117k
  auto *Result = CompCtx.addCoreShape();
381
117k
  for (const auto &Exp : Inst.getInlineExports()) {
382
3.89k
    const auto &SI = Exp.getSortIdx();
383
3.89k
    const uint32_t Idx = SI.getIdx();
384
3.89k
    if (!SI.getSort().isCore()) {
385
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
386
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
387
0
    }
388
3.89k
    Component::CoreExternInfo Ext;
389
3.89k
    switch (SI.getSort().getCoreSortType()) {
390
3.84k
    case AST::Component::Sort::CoreSortType::Func: {
391
3.84k
      const auto *F = S.getCoreFunc(Idx);
392
3.84k
      if (F == nullptr) {
393
30
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
394
30
        spdlog::error("    Core function index {} out of bounds."sv, Idx);
395
30
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
396
30
      }
397
3.81k
      Ext = Component::CoreExternInfo(ExternalType::Function, F);
398
3.81k
      break;
399
3.84k
    }
400
12
    case AST::Component::Sort::CoreSortType::Table: {
401
12
      if (Idx >= S.CoreTables.size()) {
402
12
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
403
12
        spdlog::error("    Core table index {} out of bounds."sv, Idx);
404
12
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
405
12
      }
406
0
      Ext = Component::CoreExternInfo(S.CoreTables[Idx]);
407
0
      break;
408
12
    }
409
9
    case AST::Component::Sort::CoreSortType::Memory: {
410
9
      if (Idx >= S.CoreMemories.size()) {
411
9
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
412
9
        spdlog::error("    Core memory index {} out of bounds."sv, Idx);
413
9
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
414
9
      }
415
0
      Ext = Component::CoreExternInfo(S.CoreMemories[Idx]);
416
0
      break;
417
9
    }
418
8
    case AST::Component::Sort::CoreSortType::Global: {
419
8
      if (Idx >= S.CoreGlobals.size()) {
420
8
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
421
8
        spdlog::error("    Core global index {} out of bounds."sv, Idx);
422
8
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
423
8
      }
424
0
      Ext = Component::CoreExternInfo(S.CoreGlobals[Idx]);
425
0
      break;
426
8
    }
427
17
    case AST::Component::Sort::CoreSortType::Tag: {
428
17
      if (Idx >= S.CoreTags.size()) {
429
17
        spdlog::error(ErrCode::Value::UnknownCoreTag);
430
17
        spdlog::error("    Core tag index {} out of bounds."sv, Idx);
431
17
        return Unexpect(ErrCode::Value::UnknownCoreTag);
432
17
      }
433
0
      Ext = Component::CoreExternInfo(ExternalType::Tag, S.CoreTags[Idx]);
434
0
      break;
435
17
    }
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.89k
    }
443
3.81k
    if (!Result->Exports.emplace(std::string(Exp.getName()), Ext).second) {
444
8
      spdlog::error(ErrCode::Value::DupExportName);
445
8
      spdlog::error("    Duplicate inline export name '{}'."sv, Exp.getName());
446
8
      return Unexpect(ErrCode::Value::DupExportName);
447
8
    }
448
3.81k
  }
449
117k
  S.addCoreInstance(Result);
450
117k
  return {};
451
117k
}
452
453
Expect<void>
454
233k
Validator::validate(const AST::Component::CoreTypeSection &TypeSec) noexcept {
455
233k
  for (const auto &Type : TypeSec.getContent()) {
456
171k
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
457
171k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreType));
458
171k
      return E;
459
171k
    }));
460
171k
  }
461
233k
  return {};
462
233k
}
463
464
Expect<void>
465
72.5k
Validator::validate(const AST::Component::ComponentSection &CompSec) noexcept {
466
72.5k
  auto *Shape = CompCtx.addShape();
467
72.5k
  EXPECTED_TRY(validate(CompSec.getContent(), *Shape).map_error([](auto E) {
468
72.5k
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Component));
469
72.5k
    return E;
470
72.5k
  }));
471
72.5k
  CompCtx.getTop().addComponent(Shape);
472
72.5k
  return {};
473
72.5k
}
474
475
Expect<void>
476
2.13M
Validator::validate(const AST::Component::InstanceSection &InstSec) noexcept {
477
2.13M
  for (const auto &Inst : InstSec.getContent()) {
478
2.07M
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
479
2.07M
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Instance));
480
2.07M
      return E;
481
2.07M
    }));
482
2.07M
  }
483
2.13M
  return {};
484
2.13M
}
485
486
Expect<void>
487
2.07M
Validator::validate(const AST::Component::Instance &Inst) noexcept {
488
2.07M
  auto &S = CompCtx.getTop();
489
2.07M
  if (Inst.isInstantiateModule()) {
490
975k
    const auto *CI = S.getComponent(Inst.getComponentIndex());
491
975k
    if (CI == nullptr) {
492
48
      spdlog::error(ErrCode::Value::ComponentUnknownComponent);
493
48
      spdlog::error("    Component index {} out of bounds (size {})."sv,
494
48
                    Inst.getComponentIndex(), S.Components.size());
495
48
      return Unexpect(ErrCode::Value::ComponentUnknownComponent);
496
48
    }
497
975k
    EXPECTED_TRY(const auto *Result, CompCtx.instantiateComponentShape(
498
975k
                                         *CI, Inst.getInstantiateArgs()));
499
975k
    CompCtx.getTop().addInstance(Result);
500
975k
    return {};
501
975k
  }
502
503
  // Inline exports. Index validity is checked before the export name.
504
1.10M
  auto *Result = CompCtx.addShape();
505
1.10M
  Result->DeclScope = &S;
506
1.10M
  std::vector<Component::NameRecord> Names;
507
1.10M
  for (const auto &Exp : Inst.getInlineExports()) {
508
    // Function indices get their own diagnostic here.
509
533
    if (!Exp.getSortIdx().getSort().isCore() &&
510
531
        Exp.getSortIdx().getSort().getSortType() ==
511
531
            AST::Component::Sort::SortType::Func &&
512
120
        S.getFunc(Exp.getSortIdx().getIdx()) == nullptr) {
513
7
      spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
514
7
      spdlog::error("    Function index {} out of bounds (size {})."sv,
515
7
                    Exp.getSortIdx().getIdx(), S.Funcs.size());
516
7
      return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
517
7
    }
518
1.03k
    EXPECTED_TRY(auto Info, CompCtx.getExtern(Exp.getSortIdx()));
519
1.03k
    EXPECTED_TRY(Component::ExternName CN,
520
494
                 CompCtx.parseExternName(Exp.getName(), false));
521
494
    EXPECTED_TRY(
522
494
        CompCtx.addUniqueName(Names, Component::NameRecord(CN), false));
523
494
    EXPECTED_TRY(CompCtx.checkAnnotatedName(CN, Info, false));
524
493
    EXPECTED_TRY(CompCtx.checkNameAttributes(
525
493
        CN, Exp.getImplements(), Exp.getVersionSuffixes(),
526
493
        Info.Kind == Component::ExternKind::InstanceType));
527
493
    if (!Exp.getSortIdx().getSort().isCore() &&
528
493
        Exp.getSortIdx().getSort().getSortType() ==
529
493
            AST::Component::Sort::SortType::Value) {
530
23
      EXPECTED_TRY(CompCtx.getTop().consumeValue(Exp.getSortIdx().getIdx()));
531
23
    }
532
492
    Result->Exports.emplace(std::string(Exp.getName()), Info);
533
492
    Result->ExportOrder.emplace_back(Exp.getName());
534
492
  }
535
  // An inline instance nests re-exported shapes, so it is bounded like a type.
536
1.10M
  Component::ExternInfo Probe;
537
1.10M
  Probe.Kind = Component::ExternKind::InstanceType;
538
1.10M
  Probe.Shape = Result;
539
1.10M
  EXPECTED_TRY(CompCtx.checkTypeLimits(Probe));
540
1.10M
  CompCtx.getTop().addInstance(Result);
541
1.10M
  return {};
542
1.10M
}
543
544
Expect<void>
545
82.5k
Validator::validate(const AST::Component::AliasSection &AliasSec) noexcept {
546
82.5k
  for (const auto &Alias : AliasSec.getContent()) {
547
78.0k
    EXPECTED_TRY(validate(Alias).map_error([](auto E) {
548
78.0k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Alias));
549
78.0k
      return E;
550
78.0k
    }));
551
78.0k
  }
552
82.4k
  return {};
553
82.5k
}
554
555
79.0k
Expect<void> Validator::validate(const AST::Component::Alias &Alias) noexcept {
556
79.0k
  auto &S = CompCtx.getTop();
557
79.0k
  const auto &Sort = Alias.getSort();
558
79.0k
  const bool InTypeDecl = S.Kind == Component::ScopeKind::ComponentType ||
559
78.5k
                          S.Kind == Component::ScopeKind::InstanceType;
560
561
79.0k
  switch (Alias.getTargetType()) {
562
29
  case AST::Component::Alias::TargetType::Export: {
563
29
    if (Sort.isCore() &&
564
13
        Sort.getCoreSortType() != AST::Component::Sort::CoreSortType::Module) {
565
7
      spdlog::error(ErrCode::Value::MalformedAliasTarget);
566
7
      return Unexpect(ErrCode::Value::MalformedAliasTarget);
567
7
    }
568
22
    const bool WantCoreModule = Sort.isCore();
569
22
    if (InTypeDecl &&
570
6
        (WantCoreModule ||
571
5
         (Sort.getSortType() != AST::Component::Sort::SortType::Type &&
572
3
          Sort.getSortType() != AST::Component::Sort::SortType::Instance))) {
573
3
      spdlog::error(ErrCode::Value::InvalidTypeReference);
574
3
      spdlog::error("    Aliases in a component or instance type may only "
575
3
                    "refer to types or instances."sv);
576
3
      return Unexpect(ErrCode::Value::InvalidTypeReference);
577
3
    }
578
19
    const auto &[InstIdx, Name] = Alias.getExport();
579
19
    const auto *Inst = S.getInstance(InstIdx);
580
19
    if (Inst == nullptr) {
581
11
      spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
582
11
      spdlog::error("    Instance index {} out of bounds (size {})."sv, InstIdx,
583
11
                    S.Instances.size());
584
11
      return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
585
11
    }
586
8
    auto It = Inst->Exports.find(Name);
587
8
    if (WantCoreModule) {
588
      // Core-module exports of component instances.
589
2
      if (It == Inst->Exports.end() ||
590
2
          It->second.Kind != Component::ExternKind::CoreType) {
591
2
        spdlog::error(ErrCode::Value::ComponentExportNotAModule);
592
2
        spdlog::error("    Export '{}' of instance {} is not a core module."sv,
593
2
                      Name, InstIdx);
594
2
        return Unexpect(ErrCode::Value::ComponentExportNotAModule);
595
2
      }
596
0
      CompCtx.addExtern(It->second);
597
0
      return {};
598
2
    }
599
6
    if (It == Inst->Exports.end()) {
600
6
      spdlog::error(ErrCode::Value::ComponentUnknownExport);
601
6
      spdlog::error("    Instance {} has no export named '{}'."sv, InstIdx,
602
6
                    Name);
603
6
      return Unexpect(ErrCode::Value::ComponentUnknownExport);
604
6
    }
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
300
  case AST::Component::Alias::TargetType::CoreExport: {
628
300
    if (!Sort.isCore()) {
629
3
      spdlog::error(ErrCode::Value::MalformedAliasTarget);
630
3
      return Unexpect(ErrCode::Value::MalformedAliasTarget);
631
3
    }
632
297
    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
296
    const auto &[InstIdx, Name] = Alias.getExport();
639
296
    const auto *Inst = S.getCoreInstance(InstIdx);
640
296
    if (Inst == nullptr) {
641
3
      spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
642
3
      spdlog::error("    Core instance index {} out of bounds (size {})."sv,
643
3
                    InstIdx, S.CoreInstances.size());
644
3
      return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
645
3
    }
646
293
    auto It = Inst->Exports.find(Name);
647
293
    const auto CS = Sort.getCoreSortType();
648
293
    if (It == Inst->Exports.end()) {
649
12
      const auto Code = CS == AST::Component::Sort::CoreSortType::Tag
650
12
                            ? ErrCode::Value::UnknownCoreTag
651
12
                            : ErrCode::Value::ComponentUnknownExport;
652
12
      spdlog::error(Code);
653
12
      spdlog::error("    Core instance {} has no export named '{}'."sv, InstIdx,
654
12
                    Name);
655
12
      return Unexpect(Code);
656
12
    }
657
281
    const auto &Ext = It->second;
658
281
    const bool KindOk = (CS == AST::Component::Sort::CoreSortType::Func &&
659
269
                         Ext.Kind == ExternalType::Function) ||
660
12
                        (CS == AST::Component::Sort::CoreSortType::Table &&
661
2
                         Ext.Kind == ExternalType::Table) ||
662
12
                        (CS == AST::Component::Sort::CoreSortType::Memory &&
663
2
                         Ext.Kind == ExternalType::Memory) ||
664
12
                        (CS == AST::Component::Sort::CoreSortType::Global &&
665
1
                         Ext.Kind == ExternalType::Global) ||
666
12
                        (CS == AST::Component::Sort::CoreSortType::Tag &&
667
1
                         Ext.Kind == ExternalType::Tag);
668
281
    if (!KindOk) {
669
12
      const auto Code = CS == AST::Component::Sort::CoreSortType::Tag
670
12
                            ? ErrCode::Value::UnknownCoreTag
671
12
                            : ErrCode::Value::InvalidTypeReference;
672
12
      spdlog::error(Code);
673
12
      spdlog::error("    Core export '{}' does not match the alias sort."sv,
674
12
                    Name);
675
12
      return Unexpect(Code);
676
12
    }
677
269
    S.addCoreExtern(Ext);
678
269
    return {};
679
281
  }
680
78.6k
  case AST::Component::Alias::TargetType::Outer: {
681
78.6k
    const auto &[Ct, Idx] = Alias.getOuter();
682
78.6k
    auto *Target = CompCtx.getScope(Ct);
683
78.6k
    if (Target == nullptr) {
684
24
      spdlog::error(ErrCode::Value::ComponentInvalidOuterAliasCount);
685
24
      spdlog::error("    Outer alias count {} exceeds enclosing scopes."sv, Ct);
686
24
      return Unexpect(ErrCode::Value::ComponentInvalidOuterAliasCount);
687
24
    }
688
78.6k
    if (Sort.isCore()) {
689
72.7k
      switch (Sort.getCoreSortType()) {
690
71.1k
      case AST::Component::Sort::CoreSortType::Module: {
691
71.1k
        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
71.1k
        const auto *Mod = Target->getCoreModule(Idx);
698
71.1k
        if (Mod == nullptr) {
699
10
          spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
700
10
          spdlog::error("    Aliased core module index {} out of bounds."sv,
701
10
                        Idx);
702
10
          return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
703
10
        }
704
71.1k
        S.addCoreModule(Mod);
705
71.1k
        return {};
706
71.1k
      }
707
1.59k
      case AST::Component::Sort::CoreSortType::Type: {
708
1.59k
        const auto *Entry = Target->getCoreType(Idx);
709
1.59k
        if (Entry == nullptr) {
710
19
          spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds);
711
19
          spdlog::error("    Aliased core type index {} out of bounds."sv, Idx);
712
19
          return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds);
713
19
        }
714
1.57k
        S.addCoreType(*Entry);
715
1.57k
        return {};
716
1.59k
      }
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
72.7k
      }
723
72.7k
    }
724
5.89k
    switch (Sort.getSortType()) {
725
5.25k
    case AST::Component::Sort::SortType::Type: {
726
5.25k
      const auto *Entry = Target->getType(Idx);
727
5.25k
      if (Entry == nullptr) {
728
14
        spdlog::error(ErrCode::Value::ComponentTypeIndexOutOfBounds);
729
14
        spdlog::error("    Aliased type index {} out of bounds."sv, Idx);
730
14
        return Unexpect(ErrCode::Value::ComponentTypeIndexOutOfBounds);
731
14
      }
732
      // A type crossing a component boundary must carry no free resource id.
733
5.24k
      const auto *Inside = Ct == 0 ? nullptr : CompCtx.getScope(Ct - 1);
734
5.24k
      if (Inside != nullptr &&
735
852
          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
5.24k
      S.addType(*Entry);
764
5.24k
      return {};
765
5.24k
    }
766
639
    case AST::Component::Sort::SortType::Component: {
767
639
      if (InTypeDecl) {
768
2
        spdlog::error(ErrCode::Value::InvalidTypeReference);
769
2
        spdlog::error("    Aliases in a component or instance type may only "
770
2
                      "refer to types or instances."sv);
771
2
        return Unexpect(ErrCode::Value::InvalidTypeReference);
772
2
      }
773
637
      const auto *Comp = Target->getComponent(Idx);
774
637
      if (Comp == nullptr) {
775
25
        spdlog::error(ErrCode::Value::DefTypeIndexOutOfBounds);
776
25
        spdlog::error("    Aliased component index {} out of bounds."sv, Idx);
777
25
        return Unexpect(ErrCode::Value::DefTypeIndexOutOfBounds);
778
25
      }
779
612
      S.addComponent(Comp);
780
612
      return {};
781
637
    }
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
5.89k
    }
788
5.89k
  }
789
0
  default:
790
0
    spdlog::error(ErrCode::Value::MalformedAliasTarget);
791
0
    return Unexpect(ErrCode::Value::MalformedAliasTarget);
792
79.0k
  }
793
79.0k
}
794
795
Expect<void>
796
6.43M
Validator::validate(const AST::Component::TypeSection &TypeSec) noexcept {
797
6.43M
  for (const auto &Type : TypeSec.getContent()) {
798
6.07M
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
799
6.07M
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Type));
800
6.07M
      return E;
801
6.07M
    }));
802
6.07M
  }
803
6.43M
  return {};
804
6.43M
}
805
806
Expect<void>
807
247k
Validator::validate(const AST::Component::CanonSection &CanonSec) noexcept {
808
254k
  for (const auto &Canon : CanonSec.getContent()) {
809
254k
    EXPECTED_TRY(validate(Canon).map_error([](auto E) {
810
254k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Canon));
811
254k
      return E;
812
254k
    }));
813
254k
  }
814
247k
  return {};
815
247k
}
816
817
Expect<void>
818
753
Validator::validate(const AST::Component::StartSection &StartSec) noexcept {
819
753
  const auto &Start = StartSec.getContent();
820
753
  auto &S = CompCtx.getTop();
821
753
  const auto *FI = S.getFunc(Start.getFunctionIndex());
822
753
  if (FI == nullptr || FI->FT == nullptr) {
823
38
    spdlog::error(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
824
38
    spdlog::error("    Start function index {} out of bounds (size {})."sv,
825
38
                  Start.getFunctionIndex(), S.Funcs.size());
826
38
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
827
38
    return Unexpect(ErrCode::Value::ComponentFunctionIndexOutOfBounds);
828
38
  }
829
715
  const auto Params = FI->FT->getParamList();
830
715
  const auto Args = Start.getArguments();
831
715
  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
714
  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
714
  const auto &Result = FI->FT->getResult();
865
714
  if (Start.getResult() != FI->FT->getResultArity()) {
866
6
    spdlog::error(ErrCode::Value::ArgTypeMismatch);
867
6
    spdlog::error("    Start declares {} results but the function has {}."sv,
868
6
                  Start.getResult(), FI->FT->getResultArity());
869
6
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Start));
870
6
    return Unexpect(ErrCode::Value::ArgTypeMismatch);
871
6
  }
872
708
  if (Result.has_value()) {
873
272
    S.addValue({*Result, FI->Home, FI->Remap});
874
272
  }
875
708
  return {};
876
714
}
877
878
Expect<void> Validator::validate(const AST::Component::ImportSection &ImpSec,
879
104k
                                 Component::Shape &Out) noexcept {
880
104k
  for (const auto &Import : ImpSec.getContent()) {
881
7.74k
    EXPECTED_TRY(validate(Import, Out).map_error([](auto E) {
882
7.74k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Import));
883
7.74k
      return E;
884
7.74k
    }));
885
7.74k
  }
886
103k
  return {};
887
104k
}
888
889
Expect<void> Validator::validate(const AST::Component::Import &Im,
890
7.74k
                                 Component::Shape &Out) noexcept {
891
  // The descriptor is checked before the import name.
892
7.74k
  Component::ExternInfo Resolved;
893
7.74k
  EXPECTED_TRY(validate(Im.getDesc(), true, Resolved));
894
7.65k
  EXPECTED_TRY(auto Info,
895
7.43k
               CompCtx.addImport(Im.getName(), Resolved, Im.getImplements(),
896
7.43k
                                 Im.getVersionSuffixes()));
897
7.43k
  Out.Imports.emplace_back(std::string(Im.getName()), Info);
898
7.43k
  return {};
899
7.65k
}
900
901
Expect<void> Validator::validate(const AST::Component::ExportSection &ExpSec,
902
11.2k
                                 Component::Shape &Out) noexcept {
903
11.2k
  for (const auto &Export : ExpSec.getContent()) {
904
2.88k
    EXPECTED_TRY(validate(Export, Out).map_error([](auto E) {
905
2.88k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Export));
906
2.88k
      return E;
907
2.88k
    }));
908
2.88k
  }
909
10.7k
  return {};
910
11.2k
}
911
912
Expect<void> Validator::validate(const AST::Component::Export &Ex,
913
2.88k
                                 Component::Shape &Out) noexcept {
914
2.88k
  auto &S = CompCtx.getTop();
915
  // Index bounds are diagnosed before the name; a valid name refines the code.
916
2.88k
  {
917
2.88k
    const auto &SI = Ex.getSortIndex();
918
2.88k
    Component::ExternName CN;
919
2.88k
    const bool NameOk = CN.parse(Ex.getName()).has_value();
920
2.88k
    const uint32_t Idx = SI.getIdx();
921
2.88k
    bool OOB = false;
922
2.88k
    ErrCode::Value Code = ErrCode::Value::DefTypeIndexOutOfBounds;
923
2.88k
    if (SI.getSort().isCore()) {
924
25
      if (SI.getSort().getCoreSortType() ==
925
25
              AST::Component::Sort::CoreSortType::Module &&
926
19
          S.getCoreModule(Idx) == nullptr) {
927
19
        OOB = true;
928
19
        if (NameOk) {
929
1
          Code = ErrCode::Value::ComponentModuleIndexOutOfBounds;
930
1
        }
931
19
      }
932
2.86k
    } else {
933
2.86k
      switch (SI.getSort().getSortType()) {
934
113
      case AST::Component::Sort::SortType::Func:
935
113
        if (S.getFunc(Idx) == nullptr) {
936
31
          OOB = true;
937
31
          if (NameOk) {
938
6
            Code = ErrCode::Value::ComponentFunctionIndexOutOfBounds;
939
6
          }
940
31
        }
941
113
        break;
942
392
      case AST::Component::Sort::SortType::Instance:
943
392
        if (S.getInstance(Idx) == nullptr) {
944
163
          OOB = true;
945
163
          if (NameOk) {
946
19
            Code = ErrCode::Value::ComponentInstanceIndexOutOfBounds;
947
19
          }
948
163
        }
949
392
        break;
950
2.35k
      default:
951
2.35k
        break;
952
2.86k
      }
953
2.86k
    }
954
2.88k
    if (OOB) {
955
213
      spdlog::error(Code);
956
213
      spdlog::error("    Export index {} out of bounds."sv, Idx);
957
213
      return Unexpect(Code);
958
213
    }
959
2.88k
  }
960
5.23k
  EXPECTED_TRY(auto Inferred, CompCtx.getExtern(Ex.getSortIndex()));
961
  // Exporting a value consumes it.
962
5.23k
  if (!Ex.getSortIndex().getSort().isCore() &&
963
2.56k
      Ex.getSortIndex().getSort().getSortType() ==
964
2.56k
          AST::Component::Sort::SortType::Value) {
965
87
    const uint32_t ValIdx = Ex.getSortIndex().getIdx();
966
87
    EXPECTED_TRY(S.consumeValue(ValIdx).map_error([ValIdx](auto E) {
967
85
      spdlog::error("    Exported value {} was already consumed."sv, ValIdx);
968
85
      return E;
969
85
    }));
970
    // Exported values must not transitively contain borrow handles.
971
85
    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
85
  }
977
4.95k
  EXPECTED_TRY(Component::ExternName CN,
978
4.95k
               CompCtx.registerExportName(
979
4.95k
                   Ex.getName(),
980
4.95k
                   Inferred.Kind == Component::ExternKind::InstanceType,
981
4.95k
                   Ex.getImplements(), Ex.getVersionSuffixes()));
982
4.95k
  std::optional<Component::ExternInfo> Ascribed;
983
4.95k
  if (Ex.getDesc().has_value()) {
984
86
    EXPECTED_TRY(validate(*Ex.getDesc(), false, Ascribed.emplace()));
985
86
  }
986
2.38k
  EXPECTED_TRY(auto Result, CompCtx.addExport(CN, Inferred, Ascribed));
987
  // The re-exported value index is born consumed.
988
2.34k
  if (Result.Kind == Component::ExternKind::ValueBound) {
989
17
    CompCtx.getTop().Values.back().Consumed = true;
990
17
  }
991
2.34k
  Out.Exports.emplace(std::string(Ex.getName()), Result);
992
2.34k
  return {};
993
2.38k
}
994
995
Expect<void>
996
14.4k
Validator::validate(const AST::Component::ValueSection &ValSec) noexcept {
997
15.1k
  for (const auto &Value : ValSec.getContent()) {
998
15.1k
    EXPECTED_TRY(CompCtx.validate(Value.getType()).map_error([](auto E) {
999
15.1k
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1000
15.1k
      return E;
1001
15.1k
    }));
1002
15.1k
    if (CompCtx.hasHandle({Value.getType(), &CompCtx.getTop(), nullptr})) {
1003
11
      spdlog::error(ErrCode::Value::ComponentValueHandleType);
1004
11
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1005
11
      return Unexpect(ErrCode::Value::ComponentValueHandleType);
1006
11
    }
1007
15.1k
    Component::ValueDecoder Decoder(Value.getData(), CompCtx.getTop());
1008
15.1k
    auto Decoded = Decoder.decode(Value.getType());
1009
15.1k
    if (!Decoded) {
1010
948
      spdlog::error(ErrCode::Value::ComponentMalformedValue);
1011
948
      spdlog::error("    Value definition payload does not match its type."sv);
1012
948
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Value));
1013
948
      return Unexpect(ErrCode::Value::ComponentMalformedValue);
1014
948
    }
1015
14.1k
    Value.setDecoded(std::move(*Decoded));
1016
14.1k
    CompCtx.getTop().addValue({Value.getType(), &CompCtx.getTop(), nullptr});
1017
14.1k
  }
1018
13.4k
  return {};
1019
14.4k
}
1020
1021
} // namespace Validator
1022
} // namespace WasmEdge