@@ -152,6 +152,54 @@ object Checking {
152152 else info
153153 }
154154 }
155+
156+ /** Check that refinement satisfies the following two conditions
157+ * 1. No part of it refers to a symbol that's defined in the same refinement
158+ * at a textually later point.
159+ * 2. All references to the refinement itself via `this` are followed by
160+ * selections.
161+ * Note: It's not yet clear what exactly we want to allow and what we want to rule out.
162+ * This depends also on firming up the DOT calculus. For the moment we only issue
163+ * deprecated warnings, not errors.
164+ */
165+ def checkRefinementNonCyclic (refinement : Tree , refineCls : ClassSymbol )(implicit ctx : Context ): Unit = {
166+ def flag (what : String , tree : Tree ) =
167+ ctx.deprecationWarning(i " $what reference in refinement is deprecated " , tree.pos)
168+ def forwardRef (tree : Tree ) = flag(" forward" , tree)
169+ def selfRef (tree : Tree ) = flag(" self" , tree)
170+ val checkTree = new TreeAccumulator [Unit ] {
171+ def checkRef (tree : Tree , sym : Symbol ) =
172+ if (sym.maybeOwner == refineCls && tree.pos.start <= sym.pos.end) forwardRef(tree)
173+ def apply (x : Unit , tree : Tree ) = tree match {
174+ case tree @ Select (This (_), _) =>
175+ checkRef(tree, tree.symbol)
176+ case tree : RefTree =>
177+ checkRef(tree, tree.symbol)
178+ foldOver(x, tree)
179+ case tree : This =>
180+ selfRef(tree)
181+ case tree : TypeTree =>
182+ val checkType = new TypeAccumulator [Unit ] {
183+ def apply (x : Unit , tp : Type ): Unit = tp match {
184+ case tp : NamedType =>
185+ checkRef(tree, tp.symbol)
186+ tp.prefix match {
187+ case pre : ThisType =>
188+ case pre => foldOver(x, pre)
189+ }
190+ case tp : ThisType if tp.cls == refineCls =>
191+ selfRef(tree)
192+ case _ =>
193+ foldOver(x, tp)
194+ }
195+ }
196+ checkType((), tree.tpe)
197+ case _ =>
198+ foldOver(x, tree)
199+ }
200+ }
201+ checkTree((), refinement)
202+ }
155203}
156204
157205trait Checking {
0 commit comments