Skip to content

Commit

Permalink
Tests illustrating need to deconst literal type
Browse files Browse the repository at this point in the history
(Commit message slightly reworded by adriaanm. While preserving Miles's
analysis & tests, my fix ended up differently.)

Without proper deconsting, no output is produced by:

  class Box[T](t: T) {
    def foo: T = {
      println("effect")
      t
    }
  }

  object Box {
    def apply(x: String): Box[x.type] = new Box[x.type](x)
  }

  val bar = Box("foo").foo

The cause of the problem is that the Box value is created with its type
parameter T instantiated as x.type which is computed as the
ConstantType(Literal("foo")). This results in the subsequent application
of foo also being seen as having a constant type and so being eligible
to be inlined as the constant value, eliding the object creation, method
call and effect. So the definition of bar,

  val bar = Box("foo").foo

was transformed to,

  val bar: String = "foo";

Note that although the earlier mention of LiteralType suggests that this
is related to the literal types extension, this problem is present in
compiler versions going back to 2.10.x at least.

Another occurrence of this bug is seen in scala/bug#10768:

  object Test {
    type Id[T] = T
    def foo(x: Int): Id[x.type] = x

    lazy val result = foo(1)
  }

the inferred FoldableConstantType for T is hidden in the Id type
constructor and so is not deconsted. It then reemerges during Uncurry
where Id[Int(1)] is dealiased to Int(1). Subsequently during Fields this
constant type interferes with synthesis of the various fields and
accessors associated with the lazy val.

This also affects run/macro-reify-unreify. I've been
able to convince myself that the previous output was incorrect due to
the typer seeing Expr[String("world")](...).splice as having the
constant type String("world") and hence inlining the literal String
without invoking any of the splicing machinery, ie. it's an actual
instance of the issue this commit fixes.
  • Loading branch information
milessabin authored and adriaanm committed Jan 9, 2019
1 parent 9e7cca2 commit 97edc8c
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 1 deletion.
6 changes: 6 additions & 0 deletions test/files/pos/t10768.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object Test {
type Id[T] = T
def foo(x: Int): Id[x.type] = x

lazy val result = foo(1)
}
2 changes: 1 addition & 1 deletion test/files/run/macro-reify-unreify.check
Original file line number Diff line number Diff line change
@@ -1 +1 @@
hello world = Expr[String("hello world")]("hello world")
hello world = Expr[String("hello world")]("hello ".$plus("world"))
11 changes: 11 additions & 0 deletions test/files/run/t10768.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

scala> type Id[T] = T
defined type alias Id

scala> def foo(x: Int): Id[x.type] = x
foo: (x: Int)Id[x.type]

scala> foo(1)
res0: Id[Int(1)] = 1

scala> :quit
10 changes: 10 additions & 0 deletions test/files/run/t10768.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import scala.tools.nsc.interpreter._
import scala.tools.partest.ReplTest

object Test extends ReplTest {
def code = """
|type Id[T] = T
|def foo(x: Int): Id[x.type] = x
|foo(1)
|""".stripMargin
}
1 change: 1 addition & 0 deletions test/files/run/t10788.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
effect
16 changes: 16 additions & 0 deletions test/files/run/t10788.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
object Test {
class Box[T](t: T) {
def foo: T = {
println("effect")
t
}
}

object Box {
def apply(x: String): Box[x.type] = new Box[x.type](x)
}

def main(args: Array[String]): Unit = {
val bar = Box("foo").foo
}
}
7 changes: 7 additions & 0 deletions test/files/run/t10788b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
effect
oh boy
ohai
oh boy
ohai
boo
effect42
43 changes: 43 additions & 0 deletions test/files/run/t10788b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
object Test {
abstract class Box {
type T
val t: T
def foo: T = {
println("effect")
t
}
}

object Box {
def apply(x: String): Box { type T = x.type } = new Box {
type T = x.type
val t = x
}
}

class BoxParam[T](val t: T) {
println("ohai")
def foo: T = {
println("boo")
t
}
}

object BoxParam {
def apply(x: String): BoxParam[x.type] = { println("oh boy"); new BoxParam[x.type](x) }
}


class C {
println("effect42")
final val const = 42
}

def main(args: Array[String]): Unit = {
val bar = Box("foo").foo
BoxParam("foo").t
BoxParam("foo").foo

val x = new C().const
}
}

0 comments on commit 97edc8c

Please sign in to comment.