Repository: capnproto/capnproto-rust (language: rust)

Issue:
Incorrect generated code for generic struct with union
I tried the following code:

src/test.capnp:
```capnp
@0xef09ef749da18e77;

struct Foo(T) {
    foo @0 :T;
    bar :union {
        baz @1 :Void;
        qux @2 :Int32;
    }
}
```

src/main.rs:
```rust
mod test_capnp;

fn main() {
    println!("Hello, world!");
}
```

cargo.toml:
```toml
[package]
name = "capnpc-test"
version = "0.1.0"
edition = "2021"

[dependencies]
capnp = "0.14"

[build-dependencies]
capnpc = "0.14"

```

build.rs:
```rust
fn main() {
    capnpc::CompilerCommand::new()
        .src_prefix("./src")
        .file("./src/test.capnp")
        .output_path("./src")
        .run()
        .expect("schema compiler command");
}
```

Expected result: the program compiles.
Actual result: 
```
   Compiling capnp v0.14.4
   Compiling capnpc-test v0.1.0 (/home/andrew/dev/capnpc-test)
error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> src/test_capnp.rs:65:58
    |
65  |     pub fn get_bar(self) -> crate::test_capnp::foo::bar::Reader<'a> {
    |                                                          ^^^^^^ expected 1 generic argument
    |
note: struct defined here, with 1 generic parameter: `T`
   --> src/test_capnp.rs:187:16
    |
187 |     pub struct Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    |                ^^^^^^    -
help: add missing generic argument
    |
65  |     pub fn get_bar(self) -> crate::test_capnp::foo::bar::Reader<'a, T> {
    |                                                                   +++

error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> src/test_capnp.rs:141:58
    |
141 |     pub fn get_bar(self) -> crate::test_capnp::foo::bar::Builder<'a> {
    |                                                          ^^^^^^^ expected 1 generic argument
    |
note: struct defined here, with 1 generic parameter: `T`
   --> src/test_capnp.rs:246:16
    |
246 |     pub struct Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    |                ^^^^^^^    -
help: add missing generic argument
    |
141 |     pub fn get_bar(self) -> crate::test_capnp::foo::bar::Builder<'a, T> {
    |                                                                    +++

error[E0107]: this struct takes 1 generic argument but 0 generic arguments were supplied
   --> src/test_capnp.rs:145:61
    |
145 |     pub fn init_bar(self, ) -> crate::test_capnp::foo::bar::Builder<'a> {
    |                                                             ^^^^^^^ expected 1 generic argument
    |
note: struct defined here, with 1 generic parameter: `T`
   --> src/test_capnp.rs:246:16
    |
246 |     pub struct Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    |                ^^^^^^^    -
help: add missing generic argument
    |
145 |     pub fn init_bar(self, ) -> crate::test_capnp::foo::bar::Builder<'a, T> {
    |                                                                       +++

error[E0107]: missing generics for struct `bar::Pipeline`
   --> src/test_capnp.rs:165:59
    |
165 |     pub fn get_bar(&self) -> crate::test_capnp::foo::bar::Pipeline {
    |                                                           ^^^^^^^^ expected 1 generic argument
    |
note: struct defined here, with 1 generic parameter: `T`
   --> src/test_capnp.rs:324:16
    |
324 |     pub struct Pipeline<T> {
    |                ^^^^^^^^ -
help: add missing generic argument
    |
165 |     pub fn get_bar(&self) -> crate::test_capnp::foo::bar::Pipeline<T> {
    |                                                           ~~~~~~~~~~~

For more information about this error, try `rustc --explain E0107`.
error: could not compile `capnpc-test` due to 4 previous errors
```

<details>
<summary>Generated file `src/test_capnp.rs`:</summary>

```rust
// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
// DO NOT EDIT.
// source: test.capnp


pub mod foo { /* T */
  #[derive(Copy, Clone)]
  pub struct Owned<T> {
    _phantom: ::core::marker::PhantomData<T>
  }
  impl <'a, T> ::capnp::traits::Owned<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
  impl <'a, T> ::capnp::traits::OwnedStruct<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
  impl <T> ::capnp::traits::Pipelined for Owned<T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Pipeline = Pipeline<T>; }

  #[derive(Clone, Copy)]
  pub struct Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    reader: ::capnp::private::layout::StructReader<'a>,
    _phantom: ::core::marker::PhantomData<T>
  }

  impl <'a,T> ::capnp::traits::HasTypeId for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    #[inline]
    fn type_id() -> u64 { _private::TYPE_ID }
  }
  impl <'a,T> ::capnp::traits::FromStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,T> {
      Reader { reader, _phantom: ::core::marker::PhantomData, }
    }
  }

  impl <'a,T> ::capnp::traits::FromPointerReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,T>> {
      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
    }
  }

  impl <'a,T> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
      self.reader
    }
  }

  impl <'a,T> ::capnp::traits::Imbue<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
    }
  }

  impl <'a,T> Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    pub fn reborrow(&self) -> Reader<'_,T> {
      Reader { .. *self }
    }

    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
      self.reader.total_size()
    }
    #[inline]
    pub fn get_foo(self) -> ::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Reader> {
      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
    }
    pub fn has_foo(&self) -> bool {
      !self.reader.get_pointer_field(0).is_null()
    }
    #[inline]
    pub fn get_bar(self) -> crate::test_capnp::foo::bar::Reader<'a> {
      ::capnp::traits::FromStructReader::new(self.reader)
    }
  }

  pub struct Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    builder: ::capnp::private::layout::StructBuilder<'a>,
    _phantom: ::core::marker::PhantomData<T>
  }
  impl <'a,T> ::capnp::traits::HasStructSize for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    #[inline]
    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
  }
  impl <'a,T> ::capnp::traits::HasTypeId for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    #[inline]
    fn type_id() -> u64 { _private::TYPE_ID }
  }
  impl <'a,T> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, T> {
      Builder { builder, _phantom: ::core::marker::PhantomData, }
    }
  }

  impl <'a,T> ::capnp::traits::ImbueMut<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
    }
  }

  impl <'a,T> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,T> {
      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
    }
    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,T>> {
      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
    }
  }

  impl <'a,T> ::capnp::traits::SetPointerBuilder for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,T>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
  }

  impl <'a,T> Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
    pub fn into_reader(self) -> Reader<'a,T> {
      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
    }
    pub fn reborrow(&mut self) -> Builder<'_,T> {
      Builder { .. *self }
    }
    pub fn reborrow_as_reader(&self) -> Reader<'_,T> {
      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
    }

    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
      self.builder.into_reader().total_size()
    }
    #[inline]
    pub fn get_foo(self) -> ::capnp::Result<<T as ::capnp::traits::Owned<'a>>::Builder> {
      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
    }
    #[inline]
    pub fn initn_foo(self, length: u32) -> <T as ::capnp::traits::Owned<'a>>::Builder {
      ::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).initn_as(length)
    }
    #[inline]
    pub fn set_foo(&mut self, value: <T as ::capnp::traits::Owned<'_>>::Reader) -> ::capnp::Result<()> {
      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
    }
    #[inline]
    pub fn init_foo(self, ) -> <T as ::capnp::traits::Owned<'a>>::Builder {
      ::capnp::any_pointer::Builder::new(self.builder.get_pointer_field(0)).init_as()
    }
    pub fn has_foo(&self) -> bool {
      !self.builder.get_pointer_field(0).is_null()
    }
    #[inline]
    pub fn get_bar(self) -> crate::test_capnp::foo::bar::Builder<'a> {
      ::capnp::traits::FromStructBuilder::new(self.builder)
    }
    #[inline]
    pub fn init_bar(self, ) -> crate::test_capnp::foo::bar::Builder<'a> {
      self.builder.set_data_field::<u16>(0, 0);
      self.builder.set_data_field::<i32>(1, 0i32);
      ::capnp::traits::FromStructBuilder::new(self.builder)
    }
  }

  pub struct Pipeline<T> {
    _typeless: ::capnp::any_pointer::Pipeline,
    _phantom: ::core::marker::PhantomData<T>
  }
  impl<T> ::capnp::capability::FromTypelessPipeline for Pipeline<T> {
    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline<T> {
      Pipeline { _typeless: typeless, _phantom: ::core::marker::PhantomData, }
    }
  }
  impl<T> Pipeline<T> where T: ::capnp::traits::Pipelined, <T as ::capnp::traits::Pipelined>::Pipeline: ::capnp::capability::FromTypelessPipeline  {
    pub fn get_foo(&self) -> <T as ::capnp::traits::Pipelined>::Pipeline {
      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0))
    }
    pub fn get_bar(&self) -> crate::test_capnp::foo::bar::Pipeline {
      ::capnp::capability::FromTypelessPipeline::new(self._typeless.noop())
    }
  }
  mod _private {
    use capnp::private::layout;
    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 1 };
    pub const TYPE_ID: u64 = 0x9220_f7c6_3b3a_07f3;
  }

  pub mod bar { /* T */
    pub use self::Which::{Baz,Qux};

    #[derive(Copy, Clone)]
    pub struct Owned<T> {
      _phantom: ::core::marker::PhantomData<T>
    }
    impl <'a, T> ::capnp::traits::Owned<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
    impl <'a, T> ::capnp::traits::OwnedStruct<'a> for Owned <T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Reader = Reader<'a, T>; type Builder = Builder<'a, T>; }
    impl <T> ::capnp::traits::Pipelined for Owned<T> where T: for<'c> ::capnp::traits::Owned<'c>  { type Pipeline = Pipeline<T>; }

    #[derive(Clone, Copy)]
    pub struct Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      reader: ::capnp::private::layout::StructReader<'a>,
      _phantom: ::core::marker::PhantomData<T>
    }

    impl <'a,T> ::capnp::traits::HasTypeId for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      #[inline]
      fn type_id() -> u64 { _private::TYPE_ID }
    }
    impl <'a,T> ::capnp::traits::FromStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,T> {
        Reader { reader, _phantom: ::core::marker::PhantomData, }
      }
    }

    impl <'a,T> ::capnp::traits::FromPointerReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,T>> {
        ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
      }
    }

    impl <'a,T> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
        self.reader
      }
    }

    impl <'a,T> ::capnp::traits::Imbue<'a> for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
        self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
      }
    }

    impl <'a,T> Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      pub fn reborrow(&self) -> Reader<'_,T> {
        Reader { .. *self }
      }

      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
        self.reader.total_size()
      }
      #[inline]
      pub fn which(self) -> ::core::result::Result<WhichReader, ::capnp::NotInSchema> {
        match self.reader.get_data_field::<u16>(0) {
          0 => {
            ::core::result::Result::Ok(Baz(
              ()
            ))
          }
          1 => {
            ::core::result::Result::Ok(Qux(
              self.reader.get_data_field::<i32>(1)
            ))
          }
          x => ::core::result::Result::Err(::capnp::NotInSchema(x))
        }
      }
    }

    pub struct Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      builder: ::capnp::private::layout::StructBuilder<'a>,
      _phantom: ::core::marker::PhantomData<T>
    }
    impl <'a,T> ::capnp::traits::HasStructSize for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      #[inline]
      fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
    }
    impl <'a,T> ::capnp::traits::HasTypeId for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      #[inline]
      fn type_id() -> u64 { _private::TYPE_ID }
    }
    impl <'a,T> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, T> {
        Builder { builder, _phantom: ::core::marker::PhantomData, }
      }
    }

    impl <'a,T> ::capnp::traits::ImbueMut<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
        self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
      }
    }

    impl <'a,T> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,T> {
        ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
      }
      fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,T>> {
        ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
      }
    }

    impl <'a,T> ::capnp::traits::SetPointerBuilder for Reader<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,T>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
    }

    impl <'a,T> Builder<'a,T> where T: for<'c> ::capnp::traits::Owned<'c>  {
      pub fn into_reader(self) -> Reader<'a,T> {
        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
      }
      pub fn reborrow(&mut self) -> Builder<'_,T> {
        Builder { .. *self }
      }
      pub fn reborrow_as_reader(&self) -> Reader<'_,T> {
        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
      }

      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
        self.builder.into_reader().total_size()
      }
      #[inline]
      pub fn set_baz(&mut self, _value: ())  {
        self.builder.set_data_field::<u16>(0, 0);
      }
      #[inline]
      pub fn set_qux(&mut self, value: i32)  {
        self.builder.set_data_field::<u16>(0, 1);
        self.builder.set_data_field::<i32>(1, value);
      }
      #[inline]
      pub fn which(self) -> ::core::result::Result<WhichBuilder, ::capnp::NotInSchema> {
        match self.builder.get_data_field::<u16>(0) {
          0 => {
            ::core::result::Result::Ok(Baz(
              ()
            ))
          }
          1 => {
            ::core::result::Result::Ok(Qux(
              self.builder.get_data_field::<i32>(1)
            ))
          }
          x => ::core::result::Result::Err(::capnp::NotInSchema(x))
        }
      }
    }

    pub struct Pipeline<T> {
      _typeless: ::capnp::any_pointer::Pipeline,
      _phantom: ::core::marker::PhantomData<T>
    }
    impl<T> ::capnp::capability::FromTypelessPipeline for Pipeline<T> {
      fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline<T> {
        Pipeline { _typeless: typeless, _phantom: ::core::marker::PhantomData, }
      }
    }
    impl<T> Pipeline<T> where T: ::capnp::traits::Pipelined, <T as ::capnp::traits::Pipelined>::Pipeline: ::capnp::capability::FromTypelessPipeline  {
    }
    mod _private {
      use capnp::private::layout;
      pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 1, pointers: 1 };
      pub const TYPE_ID: u64 = 0xc558_9057_3aad_b32f;
    }
    pub enum Which {
      Baz(()),
      Qux(i32),
    }
    pub type WhichReader = Which;
    pub type WhichBuilder = Which;
  }
}
```

