Cannot compile enum conversion in const fn

A simple example convert an enum to another enum

enum MyOption<T> {
    Some(T),
    None
}

const fn convert<T>(option: Option<T>) -> MyOption<T> {
    match option {
        Some(t) => MyOption::Some(t),
        None => MyOption::None,
    }
}

But rustc says the input argument will drop at the end of the function, thus cannot run the destructor, so this function cannot be a constant function.

error[E0493]: destructor of `Option<T>` cannot be evaluated at compile-time
  --> src/lib.rs:6:21
   |
6  | const fn convert<T>(option: Option<T>) -> MyOption<T> {
   |                     ^^^^^^ the destructor for this type cannot be evaluated in constant functions
...
11 | }
   | - value is dropped here

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

Is there anybody who knows why the value dropped at the end of the function? :thinking:
This error doesn't block my work as I don't actually need it to be a const fn, but I wonder why. Thanks.

There is an unstable feature that makes this work:

Apart from that, I can't provide any more insight.

Got it, thanks.
I found another interesting method to achieve this.

enum MyOption<T> {
    Some(T),
    None,
}

#[allow(dead_code)]
const fn convert<T>(mut option: Option<T>) -> MyOption<T> {
    let converted = if option.is_some() {
        // what does `take` and `unwrap` do?
        MyOption::Some(option.take().unwrap())
    } else {
        MyOption::None
    };
    
    // `option` now is sure to be empty
    std::mem::forget(option);
    converted
}

But it works by using take().unwrap() which is a const operation, whose inner uses a special feature.

You don’t need to make use of take(), just unwrap():

const fn convert<T>(option: Option<T>) -> MyOption<T> {
    if option.is_some() {
        MyOption::Some(option.unwrap())
    } else {
        // We know the option is None, so this leaks nothing.
        std::mem::forget(option);
        MyOption::None
    }
}

You could also write it in match form which I think might bring some clarity:

const fn convert<T>(option: Option<T>) -> MyOption<T> {
    match option {
        Some(_) => MyOption::Some(option.unwrap()),
        None => {
            // We know the option is None, so this leaks nothing.
            std::mem::forget(option);
            MyOption::None
        }
    }
}

The fundamental reason this works where a plain match doesn’t is that Option::unwrap() is allowed to use feature(const_precise_live_drops) internally. If that weren’t true, there would be no solution to the problem, because there would be no way to stop having the Option at all.