Skip to content

Commit

Permalink
Fix Typeable for inner classes
Browse files Browse the repository at this point in the history
Fixes #748
  • Loading branch information
joroKr21 committed Dec 24, 2019
1 parent 8ce40d1 commit fe4bbe0
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
13 changes: 12 additions & 1 deletion core/src/main/scala/shapeless/typeable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable {
def describe = name
}

/** Typeable instance defined by a partial function and given an explicit name */
def partialFunctionTypeable[T](pf: PartialFunction[Any, T], name: => String): Typeable[T] =
new Typeable[T] {
val caster = pf.lift
def cast(t: Any) = caster(t)
def describe = name
}

/** Typeable instance for singleton value types */
def valueSingletonTypeable[T](value: T, name: String): Typeable[T] =
new Typeable[T] {
Expand Down Expand Up @@ -454,8 +462,11 @@ class TypeableMacros(val c: blackbox.Context) extends SingletonTypeUtils {
} else {
c.abort(c.enclosingPosition, s"No default Typeable for type $tpe capturing an outer type variable")
}
} else if (tsym.isStatic || tsym.isFinal || (tsym.isClass && tsym.asClass.isTrait)) {
// scala/bug#4440 Final inner classes and traits have no outer accessor.
q"_root_.shapeless.Typeable.namedSimpleTypeable(classOf[$tpe], ${nameOf(tsym)})"
} else {
q"""_root_.shapeless.Typeable.namedSimpleTypeable(_root_.scala.Predef.classOf[$tpe], ${nameOf(tsym)})"""
q"_root_.shapeless.Typeable.partialFunctionTypeable({ case x: $tpe => x }, ${nameOf(tsym)})"
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions core/src/test/scala/shapeless/typeable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class TypeableTests {
import syntax.typeable._
import test._

class Outer {
class Inner
val inner = new Inner
}

@Test
def testPrimitives: Unit = {
val b: Any = 23.toByte
Expand Down Expand Up @@ -684,4 +689,12 @@ class TypeableTests {
assertEquals("|+|.type", Typeable[|+|.type].describe)
assertEquals("Symbol('witness)", Typeable[witness.T].describe)
}

@Test
def testInnerClasses(): Unit = {
val outer1 = new Outer
val outer2 = new Outer
assertEquals(None, outer1.inner.cast[outer2.Inner])
assertEquals(Some(outer1.inner), outer1.inner.cast[outer1.Inner])
}
}

0 comments on commit fe4bbe0

Please sign in to comment.