Coverage Report

Created: 2025-12-31 06:34

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: 2019-2024 Second State INC
3
4
#include "common/errinfo.h"
5
#include "common/spdlog.h"
6
#include "validator/validator.h"
7
8
#include <variant>
9
10
namespace WasmEdge {
11
namespace Validator {
12
13
using namespace std::literals;
14
15
Expect<void>
16
0
Validator::validate(const AST::Component::Component &Comp) noexcept {
17
0
  spdlog::warn("Component Model Validation is in active development."sv);
18
0
  CompCtx.reset();
19
0
  return validateComponent(Comp).and_then([&]() {
20
0
    const_cast<AST::Component::Component &>(Comp).setIsValidated();
21
0
    return Expect<void>{};
22
0
  });
23
0
}
24
25
Expect<void>
26
0
Validator::validateComponent(const AST::Component::Component &Comp) noexcept {
27
0
  auto ReportError = [](auto E) {
28
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Component));
29
0
    return E;
30
0
  };
31
32
0
  CompCtx.enterComponent(Comp);
33
0
  for (const auto &Sec : Comp.getSections()) {
34
0
    auto Func = [&](auto &&S) -> Expect<void> {
35
0
      using T = std::decay_t<decltype(S)>;
36
0
      if constexpr (std::is_same_v<T, AST::CustomSection>) {
37
        // Always pass validation.
38
0
      } else {
39
0
        EXPECTED_TRY(validate(S).map_error(ReportError));
40
0
      }
41
0
      return {};
42
0
    };
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::CustomSection const&>(WasmEdge::AST::CustomSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::CoreModuleSection const&>(WasmEdge::AST::Component::CoreModuleSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::CoreInstanceSection const&>(WasmEdge::AST::Component::CoreInstanceSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::CoreTypeSection const&>(WasmEdge::AST::Component::CoreTypeSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::ComponentSection const&>(WasmEdge::AST::Component::ComponentSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::InstanceSection const&>(WasmEdge::AST::Component::InstanceSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::AliasSection const&>(WasmEdge::AST::Component::AliasSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::TypeSection const&>(WasmEdge::AST::Component::TypeSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::CanonSection const&>(WasmEdge::AST::Component::CanonSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::StartSection const&>(WasmEdge::AST::Component::StartSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::ImportSection const&>(WasmEdge::AST::Component::ImportSection const&) const
Unexecuted instantiation: component_validator.cpp:cxx20::expected<void, WasmEdge::ErrCode> WasmEdge::Validator::Validator::validateComponent(WasmEdge::AST::Component::Component const&)::$_0::operator()<WasmEdge::AST::Component::ExportSection const&>(WasmEdge::AST::Component::ExportSection const&) const
43
0
    EXPECTED_TRY(std::visit(Func, Sec));
44
0
  }
45
0
  CompCtx.exitComponent();
46
0
  return {};
47
0
}
48
49
Expect<void>
50
0
Validator::validate(const AST::Component::CoreModuleSection &ModSec) noexcept {
51
0
  EXPECTED_TRY(validate(ModSec.getContent()).map_error([](auto E) {
52
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreMod));
53
0
    return E;
54
0
  }));
55
0
  CompCtx.incCoreSortIndexSize(AST::Component::Sort::CoreSortType::Module);
56
0
  const_cast<AST::Module &>(ModSec.getContent()).setIsValidated();
57
0
  CompCtx.addCoreModule(ModSec.getContent());
58
0
  return {};
59
0
}
60
61
Expect<void> Validator::validate(
62
0
    const AST::Component::CoreInstanceSection &InstSec) noexcept {
63
0
  for (const auto &Inst : InstSec.getContent()) {
64
0
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
65
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreInstance));
66
0
      return E;
67
0
    }));
68
0
  }
69
0
  return {};
70
0
}
71
72
Expect<void>
73
0
Validator::validate(const AST::Component::CoreTypeSection &TypeSec) noexcept {
74
0
  for (const auto &Type : TypeSec.getContent()) {
75
0
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
76
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_CoreType));
77
0
      return E;
78
0
    }));
79
0
  }
80
0
  return {};
81
0
}
82
83
Expect<void>
84
0
Validator::validate(const AST::Component::ComponentSection &CompSec) noexcept {
85
0
  EXPECTED_TRY(validateComponent(CompSec.getContent()).map_error([](auto E) {
86
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Component));
87
0
    return E;
88
0
  }));
89
0
  CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Component);
90
0
  return {};
91
0
}
92
93
Expect<void>
94
0
Validator::validate(const AST::Component::InstanceSection &InstSec) noexcept {
95
0
  for (const auto &Inst : InstSec.getContent()) {
96
0
    EXPECTED_TRY(validate(Inst).map_error([](auto E) {
97
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Instance));
98
0
      return E;
99
0
    }));
100
0
  }
101
0
  return {};
