Coverage Report

Created: 2025-08-25 06:58

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