diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-10-28 14:54:35 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-10-28 19:18:59 +1000 |
commit | 7664e25eed8ae4547f1cfd774b62a7b6a4baf8b5 (patch) | |
tree | aacec0e13e33940b39b77b26929e23392f775d7d /test | |
parent | bdae51d6a8f18a5456a32c350cb551d42a3cb6c6 (diff) | |
download | scala-7664e25eed8ae4547f1cfd774b62a7b6a4baf8b5.tar.gz scala-7664e25eed8ae4547f1cfd774b62a7b6a4baf8b5.tar.bz2 scala-7664e25eed8ae4547f1cfd774b62a7b6a4baf8b5.zip |
SI-8941 Idempotent presentation compilation of implicit classes
When we name an implicit class, `enterImplicitWrapper` is called,
which enters the symbol for the factory method into the
owning scope. The tree defining this factory method is stowed into
`unit.synthetics`, from whence it will be retrieved and incorporated
into the enclosing tree during typechecking (`addDerivedTrees`).
The entry in `unit.synthetics` is removed at that point.
However, in the presentation compiler, we can typecheck a unit
more than once in a single run. For example, if, as happens
in the enclosed test, a call to ask for a type at a given
position interrupts type checking of the entire unit, we
can get into a situation whereby the first type checking
invocation has consumed the entry from `unit.synthetics`,
and the second will crash when it can't find an entry.
Similar problems have been solved in the past in
`enterExistingSym` in the presentation compiler. This method
is called when the namer encounters a tree that already has
a symbol attached. See 0b78a0196 / 148736c3df.
This commit takes a two pronged approach.
First, `enterExistingSym` is extended to handle implicit classes.
Any previous factory method in the owning scope is removed, and
`enterImplicitWrapper` is called to place a new tree for the factory
into `unit.synthetics` and to enter its symbol into the owning scope.
Second, the assertions that could be tripped in `addDerivedTrees`
and in `ImplicitClassWrapper#derivedSym` have been converted to
positioned errors.
The first change is sufficient to fix this bug, but the second
is also enough to make the enclosed test pass, and has been retained
as an extra layer of defence.
Diffstat (limited to 'test')
-rw-r--r-- | test/files/presentation/t8941.check | 7 | ||||
-rw-r--r-- | test/files/presentation/t8941/Runner.scala | 11 | ||||
-rw-r--r-- | test/files/presentation/t8941/src/Source.scala | 8 |
3 files changed, 26 insertions, 0 deletions
diff --git a/test/files/presentation/t8941.check b/test/files/presentation/t8941.check new file mode 100644 index 0000000000..341804903a --- /dev/null +++ b/test/files/presentation/t8941.check @@ -0,0 +1,7 @@ +reload: Source.scala + +askType at Source.scala(6,7) +================================================================================ +[response] askTypeAt (6,7) +scala.this.Predef.??? +================================================================================ diff --git a/test/files/presentation/t8941/Runner.scala b/test/files/presentation/t8941/Runner.scala new file mode 100644 index 0000000000..0a8923a583 --- /dev/null +++ b/test/files/presentation/t8941/Runner.scala @@ -0,0 +1,11 @@ +import scala.tools.nsc.interactive.tests.InteractiveTest + +object Test extends InteractiveTest { + override def runDefaultTests() { + // make sure typer is done.. the virtual pattern matcher might translate + // some trees and mess up positions. But we'll catch it red handed! + // sourceFiles foreach (src => askLoadedTyped(src).get) + super.runDefaultTests() + } + +} diff --git a/test/files/presentation/t8941/src/Source.scala b/test/files/presentation/t8941/src/Source.scala new file mode 100644 index 0000000000..7438cccb03 --- /dev/null +++ b/test/files/presentation/t8941/src/Source.scala @@ -0,0 +1,8 @@ +object Foo { + implicit class MatCreator(val ctx: StringContext) extends AnyVal { + def m(args: Any*): Unit = { + ctx.checkLengths(args) + } + ???/*?*/ + } +} |