forked from scala/scala
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tests illustrating need to deconst literal type
(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
1 parent
882972d
commit 41a2fe4
Showing
8 changed files
with
109 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
effect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
effect | ||
effect | ||
effect | ||
oh boy | ||
ohai | ||
oh boy | ||
ohai | ||
boo | ||
effect42 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
object Test { | ||
abstract class Box { | ||
type T | ||
val t: T | ||
def foo: T = { | ||
println("effect") | ||
t | ||
} | ||
def fooEff(): T = { | ||
println("effect") | ||
t | ||
} | ||
|
||
def fooEffPoly[U >: T <: T](): U = { | ||
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 | ||
Box("foo").fooEff() | ||
Box("foo").fooEffPoly() | ||
BoxParam("foo").t | ||
BoxParam("foo").foo | ||
|
||
val x = new C().const | ||
} | ||
} |