I would expect this to be impossible. Consider (assuming class Foo extends Elem
)
val obj1 = new Obj {
type E = Elem
def elem = new Foo
}
Since obj.elem
does match f: Foo
, but obj1
doesn't actually have type Obj { type E = Foo }
, you do have to cast. This cast is actually safe in this case, but only because Actually, it isn't safe, since the value of the first call to Obj
doesn't have e.g. any methods taking E
.elem
having class Foo
doesn't mean all calls to elem
will return Foo
.
EDIT: if you are all right with merely hiding the cast in the extractor, you may be able to do something like this:
case class IsElem[T <: Elem]()(implicit ct: ClassTag[T]) {
def unapply(obj: Obj): Option[Obj { type E = T }] =
if (ct.runtimeClass.isInstance(obj.elem)) Some(obj.asInstanceOf[Obj { type E = T }])
else None
}
val IsFoo = IsElem[Foo]
val IsBar = IsElem[Bar]
...
EDIT2: with type parameters, you can do
(obj, obj.elem) match {
case (obj: Obj[Foo] @unchecked, f: Foo) => ...
case (obj: Obj[Bar] @unchecked, f: Bar) => ...
}
Obviously, this doesn't help safety issues.