Skip to main content

miden_assembly_syntax/ast/
module.rs

1use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
2use core::fmt;
3
4use miden_core::{
5    advice::AdviceMap,
6    serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
7};
8use miden_debug_types::{SourceFile, SourceManager, SourceSpan, Span, Spanned};
9use miden_utils_diagnostics::Report;
10use smallvec::SmallVec;
11
12use super::{
13    Alias, Constant, DocString, EnumType, Export, FunctionType, GlobalItemIndex, ItemIndex,
14    LocalSymbolResolver, Path, Procedure, ProcedureName, QualifiedProcedureName, SymbolResolution,
15    SymbolResolutionError, TypeAlias, TypeDecl, TypeResolver, Variant,
16};
17use crate::{
18    PathBuf,
19    ast::{self, Ident, types},
20    parser::ModuleParser,
21    sema::SemanticAnalysisError,
22};
23
24// MODULE KIND
25// ================================================================================================
26
27/// Represents the kind of a [Module].
28///
29/// The three different kinds have slightly different rules on what syntax is allowed, as well as
30/// what operations can be performed in the body of procedures defined in the module. See the
31/// documentation for each variant for a summary of these differences.
32#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
33#[repr(u8)]
34pub enum ModuleKind {
35    /// A library is a simple container of code that must be included into an executable module to
36    /// form a complete program.
37    ///
38    /// Library modules cannot use the `begin`..`end` syntax, which is used to define the
39    /// entrypoint procedure for an executable. Aside from this, they are free to use all other
40    /// MASM syntax.
41    #[default]
42    Library = 0,
43    /// An executable is the root module of a program, and provides the entrypoint for executing
44    /// that program.
45    ///
46    /// As the executable module is the root module, it may not export procedures for other modules
47    /// to depend on, it may only import and call externally-defined procedures, or private
48    /// locally-defined procedures.
49    ///
50    /// An executable module must contain a `begin`..`end` block.
51    Executable = 1,
52    /// A kernel is like a library module, but is special in a few ways:
53    ///
54    /// * Its code always executes in the root context, so it is stateful in a way that normal
55    ///   libraries cannot replicate. This can be used to provide core services that would otherwise
56    ///   not be possible to implement.
57    ///
58    /// * The procedures exported from the kernel may be the target of the `syscall` instruction,
59    ///   and in fact _must_ be called that way.
60    Kernel = 2,
61}
62
63impl ModuleKind {
64    pub fn is_executable(&self) -> bool {
65        matches!(self, Self::Executable)
66    }
67
68    pub fn is_kernel(&self) -> bool {
69        matches!(self, Self::Kernel)
70    }
71
72    pub fn is_library(&self) -> bool {
73        matches!(self, Self::Library)
74    }
75}
76
77impl fmt::Display for ModuleKind {
78    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        match self {
80            Self::Library => f.write_str("library"),
81            Self::Executable => f.write_str("executable"),
82            Self::Kernel => f.write_str("kernel"),
83        }
84    }
85}
86
87impl Serializable for ModuleKind {
88    fn write_into<W: ByteWriter>(&self, target: &mut W) {
89        target.write_u8(*self as u8)
90    }
91}
92
93impl Deserializable for ModuleKind {
94    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
95        match source.read_u8()? {
96            0 => Ok(Self::Library),
97            1 => Ok(Self::Executable),
98            2 => Ok(Self::Kernel),
99            n => Err(DeserializationError::InvalidValue(format!("invalid module kind tag: {n}"))),
100        }
101    }
102}
103
104// MODULE
105// ================================================================================================
106
107/// The abstract syntax tree for a single Miden Assembly module.
108///
109/// All module kinds share this AST representation, as they are largely identical. However, the
110/// [ModuleKind] dictates how the parsed module is semantically analyzed and validated.
111#[derive(Clone)]
112pub struct Module {
113    /// The span covering the entire definition of this module.
114    span: SourceSpan,
115    /// The documentation associated with this module.
116    ///
117    /// Module documentation is provided in Miden Assembly as a documentation comment starting on
118    /// the first line of the module. All other documentation comments are attached to the item the
119    /// precede in the module body.
120    docs: Option<DocString>,
121    /// The fully-qualified path representing the name of this module.
122    path: PathBuf,
123    /// The kind of module this represents.
124    kind: ModuleKind,
125    /// The items (defined or re-exported) in the module body.
126    pub(crate) items: Vec<Export>,
127    /// AdviceMap that this module expects to be loaded in the host before executing.
128    pub(crate) advice_map: AdviceMap,
129}
130
131/// Constants
132impl Module {
133    /// File extension for a Assembly Module.
134    pub const FILE_EXTENSION: &'static str = "masm";
135
136    /// Name of the root module.
137    pub const ROOT: &'static str = "mod";
138
139    /// File name of the root module.
140    pub const ROOT_FILENAME: &'static str = "mod.masm";
141}
142
143/// Construction
144impl Module {
145    /// Creates a new [Module] with the specified `kind` and fully-qualified path, e.g.
146    /// `std::math::u64`.
147    pub fn new(kind: ModuleKind, path: impl AsRef<Path>) -> Self {
148        let path = path.as_ref().to_absolute().into_owned();
149        Self {
150            span: Default::default(),
151            docs: None,
152            path,
153            kind,
154            items: Default::default(),
155            advice_map: Default::default(),
156        }
157    }
158
159    /// An alias for creating the default, but empty, `#kernel` [Module].
160    pub fn new_kernel() -> Self {
161        Self::new(ModuleKind::Kernel, Path::kernel_path())
162    }
163
164    /// An alias for creating the default, but empty, `$exec` [Module].
165    pub fn new_executable() -> Self {
166        Self::new(ModuleKind::Executable, Path::exec_path())
167    }
168
169    /// Specifies the source span in the source file in which this module was defined, that covers
170    /// the full definition of this module.
171    pub fn with_span(mut self, span: SourceSpan) -> Self {
172        self.span = span;
173        self
174    }
175
176    /// Sets the [Path] for this module
177    pub fn set_path(&mut self, path: impl AsRef<Path>) {
178        self.path = path.as_ref().to_path_buf();
179    }
180
181    /// Modifies the path of this module by overriding the portion of the path preceding
182    /// [`Self::name`], i.e. the portion returned by [`Self::parent`].
183    ///
184    /// See [`PathBuf::set_parent`] for details.
185    pub fn set_parent(&mut self, ns: impl AsRef<Path>) {
186        self.path.set_parent(ns.as_ref());
187    }
188
189    /// Sets the documentation for this module
190    pub fn set_docs(&mut self, docs: Option<Span<String>>) {
191        self.docs = docs.map(DocString::new);
192    }
193
194    /// Like [Module::with_span], but does not require ownership of the [Module].
195    pub fn set_span(&mut self, span: SourceSpan) {
196        self.span = span;
197    }
198
199    /// Defines a constant, raising an error if the constant conflicts with a previous definition
200    pub fn define_constant(&mut self, constant: Constant) -> Result<(), SemanticAnalysisError> {
201        for item in self.items.iter() {
202            if let Export::Constant(c) = item
203                && c.name == constant.name
204            {
205                return Err(SemanticAnalysisError::SymbolConflict {
206                    span: constant.span,
207                    prev_span: c.span,
208                });
209            }
210        }
211        self.items.push(Export::Constant(constant));
212        Ok(())
213    }
214
215    /// Defines a type alias, raising an error if the alias conflicts with a previous definition
216    pub fn define_type(&mut self, ty: TypeAlias) -> Result<(), SemanticAnalysisError> {
217        for item in self.items.iter() {
218            if let Export::Type(t) = item
219                && t.name() == ty.name()
220            {
221                return Err(SemanticAnalysisError::SymbolConflict {
222                    span: ty.span(),
223                    prev_span: t.span(),
224                });
225            }
226        }
227        self.items.push(Export::Type(ty.into()));
228        Ok(())
229    }
230
231    /// Define a new enum type `ty` with `visibility`
232    ///
233    /// Returns `Err` if:
234    ///
235    /// * A type alias with the same name as the enum type is already defined
236    /// * Two or more variants of the given enum type have the same name
237    /// * A constant (including those implicitly defined by variants of other enums in this module)
238    ///   with the same name as any of the variants of the given enum type, is already defined
239    /// * The concrete type of the enumeration is not an integral type
240    pub fn define_enum(&mut self, ty: EnumType) -> Result<(), SemanticAnalysisError> {
241        let repr = ty.ty().clone();
242
243        if !repr.is_integer() {
244            return Err(SemanticAnalysisError::InvalidEnumRepr { span: ty.span() });
245        }
246
247        // We only define constants for C-like enums
248        if ty.is_c_like() {
249            self.items.push(Export::Type(ty.into()));
250            return Ok(());
251        }
252
253        let export = ty.clone();
254
255        let (alias, variants) = ty.into_parts();
256
257        if let Some(prev) = self.items.iter().find(|t| t.name() == &alias.name) {
258            return Err(SemanticAnalysisError::SymbolConflict {
259                span: alias.span(),
260                prev_span: prev.span(),
261            });
262        }
263
264        let mut values = SmallVec::<[Span<u64>; 8]>::new_const();
265
266        for variant in variants {
267            // Validate that the discriminant value is unique amongst all variants
268            let value = match &variant.discriminant {
269                ast::ConstantExpr::Int(value) => (*value).map(|v| v.as_int()),
270                expr => {
271                    return Err(SemanticAnalysisError::InvalidEnumDiscriminant {
272                        span: expr.span(),
273                        repr,
274                    });
275                },
276            };
277            if let Some(prev) = values.iter().find(|v| *v == &value) {
278                return Err(SemanticAnalysisError::EnumDiscriminantConflict {
279                    span: value.span(),
280                    prev: prev.span(),
281                });
282            } else {
283                values.push(value);
284            }
285
286            // Validate that the discriminant is a valid instance of the `repr` type
287            variant.assert_instance_of(&repr)?;
288
289            let Variant {
290                span,
291                docs,
292                name,
293                value_ty: _,
294                discriminant,
295            } = variant;
296
297            self.define_constant(Constant {
298                span,
299                docs,
300                visibility: alias.visibility(),
301                name,
302                value: discriminant,
303            })?;
304        }
305
306        self.items.push(Export::Type(export.into()));
307
308        Ok(())
309    }
310
311    /// Defines a procedure, raising an error if the procedure is invalid, or conflicts with a
312    /// previous definition
313    pub fn define_procedure(
314        &mut self,
315        procedure: Procedure,
316        source_manager: Arc<dyn SourceManager>,
317    ) -> Result<(), SemanticAnalysisError> {
318        let name = procedure.name();
319        let name = Span::new(name.span(), name.as_str());
320        if let Ok(prev) = self.resolve(name, source_manager) {
321            let prev_span = prev.span();
322            Err(SemanticAnalysisError::SymbolConflict { span: procedure.span(), prev_span })
323        } else {
324            self.items.push(Export::Procedure(procedure));
325            Ok(())
326        }
327    }
328
329    /// Defines an item alias, raising an error if the alias is invalid, or conflicts with a
330    /// previous definition
331    pub fn define_alias(
332        &mut self,
333        item: Alias,
334        source_manager: Arc<dyn SourceManager>,
335    ) -> Result<(), SemanticAnalysisError> {
336        if self.is_kernel() && item.visibility().is_public() {
337            return Err(SemanticAnalysisError::ReexportFromKernel { span: item.span() });
338        }
339        let name = item.name();
340        let name = Span::new(name.span(), name.as_str());
341        if let Ok(prev) = self.resolve(name, source_manager) {
342            let prev_span = prev.span();
343            Err(SemanticAnalysisError::SymbolConflict { span: item.span(), prev_span })
344        } else {
345            self.items.push(Export::Alias(item));
346            Ok(())
347        }
348    }
349}
350
351/// Parsing
352impl Module {
353    /// Parse a [Module], `name`, of the given [ModuleKind], from `source_file`.
354    pub fn parse(
355        name: impl AsRef<Path>,
356        kind: ModuleKind,
357        source_file: Arc<SourceFile>,
358        source_manager: Arc<dyn SourceManager>,
359    ) -> Result<Box<Self>, Report> {
360        let name = name.as_ref();
361        let mut parser = Self::parser(kind);
362        parser.parse(name, source_file, source_manager)
363    }
364
365    /// Get a [ModuleParser] for parsing modules of the provided [ModuleKind]
366    pub fn parser(kind: ModuleKind) -> ModuleParser {
367        ModuleParser::new(kind)
368    }
369}
370
371/// Metadata
372impl Module {
373    /// Get the name of this specific module, i.e. the last component of the [Path] that
374    /// represents the fully-qualified name of the module, e.g. `u64` in `std::math::u64`
375    pub fn name(&self) -> &str {
376        self.path.last().expect("non-empty module path")
377    }
378
379    /// Get the fully-qualified name of this module, e.g. `std::math::u64`
380    pub fn path(&self) -> &Path {
381        &self.path
382    }
383
384    /// Get the path of the parent module of this module, e.g. `std::math` in `std::math::u64`
385    pub fn parent(&self) -> Option<&Path> {
386        self.path.parent()
387    }
388
389    /// Returns true if this module belongs to the provided namespace.
390    pub fn is_in_namespace(&self, namespace: &Path) -> bool {
391        self.path.starts_with(namespace)
392    }
393
394    /// Get the module documentation for this module, if it was present in the source code the
395    /// module was parsed from
396    pub fn docs(&self) -> Option<Span<&str>> {
397        self.docs.as_ref().map(|spanned| spanned.as_spanned_str())
398    }
399
400    /// Get the type of module this represents:
401    ///
402    /// See [ModuleKind] for details on the different types of modules.
403    pub fn kind(&self) -> ModuleKind {
404        self.kind
405    }
406
407    /// Override the type of module this represents.
408    ///
409    /// See [ModuleKind] for details on what the different types are.
410    pub fn set_kind(&mut self, kind: ModuleKind) {
411        self.kind = kind;
412    }
413
414    /// Returns true if this module is an executable module.
415    #[inline(always)]
416    pub fn is_executable(&self) -> bool {
417        self.kind.is_executable()
418    }
419
420    /// Returns true if this module is the top-level kernel module.
421    #[inline(always)]
422    pub fn is_kernel(&self) -> bool {
423        self.kind.is_kernel() && self.path.is_kernel_path()
424    }
425
426    /// Returns true if this module is a kernel module.
427    #[inline(always)]
428    pub fn is_in_kernel(&self) -> bool {
429        self.kind.is_kernel()
430    }
431
432    /// Returns true if this module has an entrypoint procedure defined,
433    /// i.e. a `begin`..`end` block.
434    pub fn has_entrypoint(&self) -> bool {
435        self.index_of(|p| p.is_main()).is_some()
436    }
437
438    /// Returns a reference to the advice map derived from this module
439    pub fn advice_map(&self) -> &AdviceMap {
440        &self.advice_map
441    }
442
443    /// Get an iterator over the constants defined in this module.
444    pub fn constants(&self) -> impl Iterator<Item = &Constant> + '_ {
445        self.items.iter().filter_map(|item| match item {
446            Export::Constant(item) => Some(item),
447            _ => None,
448        })
449    }
450
451    /// Same as [Module::constants], but returns mutable references.
452    pub fn constants_mut(&mut self) -> impl Iterator<Item = &mut Constant> + '_ {
453        self.items.iter_mut().filter_map(|item| match item {
454            Export::Constant(item) => Some(item),
455            _ => None,
456        })
457    }
458
459    /// Get an iterator over the types defined in this module.
460    pub fn types(&self) -> impl Iterator<Item = &TypeDecl> + '_ {
461        self.items.iter().filter_map(|item| match item {
462            Export::Type(item) => Some(item),
463            _ => None,
464        })
465    }
466
467    /// Same as [Module::types], but returns mutable references.
468    pub fn types_mut(&mut self) -> impl Iterator<Item = &mut TypeDecl> + '_ {
469        self.items.iter_mut().filter_map(|item| match item {
470            Export::Type(item) => Some(item),
471            _ => None,
472        })
473    }
474
475    /// Get an iterator over the procedures defined in this module.
476    pub fn procedures(&self) -> impl Iterator<Item = &Procedure> + '_ {
477        self.items.iter().filter_map(|item| match item {
478            Export::Procedure(item) => Some(item),
479            _ => None,
480        })
481    }
482
483    /// Same as [Module::procedures], but returns mutable references.
484    pub fn procedures_mut(&mut self) -> impl Iterator<Item = &mut Procedure> + '_ {
485        self.items.iter_mut().filter_map(|item| match item {
486            Export::Procedure(item) => Some(item),
487            _ => None,
488        })
489    }
490
491    /// Get an iterator over the item aliases in this module.
492    pub fn aliases(&self) -> impl Iterator<Item = &Alias> + '_ {
493        self.items.iter().filter_map(|item| match item {
494            Export::Alias(item) => Some(item),
495            _ => None,
496        })
497    }
498
499    /// Same as [Module::aliases], but returns mutable references.
500    pub fn aliases_mut(&mut self) -> impl Iterator<Item = &mut Alias> + '_ {
501        self.items.iter_mut().filter_map(|item| match item {
502            Export::Alias(item) => Some(item),
503            _ => None,
504        })
505    }
506
507    /// Get a reference to the items stored in this module
508    pub fn items(&self) -> &[Export] {
509        &self.items
510    }
511
512    /// Get a mutable reference to the storage for items defined in this module
513    pub fn items_mut(&mut self) -> &mut Vec<Export> {
514        &mut self.items
515    }
516
517    /// Returns items exported from this module.
518    ///
519    /// Each exported item is represented by its local item index and a fully qualified name.
520    pub fn exported(&self) -> impl Iterator<Item = (ItemIndex, QualifiedProcedureName)> + '_ {
521        self.items.iter().enumerate().filter_map(|(idx, item)| {
522            // skip un-exported items
523            if !item.visibility().is_public() {
524                return None;
525            }
526
527            let idx = ItemIndex::new(idx);
528            let name = ProcedureName::from_raw_parts(item.name().clone());
529            let fqn = QualifiedProcedureName::new(self.path.clone(), name);
530
531            Some((idx, fqn))
532        })
533    }
534
535    /// Gets the type signature for the given [ItemIndex], if available.
536    pub fn procedure_signature(&self, id: ItemIndex) -> Option<&FunctionType> {
537        self.items[id.as_usize()].signature()
538    }
539
540    /// Get the item at `index` in this module's item table.
541    ///
542    /// The item returned may be either a locally-defined item, or a re-exported item. See [Export]
543    /// for details.
544    pub fn get(&self, index: ItemIndex) -> Option<&Export> {
545        self.items.get(index.as_usize())
546    }
547
548    /// Get the [ItemIndex] for the first item in this module's item table which returns true for
549    /// `predicate`.
550    pub fn index_of<F>(&self, predicate: F) -> Option<ItemIndex>
551    where
552        F: FnMut(&Export) -> bool,
553    {
554        self.items.iter().position(predicate).map(ItemIndex::new)
555    }
556
557    /// Get the [ItemIndex] for the item whose name is `name` in this module's item table, _if_ that
558    /// item is exported.
559    ///
560    /// Non-exported items can be retrieved by using [Module::index_of].
561    pub fn index_of_name(&self, name: &Ident) -> Option<ItemIndex> {
562        self.index_of(|item| item.name() == name && item.visibility().is_public())
563    }
564
565    /// Resolves `name` to an item within the local scope of this module
566    pub fn resolve(
567        &self,
568        name: Span<&str>,
569        source_manager: Arc<dyn SourceManager>,
570    ) -> Result<SymbolResolution, SymbolResolutionError> {
571        let resolver = self.resolver(source_manager);
572        resolver.resolve(name)
573    }
574
575    /// Resolves `path` to an item within the local scope of this module
576    pub fn resolve_path(
577        &self,
578        path: Span<&Path>,
579        source_manager: Arc<dyn SourceManager>,
580    ) -> Result<SymbolResolution, SymbolResolutionError> {
581        let resolver = self.resolver(source_manager);
582        resolver.resolve_path(path)
583    }
584
585    /// Construct a search structure that can resolve procedure names local to this module
586    #[inline]
587    pub fn resolver(&self, source_manager: Arc<dyn SourceManager>) -> LocalSymbolResolver {
588        LocalSymbolResolver::new(self, source_manager)
589    }
590
591    /// Resolves `module_name` to an [Alias] within the context of this module
592    pub fn get_import(&self, module_name: &str) -> Option<&Alias> {
593        self.items.iter().find_map(|item| match item {
594            Export::Alias(item) if item.name().as_str() == module_name => Some(item),
595            _ => None,
596        })
597    }
598
599    /// Same as [Module::get_import], but returns a mutable reference to the [Alias]
600    pub fn get_import_mut(&mut self, module_name: &str) -> Option<&mut Alias> {
601        self.items.iter_mut().find_map(|item| match item {
602            Export::Alias(item) if item.name().as_str() == module_name => Some(item),
603            _ => None,
604        })
605    }
606
607    /// Resolves a user-expressed type, `ty`, to a concrete type
608    pub fn resolve_type(
609        &self,
610        ty: &ast::TypeExpr,
611        source_manager: Arc<dyn SourceManager>,
612    ) -> Result<Option<types::Type>, SymbolResolutionError> {
613        let mut type_resolver = ModuleTypeResolver::new(self, source_manager);
614        type_resolver.resolve(ty)
615    }
616
617    /// Get a type resolver for this module
618    pub fn type_resolver(
619        &self,
620        source_manager: Arc<dyn SourceManager>,
621    ) -> impl TypeResolver<SymbolResolutionError> + '_ {
622        ModuleTypeResolver::new(self, source_manager)
623    }
624}
625
626impl core::ops::Index<ItemIndex> for Module {
627    type Output = Export;
628
629    #[inline]
630    fn index(&self, index: ItemIndex) -> &Self::Output {
631        &self.items[index.as_usize()]
632    }
633}
634
635impl core::ops::IndexMut<ItemIndex> for Module {
636    #[inline]
637    fn index_mut(&mut self, index: ItemIndex) -> &mut Self::Output {
638        &mut self.items[index.as_usize()]
639    }
640}
641
642impl Spanned for Module {
643    fn span(&self) -> SourceSpan {
644        self.span
645    }
646}
647
648impl Eq for Module {}
649
650impl PartialEq for Module {
651    fn eq(&self, other: &Self) -> bool {
652        self.kind == other.kind
653            && self.path == other.path
654            && self.docs == other.docs
655            && self.items == other.items
656    }
657}
658
659/// Debug representation of this module
660impl fmt::Debug for Module {
661    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662        f.debug_struct("Module")
663            .field("docs", &self.docs)
664            .field("path", &self.path)
665            .field("kind", &self.kind)
666            .field("items", &self.items)
667            .finish()
668    }
669}
670
671/// Pretty-printed representation of this module as Miden Assembly text format
672///
673/// NOTE: Delegates to the [crate::prettier::PrettyPrint] implementation internally
674impl fmt::Display for Module {
675    /// Writes this [Module] as formatted MASM code into the formatter.
676    ///
677    /// The formatted code puts each instruction on a separate line and preserves correct
678    /// indentation for instruction blocks.
679    #[inline]
680    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
681        use crate::prettier::PrettyPrint;
682
683        self.pretty_print(f)
684    }
685}
686
687/// The pretty-printer for [Module]
688impl crate::prettier::PrettyPrint for Module {
689    fn render(&self) -> crate::prettier::Document {
690        use crate::prettier::*;
691
692        let mut doc = self
693            .docs
694            .as_ref()
695            .map(|docstring| docstring.render() + nl())
696            .unwrap_or(Document::Empty);
697
698        for (item_index, item) in self.items.iter().enumerate() {
699            if item_index > 0 {
700                doc += nl();
701            }
702            doc += item.render();
703        }
704
705        doc
706    }
707}
708
709struct ModuleTypeResolver<'a> {
710    module: &'a Module,
711    resolver: LocalSymbolResolver,
712}
713
714impl<'a> ModuleTypeResolver<'a> {
715    pub fn new(module: &'a Module, source_manager: Arc<dyn SourceManager>) -> Self {
716        let resolver = module.resolver(source_manager);
717        Self { module, resolver }
718    }
719}
720
721impl TypeResolver<SymbolResolutionError> for ModuleTypeResolver<'_> {
722    fn source_manager(&self) -> Arc<dyn SourceManager> {
723        self.resolver.source_manager()
724    }
725    fn get_type(
726        &mut self,
727        context: SourceSpan,
728        _gid: GlobalItemIndex,
729    ) -> Result<ast::types::Type, SymbolResolutionError> {
730        Err(SymbolResolutionError::undefined(context, &self.resolver.source_manager()))
731    }
732    fn get_local_type(
733        &mut self,
734        context: SourceSpan,
735        id: ItemIndex,
736    ) -> Result<Option<ast::types::Type>, SymbolResolutionError> {
737        match &self.module[id] {
738            super::Export::Type(ty) => match ty {
739                TypeDecl::Alias(ty) => self.resolve(&ty.ty),
740                TypeDecl::Enum(ty) => Ok(Some(ty.ty().clone())),
741            },
742            item => Err(self.resolve_local_failed(SymbolResolutionError::invalid_symbol_type(
743                context,
744                "type",
745                item.span(),
746                &self.resolver.source_manager(),
747            ))),
748        }
749    }
750    #[inline(always)]
751    fn resolve_local_failed(&self, err: SymbolResolutionError) -> SymbolResolutionError {
752        err
753    }
754    fn resolve_type_ref(
755        &mut self,
756        path: Span<&Path>,
757    ) -> Result<SymbolResolution, SymbolResolutionError> {
758        self.resolver.resolve_path(path)
759    }
760}