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::diagnostics::{Diagnostic, RelatedLabel, miette};
9
10/// Represents an error that occurs during symbol resolution
11#[derive(Debug, Clone, thiserror::Error, Diagnostic)]
12pub enum SymbolResolutionError {
13    #[error("undefined symbol reference")]
14    #[diagnostic(help("maybe you are missing an import?"))]
15    UndefinedSymbol {
16        #[label("this symbol path could not be resolved")]
17        span: SourceSpan,
18        #[source_code]
19        source_file: Option<Arc<SourceFile>>,
20    },
21    #[error("invalid symbol reference")]
22    #[diagnostic(help(
23        "references to a subpath of an imported symbol require the imported item to be a module"
24    ))]
25    InvalidAliasTarget {
26        #[label("this reference specifies a subpath relative to an import")]
27        span: SourceSpan,
28        #[source_code]
29        source_file: Option<Arc<SourceFile>>,
30        #[related]
31        relative_to: Option<RelatedLabel>,
32    },
33    #[error("invalid symbol path")]
34    #[diagnostic(help("all ancestors of a path must be modules"))]
35    InvalidSubPath {
36        #[label("this path specifies a subpath relative to another item")]
37        span: SourceSpan,
38        #[source_code]
39        source_file: Option<Arc<SourceFile>>,
40        #[related]
41        relative_to: Option<RelatedLabel>,
42    },
43    #[error("invalid symbol reference: wrong type")]
44    #[diagnostic()]
45    InvalidSymbolType {
46        expected: &'static str,
47        #[label("expected this symbol to reference a {expected} item")]
48        span: SourceSpan,
49        #[source_code]
50        source_file: Option<Arc<SourceFile>>,
51        #[related]
52        actual: Option<RelatedLabel>,
53    },
54    #[error("type expression nesting depth exceeded")]
55    #[diagnostic(help("type expression nesting exceeded the maximum depth of {max_depth}"))]
56    TypeExpressionDepthExceeded {
57        #[label("type expression nesting exceeded the configured depth limit")]
58        span: SourceSpan,
59        #[source_code]
60        source_file: Option<Arc<SourceFile>>,
61        max_depth: usize,
62    },
63    #[error("alias expansion cycle detected")]
64    #[diagnostic(help("alias expansion encountered a cycle"))]
65    AliasExpansionCycle {
66        #[label("this alias expansion is part of a cycle")]
67        span: SourceSpan,
68        #[source_code]
69        source_file: Option<Arc<SourceFile>>,
70    },
71    #[error("alias expansion depth exceeded")]
72    #[diagnostic(help("alias expansion exceeded the maximum depth of {max_depth}"))]
73    AliasExpansionDepthExceeded {
74        #[label("alias expansion exceeded the configured depth limit")]
75        span: SourceSpan,
76        #[source_code]
77        source_file: Option<Arc<SourceFile>>,
78        max_depth: usize,
79    },
80}
81
82impl SymbolResolutionError {
83    pub fn undefined(span: SourceSpan, source_manager: &dyn SourceManager) -> Self {
84        Self::UndefinedSymbol {
85            span,
86            source_file: source_manager.get(span.source_id()).ok(),
87        }
88    }
89
90    pub fn invalid_alias_target(
91        span: SourceSpan,
92        referrer: SourceSpan,
93        source_manager: &dyn SourceManager,
94    ) -> Self {
95        let referer_source_file = source_manager.get(referrer.source_id()).ok();
96        let source_file = source_manager.get(span.source_id()).ok();
97        Self::InvalidAliasTarget {
98            span,
99            source_file,
100            relative_to: Some(
101                RelatedLabel::advice("this reference specifies a subpath relative to an import")
102                    .with_labeled_span(
103                        referrer,
104                        "this reference specifies a subpath relative to an import",
105                    )
106                    .with_source_file(referer_source_file),
107            ),
108        }
109    }
110
111    pub fn invalid_sub_path(
112        span: SourceSpan,
113        relative_to: SourceSpan,
114        source_manager: &dyn SourceManager,
115    ) -> Self {
116        let relative_to_source_file = source_manager.get(relative_to.source_id()).ok();
117        let source_file = source_manager.get(span.source_id()).ok();
118        Self::InvalidSubPath {
119            span,
120            source_file,
121            relative_to: Some(
122                RelatedLabel::advice("but this item is not a module")
123                    .with_labeled_span(relative_to, "but this item is not a module")
124                    .with_source_file(relative_to_source_file),
125            ),
126        }
127    }
128
129    pub fn invalid_symbol_type(
130        span: SourceSpan,
131        expected: &'static str,
132        actual: SourceSpan,
133        source_manager: &dyn SourceManager,
134    ) -> Self {
135        let actual_source_file = source_manager.get(actual.source_id()).ok();
136        let source_file = source_manager.get(span.source_id()).ok();
137        Self::InvalidSymbolType {
138            expected,
139            span,
140            source_file,
141            actual: Some(
142                RelatedLabel::advice("but the symbol resolved to this item")
143                    .with_labeled_span(actual, "but the symbol resolved to this item")
144                    .with_source_file(actual_source_file),
145            ),
146        }
147    }
148
149    pub fn type_expression_depth_exceeded(
150        span: SourceSpan,
151        max_depth: usize,
152        source_manager: &dyn SourceManager,
153    ) -> Self {
154        Self::TypeExpressionDepthExceeded {
155            span,
156            source_file: source_manager.get(span.source_id()).ok(),
157            max_depth,
158        }
159    }
160
161    pub fn alias_expansion_cycle(span: SourceSpan, source_manager: &dyn SourceManager) -> Self {
162        Self::AliasExpansionCycle {
163            span,
164            source_file: source_manager.get(span.source_id()).ok(),
165        }
166    }
167
168    pub fn alias_expansion_depth_exceeded(
169        span: SourceSpan,
170        max_depth: usize,
171        source_manager: &dyn SourceManager,
172    ) -> Self {
173        Self::AliasExpansionDepthExceeded {
174            span,
175            source_file: source_manager.get(span.source_id()).ok(),
176            max_depth,
177        }
178    }
179}