102
0
}
103
104
Expect<void>
105
0
Validator::validate(const AST::Component::AliasSection &AliasSec) noexcept {
106
0
  for (const auto &Alias : AliasSec.getContent()) {
107
0
    EXPECTED_TRY(validate(Alias).map_error([](auto E) {
108
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Alias));
109
0
      return E;
110
0
    }));
111
0
    const auto &Sort = Alias.getSort();
112
0
    if (Sort.isCore()) {
113
0
      CompCtx.incCoreSortIndexSize(Sort.getCoreSortType());
114
0
    } else {
115
0
      CompCtx.incSortIndexSize(Sort.getSortType());
116
0
    }
117
0
  }
118
0
  return {};
119
0
}
120
121
Expect<void>
122
0
Validator::validate(const AST::Component::TypeSection &TypeSec) noexcept {
123
0
  for (const auto &Type : TypeSec.getContent()) {
124
0
    EXPECTED_TRY(validate(Type).map_error([](auto E) {
125
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Type));
126
0
      return E;
127
0
    }));
128
0
  }
129
0
  return {};
130
0
}
131
132
Expect<void>
133
0
Validator::validate(const AST::Component::CanonSection &CanonSec) noexcept {
134
  // TODO: Validation prevents duplicate or conflicting canonopt.
135
0
  for (const auto &C : CanonSec.getContent()) {
136
0
    EXPECTED_TRY(validate(C).map_error([](auto E) {
137
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Canon));
138
0
      return E;
139
0
    }));
140
0
  }
141
0
  return {};
142
0
}
143
144
Expect<void>
145
0
Validator::validate(const AST::Component::StartSection &) noexcept {
146
  // TODO: Validation requires f have functype with param arity and types
147
  // matching arg* and result arity r.
148
149
  // TODO: Validation appends the result types of f to the value index space
150
  // (making them available for reference by subsequent definitions).
151
152
  // TODO: In addition to the type-compatibility checks mentioned above, the
153
  // validation rules for value definitions additionally require that each
154
  // value is consumed exactly once. Thus, during validation, each value has
155
  // an associated "consumed" boolean flag. When a value is first added to
156
  // the value index space (via import, instance, alias or start), the flag
157
  // is clear. When a value is used (via export, instantiate or start), the
158
  // flag is set. After validating the last definition of a component,
159
  // validation requires all values' flags are set.
160
0
  return {};
161
0
}
162
163
Expect<void>
164
0
Validator::validate(const AST::Component::ImportSection &ImpSec) noexcept {
165
0
  for (const auto &Imp : ImpSec.getContent()) {
166
0
    EXPECTED_TRY(validate(Imp).map_error([](auto E) {
167
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Import));
168
0
      return E;
169
0
    }));
170
0
  }
171
0
  return {};
172
0
}
173
174
Expect<void>
175
0
Validator::validate(const AST::Component::ExportSection &ExpSec) noexcept {
176
0
  for (const auto &Exp : ExpSec.getContent()) {
177
0
    EXPECTED_TRY(validate(Exp).map_error([](auto E) {
178
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Sec_Export));
179
0
      return E;
180
0
    }));
181
0
  }
182
0
  return {};
183
0
}
184
185
Expect<void>
186
0
Validator::validate(const AST::Component::CoreInstance &Inst) noexcept {
187
0
  if (Inst.isInstantiateModule()) {
188
    // Instantiate module case.
189
190
    // Check the module index bound first.
191
0
    const uint32_t ModIdx = Inst.getModuleIndex();
192
0
    if (ModIdx >= CompCtx.getCoreModuleCount()) {
193
0
      spdlog::error(ErrCode::Value::InvalidIndex);
194
0
      spdlog::error(
195
0
          "    CoreInstance: Module index {} exceeds available core modules {}"sv,
196
0
          ModIdx, CompCtx.getCoreModuleCount());
197
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_CoreInstance));
198
0
      return Unexpect(ErrCode::Value::InvalidIndex);
199
0
    }
200
    // Get the import descriptors of the module to instantiate.
201
0
    const auto &Mod = CompCtx.getCoreModule(ModIdx);
202
0
    const auto &ImportDescs = Mod.getImportSection().getContent();
203
    // Get the instantiate args.
204
0
    auto Args = Inst.getInstantiateArgs();
205
    // Check the import module names are supplied from the instantiate args.
206
0
    for (const auto &Import : ImportDescs) {
207
0
      auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) {
208
0
        return Arg.getName() == Import.getModuleName();
209
0
      });
210
0
      if (ArgIt == Args.end()) {
211
0
        spdlog::error(ErrCode::Value::MissingArgument);
212
0
        spdlog::error(
213
0
            "    CoreInstance: Module index {} missing argument for import '{}'"sv,
214
0
            Inst.getModuleIndex(), Import.getModuleName());
215
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_CoreInstance));
216
0
        return Unexpect(ErrCode::Value::MissingArgument);
217
0
      }
218
0
    }
219
    // Add the module exports and bind to the core:instance index.
220
0
    uint32_t InstanceIdx = CompCtx.getCoreSortIndexSize(
221
0
        AST::Component::Sort::CoreSortType::Instance);
222
0
    const auto &ExportDescs = Mod.getExportSection().getContent();
223
0
    for (const auto &ExportDesc : ExportDescs) {
224
0
      CompCtx.addCoreInstanceExport(InstanceIdx, ExportDesc.getExternalName(),
225
0
                                    ExportDesc.getExternalType());
226
0
    }
227
0
  } else if (Inst.isInlineExport()) {
228
    // Inline export case.
229
230
    // Check the core:sort index bound of the inline exports.
231
0
    for (const auto &Export : Inst.getInlineExports()) {
232
0
      const auto &Sort = Export.getSortIdx().getSort();
233
0
      uint32_t Idx = Export.getSortIdx().getIdx();
234
0
      assuming(Sort.isCore());
235
0
      if (Idx >= CompCtx.getCoreSortIndexSize(Sort.getCoreSortType())) {
236
0
        spdlog::error(ErrCode::Value::InvalidIndex);
237
0
        spdlog::error(
238
0
            "    CoreInstance: Inline export '{}' refers to invalid index {}"sv,
239
0
            Export.getName(), Idx);
240
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_CoreInstance));
241
0
        return Unexpect(ErrCode::Value::InvalidIndex);
242
0
      }
243
0
    }
244
0
  } else {
245
0
    assumingUnreachable();
246
0
  }
247
  // Increase the sort index of the core:instance.
248
0
  CompCtx.incCoreSortIndexSize(AST::Component::Sort::CoreSortType::Instance);
249
0
  return {};
