-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid the orphan rule for Rt Deref (splitting the core) #42
Comments
I'm guessing you are using Env as an example, as they are others impls of Rt in level 3, right? I'm thinking about the constraints of the new trait. Would that trait be defined in level 3 (with the defuns) as well? Just to avoid falling into the orphan rule again. |
Yes just using Env as an example. The trait would be defined in the core (level 1). The orphan rule says you can’t implement a foreign trait on a foreign type. So to avoid it one of those needs to be crate local. |
Yes, that looks good. Just to make sure I understood. For any types in all levels to derive Sorry, hard to grasp. |
When we add Now inside core we create a blanket impl of the key thing that makes this work is that |
Makes lots of sense, thanks for clarifying. |
I'm just facing this issue now. There are other examples of foreign traits that are causing us falling into the orphan rule (not quite, but a variation of it). Here's an example: #[derive(Debug, Default)]
#[repr(transparent)]
struct LispStack(Vec<GcObj<'static>>); We define the
We also implement Your solution would solve the Trace derive, but since we implement other foreign traits, this still won't work. I'm thinking that in those cases, we should be the struct to |
Makes the bytecode module work correctly, only missing the Trace derive macro redefinition, tracked here: CeleritasCelery#42 We'll continue the explanation there, and see who picks that up. I can continue on the rune_core refactoring, but we'll need that eventually to move forward.
In the commit that I added above, you can see what I meant with the previous comment. There are some structs that we have the opportunity to move to core and for consistency, we should do so. Since we have |
Regarding the changes on the derive macro. Is that something you'll pick up, or should I, given I'm doing the refactoring either way? Probably that's something we can PR first, and once that's green, we'll continue with the rune-core refactoring. |
Here's the documented trait. I'll make a first go and you can review it here, before PRing, to keep the context in the same issue: /// Trait created to overpass the orphan rule when deriving the
/// [Trace](`rune_macros::Trace`) derive macro. The derive
/// macro contains a blanket deref like this:
///
/// ```ignore
/// unsafe { &*(rt as *const Rt<Self>).cast::<Self::Target>() }
/// ```
///
/// By creating a trait that the functions defined in the main crate
/// can define, we avoid the orphan rule by implementing `Deref`
/// on the rooted version of the types: [Rt<T>](`self::Rt`).
pub trait RootedDeref {
type Target;
fn rooted_deref(rooted: &Rt<Self>) -> &Self::Target;
} |
This is a key and PRable part of the effort of refactoring the core out of the main crate to an auxiliar crate, imported by all the other levels: rune_core. To avoid the orphan rule (See RFC 1023 - rebalancing coherence) we can't implement foreign traits for foreign types. A plain example is us implementing `Deref` and `DerefMut` for the "future" foreign type `Rt`. As `Rt` (with the core refactor) would now be foreign, we fall into the orphan rule. We overcome that limitation by introducing a trait that would act as the foreign trait, but the key difference is that we are now implementing it on the actual type `T`, not the rooted type `Rt<T>`, as part of the `Trace` macro. When types now derive the `Trace` macro, we implement `RootedDeref` and whenever the rooted types need to access `deref` or `deref_mut`, they are able to do so, as we also implement blanket implementations below it, for all rooted types `Rt<T>`. All of this and more discussions are part of this issue: CeleritasCelery#42
This is a key and PRable part of the effort of refactoring the core out of the main crate to an auxiliar crate, imported by all the other levels: rune_core. To avoid the orphan rule (See RFC 1023 - rebalancing coherence) we can't implement foreign traits for foreign types. A plain example is us implementing `Deref` and `DerefMut` for the "future" foreign type `Rt`. As `Rt` (with the core refactor) would now be foreign, we fall into the orphan rule. We overcome that limitation by introducing a trait that would act as the foreign trait, but the key difference is that we are now implementing it on the actual type `T`, not the rooted type `Rt<T>`, as part of the `Trace` macro. When types now derive the `Trace` macro, we implement `RootedDeref` and whenever the rooted types need to access `deref` or `deref_mut`, they are able to do so, as we also implement blanket implementations below it, for all rooted types `Rt<T>`. All of this and more discussions are part of this issue: CeleritasCelery#42
This is a key and PRable part of the effort of refactoring the core out of the main crate to an auxiliar crate, imported by all the other levels: rune_core. To avoid the orphan rule (See RFC 1023 - rebalancing coherence) we can't implement foreign traits for foreign types. A plain example is us implementing `Deref` and `DerefMut` for the "future" foreign type `Rt`. As `Rt` (with the core refactor) would now be foreign, we fall into the orphan rule. We overcome that limitation by introducing a trait that would act as the foreign trait, but the key difference is that we are now implementing it on the actual type `T`, not the rooted type `Rt<T>`, as part of the `Trace` macro. When types now derive the `Trace` macro, we implement `RootedDeref` and whenever the rooted types need to access `deref` or `deref_mut`, they are able to do so, as we also implement blanket implementations below it, for all rooted types `Rt<T>`. All of this and more discussions are part of this issue: #42
As far as
|
I tried the new type pattern for A few thoughts: First is that I think we should consider splitting the Given that I think we could avoid the problem of implementing functions on |
Really liked that you suggested different options and tried them out, thanks! I was thinking about this. Regarding the Regarding the #[automatically_derived]
#[allow(non_camel_case_types)]
#vis struct #rooted_name #orig_generics #new_fields I'm thinking a proc macro called I'm currently on the core refactoring, and I have already compiled |
|
I think we might be able to work around this by introducing a new trait. Right now the generated Deref for Env would look like this.
We are always just doing a transmute (via pointer cast) to get the
Rooted
type. If we defined another trait like this:Then we could define a blanket
Deref
impl like this:Then in the proc macro we could define an impl like this:
That would avoid the orphan rule because we are not using a foreign type anymore. That would let us keep Rt in the core but still
#[derive(Trace)]
outside of the core.The text was updated successfully, but these errors were encountered: