First, Nico's Handle blog post suggested the Handle trait should signify whether or not a clone aliases the same data, especially for types with interior mutability, but then his Handle trait wound up being save.
I'd have expected that both Handle and !Handle would enable some unsafe compiler optimisations, so maybe this trait:
unsafe trait HandleIsKnown : Deref + Clone {
const is_handle: bool;
final fn handle(&self) -> Self
where Self::is_handle == true
{ self.clone() }
}
It’d always be unsafe to say if a type is a handle or not a handle, but either way enables some optimisations for what it dereferences to, and miss-use gives segfaults. If a handle, then you get the handle method, which avoids Arc::clone.
Second, there is a mildly serious risk that Handle gets miss-used as merely “ergonomic clone”, which seemingly precludes its usage for aliasing information.
Around this, we already have serious logic bugs arise when passing around Iterator<Item = &mut T> with T: Copy lots, because existing ergonomics tricks often some local T to be mutated and discarded, instead of the &mut T, so more implicit behavior here sounds pretty fraught.
I’d suggest that “clone ergonomics” should be a completely orthogonal topic, unrelated to aliasing and some Handle trait, if only to prevent abuse.
As a "sane default proposal", each & every source file could declare the non-copy types it wishes to be auto clone, and declare the copy types it wants to not be auto clone:
#![implicit_clone(Rc,Arc<Foo>,GuiPtr,GamePtr)]
#[no_implicit_copy(&[u64, N], N>1)] // prevent local copy bugs
fn foo(.. x: impl Iterator<Item = &mut [u64, 2]>, ..) { ..
There could be a lint against #[implicit_clone(T)] with T: Clone + !Handle, but importantly you could turn this lint off if you want implicit cloning some some !Handle type. Allowing the automation of regular clones would hopefully prevents the incorrect proliferation of impl Handle on non-pointer types for purely ergonomic concerns.
Implicit clones would never occur for fully generic types T: ..traits.., maybe even T: Copy could stop being implicit clone eventually. Implicit clones do occur when wrapped inside some pointer type though, so like Rc<T> types. It's likely that folks who want implicit clones want them only in clone heavy buisness logic, but do not want them in really performance sensitive code, like custom executors.