rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.03k stars 12.54k forks source link

Tracking Issue for RFC 3086: macro metavariable expressions #83527

Open nikomatsakis opened 3 years ago

nikomatsakis commented 3 years ago

This is a tracking issue for the RFC "3086" (rust-lang/rfcs#3086). The feature gate for the issue is #![feature(macro_metavar_expr)].

About tracking issues

Tracking issues are used to record the overall progress of implementation. They are also used as hubs connecting to other relevant issues, e.g., bugs or open design questions. A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature. Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved questions and bugs

Implementation history

markbt commented 3 years ago

There is a working prototype on the markbt/rust/metavariable_expressions branch. This needs feature gating, and there are a couple of TODOs to resolve, but it's otherwise in reasonable shape. I'm planning to work on it over the coming weeks.

markbt commented 3 years ago

Update (2021-04-07)

I've not yet started work on productionizing the prototype on the markbt/rust/metavariable_expressions branch. I plan to start later this month, free time permitting.

markbt commented 3 years ago

Update (2021-05-09)

I still haven't started on this yet as some stuff came up last month that prevented from having the time to work on it. It's still in my plan to work on it, and hopefully I'll have some time soon.

markbt commented 3 years ago

Update (2021-06-29)

Still no progress, as I haven't had any spare time to work on this project. I'm still planning to work on it, and hopefully will get some time soon.

joshtriplett commented 3 years ago

@markbt If you don't expect to find the bandwidth in the near future, would you potentially be interested in seeking help in the form of another owner for this initiative? If you're still interested in driving this, that's fine, but if you'd like us to switch gears from pinging you to broadcasting that the project could use help, we'd be happy to do that.

markbt commented 3 years ago

I'd be happy with any help if there's someone available. I still plan to work on it, but personal stuff is getting in the way at the moment. Sorry about that.

To recap: I have a working prototype on my branch at https://github.com/markbt/rust/tree/metavariable_expressions . The next steps are to rebase that onto the latest master, and then polish it up so that it's ready for inclusion. Then there's also the doc work to make sure the new feature is documented well. Help with any of this would be appreciated.

c410-f3r commented 2 years ago

@markbt Are you still working on this feature? If not, then I can pick up from where you stopped

markbt commented 2 years ago

I haven't had a chance to work on it for a while. I'm still interested in it, so happy to help out if you're picking it up, it just had to take a back burner relative to some personal things.I have a branch with a prototype implementation on my github fork. It's likely very out of date, so will need rebasing up to something more recent. Or perhaps you can just use it for inspiration and start from scratch. Let me know if I can help at all, although I don't have a lot of free time at the moment.

c410-f3r commented 2 years ago

Thank you @markbt

I will take a look at the branch and then get in touch if any questions arise

c410-f3r commented 2 years ago

The implementation has been merged so please try testing the feature as much as possible to find any potential bugs

mark-i-m commented 2 years ago

Thanks @c410-f3r for all your hard work!

From my limited experience with this feature, I have some concerns about the design:

c410-f3r commented 2 years ago

Thank you @mark-i-m for reviewing https://github.com/rust-lang/rust/pull/93545 and for all your contributions to the compiler.

Hehehehe... You, me and @petrochenkov had trouble trying to understand this feature

  • The depth arguments are confusing because some of the functions count up from the most nested depth and some count down from the outermost level.

Indeed! It is much easier cognitively to keep everything with the same direction instead of having count going from outer-to-inner and index/length from inner-to-outer. Although I am not sure if semantic would be impacted.

  • Also, indexing does not universally start at 0, and an index of 1 means different things for different meta-variable expressions.
  • I find the semantics of count confusing and hard to keep track of. Which level is it counting? Does depth 1 mean count everything or count the 2nd nested loop? Does depth 1 mean count everything or count only the outermost loop? Maybe a name like total_count would be clearer? Maybe the depth option should not be optional? Maybe count should be removed, and people can just sum the output of length?

Yeap, someone that wrote ${count(foo)} will probably expect that ${count(foo, 1)} will return some value related to the amount of foos instead of the actual number of outer repetitions.

If repetitions are nested, then an optional depth parameter can be used to limit the number of nested repetitions that are counted. For example, a macro expansion like:

${count(x, 1)} ${count(x, 2)} ${count(x, 3)} $( a $( b $( $x ) ) )*

The three values this expands to are the number of outer-most repetitions (the number of times a would be generated), the sum of the number of middle repetitions (the number of times b would be generated), and the total number of repetitions of $x.

https://github.com/markbt/rfcs/blob/macro_metavar_expr/text/0000-macro-metavar-expr.md#count

And as you said, throwing nested loops into the equation will alter indexing making understanding even harder. Not to mention mixing other meta-variable expressions like length 🙁.

#![feature(macro_metavar_expr)]

fn main() {
    macro_rules! mac {
        ( $( [ $( $i:ident )* ] )* ) => {{
            // ***** No loop *****

            println!("{}", ${count(i)}); // 5
            println!("{}", ${count(i, 0)}); // 2

            // Same as ${count(i)}
            //println!("{}", ${count(i, 1)});

            // Fobirdden. Index out of bounds
            //println!("{}", ${count(i, 2)});

            // ***** Outer-most loop *****

            $(
                println!("{}", ${count(i)}); // 3 and 2

                // Same as ${count(i)}
                //println!("{}", ${count(i, 0)});

                // Fobirdden. Index out of bounds
                //println!("{}", ${count(i, 1)});
            )*

            // ***** Outer-most and inner-most loops *****

            $(
                $(
                    ${ignore(i)}

                    // Forbidden. Can't be placed inside the inner-most repetition
                    //println!("{}", ${count(i)});
                )*
            )*
        }};
    }

    mac!([a b c] [d e]);
}

Maybe total_count and a mandatory depth can be nice modifications but I am also not sure about the removal of count (Useful for nested stuff). Overall, I think that users will have a hard time even with a good set of documentation.

As for myself, I learned to accept the things as they are currently defined in RFC, hehehehe 😁

c410-f3r commented 2 years ago

Any thoughts @markbt?

camsteffen commented 2 years ago
  • The depth arguments are confusing because some of the functions count up from the most nested depth and some count down from the outermost level.

+1. Being inconsistent here seems out of the question. I would vote for "distance from innermost", agreeing with the rationale in the RFC:

The meaning of the depth parameter in index and count originally counted inwards from the outer-most nesting. This was changed to count outwards from the inner-most nesting so that expressions can be copied to a different nesting depth without needing to change them.

Adding to this, having the depth parameters represent "distance from outermost" will lead to the following (unfortunate) user story:

I have a macro build_foo!. I want to refactor it to build_many_foos!, so I wrap the macro definition with $(...),*. Now all of the depth parameters are off by one so I increment them.

The only bad thing is that the English meaning of "depth" lends to "distance from outermost". But this is less important IMO.

We could support both by having negative numbers (e.g. ${index(-1)}) work as "distance from innermost", but that is probably not necessary. You'd also have to decide what to do with 0.


Maybe count should be removed, and people can just sum the output of length?

~Yes this might be a "less is more" scenario. You could potentially get what you need using expressions of index and length, like ${length(1)+index(2)} or ${length(1)*length(2)}, but we'd have to support math within ${..}.~ Edit: this doesn't work

Position Total
Current repetition index length
All repetitions count

Has it been considered to make theses values bind-able within the macro pattern? This would take depth out of the picture completely since the variables are syntactically attached to a repetition. Inspired by ngFor in Angular.

macro_rules! mac {
    ($[i=index, l=length]($word:ident),*) => {
        $(println!("{}/{}: {}", $i, $l, stringify!($word));)*
    };
}
camsteffen commented 2 years ago

It also seems odd to me that index doesn't support an ident parameter but all the other functions do.

markbt commented 2 years ago

First off, thanks to @c410-f3r for implementing this. Really excited to see it merged, and I'm going to try to find some time to try it out soon.

Thanks for all the feedback, too. I'm going to try to explain my thinking about this, as I spent some time thinking through these points when I was drafting the RFC. This was quite some time ago, so my memory is a little rusty (excuse the pun). Overall I think the RFC as it is currently is still the best way to do it, but perhaps we need to document it better to make it clearer how things work (especially count vs length).

It also seems odd to me that index doesn't support an ident parameter but all the other functions do.

Both index and length do not take ident parameters. This is because macro repetitions happen in lockstep, and so there is only one index and count for the current repetition, no matter which ident is involved. Contrast this with count where it does matter what ident it involved, as different idents can repeat different amounts in nested repetitions.

I find the semantics of count confusing and hard to keep track of. Which level is it counting? Does depth 1 mean count everything or count the 2nd nested loop? Does depth 1 mean count everything or count only the outermost loop? Maybe a name like total_count would be clearer? Maybe the depth option should not be optional? Maybe count should be removed, and people can just sum the output of length?

count was pretty much the reason I started this RFC in the first place. Part of the reason for metavar expressions is to avoid constructing large constant expressions that the compiler has to fold down, as these have a performance impacts and limitations with large numbers of repetitions which can be entirely avoided as the compiler already knows the answer.

It may be we need to improve documentation, as teaching things can sometimes be difficult. count can be thought of as "count the number of times this ident will appear". For most people there will be no need to use a depth parameter - the default of counting all depths will be what they want. The "limit to a particular number of depths" is likely only needed for special cases, when it will be worth learning the details of how it works. If we want to ensure values start at 0, I think ${count(indent, 0)} could be legitimately made to always evaluate to 1: i.e. how often does it repeat with no repetition, which is vacuously once, and shift everything down by one. We would need to distinguish "not provided" from "0" (perhaps effectively Option<usize>, where None means "all depths", although syntactically I think we would want to avoid having to write Some(2)).

We could support both by having negative numbers (e.g. ${index(-1)}) work as "distance from innermost", but that is probably not necessary. You'd also have to decide what to do with 0.

Negative numbers could work if that makes it more understandable. 0 would still mean "this depth", which is the default. In this case positive numbers >=1 would be meaningless, so the minus sign effectively becomes mandatory. Maybe another way would be to name it something different to make it clear it goes the other way (height, surround, level, ...).

The depth arguments are confusing because some of the functions count up from the most nested depth and some count down from the outermost level.

They all count from the current repetition level. count counts inwards, as it is concerned with the number of times the ident repeats within the repetition we're currently inside of. The default is "all of them", as that's the most common case. index and length count outwards as they are concerned with the place of the repetition we are currently inside of relative to the other repetitions it is itself part of. The default is the inner-most one, as, again, it's the most common case. I think this confusion perhaps lends some weight to using a different name for the depth parameters of index and length, but I don't have a good suggestion to hand.

Has it been considered to make theses values bind-able within the macro pattern?

That's really neat, but I do find it a little harder to understand (it's a bit un-Rust-lish). I'm also not sure how it would solve the count case or the ignore case. It's also quite a different design so we'd presumably need to spin through the RFC process again.

Yeap, someone that wrote ${count(foo)} will probably expect that ${count(foo, 1)} will return some value related to the amount of foos instead of the actual number of outer repetitions.

It is related to the number of foos - specifically it's the number of next-level repetitions that include foo, which might be different to the number of repetitions that include bar in the case of expressions like $( [ $( $( $foo ),* );* / $( $bar ),* ] )

camsteffen commented 2 years ago

Okay I now understand how count is categorically different from index and length. count is for inner repetitions and index and length are for outer repetitions, relative to the current expansion context. An ident is necessary for specifying an inner repetition since there could be multiple (and multiple within those etc.). But outer repetitions only need a relative depth. With this distinction in mind, it makes sense to me now that depth can point in two directions. (sorry for lagging) I would either rename depth to distance, or use a different word for "going outward" cases like level.

With regard to my alternate syntax idea, that would only work for the "outward looking" functions index and length. To that end, I am even more convinced that this would be good. It resolves the discrepancy with depth so that it now has its intuitive meaning. Having a different syntax for inward and outward looking values lends to a not-conflated mental model. To be clear, I am suggesting to keep count as is, but replace index and length as described earlier.

Another discrepancy I found in my understanding is that I assumed that count(x) would give the number of occurrences of $x in the macro input, but rather it is the number of times $x is expanded? This is usually but not always the same, and I think input count would be generally more useful and less surprising.

In any case, pointing out the inward/outward distinction upfront as it applies to the functions would resolve confusion. I think I assumed that all functions can be used in both directions (which doesn't make sense now).

camsteffen commented 2 years ago

For count, depth could be "outward distance from $x" rather than "inward distance from count(..)". I think that would be more consistent and intuitive.


Hope you don't mind one more alternate idea. Named repetitions. This allows for referencing repetitions that do not otherwise have an ident.

macro_rules! mac {
    ($h(hello)*) => {
        println!("hello {} times", ${count(h)});
    };
}
mac!(hello hello hello);
c410-f3r commented 2 years ago

A little pseudo illustration. Hope it helps

meta

// Another example

#![feature(macro_metavar_expr)]

macro_rules! mac {
    ( $( [ $( ( $($i:ident)* ) )* ] )* ) => {
        [
            // ****** 6 `ident` repetitions *****
            //
            // 6 (a, b, c, d, e f)
            ${count(i)},

            // ****** 3 `[...]` repetitions *****
            //
            // 2 (a, b)
            // 4 (c d e f)
            // 0
            $( ${count(i)}, )*

            // ****** 5 `(...)` repetitions *****
            //
            // 2 (a, b)
            // 0
            // 1 (c)
            // 0
            // 3 (d e f)
            $( $( ${count(i)}, )* )*
        ]
    }
}

fn main() {
    let array = mac!([(a b) ()] [(c) () (d e f)] []);
    dbg!(array);
}
petrochenkov commented 2 years ago

Issue: literal tokens emitted by meta-variable expression need to have correct hygiene (SyntaxContext).

For that the span assigned to them needs to be processed by Marker (see fn transcribe for examples).

nikomatsakis commented 2 years ago

@petrochenkov that sounds like a blocker for stabilization, right? (If so, I'll add to the OP)

mark-i-m commented 2 years ago

@nikomatsakis Yes, it is a blocker.

c410-f3r commented 2 years ago

If you guys don't mind, I would like to at least try stabilizing the only two things that weren't part of a discussion: ${ignore} and $$. They open a range of new possibilities, don't have the inner/outer dilemma and are IMO as useful as any counting method.

c410-f3r commented 2 years ago

A stabilization attempt is available at https://github.com/rust-lang/rust/pull/95860

CAD97 commented 2 years ago

$$crate may be surprising: #99035

joshtriplett commented 2 years ago

Labeling as design concerns due to various discussions around semantics of $$ (e.g. $$crate), as well as questions about the bits not yet stabilized.

cybersoulK commented 1 year ago

when is this stabilized? it's so important

c410-f3r commented 1 year ago

I will probably review the concerns and try stabilization again in the next months

CAD97 commented 1 year ago

The main blocking issue is determining the exact behavior we want out of $$crate and ensuring that's what's implemented. This is what reverted the first stabilization attempt, anyway.

This question is essentially whether $$crate should be equivalent to writing $crate in the crate where the macro which wrote $$crate or the crate which expanded that macro. https://github.com/rust-lang/rust/issues/99035

Linking some relevant comments:

TL;DR $$ cannot just be stabilized as-is without addressing $crate somehow.


The second question is how the metafunction interface should work; I don't think there's been a decision here. TL;DR is it ${ignore(binder)} or ${ignore($binder)}? (What "kind" level do the metafunctions operate at? It would be nice if this same syntax could be used for other metafunctionality in a somewhat uniform way; the big one is perhaps eager macro expansion.)

With a decision there, ${ignore} could be stabilized without $$.

stephanemagnenat commented 1 year ago

Hello. Is there any progress on this issue? Maybe a min-stabilisation for index (is it possible to do it without solving other issues?)? As a user, I am dealing with a horrible super complex macro with 30 internal rules combining a push-down accumulator, a counter and quite a bunch of TT munching, to generate some description structures that are not that convoluted after all. Having the index variable would allow to get rid of a significant part of the complexity.

c410-f3r commented 1 year ago

Yeah, index is very useful specially when dealing with tuples.

IMO, a partial-stabilization is unlikely to happen because of the unresolved concerns and I still could not find the time to work on this feature.

Due to low-traction and based on the following incomplete list of views that deviate from the original RFC, maybe it's worth considering creating an "amending" RFC?

JarredAllen commented 1 year ago

Would it be possible to somehow stabilize $$ without stabilizing $$crate (I'm not sure if excluding $$crate is even technically possible, let alone practically feasible) and the rest of the proposed metavariable functionality? I'd like to be able to use $$ for defining macros inside the expansions of other macros (I have code right now that does this and it's quite ugly and difficult to read since I can't use $$).

Inspirateur commented 1 year ago

this would be really nice 🥺

lowr commented 1 year ago

While fiddling around with ${count()}, I've noticed some unexpected behavior (at least to me). I'd like some clarification on whether they are intentional since they are not specified in the RFC unless I've missed.

c410-f3r commented 1 year ago

While fiddling around with ${count()}, I've noticed some unexpected behavior (at least to me). I'd like some clarification on whether they are intentional since they are not specified in the RFC unless I've missed.

* `${count(t,)}` is accepted and interpreted as `${count(t, 0)}`. I'd expected it to be rejected, and even if it were to be accepted, I'd have imagined it to be interpreted as `${count(t)}`.

* When the entire repetition (at _some_ depth) is empty, depth parameter has no effect whatsoever.
  ```rust
  macro_rules! foo {
      ($($t:ident)*) => { ${count(t, 4294967296)} }; 
  }

  macro_rules! bar {
      ( $( { $( [ $( ( $( $t:ident )* ) )* ] )* } )* ) => { ${count(t, 4294967296)} }
  }

  fn test() {
      foo!();            // successfully expands to 0
      bar!( { [] [] } ); // successfully expands to 0
  }
  ```

  ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=56143f6e068dcddc6ef5c31fed1db791))

Yeah, ${count(t,)} probably shouldn't be allowed and out of bound indexes should panic IIRC.

Can you open an issue? I will try to fix the underlying problems.

lowr commented 1 year ago

@c410-f3r Thanks for checking it out quickly! Filed #111904 and #111905.

cybersoulK commented 1 year ago

@CAD97 for real? $$ and $ignore were supposed to be stabilized for over a year now. have you actually had a need for nested macros? i do, and this is a must requirement, why block stabilization because of $$crate, i never used it, and i can't se myself using $crate at all

cybersoulK commented 1 year ago

i am guessing the solution would be to merge $$ and $ignore ASAP, and make usage of "$crate" behind an unstable feature until you decide what do to with $$crate

CAD97 commented 1 year ago

have you actually had a need for nested macros?

Yes, and I discovered the interesting behavior of $crate when writing a macro-expanded macro-expanded macro definition making use of $$ (at that time; it now uses stable-compatible techniques). I would absolutely and immediately benefit from the stabilization of both $$ and ${ignore} (or even better for my use cases, some kind of $:empty matcher).

i can't se myself using $crate at all [...] make usage of "$crate" behind an unstable feature

$crate is stable and very needed when defining resilient exported macros to be used by downstream crates. If your macro is #[macro_export]ed, you should be using $crate to refer to any item defined in your crate or upstream to you, such that downstream usage can't shadow your expected names and cause issues.

This becomes extremely necessary when using unsafe in the macro expansion, such that you can be absolutely sure that you completely control what code gets trusted and aren't exporting a macro making a soundness assumption that the user won't shadow any names that it uses.

until you decide what do to with $$crate

I originally claimed it wouldn't be possible to stabilize $$crate without

$$ and $ignore were supposed to be stabilized for over a year now.

$$ was in fact temporarily accepted for stabilization before it was backed out, but ${ignore} was not. ${ignore} was originally part of the proposed stabilization PR, but it was dropped before it was accepted due to design concerns.

why block stabilization

I don't actually have any power to directly block stabilization, let alone to revert an accepted stabilization on beta; if T-lang[^1] didn't agree with my concern about $$ they could just ignore me and stabilize it anyway. I was the one to post the revert PR, but I did so on request of T-lang.

[^1]: Technically, I am now a part of T-opsem (thus the [Member] tag), which is a subteam of T-lang. However, 1) I was not at the time of the revert (T-opsem didn't even exist), and 2) that membership does not confer T-lang membership or powers. Even if it did for some reason, I'd defer to the rest of T-lang on this.

Though tbf, I'm not blameless; I've proposed various resolutions and haven't followed up with an implementation. (This reminds me, I should ideally try my hand at properly implementing my desired fix for $crate semantics relatively soon, so it has a chance of landing for edition2024.) Time and motivation and hard to find concurrently, and no unpaid volunteer owes the project anything.

cybersoulK commented 1 year ago

@CAD97

$crate feels hacky to me. With macros 1.0, i force the user to import the entire scope of the macro, if it requires it.

I admit i am not an expert, but it might be worth to read my ideas for macro 2.0:

https://github.com/rust-lang/rust/issues/39412#issuecomment-1670841969

c410-f3r commented 11 months ago

Proposal

In hopes of making some progress, two approaches based on the feedback provided so far will be proposed here. Feel free to discuss alternatives that will lead to consensus if any of the following suggestions are not desired.

1. Innermost vs Outermost indexes

count uses outermost indices while length uses innermost indices and this inconsistency creates unnecessary confusion.

meta

To improve the situation, the order of all elements should start from the innermost index to the outermost index.

Mentions

2. $ prefix

Taking count as an example, should the syntax be count(some_metavariable) or count($some_metavariable)? The original RFC specified that metavariable expressions should refer metavariables without $ prefixes but there were some arguments in favour of $.

For unblocking purposes, the requirement of $ is being suggested. Such enforcement doesn't appear to incur a significant overhead besides the additional typing and interactions with $$ or multiple $$s shouldn't be a problem as long as the final expanded $ refers a metavariable.

Mentions

markbt commented 10 months ago

It's nice to see this progressing. We recently found some more places where this would be useful, e.g. in constructing a tuple from a method that takes indexes using an expression like ( $( ${ignore($t)} row.get(${index()}), )* ).

1. Indexes

For ${index()} and ${length()} I think the inner-to-outer ordering is important, as it means you can move these expressions without having to re-index them.

For ${count(...)} I think either order is fine. I chose outer-to-inner as to my mind the count proceeds from outside to inside, but actually it doesn't matter. For reference I use this diagram to think about it (based on the definitions in the previous comment):

    .-- current
    |   .-- proposed
    |   |
N = 2   0  ----------.                     (default)
N = 1   1  -------.  |
N = 0   2  ----.  |  |
               v  v  v
$count($x, N)  [  (  $x $length(L)  )  ]
L = 0                <----------->         (default)
L = 1             <----------------->
L = 2           <--------------------->

This proposal switches the order of N, but it's fine for it to mean either way.

2. $ prefix

Again, I think this is fine. In fact, for $ignore it makes more sense, as we could later generalize it to more complex expressions with side-effects.

3. The $$crate problem.

Has anything been decided about this? A possible alternative would be to define ${crate()} which expands to the same thing as $crate but correctly in the case of recursive macros. It could be a warning to specify $$crate, and users should use $${crate()} instead, with ordinary $crate essentially becoming shorthand for ${crate()}.

nikomatsakis commented 10 months ago

Note from lang team: we discussed @c410-f3r's proposed changes in our meeting today and agree we should move forward, but please update the comment at top of the issue. More here.

rslife commented 9 months ago

Nesting ignores issue:

#![feature(macro_metavar_expr)]

struct Foo(i32);
struct Bar(i32);
struct Baz(i32);

macro_rules! mk_p {
    ($p_ty:ty $(, foo=$foo:ident)? $(, bar=$bar:ident)?) => {
        $(${ignore($foo)} mk_p!($p_ty, foo=$foo, foo_or_bar=foo_or_bar); )?
        $(${ignore($bar)} mk_p!($p_ty, bar=$bar, foo_or_bar=foo_or_bar); )?
    };
    ($p_ty:ty $(, foo=$foo:ident)? $(, bar=$bar:ident)? $(, baz=$baz:ident)? $(, foo_or_bar=$foo_or_bar:ident)?) => {
        impl $p_ty {
            fn p(&self) {
                $(
                    ${ignore($baz)}
                    eprintln!("baz={}", self.0);
                )?

                $(
                    ${ignore($foo_or_bar)}
                    let i = self.0 + 5;
                    $(
                        ${ignore($foo)}
                        eprintln!("foo={i}");
                    )?
                    $(
                        ${ignore($bar)}
                        eprintln!("bar={i}");
                    )?
                )?
            }
        }
    };
}

mk_p!(Foo, foo=foo);
mk_p!(Bar, bar=bar);
mk_p!(Baz, baz=baz);

fn main() {}

Error:

error: meta-variable `foo_or_bar` repeats 1 time, but `bar` repeats 0 times
  --> src/main.rs:20:18
   |
20 |                   $(
   |  __________________^
21 | |                     ${ignore($foo_or_bar)}
22 | |                     let i = self.0 + 5;
23 | |                     $(
...  |
30 | |                     )?
31 | |                 )?
   | |_________________^

error: meta-variable `foo_or_bar` repeats 1 time, but `foo` repeats 0 times
  --> src/main.rs:20:18
   |
20 |                   $(
   |  __________________^
21 | |                     ${ignore($foo_or_bar)}
22 | |                     let i = self.0 + 5;
23 | |                     $(
...  |
30 | |                     )?
31 | |                 )?
   | |_________________^

Is this a current limitation or intended behavior?

i18nsite commented 8 months ago

the resolved

use ignore!

old

can $index support $index for xxx ? for example ${task.index}

image
c410-f3r commented 7 months ago

https://github.com/rust-lang/rust/pull/117050 was merged ~2 months ago and no related issues have been created since then.

Can we finally proceed with the stabilization of everything but $$? Does anyone still have any kind of blocking concern?

c410-f3r commented 6 months ago

A stabilization attempt is available at #122808