Rust: decl_macro: las importaciones no funcionan en invocaciones entre cajas

Creado en 31 may. 2017  ·  3Comentarios  ·  Fuente: rust-lang/rust

Reproducción 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 la macro en la misma caja que está definida funciona como se esperaba.

cc @jseyfried

A-macros-2.0 C-bug

Comentario más útil

Perdón por la demora en llegar a esto. Corregido en # 46419.

Todos 3 comentarios

Perdón por la demora en llegar a esto. Corregido en # 46419.

No sé si es el mismo problema (y si el RP lo solucionó), pero obtengo el mismo error con proc_macro .
Aquí hay un ejemplo mínimo para reproducir este problema.
¿Es el mismo problema?
Cuando ejecuto cargo build , obtengo los siguientes errores:

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 alguna solución para este problema?
Gracias.

@antoyo Esto es consecuencia de la higiene.

Dado que ::postgres::types::Type está en la definición de proc-macro, se resuelve en el alcance de la definición de macro. En particular, resolverá lo mismo sin importar dónde se invoque la macro.

No hay extern crate postgres; en la raíz de la caja proc-macro, por lo que obtiene un error de resolución. Sin embargo, simplemente agregar extern crate postgres; a la raíz de la caja proc-macro tampoco es suficiente, ya que las dependencias proc-macro se compilan para la plataforma host (fase 0), no para la plataforma de destino (fase 1) y, por lo tanto, el la expansión no puede verlos.

La solución aquí es agregar dependencias de destino a las cajas proc-macro como se describe en https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Por ahora, debe poner extern crate postgres; en la expansión macro. Debido a la higiene, esto no entrará en conflicto con nada llamado postgres en el sitio de invocación, no afectará la resolución de los argumentos de la macro, etc. Por ejemplo:

            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, puede hacer que ::postgres::types::Type resuelva en el sitio de la llamada (de manera antihigiénica) dándole Span::call_site() (los tokens de quote! tienen Span::def_site() de forma predeterminada). Pronto, spanned_quote!(span, tokens...) hará que esto sea más fácil.

¿Fue útil esta página
0 / 5 - 0 calificaciones