tokio-rs / prost

PROST! a Protocol Buffers implementation for the Rust Language
Apache License 2.0
3.69k stars 481 forks source link

`impl ::prost::Message` for a struct shadows the user-defined type #1042

Closed shizzard closed 2 months ago

shizzard commented 3 months ago

Minimal protobuf file to reproduce:

syntax = "proto3";
enum B {
  DEFAULT = 0;
  NON_DEFAULT = 1;
}
message A { B f1 = 1; }

Problem is that generated impl ::prost::Message for A contains a generic type parameter for a number of functions, that shadows the B enum:

            #[allow(unused_variables)]
            fn encode_raw<B>(&self, buf: &mut B)
            where
                B: ::prost::bytes::BufMut,
            {
                if self.f1 != B::default() as i32 {
                    ::prost::encoding::int32::encode(1u32, &self.f1, buf);
                }
            }

The error message from the compiler, that is not clear:

error[E0599]: no function or associated item named `default` found for type parameter `B` in the current scope
 --> tests/../.proto_out/test.rs:3:28
  |
3 | #[derive(Clone, PartialEq, ::prost::Message)]
  |                            ^^^^^^^^^^^^^^^^
  |                            |
  |                            function or associated item not found in `B`
  |                            function or associated item `default` not found for this type parameter
  |
  = help: items from traits can only be used if the type parameter is bounded by the trait
  = note: this error originates in the derive macro `::prost::Message` (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait defines an item `default`, perhaps you need to restrict type parameter `B` with it:
  |
3 | #[derive(Clone, PartialEq, ::prost::Message: Default)]
  |                                            +++++++++

For more information about this error, try `rustc --explain E0599`.

There are at least two possible solutions:

  1. Rename the generic type parameter to reduce the chance of ident clashes (e.g. <ImplProstBytesBufMut> instead of <B>);
  2. Add a note or a known issue regarding this problem.

Probably, there are some other similar issues that are not noticed yet.

caspermeijn commented 3 months ago

So because you generate an enum B and there is a generic type B, there is a conflict.

The simplest solution seems to change the generated function signature to: fn encode_raw(&self, buf: &mut impl ::prost::bytes::BufMut). That way there is no generic parameter B. Are you willing to create a PR that changes all <B> + where B to a impl Type?

shizzard commented 3 months ago

Yes, the solution makes sense, I'll make a PR with these changes.

shizzard commented 3 months ago

@caspermeijn note, I also changed the generated functions for enums (Enumeration derive), to make everything consistent and to avoid similar issues with enums.