Ошибка макроса Rust: локальная неоднозначность: несколько вариантов разбора - PullRequest
0 голосов
/ 13 января 2020

Следующий код ржавчины не компилируется из-за ошибки макроса

error: local ambiguity: multiple parsing options: built-in NTs stmt ('s') or 1 other option. 

макрос A в порядке. Макрос B показывает ошибку.

macro_rules! A {
    ($x: ident, $($s: stmt)*) => {
        println!("hello");
    };
}

macro_rules! B {
    ($x: ident, $($s: stmt)*; $e: expr) => {
        println!("hello");
    };
}

fn main() {
    A![my_name, let x=5];
    B![my_name, let x=5; 5];
}

Этот минимальный воспроизводимый пример в B - именно то, что мне нужно. Я хочу, чтобы макрос принимал несколько операторов let и завершался каким-то другим выражением.

Какая неопределенность упоминается?

Есть ли способ обойти это?

Из тех жетонов, которые были приняты после фрагментов выписки, я попробовал несколько комбинаций, но ни один из них, похоже, не имеет значения. Также нельзя поменять оператор на дерево токенов.

1 Ответ

3 голосов
/ 13 января 2020

Выражения являются операторами, поэтому $($s: stmt)*; $e: expr является неоднозначным, потому что компилятор не может выбирать между использованием s или e, когда он встречается с ним.

Поскольку вы ожидаете только привязки, вы можете легко расширить сами:

macro_rules! A {
    ($x: ident, $($s: stmt)*) => {
        println!("hello");
    };
}

macro_rules! B {
    ($x: ident, $(let $p:pat = $v:expr)*; $e: expr) => {
        $(let $p = $v);*
        println!("hello: {}", $e);
    };
}

fn main() {
    A![my_name, let x=5];
    B![my_name, let x=5; x+2];
}

Обратите внимание, что это не поддерживает включение типов в привязку (let a: i32 = 42;), потому что pat не может сопровождаться :.

...