Coverage Report

Created: 2026-08-13 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/include/validator/component_context.h
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#pragma once
5
6
#include "ast/component/component.h"
7
#include "ast/module.h"
8
#include "validator/component_name.h"
9
10
#include <deque>
11
#include <optional>
12
#include <string>
13
#include <unordered_map>
14
#include <unordered_set>
15
#include <vector>
16
17
namespace WasmEdge {
18
namespace Validator {
19
20
class ComponentContext {
21
public:
22
  // ==========================================================================
23
  // Validation context (one per component scope)
24
  // ==========================================================================
25
26
  struct Context {
27
    Context(const AST::Component::Component *C,
28
            const Context *P = nullptr) noexcept
29
1.22M
        : Component(C), Parent(P) {}
30
31
    // ---- Nested types ----
32
    // Per-sort slot structs bundling body + externdesc type ascription.
33
    // Exactly one of {Body, Type} is non-null per slot (Body for inline,
34
    // Type for imported / outer-aliased).
35
    struct CoreModuleSlot {
36
      const AST::Module *Body;
37
      const AST::Component::CoreDefType *Type;
38
0
      CoreModuleSlot() noexcept : Body(nullptr), Type(nullptr) {}
39
1.49k
      CoreModuleSlot(const AST::Module &B) noexcept : Body(&B), Type(nullptr) {}
40
      CoreModuleSlot(const AST::Component::CoreDefType *T) noexcept
41
120
          : Body(nullptr), Type(T) {}
42
    };
43
    struct ComponentSlot {
44
      const AST::Component::Component *Body;
45
      const AST::Component::ComponentType *Type;
46
422
      ComponentSlot() noexcept : Body(nullptr), Type(nullptr) {}
47
      ComponentSlot(const AST::Component::Component &B) noexcept
48
3.83k
          : Body(&B), Type(nullptr) {}
49
      ComponentSlot(const AST::Component::ComponentType *T) noexcept
50
318
          : Body(nullptr), Type(T) {}
51
    };
52
    // Per-export entry inside an instance's export table.
53
    // ResourceId is set when ST == Type and the exported type is a resource
54
    // (so an alias-export onto a new type slot can carry the same identity).
55
    struct InstanceExport {
56
      AST::Component::Sort::SortType ST;
57
      const AST::Component::InstanceType *IT;
58
      std::optional<uint32_t> NestedInstIdx;
59
      std::optional<uint64_t> ResourceId;
60
    };
61
    // Instance slot. Type is set only when bound via
62
    // validate(ExternDesc::InstanceType) (GAP-I-5b follow-up otherwise).
63
    struct InstanceSlot {
64
      std::unordered_map<std::string, InstanceExport> Exports;
65
      const AST::Component::InstanceType *Type;
66
27.3k
      InstanceSlot() : Type(nullptr) {}
67
234
      InstanceSlot(const AST::Component::InstanceType *T) : Type(T) {}
68
    };
69
    // Per-resource bookkeeping. "Key present in Resources" means resource.
70
    // The resource's AST body lives on ComponentContext::ResourceRegistry[Id].
71
    struct ResourceInfo {
72
      // Canonical identity. Two indices share a resource iff ids match.
73
      uint64_t Id = 0;
74
      // True for validate(DefType) in this scope. Gates resource.new/.rep.
75
      bool LocallyDefined = false;
76
    };
77
78
    // ---- Scope identity ----
79
    const AST::Component::Component *Component;
80
    const Context *Parent;
81
82
    // ---- Core sort index spaces ----
83
    std::vector<CoreModuleSlot> CoreModules; // core:module
84
    std::vector<std::unordered_map<std::string, ExternalType>>
85
        CoreInstances;                                 // core:instance
86
    std::vector<const AST::SubType *> CoreTypes;       // core:type
87
    std::vector<const AST::SubType *> CoreFuncs;       // core:func
88
    std::vector<const AST::TableType *> CoreTables;    // core:table
89
    std::vector<const AST::MemoryType *> CoreMemories; // core:memory
90
    std::vector<const AST::GlobalType *> CoreGlobals;  // core:global
91
    uint32_t CoreTagCount = 0;                         // core:tag
92
93
    // ---- Component sort index spaces ----
94
    std::vector<ComponentSlot> Components;               // component
95
    std::vector<InstanceSlot> Instances;                 // instance
96
    std::vector<const AST::Component::DefType *> Types;  // type
97
    std::vector<const AST::Component::FuncType *> Funcs; // func (i may be null)
98
    uint32_t ValueCount = 0;                             // value
99
100
    // ---- Type annotations (keyed by type index) ----
101
    // ResourceType bodies live on Resources[i].Body (see below).
102
    std::unordered_map<uint32_t, const AST::Component::InstanceType *>
103
        InstanceTypes;
104
    std::unordered_map<uint32_t, const AST::Component::ComponentType *>
105
        ComponentTypes;
106
    // CoreDefType (moduletype) bodies, keyed by core:type-idx.
107
    std::unordered_map<uint32_t, const AST::Component::CoreDefType *>
108
        CoreModuleTypes;
109
110
    // ---- Resource state (keyed by type index) ----
111
    std::unordered_map<uint32_t, ResourceInfo> Resources;
112
113
    // ---- Validation state ----
114
    std::unordered_map<std::string, uint32_t> TypeSubstitutions;
115
    std::unordered_set<std::string> ImportedNames;
116
    std::unordered_set<std::string> ExportedNames;
117
    // Kebab-case resource name → type-idx; consumed by annotated-name
118
    // validation ([constructor]R / [method]R.f / [static]R.f).
119
    std::unordered_map<std::string, uint32_t> ResourceLabels;
120
121
    // ---- Size queries (used by outer-alias validation on parent ctxs) ----
122
    uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept;
123
    uint32_t
124
    getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept;
125
126
    bool AddImportedName(const ComponentName &Name) noexcept;
127
    bool AddExportedName(const ComponentName &Name) noexcept;
128
  };
129
130
  // Per-id row of the session-global resource registry. Held by
131
  // ComponentContext::ResourceRegistry; vector index IS the resource id.
132
  struct ResourceRegistryEntry {
133
    const AST::Component::ResourceType *Body = nullptr;
134
  };
135
136
  // ==========================================================================
137
  // Context stack management
138
  // ==========================================================================
139
140
3.59k
  void reset() noexcept {
141
3.59k
    CompCtxs.clear();
142
3.59k
    ResourceRegistry.clear();
143
3.59k
  }
144
145
  /// Push a new validation scope for a real component.
146
7.44k
  void enterComponent(const AST::Component::Component *C) noexcept {
147
7.44k
    const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back();
148
7.44k
    CompCtxs.emplace_back(C, Parent);
149
7.44k
  }
150
151
  /// Push a new validation scope for a type definition
152
  /// (componenttype, instancetype, or moduletype).
153
1.21M
  void enterTypeDefinition() noexcept {
154
1.21M
    const Context *Parent = CompCtxs.empty() ? nullptr : &CompCtxs.back();
155
1.21M
    CompCtxs.emplace_back(nullptr, Parent);
156
1.21M
  }
157
158
1.22M
  void exitComponent() noexcept {
159
1.22M
    assuming(!CompCtxs.empty());
160
1.22M
    CompCtxs.pop_back();
161
1.22M
  }
162
163
  /// Returns true if the current scope is a type definition scope
164
  /// (componenttype or instancetype), not a real component scope.
165
16.5k
  bool isTypeDefinitionScope() const noexcept {
166
16.5k
    return !CompCtxs.empty() && CompCtxs.back().Component == nullptr;
167
16.5k
  }
168
169
580M
  Context &getCurrentContext() noexcept {
170
580M
    assuming(!CompCtxs.empty());
171
580M
    return CompCtxs.back();
172
580M
  }
173
106k
  const Context &getCurrentContext() const noexcept {
174
106k
    assuming(!CompCtxs.empty());
175
106k
    return CompCtxs.back();
176
106k
  }
177
178
  // ==========================================================================
179
  // Index space size queries (generic dispatch by sort enum)
180
  // ==========================================================================
181
182
39.8k
  uint32_t getSortIndexSize(AST::Component::Sort::SortType ST) const noexcept {
183
39.8k
    return getCurrentContext().getSortIndexSize(ST);
184
39.8k
  }
185
  uint32_t
186
13.9k
  getCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) const noexcept {
187
13.9k
    return getCurrentContext().getCoreSortIndexSize(ST);
188
13.9k
  }
189
190
  // ==========================================================================
191
  // Generic index space increment (for dynamic sort values)
192
  // ==========================================================================
193
194
  uint32_t incSortIndexSize(AST::Component::Sort::SortType ST) noexcept;
195
  uint32_t incCoreSortIndexSize(AST::Component::Sort::CoreSortType ST) noexcept;
196
197
  // ==========================================================================
198
  // core:module
199
  // ==========================================================================
200
201
  /// Append a core-module slot. Slot's implicit constructors accept
202
  /// `const AST::Module &` (inline body), `const CoreDefType *` (typed
203
  /// import / alias), or nothing (empty slot, used by outer-alias
204
  /// validation and incCoreSortIndexSize).
205
1.61k
  uint32_t addCoreModule(Context::CoreModuleSlot S = {}) noexcept {
206
1.61k
    auto &Ctx = getCurrentContext();
207
1.61k
    uint32_t Idx = static_cast<uint32_t>(Ctx.CoreModules.size());
208
1.61k
    Ctx.CoreModules.push_back(std::move(S));
209
1.61k
    return Idx;
210
1.61k
  }
211
212
  /// Read a core-module slot. Callers access `.Body` (inline body) or
213
  /// `.Type` (externdesc-bound moduletype) as needed.
214
258
  const Context::CoreModuleSlot &getCoreModule(uint32_t Idx) const noexcept {
215
258
    return getCurrentContext().CoreModules.at(Idx);
216
258
  }
217
218
  /// Returns the CoreDefType (a moduletype) stored at a core:type index, or
219
  /// nullptr if the core type is not a ModuleType (or its body is not
220
  /// visible here).
221
  const AST::Component::CoreDefType *
222
120
  getCoreModuleType(uint32_t TypeIdx) const noexcept {
223
120
    const auto &Ctx = getCurrentContext();
224
120
    auto It = Ctx.CoreModuleTypes.find(TypeIdx);
225
120
    return It != Ctx.CoreModuleTypes.end() ? It->second : nullptr;
226
120
  }
227
228
  /// Bind a CoreDefType (a moduletype) to a core:type index. Called by
229
  /// validate(CoreDefType) when adding a moduletype to the core:type space.
230
  void setCoreModuleType(uint32_t TypeIdx,
231
112k
                         const AST::Component::CoreDefType *CT) noexcept {
232
112k
    getCurrentContext().CoreModuleTypes[TypeIdx] = CT;
233
112k
  }
234
235
  // ==========================================================================
236
  // core:instance
237
  // ==========================================================================
238
239
6.08k
  uint32_t addCoreInstance() noexcept {
240
6.08k
    auto &V = getCurrentContext().CoreInstances;
241
6.08k
    uint32_t Idx = static_cast<uint32_t>(V.size());
242
6.08k
    V.emplace_back();
243
6.08k
    return Idx;
244
6.08k
  }
245
246
  const std::unordered_map<std::string, ExternalType> &
247
321
  getCoreInstance(uint32_t Idx) const noexcept {
248
321
    return getCurrentContext().CoreInstances.at(Idx);
249
321
  }
250
251
  void addCoreInstanceExport(uint32_t InstIdx, std::string_view Name,
252
1.47k
                             ExternalType ET) {
253
1.47k
    getCurrentContext().CoreInstances.at(InstIdx)[std::string(Name)] = ET;
254
1.47k
  }
255
256
  // ==========================================================================
257
  // core:type / core:func / core:table / core:memory / core:global / core:tag
258
  // ==========================================================================
259
260
252k
  uint32_t addCoreType(const AST::SubType *ST = nullptr) noexcept {
261
252k
    auto &V = getCurrentContext().CoreTypes;
262
252k
    uint32_t Idx = static_cast<uint32_t>(V.size());
263
252k
    V.push_back(ST);
264
252k
    return Idx;
265
252k
  }
266
4.04k
  uint32_t addCoreFunc(const AST::SubType *ST = nullptr) noexcept {
267
4.04k
    auto &V = getCurrentContext().CoreFuncs;
268
4.04k
    uint32_t Idx = static_cast<uint32_t>(V.size());
269
4.04k
    V.push_back(ST);
270
4.04k
    return Idx;
271
4.04k
  }
272
561
  const AST::SubType *getCoreFunc(uint32_t Idx) const noexcept {
273
561
    const auto &V = getCurrentContext().CoreFuncs;
274
561
    return Idx < V.size() ? V[Idx] : nullptr;
275
561
  }
276
277
493
  uint32_t addCoreTable(const AST::TableType *TT = nullptr) noexcept {
278
493
    auto &V = getCurrentContext().CoreTables;
279
493
    uint32_t Idx = static_cast<uint32_t>(V.size());
280
493
    V.push_back(TT);
281
493
    return Idx;
282
493
  }
283
434
  uint32_t addCoreMemory(const AST::MemoryType *MT = nullptr) noexcept {
284
434
    auto &V = getCurrentContext().CoreMemories;
285
434
    uint32_t Idx = static_cast<uint32_t>(V.size());
286
434
    V.push_back(MT);
287
434
    return Idx;
288
434
  }
289
254
  uint32_t addCoreGlobal(const AST::GlobalType *GT = nullptr) noexcept {
290
254
    auto &V = getCurrentContext().CoreGlobals;
291
254
    uint32_t Idx = static_cast<uint32_t>(V.size());
292
254
    V.push_back(GT);
293
254
    return Idx;
294
254
  }
295
138
  uint32_t addCoreTag() noexcept { return getCurrentContext().CoreTagCount++; }
296
297
  // ==========================================================================
298
  // component
299
  // ==========================================================================
300
301
  /// Append a component slot. Slot's implicit constructors accept
302
  /// `const Component &` (inline body), `const ComponentType *` (typed
303
  /// import / alias), or nothing (empty slot).
304
4.57k
  uint32_t addComponent(Context::ComponentSlot S = {}) noexcept {
305
4.57k
    auto &Ctx = getCurrentContext();
306
4.57k
    uint32_t Idx = static_cast<uint32_t>(Ctx.Components.size());
307
4.57k
    Ctx.Components.push_back(std::move(S));
308
4.57k
    return Idx;
309
4.57k
  }
310
311
  /// Read a component slot. Callers access `.Body` (inline body) or
312
  /// `.Type` (externdesc-bound ComponentType) as needed.
313
2.70k
  const Context::ComponentSlot &getComponent(uint32_t Idx) const noexcept {
314
2.70k
    return getCurrentContext().Components.at(Idx);
315
2.70k
  }
316
317
  /// Returns the ComponentType stored at a type index, or nullptr if the
318
  /// type is not a ComponentType (or its body is not visible here).
319
  const AST::Component::ComponentType *
320
318
  getComponentType(uint32_t TypeIdx) const noexcept {
321
318
    const auto &Ctx = getCurrentContext();
322
318
    auto It = Ctx.ComponentTypes.find(TypeIdx);
323
318
    return It != Ctx.ComponentTypes.end() ? It->second : nullptr;
324
318
  }
325
326
  // The scope an outer alias targets: Ct parent hops up. nullptr if Ct
327
  // exceeds the enclosing depth.
328
3.75k
  const Context *resolveOuterContext(uint32_t Ct) const noexcept {
329
3.75k
    uint32_t Hops = 0;
330
3.75k
    const Context *T = &getCurrentContext();
331
4.14k
    while (Ct > Hops && T != nullptr) {
332
387
      T = T->Parent;
333
387
      ++Hops;
334
387
    }
335
3.75k
    return T;
336
3.75k
  }
337
338
  // Reproduce an outer-aliased core module's slot into the alias's slot
339
  // DstIdx, so its exports stay enumerable when the alias is instantiated.
340
  void carryOuterCoreModule(uint32_t DstIdx, uint32_t Ct,
341
0
                            uint32_t SrcIdx) noexcept {
342
0
    const Context *O = resolveOuterContext(Ct);
343
0
    auto &Dst = getCurrentContext().CoreModules;
344
0
    if (O != nullptr && SrcIdx < O->CoreModules.size() && DstIdx < Dst.size()) {
345
0
      Dst[DstIdx] = O->CoreModules[SrcIdx];
346
0
    }
347
0
  }
348
349
  // Component analogue of carryOuterCoreModule.
350
  void carryOuterComponent(uint32_t DstIdx, uint32_t Ct,
351
422
                           uint32_t SrcIdx) noexcept {
352
422
    const Context *O = resolveOuterContext(Ct);
353
422
    auto &Dst = getCurrentContext().Components;
354
422
    if (O != nullptr && SrcIdx < O->Components.size() && DstIdx < Dst.size()) {
355
422
      Dst[DstIdx] = O->Components[SrcIdx];
356
422
    }
357
422
  }
358
359
  // Inherit an outer-aliased resource type's identity into the alias's type
360
  // slot DstIdx, so own/borrow checks and TypeBound (eq i) propagation in this
361
  // scope still recognise the aliased type as a resource. The alias does not
362
  // locally define the resource, so LocallyDefined stays false (it must not
363
  // gate resource.new/.rep here).
364
  void carryOuterResource(uint32_t DstIdx, uint32_t Ct,
365
3.33k
                          uint32_t SrcIdx) noexcept {
366
3.33k
    const Context *O = resolveOuterContext(Ct);
367
3.33k
    if (O == nullptr) {
368
0
      return;
369
0
    }
370
3.33k
    auto It = O->Resources.find(SrcIdx);
371
3.33k
    if (It != O->Resources.end()) {
372
1.93k
      getCurrentContext().Resources[DstIdx] = {It->second.Id,
373
1.93k
                                               /*LocallyDefined=*/false};
374
1.93k
    }
375
3.33k
  }
376
377
  // ==========================================================================
378
  // instance
379
  // ==========================================================================
380
381
  /// Append an instance slot. Slot's implicit constructor accepts
382
  /// `const InstanceType *` (typed source) or nothing (untyped — used by
383
  /// inline-export / (instantiate ...) sources).
384
27.5k
  uint32_t addInstance(Context::InstanceSlot S = {}) {
385
27.5k
    auto &Ctx = getCurrentContext();
386
27.5k
    uint32_t Idx = static_cast<uint32_t>(Ctx.Instances.size());
387
27.5k
    Ctx.Instances.push_back(std::move(S));
388
27.5k
    return Idx;
389
27.5k
  }
390
391
  using InstanceExport = Context::InstanceExport;
392
393
  /// Read an instance slot. Callers access `.Exports` (export table) or
394
  /// `.Type` (externdesc-bound InstanceType) as needed.
395
4.51k
  const Context::InstanceSlot &getInstance(uint32_t Idx) const noexcept {
396
4.51k
    return getCurrentContext().Instances.at(Idx);
397
4.51k
  }
398
399
  void addInstanceExport(
400
      uint32_t InstIdx, std::string_view Name,
401
      AST::Component::Sort::SortType ST,
402
      const AST::Component::InstanceType *IT = nullptr,
403
      std::optional<uint32_t> NestedInstIdx = std::nullopt,
404
3.39k
      std::optional<uint64_t> ResourceId = std::nullopt) noexcept {
405
3.39k
    getCurrentContext().Instances.at(InstIdx).Exports[std::string(Name)] = {
406
3.39k
        ST, IT, NestedInstIdx, ResourceId};
407
3.39k
  }
408
409
  // ==========================================================================
410
  // type
411
  // ==========================================================================
412
413
  /// Append a type slot. IsLocal=false for resource type imports and
414
  /// outer-alias resources, true otherwise.
415
  uint32_t addType(const AST::Component::DefType *DT = nullptr,
416
1.20M
                   bool IsLocal = true) noexcept {
417
1.20M
    return addTypeImpl(DT, IsLocal);
418
1.20M
  }
419
420
33.8k
  const AST::Component::DefType *getDefType(uint32_t Idx) const noexcept {
421
33.8k
    const auto &Ctx = getCurrentContext();
422
33.8k
    if (Idx < Ctx.Types.size()) {
423
33.8k
      return Ctx.Types[Idx];
424
33.8k
    }
425
0
    return nullptr;
426
33.8k
  }
427
428
  const AST::Component::InstanceType *
429
234
  getInstanceType(uint32_t Idx) const noexcept {
430
234
    const auto &Ctx = getCurrentContext();
431
234
    auto It = Ctx.InstanceTypes.find(Idx);
432
234
    return It != Ctx.InstanceTypes.end() ? It->second : nullptr;
433
234
  }
434
435
  // ==========================================================================
436
  // resource
437
  // ==========================================================================
438
439
  /// Allocate a fresh resource id, pushing a new registry row. Body is
440
  /// nullptr for (sub resource) imports.
441
  uint64_t allocateFreshResourceId(
442
18.6k
      const AST::Component::ResourceType *Body = nullptr) noexcept {
443
18.6k
    uint64_t Id = ResourceRegistry.size();
444
18.6k
    ResourceRegistry.push_back({Body});
445
18.6k
    return Id;
446
18.6k
  }
447
448
  /// Bind a ResourceInfo to a type index in the current scope.
449
2.08k
  void addResource(uint32_t TypeIdx, Context::ResourceInfo Info) noexcept {
450
2.08k
    getCurrentContext().Resources[TypeIdx] = Info;
451
2.08k
  }
452
453
  /// ResourceInfo at this type index, or nullptr if not a resource.
454
3.94k
  const Context::ResourceInfo *getResource(uint32_t Idx) const noexcept {
455
3.94k
    const auto &R = getCurrentContext().Resources;
456
3.94k
    auto It = R.find(Idx);
457
3.94k
    return It != R.end() ? &It->second : nullptr;
458
3.94k
  }
459
460
  /// Register a kebab-case resource name (from a TypeBound import / export)
461
  /// so annotated names ([constructor]R / [method]R.f / [static]R.f) resolve.
462
2.05k
  void addResourceLabel(std::string_view Name, uint32_t TypeIdx) noexcept {
463
2.05k
    getCurrentContext().ResourceLabels.emplace(std::string(Name), TypeIdx);
464
2.05k
  }
465
466
0
  bool hasResourceLabel(std::string_view Name) const noexcept {
467
0
    return getCurrentContext().ResourceLabels.find(std::string(Name)) !=
468
0
           getCurrentContext().ResourceLabels.end();
469
0
  }
470
471
  // ==========================================================================
472
  // func / value
473
  // ==========================================================================
474
475
3.94k
  uint32_t addFunc(const AST::Component::FuncType *FT = nullptr) noexcept {
476
3.94k
    auto &V = getCurrentContext().Funcs;
477
3.94k
    uint32_t Idx = static_cast<uint32_t>(V.size());
478
3.94k
    V.push_back(FT);
479
3.94k
    return Idx;
480
3.94k
  }
481
1.15k
  const AST::Component::FuncType *getFunc(uint32_t Idx) const noexcept {
482
1.15k
    const auto &V = getCurrentContext().Funcs;
483
1.15k
    return Idx < V.size() ? V[Idx] : nullptr;
484
1.15k
  }
485
579M
  uint32_t addValue() noexcept { return getCurrentContext().ValueCount++; }
486
487
  // ==========================================================================
488
  // Validation state
489
  // ==========================================================================
490
491
  void substituteTypeImport(const std::string &ImportName,
492
0
                            uint32_t TypeIdx) noexcept {
493
0
    getCurrentContext().TypeSubstitutions[ImportName] = TypeIdx;
494
0
  }
495
496
  std::optional<uint32_t>
497
959
  getSubstitutedType(const std::string &ImportName) const {
498
959
    const auto &Ctx = getCurrentContext();
499
959
    auto It = Ctx.TypeSubstitutions.find(ImportName);
500
959
    if (It != Ctx.TypeSubstitutions.end()) {
501
0
      return It->second;
502
0
    }
503
959
    return std::nullopt;
504
959
  }
505
506
5.10k
  bool addImportedName(const ComponentName &Name) noexcept {
507
5.10k
    return getCurrentContext().AddImportedName(Name);
508
5.10k
  }
509
510
  /// Returns false if the export name violates strong-uniqueness.
511
878
  bool addExportedName(const ComponentName &Name) noexcept {
512
878
    return getCurrentContext().AddExportedName(Name);
513
878
  }
514
515
private:
516
  uint32_t addTypeImpl(const AST::Component::DefType *DT,
517
1.20M
                       bool IsLocal) noexcept {
518
1.20M
    auto &Ctx = getCurrentContext();
519
1.20M
    uint32_t Idx = static_cast<uint32_t>(Ctx.Types.size());
520
1.20M
    Ctx.Types.push_back(DT);
521
1.20M
    if (DT != nullptr) {
522
1.19M
      if (DT->isInstanceType()) {
523
348k
        Ctx.InstanceTypes[Idx] = &DT->getInstanceType();
524
851k
      } else if (DT->isResourceType()) {
525
        // Locally-defined: body goes to the registry; IsLocal sets locality.
526
16.5k
        Ctx.Resources[Idx] = {allocateFreshResourceId(&DT->getResourceType()),
527
16.5k
                              IsLocal};
528
834k
      } else if (DT->isComponentType()) {
529
754k
        Ctx.ComponentTypes[Idx] = &DT->getComponentType();
530
754k
      }
531
1.19M
    }
532
1.20M
    return Idx;
533
1.20M
  }
534
535
  std::deque<Context> CompCtxs;
536
537
  // Session-global resource registry; vector index IS the resource id.
538
  std::vector<ResourceRegistryEntry> ResourceRegistry;
539
};
540
541
} // namespace Validator
542
} // namespace WasmEdge