Deref is allowed in some particular expression in const context?

The code following is expanded from macro, most from ctor, which can be compiled for V3, but not V4

What confuses me is V3 can be compiled, due to the error message, it shouldn't. I believe same error should be reported too.

pub struct optv(pub &'static dyn Deref<Target = &'static OptVal>);
unsafe impl Sync for optv {}

static V3: flags::optv = ::comn::flags::optv({
    static mut opt___rust_ctor___storage: Option<&'static ::comn::flags::OptVal> = None;
    #[used]
    #[link_section = ".init_array"]
    static opt___rust_ctor___ctor: unsafe extern "C" fn() = {
        #[link_section = ".text.startup"]
        unsafe extern "C" fn initer() {
            opt___rust_ctor___storage = Some({
                static x: ::comn::flags::OptVal = ::comn::flags::OptVal::new();
                init(&x...);
                &x
            });
        }
        initer
    };

    struct opt<T> {
        _data: core::marker::PhantomData<T>,
    }
    impl core::ops::Deref for opt<&'static ::comn::flags::OptVal> {
        type Target = &'static ::comn::flags::OptVal;
        fn deref(&self) -> &'static &'static ::comn::flags::OptVal {
            unsafe { opt___rust_ctor___storage.as_ref().unwrap() }
        }
    }

    static opt: opt<&'static ::comn::flags::OptVal> = opt {
        _data: core::marker::PhantomData::<&'static ::comn::flags::OptVal>,
    };
    &opt
});

static V4: &'static &'static flags::OptVal = {
    static mut opt___rust_ctor___storage: Option<&'static ::comn::flags::OptVal> = None;
    #[link_section = ".init_array"]
    static opt___rust_ctor___ctor: unsafe extern "C" fn() = {
        #[link_section = ".text.startup"]
        unsafe extern "C" fn initer() {
            opt___rust_ctor___storage = Some({
                static x: ::comn::flags::OptVal = ::comn::flags::OptVal::new();
                init(&x...);
                &x
            });
        }
        initer
    };

    struct opt<T> {
        _data: core::marker::PhantomData<T>,
    }
    impl core::ops::Deref for opt<&'static ::comn::flags::OptVal> {
        type Target = &'static ::comn::flags::OptVal;
        fn deref(&self) -> &'static &'static ::comn::flags::OptVal {
            unsafe { opt___rust_ctor___storage.as_ref().unwrap() }
        }
    }

    static opt: opt<&'static ::comn::flags::OptVal> = opt {
        _data: core::marker::PhantomData::<&'static ::comn::flags::OptVal>,
    };
    &opt
};

The error message:

rror[E0277]: the trait bound `V4::opt<&'static OptVal>: Deref` is not satisfied                                                                                                                                                                                         
   --> b.rs:174:5                                                                                                                                                                                                                                                        
    |                                                                                                                                                                                                                                                                    
174 |     &opt                                                                                                                                                                                                                                                           
    |     ^^^^ the trait `~const Deref` is not implemented for `V4::opt<&'static OptVal>`                                                                                                                                                                                
    |                                                                                                                                                                                                                                                                    
note: the trait `Deref` is implemented for `V4::opt<&'static OptVal>`, but that implementation is not `const` 

Can you provide a diff? It's very hard to tell the difference between the two versions, they are so mangled.

The only difference is

static V4: &'static &'static flags::OptVal = { ... }
static V3: flags::optv = ::comn::flags::optv({ ... })

while optv is a wrapper of &&OptVal

pub struct optv(pub &'static dyn Deref<Target = &'static OptVal>);
impl Deref for optv {
    type Target = &'static OptVal;
    fn deref(&self) -> &Self::Target {
        self.0.deref()
    }
}

I see. The V3 version doesn't actually invoke the Deref in the const context (it merely coerces the wrapper to dyn Deref). The V4 version does indeed try to use the effect of Deref in a const context, but the Deref impl is not const.

That question is why V3 is not invoked, anyway, it should be invoked because the result will be stored in static V3, and this happens in compiling time.

In V3, you store &'static opt<&'static OptVal> as &'static dyn Deref - this is only an unsized coercion, not a dereference. In V4, however, you attempt to store the same value as &'static &'static OptVal, i.e. you try to go from opt<T> to T, and that's what requires Deref.

2 Likes

Oh, yes.

&'static dyn Deref<Target = &'static OptVal> matches both &&OptVal and &'static opt<&'static OptVal>

So, v3 compiles because of &'static opt<&'static OptVal>

It is not invoked because you are not trying to reach behind the value; you are not dereferencing anything. You are coercinf a &T to &dyn Deref where T: Deref. Nothing in that coercion needs anything to go through the deref. It's just an unsized coercion.

The trait could as well have been ToString, for example. Then would you expect a coercion into &dyn ToString to automatically invoke the implementation itself? Of course not.