@@ -26,6 +26,7 @@ import ast.Trees._
26
26
import ast .{tpd , untpd }
27
27
import util .SourcePosition
28
28
import util .Chars ._
29
+
29
30
import collection .mutable
30
31
import ProtoTypes ._
31
32
import config .Printers
@@ -122,6 +123,10 @@ class TreeChecker extends Phase with SymTransformer {
122
123
val squahsedPhase = ctx.squashed(prevPhase)
123
124
ctx.echo(s " checking ${ctx.compilationUnit} after phase ${squahsedPhase}" )
124
125
126
+ if (ctx.isAfterTyper) {
127
+ WrappedNewChecker .assertSelectWrapsNew(ctx.compilationUnit.tpdTree)(ctx)
128
+ }
129
+
125
130
val checkingCtx = ctx
126
131
.fresh
127
132
.setMode(Mode .ImplicitsEnabled )
@@ -449,6 +454,53 @@ class TreeChecker extends Phase with SymTransformer {
449
454
tree
450
455
}
451
456
}
457
+
458
+ /**
459
+ * Checks that `New` nodes are always wrapped inside `Select` nodes.
460
+ */
461
+ private object WrappedNewChecker {
462
+
463
+ // Current state of the search. We return as soon as we see the first improperly wrapped `New`.
464
+ sealed trait State
465
+ case class NotFound (parent : Option [tpd.Tree ]) extends State
466
+ case class Found (parent : Option [tpd.Tree ], child : tpd.New ) extends State
467
+
468
+ def assertSelectWrapsNew (tree : tpd.Tree )(implicit ctx : Context ): Unit = {
469
+ val detect = new TreeAccumulator [State ] {
470
+ override def apply (st : State , tree : tpd.Tree )(implicit ctx : Context ): State = {
471
+ st match {
472
+ case _ : Found => st // thread the found pair
473
+ case NotFound (oldParent) =>
474
+ tree match {
475
+ case tree : tpd.New if ! canWrapNew(oldParent) => Found (oldParent, tree)
476
+ case _ =>
477
+ // replace the parent when folding over the children
478
+ foldOver(NotFound (Some (tree)), tree) match {
479
+ case found : Found => found
480
+ case _ => st // return the old parent so that my siblings see it
481
+ }
482
+ }
483
+ }
484
+ }
485
+ }
486
+
487
+ detect(NotFound (None ), tree) match {
488
+ case Found (Some (parent), child) =>
489
+ assert(assertion = false , i " `New` node must be wrapped in a `Select`: \n parent = ${parent.show}\n child = ${child.show}" )
490
+ case Found (None , child) =>
491
+ assert(assertion = false , i " `New` node without a parent: \n ${child.show}" )
492
+ case _ => ()
493
+ }
494
+ }
495
+
496
+ def canWrapNew (tree : Option [tpd.Tree ]): Boolean = {
497
+ tree match {
498
+ case Some (_ : tpd.Select ) => true
499
+ case _ => false
500
+ }
501
+ }
502
+ }
503
+
452
504
}
453
505
454
506
object TreeChecker {
0 commit comments