diff options
Diffstat (limited to 'src/dotty')
19 files changed, 501 insertions, 106 deletions
diff --git a/src/dotty/tools/dotc/config/Settings.scala b/src/dotty/tools/dotc/config/Settings.scala index e8cbaa4ec..adac2ecfd 100644 --- a/src/dotty/tools/dotc/config/Settings.scala +++ b/src/dotty/tools/dotc/config/Settings.scala @@ -7,6 +7,7 @@ import scala.reflect.internal.util.StringOps import reflect.ClassTag import core.Contexts._ import annotation.unchecked +import language.existentials object Settings { diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 4b730a4aa..fd2ce2251 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -16,6 +16,7 @@ import reporting._ import collection.mutable import collection.immutable.BitSet import config.{Settings, Platform, JavaPlatform} +import language.implicitConversions object Contexts { @@ -156,7 +157,6 @@ object Contexts { /** Is the verbose option set? */ def verbose: Boolean = base.settings.verbose.value - /** A condensed context containing essential information of this but * no outer contexts except the initial context. */ @@ -254,6 +254,7 @@ object Contexts { .withSetting(settings.verbose, true) // !!! for now .withSetting(settings.debug, true) .withSetting(settings.Ylogcp, true) + .withSetting(settings.printtypes, true) /** The symbol loaders */ val loaders = new SymbolLoaders diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index d8235b1e4..880182614 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -31,19 +31,22 @@ class Definitions(implicit ctx: Context) { scope.enter(tparam) } - private def specialPolyClass(name: TypeName, flags: FlagSet, parentConstrs: Type*): ClassSymbol = - ctx.newClassSymbolDenoting { cls => - val paramDecls = newScope - val typeParam = newSyntheticTypeParam(cls, paramDecls) - def instantiate(tpe: Type) = - if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.symbolicRef) - else tpe - val parents = parentConstrs.toList map instantiate - val parentRefs: List[TypeRef] = ctx.normalizeToRefs(parents, cls, paramDecls) - ctx.SymDenotation( - cls, ScalaPackageClass, name, flags, - ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls)) + private def specialPolyClass(name: TypeName, flags: FlagSet, parentConstrs: Type*): ClassSymbol = { + val completer = new LazyType { + def complete(denot: SymDenotation): Unit = { + val cls = denot.asClass.classSymbol + val paramDecls = newScope + val typeParam = newSyntheticTypeParam(cls, paramDecls) + def instantiate(tpe: Type) = + if (tpe.typeParams.nonEmpty) tpe.appliedTo(typeParam.symbolicRef) + else tpe + val parents = parentConstrs.toList map instantiate + val parentRefs: List[TypeRef] = ctx.normalizeToRefs(parents, cls, paramDecls) + denot.info = ClassInfo(ScalaPackageClass.thisType, cls, parentRefs, paramDecls) + } } + ctx.newClassSymbol(ScalaPackageClass, name, flags, completer) + } private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = { val arr = new Array[ClassSymbol](arity) diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 14f31a16d..1a8ff3ea8 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -1,5 +1,7 @@ package dotty.tools.dotc.core +import language.implicitConversions + object Flags { /** A FlagSet represents a set of flags. Flags are encoded as follows: @@ -65,13 +67,13 @@ object Flags { def <= (that: FlagSet) = (bits & that.bits) == bits /** This flag set with all flags transposed to be type flags */ - def toTypeFlags = FlagSet(bits & ~KINDFLAGS | TYPES) + def toTypeFlags = if (bits == 0) this else FlagSet(bits & ~KINDFLAGS | TYPES) /** This flag set with all flags transposed to be term flags */ - def toTermFlags = FlagSet(bits & ~KINDFLAGS | TERMS) + def toTermFlags = if (bits == 0) this else FlagSet(bits & ~KINDFLAGS | TERMS) /** This flag set with all flags transposed to be common flags */ - def toCommonFlags = FlagSet(bits | KINDFLAGS) + def toCommonFlags = if (bits == 0) this else FlagSet(bits | KINDFLAGS) /** The number of non-kind flags in this set */ def numFlags: Int = java.lang.Long.bitCount(bits & ~KINDFLAGS) @@ -334,7 +336,8 @@ object Flags { final val ImplClass = typeFlag(54, "<implclass>") /** An existentially bound symbol (Scala 2.x only) */ - final val Scala2Existential = typeFlag(55, "<existential>") + final val Scala2ExistentialCommon = commonFlag(55, "<existential>") + final val Scala2Existential = Scala2ExistentialCommon.toTypeFlags /** An overloaded symbol (Scala 2.x only) */ final val Scala2Overloaded = termFlag(56, "<overloaded>") @@ -354,7 +357,7 @@ object Flags { /** Flags guaranteed to be set upon symbol creation */ final val FromStartFlags = - AccessFlags | Module | Package | Deferred + AccessFlags | Module | Package | Deferred | Param | Scala2ExistentialCommon /** Flags representing access rights */ final val AccessFlags = Private | Protected | Local @@ -367,10 +370,10 @@ object Flags { final val RetainedTypeArgFlags = Covariant | Contravariant | Protected | Local /** Modules always have these flags set */ - final val ModuleCreationFlags = Module + final val ModuleCreationFlags = ModuleVal /** Module classes always have these flags set */ - final val ModuleClassCreationFlags = Module | Final + final val ModuleClassCreationFlags = ModuleClass | Final /** The flags of a type parameter */ final val TypeParamCreationFlags = TypeParam | Protected | Local @@ -393,7 +396,9 @@ object Flags { InConstructor | ImplClass /** Packages and package classes always have these flags set */ - final val PackageCreationFlags = Module | Package | Final | JavaDefined | Static + final val PackageCreationFlags = + (Module | Package | Final | JavaDefined | Static).toTermFlags + final val PackageClassCreationFlags = PackageCreationFlags.toTypeFlags /** These flags are pickled */ final val PickledFlags = flagRange(FirstFlag, FirstNotPickledFlag) diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 1099afb46..f50b44ac8 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -104,7 +104,7 @@ object NameOps { /** The expanded name of `name` relative to this class `base` with given `separator` */ def expandedName(base: Symbol, separator: Name = nme.EXPAND_SEPARATOR)(implicit ctx: Context): N = - name.fromName((base.fullName('$') ++ separator ++ name)).asInstanceOf[N] + name.fromName(base.fullName('$') ++ separator ++ name).asInstanceOf[N] def unexpandedName(separator: Name = nme.EXPAND_SEPARATOR): N = { val idx = name.lastIndexOfSlice(separator) diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala index 0b1d951aa..6e89b2034 100644 --- a/src/dotty/tools/dotc/core/Printers.scala +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -385,8 +385,10 @@ object Printers { val nodeName = node.productPrefix val elems = node.productIterator.map(showElem).mkString(", ") val tpSuffix = - if (ctx.settings.printtypes.value && tree.hasType) s" | ${tree.tpe}" - else "" + if (ctx.settings.printtypes.value && tree.hasType) + s" | ${tree.tpe.asInstanceOf[Type].show}" + else + "" s"$nodeName($elems$tpSuffix)" case _ => diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 68aa2f0fa..1bbeb1009 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -51,6 +51,9 @@ object SymDenotations { private[this] var _privateWithin: Symbol = initPrivateWithin private[this] var _annotations: List[Annotation] = Nil + if (isType) assert(_flags.toTypeFlags == _flags, this.name + " " + _flags) + if (isTerm) assert(_flags.toTermFlags == _flags, this.name + " " + _flags) + /** The owner of the symbol */ def owner: Symbol = _owner @@ -58,8 +61,11 @@ object SymDenotations { final def flags: FlagSet = { ensureCompleted(); _flags } /** Update the flag set */ - private[core] final def flags_=(flags: FlagSet): Unit = + private[core] final def flags_=(flags: FlagSet): Unit = { _flags = flags + if (isType) assert(_flags.toTypeFlags == _flags, this.name) + if (isTerm) assert(_flags.toTermFlags == _flags, this.name) + } /** Set given flags(s) of this denotation */ final def setFlag(flags: FlagSet): Unit = { _flags |= flags } @@ -67,14 +73,15 @@ object SymDenotations { /** UnsSet given flags(s) of this denotation */ final def resetFlag(flags: FlagSet): Unit = { _flags &~= flags } - final def is(fs: FlagSet) = + final def is(fs: FlagSet) = { (if (fs <= FromStartFlags) _flags else flags) is fs + } final def is(fs: FlagSet, butNot: FlagSet) = - (if (fs <= FromStartFlags) _flags else flags) is (fs, butNot) + (if (fs <= FromStartFlags && butNot <= FromStartFlags) _flags else flags) is (fs, butNot) final def is(fs: FlagConjunction) = (if (fs <= FromStartFlags) _flags else flags) is fs final def is(fs: FlagConjunction, butNot: FlagSet) = - (if (fs <= FromStartFlags) _flags else flags) is (fs, butNot) + (if (fs <= FromStartFlags && butNot <= FromStartFlags) _flags else flags) is (fs, butNot) /** The type info. * The info is an instance of TypeType iff this is a type denotation @@ -88,6 +95,7 @@ object SymDenotations { private def completedInfo(completer: LazyType): Type = { if (_flags is CompletionStarted) throw new CyclicReference(this) _flags |= CompletionStarted + println("completing "+this.debugString+"/"+owner.id) // !!! DEBUG completer.complete(this) info } diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index 93e8ed64a..c3b3a944f 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -34,8 +34,10 @@ class SymbolLoaders { /** Enter module with given `name` into scope of `owner`. */ - def enterModule(owner: Symbol, name: PreName, completer: SymbolLoader, flags: FlagSet = EmptyFlags)(implicit ctx: Context): Symbol = { - val module = ctx.newModuleSymbol(owner, name.toTermName, flags, completer, assocFile = completer.sourceFileOrNull) + def enterModule(owner: Symbol, name: PreName, completer: SymbolLoader, modFlags: FlagSet = EmptyFlags, clsFlags: FlagSet = EmptyFlags)(implicit ctx: CondensedContext): Symbol = { + def moduleCompleterFn(modul: TermSymbol, cls: ClassSymbol): LazyType = + new ModuleClassCompleter(modul, completer) + val module = ctx.newModuleSymbol(owner, name.toTermName, modFlags, clsFlags, moduleCompleterFn, assocFile = completer.sourceFileOrNull) enterNew(owner, module, completer) } @@ -65,14 +67,14 @@ class SymbolLoaders { return NoSymbol } } - ctx.newModuleSymbol(owner, pname, PackageCreationFlags, + ctx.newModuleSymbol(owner, pname, PackageCreationFlags, PackageClassCreationFlags, (module, modcls) => new PackageLoader(module, pkg)).entered } /** Enter class and module with given `name` into scope of `owner` * and give them `completer` as type. */ - def enterClassAndModule(owner: Symbol, name: PreName, completer: SymbolLoader, flags: FlagSet = EmptyFlags)(implicit ctx: Context) { + def enterClassAndModule(owner: Symbol, name: PreName, completer: SymbolLoader, flags: FlagSet = EmptyFlags)(implicit ctx: CondensedContext) { val clazz = enterClass(owner, name, completer, flags) val module = enterModule(owner, name, completer, flags) /* @@ -90,7 +92,7 @@ class SymbolLoaders { * with source completer for given `src` as type. * (overridden in interactive.Global). */ - def enterToplevelsFromSource(owner: Symbol, name: PreName, src: AbstractFile)(implicit ctx: Context) { + def enterToplevelsFromSource(owner: Symbol, name: PreName, src: AbstractFile)(implicit ctx: CondensedContext) { enterClassAndModule(owner, name, new SourcefileLoader(src)(ctx.condensed)) } @@ -107,7 +109,7 @@ class SymbolLoaders { /** Initialize toplevel class and module symbols in `owner` from class path representation `classRep` */ - def initializeFromClassPath(owner: Symbol, classRep: ClassPath#ClassRep)(implicit ctx: Context) { + def initializeFromClassPath(owner: Symbol, classRep: ClassPath#ClassRep)(implicit ctx: CondensedContext) { ((classRep.binary, classRep.source): @unchecked) match { case (Some(bin), Some(src)) if needCompile(bin, src) && !binaryOnly(owner, classRep.name) => if (ctx.settings.verbose.value) ctx.inform("[symloader] picked up newer source file for " + src.path) @@ -127,9 +129,9 @@ class SymbolLoaders { */ class PackageLoader(module: TermSymbol, classpath: ClassPath)(implicit val cctx: CondensedContext) extends LazyModuleClassInfo(module) with SymbolLoader { - protected def description = "package loader " + classpath.name + def description = "package loader " + classpath.name - protected override def doComplete(root: SymDenotation) { + def doComplete(root: SymDenotation) { assert(root is PackageClass, root) val pre = root.owner.thisType root.info = ClassInfo(pre, root.symbol.asClass, Nil, newScope, TermRef(pre, module)) @@ -192,14 +194,14 @@ trait SymbolLoader extends LazyType { implicit val cctx: CondensedContext /** Load source or class file for `root`, return */ - protected def doComplete(root: SymDenotation): Unit + def doComplete(root: SymDenotation): Unit def sourceFileOrNull: AbstractFile = null /** Description of the resource (ClassPath, AbstractFile, MsilFile) * being processed by this loader */ - protected def description: String + def description: String override def complete(root: SymDenotation): Unit = { def signalError(ex: Exception) { @@ -235,7 +237,7 @@ class ClassfileLoader(val classfile: AbstractFile)(implicit val cctx: CondensedC override def sourceFileOrNull: AbstractFile = classfile - protected def description = "class file "+ classfile.toString + def description = "class file "+ classfile.toString def rootDenots(rootDenot: ClassDenotation): (ClassDenotation, ClassDenotation) = { val linkedDenot = rootDenot.linkedClass.denot match { @@ -246,14 +248,23 @@ class ClassfileLoader(val classfile: AbstractFile)(implicit val cctx: CondensedC else (rootDenot, linkedDenot) } - protected def doComplete(root: SymDenotation) { + def doComplete(root: SymDenotation) { val (classRoot, moduleRoot) = rootDenots(root.asClass) new ClassfileParser(classfile, classRoot, moduleRoot).run() } } class SourcefileLoader(val srcfile: AbstractFile)(implicit val cctx: CondensedContext) extends SymbolLoader { - protected def description = "source file "+ srcfile.toString + def description = "source file "+ srcfile.toString override def sourceFileOrNull = srcfile - protected def doComplete(root: SymDenotation): Unit = unsupported("doComplete") + def doComplete(root: SymDenotation): Unit = unsupported("doComplete") +} + +class ModuleClassCompleter(modul: TermSymbol, classCompleter: SymbolLoader)(implicit val cctx: CondensedContext) + extends LazyModuleClassInfo(modul) with SymbolLoader { + def description: String = classCompleter.description + override def sourceFileOrNull = classCompleter.sourceFileOrNull + def doComplete(root: SymDenotation): Unit = { + classCompleter.doComplete(root) + } } diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 213ddb765..809265856 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -15,6 +15,7 @@ import Types._, Annotations._, Positions._, StdNames._, Trees._ import Denotations.{ Denotation, SingleDenotation, MultiDenotation } import collection.mutable import io.AbstractFile +import language.implicitConversions /** Creation methods for symbols */ trait Symbols { this: Context => @@ -101,13 +102,12 @@ trait Symbols { this: Context => /** Create a module symbol with associated module class * from its non-info fields and a function producing the info * of the module class (this info may be lazy). - * @param flags The combined flags of the module and the module class - * These are masked with RetainedModuleFlags/RetainedModuleClassFlags. */ def newModuleSymbol( owner: Symbol, name: TermName, - flags: FlagSet, + modFlags: FlagSet, + clsFlags: FlagSet, infoFn: (TermSymbol, ClassSymbol) => Type, privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord, @@ -117,12 +117,10 @@ trait Symbols { this: Context => val module = newNakedSymbol[TermName](coord) val modcls = newNakedClassSymbol(coord, assocFile) val cdenot = SymDenotation( - modcls, owner, name.toTypeName, - flags & RetainedModuleClassFlags | ModuleClassCreationFlags, + modcls, owner, name.toTypeName, clsFlags, infoFn(module, modcls), privateWithin) val mdenot = SymDenotation( - module, owner, name, - flags & RetainedModuleValFlags | ModuleCreationFlags, + module, owner, name, modFlags, if (cdenot.isCompleted) TypeRef(owner.thisType, name.toTypeName, modcls) else new LazyModuleInfo(modcls)(condensed)) module.denot = mdenot @@ -138,14 +136,15 @@ trait Symbols { this: Context => def newCompleteModuleSymbol( owner: Symbol, name: TermName, - flags: FlagSet, + modFlags: FlagSet, + clsFlags: FlagSet, parents: List[TypeRef], decls: Scope, privateWithin: Symbol = NoSymbol, coord: Coord = NoCoord, assocFile: AbstractFile = null): TermSymbol = newModuleSymbol( - owner, name, flags, + owner, name, modFlags, clsFlags, (module, modcls) => ClassInfo( owner.thisType, modcls, parents, decls, TermRef(owner.thisType, name, module)), privateWithin, coord, assocFile) @@ -157,7 +156,7 @@ trait Symbols { this: Context => owner: Symbol, name: TermName, infoFn: (TermSymbol, ClassSymbol) => LazyType): TermSymbol = - newModuleSymbol(owner, name, PackageCreationFlags, infoFn) + newModuleSymbol(owner, name, PackageCreationFlags, PackageClassCreationFlags, infoFn) /** Create a package symbol with associated package class * from its non-info fields its member scope. @@ -165,9 +164,13 @@ trait Symbols { this: Context => def newCompletePackageSymbol( owner: Symbol, name: TermName, - flags: FlagSet = EmptyFlags, + modFlags: FlagSet = EmptyFlags, + clsFlags: FlagSet = EmptyFlags, decls: Scope = newScope): TermSymbol = - newCompleteModuleSymbol(owner, name, flags | PackageCreationFlags, Nil, decls) + newCompleteModuleSymbol( + owner, name, + modFlags | PackageCreationFlags, clsFlags | PackageClassCreationFlags, + Nil, decls) /** Create a stub symbol that will issue a missing reference error @@ -178,7 +181,7 @@ trait Symbols { this: Context => println(s"creating stub for $name") // !!! DEBUG name match { case name: TermName => - newModuleSymbol(owner, name, EmptyFlags, stub, assocFile = file) + newModuleSymbol(owner, name, EmptyFlags, EmptyFlags, stub, assocFile = file) case name: TypeName => newClassSymbol(owner, name, EmptyFlags, stub, assocFile = file) } diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala index a2b134226..bc3d83aa1 100644 --- a/src/dotty/tools/dotc/core/Trees.scala +++ b/src/dotty/tools/dotc/core/Trees.scala @@ -3,6 +3,7 @@ package dotty.tools.dotc.core import Types._, Names._, Flags._, Positions._, Contexts._, Constants._, SymDenotations._, Symbols._ import Denotations._, StdNames._ import annotation.tailrec +import language.higherKinds object Trees { diff --git a/src/dotty/tools/dotc/core/TypedTrees.scala b/src/dotty/tools/dotc/core/TypedTrees.scala index d7179e9ac..bc85961dd 100644 --- a/src/dotty/tools/dotc/core/TypedTrees.scala +++ b/src/dotty/tools/dotc/core/TypedTrees.scala @@ -97,7 +97,7 @@ object TypedTrees { def Apply(fn: Tree, args: List[Tree])(implicit ctx: Context): Apply = { val owntype = fn.tpe.widen match { case fntpe @ MethodType(pnames, ptypes) => - check(sameLength(ptypes, args)) + check(sameLength(ptypes, args), s"${fn.show}: ${fntpe.show} to ${args.map(_.show).mkString(", ")}") fntpe.instantiate(args map (_.tpe)) case _ => check(false) @@ -400,7 +400,7 @@ object TypedTrees { import Trees._ - def check(p: Boolean)(implicit ctx: Context): Unit = assert(p) + def check(p: Boolean, msg: => String = "")(implicit ctx: Context): Unit = assert(p, msg) def checkTypeArg(arg: tpd.Tree, bounds: TypeBounds)(implicit ctx: Context): Unit = { check(arg.isValueType) diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index a5a09a4cd..8699033bd 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -222,7 +222,7 @@ class ClassfileParser( case BOOL_TAG => defn.BooleanType case 'L' => def processInner(tp: Type): Type = tp match { - case tp @ TypeRef(pre, name) if !tp.symbol.isStatic => + case tp @ TypeRef(pre, name) if !(tp.symbol.owner is Flags.ModuleClass) => TypeRef(pre.widen, name) case _ => tp diff --git a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala index 74abf0ed8..ebda07f7f 100644 --- a/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala +++ b/src/dotty/tools/dotc/core/pickling/PickleBuffer.scala @@ -173,19 +173,37 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { private val (scalaTermFlagMap, scalaTypeFlagMap) = { import scala.reflect.internal.Flags._ + + // The following vals are copy-pasted from reflect.internal.Flags. + // They are unfortunately private there, so we cannot get at them directly. + // Using the public method pickledToRawFlags instead looks unattractive + // because of performance. + val IMPLICIT_PKL = (1 << 0) + val FINAL_PKL = (1 << 1) + val PRIVATE_PKL = (1 << 2) + val PROTECTED_PKL = (1 << 3) + val SEALED_PKL = (1 << 4) + val OVERRIDE_PKL = (1 << 5) + val CASE_PKL = (1 << 6) + val ABSTRACT_PKL = (1 << 7) + val DEFERRED_PKL = (1 << 8) + val METHOD_PKL = (1 << 9) + val MODULE_PKL = (1 << 10) + val INTERFACE_PKL = (1 << 11) + val corr = Map( - PROTECTED -> Protected, - OVERRIDE -> Override, - PRIVATE -> Private, - ABSTRACT -> Abstract, - DEFERRED -> Deferred, - FINAL -> Final, - METHOD -> Method, - INTERFACE -> Interface, - MODULE -> Module, - IMPLICIT -> Implicit, - SEALED -> Sealed, - CASE -> Case, + PROTECTED_PKL -> Protected, + OVERRIDE_PKL -> Override, + PRIVATE_PKL -> Private, + ABSTRACT_PKL -> Abstract, + DEFERRED_PKL -> Deferred, + FINAL_PKL -> Final, + METHOD_PKL -> Method, + INTERFACE_PKL -> Interface, + MODULE_PKL -> Module, + IMPLICIT_PKL -> Implicit, + SEALED_PKL -> Sealed, + CASE_PKL -> Case, MUTABLE -> Mutable, PARAM -> Param, PACKAGE -> Package, @@ -243,6 +261,24 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { (chunkMap(termMap), chunkMap(typeMap)) } + /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry} + * Entry = type_Nat length_Nat [actual entries] + * + * Assumes that the ..Version_Nat are already consumed. + * + * @return an array mapping entry numbers to locations in + * the byte array where the entries start. + */ + def createIndex: Array[Int] = { + val index = new Array[Int](readNat()) // nbEntries_Nat + for (i <- 0 until index.length) { + index(i) = readIndex + readByte() // skip type_Nat + readIndex = readNat() + readIndex // read length_Nat, jump to next entry + } + index + } + def unpickleScalaFlags(sflags: Long, isType: Boolean): FlagSet = { val map: FlagMap = if (isType) scalaTypeFlagMap else scalaTermFlagMap val shift = ChunkBits diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index db3370601..c26b33758 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -72,13 +72,25 @@ object UnPickler { * @param moduleroot the top-level module class which is unpickled, or NoSymbol if inapplicable * @param filename filename associated with bytearray, only used for error messages */ -class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: ClassDenotation)(implicit cctx: CondensedContext) +class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(implicit cctx: CondensedContext) extends PickleBuffer(bytes, 0, -1) { + def showPickled() = { + atReadPos(0, () => { + println(s"classRoot = ${classRoot.debugString}, moduleClassRoot = ${moduleClassRoot.debugString}") + util.ShowPickled.printFile(this) + }) + } + + print("unpickling "); showPickled() // !!! DEBUG + import UnPickler._ import cctx.debug + val moduleRoot = moduleClassRoot.sourceModule.denot + println(s"moduleRoot = $moduleRoot, ${moduleRoot.isTerm}") // !!! DEBUG + checkVersion() private val loadingMirror = defn // was: mirrorThatLoaded(classRoot) @@ -116,6 +128,8 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas } i += 1 } + finishCompletion(classRoot) + finishCompletion(moduleClassRoot) // read children last, fix for #3951 i = 0 while (i < index.length) { @@ -138,12 +152,22 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas case ex: BadSignature => throw ex case ex: RuntimeException => + ex.printStackTrace() // !!! DEBUG errorBadSignature(s"a runtime exception occured: $ex $ex.getMessage()") } + def finishCompletion(root: SymDenotation) = { + if (!root.isCompleted) + root.completer match { + case completer: LocalUnpickler => + completer.complete(root) + case _ => + } + } + def source: AbstractFile = { val f = classRoot.symbol.associatedFile - if (f != null) f else moduleRoot.symbol.associatedFile + if (f != null) f else moduleClassRoot.symbol.associatedFile } private def checkVersion() { @@ -157,24 +181,6 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas " in " + source) } - /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry} - * Entry = type_Nat length_Nat [actual entries] - * - * Assumes that the ..Version_Nat are already consumed. - * - * @return an array mapping entry numbers to locations in - * the byte array where the entries start. - */ - def createIndex: Array[Int] = { - val index = new Array[Int](readNat()) // nbEntries_Nat - for (i <- 0 until index.length) { - index(i) = readIndex - readByte() // skip type_Nat - readIndex = readNat() + readIndex // read length_Nat, jump to next entry - } - index - } - /** The `decls` scope associated with given symbol */ protected def symScope(sym: Symbol) = symScopes.getOrElseUpdate(sym, newScope) @@ -231,7 +237,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas protected def isUnpickleRoot(sym: Symbol) = { val d = sym.denot - d == moduleRoot || d == classRoot + d == moduleRoot || d == moduleClassRoot || d == classRoot } /** If entry at <code>i</code> is undefined, define it by performing @@ -344,11 +350,17 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas val owner = readSymbolRef() val flags = unpickleScalaFlags(readLongNat(), name.isTypeName) - def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) - def isModuleRoot = (name.toTermName == moduleRoot.name.toTermName) && (owner == moduleRoot.owner) + def isClassRoot = (name == classRoot.name) && (owner == classRoot.owner) && !(flags is ModuleClass) + def isModuleClassRoot = (name == moduleClassRoot.name) && (owner == moduleClassRoot.owner) && (flags is Module) + def isModuleRoot = (name == moduleClassRoot.name.toTermName) && (owner == moduleClassRoot.owner) && (flags is Module) + + if (isClassRoot) println(s"classRoot of $classRoot found at $readIndex, flags = $flags") // !!! DEBUG + if (isModuleRoot) println(s"moduleRoot of $moduleRoot found at $readIndex, flags = $flags") // !!! DEBUG + if (isModuleClassRoot) println(s"moduleClassRoot of $moduleClassRoot found at $readIndex, flags = $flags") // !!! DEBUG def completeRoot(denot: ClassDenotation): Symbol = { - atReadPos(start.toIndex, () => localUnpickler.parseToCompletion(denot)) + denot.setFlag(flags) + denot.info = new RootUnpickler(start) denot.symbol } @@ -372,11 +384,11 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas cctx.newSymbol(owner, name1, flags1, localUnpickler, coord = start) case CLASSsym => if (isClassRoot) completeRoot(classRoot) - else if (isModuleRoot) completeRoot(moduleRoot) + else if (isModuleClassRoot) completeRoot(moduleClassRoot) else cctx.newClassSymbol(owner, name.asTypeName, flags, localUnpickler, coord = start) case MODULEsym | VALsym => if (isModuleRoot) { - moduleRoot.flags = flags + moduleRoot setFlag flags moduleRoot.symbol } else cctx.newSymbol(owner, name.asTermName, flags, localUnpickler, coord = start) case _ => @@ -384,7 +396,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas }) } - val localUnpickler = new LazyType { + abstract class LocalUnpickler extends LazyType { def parseToCompletion(denot: SymDenotation) = { val tag = readByte() val end = readNat() + readIndex @@ -413,17 +425,25 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas assert(denot is (SuperAccessor | ParamAccessor), denot) def disambiguate(alt: Symbol) = denot.info =:= denot.owner.thisType.memberInfo(alt) - val aliasRef = readNat() - val alias = at(aliasRef, readDisambiguatedSymbol(disambiguate)).asTerm + val alias = readDisambiguatedSymbolRef(disambiguate).asTerm denot.addAnnotation(Annotation.makeAlias(alias)) } } } + def startCoord(denot: SymDenotation): Coord def complete(denot: SymDenotation): Unit = { - atReadPos(denot.symbol.coord.toIndex, () => parseToCompletion(denot)) + atReadPos(startCoord(denot).toIndex, () => parseToCompletion(denot)) } } + object localUnpickler extends LocalUnpickler { + def startCoord(denot: SymDenotation): Coord = denot.symbol.coord + } + + class RootUnpickler(start: Coord) extends LocalUnpickler { + def startCoord(denot: SymDenotation): Coord = start + } + /** Convert * tp { type name = sym } forSome { sym >: L <: H } * to @@ -485,7 +505,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas else ThisType(cls) case SINGLEtpe => val pre = readTypeRef() - val sym = readDisambiguatedSymbol(_.isParameterless) + val sym = readDisambiguatedSymbolRef(_.isParameterless) if (isLocal(sym)) TermRef(pre, sym.asTerm) else TermRef(pre, sym.name.asTermName, NotAMethod) case SUPERtpe => @@ -609,6 +629,9 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas r.asInstanceOf[Symbol] } + protected def readDisambiguatedSymbolRef(p: Symbol => Boolean): Symbol = + at(readNat(), readDisambiguatedSymbol(p)) + protected def readNameRef(): Name = at(readNat(), readName) protected def readTypeRef(): Type = at(readNat(), () => readType()) // after the NMT_TRANSITION period, we can leave off the () => ... () protected def readConstantRef(): Constant = at(readNat(), readConstant) diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index 4b11b415a..cab75cbfd 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -14,22 +14,27 @@ trait Reporting { this: Context => def warning(msg: String, pos: Position = NoPosition): Unit = reporter.warning(msg, pos) def inform(msg: String, pos: Position = NoPosition): Unit = reporter.info(msg, pos) - def log(msg: => String)(implicit ctx: Context): Unit = + def log(msg: => String): Unit = if (true || // !!! for now this.settings.log.value.containsPhase(phase)) inform(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg") - def debuglog(msg: => String)(implicit ctx: Context): Unit = + def debuglog(msg: => String): Unit = if (ctx.debug) log(msg) - def informTime(msg: => String, start: Long)(implicit ctx: Context): Unit = + def informTime(msg: => String, start: Long): Unit = informProgress(msg + elapsed(start)) private def elapsed(start: Long) = " in " + (currentTimeMillis - start) + "ms" - def informProgress(msg: => String)(implicit ctx: Context) = + def informProgress(msg: => String) = if (ctx.settings.verbose.value) inform("[" + msg + "]") + + def trace[T](msg: => String)(value: T) = { + log(msg + " " + value) + value + } } object Reporter { diff --git a/src/dotty/tools/dotc/util/ShowPickled.scala b/src/dotty/tools/dotc/util/ShowPickled.scala new file mode 100644 index 000000000..ab2801127 --- /dev/null +++ b/src/dotty/tools/dotc/util/ShowPickled.scala @@ -0,0 +1,294 @@ +package dotty.tools.dotc +package util + +import java.io.{File, FileInputStream, PrintStream} +import java.lang.Long.toHexString +import java.lang.Float.intBitsToFloat +import java.lang.Double.longBitsToDouble +import scala.reflect.internal.Flags +import scala.reflect.internal.pickling.PickleFormat +import core.pickling.PickleBuffer +import core.Names._ + +object ShowPickled { + import PickleFormat._ + + case class PickleBufferEntry(num: Int, startIndex: Int, tag: Int, bytes: Array[Byte]) { + def isName = tag == TERMname || tag == TYPEname + def hasName = tag match { + case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym | EXTref | EXTMODCLASSref => true + case _ => false + } + def readName = + if (isName) new String(bytes, "UTF-8") + else sys.error("%s is no name" format tagName) + def nameIndex = + if (hasName) readNat(bytes, 0) + else sys.error("%s has no name" format tagName) + + def tagName = tag2string(tag) + override def toString = "%d,%d: %s".format(num, startIndex, tagName) + } + + case class PickleBufferEntryList(entries: IndexedSeq[PickleBufferEntry]) { + def nameAt(idx: Int) = { + val entry = entries(idx) + if (entry.isName) entry.readName + else if (entry.hasName) entries(entry.nameIndex).readName + else "?" + } + } + + def makeEntryList(buf: PickleBuffer, index: Array[Int]) = { + val entries = buf.toIndexedSeq.zipWithIndex map { + case ((tag, data), num) => PickleBufferEntry(num, index(num), tag, data) + } + + PickleBufferEntryList(entries) + } + + def tag2string(tag: Int): String = tag match { + case TERMname => "TERMname" + case TYPEname => "TYPEname" + case NONEsym => "NONEsym" + case TYPEsym => "TYPEsym" + case ALIASsym => "ALIASsym" + case CLASSsym => "CLASSsym" + case MODULEsym => "MODULEsym" + case VALsym => "VALsym" + case EXTref => "EXTref" + case EXTMODCLASSref => "EXTMODCLASSref" + case NOtpe => "NOtpe" + case NOPREFIXtpe => "NOPREFIXtpe" + case THIStpe => "THIStpe" + case SINGLEtpe => "SINGLEtpe" + case CONSTANTtpe => "CONSTANTtpe" + case TYPEREFtpe => "TYPEREFtpe" + case TYPEBOUNDStpe => "TYPEBOUNDStpe" + case REFINEDtpe => "REFINEDtpe" + case CLASSINFOtpe => "CLASSINFOtpe" + case METHODtpe => "METHODtpe" + case POLYtpe => "POLYtpe" + case IMPLICITMETHODtpe => "METHODtpe" // IMPLICITMETHODtpe no longer used. + case SUPERtpe => "SUPERtpe" + case LITERALunit => "LITERALunit" + case LITERALboolean => "LITERALboolean" + case LITERALbyte => "LITERALbyte" + case LITERALshort => "LITERALshort" + case LITERALchar => "LITERALchar" + case LITERALint => "LITERALint" + case LITERALlong => "LITERALlong" + case LITERALfloat => "LITERALfloat" + case LITERALdouble => "LITERALdouble" + case LITERALstring => "LITERALstring" + case LITERALnull => "LITERALnull" + case LITERALclass => "LITERALclass" + case LITERALenum => "LITERALenum" + case SYMANNOT => "SYMANNOT" + case CHILDREN => "CHILDREN" + case ANNOTATEDtpe => "ANNOTATEDtpe" + case ANNOTINFO => "ANNOTINFO" + case ANNOTARGARRAY => "ANNOTARGARRAY" + // case DEBRUIJNINDEXtpe => "DEBRUIJNINDEXtpe" + case EXISTENTIALtpe => "EXISTENTIALtpe" + case TREE => "TREE" + case MODIFIERS => "MODIFIERS" + + case _ => "***BAD TAG***(" + tag + ")" + } + + /** Extremely regrettably, essentially copied from PickleBuffer. + */ + def readNat(data: Array[Byte], index: Int): Int = { + var idx = index + var result = 0L + var b = 0L + do { + b = data(idx) + idx += 1 + result = (result << 7) + (b & 0x7f) + } while((b & 0x80) != 0L) + + result.toInt + } + + def printFile(buf: PickleBuffer, out: PrintStream = System.out) { + out.println("Version " + buf.readNat() + "." + buf.readNat()) + val index = buf.createIndex + val entryList = makeEntryList(buf, index) + buf.readIndex = 0 + + def p(s: String) = out print s + + def printNameRef() { + val idx = buf.readNat() + val name = entryList nameAt idx + val toPrint = " %s(%s)".format(idx, name) + + out print toPrint + } + + def printNat() = p(" " + buf.readNat()) + def printReadNat(x: Int) = p(" " + x) + + def printSymbolRef() = printNat() + def printTypeRef() = printNat() + def printConstantRef() = printNat() + def printAnnotInfoRef() = printNat() + def printConstAnnotArgRef() = printNat() + def printAnnotArgRef() = printNat() + + def printSymInfo(end: Int) { + printNameRef() + printSymbolRef() + val pflags = buf.readLongNat() + def printFlags(privateWithin: Option[Int]) = { + val accessBoundary = ( + for (idx <- privateWithin) yield { + val s = entryList nameAt idx + idx + "(" + s + ")" + } + ) + val flagString = { + val arg1 = Flags.pickledToRawFlags(pflags) + accessBoundary match { + case Some(pw) => Flags.flagsToString(arg1, pw) + case _ => Flags.flagsToString(arg1) + } + } + + out.print(" %s[%s]".format(toHexString(pflags), flagString)) + } + + /** Might be info or privateWithin */ + val x = buf.readNat() + if (buf.readIndex == end) { + printFlags(None) + printReadNat(x) + } + else { + printFlags(Some(x)) + printTypeRef() + } + } + + /** Note: the entries which require some semantic analysis to be correctly + * interpreted are for the most part going to tell you the wrong thing. + * It's not so easy to duplicate the logic applied in the UnPickler. + */ + def printEntry(i: Int) { + buf.readIndex = index(i) + p(i + "," + buf.readIndex + ": ") + val tag = buf.readByte() + out.print(tag2string(tag)) + val len = buf.readNat() + val end = len + buf.readIndex + p(" " + len + ":") + tag match { + case TERMname => + out.print(" ") + out.print(termName(buf.bytes, buf.readIndex, len).toString) + buf.readIndex = end + case TYPEname => + out.print(" ") + out.print(typeName(buf.bytes, buf.readIndex, len)) + buf.readIndex = end + case TYPEsym | ALIASsym | CLASSsym | MODULEsym | VALsym => + printSymInfo(end) + if (tag == CLASSsym && (buf.readIndex < end)) printTypeRef() + case EXTref | EXTMODCLASSref => + printNameRef() + if (buf.readIndex < end) { printSymbolRef() } + case THIStpe => + printSymbolRef() + case SINGLEtpe => + printTypeRef(); printSymbolRef() + case CONSTANTtpe => + printTypeRef(); printConstantRef() + case TYPEREFtpe => + printTypeRef(); printSymbolRef(); buf.until(end, printTypeRef) + case TYPEBOUNDStpe => + printTypeRef(); printTypeRef() + case REFINEDtpe => + printSymbolRef(); buf.until(end, printTypeRef) + case CLASSINFOtpe => + printSymbolRef(); buf.until(end, printTypeRef) + case METHODtpe | IMPLICITMETHODtpe => + printTypeRef(); buf.until(end, printTypeRef) + case POLYtpe => + printTypeRef(); buf.until(end, printSymbolRef) + case LITERALboolean => + out.print(if (buf.readLong(len) == 0L) " false" else " true") + case LITERALbyte => + out.print(" " + buf.readLong(len).toByte) + case LITERALshort => + out.print(" " + buf.readLong(len).toShort) + case LITERALchar => + out.print(" " + buf.readLong(len).toChar) + case LITERALint => + out.print(" " + buf.readLong(len).toInt) + case LITERALlong => + out.print(" " + buf.readLong(len)) + case LITERALfloat => + out.print(" " + intBitsToFloat(buf.readLong(len).toInt)) + case LITERALdouble => + out.print(" " + longBitsToDouble(buf.readLong(len))) + case LITERALstring => + printNameRef() + case LITERALenum => + printSymbolRef() + case LITERALnull => + out.print(" <null>") + case LITERALclass => + printTypeRef() + case CHILDREN => + printSymbolRef(); buf.until(end, printSymbolRef) + case SYMANNOT => + printSymbolRef(); printTypeRef(); buf.until(end, printAnnotArgRef) + case ANNOTATEDtpe => + printTypeRef(); buf.until(end, printAnnotInfoRef); + case ANNOTINFO => + printTypeRef(); buf.until(end, printAnnotArgRef) + case ANNOTARGARRAY => + buf.until(end, printConstAnnotArgRef) + case EXISTENTIALtpe => + printTypeRef(); buf.until(end, printSymbolRef) + + case _ => + } + out.println() + if (buf.readIndex != end) { + out.println("BAD ENTRY END: computed = %d, actual = %d, bytes = %s".format( + end, buf.readIndex, buf.bytes.slice(index(i), (end max buf.readIndex)).mkString(", ") + )) + } + } + + for (i <- 0 until index.length) printEntry(i) + } + +/* + * + def fromFile(path: String) = fromBytes(io.File(path).toByteArray) + def fromName(name: String) = fromBytes(scalaSigBytesForPath(name) getOrElse Array()) + def fromBytes(data: => Array[Byte]): Option[PickleBuffer] = + try Some(new PickleBuffer(data, 0, data.length)) + catch { case _: Exception => None } + + def show(what: String, pickle: PickleBuffer) = { + Console.println(what) + val saved = pickle.readIndex + pickle.readIndex = 0 + printFile(pickle, Console.out) + pickle.readIndex = saved + } + + def main(args: Array[String]) { + args foreach { arg => + (fromFile(arg) orElse fromName(arg)) match { + case Some(pb) => show(arg + ":", pb) + case _ => Console.println("Cannot read " + arg) + } + } + }*/ +} diff --git a/src/dotty/tools/io/ClassPath.scala b/src/dotty/tools/io/ClassPath.scala index 83a7703f4..9e44cc15c 100644 --- a/src/dotty/tools/io/ClassPath.scala +++ b/src/dotty/tools/io/ClassPath.scala @@ -15,6 +15,7 @@ import Jar.isJarOrZip import ClassPath._ import scala.Option.option2Iterable import scala.reflect.io.Path.string2path +import language.postfixOps /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as diff --git a/src/dotty/tools/io/Fileish.scala b/src/dotty/tools/io/Fileish.scala index 4f17ec4d0..0fcb13307 100644 --- a/src/dotty/tools/io/Fileish.scala +++ b/src/dotty/tools/io/Fileish.scala @@ -8,6 +8,7 @@ package io import java.io.{ InputStream } import java.util.jar.JarEntry +import language.postfixOps /** A common interface for File-based things and Stream-based things. * (In particular, io.File and JarEntry.) diff --git a/src/dotty/tools/io/Jar.scala b/src/dotty/tools/io/Jar.scala index 6977f868d..01d30b76f 100644 --- a/src/dotty/tools/io/Jar.scala +++ b/src/dotty/tools/io/Jar.scala @@ -11,7 +11,7 @@ import java.io.{ InputStream, OutputStream, IOException, FileNotFoundException, import java.util.jar._ import scala.collection.JavaConverters._ import Attributes.Name -import scala.language.implicitConversions +import scala.language.{postfixOps, implicitConversions} // Attributes.Name instances: // |