logicaffeine_kernel/interface/lean/
diagnostic.rs1use std::fmt;
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
17pub enum DiagnosticCode {
18 InvalidProof,
21 MalformedExport,
23 UnsupportedExportVersion,
25 UnsupportedToolchain,
27 UnknownRecordKind,
29 UnknownField,
31 UnresolvedMetavariable,
33 MissingDeclaration,
35 DuplicateDeclaration,
37 MissingModule,
39 ImportCycle,
41 LeanRejected,
43 LeanAcceptanceNotObserved,
45 UnsupportedFeature,
47 RecheckRefused,
49 AuditIncomplete,
51 DisallowedAssumption,
53 AssumptionDisagreement,
55 ResourceLimit,
57 Infrastructure,
60 InternalInconsistency,
64 Usage,
66 Unclassified,
68}
69
70impl DiagnosticCode {
71 pub const ALL: [DiagnosticCode; 23] = [
72 DiagnosticCode::InvalidProof,
73 DiagnosticCode::MalformedExport,
74 DiagnosticCode::UnsupportedExportVersion,
75 DiagnosticCode::UnsupportedToolchain,
76 DiagnosticCode::UnknownRecordKind,
77 DiagnosticCode::UnknownField,
78 DiagnosticCode::UnresolvedMetavariable,
79 DiagnosticCode::MissingDeclaration,
80 DiagnosticCode::DuplicateDeclaration,
81 DiagnosticCode::MissingModule,
82 DiagnosticCode::ImportCycle,
83 DiagnosticCode::LeanRejected,
84 DiagnosticCode::LeanAcceptanceNotObserved,
85 DiagnosticCode::UnsupportedFeature,
86 DiagnosticCode::RecheckRefused,
87 DiagnosticCode::AuditIncomplete,
88 DiagnosticCode::DisallowedAssumption,
89 DiagnosticCode::AssumptionDisagreement,
90 DiagnosticCode::ResourceLimit,
91 DiagnosticCode::Infrastructure,
92 DiagnosticCode::InternalInconsistency,
93 DiagnosticCode::Usage,
94 DiagnosticCode::Unclassified,
95 ];
96
97 pub fn as_str(self) -> &'static str {
98 match self {
99 DiagnosticCode::InvalidProof => "invalid_proof",
100 DiagnosticCode::MalformedExport => "malformed_export",
101 DiagnosticCode::UnsupportedExportVersion => "unsupported_export_version",
102 DiagnosticCode::UnsupportedToolchain => "unsupported_toolchain",
103 DiagnosticCode::UnknownRecordKind => "unknown_record_kind",
104 DiagnosticCode::UnknownField => "unknown_field",
105 DiagnosticCode::UnresolvedMetavariable => "unresolved_metavariable",
106 DiagnosticCode::MissingDeclaration => "missing_declaration",
107 DiagnosticCode::DuplicateDeclaration => "duplicate_declaration",
108 DiagnosticCode::MissingModule => "missing_module",
109 DiagnosticCode::ImportCycle => "import_cycle",
110 DiagnosticCode::LeanRejected => "lean_rejected",
111 DiagnosticCode::LeanAcceptanceNotObserved => "lean_acceptance_not_observed",
112 DiagnosticCode::UnsupportedFeature => "unsupported_feature",
113 DiagnosticCode::RecheckRefused => "recheck_refused",
114 DiagnosticCode::AuditIncomplete => "audit_incomplete",
115 DiagnosticCode::DisallowedAssumption => "disallowed_assumption",
116 DiagnosticCode::AssumptionDisagreement => "assumption_disagreement",
117 DiagnosticCode::ResourceLimit => "resource_limit",
118 DiagnosticCode::Infrastructure => "infrastructure",
119 DiagnosticCode::InternalInconsistency => "internal_inconsistency",
120 DiagnosticCode::Usage => "usage",
121 DiagnosticCode::Unclassified => "unclassified",
122 }
123 }
124
125 pub fn from_wire(wire: &str) -> Option<Self> {
127 Self::ALL.into_iter().find(|code| code.as_str() == wire)
128 }
129
130 pub fn outcome(self) -> Option<Outcome> {
133 use DiagnosticCode as C;
134 Some(match self {
135 C::InvalidProof
136 | C::MalformedExport
137 | C::UnresolvedMetavariable
138 | C::MissingDeclaration
139 | C::DuplicateDeclaration
140 | C::MissingModule
141 | C::ImportCycle
142 | C::LeanRejected => Outcome::InvalidSource,
143 C::UnsupportedExportVersion
144 | C::UnsupportedToolchain
145 | C::UnknownRecordKind
146 | C::UnknownField
147 | C::LeanAcceptanceNotObserved
148 | C::UnsupportedFeature
149 | C::RecheckRefused
150 | C::AuditIncomplete => Outcome::UnsupportedFeature,
151 C::DisallowedAssumption | C::AssumptionDisagreement => Outcome::DisallowedAssumptions,
152 C::ResourceLimit => Outcome::ResourceLimit,
153 C::Infrastructure | C::InternalInconsistency => Outcome::InfrastructureFailure,
154 C::Usage | C::Unclassified => return None,
155 })
156 }
157}
158
159impl fmt::Display for DiagnosticCode {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 f.write_str(self.as_str())
162 }
163}
164
165#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
167pub enum Outcome {
168 Verified,
170 InvalidSource,
172 UnsupportedFeature,
174 DisallowedAssumptions,
176 ResourceLimit,
178 InfrastructureFailure,
180}
181
182impl Outcome {
183 pub const ALL: [Outcome; 6] = [
184 Outcome::Verified,
185 Outcome::InvalidSource,
186 Outcome::UnsupportedFeature,
187 Outcome::DisallowedAssumptions,
188 Outcome::ResourceLimit,
189 Outcome::InfrastructureFailure,
190 ];
191
192 pub fn as_str(self) -> &'static str {
193 match self {
194 Outcome::Verified => "verified",
195 Outcome::InvalidSource => "invalid_source",
196 Outcome::UnsupportedFeature => "unsupported_feature",
197 Outcome::DisallowedAssumptions => "disallowed_assumptions",
198 Outcome::ResourceLimit => "resource_limit",
199 Outcome::InfrastructureFailure => "infrastructure_failure",
200 }
201 }
202
203 pub fn exit_code(self) -> i32 {
206 match self {
207 Outcome::Verified => 0,
208 Outcome::InvalidSource => 1,
209 Outcome::UnsupportedFeature => 2,
210 Outcome::DisallowedAssumptions => 3,
211 Outcome::ResourceLimit => 4,
212 Outcome::InfrastructureFailure => 5,
213 }
214 }
215
216 pub fn of_refusal(code: DiagnosticCode, rejected: bool) -> Outcome {
219 code.outcome().unwrap_or(if rejected {
220 Outcome::InvalidSource
221 } else {
222 Outcome::UnsupportedFeature
223 })
224 }
225}
226
227impl fmt::Display for Outcome {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 f.write_str(self.as_str())
230 }
231}
232
233#[derive(Clone, PartialEq, Eq)]
236pub struct Reason {
237 code: DiagnosticCode,
238 message: String,
239 line: Option<usize>,
240 declaration: Option<String>,
241 stage: Option<&'static str>,
242}
243
244impl Reason {
245 pub fn new(code: DiagnosticCode, message: impl Into<String>) -> Self {
246 Reason {
247 code,
248 message: message.into(),
249 line: None,
250 declaration: None,
251 stage: None,
252 }
253 }
254 pub fn code(&self) -> DiagnosticCode {
255 self.code
256 }
257 pub fn stage(&self) -> Option<&'static str> {
260 self.stage
261 }
262 pub fn at_stage(self, stage: &'static str) -> Self {
264 Reason {
265 stage: Some(stage),
266 ..self
267 }
268 }
269 pub fn message(&self) -> &str {
270 &self.message
271 }
272 pub fn line(&self) -> Option<usize> {
274 self.line
275 }
276 pub fn declaration(&self) -> Option<&str> {
278 self.declaration.as_deref()
279 }
280 pub fn located(self, prefix: impl fmt::Display) -> Self {
282 Reason {
283 message: format!("{prefix}: {}", self.message),
284 ..self
285 }
286 }
287 pub fn at_line(self, line: usize) -> Self {
290 Reason {
291 line: self.line.or(Some(line)),
292 ..self
293 }
294 }
295 pub fn in_declaration(self, declaration: impl Into<String>) -> Self {
297 let declaration = self
298 .declaration
299 .clone()
300 .or_else(|| Some(declaration.into()));
301 Reason {
302 declaration,
303 ..self
304 }
305 }
306}
307
308impl std::ops::Deref for Reason {
309 type Target = str;
310 fn deref(&self) -> &str {
311 &self.message
312 }
313}
314
315impl fmt::Display for Reason {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 f.write_str(&self.message)
318 }
319}
320
321impl fmt::Debug for Reason {
323 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324 fmt::Debug::fmt(&self.message, f)
325 }
326}