miden_assembly_syntax/ast/
module.rs

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