Skip to content

Specializing Option<T> for bool with associated types is not expressible (even on nightly) #150087

@ImadRedwan

Description

@ImadRedwan

I am trying to implement a trait for Option<T> with a special case for Option<bool>.
It is about a trait for converting object to intermediate form for using in FFI.

The trait definition is like this:

trait IntoInterm {
    type IntermT: Default + Debug + ?Sized;
    fn into_interm(self) -> Result<Self::IntermT, Error>;
}

Desired behavior:

  • For Option<T> (general case):

    Option<T> -> IntermediateOption
  • For Option<bool> (special case):

    Option<bool> -> IntermediateOptionBool

This is required for FFI reasons (ABI/layout differences).

Object definitions:

#[repr(C)]
#[derive(Debug, Default)]
pub struct IntermOption {
    pub value:     *mut c_void,
    pub item_type: IntermType
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct IntermOptionBool {
    pub kind:  OptionKind, // Some | None,
    pub value: bool
}

The reason for such a definition is to achieve generality.


Attempt 1: Stable Rust (expectedly impossible)

On stable Rust, this is not possible due to the lack of:

  • specialization
  • negative bounds (T != bool)
  • conditional type constraints
  • difference of return types

This part is understood and expected.


Attempt 2: Nightly specialization (fails)

Code

#![feature(specialization)]

impl<T> IntoInterm for Option<T>
where
    T: IntoInterm,
{
    default type IntermT = IntermediateOption<T::IntermT>;

    default fn into_interm(self) -> Self::IntermT {
        // implementations
        Ok(IntermOption { /* ... */ }) // or even Ok(Self::IntermT { /* ... */ })
    }
}

impl IntoInterm for Option<bool> {
    type IntermT = IntermediateOptionBool;

    fn into_interm(self) -> Self::IntermT {
        if let Some(val) = self {
            Ok(IntermOptionBool { kind: SOME, value: val })
        }
        else {
            Ok(IntermOptionBool { kind: NONE, value: false })
        }
    }
}

Error

error[E0308]: mismatched types
default type IntermT = IntermOption;
------------------------------------ associated type is `default` and may be overridden
Ok(IntermOption { /* ... */ })
   ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found `IntermOption`

Attempt 3: Indirection via helper traits (also fails)

A natural workaround is to defer construction via another trait, e.g.:

trait OptionCtor<V> {
    fn some(v: V) -> Self;
    fn none() -> Self;
}

and then require:

where Self::IntermT: OptionCtor<T::IntermT>

However, this is not allowed, constraints on Self::IntermT inside a specializing impl are rejected. So this approach is also invalid.

What's the solution?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-specializationArea: Trait impl specializationC-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions