Project: Scala
Revision: 16035
Author: washburn
Date: 05 Sep 2008 10:25:05
Diff at Trac: https://lampsvn.epfl.ch/trac/scala/changeset/16035
Changes:Added support for -Yrecursion compiler flag.
Added two tests involving this flag.
Files:added: /scala/trunk/test/files/pos/proj-rec-test.flags (
try)
modified: /scala/trunk/src/compiler/scala/tools/nsc/symtab/Types.scala (
try)
added: /scala/trunk/test/files/pos/comp-rec-test.flags (
try)
modified: /scala/trunk/src/compiler/scala/tools/nsc/symtab/Symbols.scala (
try)
added: /scala/trunk/test/files/pos/proj-rec-test.scala (
try)
modified: /scala/trunk/src/compiler/scala/tools/nsc/typechecker/Typers.scala (
try)
added: /scala/trunk/test/files/pos/comp-rec-test.scala (
try)
modified: /scala/trunk/src/compiler/scala/tools/nsc/Settings.scala (
try)
Diff:
| ... | ...@@ -0,0 +1 @@ |
| 0 | -Yrecursion 1 |
| ... | ...@@ -2051,12 +2051,12 @@ |
| 2051 | 2051 | if (sym1.isAliasType && sym1.info.typeParams.length == args.length) { |
| 2052 | 2052 | // note: we require that object is initialized, |
| 2053 | 2053 | // that's why we use info.typeParams instead of typeParams. |
| 2054 | | if (sym1.hasFlag(LOCKED)) |
| 2054 | sym1.lock { |
| 2055 | 2055 | throw new TypeError("illegal cyclic reference involving " + sym1) |
| 2056 | | sym1.setFlag(LOCKED) |
| 2057 | | transform(sym1.info) // check there are no cycles |
| 2058 | | sym1.resetFlag(LOCKED) |
| 2059 | | |
| 2056 | } |
| 2057 | transform(sym1.info) // check there are no cycles |
| 2058 | sym1.unlock() |
| 2059 | |
| 2060 | 2060 | rawTypeRef(pre, sym1, args) // don't expand type alias (cycles checked above) |
| 2061 | 2061 | } else { |
| 2062 | 2062 | val pre1 = removeSuper(pre, sym1) |
| ... | ...@@ -0,0 +1 @@ |
| 0 | -Yrecursion 1 |
| ... | ...@@ -7,6 +7,7 @@ |
| 7 | 7 | package scala.tools.nsc.symtab |
| 8 | 8 | |
| 9 | 9 | import scala.collection.mutable.ListBuffer |
| 10 | import scala.collection.immutable.Map |
| 10 | 11 | import scala.tools.nsc.io.AbstractFile |
| 11 | 12 | import scala.tools.nsc.util.{Position, NoPosition, BatchSourceFile} |
| 12 | 13 | import Flags._ |
| ... | ...@@ -26,6 +27,11 @@ |
| 26 | 27 | |
| 27 | 28 | val emptySymbolArray = new Array[Symbol](0) |
| 28 | 29 | val emptySymbolSet = Set.empty[Symbol] |
| 30 | |
| 31 | |
| 32 | /** Used to keep track of the recursion depth on locked symbols */ |
| 33 | private var recursionTable = Map.empty[Symbol, Int] |
| 34 | |
| 29 | 35 | /* |
| 30 | 36 | type Position; |
| 31 | 37 | def NoPos : Position; |
| ... | ...@@ -181,6 +187,44 @@ |
| 181 | 187 | final def newErrorSymbol(name: Name): Symbol = |
| 182 | 188 | if (name.isTypeName) newErrorClass(name) else newErrorValue(name) |
| 183 | 189 | |
| 190 | // Locking and unlocking ------------------------------------------------------ |
| 191 | |
| 192 | // True if the symbol is unlocked. |
| 193 | // True if the symbol is locked but still below the allowed recursion depth. |
| 194 | // False otherwise |
| 195 | def lockOK: Boolean = { |
| 196 | ((rawflags & LOCKED) == 0) || |
| 197 | ((settings.Yrecursion.value != 0) && |
| 198 | (recursionTable get this match { |
| 199 | case Some(n) => (n <= settings.Yrecursion.value) |
| 200 | case None => true })) |
| 201 | } |
| 202 | |
| 203 | // Lock a symbol, using the handler if the recursion depth becomes too great. |
| 204 | def lock(handler: => Unit) = { |
| 205 | if ((rawflags & LOCKED) != 0) { |
| 206 | if (settings.Yrecursion.value != 0) { |
| 207 | recursionTable get this match { |
| 208 | case Some(n) => |
| 209 | if (n > settings.Yrecursion.value) { |
| 210 | handler |
| 211 | } else { |
| 212 | recursionTable += (this -> (n + 1)) |
| 213 | } |
| 214 | case None => |
| 215 | recursionTable += (this -> 1) |
| 216 | } |
| 217 | } else { handler } |
| 218 | } else { rawflags |= LOCKED } |
| 219 | } |
| 220 | |
| 221 | // Unlock a symbol |
| 222 | def unlock() = { |
| 223 | rawflags = rawflags & ~LOCKED |
| 224 | if (settings.Yrecursion.value != 0) |
| 225 | recursionTable -= this |
| 226 | } |
| 227 | |
| 184 | 228 | // Tests ---------------------------------------------------------------------- |
| 185 | 229 | |
| 186 | 230 | def isTerm = false //to be overridden |
| ... | ...@@ -499,17 +543,16 @@ |
| 499 | 543 | assert(infos.prev eq null, this.name) |
| 500 | 544 | val tp = infos.info |
| 501 | 545 | //if (settings.debug.value) System.out.println("completing " + this.rawname + tp.getClass());//debug |
| 502 | | if ((rawflags & LOCKED) != 0) { |
| 546 | lock { |
| 503 | 547 | setInfo(ErrorType) |
| 504 | 548 | throw CyclicReference(this, tp) |
| 505 | 549 | } |
| 506 | | rawflags = rawflags | LOCKED |
| 507 | 550 | val current = phase |
| 508 | 551 | try { |
| 509 | 552 | phase = phaseOf(infos.validFrom) |
| 510 | 553 | tp.complete(this) |
| 511 | 554 | // if (settings.debug.value && runId(validTo) == currentRunId) System.out.println("completed " + this/* + ":" + info*/);//DEBUG |
| 512 | | rawflags = rawflags & ~LOCKED |
| 555 | unlock() |
| 513 | 556 | } finally { |
| 514 | 557 | phase = current |
| 515 | 558 | } |
| ... | ...@@ -531,10 +574,10 @@ |
| 531 | 574 | assert(info ne null) |
| 532 | 575 | infos = TypeHistory(currentPeriod, info, null) |
| 533 | 576 | if (info.isComplete) { |
| 534 | | rawflags = rawflags & ~LOCKED |
| 577 | unlock() |
| 535 | 578 | validTo = currentPeriod |
| 536 | 579 | } else { |
| 537 | | rawflags = rawflags & ~LOCKED |
| 580 | unlock() |
| 538 | 581 | validTo = NoPeriod |
| 539 | 582 | } |
| 540 | 583 | this |
| ... | ...@@ -1597,7 +1640,8 @@ |
| 1597 | 1640 | privateWithin = this |
| 1598 | 1641 | override def setInfo(info: Type): this.type = { |
| 1599 | 1642 | infos = TypeHistory(1, NoType, null) |
| 1600 | | rawflags = rawflags & ~ LOCKED |
| 1643 | unlock() |
| 1644 | // rawflags = rawflags & ~ LOCKED |
| 1601 | 1645 | validTo = currentPeriod |
| 1602 | 1646 | this |
| 1603 | 1647 | } |
| ... | ...@@ -0,0 +1,13 @@ |
| 1 | object ProjTest { |
| 2 | trait MInt { type Type } |
| 3 | trait _0 extends MInt { type Type = Boolean } |
| 4 | trait Succ[Pre <: MInt] extends MInt { type Type = Pre#Type } |
| 5 | |
| 6 | type _1 = Succ[_0] |
| 7 | type _2 = Succ[_1] |
| 8 | |
| 9 | type X1 = _0#Type // Ok |
| 10 | type X2 = _1#Type // Ok |
| 11 | type X3 = _2#Type // Compiler error, illegal cyclic reference involving type Type |
| 12 | } |
| 13 | |
| ... | ...@@ -301,9 +301,7 @@ |
| 301 | 301 | def checkNonCyclic(pos: Position, tp: Type): Boolean = { |
| 302 | 302 | def checkNotLocked(sym: Symbol): Boolean = { |
| 303 | 303 | sym.initialize |
| 304 | | if (sym hasFlag LOCKED) { |
| 305 | | error(pos, "cyclic aliasing or subtyping involving "+sym); false |
| 306 | | } else true |
| 304 | sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false} |
| 307 | 305 | } |
| 308 | 306 | tp match { |
| 309 | 307 | case TypeRef(pre, sym, args) => |
| ... | ...@@ -332,9 +330,11 @@ |
| 332 | 330 | } |
| 333 | 331 | |
| 334 | 332 | def checkNonCyclic(pos: Position, tp: Type, lockedSym: Symbol): Boolean = { |
| 335 | | lockedSym.setFlag(LOCKED) |
| 333 | lockedSym.lock { |
| 334 | throw new TypeError("illegal cyclic reference involving " + lockedSym) |
| 335 | } |
| 336 | 336 | val result = checkNonCyclic(pos, tp) |
| 337 | | lockedSym.resetFlag(LOCKED) |
| 337 | lockedSym.unlock() |
| 338 | 338 | result |
| 339 | 339 | } |
| 340 | 340 | |
| ... | ...@@ -0,0 +1,24 @@ |
| 1 | object Comp extends Application { |
| 2 | |
| 3 | trait Family { |
| 4 | type T |
| 5 | } |
| 6 | |
| 7 | object Trivial extends Family { |
| 8 | type T = Unit |
| 9 | } |
| 10 | |
| 11 | trait Wrap extends Family { |
| 12 | val v : Family |
| 13 | type T = v.T |
| 14 | } |
| 15 | |
| 16 | object WrapTrivial extends Wrap { |
| 17 | val v = Trivial |
| 18 | } |
| 19 | |
| 20 | object WrapWrapTrivial extends Wrap { |
| 21 | val v = WrapTrivial |
| 22 | } |
| 23 | |
| 24 | } |
| ... | ...@@ -141,6 +141,7 @@ |
| 141 | 141 | val logAll = BooleanSetting ("-Ylog-all", "Log all operations").hideToIDE |
| 142 | 142 | val noimports = BooleanSetting ("-Yno-imports", "Compile without any implicit imports") |
| 143 | 143 | val nopredefs = BooleanSetting ("-Yno-predefs", "Compile without any implicit predefined values") |
| 144 | val Yrecursion = IntSetting ("-Yrecursion", "Recursion depth used when locking symbols", 0, Some(0), None) |
| 144 | 145 | val script = StringSetting ("-Xscript", "object", "Compile as a script, wrapping the code into object.main()", "").hideToIDE |
| 145 | 146 | |
| 146 | 147 | val Xshowtrees = BooleanSetting ("-Yshow-trees", "Show detailed trees when used in connection with -print:phase").hideToIDE |
To list