This is not going to be a full blown answer (and contains a high dose of speculation), but given that you got none until now I imagine that it's better than nothing.
It seems that the problem lies with the fact that the compiler treats X
in new Foo with X
as a path-dependant type, even though we are in an object definition rather than a class.
Because of this, the compiler then infers A = (Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }
in the second call to bar
.
This requires the compiler to find an implicit value of type TC[(Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }]
, and apparently tc2
is no fit (I am not intimate enough with the corner cases fo the scala type system to know for sure if there is a genuine incompatibility, or if the compiler just has no clue)
[speculation mode]
The problem with the path-dependent type handling smells like a bug to me (or at least an underspecified oddity). I think that the culprit is that the body of an object is compiled no different from a class, and then is somehow made into a singleton object, which means that new Foo with X
is really seen as new Foo with this.X
instead of new Foo with Bar.X
, and thus treated as a path dependent type (even though they should IMHO denote the very same thing in this case).
[/speculation mode]
And now for the weird part (which is also the work around that you requested): turning this:
val c = new Foo with X
into this:
val c = new Foo with Bar.X
actually fixes the compilation. As I understand it, this is because by explicitly specifying Bar
we force the compiler to recognize that Bar.X
is a stable path, which clears the problem with path dependent types.
Now, the real work around is of course to really move X
outside Bar
as you suggested. It works and is painless, so why not do it?