Does the metavariable preserve its fragment-specifier meaning when it is used?

In this example

macro_rules! test_index {
    ($id:ident,$index:literal) => {
        $id.$index
    };
}

fn main() {
    let a = (1, 2);
    test_index!(a, 0);
}

There is an error:

error: unexpected token: `literal` metavariable
 --> src/main.rs:3:13
  |
3 |         $id.$index
  |             ^^^^^^
...
9 |     test_index!(a, 0);
  |     ----------------- in this macro invocation
  |
  = note: this error originates in the macro `test_index` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `literal` metavariable

tuple index syntax states that the tuple index is TUPLE_INDEX, which is a literal.

fragment specifiers defines literal as

I suppose the reason why the compiler reports an error is that $index matches a LiteralExpression; wherever the metavariable is used, it always preserves the information that it is a LiteralExpression. So, the metavariable can only be used where the syntax permits a LiteralExpression to appear.

Instead, the tuple index expects a TUPLE_INDEX in which a LiteralExpression is not permitted to appear. Even though both TUPLE_INDEX and LiteralExpression are sourced from the token(i.e., Literal) 0, they have different syntax meanings. The metavariable preserves its syntax meaning indicated by the fragment specifier.

This is the reason for the error. Is my understanding right?

TUPLE_INDEX is an (non-negative) integer literal, which can be decimal, binary, hexadecimal, or octal.

the literal fragment can capture any literal values, such as string literals, floating point number literals, boolean values, not just integer literals,

you reasoning is correct. the literal fragment and tuple index are different kinds of parsed syntax nodes.

unfortunately, we don't have a fragment type specific for tuple indexes, so you'll need to resort to the tt fragment kind for such uses.

Is the reason why this works, is that the tt fragment in this example only preserves the metavariable to be a token, then it is subsequently interpreted as the syntax component TUPLE_INDEX? In other words, all valid syntax components are transformed from tokens; tt only preserves the metavariable to be a valid token, which hasn't included syntax information that would be prevented by TUPLE_INDEX. The token can appear in the place as long as the token can be interpreted as a TUPLE_INDEX. Is this understanding right?

yes. tt preserves the original "raw" tokens. technically, it is called Token Tree:

for example,if a metavariable of tt kind captures an integer literal, when it was expanded, the parser sees the original tokens, not an opaque "LiteralExpression" node.

1 Like