</details>

It appears there is incorrect handling of this case, where capnpc is missing the generic parameter for the union getters/setters.



Discussion / hints:
I think it's incorrectly detecting that the union is generic, the parameter shouldn't be there in the generated code for `bar`. So, it's not a missing parameter, it's extras. The `T` is showing up where it shouldn't. 

This might be an upstream bug. In the intermediary file generated by the C++ capnp tool, the generic flag might be set incorrectly for the nested union.

When I inspect the generated intermediary file with:
```
capnp compile -o- src/test.capnp > test.bin
capnp decode schema.capnp Node < test.bin > test.txt
```

I got: 
```
( nodes = [
    ( id = 17224561533995028087,
      displayName = "src/test.capnp",
      displayNamePrefixLength = 9,
      scopeId = 0,
      nestedNodes = [
        ( name = "Foo",
          id = 10529688359561463795 ) ],
      file = void,
      isGeneric = false ),
    ( id = 10529688359561463795,
      displayName = "src/test.capnp:Foo",
      displayNamePrefixLength = 15,
      scopeId = 17224561533995028087,
      nestedNodes = [],
      struct = (
        dataWordCount = 1,
        pointerCount = 1,
        preferredListEncoding = inlineComposite,
        isGroup = false,
        discriminantCount = 0,
        discriminantOffset = 0,
        fields = [
          ( name = "foo",
            codeOrder = 0,
            discriminantValue = 65535,
            slot = (
              offset = 0,
              type = (
                anyPointer = (
                  parameter = (
                    scopeId = 10529688359561463795,
                    parameterIndex = 0 ) ) ),
              defaultValue = (
                anyPointer = <opaque pointer> ),
              hadExplicitDefault = false ),
            ordinal = (explicit = 0) ),
          ( name = "bar",
            codeOrder = 1,
            discriminantValue = 65535,
            group = (
              typeId = 14220274527743357743 ),
            ordinal = (implicit = void) ) ] ),
      parameters = [(name = "T")],
      isGeneric = true ),
    ( id = 14220274527743357743,
      displayName = "src/test.capnp:Foo.bar",
      displayNamePrefixLength = 19,
      scopeId = 10529688359561463795,
      struct = (
        dataWordCount = 1,
        pointerCount = 1,
        preferredListEncoding = inlineComposite,
        isGroup = true,
        discriminantCount = 2,
        discriminantOffset = 0,
        fields = [
          ( name = "baz",
            codeOrder = 0,
            discriminantValue = 0,
            slot = (
              offset = 0,
              type = (void = void),
              defaultValue = (void = void),
              hadExplicitDefault = false ),
            ordinal = (explicit = 1) ),
          ( name = "qux",
            codeOrder = 1,
            discriminantValue = 1,
            slot = (
              offset = 1,
              type = (int32 = void),
              defaultValue = (int32 = 0),
              hadExplicitDefault = false ),
            ordinal = (explicit = 2) ) ] ),
      isGeneric = true ) ],
  requestedFiles = [
    ( id = 17224561533995028087,
      filename = "src/test.capnp",
      imports = [] ) ],
  capnpVersion = (major = 0, minor = 9, micro = 1),
  sourceInfo = [
    ( id = 14220274527743357743,
      members = [(), ()] ),
    ( id = 10529688359561463795,
      members = [(), ()] ),
    ( id = 17224561533995028087 ) ] )
```
 If you edit your `test.capnp` to make `bar` generic, it still breaks in the same way,
