So currently recursive type aliases are not supposed to be legal in Scala.
There are various workarounds. For examples I’ve seen people use match types to do it:
type NestedSet1[A] = A match
case Nothing => Nothing // used to turn of the cycle detector...
case String => Set[NestedSet1[A]]
type S = NestedSet1[String]
// expected:
val s0: S = Set() ; s0
val s1: S = Set(Set()) ; s1
val s2: S = Set(s0, s1) ; s2
// unexpected:
// val sAny: S = (Set("hello"): Set[Any]) ; sAny // now an error
val unsound: S = s1.head // works
One can also probably tie such indirect recursive knots through intersection types/refinements.
This looks like a bug. I don’t see why Scala 3 accepts the first recursive type alias definition. And it also accepts a type alias with wildcard type argument, which it shouldn’t.
This looks like a couple of other bugs!
- I think it shouldn’t let you upcast a
Set[Any]
into anS
; - It should probably let you type
s1.head
as anS
. In any case there should be noSet[Any]
in there. Looks like an avoidance/wildcard bug (cc @smarter).