neon64
1
After updating rustc to the latest 1.6.0 nightly my crazy over-generified graphics library fails to build yet again.
This time it is complaining about an overflow while adding drop-check rules.
This is the most important few lines of code (the complete thing is here and here).
On the playground
pub struct DescriptorSet<'a> {
pub slots: Vec<AttachInfo<'a, Resources>>
}
pub struct Resources;
impl<'a> ResourcesTrait<'a> for Resources {
type DescriptorSet = descriptor::DescriptorSet<'a>;
// more definitions here
}
pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
Buffer(BufferViewAttachInfo<'a, R>),
NextDescriptorSet(Arc<'a, R::DescriptorSet>)
}
What I have found out
- I have tried increasing the recursion limit to 1000 with
#![recursion_limit="1000"]
- The error is because the
DescriptorSet struct is recursive. (because R::DescriptorSet == DescriptorSet<'a> there can be an infinite amount of 'next descriptor sets')
- I think the issue was introduced by implementing non-parametric dropck
- I think my issue is similar to this test case
This reduced example works, so something more must be going on. I forgot to actually use the types, if I add let x = DescriptorSet {slots: Vec::new()}; it then fails
Questions
- Is
DescriptorSet a non-regular type? If so, what does that mean.
- It seems like this is caused by my type having 'polymorphic recursion'. Is there a way I can make it more concrete?
- In short is there a 'fix' for the error or is this invalid code that is now correctly rejected.
Full Error
opal_driver_gl/src/device.rs:125:9: 125:65 error: overflow while adding drop-check rules for core::result::Result<alloc::arc::Arc<descriptor::DescriptorSet<'_>>, opal::descriptor::DescriptorSetCreationError> [E0320]
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
opal_driver_gl/src/device.rs:125:9: 125:65 note: overflowed on struct core::nonzero::NonZero field #0 type: *const alloc::arc::ArcInner<buffer::Buffer<'_>>
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
opal_driver_gl/src/device.rs:125:9: 125:34 error: overflow while adding drop-check rules for core::result::Result<descriptor::DescriptorSet<'_>, opal::descriptor::DescriptorSetCreationError> [E0320]
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~~~~~~~~~~
opal_driver_gl/src/device.rs:125:9: 125:34 note: overflowed on struct core::nonzero::NonZero field #0 type: *const opal::descriptor::AttachInfo<'_, Resources>
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~~~~~~~~~~
opal_driver_gl/src/device.rs:125:48: 125:64 error: overflow while adding drop-check rules for alloc::arc::Arc<descriptor::DescriptorSet<'_>> [E0320]
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~
opal_driver_gl/src/device.rs:125:48: 125:64 note: overflowed on struct alloc::arc::ArcInner field `strong` type: core::sync::atomic::AtomicUsize
opal_driver_gl/src/device.rs:125 DescriptorSet::new(slots).map(|result| Arc::new(result))
^~~~~~~~~~~~~~~~
opal_driver_gl/src/descriptor.rs:31:9: 33:11 error: overflow while adding drop-check rules for core::result::Result<descriptor::DescriptorSet<'_>, opal::descriptor::DescriptorSetCreationError> [E0320]
opal_driver_gl/src/descriptor.rs:31 Ok(DescriptorSet {
opal_driver_gl/src/descriptor.rs:32 slots: slots
opal_driver_gl/src/descriptor.rs:33 })
opal_driver_gl/src/descriptor.rs:31:9: 33:11 note: overflowed on struct core::nonzero::NonZero field #0 type: *const opal::descriptor::AttachInfo<'_, Resources>
opal_driver_gl/src/descriptor.rs:31 Ok(DescriptorSet {
opal_driver_gl/src/descriptor.rs:32 slots: slots
opal_driver_gl/src/descriptor.rs:33 })
opal_driver_gl/src/descriptor.rs:31:12: 33:10 error: overflow while adding drop-check rules for descriptor::DescriptorSet<'_> [E0320]
opal_driver_gl/src/descriptor.rs:31 Ok(DescriptorSet {
opal_driver_gl/src/descriptor.rs:32 slots: slots
opal_driver_gl/src/descriptor.rs:33 })
opal_driver_gl/src/descriptor.rs:31:12: 33:10 note: overflowed on enum opal::descriptor::AttachInfo variant Buffer field #0 type: opal::descriptor::BufferViewAttachInfo<'_, Resources>
opal_driver_gl/src/descriptor.rs:31 Ok(DescriptorSet {
opal_driver_gl/src/descriptor.rs:32 slots: slots
opal_driver_gl/src/descriptor.rs:33 })
Thanks if you could assist me.
Reduces to:
use std::sync::Arc;
pub struct DescriptorSet<'a> {
pub slots: Vec<AttachInfo<'a, Resources>>
}
pub trait ResourcesTrait<'r>: Sized {
type DescriptorSet: 'r;
}
pub struct Resources;
impl<'a> ResourcesTrait<'a> for Resources {
type DescriptorSet = DescriptorSet<'a>;
}
pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
NextDescriptorSet(Arc<R::DescriptorSet>)
}
fn main() {
let _x = DescriptorSet {slots: Vec::new()};
}
Looks like a bug to me, although I haven't looked too deeply.
In terms of avoiding the issue... associated types have a tendency to trigger obscure issues.
DescriptorSet isn't an irregular type; that refers to types with recursion that doesn't form a cycle.
neon64
3
Thank you for your analysis. I realised I forgot to actually create a DescriptorSet in the playground example so that is why it seemed to 'work'.
I agree that associated types are pretty buggy, however I can't find a way to eliminate them here.
RawBuffer is the only part that needs the to be generic over Resources. It is defined like this:
pub struct RawBuffer<'r, R: Resources<'r>> {
pub data: Arc<R::Buffer>,
}
It seems like I could simplify it to this:
pub struct RawBuffer<'r, B: Buffer<'r>> {
pub data: Arc<B>,
}
However at the moment R::Buffer is not just a simple trait, but actually Buffer<'r, Self> + 'r and thus because of the Self type I need to make it generic over the entire Resources trait.
neon64
5
Thank you for filing the issue. It is good to hear that it's not just my own programming error.
If you like, I could investigate the bug further myself. I've messed around with procedural macros and lint passes a bit and it would be great to understand dropck as well.