Skip to content
Browse files

Fix typing idempotency bug with Annotated trees

typedAnnotated transforms an Annotated tree into a Typed tree. The
original field of the result is set to the Annotated tree.

The bug was that typedAnnotated was using the untyped Annotated tree
as original, but also set its type. When re-typing later on the same
Annotated tree, the typer would consider it as alreadyTyped. This
is incorrect, the typer needs to convert Annotated trees to Typed.

Also, the Annotated tree only had its type field set, but its children
were still untyped. This crashed the compiler lateron, non-typed trees
would get out of the typing phase.
  • Loading branch information...
1 parent f51ed74 commit 8206e26f7b04b028b6a81cf7008d9b49169341fd @lrytz lrytz committed Feb 12, 2013
View
14 src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4153,15 +4153,11 @@ trait Typers extends Modes with Adaptations with Tags {
def resultingTypeTree(tpe: Type) = {
// we need symbol-ful originals for reification
// hence we go the extra mile to hand-craft tis guy
- val original =
- if (arg1.isType)
- arg1 match {
- case tt @ TypeTree() => Annotated(ann, tt.original)
- // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)"
- case _ => Annotated(ann, arg1)
- }
- else
- tree
+ val original = arg1 match {
+ case tt @ TypeTree() => Annotated(ann, tt.original)
+ // this clause is needed to correctly compile stuff like "new C @D" or "@(inline @getter)"
+ case _ => Annotated(ann, arg1)
+ }
original setType ann.tpe
TypeTree(tpe) setOriginal original setPos tree.pos.focus
}
View
6 test/files/run/annotatedRetyping.check
@@ -0,0 +1,6 @@
+typing List(1, 2).map(((x) => {
+ val another = scala.Tuple2(t.nt, t.tr): @testAnn match {
+ case scala.Tuple2(_, _) => 1
+ };
+ x
+}))
View
62 test/files/run/annotatedRetyping.scala
@@ -0,0 +1,62 @@
+import scala.tools.partest._
+import scala.tools.nsc._
+
+object Test extends DirectTest {
+
+ override def extraSettings: String = "-usejavacp"
+
+ def code = """
+ class testAnn extends annotation.Annotation
+
+ object t {
+ def nt = 1
+ def tr = "a"
+ }
+
+ class Test {
+ List(1,2).map(x => {
+ val another = ((t.nt, t.tr): @testAnn) match { case (_, _) => 1 }
+ x
+ })
+ }
+ """.trim
+
+
+ // point of this test: type-check the "Annotated" tree twice. first time the analyzer plugin types it,
+ // second time the typer.
+
+ // bug was that typedAnnotated assigned a type to the Annotated tree. The second type check would consider
+ // the tree as alreadyTyped, which is not cool, the Annotated needs to be transformed into a Typed tree.
+
+ def show() {
+ val global = newCompiler()
+ import global._
+ import analyzer._
+ import collection.{mutable => m}
+
+ object analyzerPlugin extends AnalyzerPlugin {
+ val templates: m.Map[Symbol, (Template, Typer)] = m.Map()
+ override def pluginsTypeSig(tpe: Type, typer: Typer, defTree: Tree, pt: Type): Type = {
+ defTree match {
+ case impl: Template =>
+ templates += typer.context.owner -> (impl, typer)
+
+ case dd: DefDef if dd.symbol.isPrimaryConstructor && templates.contains(dd.symbol.owner) =>
+ val (impl, templTyper) = templates(dd.symbol.owner)
+ for (stat <- impl.body.filterNot(_.isDef)) {
+ println("typing "+ stat)
+ val statsOwner = impl.symbol orElse templTyper.context.owner.newLocalDummy(impl.pos)
+ val tpr = analyzer.newTyper(templTyper.context.make(stat, statsOwner))
+ tpr.typed(stat)
+ }
+
+ case _ =>
+ }
+ tpe
+ }
+ }
+
+ addAnalyzerPlugin(analyzerPlugin)
+ compileString(global)(code)
+ }
+}

0 comments on commit 8206e26

Please sign in to comment.
Something went wrong with that request. Please try again.