1use std::ops::ControlFlow;
2
3use rustc_errors::{Diagnostic, ErrorGuaranteed};
4
5pub trait ErrorEmitter {
6 #[track_caller]
7 fn emit<'a>(&'a self, err: impl Diagnostic<'a>) -> ErrorGuaranteed;
8}
9
10pub trait ErrorCollector<E> {
11 type Result;
12
13 fn collect(&mut self, err: E);
14
15 fn into_result(self) -> Self::Result;
16}
17
18impl ErrorCollector<ErrorGuaranteed> for Option<ErrorGuaranteed> {
19 type Result = Result<(), ErrorGuaranteed>;
20
21 fn collect(&mut self, err: ErrorGuaranteed) {
22 *self = Some(err).or(*self);
23 }
24
25 fn into_result(self) -> Self::Result {
26 if let Some(err) = self { Err(err) } else { Ok(()) }
27 }
28}
29
30pub trait ResultExt<T, E> {
31 fn into_control_flow(self) -> ControlFlow<E, T>;
32
33 fn collect_err(self, collector: &mut impl ErrorCollector<E>) -> Option<T>;
34
35 #[track_caller]
36 fn emit<'a>(self, emitter: &'a impl ErrorEmitter) -> Result<T, ErrorGuaranteed>
37 where
38 E: Diagnostic<'a>;
39}
40
41impl<T, E> ResultExt<T, E> for Result<T, E> {
42 fn into_control_flow(self) -> ControlFlow<E, T> {
43 match self {
44 Ok(v) => ControlFlow::Continue(v),
45 Err(e) => ControlFlow::Break(e),
46 }
47 }
48
49 fn collect_err(self, collector: &mut impl ErrorCollector<E>) -> Option<T> {
50 match self {
51 Ok(v) => Some(v),
52 Err(err) => {
53 collector.collect(err);
54 None
55 }
56 }
57 }
58
59 #[track_caller]
60 fn emit<'a>(self, emitter: &'a impl ErrorEmitter) -> Result<T, ErrorGuaranteed>
61 where
62 E: Diagnostic<'a>,
63 {
64 match self {
65 Ok(v) => Ok(v),
66 Err(err) => Err(emitter.emit(err)),
67 }
68 }
69}