Leaking traits or types from private modules

And are there any implications in leaking a private an inaccessible type?

Considering the warning I got, I have to agree.

I don't think this is identical to the "sealed trait pattern". This is because the trait HasState isn't visible from outside the module module, and the trait FooTrait isn't sealed. Compare to the example in the API guidelines, where TheTrait is public:

/// This trait is sealed and cannot be implemented for types outside this crate.
pub trait TheTrait: private::Sealed {
    // Zero or more methods that the user is allowed to call.
    fn ...();

    // Zero or more private methods, not allowed for user to call.
    #[doc(hidden)]
    fn ...();
}

// Implement for some types.
impl TheTrait for usize {
    /* ... */
}

mod private {
    pub trait Sealed {}

    // Implement for those same types, but no others.
    impl Sealed for usize {}
}

Instead, in my Case 1, mentioning HasState happens here:

    /// Anything that has a state (i.e. implements internal::HasState)
    /// will automatically get an implementation of FooTrait
    impl<T: internal::HasState> FooTrait for T {
        fn foo(&self) {
            self.state().hello_world();
        }
    }

Thus I see a difference between those "patterns".

That said, the pattern in Case 1 utilizes the same odd behavior that the sealed trait pattern is exploiting: Inside a module, I can, within a public item, refer to a trait X that is non-visible from outside the module by making X public but placing it in a private submodule.

The Rust documentation guarantees that X will not be visible. See section 12.6 (Visibility and Privacy):

With the notion of an item being either public or private, Rust allows item accesses in two cases:

  1. If an item is public, then it can be accessed externally from some module m if you can access all the item's ancestor modules from m. You can also potentially be able to name the item through re-exports. See below.
  2. If an item is private, it may be accessed by the current module and its descendants.

Thus it's clear that HasState isn't "accessible". But I still get a guarantee that the

impl<T: internal::HasState> FooTrait for T

is "accessible" from the outside? I don't see a clear answer for that in the reference. Maybe there is one. If so, can you help me find it?

Even if in case of sealed traits, the behavior will be stable (I didn't find any guarantee on that either in the reference), the behavior in case of using such a non-visible trait in impls might be a different case.

Following the other threads linked above, I came to the conclusion that the "sealed trait pattern" (and thus relying on the current behavior) seems to be common. However, I also found a voice which described this as possible "bug":

That's a lot of links to follow, and I have to admit, I didn't read all of that. The last one, however, indeed seems to be official(ish?) because its source is located under https://github.com/rust-lang/api-guidelines. However, the API guidelines reflect best practices and aren't a reference, right?

Besides, my case doesn't seem to be identical to the sealed trait pattern, as explained above.