250
0
}
251
252
Expect<void>
253
0
Validator::validate(const AST::Component::Instance &Inst) noexcept {
254
0
  if (Inst.isInstantiateModule()) {
255
    // Instantiate module case.
256
257
    // Check the component index bound first.
258
0
    const uint32_t CompIdx = Inst.getComponentIndex();
259
0
    if (CompIdx >= CompCtx.getComponentCount()) {
260
0
      spdlog::error(ErrCode::Value::InvalidIndex);
261
0
      spdlog::error(
262
0
          "    Instance: Component index {} exceeds available components {}"sv,
263
0
          CompIdx, CompCtx.getComponentCount());
264
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
265
0
      return Unexpect(ErrCode::Value::InvalidIndex);
266
0
    }
267
    // Get the imports of the component to instantiate.
268
0
    const auto &Comp = CompCtx.getComponent(CompIdx);
269
    // Prepare the import descriptor map.
270
    // TODO: move this to the context.
271
0
    std::unordered_map<std::string, const AST::Component::ExternDesc *>
272
0
        ImportMap;
273
0
    for (const auto &Sec : Comp.getSections()) {
274
0
      if (std::holds_alternative<AST::Component::ImportSection>(Sec)) {
275
0
        const auto &ImportSec = std::get<AST::Component::ImportSection>(Sec);
276
0
        for (const auto &Import : ImportSec.getContent()) {
277
          // TODO: strongly-unique problem of the import name.
278
0
          ImportMap[std::string(Import.getName())] = &Import.getDesc();
279
0
        }
280
0
      }
281
0
    }
282
    // Get the instantiate args.
283
0
    auto Args = Inst.getInstantiateArgs();
284
    // Check the import names are supplied from the instantiate args.
285
0
    for (auto It = ImportMap.begin(); It != ImportMap.end(); ++It) {
286
0
      const auto &ImportName = It->first;
287
0
      const auto &ImportDesc = *It->second;
288
0
      auto ArgIt = std::find_if(Args.begin(), Args.end(), [&](const auto &Arg) {
289
0
        return Arg.getName() == ImportName;
290
0
      });
291
0
      if (ArgIt == Args.end()) {
292
0
        spdlog::error(ErrCode::Value::MissingArgument);
293
0
        spdlog::error(
294
0
            "    Instance: Component index {} missing argument for import '{}'"sv,
295
0
            Inst.getComponentIndex(), ImportName);
296
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
297
0
        return Unexpect(ErrCode::Value::MissingArgument);
298
0
      }
299
300
0
      const auto &Sort = ArgIt->getIndex().getSort();
301
0
      const uint32_t Idx = ArgIt->getIndex().getIdx();
302
303
0
      if (Sort.isCore()) {
304
        // Check the import descriptor type matches the core:sort type.
305
0
        bool IsMatched = false;
306
0
        switch (ImportDesc.getDescType()) {
307
0
        case AST::Component::ExternDesc::DescType::CoreType:
308
0
          IsMatched = Sort.getCoreSortType() ==
309
0
                      AST::Component::Sort::CoreSortType::Type;
310
0
          break;
311
0
        case AST::Component::ExternDesc::DescType::FuncType:
312
0
          IsMatched = Sort.getCoreSortType() ==
313
0
                      AST::Component::Sort::CoreSortType::Func;
314
0
          break;
315
0
        case AST::Component::ExternDesc::DescType::ValueBound:
316
0
          IsMatched = Sort.getCoreSortType() ==
317
0
                          AST::Component::Sort::CoreSortType::Func ||
318
0
                      Sort.getCoreSortType() ==
319
0
                          AST::Component::Sort::CoreSortType::Table ||
320
0
                      Sort.getCoreSortType() ==
321
0
                          AST::Component::Sort::CoreSortType::Memory ||
322
0
                      Sort.getCoreSortType() ==
323
0
                          AST::Component::Sort::CoreSortType::Global;
324
0
          break;
325
0
        case AST::Component::ExternDesc::DescType::TypeBound:
326
0
          IsMatched = Sort.getCoreSortType() ==
327
0
                          AST::Component::Sort::CoreSortType::Module ||
328
0
                      Sort.getCoreSortType() ==
329
0
                          AST::Component::Sort::CoreSortType::Instance;
330
0
          break;
331
0
        case AST::Component::ExternDesc::DescType::ComponentType:
332
0
          IsMatched = Sort.getCoreSortType() ==
333
0
                      AST::Component::Sort::CoreSortType::Module;
334
0
          break;
335
0
        case AST::Component::ExternDesc::DescType::InstanceType:
336
0
          IsMatched = Sort.getCoreSortType() ==
337
0
                      AST::Component::Sort::CoreSortType::Instance;
338
0
          break;
339
0
        default:
340
0
          break;
341
0
        }
342
0
        if (!IsMatched) {
343
          // TODO: print types to string
344
0
          spdlog::error(ErrCode::Value::ArgTypeMismatch);
345
0
          spdlog::error(
346
0
              "    Instance: Component index {} Argument '{}' type mismatch"sv,
347
0
              Inst.getComponentIndex(), ImportName);
348
0
          return Unexpect(ErrCode::Value::ArgTypeMismatch);
349
0
        }
350
        // Check the core:sort index bound of the args.
351
0
        if (Idx >= CompCtx.getCoreSortIndexSize(Sort.getCoreSortType())) {
352
0
          spdlog::error(ErrCode::Value::InvalidIndex);
353
0
          spdlog::error(
354
0
              "    Instance: Argument '{}' refers to invalid index {}"sv,
355
0
              ImportName, Idx);
356
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
357
0
          return Unexpect(ErrCode::Value::InvalidIndex);
358
0
        }
359
0
      } else {
360
        // Check the import descriptor type matches the sort type.
361
0
        bool IsMatched = false;
362
0
        switch (ImportDesc.getDescType()) {
363
0
        case AST::Component::ExternDesc::DescType::CoreType:
364
0
          IsMatched =
365
0
              Sort.getSortType() == AST::Component::Sort::SortType::Type;
366
0
          break;
367
0
        case AST::Component::ExternDesc::DescType::FuncType:
368
0
          IsMatched =
369
0
              Sort.getSortType() == AST::Component::Sort::SortType::Func;
370
0
          break;
371
0
        case AST::Component::ExternDesc::DescType::ValueBound:
372
0
          IsMatched =
373
0
              Sort.getSortType() == AST::Component::Sort::SortType::Value;
374
0
          break;
375
0
        case AST::Component::ExternDesc::DescType::TypeBound:
376
0
          IsMatched =
377
0
              Sort.getSortType() == AST::Component::Sort::SortType::Type;
378
0
          break;
379
0
        case AST::Component::ExternDesc::DescType::ComponentType:
380
0
          IsMatched =
381
0
              Sort.getSortType() == AST::Component::Sort::SortType::Component;
382
0
          break;
383
0
        case AST::Component::ExternDesc::DescType::InstanceType:
384
0
          IsMatched =
385
0
              Sort.getSortType() == AST::Component::Sort::SortType::Instance;
386
0
          break;
387
0
        default:
388
0
          break;
389
0
        }
390
0
        if (!IsMatched) {
391
          // TODO: print types to string
392
0
          spdlog::error(ErrCode::Value::ArgTypeMismatch);
393
0
          spdlog::error(
394
0
              "    Instance: Component index {} Argument '{}' type mismatch"sv,
395
0
              Inst.getComponentIndex(), ImportName);
396
0
          return Unexpect(ErrCode::Value::ArgTypeMismatch);
397
0
        }
398
        // Check the sort index bound of the args.
399
0
        if (Idx >= CompCtx.getSortIndexSize(Sort.getSortType())) {
400
0
          spdlog::error(ErrCode::Value::InvalidIndex);
401
0
          spdlog::error(
402
0
              "    Instance: Argument '{}' refers to invalid index {}"sv,
403
0
              ImportName, Idx);
404
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
405
0
          return Unexpect(ErrCode::Value::InvalidIndex);
406
0
        }
407
0
        if (Sort.getSortType() == AST::Component::Sort::SortType::Type &&
408
0
            ImportDesc.getDescType() ==
409
0
                AST::Component::ExternDesc::DescType::TypeBound) {
410
0
          CompCtx.substituteTypeImport(ImportName, Idx);
411
0
        }
412
0
      }
413
0
    }
414
0
  } else if (Inst.isInlineExport()) {
415
    // Inline export case.
416
417
    // Check the sort index bound of the inline exports.
418
0
    for (const auto &Export : Inst.getInlineExports()) {
419
0
      const auto &Sort = Export.getSortIdx().getSort();
420
0
      uint32_t Idx = Export.getSortIdx().getIdx();
421
0
      if (Sort.isCore()) {
422
0
        if (Idx >= CompCtx.getCoreSortIndexSize(Sort.getCoreSortType())) {
423
0
          spdlog::error(ErrCode::Value::InvalidIndex);
424
0
          spdlog::error(
425
0
              "    Instance: Inline export '{}' refers to invalid index {}"sv,
426
0
              Export.getName(), Idx);
427
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
428
0
          return Unexpect(ErrCode::Value::InvalidIndex);
429
0
        }
430
0
      } else {
431
0
        if (Idx >= CompCtx.getSortIndexSize(Sort.getSortType())) {
432
0
          spdlog::error(ErrCode::Value::InvalidIndex);
433
0
          spdlog::error(
434
0
              "    Instance: Inline export '{}' refers to invalid index {}"sv,
435
0
              Export.getName(), Idx);
436
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Instance));
437
0
          return Unexpect(ErrCode::Value::InvalidIndex);
438
0
        }
439
0
        if (Sort.getSortType() == AST::Component::Sort::SortType::Type) {
440
0
          auto SubstitutedIdx =
441
0
              CompCtx.getSubstitutedType(std::string(Export.getName()));
442
0
          if (SubstitutedIdx.has_value() && Idx != SubstitutedIdx.value()) {
443
0
            spdlog::error(ErrCode::Value::InvalidTypeReference);
444
0
            spdlog::error(
445
0
                "    Instance: Inline export '{}' type index {} does not match substituted type index {}"sv,
446
0
                Export.getName(), Idx, *SubstitutedIdx);
447
0
            return Unexpect(ErrCode::Value::InvalidTypeReference);
448
0
          }
449
0
        }
450
0
      }
451
0
    }