```
@0xef09ef749da18e77;

struct Foo(T) {
    foo @0 :T;
    bar :union {
        baz @1 :Void;
        qux @2 :T;
    }
}
```

The intermediary schema file generated for `bar` is as expected, but there's no difference in the schema for Foo. The accessor for `bar` in `Foo` is identical and contains no hint that the nested `bar` is generic.

```
( nodes = [
    ( id = 17224561533995028087,
      displayName = "src/test.capnp",
      displayNamePrefixLength = 9,
      scopeId = 0,
      nestedNodes = [
        ( name = "Foo",
          id = 10529688359561463795 ) ],
      file = void,
      isGeneric = false ),
    ( id = 10529688359561463795,
      displayName = "src/test.capnp:Foo",
      displayNamePrefixLength = 15,
      scopeId = 17224561533995028087,
      nestedNodes = [],
      struct = (
        dataWordCount = 1,
        pointerCount = 2,
        preferredListEncoding = inlineComposite,
        isGroup = false,
        discriminantCount = 0,
        discriminantOffset = 0,
        fields = [
          ( name = "foo",
            codeOrder = 0,
            discriminantValue = 65535,
            slot = (
              offset = 0,
              type = (
                anyPointer = (
                  parameter = (
                    scopeId = 10529688359561463795,
                    parameterIndex = 0 ) ) ),
              defaultValue = (
                anyPointer = <opaque pointer> ),
              hadExplicitDefault = false ),
            ordinal = (explicit = 0) ),
          ( name = "bar",
            codeOrder = 1,
            discriminantValue = 65535,
            group = (
              typeId = 14220274527743357743 ),
            ordinal = (implicit = void) ) ] ),
      parameters = [(name = "T")],
      isGeneric = true ),
    ( id = 14220274527743357743,
      displayName = "src/test.capnp:Foo.bar",
      displayNamePrefixLength = 19,
      scopeId = 10529688359561463795,
      struct = (
        dataWordCount = 1,
        pointerCount = 2,
        preferredListEncoding = inlineComposite,
        isGroup = true,
        discriminantCount = 2,
        discriminantOffset = 0,
        fields = [
          ( name = "baz",
            codeOrder = 0,
            discriminantValue = 0,
            slot = (
              offset = 0,
              type = (void = void),
              defaultValue = (void = void),
              hadExplicitDefault = false ),
            ordinal = (explicit = 1) ),
          ( name = "qux",
            codeOrder = 1,
            discriminantValue = 1,
            slot = (
              offset = 1,
              type = (
                anyPointer = (
                  parameter = (
                    scopeId = 10529688359561463795,
                    parameterIndex = 0 ) ) ),
              defaultValue = (
                anyPointer = <opaque pointer> ),
              hadExplicitDefault = false ),
            ordinal = (explicit = 2) ) ] ),
      isGeneric = true ) ],
  requestedFiles = [
    ( id = 17224561533995028087,
      filename = "src/test.capnp",
      imports = [] ) ],
  capnpVersion = (major = 0, minor = 9, micro = 1),
  sourceInfo = [
    ( id = 14220274527743357743,
      members = [(), ()] ),
    ( id = 10529688359561463795,
      members = [(), ()] ),
    ( id = 17224561533995028087 ) ] )
```

