expandable_impl/
error.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Architectural invariant: this module contains types that are useful for error
// reporting and nothing else.

use crate::{RepetitionQuantifierKind, Terminal, grammar::TokenDescription};

/// An error that is generated when checking an incorrect macro.
///
/// This enum allows crate users to handle and report errors detected by
/// [`check_macro`].
///
/// Everything in this enum in marked as `non_exhaustive`, in order to partially
/// mitigate future variant additions.
///
/// [`check_macro`]: crate::check_macro
#[derive(Debug)]
#[non_exhaustive]
pub enum Error<Span> {
    /// Generated when the macro definition itself doesn't parse correctly.
    ///
    /// The Rust compiler is likely to emit an error anyway. Below is an
    /// example of code that triggers this error:
    ///
    /// ```rust,compile_fail
    /// macro_rules! blatant_error {
    ///     () => =>;
    ///     //    |
    ///     //    error: macro rhs must be delimited.
    /// }
    /// ```
    ///
    /// This prevents us from doing any analyses.
    #[non_exhaustive]
    ParsingFailed {
        /// What was expected.
        what: Vec<MacroRuleNode>,
        /// Where it was expected.
        where_: Span,
    },

    /// An EOF was reached when it was not expected.
    #[non_exhaustive]
    UnexpectedEnd {
        /// The position the parser was at when it reached EOF.
        last_token: Option<Span>,
    },

    /// The macro may expand to invalid AST.
    ///
    /// This variant is very minimal for now. We may add more information to
    /// it in the future. Please open an issue if you have opinions on what
    /// to add!
    #[non_exhaustive]
    InvalidProducedAst {
        /// Where the error happens.
        span: Span,
        /// What tokens are expected here.
        expected: Vec<TokenDescription>,
        /// A possible expansion of the macro that exhibits a parsing error.
        ///
        /// The expansion may contain fragments.
        counter_example: Vec<(TokenDescription, Span)>,
    },

    /// A macro expansion refers to a metavariable that is not defined in the
    /// macro match arm.
    ///
    /// If you ever hit this error on a macro that works, then please file an
    /// issue.
    #[non_exhaustive]
    UnboundMetavariable {
        /// The name of the metavariable that was used.
        name: String,
        /// Where it was used.
        where_: Span,
    },

    /// A variable is being repeated with a sequence of operator that does not
    /// match the one used when the variable was declared.
    ///
    /// # Example
    ///
    /// ```rust,compile_fail
    /// macro_rules! subtraction {
    ///     ( $( $first:literal $( - $then:literal )* )? ) => {
    ///         $first $( - $then )*
    ///     };
    /// }
    ///
    /// subtraction!(101 - 42);
    /// ```
    ///
    /// In this example, the repetition nesting of the matched metavariable
    /// `then` is `?*`, while the nesting of the metavariable indication
    /// `then` is `*`.
    ///
    /// This variant represents both the case where the amount of repetitions
    /// does not match (which is an error) and the case where the repetition
    /// operators used do not match (which is allowed, but can lead to confusing
    /// errors).
    InvalidRepetitionNesting {
        /// The name of the metavariable.
        metavariable_name: String,
        /// Where the metavariable was declared.
        decl_span: Span,
        /// Where the metavariable was used with an incorrect nesting.
        usage_span: Span,
        /// The nesting used when the metavariable was declared.
        expected_nesting: Vec<RepetitionQuantifierKind>,
        /// The nesting encountered when the metavariable was used.
        got_nesting: Vec<RepetitionQuantifierKind>,
    },
}

/// Various nodes that can be expected in a `macro_rules!` invocation.
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum MacroRuleNode {
    /// A matcher (everything that comes _before_ the `=>` of a macro rule.
    Matcher,
    /// A transcriber (everything that comes _after_ the `=>` of a macro rule.
    Transcriber,
    /// A repetition.
    Repetition,
    /// A fragment name.
    FragmentName,
    /// A fragment type specifier (`ident`, `expr`, ...).
    FragmentSpecifier,
    /// A meta variable match, such as `$a:ident`.
    MetaVariableMatch,
    /// A repetition quantifier (`?`, `*`, `+`).
    RepetitionQuantifier,
    /// A repetition separator (the `,` in `$( $expr ),*`).
    RepetitionSeparator,
    /// Any terminal.
    Terminal(Terminal),
}