Rust: decl_macro : les importations ne fonctionnent pas dans les appels inter-crate

Créé le 31 mai 2017  ·  3Commentaires  ·  Source: rust-lang/rust

Reproduction minimale :

// 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`.

L'appel de la macro dans la même caisse que celle définie fonctionne comme prévu.

cc @jseyfried

A-macros-2.0 C-bug

Commentaire le plus utile

Désolé pour le retard pour en arriver là. Corrigé dans #46419.

Tous les 3 commentaires

Désolé pour le retard pour en arriver là. Corrigé dans #46419.

Je ne sais pas si c'est le même problème (et si le PR l'a corrigé), mais j'obtiens la même erreur avec proc_macro .
Voici un exemple minimal pour reproduire ce problème.
Est-ce le même problème ?
Lorsque j'exécute cargo build , j'obtiens les erreurs suivantes :

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-t-il une solution de contournement pour ce problème ?
Merci.

@antoyo C'est une conséquence de l'hygiène.

Puisque ::postgres::types::Type trouve dans la définition proc-macro, il se résout dans la portée de la définition de la macro. En particulier, il résoudra la même chose, peu importe où la macro est invoquée.

Il n'y a pas de extern crate postgres; à la racine du crate proc-macro, vous obtenez donc une erreur de résolution. Le simple ajout de extern crate postgres; à la racine de la caisse proc-macro n'est pas suffisant non plus, car les dépendances proc-macro sont compilées pour la plate-forme hôte (phase 0), pas la plate-forme cible (phase 1) et donc le l'expansion ne peut pas les voir.

La solution ici consiste à ajouter des dépendances cibles aux caisses proc-macro comme décrit dans https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

Pour l'instant, vous devez mettre un extern crate postgres; dans l'extension de macro. Pour des raisons d'hygiène, cela n'entrera en conflit avec aucun élément nommé postgres sur le site d'invocation, n'affectera pas la résolution des arguments de la macro, etc. Par exemple :

            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)
                    }
                }
            }

Alternativement, vous pouvez faire résoudre ::postgres::types::Type sur le site d'appel (non hygiénique) en lui donnant Span::call_site() (les jetons de quote! ont Span::def_site() par défaut). Bientôt, spanned_quote!(span, tokens...) rendra cela plus facile.

Cette page vous a été utile?
0 / 5 - 0 notes