-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Typer crash related to literal singleton types #10768
Comments
Hmm, looks like this is the same bug as #10358, but now it can be triggered without using an external library. |
closed that one, let's consolidate here |
This turns out not to be REPL only ... it's an artefact of the fact that the REPL object Test {
type Id[T] = T
def foo(x: Int): Id[x.type] = x
lazy val result = foo(1)
} This is due to the inferred This fix is to deconst more thoroughly earlier. PR incoming ... |
Prior to this commit deconst only converted a top level FoldableConstantType to a LiteralType. This left FoldableConstantTypes possibly embedded somewhere in a TypeRef or suchlike where it might reemerge unexpectedly at a later point. This could result in result bogus inlining and the elimination of expected side-effects. For instance, no output is produced when the following is run, 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. The fix is for deconst to recurse through the type eliminating all FoldableConstantType components. This fixes scala/bug#10788 and almost incidentally fixes scala/bug#10768. In, 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 fix also changes the output of 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.
Fixed in scala/scala#6452. |
Incidentally, this isn't a regression ... it's present at least as far back as 2.10.x, although prior to literal types you have to use miles@tarski:~% scala
Welcome to Scala 2.12.4-20171023-143547-unknown (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_162).
Type in expressions for evaluation. Or try :help.
scala> type Id[T] = T
defined type alias Id
scala> def foo(x: String): Id[x.type] = x
foo: (x: String)Id[x.type]
scala> foo("bar")
scala.reflect.internal.Types$TypeError: assignment to non variable
at scala.tools.nsc.typechecker.Contexts$ThrowingReporter.handleError(Contexts.scala:1426)
at scala.tools.nsc.typechecker.Contexts$ContextReporter.issue(Contexts.scala:1278)
... |
Prior to this commit deconst only converted a top level FoldableConstantType to a LiteralType. This left FoldableConstantTypes possibly embedded somewhere in a TypeRef or suchlike where it might reemerge unexpectedly at a later point. This could result in result bogus inlining and the elimination of expected side-effects. For instance, no output is produced when the following is run, 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. The fix is for deconst to recurse through the type eliminating all FoldableConstantType components. This fixes scala/bug#10788 and almost incidentally fixes scala/bug#10768. In, 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 fix also changes the output of 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.
constant folding time is over (that happens before, during typers), but constant types have not yet been eliminated (that happens during erasure). So, we must deconst the result type of methods to avoid treating their application as a constant... Fix scala/bug#10768
(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.
constant folding time is over (that happens before, during typers), but constant types have not yet been eliminated (that happens during erasure). So, we must deconst the result type of methods to avoid treating their application as a constant... Fix scala/bug#10768
(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.
(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.
I haven't been able to reproduce this outside of the REPL, I assume this is related to literal singleton types since
val a = 1; foo(a)
does not trigger the crash:The text was updated successfully, but these errors were encountered: