proptest_derive/
error.rs

1// Copyright 2018 The proptest developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Provides error messages and some checkers.
10
11use std::fmt::Display;
12
13use proc_macro2::TokenStream;
14use quote::ToTokens;
15
16use crate::attr::ParsedAttributes;
17use syn;
18
19//==============================================================================
20// Item descriptions
21//==============================================================================
22
23/// Item name of structs.
24pub const STRUCT: &str = "struct";
25
26/// Item name of struct fields.
27pub const STRUCT_FIELD: &str = "struct field";
28
29/// Item name of enums.
30pub const ENUM: &str = "enum";
31
32/// Item name of enum variants.
33pub const ENUM_VARIANT: &str = "enum variant";
34
35/// Item name of enum variant fields.
36pub const ENUM_VARIANT_FIELD: &str = "enum variant field";
37
38/// Item name for a type variable.
39pub const TY_VAR: &str = "a type variable";
40
41//==============================================================================
42// Checkers
43//==============================================================================
44
45/// Ensures that the type is not parametric over lifetimes.
46pub fn if_has_lifetimes(ctx: Ctx, ast: &syn::DeriveInput) {
47    if ast.generics.lifetimes().count() > 0 {
48        has_lifetimes(ctx);
49    }
50}
51
52/// Ensures that no attributes were specified on `item`.
53pub fn if_anything_specified(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
54    if_enum_attrs_present(ctx, attrs, item);
55    if_strategy_present(ctx, attrs, item);
56    if_specified_params(ctx, attrs, item);
57    if_specified_filter(ctx, attrs, item);
58}
59
60/// Ensures that things only allowed on an enum variant is not present on
61/// `item` which is not an enum variant.
62pub fn if_enum_attrs_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
63    if_skip_present(ctx, attrs, item);
64    if_weight_present(ctx, attrs, item);
65}
66
67/// Ensures that parameters is not present on `item`.
68pub fn if_specified_filter(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
69    if !attrs.filter.is_empty() {
70        meaningless_filter(ctx, item);
71    }
72}
73
74/// Ensures that parameters is not present on `item`.
75pub fn if_specified_params(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
76    if attrs.params.is_set() {
77        parent_has_param(ctx, item);
78    }
79}
80
81/// Ensures that an explicit strategy or value is not present on `item`.
82pub fn if_strategy_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
83    use crate::attr::StratMode::*;
84    match attrs.strategy {
85        Arbitrary => {}
86        Strategy(_) => illegal_strategy(ctx, "strategy", item),
87        Value(_) => illegal_strategy(ctx, "value", item),
88        Regex(_) => illegal_regex(ctx, item),
89    }
90}
91
92/// Ensures that a strategy, value, params, filter is not present on a unit variant.
93pub fn if_present_on_unit_variant(ctx: Ctx, attrs: &ParsedAttributes) {
94    /// Ensures that an explicit strategy or value is not present on a unit variant.
95    use crate::attr::StratMode::*;
96    match attrs.strategy {
97        Arbitrary => {}
98        Strategy(_) => strategy_on_unit_variant(ctx, "strategy"),
99        Value(_) => strategy_on_unit_variant(ctx, "value"),
100        Regex(_) => regex_on_unit_variant(ctx),
101    }
102
103    if attrs.params.is_set() {
104        params_on_unit_variant(ctx)
105    }
106
107    if !attrs.filter.is_empty() {
108        filter_on_unit_variant(ctx)
109    }
110}
111
112/// Ensures that parameters or filter is not present on a unit struct.
113pub fn if_present_on_unit_struct(ctx: Ctx, attrs: &ParsedAttributes) {
114    if attrs.params.is_set() {
115        params_on_unit_struct(ctx)
116    }
117
118    if !attrs.filter.is_empty() {
119        filter_on_unit_struct(ctx)
120    }
121}
122
123/// Ensures that skip is not present on `item`.
124pub fn if_skip_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
125    if attrs.skip {
126        illegal_skip(ctx, item)
127    }
128}
129
130/// Ensures that a weight is not present on `item`.
131pub fn if_weight_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) {
132    if attrs.weight.is_some() {
133        illegal_weight(ctx, item)
134    }
135}
136
137//==============================================================================
138// Messages
139//==============================================================================
140
141/// Denotes that a fatal error happened in dealing somewhere in the
142/// procedural macro pipeline. A fatal error is different from a
143/// normal error in the sense that it halts progress in the macro
144/// immediately instead of allowing other errors to be accumulated.
145#[derive(Debug)]
146pub struct Fatal;
147
148/// The return type of a possibly fatal computation in the macro.
149pub type DeriveResult<T> = Result<T, Fatal>;
150
151/// A mutable view / shorthand for the context.
152/// Prefer this type over `Context` in functions.
153pub type Ctx<'ctx> = &'ctx mut Context;
154
155/// The context / environment that the macro is operating in.
156/// Right now, it simply tracks all the errors collected during
157/// the running of the macro.
158#[derive(Default)]
159pub struct Context {
160    errors: Vec<String>,
161}
162
163impl Context {
164    /// Add a non-fatal error to the context.
165    pub fn error<T: Display>(&mut self, msg: T) {
166        self.errors.push(msg.to_string());
167    }
168
169    /// Add an error to the context and produce an erroring
170    /// computation that will halt the macro.
171    pub fn fatal<T: Display, A>(&mut self, msg: T) -> DeriveResult<A> {
172        self.error(msg);
173        Err(Fatal)
174    }
175
176    /// Consume the context and if there were any errors,
177    /// emit `compile_error!(..)` such that the crate using
178    /// `#[derive(Arbitrary)]` will fail to compile.
179    pub fn check(mut self) -> Result<(), TokenStream> {
180        fn compile_error(msg: &str) -> TokenStream {
181            quote! {
182                compile_error!(#msg);
183            }
184        }
185
186        match self.errors.len() {
187            0 => Ok(()),
188            1 => Err(compile_error(&self.errors.pop().unwrap())),
189            n => {
190                let mut msg = format!("{} errors:", n);
191                for err in self.errors {
192                    msg.push_str("\n\t# ");
193                    msg.push_str(&err);
194                }
195                Err(compile_error(&msg))
196            }
197        }
198    }
199}
200
201//==============================================================================
202// Messages
203//==============================================================================
204
205/// Produce an error string with the error `$code` which corresponds
206/// to the given `$message`.
207macro_rules! mk_err_msg {
208    ($code: ident, $msg: expr) => {
209        format!(
210            "[proptest_derive, {}] during #[derive(Arbitrary)]:\n{} Please see: https://proptest-rs.github.io/proptest/proptest-derive/errors.html#{} for more information.",
211            stringify!($code),
212            $msg,
213            (stringify!($code)).to_lowercase()
214        )
215    };
216}
217
218/// A macro constructing errors that do halt compilation immediately.
219macro_rules! fatal {
220    ($error: ident, $code: ident, $msg: expr) => {
221        pub fn $error<T>(ctx: Ctx) -> DeriveResult<T> {
222            ctx.fatal(mk_err_msg!($code, $msg))
223        }
224    };
225    ($error: ident ($($arg: ident: $arg_ty: ty),*), $code: ident,
226     $msg: expr, $($fmt: tt)+) => {
227        pub fn $error<T>(ctx: Ctx, $($arg: $arg_ty),*) -> DeriveResult<T> {
228            ctx.fatal(mk_err_msg!($code, format!($msg, $($fmt)+)))
229        }
230    };
231}
232
233/// A macro constructing fatal errors that do not halt compilation immediately.
234macro_rules! error {
235    ($error: ident, $code: ident, $msg: expr) => {
236        pub fn $error(ctx: Ctx) {
237            ctx.error(mk_err_msg!($code, $msg))
238        }
239    };
240    ($error: ident ($($arg: ident: $arg_ty: ty),*), $code: ident,
241     $msg: expr, $($fmt: tt)+) => {
242        pub fn $error(ctx: Ctx, $($arg: $arg_ty),*) {
243            ctx.error(mk_err_msg!($code, format!($msg, $($fmt)+)))
244        }
245    };
246}
247
248// Happens when we've been asked to derive `Arbitrary` for a type
249// that is parametric over lifetimes. Since proptest does not support
250// such types (yet), neither can we.
251error!(
252    has_lifetimes,
253    E0001,
254    "Cannot derive `Arbitrary` for types with generic lifetimes, such as: \
255     `struct Foo<'a> { bar: &'a str }`. Currently, strategies for such types \
256     are impossible to define."
257);
258
259// Happens when we've been asked to derive `Arbitrary` for something
260// that is neither an enum nor a struct. Most likely, we've been given
261// a union type. This might be supported in the future, but not yet.
262fatal!(
263    not_struct_or_enum,
264    E0002,
265    "Deriving is only possible for structs and enums. \
266     It is currently not defined unions."
267);
268
269// Happens when a struct has at least one field that is uninhabited.
270// There must at least exist one variant that we can construct.
271error!(
272    uninhabited_struct,
273    E0003,
274    "The struct you are deriving `Arbitrary` for is uninhabited since one of \
275    its fields is uninhabited. An uninhabited type is by definition impossible \
276    to generate."
277);
278
279// Happens when an enum has zero variants. Such an enum is obviously
280// uninhabited and can not be constructed. There must at least exist
281// one variant that we can construct.
282fatal!(
283    uninhabited_enum_with_no_variants,
284    E0004,
285    "The enum you are deriving `Arbitrary` for is uninhabited since it has no \
286     variants. An example of such an `enum` is: `enum Void {}`. \
287     An uninhabited type is by definition impossible to generate."
288);
289
290// Happens when an enum is uninhabited due all its variants being
291// uninhabited (why has the user given us such a weird enum?..
292// Nonetheless, we do our best to ensure soundness).
293// There must at least exist one variant that we can construct.
294fatal!(
295    uninhabited_enum_variants_uninhabited,
296    E0005,
297    "The enum you are deriving `Arbitrary` for is uninhabited since all its \
298     variants are uninhabited. \
299     An uninhabited type is by definition impossible to generate."
300);
301
302// Happens when an enum becomes effectively uninhabited due
303// to all inhabited variants having been skipped. There must
304// at least exist one variant that we can construct.
305error!(
306    uninhabited_enum_because_of_skipped_variants,
307    E0006,
308    "The enum you are deriving `Arbitrary` for is uninhabited for all intents \
309     and purposes since you have `#[proptest(skip)]`ed all inhabited variants. \
310     An uninhabited type is by definition impossible to generate."
311);
312
313// Happens when `#[proptest(strategy = "<expr>")]` or
314// `#[proptest(value = "<expr>")]` is specified on an `item`
315// that does not support setting an explicit value or strategy.
316// An enum or struct does not support that.
317error!(illegal_strategy(attr: &str, item: &str), E0007,
318    "`#[proptest({0} = \"<expr>\")]` is not allowed on {1}. Only struct fields, \
319    enum variants and fields inside those can use an explicit {0}.",
320    attr, item);
321
322// Happens when `#[proptest(regex = "<string>")]` is specified on an `item`
323// that does not support setting an explicit value or strategy.
324// See `illegal_strategy` for more.
325error!(
326    illegal_regex(item: &str),
327    E0007,
328    "`#[proptest(regex = \"<string>\")]` is not allowed on {0}. Only struct \
329     fields, enum variant fields can use an explicit regex.",
330    item
331);
332
333// Happens when `#[proptest(skip)]` is specified on an `item` that does
334// not support skipping. Only enum variants support skipping.
335error!(
336    illegal_skip(item: &str),
337    E0008,
338    "A {} can't be `#[proptest(skip)]`ed, only enum variants can be skipped.",
339    item
340);
341
342// Happens when `#[proptest(weight = <integer>)]` is specified on an
343// `item` that does not support weighting.
344error!(
345    illegal_weight(item: &str),
346    E0009,
347    "`#[proptest(weight = <integer>)]` is not allowed on {} as it is \
348     meaningless. Only enum variants can be assigned weights.",
349    item
350);
351
352// Happens when `#[proptest(params = <type>)]` is set on `item`
353// but also on the parent of `item`. If the parent has set `params`
354// then that applies, and the `params` on `item` would be meaningless
355// wherefore it is forbidden.
356error!(
357    parent_has_param(item: &str),
358    E0010,
359    "Cannot set the associated type `Parameters` of `Arbitrary` with either \
360     `#[proptest(no_params)]` or `#[proptest(params(<type>)]` on {} since it \
361     was set on the parent.",
362    item
363);
364
365// Happens when `#[proptest(params = <type>)]` is set on `item`
366// but not `#[proptest(strategy = <expr>)]`.
367// This does not apply to the top level type declaration.
368fatal!(
369    cant_set_param_but_not_strat(self_ty: &syn::Type, item: &str),
370    E0011,
371    "Cannot set `#[proptest(params = <type>)]` on {0} while not providing a \
372     strategy for the {0} to use it since `<{1} as Arbitrary<'a>>::Strategy` \
373     may require a different type than the one provided in `<type>`.",
374    item,
375    quote! { #self_ty }
376);
377
378// Happens when `#[proptest(filter = "<expr>")]` is set on `item`,
379// but the parent of the `item` explicitly specifies a value or strategy,
380// which would cause the value to be generated without consulting the
381// `filter`.
382error!(
383    meaningless_filter(item: &str),
384    E0012,
385    "Cannot set `#[proptest(filter = <expr>)]` on {} since it is set on the \
386     item which it is inside of that outer item specifies how to generate \
387     itself.",
388    item
389);
390
391// Happens when the form `#![proptest<..>]` is used. This will probably never
392// happen - but just in case it does, we catch it and emit an error.
393error!(
394    inner_attr,
395    E0013, "Inner attributes `#![proptest(..)]` are not currently supported."
396);
397
398// Happens when the form `#[proptest]` is used. The form contains no
399// information for us to process, so we disallow it.
400error!(
401    bare_proptest_attr,
402    E0014, "Bare `#[proptest]` attributes are not allowed."
403);
404
405// Happens when the form `#[proptest = <literal>)]` is used.
406// Only the form `#[proptest(<contents>)]` is supported.
407error!(
408    literal_set_proptest,
409    E0015, "The attribute form `#[proptest = <literal>]` is not allowed."
410);
411
412// Happens when `<modifier>` in `#[proptest(<modifier>)]` is a literal and
413// not a real modifier.
414error!(
415    immediate_literals,
416    E0016,
417    "Literals immediately inside `#[proptest(..)]` as in \
418     `#[proptest(<lit>, ..)]` are not allowed."
419);
420
421// Happens when `<modifier>` in `#[proptest(<modifier>)]` is set more than
422// once.
423error!(
424    set_again(meta: &syn::Meta),
425    E0017,
426    "The attribute modifier `{}` inside `#[proptest(..)]` has already been \
427     set. To fix the error, please remove at least one such modifier.",
428    meta.path().into_token_stream()
429);
430
431// Happens when `<modifier>` in `#[proptest(<modifier>)]` is unknown to
432// us but we can make an educated guess as to what the user meant.
433error!(
434    did_you_mean(found: &str, expected: &str),
435    E0018,
436    "Unknown attribute modifier `{}` inside #[proptest(..)] is not allowed. \
437     Did you mean to use `{}` instead?",
438    found,
439    expected
440);
441
442// TODO: `unkown_modifier` is misspelled
443// Happens when `<modifier>` in `#[proptest(<modifier>)]` is unknown to us.
444error!(
445    unkown_modifier(modifier: &str),
446    E0018,
447    "Unknown attribute modifier `{}` inside `#[proptest(..)]` is not allowed.",
448    modifier
449);
450
451// Happens when `#[proptest(no_params)]` is malformed.
452error!(
453    no_params_malformed,
454    E0019,
455    "The attribute modifier `no_params` inside `#[proptest(..)]` does not \
456     support any further configuration and must be a plain modifier as in \
457     `#[proptest(no_params)]`."
458);
459
460// Happens when `#[proptest(skip)]` is malformed.
461error!(
462    skip_malformed,
463    E0020,
464    "The attribute modifier `skip` inside `#[proptest(..)]` does not support \
465     any further configuration and must be a plain modifier as in \
466     `#[proptest(skip)]`."
467);
468
469// Happens when `#[proptest(weight..)]` is malformed.
470error!(
471    weight_malformed(meta: &syn::Meta),
472    E0021,
473    "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \
474    format `#[proptest({0} = <integer>)]` where `<integer>` is an integer that \
475    fits within a `u32`. An example: `#[proptest({0} = 2)]` to set a relative \
476    weight of 2.",
477    meta.path().into_token_stream()
478);
479
480// Happens when both `#[proptest(params = "<type>")]` and
481// `#[proptest(no_params)]` were specified. They are mutually
482// exclusive choices. The user can resolve this by picking one.
483fatal!(
484    overspecified_param,
485    E0022,
486    "Cannot set `#[proptest(no_params)]` as well as \
487     `#[proptest(params(<type>))]` simultaneously. \
488     Please pick one of these attributes."
489);
490
491// This happens when `#[proptest(params..)]` is malformed.
492// For example, `#[proptest(params)]` is malformed. Another example is when
493// `<type>` inside `#[proptest(params = "<type>")]` or
494// `#[proptest(params("<type>"))]` is malformed. In other words, `<type>` is
495// not a valid Rust type. Note that `syn` may not cover all valid Rust types.
496error!(
497    param_malformed,
498    E0023,
499    "The attribute modifier `params` inside #[proptest(..)] must have the \
500     format `#[proptest(params = \"<type>\")]` where `<type>` is a valid type \
501     in Rust. An example: `#[proptest(params = \"ComplexType<Foo>\")]`."
502);
503
504// Happens when more than one of `#[proptest(strategy..)]`,
505// `#[proptest(value..)]`, or `#[proptest(regex..)]` were specified.
506// They are mutually exclusive choices.
507// The user can resolve this by picking one.
508fatal!(
509    overspecified_strat,
510    E0025,
511    "Cannot set more than one of `#[proptest(value = \"<expr>\")]`,
512    `#[proptest(strategy = \"<expr>\")]`, `#[proptest(regex = \"<string>\")]` \
513    simultaneously. Please pick one of these attributes."
514);
515
516// Happens when `#[proptest(strategy..)]` or `#[proptest(value..)]` is
517// malformed. For example, `<expr>` inside `#[proptest(strategy = "<expr>")]`
518// or `#[proptest(value = "<expr>")]` is malformed. In other words, `<expr>`
519// is not a valid Rust expression.
520error!(
521    strategy_malformed(meta: &syn::Meta),
522    E0026,
523    "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \
524     format `#[proptest({0} = \"<expr>\")]` where `<expr>` is a valid Rust \
525     expression.",
526    meta.path().into_token_stream()
527);
528
529// Happens when `#[proptest(filter..)]` is malformed.
530// For example, `<expr>` inside `#[proptest(filter = "<expr>")]` or
531// is malformed. In other words, `<expr>` is not a valid Rust expression.
532error!(
533    filter_malformed(meta: &syn::Meta),
534    E0027,
535    "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \
536     format `#[proptest({0} = \"<expr>\")]` where `<expr>` is a valid Rust \
537     expression.",
538    meta.path().into_token_stream()
539);
540
541// Any attributes on a skipped variant has no effect - so we emit this error
542// to the user so that they are aware.
543error!(
544    skipped_variant_has_weight(item: &str),
545    E0028,
546    "A variant has been skipped. Setting `#[proptest(weight = <value>)]` on \
547     the {} is meaningless and is not allowed.",
548    item
549);
550
551// Any attributes on a skipped variant has no effect - so we emit this error
552// to the user so that they are aware.
553error!(
554    skipped_variant_has_param(item: &str),
555    E0028,
556    "A variant has been skipped. Setting `#[proptest(no_param)]` or \
557    `#[proptest(params(<type>))]` on the {} is meaningless and is not allowed.",
558    item
559);
560
561// Any attributes on a skipped variant has no effect - so we emit this error
562// to the user so that they are aware.
563error!(
564    skipped_variant_has_strat(item: &str),
565    E0028,
566    "A variant has been skipped. Setting `#[proptest(value = \"<expr>\")]` or \
567     `#[proptest(strategy = \"<expr>\")]` on the {} is meaningless and is not \
568     allowed.",
569    item
570);
571
572// Any attributes on a skipped variant has no effect - so we emit this error
573// to the user so that they are aware. Unfortunately, there's no way to
574// emit a warning to the user, so we emit an error instead.
575error!(skipped_variant_has_filter(item: &str), E0028,
576    "A variant has been skipped. Setting `#[proptest(filter = \"<expr>\")]` or \
577    on the {} is meaningless and is not allowed.",
578    item);
579
580// There's only one way to produce a specific unit variant, so setting
581// `#[proptest(strategy = "<expr>")]` or `#[proptest(value = "<expr>")]`
582// would be pointless.
583error!(
584    strategy_on_unit_variant(what: &str),
585    E0029,
586    "Setting `#[proptest({0} = \"<expr>\")]` on a unit variant has no effect \
587     and is redundant because there is nothing to configure.",
588    what
589);
590
591// See `strategy_on_unit_variant`.
592error!(regex_on_unit_variant, E0029,
593    "Setting `#[proptest(regex = \"<string>\")]` on a unit variant has no effect \
594    and is redundant because there is nothing to configure.");
595
596// There's only one way to produce a specific unit variant, so setting
597// `#[proptest(params = "<type>")]` would be pointless.
598error!(
599    params_on_unit_variant,
600    E0029,
601    "Setting `#[proptest(params = \"<type>\")]` on a unit variant has \
602     no effect and is redundant because there is nothing to configure."
603);
604
605// There's only one way to produce a specific unit variant, so setting
606// `#[proptest(filter = "<expr>")]` would be pointless.
607error!(
608    filter_on_unit_variant,
609    E0029,
610    "Setting `#[proptest(filter = \"<expr>\")]` on a unit variant has \
611     no effect and is redundant because there is nothing to further filter."
612);
613
614// Occurs when `#[proptest(params = "<type>")]` is specified on a unit
615// struct. There's only one way to produce a unit struct, so specifying
616// `Parameters` would be pointless.
617error!(params_on_unit_struct, E0030,
618    "Setting `#[proptest(params = \"<type>\")]` on a unit struct has no effect \
619    and is redundant because there is nothing to configure.");
620
621// Occurs when `#[proptest(filter = "<expr>")]` is specified on a unit
622// struct. There's only one way to produce a unit struct, so filtering
623// would be pointless.
624error!(filter_on_unit_struct, E0030,
625    "Setting `#[proptest(filter = \"<expr>\")]` on a unit struct has no effect \
626    and is redundant because there is nothing to filter.");
627
628// Occurs when `#[proptest(no_bound)]` is specified
629// on something that is not a type variable.
630error!(
631    no_bound_set_on_non_tyvar,
632    E0031,
633    "Setting `#[proptest(no_bound)]` on something that is not a type variable \
634     has no effect and is redundant. Therefore it is not allowed."
635);
636
637// Happens when `#[proptest(no_bound)]` is malformed.
638error!(
639    no_bound_malformed,
640    E0032,
641    "The attribute modifier `no_bound` inside `#[proptest(..)]` does not \
642     support any further configuration and must be a plain modifier as in \
643     `#[proptest(no_bound)]`."
644);
645
646// Happens when the sum of weights on enum variants overflowing an u32.
647error!(
648    weight_overflowing,
649    E0033,
650    "The sum of the weights specified on variants of the enum you are \
651     deriving `Arbitrary` for overflows an `u32` which it can't do."
652);
653
654// Happens when `#[proptest(regex..)]` is malformed.
655// For example, `#[proptest(regex = 1)]` is not a valid form.
656error!(
657    regex_malformed,
658    E0034,
659    "The attribute modifier `regex` inside `#[proptest(..)]` must have the \
660    format `#[proptest(regex = \"<string>\")]` where `<string>` is a valid
661    regular expression embedded in a Rust string slice."
662);
663
664// Happens when `#[proptest(params = <type>)]` is set on `item` and then
665// `#[proptest(regex = "<string>")]` is also set. We reject this because
666// the params can't be used. TODO: reduce this to a warning once we can
667// emit warnings.
668error!(
669    cant_set_param_and_regex(item: &str),
670    E0035,
671    "Cannot set #[proptest(regex = \"<string>\")] and \
672     `#[proptest(params = <type>)]` on {0} because the latter is a logic bug \
673     since `params` cannot be used in `<string>`.",
674    item
675);
676
677#[cfg(test)]
678mod tests {
679    #[test]
680    fn test_mk_err_msg_format() {
681        assert_eq!(
682            mk_err_msg!(E0001, "This is a sample error message."),
683            "[proptest_derive, E0001] during #[derive(Arbitrary)]:\nThis is a sample error message. Please see: https://proptest-rs.github.io/proptest/proptest-derive/errors.html#e0001 for more information."
684        );
685    }
686}