Though, this works, if you need a work around @as-com :
```
@0xe2d247c4d4c69e0b;

struct Foo(T) {
    foo @0 :T;
    bar @1 :Bar;
}

struct Bar(T) {
    union {
        baz @0 :Void;
        qux @1 :T;
    }
}
```
A somewhat simpler case that also fails:
```capnp
struct Foo(T) {
    bar :group {
        baz @0 :T;
    }
}
```

Looks like we need to add generic parameters here: https://github.com/capnproto/capnproto-rust/blob/267b8b8939fb63b1765741617b98d1029466c917/capnpc/src/codegen.rs#L514-L517
Potential fix here: #252. (Needs some cleanup before landing.)

Fix patch:
diff --git a/capnpc/src/codegen.rs b/capnpc/src/codegen.rs
index 07951e07f..9e31b1d39 100644
--- a/capnpc/src/codegen.rs
+++ b/capnpc/src/codegen.rs
@@ -497,6 +497,26 @@ fn prim_default(value: &schema_capnp::value::Reader) -> ::capnp::Result<Option<S
     }
 }
 
+// Gets the full list ordered of generic parameters for a node. Outer scopes come first.
+fn get_params(gen: &GeneratorContext,
+              mut node_id: u64) -> ::capnp::Result<Vec<String>> {
+    let mut result = Vec::new();
+
+    while node_id != 0 {
+        let node = gen.node_map[&node_id];
+        let parameters = node.get_parameters()?;
+
+        for idx in 0 .. parameters.len() {
+            result.push(parameters.get(parameters.len() - 1 - idx).get_name()?.into());
+        }
+
+        node_id = node.get_scope_id();
+    }
+
+    result.reverse();
+    Ok(result)
+}
+
 //
 // Returns (type, getter body, default_decl)
 //
@@ -509,12 +529,19 @@ pub fn getter_text(gen: &GeneratorContext,
 
     match field.which()? {
         field::Group(group) => {
+            let params = get_params(gen, group.get_type_id())?;
+            let params_string = if params.is_empty() {
+                "".to_string()
+            } else {
+                format!(",{}", params.join(","))
+            };
+
             let the_mod = gen.scope_map[&group.get_type_id()].join("::");
 
             let mut result_type = if is_reader {
-                format!("{}::Reader<'a>", the_mod)
+                format!("{}::Reader<'a{}>", the_mod, params_string)
             } else {
-                format!("{}::Builder<'a>", the_mod)
+                format!("{}::Builder<'a{}>", the_mod, params_string)
             };
 
             if is_fn {
@@ -747,6 +774,13 @@ fn generate_setter(gen: &GeneratorContext, discriminant_offset: u32,
 
     let (maybe_reader_type, maybe_builder_type) : (Option<String>, Option<String>) = match field.which()? {
         field::Group(group) => {
+            let params = get_params(gen, group.get_type_id())?;
+            let params_string = if params.is_empty() {
+                "".to_string()
+            } else {
+                format!(",{}", params.join(","))
+            };
+
             let scope = &gen.scope_map[&group.get_type_id()];
             let the_mod = scope.join("::");
 
@@ -754,7 +788,7 @@ fn generate_setter(gen: &GeneratorContext, discriminant_offset: u32,
 
             initter_interior.push(Line(format!("::capnp::traits::FromStructBuilder::new(self.builder)")));
 
-            (None, Some(format!("{}::Builder<'a>", the_mod)))
+            (None, Some(format!("{}::Builder<'a{}>", the_mod, params_string)))
         }
         field::Slot(reg_field) => {
             let offset = reg_field.get_offset() as usize;
@@ -1082,11 +1116,19 @@ fn generate_pipeline_getter(gen: &GeneratorContext,
 
     match field.which()? {
         field::Group(group) => {
+            let params = get_params(gen, group.get_type_id())?;
+            let params_string = if params.is_empty() {
+                "".to_string()
+            } else {
+                format!("<{}>", params.join(","))
+            };
+
             let the_mod = gen.scope_map[&group.get_type_id()].join("::");
             Ok(Branch(vec!(
-                Line(format!("pub fn get_{}(&self) -> {}::Pipeline {{",
+                Line(format!("pub fn get_{}(&self) -> {}::Pipeline{} {{",
                              camel_to_snake_case(name),
-                             the_mod)),
+                             the_mod,
+                             params_string)),
                 Indent(
                     Box::new(Line("::capnp::capability::FromTypelessPipeline::new(self._typeless.noop())".to_string()))),
                 Line("}".to_string()))))


Test patch:
diff --git a/capnpc/test/test.capnp b/capnpc/test/test.capnp
index 508f00a4b..7aa3ca4f1 100644
--- a/capnpc/test/test.capnp
+++ b/capnpc/test/test.capnp
@@ -508,6 +508,21 @@ struct TestGenericsUnion(Foo, Bar) {
   }
 }
 
+struct TestGenericsGroups(T1, T2) {
+  foo @0 :T1;
+  bar :group {
+    baz @1 :T2;
+  }
+
+  struct Inner(T3, T4) {
+    foo @0 :T3;
+    bar :union {
+      baz @1 :Void;
+      qux @2 :Int32;
+    }
+  }
+}
+
 struct TestUseGenerics $TestGenerics(Text, Data).ann("foo") {
   basic @0 :TestGenerics(TestAllTypes, TestAnyPointer);
   inner @1 :TestGenerics(TestAllTypes, TestAnyPointer).Inner;
diff --git a/capnpc/test/test.rs b/capnpc/test/test.rs
index fad2a5e8c..c9b2dd1b5 100644
--- a/capnpc/test/test.rs
+++ b/capnpc/test/test.rs
@@ -692,6 +692,63 @@ mod tests {
         }
     }
 
+    #[test]
+    fn test_generics_groups() {
+        use capnp::primitive_list;
+        use test_capnp::{test_generics_groups, test_all_types};
+        {
+            let mut message = message::Builder::new_default();
+            {
+                let mut root: test_generics_groups::Builder<'_, test_all_types::Owned, primitive_list::Owned<u32>>
+                    = message.init_root();
+                {
+                    root.reborrow().get_foo().unwrap().set_int16_field(17);
+                    let mut bar = root.init_bar();
+                    let mut baz = bar.reborrow().initn_baz(5);
+                    baz.set(2, 11);
+                }
+            }
+            let root: test_generics_groups::Reader<'_, test_all_types::Owned, primitive_list::Owned<u32>>
+                = message.get_root_as_reader().unwrap();
+            assert_eq!(17, root.get_foo().unwrap().get_int16_field());
+            let baz = root.get_bar().get_baz().unwrap();
+            assert_eq!(5, baz.len());
+            assert_eq!(11, baz.get(2));
+        }
+
+        {
+            let mut message = message::Builder::new_default();
+            {
+                let mut root: test_generics_groups::inner::Builder<'_,
+                                                                   test_all_types::Owned,
+                                                                   primitive_list::Owned<u8>,
+                                                                   primitive_list::Owned<i16>,
+                                                                   primitive_list::Owned<u32>>
+                    = message.init_root();
+                {
+                    let mut foo = root.reborrow().initn_foo(3);
+                    foo.set(1, -1025);
+
+                    let mut bar = root.get_bar();
+                    bar.set_baz(());
+                }
+            }
+            let root: test_generics_groups::inner::Reader<'_,
+                                                          test_all_types::Owned,
+                                                          primitive_list::Owned<u8>,
+                                                          primitive_list::Owned<i16>,
+                                                          primitive_list::Owned<u32>>
+                = message.get_root_as_reader().unwrap();
+            let foo = root.get_foo().unwrap();
+            assert_eq!(3, foo.len());
+            assert_eq!(-1025, foo.get(1));
+            match root.get_bar().which().unwrap() {
+                test_generics_groups::inner::bar::Baz(()) => (),
+                test_generics_groups::inner::bar::Qux(_) => panic!("expected baz"),
+            }
+        }
+    }
+
     #[test]
     fn test_union() {
         use test_capnp::test_union;