2

I'm getting the following 2.13.0-M3 compiler error: type Trees$Literal is not a member of package scala.reflect.internal

This compiled fine under 2.11 and 2.12. In 2.13.0-M3 I get the error in the title. Did this change? An example full line of code that broke is this:

// Extract MapName annotation if present
val optionalMapName = member.annotations.find(_.tree.tpe =:= typeOf[MapName])
.map { index =>
  index.tree.children(1).productElement(1)
   .asInstanceOf[scala.reflect.internal.Trees$Literal].value().value
 }.asInstanceOf[Option[String]]
Greg
  • 10,696
  • 22
  • 68
  • 98
  • Not as far as I [can see](https://github.com/scala/scala/blob/v2.13.0-M3/src/reflect/scala/reflect/internal/Trees.scala#L817). What does `scala.reflect.internal.Trees#Literal` say? – Jasper-M Feb 12 '18 at 20:25
  • Sorry... not clear what you mean by what does it say. The error I got was just like the first sentence. Couldn't find it in the package. Like you, I don't see any obvious change, and no code was changed (I'm cross-compiling, actually), but this blew up in 2.13. – Greg Feb 12 '18 at 20:30
  • I mean does it work if you use `scala.reflect.internal.Trees#Literal`? `Trees$Literal` is sort of an implementation detail. – Jasper-M Feb 12 '18 at 20:33
  • Ah, got it. Well, I get a different error if I use Trees#Literal: scala.reflect.internal.Trees#Constant does not take parameters (the error appears under the ".value()" in the sample above. – Greg Feb 12 '18 at 20:37
  • `value` is probably a `val` or a `def` without parameter list – Jasper-M Feb 12 '18 at 20:46
  • also asked at https://users.scala-lang.org/t/2-13-0-m3-error-type-trees-literal-is-not-a-member-of-package-scala-reflect-internal/2331 – Seth Tisue Feb 17 '18 at 18:59

1 Answers1

2

I don't know why this worked before and not anymore in 2.13.0-M3, but Trees$Literal is sort of an implementation detail. It's how names of inner classes are encoded by the compiler. An actual Scala type with which you can refer to that class is the type projection Trees#Literal.

So what will probably work is

const.asInstanceOf[scala.reflect.internal.Trees#Literal].value.value

I'm guessing value() in your code used to work because the compiler didn't recognize Trees$Literal as a Scala type anymore, and in Java all methods have a parameter list. A Scala def foo compiles to a method with a parameter list, but the compiler can see in the Scala-specific metadata if it's a method without parameter list or not. A (non local) val compiles to a field and a method.

By the way, interesting as this may be, I don't think you actually need to cast to the internal API for this. You can simply pattern match to get the value out of the literal constant. With Literal and Constant imported from scala.reflect.runtime.universe or c.universe (c being a macro context):

val Literal(Constant(value: String)) = const

or

const match {
  case Literal(Constant(value: String)) => value
}
Jasper-M
  • 14,966
  • 2
  • 26
  • 37
  • I would still be interested to see what changed in 2.13.0-M3 that causes these hidden types to remain hidden. And whether or not that was intentional. – Jasper-M Feb 13 '18 at 09:50