Skip to main content

miden_assembly_syntax/ast/item/resolver/
error.rs

1// Allow unused assignments - required by miette::Diagnostic derive macro
2#![allow(unused_assignments)]
3
4use alloc::sync::Arc;
5
6use miden_debug_types::{SourceFile, SourceManager, SourceSpan};
7
8use crate::{
9    ast::ItemIndex,
10    diagnostics::{Diagnostic, RelatedLabel, miette},
11};
12
13/// Represents an error that occurs during symbol resolution
14#[derive(Debug, Clone, thiserror::Error, Diagnostic)]
15pub enum SymbolResolutionError {
16    #[error("undefined symbol reference")]
17    #[diagnostic(help("maybe you are missing an import?"))]
18    UndefinedSymbol {
19        #[label("this symbol path could not be resolved")]
20        span: SourceSpan,
21        #[source_code]
22        source_file: Option<Arc<SourceFile>>,
23    },
24    #[error("invalid symbol reference")]
25    #[diagnostic(help(
26        "references to a subpath of an imported symbol require the imported item to be a module"
27    ))]
28    InvalidAliasTarget {
29        #[label("this reference specifies a subpath relative to an import")]
30        span: SourceSpan,
31        #[source_code]
32        source_file: Option<Arc<SourceFile>>,
33        #[related]
34        relative_to: Option<RelatedLabel>,
35    },
36    #[error("invalid symbol path")]
37    #[diagnostic(help("all ancestors of a path must be modules"))]
38    InvalidSubPath {
39        #[label("this path specifies a subpath relative to another item")]
40        span: SourceSpan,
41        #[source_code]
42        source_file: Option<Arc<SourceFile>>,
43        #[related]
44        relative_to: Option<RelatedLabel>,
45    },
46    #[error("invalid symbol reference: wrong type")]
47    #[diagnostic()]
48    InvalidSymbolType {
49        expected: &'static str,
50        #[label("expected this symbol to reference a {expected} item")]
51        span: SourceSpan,
52        #[source_code]
53        source_file: Option<Arc<SourceFile>>,
54        #[related]
55        actual: Option<RelatedLabel>,
56    },
57    #[error("private symbol reference")]
58    #[diagnostic(help("only public items can be referenced from another module"))]
59    PrivateSymbol {
60        #[label("this symbol is private to another module")]
61        span: SourceSpan,
62        #[source_code]
63        source_file: Option<Arc<SourceFile>>,
64        #[related]
65        defined: Option<RelatedLabel>,
66    },
67    #[error("type expression nesting depth exceeded")]
68    #[diagnostic(help("type expression nesting exceeded the maximum depth of {max_depth}"))]
69    TypeExpressionDepthExceeded {
70        #[label("type expression nesting exceeded the configured depth limit")]
71        span: SourceSpan,
72        #[source_code]
73        source_file: Option<Arc<SourceFile>>,
74        max_depth: usize,
75    },
76    #[error("alias expansion cycle detected")]
77    #[diagnostic(help("alias expansion encountered a cycle"))]
78    AliasExpansionCycle {
79        #[label("this alias expansion is part of a cycle")]
80        span: SourceSpan,
81        #[source_code]
82        source_file: Option<Arc<SourceFile>>,
83    },
84    #[error("alias expansion depth exceeded")]
85    #[diagnostic(help("alias expansion exceeded the maximum depth of {max_depth}"))]
86    AliasExpansionDepthExceeded {
87        #[label("alias expansion exceeded the configured depth limit")]
88        span: SourceSpan,
89        #[source_code]
90        source_file: Option<Arc<SourceFile>>,
91        max_depth: usize,
92    },
93    #[error("too many items in module")]
94    #[diagnostic(help("break this module up into smaller modules"))]
95    TooManyItemsInModule {
96        #[label("module item count exceeds the supported limit of {max_items}")]
97        span: SourceSpan,
98        #[source_code]
99        source_file: Option<Arc<SourceFile>>,
100        max_items: usize,
101    },
102}
103
104impl SymbolResolutionError {
105    pub fn undefined(span: SourceSpan, source_manager: &dyn SourceManager) -> Self {
106        Self::UndefinedSymbol {
107            span,
108            source_file: source_manager.get(span.source_id()).ok(),
109        }
110    }
111
112    pub fn invalid_alias_target(
113        span: SourceSpan,
114        referrer: SourceSpan,
115        source_manager: &dyn SourceManager,
116    ) -> Self {
117        let referer_source_file = source_manager.get(referrer.source_id()).ok();
118        let source_file = source_manager.get(span.source_id()).ok();
119        Self::InvalidAliasTarget {
120            span,
121            source_file,
122            relative_to: Some(
123                RelatedLabel::advice("this reference specifies a subpath relative to an import")
124                    .with_labeled_span(
125                        referrer,
126                        "this reference specifies a subpath relative to an import",
127                    )
128                    .with_source_file(referer_source_file),
129            ),
130        }
131    }
132
133    pub fn invalid_sub_path(
134        span: SourceSpan,
135        relative_to: SourceSpan,
136        source_manager: &dyn SourceManager,
137    ) -> Self {
138        let relative_to_source_file = source_manager.get(relative_to.source_id()).ok();
139        let source_file = source_manager.get(span.source_id()).ok();
140        Self::InvalidSubPath {
141            span,
142            source_file,
143            relative_to: Some(
144                RelatedLabel::advice("but this item is not a module")
145                    .with_labeled_span(relative_to, "but this item is not a module")
146                    .with_source_file(relative_to_source_file),
147            ),
148        }
149    }
150
151    pub fn invalid_symbol_type(
152        span: SourceSpan,
153        expected: &'static str,
154        actual: SourceSpan,
155        source_manager: &dyn SourceManager,
156    ) -> Self {
157        let actual_source_file = source_manager.get(actual.source_id()).ok();
158        let source_file = source_manager.get(span.source_id()).ok();
159        Self::InvalidSymbolType {
160            expected,
161            span,
162            source_file,
163            actual: Some(
164                RelatedLabel::advice("but the symbol resolved to this item")
165                    .with_labeled_span(actual, "but the symbol resolved to this item")
166                    .with_source_file(actual_source_file),
167            ),
168        }
169    }
170
171    pub fn private_symbol(
172        span: SourceSpan,
173        defined: SourceSpan,
174        source_manager: &dyn SourceManager,
175    ) -> Self {
176        let defined_source_file = source_manager.get(defined.source_id()).ok();
177        let source_file = source_manager.get(span.source_id()).ok();
178        Self::PrivateSymbol {
179            span,
180            source_file,
181            defined: Some(
182                RelatedLabel::advice("the referenced item is private")
183                    .with_labeled_span(defined, "the referenced item is private")
184                    .with_source_file(defined_source_file),
185            ),
186        }
187    }
188
189    pub fn type_expression_depth_exceeded(
190        span: SourceSpan,
191        max_depth: usize,
192        source_manager: &dyn SourceManager,
193    ) -> Self {
194        Self::TypeExpressionDepthExceeded {
195            span,
196            source_file: source_manager.get(span.source_id()).ok(),
197            max_depth,
198        }
199    }
200
201    pub fn alias_expansion_cycle(span: SourceSpan, source_manager: &dyn SourceManager) -> Self {
202        Self::AliasExpansionCycle {
203            span,
204            source_file: source_manager.get(span.source_id()).ok(),
205        }
206    }
207
208    pub fn alias_expansion_depth_exceeded(
209        span: SourceSpan,
210        max_depth: usize,
211        source_manager: &dyn SourceManager,
212    ) -> Self {
213        Self::AliasExpansionDepthExceeded {
214            span,
215            source_file: source_manager.get(span.source_id()).ok(),
216            max_depth,
217        }
218    }
219
220    pub fn too_many_items_in_module(span: SourceSpan, source_manager: &dyn SourceManager) -> Self {
221        Self::TooManyItemsInModule {
222            span,
223            source_file: source_manager.get(span.source_id()).ok(),
224            max_items: ItemIndex::MAX_ITEMS,
225        }
226    }
227}