diff options
author | Martin Odersky <odersky@gmail.com> | 2014-09-01 13:51:12 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-09-01 13:52:07 +0200 |
commit | 2788547565d178f9bca93adc0df69029024bf4e6 (patch) | |
tree | c3fe449fda762b28d14db563678644ff56fe885c | |
parent | dc958b7773249105224f667bdd83154235efe79b (diff) | |
download | dotty-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.scala | 35 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 7 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymDenotations.scala | 20 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Mode.scala | 12 |
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 |