circomspect_program_structure/control_flow_graph/
errors.rs

1use thiserror::Error;
2
3use crate::report_code::ReportCode;
4use crate::report::Report;
5use crate::file_definition::{FileID, FileLocation};
6use crate::ir::errors::IRError;
7
8/// Error enum for CFG generation errors.
9#[derive(Debug, Error)]
10pub enum CFGError {
11    #[error("The variable `{name}` is read before it is declared/written.")]
12    UndefinedVariableError { name: String, file_id: Option<FileID>, file_location: FileLocation },
13    #[error("The variable name `{name}` contains invalid characters.")]
14    InvalidVariableNameError { name: String, file_id: Option<FileID>, file_location: FileLocation },
15    #[error("The declaration of the variable `{name}` shadows a previous declaration.")]
16    ShadowingVariableWarning {
17        name: String,
18        primary_file_id: Option<FileID>,
19        primary_location: FileLocation,
20        secondary_file_id: Option<FileID>,
21        secondary_location: FileLocation,
22    },
23    #[error("Multiple parameters with the same name `{name}` in function or template definition.")]
24    ParameterNameCollisionError {
25        name: String,
26        file_id: Option<FileID>,
27        file_location: FileLocation,
28    },
29}
30
31pub type CFGResult<T> = Result<T, CFGError>;
32
33impl CFGError {
34    pub fn into_report(self) -> Report {
35        use CFGError::*;
36        match self {
37            UndefinedVariableError { name, file_id, file_location } => {
38                let mut report = Report::error(
39                    format!("The variable `{name}` is used before it is defined."),
40                    ReportCode::UninitializedSymbolInExpression,
41                );
42                if let Some(file_id) = file_id {
43                    report.add_primary(
44                        file_location,
45                        file_id,
46                        format!("The variable `{name}` is first seen here."),
47                    );
48                }
49                report
50            }
51            InvalidVariableNameError { name, file_id, file_location } => {
52                let mut report = Report::error(
53                    format!("Invalid variable name `{name}`."),
54                    ReportCode::ParseFail,
55                );
56                if let Some(file_id) = file_id {
57                    report.add_primary(
58                        file_location,
59                        file_id,
60                        "This variable name contains invalid characters.".to_string(),
61                    );
62                }
63                report
64            }
65            ShadowingVariableWarning {
66                name,
67                primary_file_id,
68                primary_location,
69                secondary_file_id,
70                secondary_location,
71            } => {
72                let mut report = Report::warning(
73                    format!("Declaration of variable `{name}` shadows previous declaration."),
74                    ReportCode::ShadowingVariable,
75                );
76                if let Some(primary_file_id) = primary_file_id {
77                    report.add_primary(
78                        primary_location,
79                        primary_file_id,
80                        "Shadowing declaration here.".to_string(),
81                    );
82                }
83                if let Some(secondary_file_id) = secondary_file_id {
84                    report.add_secondary(
85                        secondary_location,
86                        secondary_file_id,
87                        Some("Shadowed variable is declared here.".to_string()),
88                    );
89                }
90                report.add_note(format!("Consider renaming the second occurrence of `{name}`."));
91                report
92            }
93            ParameterNameCollisionError { name, file_id, file_location } => {
94                let mut report = Report::warning(
95                    format!("Parameter `{name}` declared multiple times."),
96                    ReportCode::ParameterNameCollision,
97                );
98                if let Some(file_id) = file_id {
99                    report.add_primary(
100                        file_location,
101                        file_id,
102                        "Parameters declared here.".to_string(),
103                    );
104                }
105                report.add_note(format!("Rename the second occurrence of `{name}`."));
106                report
107            }
108        }
109    }
110}
111
112impl From<IRError> for CFGError {
113    fn from(error: IRError) -> CFGError {
114        match error {
115            IRError::UndefinedVariableError { name, file_id, file_location } => {
116                CFGError::UndefinedVariableError { name, file_id, file_location }
117            }
118            IRError::InvalidVariableNameError { name, file_id, file_location } => {
119                CFGError::InvalidVariableNameError { name, file_id, file_location }
120            }
121        }
122    }
123}
124
125impl From<CFGError> for Report {
126    fn from(error: CFGError) -> Report {
127        error.into_report()
128    }
129}