aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-09-01 13:51:12 +0200
committerMartin Odersky <odersky@gmail.com>2014-09-01 13:52:07 +0200
commit2788547565d178f9bca93adc0df69029024bf4e6 (patch)
treec3fe449fda762b28d14db563678644ff56fe885c
parentdc958b7773249105224f667bdd83154235efe79b (diff)
downloaddotty-2788547565d178f9bca93adc0df69029024bf4e6.tar.gz
dotty-2788547565d178f9bca93adc0df69029024bf4e6.tar.bz2
dotty-2788547565d178f9bca93adc0df69029024bf4e6.zip
Allow more leniency in time travel.
Makes the method pioneered in elidablePrefix more general. Also applies it to accessWithin.
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala35
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala7
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala20
-rw-r--r--src/dotty/tools/dotc/typer/Mode.scala12
4 files changed, 51 insertions, 23 deletions
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 8f9a0d4b2..9b2644c85 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -8,6 +8,7 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Symbols._
import Denotations._, Decorators._
import config.Printers._
+import typer.Mode
import typer.ErrorReporting._
import scala.annotation.tailrec
@@ -252,26 +253,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
// ------ Making references ------------------------------------------------------
- def prefixIsElidable(tp: NamedType)(implicit ctx: Context) =
- try
- tp.prefix match {
- case NoPrefix =>
- true
- case pre: ThisType =>
- pre.cls.isStaticOwner ||
- tp.symbol.is(ParamOrAccessor) && ctx.owner.enclosingClass.derivesFrom(pre.cls)
- case pre: TermRef =>
- pre.symbol.is(Module) && pre.symbol.isStatic
- case _ =>
- false
- }
+ def prefixIsElidable(tp: NamedType)(implicit ctx: Context) = {
+ def test(implicit ctx: Context) = tp.prefix match {
+ case NoPrefix =>
+ true
+ case pre: ThisType =>
+ pre.cls.isStaticOwner ||
+ tp.symbol.is(ParamOrAccessor) && ctx.owner.enclosingClass.derivesFrom(pre.cls)
+ case pre: TermRef =>
+ pre.symbol.is(Module) && pre.symbol.isStatic
+ case _ =>
+ false
+ }
+ try test
catch {
- case ex: NotDefinedHere => false
- // NotDefinedHere can happen if we create a reference during unpickling
- // (which will be at phase frontend), but the request comes at a later
- // phase from within a context with owners that are not yet defined at
- // phase frontend. An example case arises when compiling pos/i143.scala
+ // See remark in SymDenotations#accessWithin
+ case ex: NotDefinedHere => test(ctx.withMode(Mode.FutureDefsOK))
}
+ }
def needsSelect(tp: Type)(implicit ctx: Context) = tp match {
case tp: TermRef => !prefixIsElidable(tp)
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index c56d2b882..507914f85 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -18,6 +18,7 @@ import printing.Texts._
import printing.Printer
import io.AbstractFile
import config.Config
+import typer.Mode
import util.common._
import collection.mutable.ListBuffer
import Decorators.SymbolIteratorDecorator
@@ -576,7 +577,11 @@ object Denotations {
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
cur = cur.nextInRun
cnt += 1
- if (cnt > MaxPossiblePhaseId) throw new NotDefinedHere(demandOutsideDefinedMsg)
+ if (cnt > MaxPossiblePhaseId)
+ if (ctx.mode is Mode.FutureDefsOK)
+ return current(ctx.withPhase(coveredInterval.firstPhaseId))
+ else
+ throw new NotDefinedHere(demandOutsideDefinedMsg)
}
cur
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 63f998c10..2260ebba3 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -11,6 +11,7 @@ import scala.reflect.io.AbstractFile
import Decorators.SymbolIteratorDecorator
import ast._
import annotation.tailrec
+import typer.Mode
import util.SimpleMap
import util.Stats
import config.Config
@@ -456,10 +457,21 @@ object SymDenotations {
final def isAccessibleFrom(pre: Type, superAccess: Boolean = false, whyNot: StringBuffer = null)(implicit ctx: Context): Boolean = {
/** Are we inside definition of `boundary`? */
- def accessWithin(boundary: Symbol) =
- ctx.owner.isContainedIn(boundary) &&
- (!(this is JavaDefined) || // disregard package nesting for Java
- ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass)
+ def accessWithin(boundary: Symbol) = {
+ def test(implicit ctx: Context) =
+ ctx.owner.isContainedIn(boundary) &&
+ (!(this is JavaDefined) || // disregard package nesting for Java
+ ctx.owner.enclosingPackageClass == boundary.enclosingPackageClass)
+ try test
+ catch {
+ // It might be we are in a definition that is not defined at the
+ // period where the test is made. Retry with FutureDefsOK. The reason
+ // for not doing this outright is speed. We would like to avoid
+ // creating a new context object each time we call accessWithin.
+ // Note that the exception should be thrown only infrequently.
+ case ex: NotDefinedHere => test(ctx.withMode(Mode.FutureDefsOK))
+ }
+ }
/** Are we within definition of linked class of `boundary`? */
def accessWithinLinked(boundary: Symbol) = {
diff --git a/src/dotty/tools/dotc/typer/Mode.scala b/src/dotty/tools/dotc/typer/Mode.scala
index 417d461e1..eb911987b 100644
--- a/src/dotty/tools/dotc/typer/Mode.scala
+++ b/src/dotty/tools/dotc/typer/Mode.scala
@@ -34,5 +34,17 @@ object Mode {
val TypevarsMissContext = newMode(4, "TypevarsMissContext")
val CheckCyclic = newMode(5, "CheckCyclic")
+ /** This mode bit is set if we want to allow accessing a symbol's denotation
+ * at a period before that symbol is first valid. An example where this is
+ * the case is if we want to examine the environment where an access is made.
+ * The computation might take place at an earlier phase (e.g. it is part of
+ * some completion such as unpickling), but the environment might contain
+ * synbols that are not yet defined in that phase.
+ * If the mode bit is set, getting the denotation of a symbol at a phase
+ * before the symbol is defined will return the symbol's denotation at the
+ * first phase where it is valid, instead of throwing a NotDefinedHere error.
+ */
+ val FutureDefsOK = newMode(6, "FutureDefsOK")
+
val PatternOrType = Pattern | Type
} \ No newline at end of file