flux-rs / flux

Refinement Types for Rust
MIT License
660 stars 21 forks source link

`error: custom attribute panicked` when creating extern spec for impl with lifetime #761

Closed enjhnsn2 closed 2 months ago

enjhnsn2 commented 3 months ago

When I try to create the extern_spec:

#[flux_rs::extern_spec]
impl<'a, T> std::slice::Iter<'a, T> {}

it crashes with:

error: custom attribute panicked
   --> src/main.rs:320:1
    |
320 | #[flux_rs::extern_spec]
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: message: at least one trait is required for an object type

I spent some time debugging this issue, and it fails on this line in flux: https://github.com/flux-rs/flux/blob/461f75c0508e159f3c76336eaf1494b8bab25290/lib/flux-attrs/src/extern_spec.rs#L122

and triggers this error in syn: https://github.com/dtolnay/syn/blob/3c24f576d7e1655da51bac4a6f80ded898fb9840/src/ty.rs#L840-L843

This means that somehow the lifetime is getting mistaken for a TraitBound. I have no idea how this is happening though, because #params and #self_ty look completely reasonable.\ params:

params = [
    GenericParam::Lifetime(
        LifetimeParam {
            attrs: [],
            lifetime: Lifetime {
                apostrophe: #0 bytes(9517..9519),
                ident: Ident {
                    ident: "a",
                    span: #0 bytes(9517..9519),
                },
            },
            colon_token: None,
            bounds: [],
        },
    ),
    Comma,
    GenericParam::Type(
        TypeParam {
            attrs: [],
            ident: Ident {
                ident: "T",
                span: #0 bytes(9521..9522),
            },
            colon_token: None,
            bounds: [],
            eq_token: None,
            default: None,
        },
    ),
] 

self_ty:

self_ty = Type::Path {
    qself: None,
    path: Path {
        leading_colon: None,
        segments: [
            PathSegment {
                ident: Ident {
                    ident: "std",
                    span: #0 bytes(9524..9527),
                },
                arguments: PathArguments::None,
            },
            PathSep,
            PathSegment {
                ident: Ident {
                    ident: "slice",
                    span: #0 bytes(9529..9534),
                },
                arguments: PathArguments::None,
            },
            PathSep,
            PathSegment {
                ident: Ident {
                    ident: "Iter",
                    span: #0 bytes(9536..9540),
                },
                arguments: PathArguments::AngleBracketed {
                    colon2_token: None,
                    lt_token: Lt,
                    args: [
                        GenericArgument::Lifetime(
                            Lifetime {
                                apostrophe: #0 bytes(9541..9543),
                                ident: Ident {
                                    ident: "a",
                                    span: #0 bytes(9541..9543),
                                },
                            },
                        ),
                        Comma,
                        GenericArgument::Type(
                            Type::Path {
                                qself: None,
                                path: Path {
                                    leading_colon: None,
                                    segments: [
                                        PathSegment {
                                            ident: Ident {
                                                ident: "T",
                                                span: #0 bytes(9545..9546),
                                            },
                                            arguments: PathArguments::None,
                                        },
                                    ],
                                },
                            },
                        ),
                    ],
                    gt_token: Gt,
                },
            },
        ],
    },
}

If you have any input, that would be much appreciated, as I'm pretty stumped.

nilehmann commented 3 months ago

The issue is that the macro is trying to generate this:

struct __FluxExternImplStruct1Iter<'a, T>('a, T, std::slice::Iter<'a, T>);

which is obviously not valid Rust syntax.

I need to think for a moment about why we are adding the generics as fields. Ranjit wrote that code...

enjhnsn2 commented 3 months ago

hmmmm, curious. Well that makes sense why it doesn't like the lifetime there, although I have no clue how to fix this.

nilehmann commented 3 months ago

I'm preparing a fix