air_parser/sema/
errors.rs

1use miden_diagnostics::{Diagnostic, Label, SourceSpan, Spanned, ToDiagnostic};
2
3use crate::ast::{Identifier, InvalidExprError, InvalidTypeError, ModuleId};
4
5/// Represents the various module validation errors we might encounter during semantic analysis.
6#[derive(Clone, Debug, thiserror::Error)]
7pub enum SemanticAnalysisError {
8    #[error("root module is missing")]
9    MissingRoot,
10    #[error(
11        "root module must contain at both boundary_constraints and integrity_constraints sections"
12    )]
13    MissingConstraints,
14    #[error("root module must contain a public_inputs section")]
15    MissingPublicInputs,
16    #[error("reference to unknown module '{0}'")]
17    MissingModule(ModuleId),
18    #[error("invalid use of restricted section type in library module")]
19    RootSectionInLibrary(SourceSpan),
20    #[error("invalid import of root module")]
21    RootImport(SourceSpan),
22    #[error("name already in use")]
23    NameConflict(SourceSpan),
24    #[error("import refers to undefined item in '{0}'")]
25    ImportUndefined(ModuleId),
26    #[error("cannot import from self")]
27    ImportSelf(SourceSpan),
28    #[error("import conflict")]
29    ImportConflict { item: Identifier, prev: SourceSpan },
30    #[error("import failed")]
31    ImportFailed(SourceSpan),
32    #[error(transparent)]
33    InvalidExpr(#[from] InvalidExprError),
34    #[error(transparent)]
35    InvalidType(#[from] InvalidTypeError),
36    #[error("module is invalid, see diagnostics for details")]
37    Invalid,
38}
39impl Eq for SemanticAnalysisError {}
40impl PartialEq for SemanticAnalysisError {
41    fn eq(&self, other: &Self) -> bool {
42        match (self, other) {
43            (Self::MissingModule(lm), Self::MissingModule(rm)) => lm == rm,
44            (Self::ImportUndefined(lm), Self::ImportUndefined(rm)) => lm == rm,
45            (Self::ImportConflict { item: li, .. }, Self::ImportConflict { item: ri, .. }) => {
46                li == ri
47            }
48            (Self::InvalidExpr(l), Self::InvalidExpr(r)) => l == r,
49            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
50        }
51    }
52}
53impl ToDiagnostic for SemanticAnalysisError {
54    fn to_diagnostic(self) -> Diagnostic {
55        match self {
56            Self::MissingRoot => Diagnostic::error().with_message("no root module found"),
57            Self::MissingConstraints => Diagnostic::error().with_message("root module must contain both boundary_constraints and integrity_constraints sections"),
58            Self::MissingPublicInputs => Diagnostic::error().with_message("root module must contain a public_inputs section"),
59            Self::MissingModule(id) => Diagnostic::error()
60                .with_message("found reference to module which does not exist")
61                .with_labels(vec![Label::primary(id.span().source_id(), id.span()).with_message("this module could not be found")]),
62            Self::RootSectionInLibrary(span) => Diagnostic::error()
63                .with_message("invalid use of restricted section type in library module")
64                .with_labels(vec![Label::primary(span.source_id(), span)
65                    .with_message("invalid declaration occurs here")]),
66            Self::RootImport(span) => Diagnostic::error()
67                .with_message("invalid import of root module")
68                .with_labels(vec![Label::primary(span.source_id(), span)
69                    .with_message("invalid declaration occurs here")])
70                .with_notes(vec!["The root module may not be imported. Try extracting the items you wish to import into a library module".to_string()]),
71            Self::NameConflict(span) => Diagnostic::error()
72                .with_message("name already in use")
73                .with_labels(vec![Label::primary(span.source_id(), span)
74                    .with_message("conflicting definition occurs here")]),
75            Self::ImportUndefined(from) => Diagnostic::error()
76                .with_message("invalid import")
77                .with_labels(vec![Label::primary(from.span().source_id(), from.span())
78                    .with_message(format!("no such item in '{from}'"))]),
79            Self::ImportSelf(span) => Diagnostic::error()
80                .with_message("invalid import")
81                .with_labels(vec![Label::primary(span.source_id(), span)
82                    .with_message("cannot import a module from within itself")]),
83            Self::ImportConflict { item, prev } => Diagnostic::error()
84                .with_message("conflicting import")
85                .with_labels(vec![Label::primary(item.span().source_id(), item.span())
86                    .with_message(format!("the item '{item}' is imported here")),
87                                  Label::secondary(prev.source_id(), prev)
88                    .with_message("but it conflicts with an item of the same name here")]),
89            Self::ImportFailed(span) => Diagnostic::error()
90                .with_message("error occurred while resolving an import")
91                .with_labels(vec![Label::primary(span.source_id(), span)
92                    .with_message("failed import occurred here")]),
93            Self::InvalidExpr(err) => err.to_diagnostic(),
94            Self::InvalidType(err) => err.to_diagnostic(),
95            Self::Invalid => Diagnostic::error().with_message("module is invalid, see diagnostics for details"),
96        }
97    }
98}