The question is not only can you do it, but should you do it. You’re taking statically computed data and basically forcing it to be accessed through dynamic dispatch.
Firstly, this handcuffs your users. If the data really is state-dependent, then why shouldn’t they be allowed to express that? Why not tell your users how the data will be used and let them provide impls to their own advantage?
Secondly, it is “weak security”, because accessing an object through a trait object confines you to an interface anyway. If Event::cancellable(&opaque self) can’t depend on object state, the second you call Event::cancel(&mut self), the user is free to look at object state anyway. So why bother? Users control their object state, they can make anything they want depend on it.
Thirdly, this is an anti-pattern. If the data is statically determinable, you should encode it in static structures so that it can be determined at compile time:
#![feature(specialization)]
pub trait Event {}
pub trait CancellableEvent {}
trait MaybeCancellableEvent { default fn is_cancellable(&self) -> bool { false }}
impl<T: Event> MaybeCancellableEvent for T {}
impl<T: Event + CancellableEvent> MaybeCancellableEvent for T { fn is_cancellable(&self) -> bool { true} }
Here, you already established that the result of the method call can’t depend on object state because you don’t even need an object to get the result. But if you have a dyn MaybeCancellableEvent, you can do exactly what you want. Without forcing your users to implement any weird methods at all.
Lastly, this is extremely niche. It still doesn’t solve any other problems with object safety, so you can’t do things like return Self or use generics.