aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/core')
-rw-r--r--src/dotty/tools/dotc/core/Annotations.scala32
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala17
-rw-r--r--src/dotty/tools/dotc/core/Decorators.scala14
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala6
-rw-r--r--src/dotty/tools/dotc/core/Flags.scala17
-rw-r--r--src/dotty/tools/dotc/core/Mode.scala3
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala6
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala42
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala2
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala12
-rw-r--r--src/dotty/tools/dotc/core/Types.scala73
-rw-r--r--src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala23
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionPickler.scala92
-rw-r--r--src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala40
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala23
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyPickler.scala1
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyPrinter.scala4
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreePickler.scala24
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala80
20 files changed, 311 insertions, 204 deletions
diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala
index 5f96a60e6..0e8e5a1f0 100644
--- a/src/dotty/tools/dotc/core/Annotations.scala
+++ b/src/dotty/tools/dotc/core/Annotations.scala
@@ -26,6 +26,8 @@ object Annotations {
}
def argumentConstant(i: Int)(implicit ctx: Context): Option[Constant] =
for (ConstantType(c) <- argument(i) map (_.tpe)) yield c
+
+ def ensureCompleted(implicit ctx: Context): Unit = tree
}
case class ConcreteAnnotation(t: Tree) extends Annotation {
@@ -42,6 +44,36 @@ object Annotations {
override def symbol(implicit ctx: Context): Symbol = sym
}
+ /** An annotation indicating the body of a right-hand side,
+ * typically of an inline method. Treated specially in
+ * pickling/unpickling and TypeTreeMaps
+ */
+ abstract class BodyAnnotation extends Annotation {
+ override def symbol(implicit ctx: Context) = defn.BodyAnnot
+ override def derivedAnnotation(tree: Tree)(implicit ctx: Context) =
+ if (tree eq this.tree) this else ConcreteBodyAnnotation(tree)
+ override def arguments(implicit ctx: Context) = Nil
+ override def ensureCompleted(implicit ctx: Context) = ()
+ }
+
+ case class ConcreteBodyAnnotation(body: Tree) extends BodyAnnotation {
+ def tree(implicit ctx: Context) = body
+ }
+
+ case class LazyBodyAnnotation(bodyExpr: Context => Tree) extends BodyAnnotation {
+ private var evaluated = false
+ private var myBody: Tree = _
+ def tree(implicit ctx: Context) = {
+ if (evaluated) assert(myBody != null)
+ else {
+ evaluated = true
+ myBody = bodyExpr(ctx)
+ }
+ myBody
+ }
+ def isEvaluated = evaluated
+ }
+
object Annotation {
def apply(tree: Tree) = ConcreteAnnotation(tree)
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index cd76fe88b..313ea3124 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -18,7 +18,7 @@ import util.Positions._
import ast.Trees._
import ast.untpd
import util.{FreshNameCreator, SimpleMap, SourceFile, NoSource}
-import typer.{Implicits, ImplicitRunInfo, ImportInfo, NamerContextOps, SearchHistory, TypeAssigner, Typer}
+import typer.{Implicits, ImplicitRunInfo, ImportInfo, Inliner, NamerContextOps, SearchHistory, TypeAssigner, Typer}
import Implicits.ContextualImplicits
import config.Settings._
import config.Config
@@ -30,6 +30,7 @@ import config.{Settings, ScalaSettings, Platform, JavaPlatform, SJSPlatform}
import language.implicitConversions
import DenotTransformers.DenotTransformer
import parsing.Scanners.Comment
+import util.Property.Key
import xsbti.AnalysisCallback
object Contexts {
@@ -177,9 +178,12 @@ object Contexts {
def freshName(prefix: Name): String = freshName(prefix.toString)
/** A map in which more contextual properties can be stored */
- private var _moreProperties: Map[String, Any] = _
- protected def moreProperties_=(moreProperties: Map[String, Any]) = _moreProperties = moreProperties
- def moreProperties: Map[String, Any] = _moreProperties
+ private var _moreProperties: Map[Key[Any], Any] = _
+ protected def moreProperties_=(moreProperties: Map[Key[Any], Any]) = _moreProperties = moreProperties
+ def moreProperties: Map[Key[Any], Any] = _moreProperties
+
+ def property[T](key: Key[T]): Option[T] =
+ moreProperties.get(key).asInstanceOf[Option[T]]
private var _typeComparer: TypeComparer = _
protected def typeComparer_=(typeComparer: TypeComparer) = _typeComparer = typeComparer
@@ -459,9 +463,10 @@ object Contexts {
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
- def setMoreProperties(moreProperties: Map[String, Any]): this.type = { this.moreProperties = moreProperties; this }
+ def setMoreProperties(moreProperties: Map[Key[Any], Any]): this.type = { this.moreProperties = moreProperties; this }
- def setProperty(prop: (String, Any)): this.type = setMoreProperties(moreProperties + prop)
+ def setProperty[T](key: Key[T], value: T): this.type =
+ setMoreProperties(moreProperties.updated(key, value))
def setPhase(pid: PhaseId): this.type = setPeriod(Period(runId, pid))
def setPhase(phase: Phase): this.type = setPeriod(Period(runId, phase.start, phase.end))
diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala
index 387e7e466..3bf17730a 100644
--- a/src/dotty/tools/dotc/core/Decorators.scala
+++ b/src/dotty/tools/dotc/core/Decorators.scala
@@ -7,6 +7,7 @@ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer, printi
import util.Positions.Position, util.SourcePosition
import collection.mutable.ListBuffer
import dotty.tools.dotc.transform.TreeTransforms._
+import ast.tpd._
import scala.language.implicitConversions
import printing.Formatting._
@@ -40,7 +41,7 @@ object Decorators {
*/
implicit class ListDecorator[T](val xs: List[T]) extends AnyVal {
- @inline final def mapconserve[U](f: T => U): List[U] = {
+ final def mapconserve[U](f: T => U): List[U] = {
@tailrec
def loop(mapped: ListBuffer[U], unchanged: List[U], pending: List[T]): List[U] =
if (pending.isEmpty) {
@@ -148,8 +149,15 @@ object Decorators {
}
}
- implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition =
- ctx.source.atPos(pos)
+ implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = {
+ def recur(inlinedCalls: List[Tree], pos: Position): SourcePosition = inlinedCalls match {
+ case inlinedCall :: rest =>
+ sourceFile(inlinedCall).atPos(pos).withOuter(recur(rest, inlinedCall.pos))
+ case empty =>
+ ctx.source.atPos(pos)
+ }
+ recur(enclosingInlineds, pos)
+ }
implicit class StringInterpolators(val sc: StringContext) extends AnyVal {
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index cb83fda04..75b75d3d5 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -456,6 +456,8 @@ class Definitions {
def AliasAnnot(implicit ctx: Context) = AliasAnnotType.symbol.asClass
lazy val AnnotationDefaultAnnotType = ctx.requiredClassRef("dotty.annotation.internal.AnnotationDefault")
def AnnotationDefaultAnnot(implicit ctx: Context) = AnnotationDefaultAnnotType.symbol.asClass
+ lazy val BodyAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Body")
+ def BodyAnnot(implicit ctx: Context) = BodyAnnotType.symbol.asClass
lazy val ChildAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Child")
def ChildAnnot(implicit ctx: Context) = ChildAnnotType.symbol.asClass
lazy val CovariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.CovariantBetween")
@@ -466,6 +468,10 @@ class Definitions {
def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass
lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound")
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
+ lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")
+ def InlineAnnot(implicit ctx: Context) = InlineAnnotType.symbol.asClass
+ lazy val InlineParamAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InlineParam")
+ def InlineParamAnnot(implicit ctx: Context) = InlineParamAnnotType.symbol.asClass
lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InvariantBetween")
def InvariantBetweenAnnot(implicit ctx: Context) = InvariantBetweenAnnotType.symbol.asClass
lazy val MigrationAnnotType = ctx.requiredClassRef("scala.annotation.migration")
diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala
index 0cdae6b98..3f4433708 100644
--- a/src/dotty/tools/dotc/core/Flags.scala
+++ b/src/dotty/tools/dotc/core/Flags.scala
@@ -431,7 +431,7 @@ object Flags {
/** Flags representing source modifiers */
final val SourceModifierFlags =
- commonFlags(Private, Protected, Abstract, Final,
+ commonFlags(Private, Protected, Abstract, Final, Inline,
Sealed, Case, Implicit, Override, AbsOverride, Lazy, JavaStatic)
/** Flags representing modifiers that can appear in trees */
@@ -450,7 +450,7 @@ object Flags {
AccessFlags | Module | Package | Deferred | Final | MethodOrHKCommon | Param | ParamAccessor | Scala2ExistentialCommon |
Mutable.toCommonFlags | InSuperCall | Touched | JavaStatic | CovariantOrOuter | ContravariantOrLabel | ExpandedName | AccessorOrSealed |
CaseAccessorOrBaseTypeArg | Fresh | Frozen | Erroneous | ImplicitCommon | Permanent | Synthetic |
- LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass
+ Inline | LazyOrTrait | SuperAccessorOrScala2x | SelfNameOrImplClass
assert(FromStartFlags.isTermFlags && FromStartFlags.isTypeFlags)
// TODO: Should check that FromStartFlags do not change in completion
@@ -529,8 +529,8 @@ object Flags {
/** Either method or lazy or deferred */
final val MethodOrLazyOrDeferred = Method | Lazy | Deferred
- /** Labeled `private` or `final` */
- final val PrivateOrFinal = Private | Final
+ /** Labeled `private`, `final`, or `inline` */
+ final val PrivateOrFinalOrInline = Private | Final | Inline
/** A private method */
final val PrivateMethod = allOf(Private, Method)
@@ -541,6 +541,9 @@ object Flags {
/** A type parameter with synthesized name */
final val ExpandedTypeParam = allOf(ExpandedName, TypeParam)
+ /** An inline method */
+ final val InlineMethod = allOf(Inline, Method)
+
/** A parameter or parameter accessor */
final val ParamOrAccessor = Param | ParamAccessor
@@ -553,6 +556,12 @@ object Flags {
/** A type parameter or type parameter accessor */
final val TypeParamOrAccessor = TypeParam | TypeParamAccessor
+ /** A deferred member or a parameter accessor (these don't have right hand sides) */
+ final val DeferredOrParamAccessor = Deferred | ParamAccessor
+
+ /** value that's final or inline */
+ final val FinalOrInline = Final | Inline
+
/** If symbol of a type alias has these flags, prefer the alias */
final val AliasPreferred = TypeParam | BaseTypeArg | ExpandedName
diff --git a/src/dotty/tools/dotc/core/Mode.scala b/src/dotty/tools/dotc/core/Mode.scala
index 3e9b7effe..7a9bb0572 100644
--- a/src/dotty/tools/dotc/core/Mode.scala
+++ b/src/dotty/tools/dotc/core/Mode.scala
@@ -89,5 +89,8 @@ object Mode {
*/
val AllowLambdaWildcardApply = newMode(15, "AllowHKApplyToWildcards")
+ /** Read original positions when unpickling from TASTY */
+ val ReadPositions = newMode(16, "ReadPositions")
+
val PatternOrType = Pattern | Type
}
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index f5e0eb8cd..48e823e81 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -84,6 +84,8 @@ object NameOps {
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit)
def isLazyLocal = name.endsWith(nme.LAZY_LOCAL)
+ def isOuterSelect = name.endsWith(nme.OUTER_SELECT)
+ def isInlineAccessor = name.startsWith(nme.INLINE_ACCESSOR_PREFIX)
/** Is name a variable name? */
def isVariableName: Boolean = name.length > 0 && {
@@ -166,7 +168,7 @@ object NameOps {
// Hack to make super accessors from traits work. They would otherwise fail because of #765
// TODO: drop this once we have more robust name handling
- if (name.slice(idx - FalseSuperLength, idx) == FalseSuper)
+ if (idx > FalseSuperLength && name.slice(idx - FalseSuperLength, idx) == FalseSuper)
idx -= FalseSuper.length
if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N]
@@ -419,6 +421,8 @@ object NameOps {
assert(name.isLazyLocal)
name.dropRight(nme.LAZY_LOCAL.length)
}
+
+ def inlineAccessorName = nme.INLINE_ACCESSOR_PREFIX ++ name ++ "$"
}
private final val FalseSuper = "$$super".toTermName
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index f47ab1744..c52264637 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -46,6 +46,7 @@ object StdNames {
final val IFkw: N = kw("if")
final val IMPLICITkw: N = kw("implicit")
final val IMPORTkw: N = kw("import")
+ final val INLINEkw: N = kw("inline")
final val LAZYkw: N = kw("lazy")
final val MACROkw: N = kw("macro")
final val MATCHkw: N = kw("match")
@@ -100,6 +101,7 @@ object StdNames {
val EXPAND_SEPARATOR: N = "$$"
val IMPL_CLASS_SUFFIX: N = "$class"
val IMPORT: N = "<import>"
+ val INLINE_ACCESSOR_PREFIX = "$inlineAccessor$"
val INTERPRETER_IMPORT_WRAPPER: N = "$iw"
val INTERPRETER_LINE_PREFIX: N = "line"
val INTERPRETER_VAR_PREFIX: N = "res"
@@ -252,7 +254,7 @@ object StdNames {
val MODULE_INSTANCE_FIELD: N = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: N = "$outer"
val OUTER_LOCAL: N = "$outer "
- val OUTER_SYNTH: N = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter
+ val OUTER_SELECT: N = "_<outer>" // emitted by inliner, replaced by outer path in explicitouter
val REFINE_CLASS: N = "<refinement>"
val ROOTPKG: N = "_root_"
val SELECTOR_DUMMY: N = "<unapply-selector>"
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index ab45550a4..969d09c3e 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -281,6 +281,15 @@ object SymDenotations {
case nil => None
}
+ /** The same as getAnnotation, but without ensuring
+ * that the symbol carrying the annotation is completed
+ */
+ final def unforcedAnnotation(cls: Symbol)(implicit ctx: Context): Option[Annotation] =
+ dropOtherAnnotations(myAnnotations, cls) match {
+ case annot :: _ => Some(annot)
+ case nil => None
+ }
+
/** Add given annotation to the annotations of this denotation */
final def addAnnotation(annot: Annotation): Unit =
annotations = annot :: myAnnotations
@@ -289,6 +298,12 @@ object SymDenotations {
final def removeAnnotation(cls: Symbol)(implicit ctx: Context): Unit =
annotations = myAnnotations.filterNot(_ matches cls)
+ /** Remove any annotations with same class as `annot`, and add `annot` */
+ final def updateAnnotation(annot: Annotation)(implicit ctx: Context): Unit = {
+ removeAnnotation(annot.symbol)
+ addAnnotation(annot)
+ }
+
/** Add all given annotations to this symbol */
final def addAnnotations(annots: TraversableOnce[Annotation])(implicit ctx: Context): Unit =
annots.foreach(addAnnotation)
@@ -670,9 +685,9 @@ object SymDenotations {
val cls = owner.enclosingSubClass
if (!cls.exists)
fail(
- i""" Access to protected $this not permitted because
- | enclosing ${ctx.owner.enclosingClass.showLocated} is not a subclass of
- | ${owner.showLocated} where target is defined""")
+ i"""
+ | Access to protected $this not permitted because enclosing ${ctx.owner.enclosingClass.showLocated}
+ | is not a subclass of ${owner.showLocated} where target is defined""")
else if (
!( isType // allow accesses to types from arbitrary subclasses fixes #4737
|| pre.baseTypeRef(cls).exists // ??? why not use derivesFrom ???
@@ -680,9 +695,9 @@ object SymDenotations {
|| (owner is ModuleClass) // don't perform this check for static members
))
fail(
- i""" Access to protected ${symbol.show} not permitted because
- | prefix type ${pre.widen.show} does not conform to
- | ${cls.showLocated} where the access takes place""")
+ i"""
+ | Access to protected ${symbol.show} not permitted because prefix type ${pre.widen.show}
+ | does not conform to ${cls.showLocated} where the access takes place""")
else true
}
@@ -744,6 +759,11 @@ object SymDenotations {
// def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined
def isSkolem: Boolean = name == nme.SKOLEM
+ def isInlineMethod(implicit ctx: Context): Boolean =
+ is(Method, butNot = Accessor) &&
+ !isCompleting && // don't force method type; recursive inlines are ignored anyway.
+ hasAnnotation(defn.InlineAnnot)
+
// ------ access to related symbols ---------------------------------
/* Modules and module classes are represented as follows:
@@ -851,7 +871,7 @@ object SymDenotations {
/** A symbol is effectively final if it cannot be overridden in a subclass */
final def isEffectivelyFinal(implicit ctx: Context): Boolean =
- is(PrivateOrFinal) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass
+ is(PrivateOrFinalOrInline) || !owner.isClass || owner.is(ModuleOrFinal) || owner.isAnonymousClass
/** The class containing this denotation which has the given effective name. */
final def enclosingClassNamed(name: Name)(implicit ctx: Context): Symbol = {
@@ -1521,7 +1541,13 @@ object SymDenotations {
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
- require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot))
+
+ require(
+ (sym.denot.flagsUNSAFE is Private) ||
+ !(this is Frozen) ||
+ (scope ne this.unforcedDecls) ||
+ sym.hasAnnotation(defn.ScalaStaticAnnot) ||
+ sym.name.isInlineAccessor)
scope.enter(sym)
if (myMemberFingerPrint != FingerPrint.unknown)
diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala
index 3f801bda5..4ae28c10b 100644
--- a/src/dotty/tools/dotc/core/SymbolLoaders.scala
+++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala
@@ -198,7 +198,7 @@ abstract class SymbolLoader extends LazyType {
try {
val start = currentTime
if (ctx.settings.debugTrace.value)
- ctx.traceIndented(s">>>> loading ${root.debugString}", _ => s"<<<< loaded ${root.debugString}") {
+ ctx.doTraceIndented(s">>>> loading ${root.debugString}", _ => s"<<<< loaded ${root.debugString}") {
doComplete(root)
}
else
diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala
index 7b8867ccc..7e332b412 100644
--- a/src/dotty/tools/dotc/core/TyperState.scala
+++ b/src/dotty/tools/dotc/core/TyperState.scala
@@ -122,6 +122,18 @@ extends TyperState(r) {
* type variables changes from this typer state to the current one. (2) Variables
* that were temporarily instantiated in the current typer state are permanently
* instantiated instead.
+ *
+ * A note on merging: An interesting test case is isApplicableSafe.scala. It turns out that this
+ * requires a context merge using the new `&' operator. Sequence of actions:
+ * 1) Typecheck argument in typerstate 1.
+ * 2) Cache argument.
+ * 3) Evolve same typer state (to typecheck other arguments, say)
+ * leading to a different constraint.
+ * 4) Take typechecked argument in same state.
+ *
+ * It turns out that the merge is needed not just for
+ * isApplicableSafe but also for (e.g. erased-lubs.scala) as well as
+ * many parts of dotty itself.
*/
override def commit()(implicit ctx: Context) = {
val targetState = ctx.typerState
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 30d1c0136..2f1b6b829 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -228,8 +228,8 @@ object Types {
!existsPart(!p(_))
/** Performs operation on all parts of this type */
- final def foreachPart(p: Type => Unit)(implicit ctx: Context): Unit =
- new ForeachAccumulator(p).apply((), this)
+ final def foreachPart(p: Type => Unit, stopAtStatic: Boolean = false)(implicit ctx: Context): Unit =
+ new ForeachAccumulator(p, stopAtStatic).apply((), this)
/** The parts of this type which are type or term refs */
final def namedParts(implicit ctx: Context): collection.Set[NamedType] =
@@ -848,30 +848,42 @@ object Types {
case tp => tp
}
- /** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
- * is no longer alias type, LazyRef, or instantiated type variable.
- */
- final def dealias(implicit ctx: Context): Type = this match {
+ private def dealias(keepAnnots: Boolean)(implicit ctx: Context): Type = this match {
case tp: TypeRef =>
if (tp.symbol.isClass) tp
else tp.info match {
- case TypeAlias(tp) => tp.dealias
+ case TypeAlias(tp) => tp.dealias(keepAnnots)
case _ => tp
}
case tp: TypeVar =>
val tp1 = tp.instanceOpt
- if (tp1.exists) tp1.dealias else tp
+ if (tp1.exists) tp1.dealias(keepAnnots) else tp
case tp: AnnotatedType =>
- tp.derivedAnnotatedType(tp.tpe.dealias, tp.annot)
+ val tp1 = tp.tpe.dealias(keepAnnots)
+ if (keepAnnots) tp.derivedAnnotatedType(tp1, tp.annot) else tp1
case tp: LazyRef =>
- tp.ref.dealias
+ tp.ref.dealias(keepAnnots)
case app @ HKApply(tycon, args) =>
- val tycon1 = tycon.dealias
- if (tycon1 ne tycon) app.superType.dealias
+ val tycon1 = tycon.dealias(keepAnnots)
+ if (tycon1 ne tycon) app.superType.dealias(keepAnnots)
else this
case _ => this
}
+ /** Follow aliases and dereferences LazyRefs and instantiated TypeVars until type
+ * is no longer alias type, LazyRef, or instantiated type variable.
+ * Goes through annotated types and rewraps annotations on the result.
+ */
+ final def dealiasKeepAnnots(implicit ctx: Context): Type =
+ dealias(keepAnnots = true)
+
+ /** Follow aliases and dereferences LazyRefs, annotated types and instantiated
+ * TypeVars until type is no longer alias type, annotated type, LazyRef,
+ * or instantiated type variable.
+ */
+ final def dealias(implicit ctx: Context): Type =
+ dealias(keepAnnots = false)
+
/** Perform successive widenings and dealiasings until none can be applied anymore */
final def widenDealias(implicit ctx: Context): Type = {
val res = this.widen.dealias
@@ -1788,6 +1800,7 @@ object Types {
false
}
override def computeHash = doHash((name, sig), prefix)
+ override def toString = super.toString ++ s"/withSig($sig)"
}
trait WithFixedSym extends NamedType {
@@ -2418,7 +2431,12 @@ object Types {
apply(nme.syntheticParamNames(paramTypes.length), paramTypes)(resultTypeExp)
def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType =
apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType)
+
+ /** Produce method type from parameter symbols, with special mappings for repeated
+ * and inline parameters.
+ */
def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = {
+ /** Replace @repeated annotations on Seq or Array types by <repeated> types */
def translateRepeated(tp: Type): Type = tp match {
case tp @ ExprType(tp1) => tp.derivedExprType(translateRepeated(tp1))
case AnnotatedType(tp, annot) if annot matches defn.RepeatedAnnot =>
@@ -2428,7 +2446,15 @@ object Types {
case tp =>
tp
}
- def paramInfo(param: Symbol): Type = translateRepeated(param.info)
+ /** Add @inlineParam to inline call-by-value parameters */
+ def translateInline(tp: Type): Type = tp match {
+ case _: ExprType => tp
+ case _ => AnnotatedType(tp, Annotation(defn.InlineParamAnnot))
+ }
+ def paramInfo(param: Symbol): Type = {
+ val paramType = translateRepeated(param.info)
+ if (param.is(Inline)) translateInline(paramType) else paramType
+ }
def transformResult(mt: MethodType) =
resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _)))
apply(params map (_.name.asTermName), params map paramInfo)(transformResult _)
@@ -2554,6 +2580,24 @@ object Types {
x => paramBounds mapConserve (_.subst(this, x).bounds),
x => resType.subst(this, x))
+ /** Merge nested polytypes into one polytype. nested polytypes are normally not supported
+ * but can arise as temporary data structures.
+ */
+ def flatten(implicit ctx: Context): PolyType = resType match {
+ case that: PolyType =>
+ val shift = new TypeMap {
+ def apply(t: Type) = t match {
+ case PolyParam(`that`, n) => PolyParam(that, n + paramNames.length)
+ case t => mapOver(t)
+ }
+ }
+ PolyType(paramNames ++ that.paramNames)(
+ x => this.paramBounds.mapConserve(_.subst(this, x).bounds) ++
+ that.paramBounds.mapConserve(shift(_).subst(that, x).bounds),
+ x => shift(that.resultType).subst(that, x).subst(this, x))
+ case _ => this
+ }
+
override def toString = s"PolyType($paramNames, $paramBounds, $resType)"
override def computeHash = doHash(paramNames, resType, paramBounds)
@@ -3704,8 +3748,7 @@ object Types {
x || p(tp) || (forceLazy || !tp.isInstanceOf[LazyRef]) && foldOver(x, tp)
}
- class ForeachAccumulator(p: Type => Unit)(implicit ctx: Context) extends TypeAccumulator[Unit] {
- override def stopAtStatic = false
+ class ForeachAccumulator(p: Type => Unit, override val stopAtStatic: Boolean)(implicit ctx: Context) extends TypeAccumulator[Unit] {
def apply(x: Unit, tp: Type): Unit = foldOver(p(tp), tp)
}
diff --git a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
index 0ad5d6966..2c93819d5 100644
--- a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
@@ -8,8 +8,8 @@ import dotty.tools.dotc.ast.tpd
import TastyUnpickler._, TastyBuffer._
import util.Positions._
import util.{SourceFile, NoSource}
-import PositionUnpickler._
import Annotations.Annotation
+import core.Mode
import classfile.ClassfileParser
object DottyUnpickler {
@@ -17,14 +17,15 @@ object DottyUnpickler {
/** Exception thrown if classfile is corrupted */
class BadSignature(msg: String) extends RuntimeException(msg)
- class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") {
+ class TreeSectionUnpickler(posUnpickler: Option[PositionUnpickler])
+ extends SectionUnpickler[TreeUnpickler]("ASTs") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
- new TreeUnpickler(reader, tastyName)
+ new TreeUnpickler(reader, tastyName, posUnpickler)
}
- class PositionsSectionUnpickler extends SectionUnpickler[(Position, AddrToPosition)]("Positions") {
+ class PositionsSectionUnpickler extends SectionUnpickler[PositionUnpickler]("Positions") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
- new PositionUnpickler(reader).unpickle()
+ new PositionUnpickler(reader)
}
}
@@ -36,7 +37,8 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
import DottyUnpickler._
val unpickler = new TastyUnpickler(bytes)
- private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler).get
+ private val posUnpicklerOpt = unpickler.unpickle(new PositionsSectionUnpickler)
+ private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler(posUnpicklerOpt)).get
/** Enter all toplevel classes and objects into their scopes
* @param roots a set of SymDenotations that should be overwritten by unpickling
@@ -44,13 +46,8 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
def enter(roots: Set[SymDenotation])(implicit ctx: Context): Unit =
treeUnpickler.enterTopLevel(roots)
- /** The unpickled trees, and the source file they come from
- * @param readPositions if true, trees get decorated with position information.
- */
- def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = {
- if (readPositions)
- for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler))
- treeUnpickler.usePositions(totalRange, positions)
+ /** The unpickled trees, and the source file they come from. */
+ def body(implicit ctx: Context): List[Tree] = {
treeUnpickler.unpickle()
}
}
diff --git a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
index b0550b70a..63bb00a71 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionPickler.scala
@@ -3,7 +3,8 @@ package dotc
package core
package tasty
-import ast.tpd._
+import ast._
+import ast.Trees._
import ast.Trees.WithLazyField
import TastyFormat._
import core._
@@ -12,64 +13,47 @@ import collection.mutable
import TastyBuffer._
import util.Positions._
-object PositionPickler {
-
- trait DeferredPosition {
- var parentPos: Position = NoPosition
- }
-
- def traverse(x: Any, parentPos: Position, op: (Tree, Position) => Unit)(implicit ctx: Context): Unit =
- if (parentPos.exists)
- x match {
- case x: Tree @unchecked =>
- op(x, parentPos)
- x match {
- case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos, op)
- case _ =>
- }
- traverse(x.productIterator, x.pos, op)
- case x: DeferredPosition =>
- x.parentPos = parentPos
- case xs: TraversableOnce[_] =>
- xs.foreach(traverse(_, parentPos, op))
- case _ =>
- }
-}
-import PositionPickler._
-
-class PositionPickler(pickler: TastyPickler, addrOfTree: Tree => Option[Addr]) {
+class PositionPickler(pickler: TastyPickler, addrOfTree: tpd.Tree => Option[Addr]) {
val buf = new TastyBuffer(5000)
pickler.newSection("Positions", buf)
import buf._
+ import ast.tpd._
+
+ def header(addrDelta: Int, hasStartDelta: Boolean, hasEndDelta: Boolean) = {
+ def toInt(b: Boolean) = if (b) 1 else 0
+ (addrDelta << 2) | (toInt(hasStartDelta) << 1) | toInt(hasEndDelta)
+ }
- def picklePositions(roots: List[Tree], totalRange: Position)(implicit ctx: Context) = {
+ def picklePositions(roots: List[Tree])(implicit ctx: Context) = {
var lastIndex = 0
- def record(tree: Tree, parentPos: Position): Unit =
- if (tree.pos.exists) {
- def msg = s"failure to pickle $tree at ${tree.pos}, parent = $parentPos"
- val endPos = tree.pos.end min parentPos.end
- // end positions can be larger than their parents
- // e.g. in the case of synthetic empty ranges, which are placed at the next token after
- // the current construct.
- val endDelta = endPos - parentPos.end
- val startPos =
- if (endDelta == 0) tree.pos.start max parentPos.start else tree.pos.start min endPos
- // Since end positions are corrected above, start positions have to follow suit.
- val startDelta = startPos - parentPos.start
- if (startDelta != 0 || endDelta != 0)
- for (addr <- addrOfTree(tree)) {
- buf.writeInt(addr.index - lastIndex)
- lastIndex = addr.index
- if (startDelta != 0) buf.writeInt(startDelta)
- if (endDelta != 0) {
- assert(endDelta < 0, msg)
- buf.writeInt(endDelta)
- } else
- assert(startDelta >= 0, msg)
+ var lastPos = Position(0, 0)
+ def pickleDeltas(index: Int, pos: Position) = {
+ val addrDelta = index - lastIndex
+ val startDelta = pos.start - lastPos.start
+ val endDelta = pos.end - lastPos.end
+ buf.writeInt(header(addrDelta, startDelta != 0, endDelta != 0))
+ if (startDelta != 0) buf.writeInt(startDelta)
+ if (endDelta != 0) buf.writeInt(endDelta)
+ lastIndex = index
+ lastPos = pos
+ }
+ def traverse(x: Any, parentPos: Position): Unit = x match {
+ case x: Tree @unchecked =>
+ if (x.pos.exists && x.pos.toSynthetic != parentPos.toSynthetic) {
+ addrOfTree(x) match {
+ case Some(addr) => pickleDeltas(addr.index, x.pos)
+ case _ =>
}
- }
-
- buf.writeNat(totalRange.end)
- traverse(roots, totalRange, record)
+ }
+ x match {
+ case x: MemberDef @unchecked => traverse(x.symbol.annotations, x.pos)
+ case _ =>
+ }
+ traverse(x.productIterator, x.pos)
+ case xs: TraversableOnce[_] =>
+ xs.foreach(traverse(_, parentPos))
+ case _ =>
+ }
+ traverse(roots, NoPosition)
}
}
diff --git a/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
index fa80a2769..c29aeba70 100644
--- a/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/PositionUnpickler.scala
@@ -6,33 +6,31 @@ package tasty
import util.Positions._
import collection.mutable
-import TastyBuffer.Addr
-
-object PositionUnpickler {
- type AddrToPosition = mutable.HashMap[Addr, Position]
-}
+import TastyBuffer.{Addr, NoAddr}
/** Unpickler for tree positions */
class PositionUnpickler(reader: TastyReader) {
- import PositionUnpickler._
import reader._
- def unpickle(): (Position, AddrToPosition) = {
- val positions = new mutable.HashMap[Addr, Position] // Dotty deviation: Can't use new AddrToPosition here. TODO: fix this!
- val sourceLength = readNat()
- def readDelta() = if (isAtEnd) 0 else readInt()
- var curIndex: Addr = Addr(readDelta())
+ private[tasty] lazy val positions = {
+ val positions = new mutable.HashMap[Addr, Position]
+ var curIndex = 0
+ var curStart = 0
+ var curEnd = 0
while (!isAtEnd) {
- val delta1 = readDelta()
- val delta2 = readDelta()
- val (startDelta, endDelta, indexDelta) =
- if (delta2 <= 0) (delta1, -delta2, readDelta())
- else if (delta1 < 0) (0, -delta1, delta2)
- else (delta1, 0, delta2)
- positions(curIndex) = Position(startDelta, endDelta, startDelta)
- // make non-synthetic position; will be made synthetic by normalization.
- curIndex += indexDelta
+ val header = readInt()
+ val addrDelta = header >> 2
+ val hasStart = (header & 2) != 0
+ val hasEnd = (header & 1) != 0
+ curIndex += addrDelta
+ assert(curIndex >= 0)
+ if (hasStart) curStart += readInt()
+ if (hasEnd) curEnd += readInt()
+ positions(Addr(curIndex)) = Position(curStart, curEnd)
}
- (Position(0, sourceLength), positions)
+ positions
}
+
+ def posAt(addr: Addr) = positions.getOrElse(addr, NoPosition)
}
+
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index e9de68e7f..8e8d58b47 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -185,21 +185,16 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t
Category 4 (tags 112-127): tag Nat AST
Category 5 (tags 128-255): tag Length <payload>
-Standard Section: "Positions" sourceLength_Nat Assoc*
-
- Assoc = addr_Delta offset_Delta offset_Delta?
- // addr_Delta :
- // Difference of address to last recorded node.
- // All but the first addr_Deltas are > 0, the first is >= 0.
- // 2nd offset_Delta:
- // Difference of end offset of addressed node vs parent node. Always <= 0
- // 1st offset Delta, if delta >= 0 or 2nd offset delta exists
- // Difference of start offset of addressed node vs parent node.
- // 1st offset Delta, if delta < 0 and 2nd offset delta does not exist:
- // Difference of end offset of addressed node vs parent node.
- // Offsets and addresses are difference encoded.
+Standard Section: "Positions" Assoc*
+
+ Assoc = Header offset_Delta? offset_Delta?
+ Header = addr_Delta + // in one Nat: difference of address to last recorded node << 2 +
+ hasStartDiff + // one bit indicating whether there follows a start address delta << 1
+ hasEndDiff // one bit indicating whether there follows an end address delta
// Nodes which have the same positions as their parents are omitted.
- Delta = Int // Difference between consecutive offsets / tree addresses,
+ // offset_Deltas give difference of start/end offset wrt to the
+ // same offset in the previously recorded node (or 0 for the first recorded node)
+ Delta = Int // Difference between consecutive offsets,
**************************************************************************************/
diff --git a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
index 83e6020d5..98b0dc7c6 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyPickler.scala
@@ -31,7 +31,6 @@ class TastyPickler {
sections += ((nameBuffer.nameIndex(name), buf))
def assembleParts(): Array[Byte] = {
- treePkl.compactify()
def lengthWithLength(buf: TastyBuffer) = {
buf.assemble()
buf.length + natSize(buf.length)
diff --git a/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
index 915ae3f21..7fcd7c29e 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
@@ -113,8 +113,8 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
class PositionSectionUnpickler extends SectionUnpickler[Unit]("Positions") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table): Unit = {
print(s"${reader.endAddr.index - reader.currentAddr.index}")
- val (totalRange, positions) = new PositionUnpickler(reader).unpickle()
- println(s" position bytes in $totalRange:")
+ val positions = new PositionUnpickler(reader).positions
+ println(s" position bytes:")
val sorted = positions.toSeq.sortBy(_._1.index)
for ((addr, pos) <- sorted) println(s"${addr.index}: ${offsetToInt(pos.start)} .. ${pos.end}")
}
diff --git a/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
index e5cacfc00..b6f52c0ec 100644
--- a/src/dotty/tools/dotc/core/tasty/TreePickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreePickler.scala
@@ -7,6 +7,7 @@ import ast.Trees._
import TastyFormat._
import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, StdNames.tpnme, NameOps._
import collection.mutable
+import typer.Inliner
import NameOps._
import TastyBuffer._
import TypeApplications._
@@ -307,7 +308,7 @@ class TreePickler(pickler: TastyPickler) {
if (!tree.isEmpty) pickleTree(tree)
def pickleDef(tag: Int, sym: Symbol, tpt: Tree, rhs: Tree = EmptyTree, pickleParams: => Unit = ())(implicit ctx: Context) = {
- assert(symRefs(sym) == NoAddr)
+ assert(symRefs(sym) == NoAddr, sym)
registerDef(sym)
writeByte(tag)
withLength {
@@ -430,6 +431,15 @@ class TreePickler(pickler: TastyPickler) {
case SeqLiteral(elems, elemtpt) =>
writeByte(REPEATED)
withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
+ case tree: Inlined =>
+ // Why drop Inlined info when pickling?
+ // Since we never inline inside an inlined method, we know that
+ // any code that continas an Inlined tree is not inlined itself.
+ // So position information for inline expansion is no longer needed.
+ // The only reason to keep the inline info around would be to have fine-grained
+ // position information in the linker. We should come back to this
+ // point once we know more what we would do with such information.
+ pickleTree(Inliner.dropInlined(tree))
case TypeTree(original) =>
pickleTpt(tree)
case Bind(name, body) =>
@@ -555,19 +565,19 @@ class TreePickler(pickler: TastyPickler) {
sym.annotations.foreach(pickleAnnotation)
}
- def pickleAnnotation(ann: Annotation)(implicit ctx: Context) = {
- writeByte(ANNOTATION)
- withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) }
- }
+ def pickleAnnotation(ann: Annotation)(implicit ctx: Context) =
+ if (ann.symbol != defn.BodyAnnot) { // inline bodies are reconstituted automatically when unpickling
+ writeByte(ANNOTATION)
+ withLength { pickleType(ann.symbol.typeRef); pickleTree(ann.tree) }
+ }
def pickle(trees: List[Tree])(implicit ctx: Context) = {
trees.foreach(tree => if (!tree.isEmpty) pickleTree(tree))
- assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %")
+ assert(forwardSymRefs.isEmpty, i"unresolved symbols: ${forwardSymRefs.keySet.toList}%, % when pickling ${ctx.source}")
}
def compactify() = {
buf.compactify()
- assert(forwardSymRefs.isEmpty, s"unresolved symbols: ${forwardSymRefs.keySet.toList}%, %")
def updateMapWithDeltas[T](mp: collection.mutable.Map[T, Addr]) =
for (key <- mp.keysIterator.toBuffer[T]) mp(key) = adjusted(mp(key))
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 56bb8498a..09f2c0d1f 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -9,38 +9,23 @@ import util.Positions._
import ast.{tpd, Trees, untpd}
import Trees._
import Decorators._
-import TastyUnpickler._, TastyBuffer._, PositionPickler._
+import TastyUnpickler._, TastyBuffer._
import scala.annotation.{tailrec, switch}
import scala.collection.mutable.ListBuffer
import scala.collection.{ mutable, immutable }
import config.Printers.pickling
/** Unpickler for typed trees
- * @param reader the reader from which to unpickle
- * @param tastyName the nametable
+ * @param reader the reader from which to unpickle
+ * @param tastyName the nametable
+ * @param posUNpicklerOpt the unpickler for positions, if it exists
*/
-class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
+class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table, posUnpicklerOpt: Option[PositionUnpickler]) {
import TastyFormat._
import TastyName._
import TreeUnpickler._
import tpd._
- private var readPositions = false
- private var totalRange = NoPosition
- private var positions: collection.Map[Addr, Position] = _
-
- /** Make a subsequent call to `unpickle` return trees with positions
- * @param totalRange the range position enclosing all returned trees,
- * or NoPosition if positions should not be unpickled
- * @param positions a map from tree addresses to their positions relative
- * to positions of parent nodes.
- */
- def usePositions(totalRange: Position, positions: collection.Map[Addr, Position]): Unit = {
- readPositions = true
- this.totalRange = totalRange
- this.positions = positions
- }
-
/** A map from addresses of definition entries to the symbols they define */
private val symAtAddr = new mutable.HashMap[Addr, Symbol]
@@ -85,10 +70,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
/** The unpickled trees */
def unpickle()(implicit ctx: Context): List[Tree] = {
assert(roots != null, "unpickle without previous enterTopLevel")
- val stats = new TreeReader(reader)
- .readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions))
- normalizePos(stats, totalRange)
- stats
+ new TreeReader(reader).readTopLevel()(ctx.addMode(Mode.AllowDependentFunctions))
}
def toTermName(tname: TastyName): TermName = tname match {
@@ -468,6 +450,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
val isClass = ttag == TEMPLATE
val templateStart = currentAddr
skipTree() // tpt
+ val rhsStart = currentAddr
val rhsIsEmpty = noRhs(end)
if (!rhsIsEmpty) skipTree()
val (givenFlags, annots, privateWithin) = readModifiers(end)
@@ -504,6 +487,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
sym.completer.withDecls(newScope)
forkAt(templateStart).indexTemplateParams()(localContext(sym))
}
+ else if (annots.exists(_.symbol == defn.InlineAnnot))
+ sym.addAnnotation(LazyBodyAnnotation { ctx0 =>
+ implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions)
+ // avoids space leaks by not capturing the current context
+ forkAt(rhsStart).readTerm()
+ })
goto(start)
sym
}
@@ -1010,44 +999,29 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
new LazyReader(localReader, op)
}
-// ------ Hooks for positions ------------------------------------------------
+// ------ Setting positions ------------------------------------------------
- /** Record address from which tree was created as a temporary position in the tree.
- * The temporary position contains deltas relative to the position of the (as yet unknown)
- * parent node. It is marked as a non-synthetic source position.
- */
- def setPos[T <: Tree](addr: Addr, tree: T): T = {
- if (readPositions)
- tree.setPosUnchecked(positions.getOrElse(addr, Position(0, 0, 0)))
- tree
- }
+ /** Set position of `tree` at given `addr`. */
+ def setPos[T <: Tree](addr: Addr, tree: T)(implicit ctx: Context): tree.type =
+ if (ctx.mode.is(Mode.ReadPositions)) {
+ posUnpicklerOpt match {
+ case Some(posUnpickler) => tree.withPos(posUnpickler.posAt(addr))
+ case _ => tree
+ }
+ }
+ else tree
}
- private def setNormalized(tree: Tree, parentPos: Position): Unit =
- tree.setPosUnchecked(
- if (tree.pos.exists)
- Position(parentPos.start + offsetToInt(tree.pos.start), parentPos.end - tree.pos.end)
- else
- parentPos)
-
- def normalizePos(x: Any, parentPos: Position)(implicit ctx: Context): Unit =
- traverse(x, parentPos, setNormalized)
-
- class LazyReader[T <: AnyRef](reader: TreeReader, op: TreeReader => Context => T) extends Trees.Lazy[T] with DeferredPosition {
+ class LazyReader[T <: AnyRef](reader: TreeReader, op: TreeReader => Context => T) extends Trees.Lazy[T] {
def complete(implicit ctx: Context): T = {
pickling.println(i"starting to read at ${reader.reader.currentAddr}")
- val res = op(reader)(ctx.addMode(Mode.AllowDependentFunctions).withPhaseNoLater(ctx.picklerPhase))
- normalizePos(res, parentPos)
- res
+ op(reader)(ctx.addMode(Mode.AllowDependentFunctions).withPhaseNoLater(ctx.picklerPhase))
}
}
- class LazyAnnotationReader(sym: Symbol, reader: TreeReader)
- extends LazyAnnotation(sym) with DeferredPosition {
+ class LazyAnnotationReader(sym: Symbol, reader: TreeReader) extends LazyAnnotation(sym) {
def complete(implicit ctx: Context) = {
- val res = reader.readTerm()(ctx.withPhaseNoLater(ctx.picklerPhase))
- normalizePos(res, parentPos)
- res
+ reader.readTerm()(ctx.withPhaseNoLater(ctx.picklerPhase))
}
}