452
0
  } else {
453
0
    assumingUnreachable();
454
0
  }
455
  // Increase the sort index of the instance.
456
0
  CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Instance);
457
0
  return {};
458
0
}
459
460
0
Expect<void> Validator::validate(const AST::Component::Alias &Alias) noexcept {
461
0
  const auto &Sort = Alias.getSort();
462
0
  switch (Alias.getTargetType()) {
463
0
  case AST::Component::Alias::TargetType::Export: {
464
0
    const auto Idx = Alias.getExport().first;
465
0
    const auto &Name = Alias.getExport().second;
466
0
    const auto &CompExports = CompCtx.getComponentInstanceExports(Idx);
467
468
0
    if (Sort.isCore()) {
469
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
470
0
      spdlog::error("    Alias export: Mapping an export '{}' to core:sort"sv,
471
0
                    Name);
472
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
473
0
    }
474
475
0
    if (Idx >= CompCtx.getComponentInstanceExportsSize()) {
476
0
      spdlog::error(ErrCode::Value::InvalidIndex);
477
0
      spdlog::error(
478
0
          "    Alias export: Export index {} exceeds available component instance index {}"sv,
479
0
          Idx, CompCtx.getComponentInstanceExportsSize());
480
0
      return Unexpect(ErrCode::Value::InvalidIndex);
481
0
    }
482
483
0
    auto It = CompExports.find(Name);
484
0
    if (It == CompExports.cend()) {
485
0
      spdlog::error(ErrCode::Value::ExportNotFound);
486
0
      spdlog::error(
487
0
          "    Alias export: No matching export '{}' found in component instance index {}"sv,
488
0
          Name, Idx);
489
0
      return Unexpect(ErrCode::Value::ExportNotFound);
490
0
    }
491
492
0
    const auto *ExternDesc = It->second;
493
0
    AST::Component::Sort::SortType ST;
494
0
    switch (ExternDesc->getDescType()) {
495
0
    case AST::Component::ExternDesc::DescType::FuncType:
496
0
      ST = AST::Component::Sort::SortType::Func;
497
0
      break;
498
0
    case AST::Component::ExternDesc::DescType::ValueBound:
499
0
    case AST::Component::ExternDesc::DescType::TypeBound:
500
0
      ST = AST::Component::Sort::SortType::Type;
501
0
      break;
502
0
    case AST::Component::ExternDesc::DescType::ComponentType:
503
0
      ST = AST::Component::Sort::SortType::Component;
504
0
      break;
505
0
    case AST::Component::ExternDesc::DescType::InstanceType:
506
0
      ST = AST::Component::Sort::SortType::Instance;
507
0
      break;
508
0
    case AST::Component::ExternDesc::DescType::CoreType:
509
0
    default:
510
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
511
0
      spdlog::error("    Alias export: Type mapping mismatch for export '{}'"sv,
512
0
                    Name);
513
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
514
0
    }
515
0
    if (ST != Sort.getSortType()) {
516
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
517
0
      spdlog::error("    Alias export: Type mapping mismatch for export '{}'"sv,
518
0
                    Name);
519
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
520
0
    }
521
0
    return {};
522
0
  }
523
0
  case AST::Component::Alias::TargetType::CoreExport: {
524
0
    const auto Idx = Alias.getExport().first;
525
0
    const auto &Name = Alias.getExport().second;
526
0
    const auto &CoreExports = CompCtx.getCoreInstanceExports(Idx);
527
528
0
    if (!Sort.isCore()) {
529
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
530
0
      spdlog::error("    Alias core:export: Mapping a export '{}' to sort"sv,
531
0
                    Name);
532
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
533
0
    }
534
535
0
    if (Idx >= CompCtx.getCoreInstanceExportsSize()) {
536
0
      spdlog::error(ErrCode::Value::InvalidIndex);
537
0
      spdlog::error(
538
0
          "    Alias core:export: Export index {} exceeds available core instance index {}"sv,
539
0
          Idx, CompCtx.getCoreInstanceExportsSize() - 1);
540
0
      return Unexpect(ErrCode::Value::InvalidIndex);
541
0
    }
542
543
0
    auto It = CoreExports.find(Name);
544
0
    if (It == CoreExports.end()) {
545
0
      spdlog::error(ErrCode::Value::ExportNotFound);
546
0
      spdlog::error(
547
0
          "    Alias core:export: No matching export '{}' found in core instance index {}"sv,
548
0
          Name, Idx);
549
0
      return Unexpect(ErrCode::Value::ExportNotFound);
550
0
    }
551
552
0
    const auto ExternTy = It->second;
553
0
    AST::Component::Sort::CoreSortType ST;
554
0
    switch (ExternTy) {
555
0
    case ExternalType::Function:
556
0
      ST = AST::Component::Sort::CoreSortType::Func;
557
0
      break;
558
0
    case ExternalType::Table:
559
0
      ST = AST::Component::Sort::CoreSortType::Table;
560
0
      break;
561
0
    case ExternalType::Memory:
562
0
      ST = AST::Component::Sort::CoreSortType::Memory;
563
0
      break;
564
0
    case ExternalType::Global:
565
0
      ST = AST::Component::Sort::CoreSortType::Global;
566
0
      break;
567
0
    case ExternalType::Tag:
568
0
    default:
569
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
570
0
      spdlog::error(
571
0
          "    Alias core:export: Type mapping mismatch for export '{}'"sv,
572
0
          Name);
573
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
574
0
    }
575
0
    if (ST != Sort.getCoreSortType()) {
576
0
      spdlog::error(ErrCode::Value::InvalidTypeReference);
577
0
      spdlog::error(
578
0
          "    Alias core:export: Type mapping mismatch for export '{}'"sv,
579
0
          Name);
580
0
      return Unexpect(ErrCode::Value::InvalidTypeReference);
581
0
    }
582
0
    return {};
583
0
  }
584
0
  case AST::Component::Alias::TargetType::Outer: {
585
0
    const auto Ct = Alias.getOuter().first;
586
0
    const auto Idx = Alias.getOuter().second;
587
588
0
    uint32_t OutLinkCompCnt = 0;
589
0
    const auto *TargetCtx = &CompCtx.getCurrentContext();
590
0
    while (Ct > OutLinkCompCnt && TargetCtx != nullptr) {
591
0
      TargetCtx = TargetCtx->Parent;
592
0
      OutLinkCompCnt++;
593
0
    }
594
0
    if (TargetCtx == nullptr) {
595
0
      spdlog::error(ErrCode::Value::InvalidIndex);
596
0
      spdlog::error(
597
0
          "    Alias outer: Component out-link count {} is exceeding the enclosing component count {}"sv,
598
0
          Ct, OutLinkCompCnt);
599
0
      return Unexpect(ErrCode::Value::InvalidIndex);
600
0
    }
601
602
0
    if (Sort.isCore()) {
603
0
      if (Sort.getCoreSortType() !=
604
0
              AST::Component::Sort::CoreSortType::Module &&
605
0
          Sort.getCoreSortType() != AST::Component::Sort::CoreSortType::Type) {
606
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
607
0
        spdlog::error(
608
0
            "    Alias outer: Invalid core:sort for outer alias. Only type, module, or component are allowed."sv);
609
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
610
0
      }
611
0
      if (Idx >= TargetCtx->getCoreSortIndexSize(Sort.getCoreSortType())) {
612
0
        spdlog::error(ErrCode::Value::InvalidIndex);
613
0
        spdlog::error(
614
0
            "    Alias outer: core:sort index {} invalid in component context"sv,
615
0
            Idx);
616
0
        return Unexpect(ErrCode::Value::InvalidIndex);
617
0
      }
618
0
    } else {
619
0
      if (Sort.getSortType() != AST::Component::Sort::SortType::Type &&
620
0
          Sort.getSortType() != AST::Component::Sort::SortType::Component) {
621
0
        spdlog::error(ErrCode::Value::InvalidTypeReference);
622
0
        spdlog::error(
623
0
            "    Alias outer: Invalid sort for outer alias. Only type, module, or component are allowed."sv);
624
0
        return Unexpect(ErrCode::Value::InvalidTypeReference);
625
0
      }
626
0
      if (Idx >= TargetCtx->getSortIndexSize(Sort.getSortType())) {
627
0
        spdlog::error(ErrCode::Value::InvalidIndex);
628
0
        spdlog::error(
629
0
            "    Alias outer: sort index {} invalid in component context"sv,
630
0
            Idx);
631
0
        return Unexpect(ErrCode::Value::InvalidIndex);
632
0
      }
633
0
      if (Sort.getSortType() == AST::Component::Sort::SortType::Type) {
634
0
        if (TargetCtx->ComponentResourceTypes.find(Idx) !=
635
0
            TargetCtx->ComponentResourceTypes.end()) {
636
0
          spdlog::error(ErrCode::Value::InvalidTypeReference);
637
0
          spdlog::error(
638
0
              "    Alias outer: Cannot outer-alias a resource type at index {}. Resource types are generative."sv,
639
0
              Idx);
640
0
          return Unexpect(ErrCode::Value::InvalidTypeReference);
641
0
        }
642
0
      }
643
0
    }
644
0
    return {};
645
0
  }
646
0
  default:
647
0
    assumingUnreachable();
648
0
  }
649
0
}
650
651
Expect<void>
652
0
Validator::validate(const AST::Component::CoreDefType &DType) noexcept {
653
0
  if (DType.isRecType()) {
654
0
    CompCtx.incCoreSortIndexSize(AST::Component::Sort::CoreSortType::Type);
655
0
  } else if (DType.isModuleType()) {
656
0
    for (const auto &Decl : DType.getModuleType()) {
657
0
      EXPECTED_TRY(validate(Decl).map_error([](auto E) {
658
0
        spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_CoreDefType));
659
0
        return E;
660
0
      }));
661
0
    }
