[Pre-RFC] Destructuring values that impl Drop

I have a major use case for destructuring Drop types that is not met by this match #[avoid_drop] proposal. In serde_json we have:

pub enum Value {
    Null,
    Bool(bool),
    Number(Number),
    String(String),
    Array(Vec<Value>),
    Object(Map<String, Value>),
}

If someone creates a deeply nested Value, its compiler-generated Drop will overflow the stack—serde-rs/json#440.

The correct fix would be to implement Drop for Value in a way that uses a loop and heap-allocated stack to drop the whole thing without recursion. I have code for this. The problem is:

  • We cannot implement Drop for Value because it breaks the ability to destructure Value, which is an extremely common and important use case that needs to be supported;

  • We cannot implement Drop for Vec<Value> because it overlaps Vec<T>'s impl;

  • We cannot implement Drop for serde_json::Map<String, Value> because implementations of Drop cannot apply to a specialized choice of type parameters;

  • We cannot implement Drop for serde_json::Map<K, V> because that requires a recursive call to V’s drop so wouldn’t solve the problem.

I believe the stack overflows are not possible to fix today nor with this proposal. Instead of (or in addition to) the match #[avoid_drop] in this proposal I would need some attribute on Value or on its Drop impl that says the type is fine to destructure despite having a Drop impl.

5 Likes