Coverage Report

Created: 2026-09-28 06:22

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