Rust: decl_macro: as importações não funcionam em invocações cruzadas

Criado em 31 mai. 2017  ·  3Comentários  ·  Fonte: rust-lang/rust

Reprodução mínima:

// src/lib.rs
#![feature(decl_macro)]

pub macro use_fmt {
    () => {
        use std::fmt;
    }
}

// examples/test.rs
#![feature(use_extern_macros)]

extern crate macro_test;

use macro_test::use_fmt;

use_fmt!();

fn main() {}
The error:
$ cargo build --example test
   Compiling macro-test v0.1.0 (file:///.../macro-test)
error[E0432]: unresolved import `std::fmt`
 --> examples/test.rs:7:1
  |
7 | use_fmt!();
  | ^^^^^^^^^^^ Could not find `std` in `{{root}}`
  |
  = note: this error originates in a macro outside of the current crate

error: aborting due to previous error(s)

error: Could not compile `macro-test`.

Invocar a macro na mesma caixa que está definida funciona conforme o esperado.

cc @jseyfried

A-macros-2.0 C-bug

Comentários muito úteis

Desculpe pela demora em chegar a isso. Corrigido em # 46419.

Todos 3 comentários

Desculpe pela demora em chegar a isso. Corrigido em # 46419.

Não sei se é o mesmo problema (e se o PR corrigiu), mas recebo o mesmo erro com proc_macro .
Aqui está um exemplo mínimo para reproduzir esse problema.
É o mesmo problema?
Quando executo cargo build , obtenho os seguintes erros:

error[E0433]: failed to resolve. Could not find `postgres` in `{{root}}`
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ Could not find `postgres` in `{{root}}`

error[E0433]: failed to resolve. Could not find `std` in `{{root}}`
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ Could not find `std` in `{{root}}`

error[E0412]: cannot find type `Table` in this scope
 --> src/lib.rs:9:17
  |
9 | #[derive(Debug, SqlTable)]
  |                 ^^^^^^^^ not found in this scope
help: possible candidate is found in another module, you can import it into scope
  |
3 | use Table;
  |

Existe alguma solução alternativa para esse problema?
Obrigada.

@antoyo Isso é uma consequência da higiene.

Como ::postgres::types::Type está na definição da macro proc, ela resolve no escopo da definição da macro. Em particular, ele resolverá o mesmo, não importa onde a macro seja chamada.

Não há extern crate postgres; na raiz da caixa proc-macro, então você obtém um erro de resolução. Apenas adicionar extern crate postgres; à raiz da caixa proc-macro também não é suficiente, no entanto, uma vez que as dependências proc-macro são compiladas para a plataforma host (fase 0), não a plataforma alvo (fase 1) e assim a expansão não pode vê-los.

A solução aqui é adicionar dependências de destino às caixas proc-macro, conforme descrito em https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Por enquanto, você precisa colocar extern crate postgres; na expansão da macro. Devido à higiene, isso não entrará em conflito com nada denominado postgres no site de invocação, não afetará a resolução dos argumentos da macro, etc. Por exemplo:

            quote! {
                extern crate std;
                extern crate postgres;
                use std::io::Write;
                use postgres::types::{IsNull, ToSql, Type};

                impl ToSql for #table_ident {
                    fn to_sql<W: Write + ?Sized>(&self, ty: &Type, out: &mut W) -> postgres::Result<IsNull> {
                        self.#primary_key_ident.to_sql(ty, out)
                    }

                    fn accepts(ty: &Type) -> bool {
                        match *ty {
                            Type::Int4 => true,
                            _ => false,
                        }
                    }

                    fn to_sql_checked(&self, ty: &Type, out: &mut Write) -> postgres::Result<IsNull> {
                        if !<Self as ToSql>::accepts(ty) {
                            return Err(postgres::error::Error::WrongType(ty.clone()));
                        }
                        self.to_sql(ty, out)
                    }
                }
            }

Alternativamente, você pode fazer ::postgres::types::Type resolver no site da chamada (sem higiene) dando Span::call_site() (tokens de quote! têm Span::def_site() por padrão). Em breve, spanned_quote!(span, tokens...) tornará isso mais fácil.

Esta página foi útil?
0 / 5 - 0 avaliações