Sealed pub traits and strange restrictions on associated types

mod sealed {
    // As expected, making this private will cause T::SealAssoc to not work, even in impl Ans
    pub trait Sealed { type SealAssoc; }
    pub trait Res: Sealed {}
}
use sealed::Res;

pub trait Ans {
    //type Dep;      fn bleh(dep: Self::Dep);
    type Dep: Res; fn bleh(dep: Self::Dep::SealAssoc);
}
impl<T: Res> Ans for T {
    //type Dep = T::SealAssoc; fn bleh(_: Self::Dep) {}
    type Dep = T;            fn bleh(_: Self::Dep::SealAssoc) {}
}

(Playground)

I see that now, one should rather make the sealed traits private to avoid exposing publicly (even if hidden) the sealed trait's associated consts and types (as per Trait with private items - #8 by tczajka).

I find that it is true that I can use the associated type from the sealed trait, but only in some conditions:

  1. If I try to compile the code as it is in the playground, it fails to compile, saying it's impossible to access the associated type.
  2. If I swap the comment on the pub trait Ans and impl Ans, it compiles

Yet, in both cases, we aren't accessing anything different, so what is going on? It appears to fail to compile if the associated type is used in a trait def, but if used in an impl block, it succeeds.

So why is it happening? (regardless of whether this is a good idea to use this in my code, I just stumbled into it, and want to understand why it's happening, while I'll remove the dependency on the sealed trait associated type later on)

it's a quirk in the qualified path syntax and associated item resolution.

in short, the full synax for associated item is <Type as Trait>::Associated, which is usually shortened as Type::Associated or Trait::Associated in generic context if the correct bounds is present.

however, this shorthand cannot be nested.

for this example, you can use the full syntax or one level shorthand:

// this is the full syntax
fn bleh(dep: <<Self as Ans>::Dep as Res>::SealAssoc);

// this uses `Self::Dep` as shorthand for `<Self as Ans>::Dep`
fn bleh(dep: <Self::Dep as Res>::SealAssoc);

both is syntactically correct, but for some reason that I can't explain, the super trait is not considered for the resolution of the associated type, you'll need to spell out the super trait explicitly to make it compile.

the actual compiling code looks like this (playground):

fn bleh(dep: <Self::Dep as sealed::Sealed>::SealAssoc);

This makes a lot of sense. Thank you for the simple explanation.