662
0
  } else {
663
0
    assumingUnreachable();
664
0
  }
665
0
  return {};
666
0
}
667
668
Expect<void>
669
0
Validator::validate(const AST::Component::DefType &DType) noexcept {
670
0
  if (DType.isDefValType()) {
671
    // TODO: Validation of valtype requires the typeidx to refer to a
672
    // defvaltype.
673
    // TODO: Validation of own and borrow requires the typeidx to refer to a
674
    // resource type.
675
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
676
0
  } else if (DType.isFuncType()) {
677
    // TODO: Validation of functype rejects any transitive use of borrow in
678
    // a result type. Similarly, validation of components and component
679
    // types rejects any transitive use of borrow in an exported value type.
680
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
681
0
  } else if (DType.isComponentType()) {
682
0
    for (const auto &Decl : DType.getComponentType().getDecl()) {
683
0
      if (Decl.isImportDecl()) {
684
0
        EXPECTED_TRY(validate(Decl.getImport()).map_error([](auto E) {
685
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_DefType));
686
0
          return E;
687
0
        }));
688
0
      } else if (Decl.isInstanceDecl()) {
689
0
        EXPECTED_TRY(validate(Decl.getInstance()).map_error([](auto E) {
690
0
          spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_DefType));
691
0
          return E;
692
0
        }));
693
0
      } else {
694
0
        assumingUnreachable();
695
0
      }
696
0
      CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
697
0
    }
698
    // TODO: Validation rejects resourcetype type definitions inside
699
    // componenttype and instancettype. Thus, handle types inside a
700
    // componenttype can only refer to resource types that are imported or
701
    // exported.
702
703
    // TODO: As described in the explainer, each component and instance type
704
    // is validated with an initially-empty type index space. Outer aliases
705
    // can be used to pull in type definitions from containing components.
706
0
  } else if (DType.isInstanceType()) {
707
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
708
0
    CompCtx.addComponentInstanceType(
709
0
        CompCtx.getSortIndexSize(AST::Component::Sort::SortType::Type) - 1,
710
0
        DType.getInstanceType());
711
0
  } else if (DType.isResourceType()) {
712
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
713
0
    CompCtx.addComponentResourceType(
714
0
        CompCtx.getSortIndexSize(AST::Component::Sort::SortType::Type) - 1,
715
0
        DType.getResourceType());
716
0
  } else {
717
0
    assumingUnreachable();
718
0
  }
719
0
  return {};
720
0
}
721
722
Expect<void>
723
0
Validator::validate(const AST::Component::Canonical &Canon) noexcept {
724
  // TODO: validation specifies
725
0
  switch (Canon.getOpCode()) {
726
0
  case AST::Component::Canonical::OpCode::Lift:
727
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Func);
728
0
    return {};
729
0
  case AST::Component::Canonical::OpCode::Lower:
730
0
  case AST::Component::Canonical::OpCode::Resource__new:
731
0
  case AST::Component::Canonical::OpCode::Resource__drop:
732
0
  case AST::Component::Canonical::OpCode::Resource__rep:
733
0
    CompCtx.incCoreSortIndexSize(AST::Component::Sort::CoreSortType::Func);
734
0
    return {};
735
0
  default:
736
0
    spdlog::error(ErrCode::Value::ComponentNotImplValidator);
737
0
    spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Canonical));
738
0
    return Unexpect(ErrCode::Value::ComponentNotImplValidator);
739
0
  }
740
0
}
741
742
0
Expect<void> Validator::validate(const AST::Component::Import &) noexcept {
743
  // TODO: Validation requires that annotated plainnames only occur on func
744
  // imports or exports and that the first label of a [constructor],
745
  // [method] or [static] matches the plainname of a preceding resource
746
  // import or export, respectively, in the same scope (component, component
747
  // type or instance type).
748
749
  // TODO: Validation of [constructor] names requires that the func returns
750
  // a (result (own $R)), where $R is the resource labeled r.
751
752
  // TODO: Validation of [method] names requires the first parameter of the
753
  // function to be (param "self" (borrow $R)), where $R is the resource
754
  // labeled r.
755
756
  // TODO: Validation of [method] and [static] names ensures that all field
757
  // names are disjoint.
758
0
  return {};
759
0
}
760
761
0
Expect<void> Validator::validate(const AST::Component::Export &Ex) noexcept {
762
0
  if (Ex.getDesc().has_value()) {
763
0
    EXPECTED_TRY(validate(*Ex.getDesc()).map_error([](auto E) {
764
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Export));
765
0
      return E;
766
0
    }));
767
0
  }
768
0
  const auto &Sort = Ex.getSortIndex().getSort();
769
0
  if (!Sort.isCore()) {
770
0
    CompCtx.incSortIndexSize(Sort.getSortType());
771
0
  }
772
0
  return {};
773
0
}
774
775
Expect<void>
776
0
Validator::validate(const AST::Component::ExternDesc &Desc) noexcept {
777
0
  switch (Desc.getDescType()) {
778
0
  case AST::Component::ExternDesc::DescType::CoreType:
779
0
    CompCtx.incCoreSortIndexSize(AST::Component::Sort::CoreSortType::Type);
780
0
    break;
781
0
  case AST::Component::ExternDesc::DescType::FuncType:
782
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Func);
783
0
    break;
784
0
  case AST::Component::ExternDesc::DescType::ValueBound:
785
0
  case AST::Component::ExternDesc::DescType::TypeBound:
786
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Type);
787
0
    break;
788
0
  case AST::Component::ExternDesc::DescType::ComponentType:
789
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Component);
790
0
    break;
791
0
  case AST::Component::ExternDesc::DescType::InstanceType: {
792
0
    CompCtx.incSortIndexSize(AST::Component::Sort::SortType::Instance);
793
0
    const auto *IT = CompCtx.getComponentInstanceType(Desc.getTypeIndex());
794
0
    if (IT != nullptr) {
795
0
      auto InstDecls = IT->getDecl();
796
0
      for (auto &InstDecl : InstDecls) {
797
0
        if (InstDecl.isCoreType()) {
798
0
          spdlog::debug("CoreDefType found"sv);
799
          // TODO
800
0
        } else if (InstDecl.isType()) {
801
0
          spdlog::debug("DefType found"sv);
802
          // TODO
803
0
        } else if (InstDecl.isAlias()) {
804
0
          spdlog::debug("Alias found"sv);
805
          // TODO
806
0
        } else if (InstDecl.isExportDecl()) {
807
0
          spdlog::debug("Export Decl found"sv);
808
0
          const auto &Exp = InstDecl.getExport();
809
0
          uint32_t InstIdx = CompCtx.getSortIndexSize(
810
0
                                 AST::Component::Sort::SortType::Instance) -
811
0
                             1;
812
0
          CompCtx.addComponentInstanceExport(InstIdx, Exp.getName(),
813
0
                                             Exp.getExternDesc());
814
0
        } else {
815
0
          assumingUnreachable();
816
0
        }
817
0
      }
818
0
    } else {
819
0
      spdlog::error(ErrCode::Value::InvalidIndex);
820
0
      spdlog::error("    ExternDesc: Instance index {} out of bound"sv,
821
0
                    Desc.getTypeIndex());
822
0
      spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Comp_Desc_Extern));
823
0
      return Unexpect(ErrCode::Value::InvalidIndex);
824
0
    }
825
0
    break;
826
0
  }
827
0
  default:
828
0
    assumingUnreachable();
829
0
  }
830
831
  // TODO: Validate the type index
832
0
  return {};
833
0
}
834
835
Expect<void>
836
0
Validator::validate(const AST::Component::CoreModuleDecl &) noexcept {
837
  // TODO
838
0
  return {};
839
0
}
840
841
0
Expect<void> Validator::validate(const AST::Component::ImportDecl &) noexcept {
842
  // TODO
843
0
  return {};
844
0
}
845
846
Expect<void>
847
0
Validator::validate(const AST::Component::InstanceDecl &) noexcept {
848
  // TODO
849
0
  return {};
850
0
}
851
852
} // namespace Validator
853
} // namespace WasmEdge