Rust: decl_macro: ΠΈΠΌΠΏΠΎΡ€Ρ‚ Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π°Ρ… кросс-ΠΊΡ€Π΅ΠΉΡ‚ΠΎΠ²

Π‘ΠΎΠ·Π΄Π°Π½Π½Ρ‹ΠΉ Π½Π° 31 мая 2017  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ  Β·  Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: rust-lang/rust

МинимальноС воспроизвСдСниС:

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

Π’Ρ‹Π·ΠΎΠ² макроса Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ ящикС, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΎΠ½ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½, Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ.

cc @jseyfried

Π‘Π°ΠΌΡ‹ΠΉ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΉ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

ΠŸΡ€ΠΈΠ½ΠΎΡΠΈΠΌ извинСния Π·Π° Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ с этим. Π˜ΡΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π² # 46419.

ВсС 3 ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ

ΠŸΡ€ΠΈΠ½ΠΎΡΠΈΠΌ извинСния Π·Π° Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ с этим. Π˜ΡΠΏΡ€Π°Π²Π»Π΅Π½ΠΎ Π² # 46419.

Π― Π½Π΅ знаю, такая ΠΆΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° (ΠΈ исправил Π»ΠΈ Π΅Π΅ PR), Π½ΠΎ я ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽ Ρ‚Ρƒ ΠΆΠ΅ ΠΎΡˆΠΈΠ±ΠΊΡƒ с proc_macro .
Π’ΠΎΡ‚ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ воспроизвСдСния этой ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹.
Π­Ρ‚ΠΎ Ρ‚Π° ΠΆΠ΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°?
Когда я Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽ cargo build , я ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ошибки:

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;
  |

Π•ΡΡ‚ΡŒ Π»ΠΈ способ Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ этой ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹?
Бпасибо.

@antoyo Π­Ρ‚ΠΎ слСдствиС Π³ΠΈΠ³ΠΈΠ΅Π½Ρ‹.

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ::postgres::types::Type находится Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠΈ макроса proc, ΠΎΠ½ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ Π² области опрСдСлСния макроса. Π’ частности, ΠΎΠ½ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ Ρ‚ΠΎ ΠΆΠ΅ самоС нСзависимо ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, Π³Π΄Π΅ вызываСтся макрос.

Π’ ΠΊΠΎΡ€Π½Π΅ ящика proc-macro Π½Π΅Ρ‚ extern crate postgres; , поэтому Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚Π΅ ΠΎΡˆΠΈΠ±ΠΊΡƒ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ. Однако простого добавлСния extern crate postgres; Π² ΠΊΠΎΡ€Π΅Π½ΡŒ ящика proc-macro Ρ‚Π°ΠΊΠΆΠ΅ нСдостаточно, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ зависимости proc-macro ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΡƒΡŽΡ‚ΡΡ для ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹ хоста (этап 0), Π° Π½Π΅ для Ρ†Π΅Π»Π΅Π²ΠΎΠΉ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡ‹ (этап 1), ΠΈ поэтому Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡ… Π²ΠΈΠ΄Π΅Ρ‚ΡŒ.

РСшСниСм здСсь являСтся Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Ρ†Π΅Π»Π΅Π²Ρ‹Ρ… зависимостСй Π² ΠΊΡ€Π΅ΠΉΡ‚Ρ‹ proc-macro, ΠΊΠ°ΠΊ описано Π² https://github.com/rust-lang/rust/issues/45934#issuecomment -344497531.

На Π΄Π°Π½Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ extern crate postgres; Π² раскрытиС макроса. Из-Π·Π° Π³ΠΈΠ³ΠΈΠ΅Π½Ρ‹ это Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΠΎΠ²Π°Ρ‚ΡŒ с Ρ‡Π΅ΠΌ-Π»ΠΈΠ±ΠΎ с ΠΈΠΌΠ΅Π½Π΅ΠΌ postgres Π½Π° сайтС Π²Ρ‹Π·ΠΎΠ²Π°, Π½Π΅ повлияСт Π½Π° Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² макроса ΠΈ Ρ‚. Π”. НапримСр:

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

Π’ качСствС Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρ‹ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠΈΡ‚ΡŒ ::postgres::types::Type Π½Π° мСстС Π²Ρ‹Π·ΠΎΠ²Π° (Π½Π΅Π³ΠΈΠ³ΠΈΠ΅Π½ΠΈΡ‡Π½ΠΎ), ΡƒΠΊΠ°Π·Π°Π² Π΅ΠΌΡƒ Span::call_site() (Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ ΠΈΠ· quote! Span::def_site() ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΈΠΌΠ΅ΡŽΡ‚ spanned_quote!(span, tokens...) упростит эту Π·Π°Π΄Π°Ρ‡Ρƒ.

Π‘Ρ‹Π»Π° Π»ΠΈ эта страница ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ?
0 / 5 - 0 Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³ΠΈ

Π‘ΠΌΠ΅ΠΆΠ½Ρ‹Π΅ вопросы

Robbepop picture Robbepop  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

jmegaffin picture jmegaffin  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

dwrensha picture dwrensha  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

drewcrawford picture drewcrawford  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

cuviper picture cuviper  Β·  3ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