-
Notifications
You must be signed in to change notification settings - Fork 939
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
lazy val
won't compile within task definitions
#952
Comments
harrah
added a commit
that referenced
this issue
Nov 22, 2013
The fix was made possible by the very helpful information provided by @retronym. This commit does two key things: 1. changes the owner when splicing original trees into new trees 2. ensures the synthetic trees that get spliced into original trees do not need typechecking Given this original source (from Defaults.scala): ... lazy val sourceConfigPaths = Seq( ... unmanagedSourceDirectories := Seq(scalaSource.value, javaSource.value), ... ) ... After expansion of .value, this looks something like: unmanagedSourceDirectories := Seq( InputWrapper.wrapInit[File](scalaSource), InputWrapper.wrapInit[File](javaSource) ) where wrapInit is something like: def wrapInit[T](a: Any): T After expansion of := we have (approximately): unmanagedSourceDirectories <<= Instance.app( (scalaSource, javaSource) ) { $p1: (File, File) => val $q4: File = $p1._1 val $q3: File = $p1._2 Seq($q3, $q4) } So, a) `scalaSource` and `javaSource` are user trees that are spliced into a tuple constructor after being temporarily held in `InputWrapper.wrapInit` b) the constructed tuple `(scalaSource, javaSource)` is passed as an argument to another method call (without going through a val or anything) and shouldn't need owner changing c) the synthetic vals $q3 and $q4 need their owner properly set to the anonymous function d) the references (Idents) $q3 and $q4 are spliced into the user tree `Seq(..., ...)` and their symbols need to be the Symbol for the referenced vals e) generally, treeCopy needs to be used when substituting Trees in order to preserve attributes, like Types and Positions changeOwner is called on the body `Seq($q3, $q4)` with the original owner sourceConfigPaths to be changed to the new anonymous function. In this example, no owners are actually changed, but when the body contains vals or anonymous functions, they will. An example of the compiler crash seen when the symbol of the references is not that of the vals: symbol value $q3 does not exist in sbt.Defaults.sourceConfigPaths$lzycompute at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) at scala.tools.nsc.Global.abort(Global.scala:254) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIdent$1(GenICode.scala:1038) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:1044) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1246) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1244) ... Other problems with the synthetic tree when it is spliced under the original tree often result in type mismatches or some other compiler error that doesn't result in a crash. If the owner is not changed correctly on the original tree that gets spliced under a synthetic tree, one way it can crash the compiler is: java.lang.IllegalArgumentException: Could not find proxy for val $q23: java.io.File in List(value $q23, method apply, anonymous class $anonfun$globalCore$5, value globalCore, object Defaults, package sbt, package <root>) (currentOwner= value dir ) ... while compiling: /home/mark/code/sbt/main/src/main/scala/sbt/Defaults.scala during phase: global=lambdalift, atPhase=constructors ... last tree to typer: term $outer symbol: value $outer (flags: <synthetic> <paramaccessor> <triedcooking> private[this]) symbol definition: private[this] val $outer: sbt.BuildCommon tpe: <notype> symbol owners: value $outer -> anonymous class $anonfun$87 -> value x$298 -> method derive -> class BuildCommon$class -> package sbt context owners: value dir -> value globalCore -> object Defaults -> package sbt ... The problem here is the difference between context owners and the proxy search chain.
harrah
added a commit
that referenced
this issue
Mar 21, 2014
The fix was made possible by the very helpful information provided by @retronym. This commit does two key things: 1. changes the owner when splicing original trees into new trees 2. ensures the synthetic trees that get spliced into original trees do not need typechecking Given this original source (from Defaults.scala): ... lazy val sourceConfigPaths = Seq( ... unmanagedSourceDirectories := Seq(scalaSource.value, javaSource.value), ... ) ... After expansion of .value, this looks something like: unmanagedSourceDirectories := Seq( InputWrapper.wrapInit[File](scalaSource), InputWrapper.wrapInit[File](javaSource) ) where wrapInit is something like: def wrapInit[T](a: Any): T After expansion of := we have (approximately): unmanagedSourceDirectories <<= Instance.app( (scalaSource, javaSource) ) { $p1: (File, File) => val $q4: File = $p1._1 val $q3: File = $p1._2 Seq($q3, $q4) } So, a) `scalaSource` and `javaSource` are user trees that are spliced into a tuple constructor after being temporarily held in `InputWrapper.wrapInit` b) the constructed tuple `(scalaSource, javaSource)` is passed as an argument to another method call (without going through a val or anything) and shouldn't need owner changing c) the synthetic vals $q3 and $q4 need their owner properly set to the anonymous function d) the references (Idents) $q3 and $q4 are spliced into the user tree `Seq(..., ...)` and their symbols need to be the Symbol for the referenced vals e) generally, treeCopy needs to be used when substituting Trees in order to preserve attributes, like Types and Positions changeOwner is called on the body `Seq($q3, $q4)` with the original owner sourceConfigPaths to be changed to the new anonymous function. In this example, no owners are actually changed, but when the body contains vals or anonymous functions, they will. An example of the compiler crash seen when the symbol of the references is not that of the vals: symbol value $q3 does not exist in sbt.Defaults.sourceConfigPaths$lzycompute at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) at scala.tools.nsc.Global.abort(Global.scala:254) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIdent$1(GenICode.scala:1038) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:1044) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1246) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1244) ... Other problems with the synthetic tree when it is spliced under the original tree often result in type mismatches or some other compiler error that doesn't result in a crash. If the owner is not changed correctly on the original tree that gets spliced under a synthetic tree, one way it can crash the compiler is: java.lang.IllegalArgumentException: Could not find proxy for val $q23: java.io.File in List(value $q23, method apply, anonymous class $anonfun$globalCore$5, value globalCore, object Defaults, package sbt, package <root>) (currentOwner= value dir ) ... while compiling: /home/mark/code/sbt/main/src/main/scala/sbt/Defaults.scala during phase: global=lambdalift, atPhase=constructors ... last tree to typer: term $outer symbol: value $outer (flags: <synthetic> <paramaccessor> <triedcooking> private[this]) symbol definition: private[this] val $outer: sbt.BuildCommon tpe: <notype> symbol owners: value $outer -> anonymous class $anonfun$87 -> value x$298 -> method derive -> class BuildCommon$class -> package sbt context owners: value dir -> value globalCore -> object Defaults -> package sbt ... The problem here is the difference between context owners and the proxy search chain.
jvican
pushed a commit
to scalacenter/sbt
that referenced
this issue
May 23, 2017
The fix was made possible by the very helpful information provided by @retronym. This commit does two key things: 1. changes the owner when splicing original trees into new trees 2. ensures the synthetic trees that get spliced into original trees do not need typechecking Given this original source (from Defaults.scala): ... lazy val sourceConfigPaths = Seq( ... unmanagedSourceDirectories := Seq(scalaSource.value, javaSource.value), ... ) ... After expansion of .value, this looks something like: unmanagedSourceDirectories := Seq( InputWrapper.wrapInit[File](scalaSource), InputWrapper.wrapInit[File](javaSource) ) where wrapInit is something like: def wrapInit[T](a: Any): T After expansion of := we have (approximately): unmanagedSourceDirectories <<= Instance.app( (scalaSource, javaSource) ) { $p1: (File, File) => val $q4: File = $p1._1 val $q3: File = $p1._2 Seq($q3, $q4) } So, a) `scalaSource` and `javaSource` are user trees that are spliced into a tuple constructor after being temporarily held in `InputWrapper.wrapInit` b) the constructed tuple `(scalaSource, javaSource)` is passed as an argument to another method call (without going through a val or anything) and shouldn't need owner changing c) the synthetic vals $q3 and $q4 need their owner properly set to the anonymous function d) the references (Idents) $q3 and $q4 are spliced into the user tree `Seq(..., ...)` and their symbols need to be the Symbol for the referenced vals e) generally, treeCopy needs to be used when substituting Trees in order to preserve attributes, like Types and Positions changeOwner is called on the body `Seq($q3, $q4)` with the original owner sourceConfigPaths to be changed to the new anonymous function. In this example, no owners are actually changed, but when the body contains vals or anonymous functions, they will. An example of the compiler crash seen when the symbol of the references is not that of the vals: symbol value $q3 does not exist in sbt.Defaults.sourceConfigPaths$lzycompute at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49) at scala.tools.nsc.Global.abort(Global.scala:254) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.genLoadIdent$1(GenICode.scala:1038) at scala.tools.nsc.backend.icode.GenICode$ICodePhase.scala$tools$nsc$backend$icode$GenICode$ICodePhase$$genLoad(GenICode.scala:1044) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1246) at scala.tools.nsc.backend.icode.GenICode$ICodePhase$$anonfun$genLoadArguments$1.apply(GenICode.scala:1244) ... Other problems with the synthetic tree when it is spliced under the original tree often result in type mismatches or some other compiler error that doesn't result in a crash. If the owner is not changed correctly on the original tree that gets spliced under a synthetic tree, one way it can crash the compiler is: java.lang.IllegalArgumentException: Could not find proxy for val $q23: java.io.File in List(value $q23, method apply, anonymous class $anonfun$globalCore$5, value globalCore, object Defaults, package sbt, package <root>) (currentOwner= value dir ) ... while compiling: /home/mark/code/sbt/main/src/main/scala/sbt/Defaults.scala during phase: global=lambdalift, atPhase=constructors ... last tree to typer: term $outer symbol: value $outer (flags: <synthetic> <paramaccessor> <triedcooking> private[this]) symbol definition: private[this] val $outer: sbt.BuildCommon tpe: <notype> symbol owners: value $outer -> anonymous class $anonfun$87 -> value x$298 -> method derive -> class BuildCommon$class -> package sbt context owners: value dir -> value globalCore -> object Defaults -> package sbt ... The problem here is the difference between context owners and the proxy search chain.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
so e.g. (with sbt 0.13):
I feel like this must be a known problem... in fact, I even feel like I remember hearing Mark talk about it... but I can't find a ticket.
if I slap a type annotation on it:
then the error changes:
The text was updated successfully, but these errors were encountered: