fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.26k stars 300 forks source link

Support parsing arbitrarily complex pub-use statement chains #2302

Open Zhou-Pixel opened 1 month ago

Zhou-Pixel commented 1 month ago

Describe the bug

error.rs

use snafu::Snafu;

pub type Result<O, E = Error> = std::result::Result<O, E>;

#[derive(Debug, Snafu)]
#[snafu(module(builder), context(suffix(false)), visibility(pub(crate)))]
pub(crate) enum Error {

    #[snafu(display("Database error: {source}"))]
    DatabaseError {
        backtrace: snafu::Backtrace,
        source: sea_orm::DbErr,
    },

}

profile.rs

#[flutter_rust_bridge::frb(opaque)]
pub struct Database {
}

impl Database {
    pub fn open() {}
}

Steps to reproduce

It is OK to write two pieces of code in the same file, but it is not OK to write them separately.

Logs

[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=PrimaryKey ans=Delegate(PrimitiveEnum(MirTypeDelegatePrimitiveEnum { mir: MirTypeEnumRef { ident: MirEnumIdent(NamespacedName { namespace: Namespace { joined_path: "crate::profile" }, name: "PrimaryKey" }), is_exception: false }, repr: I32 }))
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=PrimaryKey ans=Delegate(PrimitiveEnum(MirTypeDelegatePrimitiveEnum { mir: MirTypeEnumRef { ident: MirEnumIdent(NamespacedName { namespace: Namespace { joined_path: "crate::profile" }, name: "PrimaryKey" }), is_exception: false }, repr: I32 }))
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=Relation ans=Delegate(PrimitiveEnum(MirTypeDelegatePrimitiveEnum { mir: MirTypeEnumRef { ident: MirEnumIdent(NamespacedName { namespace: Namespace { joined_path: "crate::profile" }, name: "Relation" }), is_exception: false }, repr: I32 }))
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=Model ans=StructRef(MirTypeStructRef { ident: MirStructIdent(NamespacedName { namespace: Namespace { joined_path: "crate::profile" }, name: "Model" }), is_exception: false })
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/enum_or_struct.rs:85] Treat ActiveModel as opaque by compute_default_opaque
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=ActiveModel ans=RustAutoOpaqueImplicit(MirTypeRustAutoOpaqueImplicit { ownership_mode: Owned, inner: MirTypeRustOpaque { namespace: Namespace { joined_path: "crate::profile" }, inner: MirRustOpaqueInner(MirLifetimeAwareType { raw: "flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ActiveModel>" }), codec: Moi, dart_api_type: None, brief_name: true }, raw: MirRustAutoOpaqueRaw { string: MirLifetimeAwareType { raw: "ActiveModel" }, segments: [NameComponent { ident: "ActiveModel", args: [] }] }, reason: Some(StructOrEnumRequireOpaque), ignore: false })
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/enum_or_struct.rs:85] Treat ActiveModel as opaque by compute_default_opaque
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=ActiveModel ans=RustAutoOpaqueImplicit(MirTypeRustAutoOpaqueImplicit { ownership_mode: Owned, inner: MirTypeRustOpaque { namespace: Namespace { joined_path: "crate::profile" }, inner: MirRustOpaqueInner(MirLifetimeAwareType { raw: "flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ActiveModel>" }), codec: Moi, dart_api_type: None, brief_name: true }, raw: MirRustAutoOpaqueRaw { string: MirLifetimeAwareType { raw: "ActiveModel" }, segments: [NameComponent { ident: "ActiveModel", args: [] }] }, reason: Some(StructOrEnumRequireOpaque), ignore: false })
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/function/real/mod.rs:139] parse_function function name: "open"
[2024-09-16T05:07:40.145Z DEBUG /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/parser/mir/parser/ty/ty.rs:12] TypeParserWithContext.parse_type ty=Database ans=StructRef(MirTypeStructRef { ident: MirStructIdent(NamespacedName { namespace: Namespace { joined_path: "crate::api::error::builder" }, name: "Database" }), is_exception: false })
[77.1s] Parse ⠄
  └── [77.1s] Cargo expand & syn parse  
  └── [0.0s] Parse HIR ⠂                                                                                                                        [2024-09-16T05:07:40.145Z ERROR /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/utils/logs.rs:55] panicked at /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/ir/mir/ty/structure.rs:36:32:
no entry found for key=MirStructIdent(NamespacedName { namespace: Namespace { joined_path: "crate::api::error::builder" }, name: "Database" })
thread 'main' panicked at /home/zhou/.cargo/registry/src/index.crates.io-6f17d22bba15001f/flutter_rust_bridge_codegen-2.4.0/src/library/codegen/ir/mir/ty/structure.rs:36:32:
no entry found for key=MirStructIdent(NamespacedName { namespace: Namespace { joined_path: "crate::api::error::builder" }, name: "Database" })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Expected behavior

No response

Generated binding code

No response

OS

Linux zhou-ser 6.10.10-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 12 Sep 2024 17:21:02 +0000 x86_64 GNU/Linux

Version of flutter_rust_bridge_codegen

flutter_rust_bridge_codegen 2.4.0

Flutter info

[✓] Flutter (Channel stable, 3.24.3, on EndeavourOS 6.10.10-arch1-1, locale zh_CN.UTF-8)
    • Flutter version 3.24.3 on channel stable at /home/zhou/.cache/flutter_sdk
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2663184aa7 (4 天前), 2024-09-11 16:27:48 -0500
    • Engine revision 36335019a8
    • Dart version 3.5.3
    • DevTools version 2.37.3

[✗] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/to/linux-android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.

[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Linux toolchain - develop for Linux desktop
    • clang version 18.1.8
    • cmake version 3.30.3
    • ninja version 1.12.1
    • pkg-config version 2.1.1

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/to/linux-android-setup for detailed instructions).

[✓] Connected device (1 available)
    • Linux (desktop) • linux • linux-x64 • EndeavourOS 6.10.10-arch1-1

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 3 categories.

Version of clang++

clang version 18.1.8

Additional context

No response

welcome[bot] commented 1 month ago

Hi! Thanks for opening your first issue here! :smile:

fzyzcjy commented 1 month ago

Hmm that's weird. Could you please firstly make a minimal reproducible sample? For example,

fzyzcjy commented 1 month ago

Wild guess: is it possible snafu somehow notice DatabaseError and generate some code with name Database, which then confuses frb since there is another "Database" struct there?

To check this, try to firstly rename everything into unrelated names, such as "DatabaseError -> OneError", "Database -> Two", etc

Zhou-Pixel commented 1 month ago

Wild guess: is it possible snafu somehow notice DatabaseError and generate some code with name Database, which then confuses frb since there is another "Database" struct there?

To check this, try to firstly rename everything into unrelated names, such as "DatabaseError -> OneError", "Database -> Two", etc

Yeah, DatabaseError -> MyDatabaseError is ok. snafu do generate a struct named Database, but I think they are different and should be recognized. Their full names are pub(crate) crate::api::error::builder::Database and pub crate::api::profile::Database.

Another solution is to putting the snafu's Error and my Database declaration in the same mod

my example: https://github.com/Zhou-Pixel/test_error.git

Zhou-Pixel commented 1 month ago

Wild guess: is it possible snafu somehow notice DatabaseError and generate some code with name Database, which then confuses frb since there is another "Database" struct there?

To check this, try to firstly rename everything into unrelated names, such as "DatabaseError -> OneError", "Database -> Two", etc

One thing that confuses me is that when I write them in the same file, it works, but when I separate them, it doesn't work

fzyzcjy commented 1 month ago

I think they are different and should be recognized.

Currently this is not implemented, because it is nontrivial to correctly understand all those prefixes. For example, you need to understand use a::b::C, use a::*, pub use a::b::* (which then exports everything inside b into its current mod), etc.

Zhou-Pixel commented 1 month ago

he snafu's Error and my Database declaration in the same mod

But the Database snafu generated is pub(crate), it means I don't want to expose it to dart. Only one struct named Database is pub. is that implemented?

fzyzcjy commented 1 month ago

Due to compatibility reasons, first-party pub(crate) structs are also scanned and considered. Therefore, before we release 3.x version, maybe it is good to keep it unchanged...