Skip to content

Commit e26fb44

Browse files
committed
Updated refinement checking.
Toucher checks, but only deprecated warnings instead of errors.
1 parent 917f58f commit e26fb44

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

157205
trait Checking {

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import NameOps._
2020
import Flags._
2121
import Decorators._
2222
import ErrorReporting._
23+
import Checking._
2324
import EtaExpansion.etaExpand
2425
import dotty.tools.dotc.transform.Erasure.Boxing
2526
import util.Positions._
@@ -761,14 +762,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
761762
assert(tree.refinements.length == refinements1.length, s"${tree.refinements} != $refinements1")
762763
def addRefinement(parent: Type, refinement: Tree): Type = {
763764
typr.println(s"adding refinement $refinement")
764-
def checkRef(tree: Tree, sym: Symbol) =
765-
if (sym.maybeOwner == refineCls && tree.pos.start <= sym.pos.end)
766-
ctx.error("illegal forward reference in refinement", tree.pos)
767-
refinement foreachSubTree {
768-
case tree: RefTree => checkRef(tree, tree.symbol)
769-
case tree: TypeTree => checkRef(tree, tree.tpe.typeSymbol)
770-
case _ =>
771-
}
765+
checkRefinementNonCyclic(refinement, refineCls)
772766
val rsym = refinement.symbol
773767
val rinfo = if (rsym is Accessor) rsym.info.resultType else rsym.info
774768
RefinedType(parent, rsym.name, rt => rinfo.substThis(refineCls, RefinedThis(rt)))

0 commit comments

Comments
 (0)