Skip to main content

ir_lang/
error.rs

1//! The errors of declaring, building, and validating IR.
2
3use alloc::string::String;
4use core::fmt;
5
6use crate::entity::{AggId, Block, FuncId, GlobalId, Inst, SigId, StackSlot, Value};
7use crate::ops::PolicyFields;
8use crate::types::Type;
9
10/// Why a module-level declaration was refused.
11///
12/// Every variant names what was wrong, so a front end can report it against its own
13/// source. The enum is `#[non_exhaustive]`.
14///
15/// # Examples
16///
17/// ```
18/// use ir_lang::{Linkage, Module, ModuleError, Signature};
19///
20/// let mut m = Module::new("m");
21/// let sig = Signature::new(&[], &[]);
22/// m.declare_function("f", &sig, Linkage::Export)?;
23/// let err = m.declare_function("f", &sig, Linkage::Export).unwrap_err();
24/// assert_eq!(err, ModuleError::DuplicateName { name: "f".into() });
25/// # Ok::<(), ModuleError>(())
26/// ```
27#[derive(Clone, PartialEq, Eq, Debug)]
28#[non_exhaustive]
29pub enum ModuleError {
30    /// A function or global with this name already exists. Symbol names are one
31    /// namespace per module.
32    DuplicateName {
33        /// The repeated name.
34        name: String,
35    },
36    /// A symbol name was empty.
37    EmptyName,
38    /// The function handle does not name a declaration of this module.
39    UnknownFunction {
40        /// The handle.
41        func: FuncId,
42    },
43    /// The global handle does not name a declaration of this module.
44    UnknownGlobal {
45        /// The handle.
46        global: GlobalId,
47    },
48    /// An aggregate names an aggregate that is not declared before it.
49    UnknownAggregate {
50        /// The handle.
51        agg: AggId,
52    },
53    /// An aggregate's size exceeds [`MAX_AGGREGATE_SIZE`](crate::MAX_AGGREGATE_SIZE).
54    AggregateTooLarge,
55    /// An alignment is zero, not a power of two, or larger than allowed.
56    BadAlignment {
57        /// The alignment.
58        align: u64,
59    },
60    /// A global's initializer length differs from its declared size.
61    InitSizeMismatch {
62        /// The declared size.
63        size: u64,
64        /// The initializer length.
65        found: u64,
66    },
67    /// A relocation does not fit inside its global (`offset + pointer size > size`).
68    RelocOutOfRange {
69        /// The relocation offset.
70        offset: u64,
71    },
72    /// An imported global was given an initializer or relocations.
73    ImportWithData,
74    /// An imported function cannot have a body.
75    CannotDefineImport {
76        /// The function.
77        func: FuncId,
78    },
79    /// The function already has a body (use `Module::edit` to change it).
80    AlreadyDefined {
81        /// The function.
82        func: FuncId,
83    },
84    /// The function has no body yet (use `Module::build` to create one).
85    NotDefined {
86        /// The function.
87        func: FuncId,
88    },
89    /// A table of the module reached its capacity (`u32::MAX - 1` entries).
90    CapacityExceeded,
91}
92
93impl fmt::Display for ModuleError {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            ModuleError::DuplicateName { name } => write!(f, "symbol `{name}` is already declared"),
97            ModuleError::EmptyName => f.write_str("symbol names must not be empty"),
98            ModuleError::UnknownFunction { func } => write!(f, "unknown function {func}"),
99            ModuleError::UnknownGlobal { global } => write!(f, "unknown global {global}"),
100            ModuleError::UnknownAggregate { agg } => {
101                write!(f, "aggregate {agg} is not declared before its use")
102            }
103            ModuleError::AggregateTooLarge => f.write_str("aggregate size exceeds 2^48 bytes"),
104            ModuleError::BadAlignment { align } => {
105                write!(f, "alignment {align} is not a supported power of two")
106            }
107            ModuleError::InitSizeMismatch { size, found } => {
108                write!(
109                    f,
110                    "initializer has {found} bytes but the global is {size} bytes"
111                )
112            }
113            ModuleError::RelocOutOfRange { offset } => {
114                write!(
115                    f,
116                    "relocation at offset {offset} does not fit in its global"
117                )
118            }
119            ModuleError::ImportWithData => {
120                f.write_str("an imported global cannot have an initializer or relocations")
121            }
122            ModuleError::CannotDefineImport { func } => {
123                write!(f, "function {func} is imported and cannot have a body")
124            }
125            ModuleError::AlreadyDefined { func } => write!(f, "function {func} already has a body"),
126            ModuleError::NotDefined { func } => write!(f, "function {func} has no body"),
127            ModuleError::CapacityExceeded => f.write_str("module table capacity exceeded"),
128        }
129    }
130}
131
132impl core::error::Error for ModuleError {}
133
134/// What is wrong, for a [`ValidationError`] (and for a [`BuildError::Invalid`]).
135///
136/// The enum is `#[non_exhaustive]`: new checks may add variants in a minor release.
137#[derive(Clone, PartialEq, Eq, Debug)]
138#[non_exhaustive]
139pub enum ValidationErrorKind {
140    // ----- module level -----
141    /// Two symbols share a name.
142    DuplicateName {
143        /// The name.
144        name: String,
145    },
146    /// A symbol name is empty.
147    EmptyName,
148    /// A signature handle is out of range.
149    UnknownSignature {
150        /// The handle.
151        sig: SigId,
152    },
153    /// A function handle is out of range.
154    UnknownFunction {
155        /// The handle.
156        func: FuncId,
157    },
158    /// A global handle is out of range.
159    UnknownGlobal {
160        /// The handle.
161        global: GlobalId,
162    },
163    /// An aggregate handle is out of range, or names a later aggregate.
164    UnknownAggregate {
165        /// The handle.
166        agg: AggId,
167    },
168    /// An aggregate's recorded layout is inconsistent or too large.
169    BadAggregate {
170        /// The aggregate.
171        agg: AggId,
172    },
173    /// An alignment is not a supported power of two.
174    BadAlignment {
175        /// The alignment.
176        align: u64,
177    },
178    /// A global's initializer or relocations are inconsistent with its size or
179    /// linkage.
180    BadGlobal {
181        /// The global.
182        global: GlobalId,
183    },
184    /// A defined (local or exported) function has no body.
185    MissingBody,
186    /// An imported function has a body.
187    ImportWithBody,
188
189    // ----- function structure -----
190    /// The entry block handle is out of range or the block was removed.
191    BadEntry,
192    /// The entry block's parameters do not match the signature's parameters.
193    EntryParams {
194        /// The signature's parameter types count.
195        expected: usize,
196        /// The entry block's parameter count.
197        found: usize,
198    },
199    /// A block has no terminator.
200    MissingTerminator,
201    /// An edge targets a block that does not exist or was removed.
202    BadBlockTarget {
203        /// The target.
204        target: Block,
205    },
206    /// An edge targets the entry block, which must have no predecessors.
207    EntryBranchTarget,
208    /// The block's instruction list is corrupt (a link is out of range, points
209    /// into another block, or loops).
210    CorruptLayout,
211    /// A value handle is out of range.
212    ValueOutOfRange {
213        /// The handle.
214        value: Value,
215    },
216    /// A value's recorded definition disagrees with the block parameter list or the
217    /// instruction result range that lists it.
218    InconsistentDefinition {
219        /// The value.
220        value: Value,
221    },
222    /// A value is listed as defined at two sites.
223    DefinedTwice {
224        /// The value.
225        value: Value,
226    },
227    /// A value whose definition was removed is still used.
228    UseOfDetached {
229        /// The value.
230        value: Value,
231    },
232    /// A value's forwarding (from `replace_all_uses`) is inconsistent: it loops or
233    /// changes type.
234    BadAlias {
235        /// The value.
236        value: Value,
237    },
238    /// A value is used where its definition does not dominate the use.
239    UseBeforeDef {
240        /// The value.
241        value: Value,
242    },
243    /// A stack slot handle is out of range, or a slot has a bad size or alignment.
244    BadSlot {
245        /// The slot.
246        slot: StackSlot,
247    },
248
249    // ----- typing -----
250    /// A value has the wrong type for its position.
251    TypeMismatch {
252        /// The value (or `None` for a terminator-produced edge argument).
253        value: Option<Value>,
254        /// The required type.
255        expected: Type,
256        /// The actual type.
257        found: Type,
258    },
259    /// An operand's type is not one the operation accepts.
260    BadOperandType {
261        /// The operation's opcode.
262        op: &'static str,
263        /// The operand's type.
264        found: Type,
265    },
266    /// A conversion between these types is not allowed for this conversion op.
267    BadConversion {
268        /// The conversion's opcode.
269        op: &'static str,
270        /// The source type.
271        from: Type,
272        /// The result type.
273        to: Type,
274    },
275    /// An operation instance does not carry exactly the policy fields it needs.
276    PolicyMismatch {
277        /// The operation's opcode.
278        op: &'static str,
279        /// The fields it must carry.
280        required: PolicyFields,
281    },
282    /// An operation that can raise an error (a policy field is `error`, or
283    /// `char_from_u32`) appears as a plain instruction; it must be the operation of
284    /// a `check` terminator.
285    ErrorOutsideCheck {
286        /// The opcode.
287        op: &'static str,
288    },
289    /// A `check` terminator holds an operation that cannot raise an error, or an
290    /// instruction that is not a unary, binary, or conversion operation.
291    NotFallible {
292        /// The opcode.
293        op: &'static str,
294    },
295    /// A constant's bits do not fit its type (or a `ptr`/`ref` constant is not 0).
296    BadConst {
297        /// The type.
298        ty: Type,
299        /// The bits.
300        bits: u64,
301    },
302    /// A struct field index is out of range, or the aggregate is not a struct.
303    BadField {
304        /// The aggregate.
305        agg: AggId,
306        /// The field index.
307        field: u32,
308    },
309    /// An atomic operation has an ordering it may not have.
310    BadOrdering,
311    /// An instruction's recorded result values disagree with what it produces (count
312    /// or types).
313    ResultMismatch,
314    /// A call passes the wrong number of arguments, or a return passes the wrong
315    /// number of values.
316    ArgCount {
317        /// The required count.
318        expected: usize,
319        /// The supplied count.
320        found: usize,
321    },
322    /// An edge passes the wrong number of arguments for its target's parameters.
323    EdgeArgCount {
324        /// The target block.
325        target: Block,
326        /// The target's parameter count.
327        expected: usize,
328        /// The supplied count.
329        found: usize,
330    },
331    /// A switch has two cases with the same value, or a case value does not fit
332    /// the scrutinee's type.
333    BadSwitchCase {
334        /// The case value.
335        value: u64,
336    },
337    /// A tail call's callee returns or convention differ from this function's, or
338    /// a tail call carries a GC list.
339    BadTailCall,
340    /// A GC list entry is not a `ref`, or a `nogc` call carries a GC list.
341    BadGcList,
342
343    // ----- exception edges -----
344    /// An edge argument is a `Result`, `Exception`, or `ErrorCode` where that kind is
345    /// not allowed, or a `Result` index is out of range.
346    BadEdgeArg,
347    /// A landing pad (the target of an unwind edge) also has a non-unwind
348    /// predecessor, or an `invoke`'s normal and unwind edges target one block.
349    LandingPadPredecessor {
350        /// The landing pad.
351        block: Block,
352    },
353    /// A `nounwind` function contains a `resume`, or a call that may unwind
354    /// without an `invoke`.
355    UnwindInNounwind,
356    /// A `noreturn` function contains a `ret`.
357    ReturnInNoreturn,
358    /// A `nogc` function contains a safepoint.
359    SafepointInNogc,
360
361    // ----- safepoints -----
362    /// A `ref` value, or a pointer derived from one, is live across a safepoint
363    /// without being relocated through its GC list.
364    LiveAcrossSafepoint {
365        /// The value.
366        value: Value,
367    },
368    /// A pointer derived from a `ref` escapes tracking: it is stored to memory or
369    /// passed to a call that is a safepoint.
370    DerivedPointerEscapes {
371        /// The value.
372        value: Value,
373    },
374}
375
376impl fmt::Display for ValidationErrorKind {
377    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378        use ValidationErrorKind as K;
379        match self {
380            K::DuplicateName { name } => write!(f, "symbol `{name}` is declared twice"),
381            K::EmptyName => f.write_str("a symbol name is empty"),
382            K::UnknownSignature { sig } => write!(f, "unknown signature {sig}"),
383            K::UnknownFunction { func } => write!(f, "unknown function {func}"),
384            K::UnknownGlobal { global } => write!(f, "unknown global {global}"),
385            K::UnknownAggregate { agg } => write!(f, "unknown or forward aggregate {agg}"),
386            K::BadAggregate { agg } => write!(f, "aggregate {agg} has an invalid layout"),
387            K::BadAlignment { align } => write!(f, "alignment {align} is not supported"),
388            K::BadGlobal { global } => write!(f, "global {global} has an invalid initializer"),
389            K::MissingBody => f.write_str("a defined function has no body"),
390            K::ImportWithBody => f.write_str("an imported function has a body"),
391            K::BadEntry => f.write_str("the entry block is missing"),
392            K::EntryParams { expected, found } => write!(
393                f,
394                "the entry block has {found} parameters but the signature has {expected}"
395            ),
396            K::MissingTerminator => f.write_str("block has no terminator"),
397            K::BadBlockTarget { target } => write!(f, "edge targets missing block {target}"),
398            K::EntryBranchTarget => f.write_str("an edge targets the entry block"),
399            K::CorruptLayout => f.write_str("the block's instruction list is corrupt"),
400            K::ValueOutOfRange { value } => write!(f, "reference to nonexistent value {value}"),
401            K::InconsistentDefinition { value } => {
402                write!(f, "value {value} disagrees with its definition site")
403            }
404            K::DefinedTwice { value } => write!(f, "value {value} is defined twice"),
405            K::UseOfDetached { value } => write!(f, "value {value} is used but no longer defined"),
406            K::BadAlias { value } => write!(f, "value {value} has an invalid forwarding"),
407            K::UseBeforeDef { value } => {
408                write!(
409                    f,
410                    "value {value} is used where its definition does not dominate"
411                )
412            }
413            K::BadSlot { slot } => write!(f, "invalid stack slot {slot}"),
414            K::TypeMismatch {
415                value: Some(v),
416                expected,
417                found,
418            } => write!(f, "value {v} has type {found}, expected {expected}"),
419            K::TypeMismatch {
420                value: None,
421                expected,
422                found,
423            } => write!(f, "edge argument has type {found}, expected {expected}"),
424            K::BadOperandType { op, found } => write!(f, "`{op}` does not accept {found}"),
425            K::BadConversion { op, from, to } => write!(f, "`{op}` cannot convert {from} to {to}"),
426            K::PolicyMismatch { op, required } => {
427                write!(f, "`{op}` must carry exactly the policy fields {required}")
428            }
429            K::ErrorOutsideCheck { op } => write!(
430                f,
431                "`{op}` can raise an error and must be the operation of a `check` terminator"
432            ),
433            K::NotFallible { op } => write!(f, "`check` holds `{op}`, which cannot raise an error"),
434            K::BadConst { ty, bits } => write!(f, "constant {bits:#x} does not fit {ty}"),
435            K::BadField { agg, field } => write!(f, "{agg} has no field {field}"),
436            K::BadOrdering => f.write_str("invalid memory ordering for this atomic operation"),
437            K::ResultMismatch => {
438                f.write_str("the instruction's results disagree with what it produces")
439            }
440            K::ArgCount { expected, found } => {
441                write!(f, "expected {expected} arguments, found {found}")
442            }
443            K::EdgeArgCount {
444                target,
445                expected,
446                found,
447            } => write!(
448                f,
449                "edge to {target} passes {found} arguments for {expected} parameters"
450            ),
451            K::BadSwitchCase { value } => {
452                write!(f, "switch case {value} is repeated or out of range")
453            }
454            K::BadTailCall => {
455                f.write_str("tail call does not match this function's returns and convention")
456            }
457            K::BadGcList => f.write_str("invalid GC list"),
458            K::BadEdgeArg => f.write_str("edge argument not allowed on this edge"),
459            K::LandingPadPredecessor { block } => {
460                write!(f, "landing pad {block} is reached by a non-unwind edge")
461            }
462            K::UnwindInNounwind => f.write_str("a `nounwind` function may unwind"),
463            K::ReturnInNoreturn => f.write_str("a `noreturn` function returns"),
464            K::SafepointInNogc => f.write_str("a `nogc` function contains a safepoint"),
465            K::LiveAcrossSafepoint { value } => write!(
466                f,
467                "value {value} is a GC reference (or derived from one) live across a safepoint"
468            ),
469            K::DerivedPointerEscapes { value } => {
470                write!(f, "pointer {value} derived from a GC reference escapes")
471            }
472        }
473    }
474}
475
476/// Why a module is not well-formed: what is wrong, and where.
477///
478/// [`Module::validate`](crate::Module::validate) returns the first problem it finds
479/// in a fixed order (module declarations, then each function in handle order;
480/// within a function: structure, instructions, terminators, exception edges,
481/// dominance, safepoints).
482///
483/// # Examples
484///
485/// ```
486/// use ir_lang::{Linkage, Module, Signature, Type, ValidationErrorKind};
487///
488/// let mut m = Module::new("m");
489/// let f = m.declare_function("f", &Signature::new(&[], &[Type::I32]), Linkage::Export)?;
490/// // Exported but never given a body.
491/// let err = m.validate().unwrap_err();
492/// assert_eq!(err.func(), Some(f));
493/// assert_eq!(err.kind(), &ValidationErrorKind::MissingBody);
494/// # Ok::<(), Box<dyn std::error::Error>>(())
495/// ```
496#[derive(Clone, PartialEq, Eq, Debug)]
497pub struct ValidationError {
498    pub(crate) func: Option<FuncId>,
499    pub(crate) block: Option<Block>,
500    pub(crate) inst: Option<Inst>,
501    pub(crate) kind: ValidationErrorKind,
502}
503
504impl ValidationError {
505    pub(crate) fn module(kind: ValidationErrorKind) -> ValidationError {
506        ValidationError {
507            func: None,
508            block: None,
509            inst: None,
510            kind,
511        }
512    }
513
514    /// The function the problem is in, if it is inside one.
515    ///
516    /// See [`ValidationError`] for an example.
517    #[must_use]
518    pub fn func(&self) -> Option<FuncId> {
519        self.func
520    }
521
522    /// The block the problem is in, if any.
523    ///
524    /// # Examples
525    ///
526    /// ```
527    /// use ir_lang::{Linkage, Module, Signature};
528    ///
529    /// let mut m = Module::new("m");
530    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
531    /// let _ = m.build(f)?; // the entry block is never terminated
532    /// let err = m.validate().unwrap_err();
533    /// assert_eq!(err.block().map(|b| b.index()), Some(0));
534    /// # Ok::<(), Box<dyn std::error::Error>>(())
535    /// ```
536    #[must_use]
537    pub fn block(&self) -> Option<Block> {
538        self.block
539    }
540
541    /// The instruction the problem is in, if it is in one (`None` for a terminator
542    /// or a block-level problem).
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use ir_lang::{Linkage, Module, Signature};
548    ///
549    /// let mut m = Module::new("m");
550    /// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
551    /// let _ = m.build(f)?;
552    /// assert_eq!(m.validate().unwrap_err().inst(), None);
553    /// # Ok::<(), Box<dyn std::error::Error>>(())
554    /// ```
555    #[must_use]
556    pub fn inst(&self) -> Option<Inst> {
557        self.inst
558    }
559
560    /// What is wrong.
561    ///
562    /// See [`ValidationError`] for an example.
563    #[must_use]
564    pub fn kind(&self) -> &ValidationErrorKind {
565        &self.kind
566    }
567}
568
569impl fmt::Display for ValidationError {
570    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571        let mut sep = "";
572        if let Some(func) = self.func {
573            write!(f, "{sep}{func}")?;
574            sep = " ";
575        }
576        if let Some(block) = self.block {
577            write!(f, "{sep}{block}")?;
578            sep = " ";
579        }
580        if let Some(inst) = self.inst {
581            write!(f, "{sep}{inst}")?;
582            sep = " ";
583        }
584        if sep.is_empty() {
585            write!(f, "{}", self.kind)
586        } else {
587            write!(f, ": {}", self.kind)
588        }
589    }
590}
591
592impl core::error::Error for ValidationError {}
593
594/// Why a [`Builder`](crate::Builder) operation was refused.
595///
596/// The builder checks each instruction and terminator as it is added, so a
597/// lowering bug is reported at the call that caused it. Nothing is ever changed by
598/// a refused operation.
599///
600/// # Examples
601///
602/// ```
603/// use ir_lang::{BuildError, Linkage, Module, Signature};
604///
605/// let mut m = Module::new("m");
606/// let f = m.declare_function("f", &Signature::new(&[], &[]), Linkage::Export)?;
607/// let mut b = m.build(f)?;
608/// b.ret(&[])?;
609/// // A terminator is never silently overwritten.
610/// let entry = b.func().entry();
611/// assert_eq!(b.unreachable(), Err(BuildError::AlreadyTerminated { block: entry }));
612/// # Ok::<(), Box<dyn std::error::Error>>(())
613/// ```
614#[derive(Clone, PartialEq, Eq, Debug)]
615#[non_exhaustive]
616pub enum BuildError {
617    /// The block already has a terminator. Remove it first
618    /// ([`Builder::remove_terminator`](crate::Builder::remove_terminator)) to replace it.
619    AlreadyTerminated {
620        /// The block.
621        block: Block,
622    },
623    /// The block handle is unknown or the block was removed.
624    UnknownBlock {
625        /// The block.
626        block: Block,
627    },
628    /// The instruction handle is unknown or the instruction was removed.
629    UnknownInst {
630        /// The instruction.
631        inst: Inst,
632    },
633    /// The value handle is unknown.
634    UnknownValue {
635        /// The value.
636        value: Value,
637    },
638    /// There is no function parameter at this index.
639    UnknownParam {
640        /// The index.
641        index: usize,
642    },
643    /// The entry block cannot be removed or split off.
644    EntryBlock,
645    /// A block parameter index is out of range.
646    UnknownBlockParam {
647        /// The block.
648        block: Block,
649        /// The index.
650        index: usize,
651    },
652    /// The instruction or terminator is ill-formed.
653    Invalid(ValidationErrorKind),
654    /// A function table reached its capacity (`u32::MAX - 1` entries).
655    CapacityExceeded,
656}
657
658impl fmt::Display for BuildError {
659    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
660        match self {
661            BuildError::AlreadyTerminated { block } => {
662                write!(f, "block {block} already has a terminator")
663            }
664            BuildError::UnknownBlock { block } => write!(f, "unknown or removed block {block}"),
665            BuildError::UnknownInst { inst } => write!(f, "unknown or removed instruction {inst}"),
666            BuildError::UnknownValue { value } => write!(f, "unknown value {value}"),
667            BuildError::UnknownParam { index } => write!(f, "no function parameter {index}"),
668            BuildError::EntryBlock => f.write_str("the entry block cannot be removed or split off"),
669            BuildError::UnknownBlockParam { block, index } => {
670                write!(f, "block {block} has no parameter {index}")
671            }
672            BuildError::Invalid(kind) => write!(f, "{kind}"),
673            BuildError::CapacityExceeded => f.write_str("function table capacity exceeded"),
674        }
675    }
676}
677
678impl core::error::Error for BuildError {}
679
680impl From<ValidationErrorKind> for BuildError {
681    fn from(kind: ValidationErrorKind) -> Self {
682        BuildError::Invalid(kind)
683    }
684}
685
686#[cfg(test)]
687mod tests {
688    use super::*;
689    use alloc::string::ToString;
690
691    #[test]
692    fn test_validation_error_display_includes_location() {
693        let e = ValidationError {
694            func: Some(FuncId::from_u32(1)),
695            block: Some(Block::from_u32(2)),
696            inst: None,
697            kind: ValidationErrorKind::MissingTerminator,
698        };
699        assert_eq!(e.to_string(), "f1 b2: block has no terminator");
700        let m = ValidationError::module(ValidationErrorKind::EmptyName);
701        assert_eq!(m.to_string(), "a symbol name is empty");
702    }
703
704    #[test]
705    fn test_every_build_error_displays() {
706        let errs = [
707            BuildError::EntryBlock,
708            BuildError::CapacityExceeded,
709            BuildError::UnknownParam { index: 3 },
710            BuildError::Invalid(ValidationErrorKind::BadOrdering),
711        ];
712        for e in errs {
713            assert!(!e.to_string().is_empty());
714        }
715    }
716}