circomspect_program_structure/control_flow_graph/
errors.rs1use 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#[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}