diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2014-06-28 18:46:54 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2014-07-10 14:09:20 +0300 |
commit | 5ba2be24f82631f10d9163513204c5e44f445555 (patch) | |
tree | e043be5be121d21b9c42ad97797fdac9aeb07e62 /test/files/run | |
parent | fbfce33cb03bc2b41dd0f46fa9f4630036b4f2ca (diff) | |
download | scala-5ba2be24f82631f10d9163513204c5e44f445555.tar.gz scala-5ba2be24f82631f10d9163513204c5e44f445555.tar.bz2 scala-5ba2be24f82631f10d9163513204c5e44f445555.zip |
prevents some reflection APIs from destroying rangeposes
This commit continues the work started in fcb3932b32.
As we've figured out the hard way, exposing internally maintained trees
(e.g. macro application) to the user is dangerous, because they can mutate
the trees in place using one of the public APIs, potentially corrupting our
internal state.
Therefore, at some point we started duplicating everything that comes from the user
and goes back to the user. This was generally a good idea due to the reason
described above, but there was a problem that we didn't foresee - the problem
of corrupted positions.
It turns out that Tree.duplicate focuses positions in the tree being processed,
turning range positions into offset ones, and that makes it impossible for macro
users to make use of precise position information.
I also went through the calls to Tree.duplicate to see what can be done
to them. In cases when corruptions could happen, I tried to replace duplicate
with duplicateAndKeepPositions.
Some notes:
1) Tree rehashing performed in TreeGen uses duplicates here and there
(e.g. in mkTemplate or in mkFor), which means that if one deconstructs
a macro argument and then constructs it back, some of the positions in
synthetic trees might become inaccurate. That's a general problem with
synthetic trees though, so I don't think it should be addressed here.
2) TypeTree.copyAttrs does duplication of originals, which means that
even duplicateAndKeepPositions will adversely affect positions of certain
publicly accessible parts of type trees. I'm really scared to change this
though, because who knows who can use this invariant.
3) Some methods that can be reached from the public API (Tree.substituteXXX,
c.reifyXXX, c.untypecheck, ...) do duplicate internally, but that shouldn't be
a big problem for us, because nothing is irreversibly corrupted here.
It's the user's choice to call those methods (unlike with TypeTree.copyAttrs)
and, if necessary, they can fixup the positions themselves afterwards.
4) Macro engine internals (macro impl binding creation, exploratory typechecking
in typedMacroBody) use duplicate, but these aren't supposed to be seen by the user,
so this shouldn't be a problem.
5) Certain parser functions, member syntheses and typer desugarings also duplicate,
but in those cases we aren't talking about taking user trees and screwing them up,
but rather about emitting potentially imprecise positions in the first place.
Hence this commit isn't the right place to address these potential issues.
Diffstat (limited to 'test/files/run')
4 files changed, 25 insertions, 0 deletions
diff --git a/test/files/run/macro-rangepos-subpatterns.check b/test/files/run/macro-rangepos-subpatterns.check new file mode 100644 index 0000000000..760e15d019 --- /dev/null +++ b/test/files/run/macro-rangepos-subpatterns.check @@ -0,0 +1 @@ +The width of the subpattern is: 2 diff --git a/test/files/run/macro-rangepos-subpatterns.flags b/test/files/run/macro-rangepos-subpatterns.flags new file mode 100644 index 0000000000..fcf951d907 --- /dev/null +++ b/test/files/run/macro-rangepos-subpatterns.flags @@ -0,0 +1 @@ +-Yrangepos
\ No newline at end of file diff --git a/test/files/run/macro-rangepos-subpatterns/Macros_1.scala b/test/files/run/macro-rangepos-subpatterns/Macros_1.scala new file mode 100644 index 0000000000..0f30862347 --- /dev/null +++ b/test/files/run/macro-rangepos-subpatterns/Macros_1.scala @@ -0,0 +1,18 @@ +import scala.reflect.macros.whitebox.Context +import language.experimental.macros + +object Extractor { + def unapply(x: Any): Any = macro unapplyImpl + def unapplyImpl(c: Context)(x: c.Tree) = { + import c.universe._ + import internal._ + val pos = subpatterns(x).get.head.pos + q""" + new { + def isEmpty = false + def get = ${"The width of the subpattern is: " + (pos.end - pos.start + 1)} + def unapply(x: Any) = this + }.unapply($x) + """ + } +} diff --git a/test/files/run/macro-rangepos-subpatterns/Test_2.scala b/test/files/run/macro-rangepos-subpatterns/Test_2.scala new file mode 100644 index 0000000000..7b076e6632 --- /dev/null +++ b/test/files/run/macro-rangepos-subpatterns/Test_2.scala @@ -0,0 +1,5 @@ +object Test extends App { + 42 match { + case Extractor(a) => println(a) + } +} |