Repository: rust
Issue: Matching function signature is nearly impossible in declarative macros (mbe)
Labels: A-macros,T-lang,C-feature-request

I'm trying a write a macro that needs a function signature. I want smt like this to work:
```rust
macros! {
    pub fn foo(&self, arg: Arg) -> Ret;
    // inside the macro I have access to visibility, function qualifiers, arguments, 
}
```

However, there are 2 things that are nearly impossible to parse...

## Qualifiers

According to [rust reference][ref] rust function can have
- either `const` or `async` 
- `unsafe`
- `extern` / `extern "Abi"`

It's possible to use `$( unsafe )?` (and same for other qualifiers), however, you then can't expand it back (because in this repetition there are no `$var`s).

It's also not possible to match them with `tt`s because `:vis` [doesn't allow][tt_follow_vis] `tt` after it.

_My workaround_ is to use `[ $( $qual:tt )* ]`, but it's just a workaround and it requires changes to macro input. (you need to write `pub [unsafe] fn ...`)

[ref]: https://doc.rust-lang.org/reference/items/functions.html
[tt_follow_vis]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=460c3c4a0c1a76f9cc5cf0c5143009e2

## Trait bounds and `where` clause

there are several problems with bounds...

#### 1. there is no way to match a trait (`path::Trait<'life, Type>`)

This one is more tricky. There are no such fragments as trait or bound, so we'll need to work around this somehow. (`:ty` doesn't work because it assumes that a trait is a trait object and it [can't be used][trait_ty] in a bound)

I'd like this to work: `$trait:path $( < $( $lifes:lifetime ),* $(,)? $( $generics:ty ),* $(,)? > )?`, however, there are 2 problems with it:
1. `:path` [doesn't allow][path_lt] `<` after it. (workaround: use `$tr_head:ident $( :: $tr_tail:ident )*` instead of `:path`)
2. `rustc` can't choose between [parsing `'life` as a lifetime or as a type][local_ihateyou] (???) (it somehow [thinks that `'life` can be a part of trait object][life_tr_obj])

I thought that `2.` can be worked around by using smt like `$life_or_ty_head:tt $( :: $ty_tail:ident )* $( < $( $lifes:lifetime ),* $(,)? $( $generics:ty ),* $(,)? > )?` (`:tt` will match both `'life` and `head` part of `head::Ty...`), **but** here is a catch: to express a type you need generics with lifetimes over again :)

[trait_ty]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b7a33f376fa0b21659523236900df797
[path_lt]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2774ff6da7cc9d6abfe8e2e5d7775674
[local_ihateyou]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6cab28918be2277664dca43eb1737b70
[life_tr_obj]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=69e8b2d08b8af74590f6952c4604c2e1

#### 2. it's not possible to use `+`, `*` and `?` as a separator in repetition 

You need this to match a bound: `: Trait + 'a + Trait2 + 'b ...`

Related issue (opened in 2014! >_<): #18700 

#### 3. you can't express 'either PatternA or PatternB' with mbe

This is needed because in where clause you can alternate lifetimes and types:
```rust
fn test<'t, 'a, 'b, 'c, A, B>() 
where
    A: Trait,
    't: 'a + 'b,
    B: Trait,
    't: 'c,
{}
```
([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=8b5fd784112b8c7a84f2f46a694fdf3d))

## Possible solutions

One a may think of is to add missing fragments & separator escaping, e.g.:

- `:trait` (matches the same things as `:ty` but assumes that it's trait)
- `:bound` (matches bound, e.g.: `Trait + 'life + Trait<'life, i32, T>`)
- `:qual` (matches one of `const`, `async`, `unsafe`, `extern "Abi"` and `extern`)
- `$( ... )$+*` (matches 0 or more `...` separated by `+`, see https://github.com/rust-lang/rfcs/pull/944)

This would solve most of the mentioned problems (except `'life`/`Gen` ordering), but I have no idea what problems all of that can bring, is it hard to implement, is this breaking change, etc. I would like to hear from somebody who is more competent in this theme...

The lifetime/generics ordering problem can be solved with 'or patterns' (ADT/enums in macros? :thinking:) but this needs a syntax decision and there are a lot of open questions (I think). 

I can imagine smt like `${ A( $a:ident ... ) | B( ... $b:ident ) }` & `${ A => { a($a) }; B => { b($b) }; }` (first is a pattern and second is a expansion thing) that will expand `t ...` to `a(t)` and `... t` to `b(t)`......