abi_stable/abi_stability/abi_checking/
errors.rs
1use super::*;
2
3use core_extensions::StringExt;
4
5#[derive(Debug, PartialEq, Clone)]
7pub enum AbiInstability {
8 ReentrantLayoutCheckingCall,
9 CyclicTypeChecking {
10 interface: &'static TypeLayout,
11 implementation: &'static TypeLayout,
12 },
13 NonZeroness(ExpectedFound<bool>),
14 Name(ExpectedFound<FmtFullType>),
15 Package(ExpectedFound<RStr<'static>>),
16 PackageVersionParseError(ParseVersionError),
17 PackageVersion(ExpectedFound<VersionStrings>),
18 MismatchedPrefixSize(ExpectedFound<u8>),
19 Size(ExpectedFound<usize>),
20 Alignment(ExpectedFound<usize>),
21 GenericParamCount(ExpectedFound<FmtFullType>),
22 TLDataDiscriminant(ExpectedFound<TLDataDiscriminant>),
23 MismatchedPrimitive(ExpectedFound<TLPrimitive>),
24 FieldCountMismatch(ExpectedFound<usize>),
25 FieldLifetimeMismatch(ExpectedFound<TLField>),
26 FnLifetimeMismatch(ExpectedFound<TLFunction>),
27 FnQualifierMismatch(ExpectedFound<TLFunction>),
28 UnexpectedField(ExpectedFound<TLField>),
29 TooManyVariants(ExpectedFound<usize>),
30 MismatchedPrefixConditionality(ExpectedFound<FieldConditionality>),
31 MismatchedExhaustiveness(ExpectedFound<IsExhaustive>),
32 MismatchedConstParam(ExpectedFound<ConstGeneric>),
33 UnexpectedVariant(ExpectedFound<RStr<'static>>),
34 ReprAttr(ExpectedFound<ReprAttr>),
35 EnumDiscriminant(ExpectedFound<TLDiscriminant>),
36 IncompatibleWithNonExhaustive(IncompatibleWithNonExhaustive),
37 NoneExtraChecks,
38 ExtraCheckError(CmpIgnored<ExtraCheckError>),
39 TagError {
40 err: TagErrors,
41 },
42}
43
44#[derive(Debug, Clone)]
45pub struct ExtraCheckError {
46 pub err: RArc<RBoxError>,
47 pub expected_err: ExpectedFound<RArc<RBoxError>>,
48}
49
50use self::AbiInstability as AI;
51
52#[allow(dead_code)]
53impl AbiInstabilityErrors {
54 #[cfg(feature = "testing")]
55 pub fn flatten_errors(&self) -> RVec<AbiInstability> {
56 self.flattened_errors().collect::<RVec<AbiInstability>>()
57 }
58
59 #[cfg(feature = "testing")]
60 pub fn flattened_errors(&self) -> impl Iterator<Item = AbiInstability> + '_ {
61 self.errors.iter().flat_map(|x| &x.errs).cloned()
62 }
63}
64
65impl std::error::Error for AbiInstabilityErrors {}
66
67impl fmt::Debug for AbiInstabilityErrors {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 fmt::Display::fmt(self, f)
70 }
71}
72impl fmt::Display for AbiInstabilityErrors {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 writeln!(
75 f,
76 "Compared <this>:\n{}\nTo <other>:\n{}\n",
77 self.interface.to_string().left_padder(4),
78 self.implementation.to_string().left_padder(4),
79 )?;
80 for err in &self.errors {
81 fmt::Display::fmt(err, f)?;
82 }
83 Ok(())
84 }
85}
86
87impl fmt::Display for AbiInstabilityError {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 let mut extra_err = None::<String>;
90
91 write!(f, "{} error(s)", self.errs.len())?;
92 if self.stack_trace.is_empty() {
93 writeln!(f, ".")?;
94 } else {
95 writeln!(f, "inside:\n <other>\n")?;
96 }
97 for field in &self.stack_trace {
98 writeln!(f, "{}\n", field.found.to_string().left_padder(4))?;
99 }
100 if let Some(ExpectedFound { expected, found }) = self.stack_trace.last() {
101 writeln!(
102 f,
103 "Layout of expected type:\n{}\n\n\
104 Layout of found type:\n{}\n",
105 expected.formatted_layout().left_padder(4),
106 found.formatted_layout().left_padder(4),
107 )?;
108 }
109 writeln!(f)?;
110
111 for err in &self.errs {
112 let pair = match err {
113 AI::ReentrantLayoutCheckingCall => ("reentrant layout checking call", None),
114 AI::CyclicTypeChecking { interface, .. } => {
115 extra_err = Some(format!("The type:\n{}", interface));
116
117 (
118 "Attempted to check the layout of a type while checking the layout \
119 of one of it's const parameters/extra_checks\
120 (not necessarily a direct one).",
121 None,
122 )
123 }
124 AI::NonZeroness(v) => ("mismatched non-zeroness", v.display_str()),
125 AI::Name(v) => ("mismatched type", v.display_str()),
126 AI::Package(v) => ("mismatched package", v.display_str()),
127 AI::PackageVersionParseError(v) => {
128 let expected = "a valid version string".to_string();
129 let found = format!("{:#?}", v);
130
131 (
132 "could not parse version string",
133 Some(ExpectedFound { expected, found }),
134 )
135 }
136 AI::PackageVersion(v) => ("incompatible package versions", v.display_str()),
137 AI::MismatchedPrefixSize(v) => {
138 ("prefix-types have a different prefix", v.display_str())
139 }
140 AI::Size(v) => ("incompatible type size", v.display_str()),
141 AI::Alignment(v) => ("incompatible type alignment", v.display_str()),
142 AI::GenericParamCount(v) => {
143 ("incompatible amount of generic parameters", v.display_str())
144 }
145
146 AI::TLDataDiscriminant(v) => ("incompatible data ", v.debug_str()),
147 AI::MismatchedPrimitive(v) => ("incompatible primitive", v.debug_str()),
148 AI::FieldCountMismatch(v) => ("too many fields", v.display_str()),
149 AI::FnLifetimeMismatch(v) => (
150 "function pointers reference different lifetimes",
151 v.display_str(),
152 ),
153 AI::FnQualifierMismatch(v) => (
154 "function pointers have different qualifiers (`unsafe`, etc.)",
155 v.display_str(),
156 ),
157 AI::FieldLifetimeMismatch(v) => {
158 ("field references different lifetimes", v.display_str())
159 }
160 AI::UnexpectedField(v) => ("unexpected field", v.display_str()),
161 AI::TooManyVariants(v) => ("too many variants", v.display_str()),
162 AI::MismatchedPrefixConditionality(v) => (
163 "prefix fields differ in whether they are conditional",
164 v.debug_str(),
165 ),
166 AI::MismatchedExhaustiveness(v) => {
167 ("enums differ in whether they are exhaustive", v.debug_str())
168 }
169 AI::MismatchedConstParam(v) => {
170 ("The cconst parameters are different", v.debug_str())
171 }
172 AI::UnexpectedVariant(v) => ("unexpected variant", v.debug_str()),
173 AI::ReprAttr(v) => ("incompatible repr attributes", v.debug_str()),
174 AI::EnumDiscriminant(v) => ("different discriminants", v.debug_str()),
175 AI::IncompatibleWithNonExhaustive(e) => {
176 extra_err = Some(e.to_string());
177
178 ("", None)
179 }
180 AI::NoneExtraChecks => {
181 let msg = "\
182 Interface contains a value in `extra_checks` \
183 while the implementation does not.\
184 ";
185 (msg, None)
186 }
187 AI::ExtraCheckError(ec_error) => {
188 let ExtraCheckError { err, expected_err } = &**ec_error;
189 extra_err = Some((**err).to_string());
190
191 ("", expected_err.display_str())
192 }
193 AI::TagError { err } => {
194 extra_err = Some(err.to_string());
195
196 ("", None)
197 }
198 };
199
200 let (error_msg, expected_err): (&'static str, Option<ExpectedFound<String>>) = pair;
201
202 if let Some(expected_err) = expected_err {
203 writeln!(
204 f,
205 "\nError:{}\nExpected:\n{}\nFound:\n{}",
206 error_msg,
207 expected_err.expected.left_padder(4),
208 expected_err.found.left_padder(4),
209 )?;
210 }
211 if let Some(extra_err) = &extra_err {
212 writeln!(f, "\nExtra:\n{}\n", extra_err.left_padder(4))?;
213 }
214 }
215 Ok(())
216 }
217}
218
219#[derive(Clone, PartialEq)]
221#[repr(C)]
222pub struct AbiInstabilityErrors {
223 pub interface: &'static TypeLayout,
224 pub implementation: &'static TypeLayout,
225 pub errors: RVec<AbiInstabilityError>,
226 pub(super) _priv: (),
227}
228
229#[derive(Debug, Clone, PartialEq)]
234#[repr(C)]
235pub struct AbiInstabilityError {
236 pub stack_trace: RVec<ExpectedFound<TLFieldOrFunction>>,
237 pub errs: RVec<AbiInstability>,
238 pub index: usize,
239 pub(super) _priv: (),
240}