diff options
Diffstat (limited to 'src/dotty/tools')
26 files changed, 734 insertions, 147 deletions
diff --git a/src/dotty/tools/dotc/config/JavaPlatform.scala b/src/dotty/tools/dotc/config/JavaPlatform.scala index ef5fe9475..7f234b613 100644 --- a/src/dotty/tools/dotc/config/JavaPlatform.scala +++ b/src/dotty/tools/dotc/config/JavaPlatform.scala @@ -13,7 +13,7 @@ class JavaPlatform extends Platform { def classPath(implicit ctx: Context): ClassPath = { if (currentClassPath.isEmpty) - currentClassPath = Some(new PathResolver(ctx).result) + currentClassPath = Some(new PathResolver(ctx.condensed).result) currentClassPath.get } diff --git a/src/dotty/tools/dotc/config/PathResolver.scala b/src/dotty/tools/dotc/config/PathResolver.scala index 97ea4525e..3aa42defb 100644 --- a/src/dotty/tools/dotc/config/PathResolver.scala +++ b/src/dotty/tools/dotc/config/PathResolver.scala @@ -135,7 +135,7 @@ object PathResolver { def fromPathString(path: String)(implicit cctx: CondensedContext): JavaClassPath = { val settings = cctx.settings.classpath.update(path) - new PathResolver()(cctx.fresh.withSettings(settings)).result + new PathResolver(cctx.fresh.withSettings(settings)).result } /** With no arguments, show the interesting values in Environment and Defaults. @@ -152,7 +152,7 @@ object PathResolver { val ArgsSummary(sstate, rest, errors) = cctx.settings.processArguments(args.toList, true) errors.foreach(println) - val pr = new PathResolver()(cctx.fresh.withSettings(sstate)) + val pr = new PathResolver(cctx.fresh.withSettings(sstate)) println(" COMMAND: 'scala %s'".format(args.mkString(" "))) println("RESIDUAL: 'scala %s'\n".format(rest.mkString(" "))) pr.result.show @@ -161,7 +161,8 @@ object PathResolver { } import PathResolver.{ Defaults, Environment, firstNonEmpty, ppcp } -class PathResolver(implicit cctx: CondensedContext) { +class PathResolver(cctx: CondensedContext) { + implicit def ctx: Context = cctx import cctx.base.settings val context = ClassPath.DefaultJavaContext @@ -257,7 +258,7 @@ class PathResolver(implicit cctx: CondensedContext) { lazy val result: JavaClassPath = { val cp = new JavaClassPath(containers.toIndexedSeq, context) if (settings.Ylogcp.value) { - Console.println("Classpath built from " + settings.toConciseString(cctx.sstate)) + Console.println("Classpath built from " + settings.toConciseString(ctx.sstate)) Console.println("Defaults: " + PathResolver.Defaults) Console.println("Calculated: " + Calculated) diff --git a/src/dotty/tools/dotc/config/Settings.scala b/src/dotty/tools/dotc/config/Settings.scala index c1ac1f83a..1f96be342 100644 --- a/src/dotty/tools/dotc/config/Settings.scala +++ b/src/dotty/tools/dotc/config/Settings.scala @@ -40,7 +40,7 @@ object Settings { def fail(msg: String) = ArgsSummary(sstate, arguments, errors :+ msg) - } + } case class Setting[T: ClassTag] private[Settings] ( name: String, @@ -214,6 +214,7 @@ object Settings { setting } + def BooleanSetting(name: String, descr: String): Setting[Boolean] = publish(Setting(name, descr, false)) diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala index 3c8e02d8f..ff05c9faa 100644 --- a/src/dotty/tools/dotc/core/Annotations.scala +++ b/src/dotty/tools/dotc/core/Annotations.scala @@ -9,6 +9,9 @@ object Annotations { def symbol(implicit ctx: Context): Symbol = tree.tpe.typeSymbol def matches(cls: Symbol)(implicit ctx: Context): Boolean = symbol.isNonBottomSubClass(cls) def appliesToModule: Boolean = true // for now; see remark in SymDenotations + + def derivedAnnotation(tree: Tree) = + if (tree eq this.tree) this else Annotation(tree) } case class ConcreteAnnotation(val tree: Tree) extends Annotation @@ -42,12 +45,6 @@ object Annotations { apply(defn.ChildAnnot, List(Ident(NamedType(sym.owner.thisType, sym.name)))) } - def makeLiteralAnnotArg(const: Constant): Tree = ??? - - def makeArrayAnnotArg(elems: Array[Tree]): Tree = ??? - - def makeNestedAnnotArg(annot: Annotation): Tree = annot.tree - def ThrowsAnnotation(cls: ClassSymbol)(implicit ctx: Context) = Annotation(defn.ThrowsAnnot, Ident(cls.symbolicRef)) }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 388ae60ce..ff9d3c454 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package core import Decorators._ @@ -8,8 +9,10 @@ import Phases._ import Types._ import Symbols._ import TypeComparers._, Printers._, NameOps._, SymDenotations._, Positions._ +import TypedTrees.tpd._ import config.Settings._ import config.ScalaSettings +import reporting._ import collection.mutable import collection.immutable.BitSet import config.{Settings, Platform, JavaPlatform} @@ -38,17 +41,26 @@ object Contexts { abstract class Context extends Periods with Substituters with TypeOps + with Phases with Printers with Symbols with SymDenotations - with Cloneable { + with Reporting + with Cloneable { thiscontext => implicit val ctx: Context = this val base: ContextBase - private[this] var _underlying: Context = _ - protected def underlying_=(underlying: Context) = _underlying = underlying - def underlying: Context = _underlying + def outersIterator = new Iterator[Context] { + var current = thiscontext + def hasNext = current != NoContext + def next = { val c = current; current = current.outer; c } + } + + + private[this] var _outer: Context = _ + protected def outer_=(outer: Context) = _outer = outer + def outer: Context = _outer private[this] var _period: Period = _ protected def period_=(period: Period) = _period = period @@ -62,8 +74,8 @@ object Contexts { protected def typeComparer_=(typeComparer: TypeComparer) = _typeComparer = typeComparer def typeComparer: TypeComparer = { - if ((_typeComparer eq underlying.typeComparer) && - (constraints ne underlying.constraints)) + if ((_typeComparer eq outer.typeComparer) && + (constraints ne outer.constraints)) _typeComparer = new TypeComparer(this) _typeComparer } @@ -80,8 +92,6 @@ object Contexts { protected def refinedPrinter_=(refinedPrinter: Context => Printer) = _refinedPrinter = refinedPrinter def refinedPrinter: Context => Printer = _refinedPrinter - def printer = if (base.settings.debug.value) plainPrinter else refinedPrinter - private[this] var _owner: Symbol = _ protected def owner_=(owner: Symbol) = _owner = owner def owner: Symbol = _owner @@ -90,17 +100,26 @@ object Contexts { protected def sstate_=(sstate: SettingsState) = _sstate = sstate def sstate: SettingsState = _sstate - def phase: Phase = ??? // phase(period.phaseId) - def enclClass: Context = ??? - def erasedTypes: Boolean = ??? - def debug: Boolean = ??? - def error(msg: String): Unit = ??? - def warning(msg: String): Unit = ??? - def log(msg: String): Unit = ??? - def debuglog(msg: String): Unit = ??? - def inform(msg: String) = ??? - def informTime(msg: String, start: Long): Unit = ??? - def beforeTyper[T](op: => T): T = ??? + private[this] var _tree: Tree = _ + protected def tree_=(tree: Tree) = _tree = tree + def tree: Tree = _tree + + private[this] var _reporter: Reporter = _ + protected def reporter_=(reporter: Reporter) = _reporter = reporter + def reporter: Reporter = _reporter + + /** The next outer context whose tree is a template or package definition */ + def enclTemplate: Context = { + var c = this + while (c != NoContext && !c.tree.isInstanceOf[Template] && !c.tree.isInstanceOf[PackageDef]) + c = c.outer + c + } + + def source = io.NoSource // for now + + def erasedTypes: Boolean = phase.erasedTypes + def debug: Boolean = base.settings.debug.value private var _condensed: CondensedContext = null def condensed: CondensedContext = { @@ -115,7 +134,7 @@ object Contexts { def fresh: FreshContext = { val newctx = super.clone.asInstanceOf[FreshContext] - newctx.underlying = this + newctx.outer = this newctx._condensed = null newctx } @@ -131,16 +150,20 @@ object Contexts { def withRefinedPrinter(printer: Context => Printer): this.type = { this.refinedPrinter = printer; this } def withOwner(owner: Symbol): this.type = { this.owner = owner; this } def withSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this } + def withTree(tree: Tree): this.type = { this.tree = tree; this } + def withReporter(reporter: Reporter): this.type = { this.reporter = reporter; this } def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this } } private class InitialContext(val base: ContextBase) extends FreshContext { - underlying = NoContext + outer = NoContext period = Nowhere constraints = Map() plainPrinter = new PlainPrinter(_) refinedPrinter = new RefinedPrinter(_) owner = NoSymbol + tree = EmptyTree + reporter = new ConsoleReporter } object NoContext extends Context { @@ -150,7 +173,8 @@ object Contexts { class ContextBase extends ContextState with Transformers.TransformerBase with Printers.PrinterBase - with Denotations.DenotationsBase { + with Denotations.DenotationsBase + with Phases.PhasesBase { val settings = new ScalaSettings @@ -208,6 +232,10 @@ object Contexts { // TypeOps state private[core] var volatileRecursions: Int = 0 private[core] val pendingVolatiles = new mutable.HashSet[Type] + + // Phases state + private[core] var phases = new Array[Phase](MaxPossiblePhaseId + 1) + private[core] var nphases = 0 } object Context { diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index b45c1ee76..af8704258 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -3,8 +3,7 @@ package core import annotation.tailrec import Symbols._ - -import Contexts._, Names._ +import Contexts._, Names._, Phases._ object Decorators { @@ -43,5 +42,10 @@ object Decorators { loop(xs, 0) } } + + implicit class PhaseListDecorator(val names: List[String]) extends AnyVal { + def containsPhase(phase: Phase) = + names exists (phase.name.startsWith) + } } diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index efed9392d..0245928b2 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -149,6 +149,7 @@ class Definitions(implicit ctx: Context) { def NullType: Type = NullClass.typeConstructor def SeqType: Type = SeqClass.typeConstructor def ArrayType: Type = ArrayClass.typeConstructor + def ObjectArrayType = ArrayType.appliedTo(ObjectType) def UnitType: Type = UnitClass.typeConstructor def BooleanType: Type = BooleanClass.typeConstructor @@ -230,13 +231,27 @@ class Definitions(implicit ctx: Context) { // ----- Initialization --------------------------------------------------- + /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ + lazy val syntheticCoreClasses = List( + AnnotationDefaultAnnot, // #2264 + RepeatedParamClass, + JavaRepeatedParamClass, + ByNameParamClass, + AnyClass, + AnyRefAlias, + AnyValClass, + NullClass, + NothingClass, + SingletonClass, + EqualsPatternClass) + private[this] var _isInitialized = false def isInitialized = _isInitialized def init() = if (!_isInitialized) { // force initialization of every symbol that is synthesized or hijacked by the compiler - val forced = ??? + val forced = syntheticCoreClasses _isInitialized = true } } diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index 84564e7c7..b42854f69 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -141,10 +141,10 @@ object Denotations { def isOverloaded = isInstanceOf[MultiDenotation] /** The signature of the denotation */ - def signature: Signature + def signature(implicit ctx: Context): Signature /** Resolve overloaded denotation to pick the one with the given signature */ - def atSignature(sig: Signature): SingleDenotation + def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation /** The variant of this denotation that's current in the given context. */ def current(implicit ctx: Context): Denotation @@ -158,7 +158,7 @@ object Denotations { def orElse(that: => Denotation) = if (this.exists) this else that /** The set of alternative single-denotations making up this denotation */ - def alts(p: Symbol => Boolean)(implicit ctx: Context): List[SingleDenotation] = + def alternatives(implicit ctx: Context): List[SingleDenotation] = altsWith(scala.Function.const(true)) /** The alternatives of this denotation that satisfy the predicate `p`. */ @@ -290,7 +290,7 @@ object Denotations { if ((d1 eq denot1) && (d2 eq denot2)) this else MultiDenotation(d1, d2) def symbol = unsupported("symbol") def info = unsupported("info") - def signature = unsupported("signature") + def signature(implicit ctx: Context) = unsupported("signature") def firstSym(implicit ctx: Context): Symbol = denot1.firstSym orElse denot2.firstSym def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[SingleDenotation] = denot1.altsWith(p) ++ denot2.altsWith(p) @@ -304,7 +304,7 @@ object Denotations { } def hasAltWith(p: Symbol => Boolean)(implicit ctx: Context): Boolean = denot1.hasAltWith(p) || denot2.hasAltWith(p) - def atSignature(sig: Signature): SingleDenotation = + def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation = denot1.atSignature(sig) orElse denot2.atSignature(sig) def validFor = denot1.validFor & denot2.validFor def current(implicit ctx: Context): Denotation = @@ -313,7 +313,7 @@ object Denotations { abstract class SingleDenotation extends Denotation with DenotationSet { override def isType = info.isInstanceOf[TypeType] - override def signature: Signature = { + override def signature(implicit ctx: Context): Signature = { def sig(tp: Type): Signature = tp match { case tp: PolyType => tp.resultType match { @@ -334,7 +334,7 @@ object Denotations { def orElse(that: => SingleDenotation) = if (this.exists) this else that - def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[SingleDenotation] = + def altsWith(p: Symbol => Boolean)(implicit ctx: Context): List[SingleDenotation] = if (p(symbol)) this :: Nil else Nil def suchThat(p: Symbol => Boolean)(implicit ctx: Context): SingleDenotation = @@ -343,7 +343,7 @@ object Denotations { def hasAltWith(p: Symbol => Boolean)(implicit ctx: Context): Boolean = p(symbol) - def atSignature(sig: Signature): SingleDenotation = + def atSignature(sig: Signature)(implicit ctx: Context): SingleDenotation = if (sig == signature) this else NoDenotation // ------ Transformations ----------------------------------------- diff --git a/src/dotty/tools/dotc/core/Periods.scala b/src/dotty/tools/dotc/core/Periods.scala index 3a91b48cb..f524c8a99 100644 --- a/src/dotty/tools/dotc/core/Periods.scala +++ b/src/dotty/tools/dotc/core/Periods.scala @@ -11,17 +11,17 @@ abstract class Periods extends DotClass { self: Context => import Periods._ /** The current phase identifier */ - def phaseId = period.phaseId + def phaseId: Int = period.phaseId /** The current run identifier */ - def runId = period.runId + def runId: Int = period.runId /** Execute `op` at given period */ - def atPeriod[T](pd: Period)(op: Context => T) = + def atPeriod[T](pd: Period)(op: Context => T): T = op(ctx.fresh.withPeriod(pd)) /** Execute `op` at given phase id */ - def atPhase[T](pid: PhaseId)(op: Context => T) = + def atPhase[T](pid: PhaseId)(op: Context => T): T = op(ctx.fresh.withPhase(pid)) } @@ -117,5 +117,5 @@ object Periods { /** The number of bits needed to encode a phase identifier. */ final val PhaseWidth = 5 final val PhaseMask = (1 << PhaseWidth) - 1 - + final val MaxPossiblePhaseId = PhaseMask }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index f9b8eaa9f..02d9c9749 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -1,11 +1,91 @@ package dotty.tools.dotc package core +import Periods._, Contexts._ + +trait Phases { self: Context => + import Phases._ + + def phase: Phase = base.phases(period.phaseId) + + def phasesStack: List[Phase] = + if (phase == this.NoPhase) Nil + else phase :: outersIterator.dropWhile(_.phase == phase).next.phasesStack + + /** Execute `op` at given phase id */ + def atPhase[T](phase: Phase)(op: Context => T): T = + atPhase(phase.id)(op) + + def atPhaseNotLaterThan[T](limit: Phase)(op: Context => T): T = + if (!limit.exists || phase <= limit) op(this) else atPhase(limit)(op) + + def atPhaseNotLaterThanTyper[T](op: Context => T): T = + atPhaseNotLaterThan(base.typerPhase)(op) +} + object Phases { - abstract class Phase { - def erasedTypes: Boolean + trait PhasesBase { this: ContextBase => + + lazy val allPhases = phases.slice(FirstPhaseId, nphases) + + val NoPhase = new Phase(initialCtx) { + def name = "<no phase>" + def run() { throw new Error("NoPhase.run") } + } +/* + object SomePhase extends Phase { + def name = "<some phase>" + def run() { throw new Error("SomePhase.run") } + } +*/ + def phaseNamed(name: String) = + allPhases.find(_.name == name).getOrElse(NoPhase) + + final val typerName = "typer" + final val refchecksName = "refchecks" + final val erasureName = "erasure" + final val flattenName = "flatten" + + lazy val typerPhase = phaseNamed(typerName) + lazy val refchecksPhase = phaseNamed(refchecksName) + lazy val erasurePhase = phaseNamed(erasureName) + lazy val flattenPhase = phaseNamed(flattenName) } + abstract class Phase(initctx: Context) { + + val id: Int = initctx.nphases + initctx.nphases += 1 + def name: String + + def run(): Unit + + def description: String = name + + def checkable: Boolean = true + + final def exists: Boolean = id != NoPhaseId + + final def <= (that: Phase) = + exists && id <= that.id + + final def prev(implicit ctx: Context): Phase = + if (id > FirstPhaseId) ctx.phases(id - 1) else initctx.NoPhase + + final def next(implicit ctx: Context): Phase = + if (hasNext) ctx.phases(id + 1) else initctx.NoPhase + + final def hasNext(implicit ctx: Context) = id + 1 < ctx.nphases + + final def iterator(implicit ctx: Context) = + Iterator.iterate(this)(_.next) takeWhile (_.hasNext) + + final def erasedTypes(implicit ctx: Context): Boolean = ctx.erasurePhase <= this + final def flatClasses(implicit ctx: Context): Boolean = ctx.flattenPhase <= this + final def refChecked (implicit ctx: Context): Boolean = ctx.refchecksPhase <= this + + override def toString = name + } }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Positions.scala b/src/dotty/tools/dotc/core/Positions.scala index 1d455e6f2..e16f6abe1 100644 --- a/src/dotty/tools/dotc/core/Positions.scala +++ b/src/dotty/tools/dotc/core/Positions.scala @@ -20,6 +20,7 @@ object Positions { if (this == NoPosition) that else if (that == NoPosition) this else Position(this.start min that.start, this.end max that.end) + def exists = this != NoPosition } def Position(start: Int, end: Int, pointOffset: Int = 0): Position = diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala index 3a9aaeb5b..b65161c64 100644 --- a/src/dotty/tools/dotc/core/Printers.scala +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -10,6 +10,8 @@ trait Printers { this: Context => import Printers._ + def printer = if (base.settings.debug.value) plainPrinter else refinedPrinter + private var _diagnostics: Option[StringBuilder] = _ protected def diagnostics_=(diagnostics: Option[StringBuilder]) = _diagnostics = diagnostics @@ -203,8 +205,8 @@ object Printers { } case PolyParam(pt, n) => show(pt.paramNames(n)) - case AnnotatedType(annots, tpe) => - showLocal(tpe) + " " + annots.map(show).mkString(" ") + case AnnotatedType(annot, tpe) => + showLocal(tpe) + " " + show(annot) } } @@ -377,7 +379,7 @@ object Printers { case _ => String.valueOf(const.value) } - def show(annot: Annotation): String = ??? + def show(annot: Annotation): String = s"@${annot.symbol.name}" // for now def show(syms: List[Symbol], sep: String): String = syms map (_.showDcl) mkString sep diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index ee442223d..798f21d76 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -51,7 +51,7 @@ object Scopes { protected[Scopes] def this(base: Scope)(implicit ctx: Context) = { this(base.lastEntry, base.size, base.nestingLevel + 1) - ensureCapacity(MinHash)(ctx) // WTH??? it seems the implicit is not in scope for a secondary constructor call. + ensureCapacity(MinHash)(ctx) // WTH? it seems the implicit is not in scope for a secondary constructor call. } def this() = this(null, 0, 0) diff --git a/src/dotty/tools/dotc/core/Substituters.scala b/src/dotty/tools/dotc/core/Substituters.scala index 33dd14b8e..d4ead33b1 100644 --- a/src/dotty/tools/dotc/core/Substituters.scala +++ b/src/dotty/tools/dotc/core/Substituters.scala @@ -13,7 +13,7 @@ trait Substituters { this: Context => if (tp.binder eq from) tp.copy(to.asInstanceOf[tp.BT]) else tp case tp: NamedType => if (tp.symbol.isStatic) tp - else tp.derivedNamedType(subst(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(subst(tp.prefix, from, to, map)) case _: ThisType | NoPrefix => tp case tp: RefinedType => @@ -29,7 +29,7 @@ trait Substituters { this: Context => val sym = tp.symbol if (sym eq from) return to if (sym.isStatic && !from.isStatic) tp - else tp.derivedNamedType(subst1(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(subst1(tp.prefix, from, to, map)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -47,7 +47,7 @@ trait Substituters { this: Context => if (sym eq from1) return to1 if (sym eq from2) return to2 if (sym.isStatic && !from1.isStatic && !from2.isStatic) tp - else tp.derivedNamedType(subst2(tp.prefix, from1, to1, from2, to2, map), tp.name) + else tp.derivedNamedType(subst2(tp.prefix, from1, to1, from2, to2, map)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -70,7 +70,7 @@ trait Substituters { this: Context => ts = ts.tail } if (sym.isStatic && !existsStatic(from)) tp - else tp.derivedNamedType(subst(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(subst(tp.prefix, from, to, map)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -93,7 +93,7 @@ trait Substituters { this: Context => ts = ts.tail } if (sym.isStatic && !existsStatic(from)) tp - else tp.derivedNamedType(substSym(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(substSym(tp.prefix, from, to, map)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -109,7 +109,7 @@ trait Substituters { this: Context => if (clazz eq from) to else tp case tp: NamedType => if (tp.symbol.isStatic) tp - else tp.derivedNamedType(substThis(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(substThis(tp.prefix, from, to, map)) case _: BoundType | NoPrefix => tp case tp: RefinedType => @@ -125,7 +125,7 @@ trait Substituters { this: Context => if (rt eq from) to else tp case tp: NamedType => if (tp.symbol.isStatic) tp - else tp.derivedNamedType(substThis(tp.prefix, from, to, map), tp.name) + else tp.derivedNamedType(substThis(tp.prefix, from, to, map)) case _: ThisType | _: BoundType | NoPrefix => tp case tp: RefinedType => diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 67a1e1d03..830ceba1a 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -93,6 +93,9 @@ object SymDenotations { /** Make sure this denotation is completed */ final def ensureCompleted(): Unit = info + /** The completer of this denotation. @pre: Denotation is not yet completed */ + def completer: LazyType = _info.asInstanceOf[LazyType] + /** The privateWithin boundary, NoSymbol if no boundary is given. */ def privateWithin: Symbol = { ensureCompleted(); _privateWithin } @@ -335,7 +338,7 @@ object SymDenotations { if (!cls.exists) fail( s"""Access to protected $this not permitted because - |enclosing ${ctx.enclClass.owner.showLocated} is not a subclass of + |enclosing ${ctx.enclTemplate.owner.showLocated} is not a subclass of |${owner.showLocated} where target is defined""".stripMargin) else if (!(isType || // allow accesses to types from arbitrary subclasses fixes #4737 pre.widen.typeSymbol.isSubClassOrCompanion(cls) || diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index 85fb8037d..5b5bf0078 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -11,6 +11,7 @@ import java.io.IOException import scala.compat.Platform.currentTime import dotty.tools.io.{ ClassPath, AbstractFile } import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, Positions._, Names._ +import StdNames._ import Decorators.StringDecorator import pickling.ClassfileParser @@ -85,7 +86,7 @@ class SymbolLoaders { * (overridden in interactive.Global). */ def enterToplevelsFromSource(owner: Symbol, name: PreName, src: AbstractFile)(implicit ctx: Context) { - ??? // !!! enterClassAndModule(owner, name, new SourcefileLoader(src)) + enterClassAndModule(owner, name, new SourcefileLoader(src)(ctx.condensed)) } /** The package objects of scala and scala.reflect should always @@ -134,12 +135,44 @@ class SymbolLoaders { for (pkg <- classpath.packages) { enterPackage(root.symbol, pkg.name, new PackageLoader(pkg)) } - openPackageModule(root.symbol) + openPackageModule(root.symbol.asClass) } } } - def openPackageModule(pkgClass: Symbol): Unit = ??? + /** if there's a `package` member object in `pkgClass`, enter its members into it. */ + def openPackageModule(pkgClass: ClassSymbol)(implicit ctx: Context) { + val pkgModule = pkgClass.info.decl(nme.PACKAGEkw).symbol + if (pkgModule.isModule && + (pkgModule.isCompleted || + !pkgModule.completer.isInstanceOf[SourcefileLoader])) + // println("open "+pkgModule)//DEBUG + openPackageModule(pkgModule, pkgClass) + } + + def openPackageModule(container: Symbol, dest: ClassSymbol)(implicit ctx: Context) { + // unlink existing symbols in the package + for (member <- container.info.decls.iterator) { + if (!(member is Private) && !member.isConstructor) { + // todo: handle overlapping definitions in some way: mark as errors + // or treat as abstractions. For now the symbol in the package module takes precedence. + for (existing <- dest.info.decl(member.name).alternatives) + dest.delete(existing.symbol) + } + } + // enter non-private decls in the class + for (member <- container.info.decls.iterator) { + if (!(member is Private) && !member.isConstructor) { + dest.enter(member) + } + } + // enter decls of parent classes + for (p <- container.info.parents) { + if (p.symbol != defn.ObjectClass) { + openPackageModule(p.symbol, dest) + } + } + } } /** A lazy type that completes itself by calling parameter doComplete. * Any linked modules/classes or module classes are also initialized. @@ -203,41 +236,9 @@ class ClassfileLoader(val classfile: AbstractFile)(implicit val cctx: CondensedC new ClassfileParser(classfile, classRoot, moduleRoot).run() } } -/* - class MsilFileLoader(msilFile: MsilFile) extends SymbolLoader with FlagAssigningCompleter { - private def typ = msilFile.msilType - private object typeParser extends clr.TypeParser { - val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - } - - protected def description = "MsilFile "+ typ.FullName + ", assembly "+ typ.Assembly.FullName - protected def doComplete(root: Symbol) { typeParser.parse(typ, root) } - } - - class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader with FlagAssigningCompleter { - protected def description = "source file "+ srcfile.toString - override def fromSource = true - override def sourcefile = Some(srcfile) - protected def doComplete(root: Symbol): Unit = global.currentRun.compileLate(srcfile) - } - - object moduleClassLoader extends SymbolLoader with FlagAssigningCompleter { - protected def description = "module class loader" - protected def doComplete(root: Symbol) { root.sourceModule.initialize } - } - - object clrTypes extends clr.CLRTypes { - val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - if (global.forMSIL) init() - } - - /** used from classfile parser to avoid cyclies */ - var parentsLevel = 0 - var pendingLoadActions: List[() => Unit] = Nil -} -object SymbolLoadersStats { - import scala.reflect.internal.TypesStats.typerNanos - val classReadNanos = Statistics.newSubTimer ("time classfilereading", typerNanos) +class SourcefileLoader(val srcfile: AbstractFile)(implicit val cctx: CondensedContext) extends SymbolLoader { + protected def description = "source file "+ srcfile.toString + override def sourceFileOrNull = srcfile + protected def doComplete(root: SymDenotation): Unit = unsupported("doComplete") } -*/
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/TypedTrees.scala b/src/dotty/tools/dotc/core/TypedTrees.scala index 49d062330..f73c0fc87 100644 --- a/src/dotty/tools/dotc/core/TypedTrees.scala +++ b/src/dotty/tools/dotc/core/TypedTrees.scala @@ -168,6 +168,9 @@ object TypedTrees { def SeqLiteral(elemtpt: Tree, elems: List[Tree])(implicit ctx: Context): SeqLiteral = Trees.SeqLiteral(elemtpt, elems).withType(defn.RepeatedParamType.appliedTo(elemtpt.tpe)).checked + def SeqLiteral(elems: List[Tree])(implicit ctx: Context): SeqLiteral = + SeqLiteral(TypeTree(ctx.lub(elems map (_.tpe))), elems) + def TypeTree(tp: Type, original: Tree = EmptyTree)(implicit ctx: Context): TypeTree = Trees.TypeTree(original).withType(tp).checked @@ -276,7 +279,7 @@ object TypedTrees { Trees.PackageDef(pid, stats).withType(refType(pid.symbol)).checked def Annotated(annot: Tree, arg: Tree)(implicit ctx: Context): Annotated = - Trees.Annotated(annot, arg).withType(AnnotatedType(List(Annotation(annot)), arg.tpe)).checked + Trees.Annotated(annot, arg).withType(AnnotatedType(Annotation(annot), arg.tpe)).checked val EmptyTree: Tree = Trees.EmptyTree[Type] diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 292f78d8e..69df1275f 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -12,7 +12,9 @@ import Contexts._ import Annotations._ import SymDenotations._ import Denotations._ -import Periods._, Trees._ +import Periods._ +import TypedTrees.tpd._, TypedTrees.TreeMapper +import transform.Erasure._ import scala.util.hashing.{ MurmurHash3 => hashing } import collection.mutable @@ -41,13 +43,13 @@ object Types { * | | +--- MethodParam * | | +--- RefinedThis * | | +--- NoPrefix + * | +- PolyParam + * | +- RefinedType * | +- TypeBounds * | +- ExprType * | +- AnnotatedType * | - * +- GroundType -+- PolyParam - * +- RefinedType - * +- AndType + * +- GroundType -+- AndType * +- OrType * +- MethodType -----+- ImplicitMethodType * | +- JavaMethodType @@ -269,6 +271,15 @@ object Types { case _ => List() } + /** If this is an alias type, its alias, otherwise the type itself */ + def dealias(implicit ctx: Context): Type = this match { + case tp: TypeRef => + val info = tp.info + if (info.isAliasTypeBounds) info.dealias else this + case _ => + this + } + /** The parameter types of a PolyType or MethodType, Empty list for others */ def paramTypess: List[List[Type]] = this match { case mt: MethodType => mt.paramTypes :: mt.resultType.paramTypess @@ -470,7 +481,7 @@ object Types { * pattern is that method signatures use caching, so encapsulation * is improved using an OO scheme). */ - def signature: Signature = NullSignature + def signature(implicit ctx: Context): Signature = NullSignature final def baseType(base: Symbol)(implicit ctx: Context): Type = base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) @@ -511,10 +522,10 @@ object Types { /** If this type equals `tycon applyToArgs args`, for some * non-refinement type `tycon` and (possibly partial) type arguments * `args`, return a pair consisting of `tycon` and `args`. - * Otherwise return the type itself and `Nil`. + * Otherwise return the dealiased type itself and `Nil`. */ final def splitArgs(implicit ctx: Context): (Type, List[Type]) = { - def recur(tp: Type, nparams: Int): (Type, List[Type]) = tp match { + def recur(tp: Type, nparams: Int): (Type, List[Type]) = tp.dealias match { case tp @ RefinedType(parent, name) => def fail = (NoType, Nil) if (nparams >= 0) { @@ -538,6 +549,25 @@ object Types { if (args.length == tycon.typeParams.length) result else (NoType, Nil) } + /** If this is an encoding of an applied type, return its arguments, + * otherwise return Nil + */ + def typeArgs(implicit ctx: Context): List[Type] = splitArgs._2 + + /** If this type is of the normalized form Array[...[Array[T]...] + * return the number of Array wrappers and T. + * Otherwise return 0 and the type itself + */ + final def splitArray(implicit ctx: Context): (Int, Type) = { + def recur(n: Int, tp: Type): (Int, Type) = tp.splitArgs match { + case (arrayType, arg :: Nil) if arrayType == defn.ArrayType => + recur(n + 1, arg) + case (tp, Nil) => + (n, tp) + } + recur(0, this) + } + /** Turn this type into a TypeBounds RHS */ final def toRHS(tparam: Symbol)(implicit ctx: Context): TypeBounds = { val v = tparam.variance @@ -740,9 +770,18 @@ object Types { override def underlying(implicit ctx: Context): Type = info - def derivedNamedType(prefix: Type, name: Name)(implicit ctx: Context): Type = + def derivedNamedType(prefix: Type)(implicit ctx: Context): Type = if (prefix eq this.prefix) this - else NamedType(prefix, name) + else newLikeThis(prefix) + + /** Create a NamedType of the same kind as this type, if possible, + * but with a new prefix. For HasFixedSym instances another such + * instance is only created if the symbol's owner is a base class of + * the new prefix. If that is not the case, we fall back to a + * NamedType or in the case of a TermRef, NamedType with signature. + */ + protected def newLikeThis(prefix: Type)(implicit ctx: Context): Type = + NamedType(prefix, name) override def computeHash = doHash(name, prefix) } @@ -763,17 +802,26 @@ object Types { final class TermRefBySym(prefix: Type, val fixedSym: TermSymbol)(initctx: Context) extends TermRef(prefix, fixedSym.name(initctx).asTermName) with HasFixedSym { - } - - final class TermRefWithSignature(prefix: Type, name: TermName, override val signature: Signature) extends TermRef(prefix, name) { - override def computeHash = doHash((name, signature), prefix) + override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = + if (prefix.baseType(fixedSym.owner).exists) TermRef(prefix, fixedSym) + else TermRef(prefix, name, fixedSym.signature) + } + + final class TermRefWithSignature(prefix: Type, name: TermName, sig: Signature) extends TermRef(prefix, name) { + override def signature(implicit ctx: Context) = sig + override def computeHash = doHash((name, sig), prefix) override def loadDenot(implicit ctx: Context): Denotation = - super.loadDenot.atSignature(signature) - } + super.loadDenot.atSignature(sig) + override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRefWithSignature = + TermRef(prefix, name, sig) + } final class TypeRefBySym(prefix: Type, val fixedSym: TypeSymbol)(initctx: Context) extends TypeRef(prefix, fixedSym.name(initctx).asTypeName) with HasFixedSym { - } + override def newLikeThis(prefix: Type)(implicit ctx: Context): TypeRef = + if (prefix.baseType(fixedSym.owner).exists) TypeRef(prefix, fixedSym) + else TypeRef(prefix, name) + } final class CachedTermRef(prefix: Type, name: TermName) extends TermRef(prefix, name) final class CachedTypeRef(prefix: Type, name: TypeName) extends TypeRef(prefix, name) @@ -918,7 +966,8 @@ object Types { // The reason is that most poly types are cyclic via poly params, // and therefore two different poly types would never be equal. - abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type])(resultTypeExp: MethodType => Type) extends CachedGroundType with BindingType { + abstract case class MethodType(paramNames: List[TermName], paramTypes: List[Type]) + (resultTypeExp: MethodType => Type) extends CachedGroundType with BindingType { override lazy val resultType = resultTypeExp(this) def isJava = false def isImplicit = false @@ -928,8 +977,20 @@ object Types { case _ => false } - override lazy val signature: List[TypeName] = { - def paramSig(tp: Type): TypeName = ??? + private[this] var _signature: Signature = _ + private[this] var signatureRunId: Int = NoRunId + + override def signature(implicit ctx: Context): Signature = { + if (ctx.runId != signatureRunId) { + _signature = computeSignature + signatureRunId = ctx.runId + } + _signature + } + + private def computeSignature(implicit ctx: Context): Signature = { + def paramSig(tp: Type): TypeName = + erasure(tp).typeSymbol.asType.name val followSig = resultType match { case rtp: MethodType => rtp.signature case _ => Nil @@ -994,7 +1055,7 @@ object Types { abstract case class ExprType(override val resultType: Type) extends CachedProxyType { override def underlying(implicit ctx: Context): Type = resultType - override def signature: Signature = Nil + override def signature(implicit ctx: Context): Signature = Nil def derivedExprType(rt: Type)(implicit ctx: Context) = if (rt eq resultType) this else ExprType(rt) override def computeHash = doHash(resultType) @@ -1012,7 +1073,7 @@ object Types { lazy val paramBounds = paramBoundsExp(this) override lazy val resultType = resultTypeExp(this) - override def signature = resultType.signature + override def signature(implicit ctx: Context) = resultType.signature def instantiate(argTypes: List[Type])(implicit ctx: Context): Type = new InstPolyMap(this, argTypes) apply resultType @@ -1109,6 +1170,10 @@ object Types { parentsCache } + def derivedClassInfo(prefix: Type, classParents: List[TypeRef], optSelfType: Type)(implicit ctx: Context) = + if ((prefix eq this.prefix) && (classParents eq this.classParents) && (optSelfType eq this.optSelfType)) this + else ClassInfo(prefix, cls, classParents, decls, optSelfType) + override def computeHash = doHash(cls, prefix) } @@ -1162,20 +1227,20 @@ object Types { // ----- Annotated and Import types ----------------------------------------------- - case class AnnotatedType(annots: List[Annotation], tpe: Type) extends UncachedProxyType { + case class AnnotatedType(annot: Annotation, tpe: Type) extends UncachedProxyType { override def underlying(implicit ctx: Context): Type = tpe - def derivedAnnotatedType(annots1: List[Annotation], tpe1: Type) = - if ((annots1 eq annots) && (tpe1 eq tpe)) this - else AnnotatedType.make(annots1, tpe1) + def derivedAnnotatedType(annot: Annotation, tpe: Type) = + if ((annot eq this.annot) && (tpe eq this.tpe)) this + else AnnotatedType(annot, tpe) } object AnnotatedType { def make(annots: List[Annotation], underlying: Type) = if (annots.isEmpty) underlying - else AnnotatedType(annots, underlying) + else (underlying /: annots)((tp, ann) => AnnotatedType(ann, tp)) } - case class ImportType(expr: Shared[Type]) extends UncachedGroundType + case class ImportType(expr: Shared) extends UncachedGroundType // Special type objects ------------------------------------------------------------ @@ -1206,7 +1271,7 @@ object Types { /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { case tp: NamedType => - tp.derivedNamedType(this(tp.prefix), tp.name) + tp.derivedNamedType(this(tp.prefix)) case _: ThisType | _: BoundType => tp @@ -1235,8 +1300,8 @@ object Types { tp.derivedTypeBounds(this(lo), this(hi)) } - case tp @ AnnotatedType(annots, underlying) => - tp.derivedAnnotatedType(mapOverAnnotations(annots), this(underlying)) + case tp @ AnnotatedType(annot, underlying) => + tp.derivedAnnotatedType(mapOver(annot), this(underlying)) case _ => tp @@ -1252,7 +1317,11 @@ object Types { else newScopeWith(elems1: _*) } - def mapOverAnnotations(annots: List[Annotation]): List[Annotation] = ??? + def mapOver(annot: Annotation): Annotation = + annot.derivedAnnotation(mapOver(annot.tree)) + + def mapOver(tree: Tree): Tree = new TreeMapper(this).apply(tree) + def andThen(f: Type => Type): TypeMap = new TypeMap { def apply(tp: Type) = f(thisMap.apply(tp)) @@ -1285,7 +1354,7 @@ object Types { abstract class TypeAccumulator[T] extends ((T, Type) => T) { def apply(x: T, tp: Type): T - def apply(x: T, annot: Annotation): T = ??? + protected def apply(x: T, annot: Annotation): T = x // don't go into annotations def foldOver(x: T, tp: Type): T = tp match { case tp: NamedType => @@ -1312,8 +1381,8 @@ object Types { case TypeBounds(lo, hi) => this(this(x, lo), hi) - case AnnotatedType(annots, underlying) => - this((x /: annots)(apply), underlying) + case AnnotatedType(annot, underlying) => + this(this(x, annot), underlying) case _ => x } diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 3a1e81e2d..8e34aa0a9 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -357,18 +357,18 @@ class ClassfileParser( val index = in.nextChar tag match { case STRING_TAG => - if (skip) None else Some(makeLiteralAnnotArg(Constant(pool.getName(index).toString))) + if (skip) None else Some(Literal(Constant(pool.getName(index).toString))) case BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | INT_TAG | LONG_TAG | FLOAT_TAG | DOUBLE_TAG => - if (skip) None else Some(makeLiteralAnnotArg(pool.getConstant(index))) + if (skip) None else Some(Literal(pool.getConstant(index))) case CLASS_TAG => - if (skip) None else Some(makeLiteralAnnotArg(Constant(pool.getType(index)))) + if (skip) None else Some(Literal(Constant(pool.getType(index)))) case ENUM_TAG => val t = pool.getType(index) val n = pool.getName(in.nextChar) val s = t.typeSymbol.companionModule.info.decls.lookup(n) assert(s != NoSymbol, t) - if (skip) None else Some(makeLiteralAnnotArg(Constant(s))) + if (skip) None else Some(Literal(Constant(s))) case ARRAY_TAG => val arr = new ArrayBuffer[Tree]() var hasError = false @@ -378,9 +378,9 @@ class ClassfileParser( case None => hasError = true } if (hasError) None - else if (skip) None else Some(makeArrayAnnotArg(arr.toArray)) + else if (skip) None else Some(SeqLiteral(arr.toList)) case ANNOTATION_TAG => - parseAnnotation(index, skip) map makeNestedAnnotArg + parseAnnotation(index, skip) map (_.tree) } } @@ -656,7 +656,9 @@ class ClassfileParser( case Some(entry) => val outerName = entry.outerName.stripModuleSuffix val owner = classSymbol(outerName) - val result = cctx.beforeTyper(getMember(owner, innerName.toTypeName)) + val result = cctx.atPhaseNotLaterThanTyper { implicit ctx => + getMember(owner, innerName.toTypeName) + } assert(result ne NoSymbol, s"""failure to resolve inner class: |externalName = $externalName, diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 7460c33fe..67e7d318f 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -548,7 +548,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas val tp = readTypeRef() // no annotation self type is supported, so no test whether this is a symbol ref val annots = until(end, readAnnotationRef) - AnnotatedType(annots, tp) + AnnotatedType.make(annots, tp) case _ => noSuchTypeTag(tag, end) } diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala new file mode 100644 index 000000000..a3181a7e6 --- /dev/null +++ b/src/dotty/tools/dotc/core/transform/Erasure.scala @@ -0,0 +1,96 @@ +package dotty.tools.dotc +package core +package transform + +import Flags._ +import Symbols._, Types._, Contexts._ + +object Erasure { + + /** The erasure |T| of a type T. This is: !!! todo: update + * + * - For a constant type, itself. + * - For a refined type scala.Array+[T]: + * - if T is Nothing or Null, scala.Array+[Object] + * - otherwise, if T <: Object, scala.Array+[|T|] + * - otherwise, if T is a type paramter coming from Java, scala.Array+[Object]. + * - otherwise, Object + * - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull, java.lang.Object. + * - For a typeref scala.Unit, scala.runtime.BoxedUnit. + * - For a typeref P.C where C refers to a toplevel class, P.C. + * - For a typeref P.C where C refers to a nested class, |P|.C. + * - For a typeref P.C where C refers to an alias type, the erasure of C's alias. + * - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound. + * - For T1 & T2, erasure(T1) (??) + * - For T1 | T2, the first base class in the linearization of T which is also a base class of T2 + * - For a method type (Fs)scala.Unit, (|Fs|)scala.Unit. + * - For any other method type (Fs)T, (|Fs|)|T|. + * - For a polymorphic type, the erasure of its result type. + * - For the class info type of java.lang.Object, the same type without any parents. + * - For a class info type of a value class, the same type without any parents. + * - For any other class info type with parents Ps, the same type with + * parents |Ps|, but with duplicate references of Object removed. + * - for all other types, the type itself (with any sub-components erased) + */ + def erasure(tp: Type)(implicit ctx: Context): Type = tp match { + case ConstantType(_) => + tp + case tp: RefinedType => + val parent = tp.parent + if (parent.dealias.typeSymbol == defn.ArrayClass) { + val (n, elemtp) = tp.splitArray + if (elemtp <:< defn.NullType) + defn.ObjectArrayType + else if (elemtp <:< defn.ObjectType) + (erasure(elemtp) /: (0 until n))((erased, _) => + defn.ArrayType.appliedTo(erased)) + else if (elemtp.typeSymbol is JavaDefined) + defn.ObjectArrayType + else + defn.ObjectType + } else erasure(parent) + case tp: TypeRef => + val sym = tp.symbol + if (sym == defn.AnyClass || sym == defn.AnyValClass || sym == defn.SingletonClass || sym == defn.NotNullClass) + defn.ObjectType + else if (sym == defn.UnitClass) defn.BoxedUnitClass.typeConstructor + // else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tref) + else if (sym.isClass) + if (sym.owner.isPackage) tp + else tp.derivedNamedType(erasure(tp.prefix)) + else + erasure(sym.info) + case NoType | NoPrefix => + tp + case tp: TypeProxy => + erasure(tp.underlying) + case AndType(tp1, tp2) => + erasure(tp1) + case OrType(tp1, tp2) => + var bcs1 = tp1.baseClasses + val bc2 = tp2.baseClasses.head + while (bcs1.nonEmpty && !bc2.isNonBottomSubClass(bcs1.head)) + bcs1 = bcs1.tail + if (bcs1.isEmpty) defn.ObjectType + else erasure(bcs1.head.typeConstructor) + case tp: MethodType => + tp.derivedMethodType( + tp.paramNames, tp.paramTypes.mapConserve(erasure), resultErasure(tp.resultType)) + case tp: PolyType => + erasure(tp.resultType) + case tp @ ClassInfo(pre, cls, classParents, decls, optSelfType) => + val parents: List[TypeRef] = + if (cls == defn.ObjectClass || cls.isPrimitiveValueClass) Nil + else if (cls == defn.ArrayClass) defn.ObjectClass.typeConstructor :: Nil + else removeLaterObjects(classParents mapConserve (erasure(_).asInstanceOf[TypeRef])) + tp.derivedClassInfo(erasure(pre), parents, NoType) + } + + def resultErasure(tp: Type)(implicit ctx: Context) = + if (tp.typeSymbol == defn.UnitClass) tp else erasure(tp) + + def removeLaterObjects(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match { + case tr :: trs1 => tr :: (trs1 filter (_.typeSymbol != defn.ObjectClass)) + case nil => nil + } +} diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala new file mode 100644 index 000000000..88fdfa386 --- /dev/null +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -0,0 +1,86 @@ +package dotty.tools +package dotc +package reporting + +import scala.collection.mutable +import core.Positions.Position +import core.Contexts._ +import Reporter.Severity.{Value => Severity, _} +import java.io.{ BufferedReader, IOException, PrintWriter } +import scala.reflect.internal.util._ + +/** + * This class implements a Reporter that displays messages on a text + * console. + */ +class ConsoleReporter( + reader: BufferedReader = Console.in, + writer: PrintWriter = new PrintWriter(Console.err, true)) + extends Reporter with UniqueMessagePositions { + + /** Whether a short file name should be displayed before errors */ + protected def shortName: Boolean = false + + /** maximal number of error messages to be printed */ + protected def ErrorLimit = 100 + + def formatMessage(msg: String, pos: Position)(implicit ctx: Context) = msg // for now + + /** Prints the message. */ + def printMessage(msg: String) { writer.print(msg + "\n"); writer.flush() } + + /** Prints the message with the given position indication. */ + def printMessage(msg: String, pos: Position)(implicit ctx: Context) { + printMessage(formatMessage(msg, pos)) + } + + def printMessage(msg: String, severity: Severity, pos: Position)(implicit ctx: Context) { + printMessage(label(severity) + msg, pos) + } + + /** + * @param pos ... + + def printSourceLine(pos: Position) { + printMessage(pos.lineContent.stripLineEnd) + printColumnMarker(pos) + } + + /** Prints the column marker of the given position. + * + * @param pos ... + */ + def printColumnMarker(pos: Position) = + if (pos.isDefined) { printMessage(" " * (pos.column - 1) + "^") } +*/ + + /** Prints the number of errors and warnings if their are non-zero. */ + def printSummary() { + if (count(WARNING) > 0) printMessage(countString(WARNING) + " found") + if ( count(ERROR) > 0) printMessage(countString(ERROR ) + " found") + } + + override def report(msg: String, severity: Severity, pos: Position)(implicit ctx: Context) { + if (severity != ERROR || count(severity) <= ErrorLimit) + printMessage(msg, severity, pos) + if (ctx.settings.prompt.value) displayPrompt() + } + + def displayPrompt(): Unit = { + writer.print("\na)bort, s)tack, r)esume: ") + writer.flush() + if (reader != null) { + val response = reader.read().asInstanceOf[Char].toLower + if (response == 'a' || response == 's') { + (new Exception).printStackTrace() + if (response == 'a') + sys exit 1 + + writer.print("\n") + writer.flush() + } + } + } + + override def flush() { writer.flush() } +} diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala new file mode 100644 index 000000000..862e665ae --- /dev/null +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -0,0 +1,133 @@ +package dotty.tools +package dotc +package reporting + +import core.Contexts._ +import core.Positions._ +import core.Decorators.PhaseListDecorator +import collection.mutable +import io.{SourceFile, NoSource} +import java.lang.System.currentTimeMillis + +trait Reporting { this: Context => + def error(msg: String, pos: Position = NoPosition): Unit = reporter.error(msg, pos) + 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 = + if (this.settings.log.value.containsPhase(phase)) + inform(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg") + + def debuglog(msg: => String)(implicit ctx: Context): Unit = + if (ctx.settings.debug.value) log(msg) + + def informTime(msg: => String, start: Long)(implicit ctx: Context): Unit = + informProgress(msg + elapsed(start)) + + private def elapsed(start: Long) = + " in " + (currentTimeMillis - start) + "ms" + + def informProgress(msg: => String)(implicit ctx: Context) = + if (ctx.settings.verbose.value) inform("[" + msg + "]") +} + +object Reporter { + object Severity extends Enumeration { + val INFO, WARNING, ERROR = Value + } +} + +/** + * This interface provides methods to issue information, warning and + * error messages. + */ +abstract class Reporter { + + import Reporter.Severity.{Value => Severity, _} + + protected def report(msg: String, severity: Severity, pos: Position)(implicit ctx: Context): Unit + + protected def isHidden(severity: Severity, pos: Position)(implicit ctx: Context) = false + + val count = new mutable.HashMap[Severity, Int]() { + override def default(key: Severity) = 0 + } + + /** Whether very long lines can be truncated. This exists so important + * debugging information (like printing the classpath) is not rendered + * invisible due to the max message length. + */ + private var _truncationOK: Boolean = true + def truncationOK = _truncationOK + def withoutTruncating[T](body: => T): T = { + val saved = _truncationOK + _truncationOK = false + try body + finally _truncationOK = saved + } + + type ErrorHandler = (String, Position, Context) => Unit + private var incompleteHandler: ErrorHandler = error(_, _)(_) + def withIncompleteHandler[T](handler: ErrorHandler)(op: => T): T = { + val saved = incompleteHandler + incompleteHandler = handler + try op + finally incompleteHandler = saved + } + + def hasErrors = count(ERROR) > 0 + def hasWarnings = count(WARNING) > 0 + + /** For sending messages that are printed only if -verbose is set */ + def info(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit = + if (ctx.settings.verbose.value) info0(msg, INFO, pos) + + /** For sending a message which should not be labeled as a warning/error, + * but also shouldn't require -verbose to be visible. + */ + def echo(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit = + info0(msg, INFO, pos) + + def warning(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit = + if (!ctx.settings.nowarn.value) + withoutTruncating(info0(msg, WARNING, pos)) + + def error(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit = + withoutTruncating(info0(msg, ERROR, pos)) + + def incompleteInputError(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit = + incompleteHandler(msg, pos, ctx) + + private def info0(msg: String, severity: Severity, pos: Position)(implicit ctx: Context): Unit = { + if (!isHidden(severity, pos)) { + count(severity) += 1 + report(msg, severity, pos) + } + } + + /** Returns a string meaning "n elements". */ + private def countElementsAsString(n: Int, elements: String): String = + n match { + case 0 => "no " + elements + "s" + case 1 => "one " + elements + case 2 => "two " + elements + "s" + case 3 => "three " + elements + "s" + case 4 => "four " + elements + "s" + case _ => n + " " + elements + "s" + } + + protected def label(severity: Severity): String = severity match { + case INFO => "" + case ERROR => "error: " + case WARNING => "warning: " + } + + protected def countString(severity: Severity) = { + assert(severity != INFO) + countElementsAsString(count(severity), label(severity).dropRight(2)) + } + + def flush(): Unit = {} + + def reset(): Unit = count.clear() +} diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala new file mode 100644 index 000000000..5b9553509 --- /dev/null +++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -0,0 +1,28 @@ +package dotty.tools +package dotc +package reporting + +import core.Contexts.Context +import scala.collection.mutable +import core.Positions.Position +import Reporter.Severity.{Value => Severity} + +/** + * This class implements a Reporter that stores all messages + */ +class StoreReporter extends Reporter { + + class Info(val msg: String, val severity: Severity, val pos: Position) { + override def toString() = "pos: " + pos + " " + msg + " " + severity + } + val infos = new mutable.LinkedHashSet[Info] + + protected def report(msg: String, severity: Severity, pos: Position)(implicit ctx: Context): Unit = { + infos += new Info(msg, severity, pos) + } + + override def reset() { + super.reset() + infos.clear() + } +} diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala new file mode 100644 index 000000000..5df999aab --- /dev/null +++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -0,0 +1,35 @@ +package dotty.tools +package dotc +package reporting + +import scala.collection.mutable +import core.Positions.Position +import Reporter.Severity.{Value => Severity} +import io.SourceFile +import core.Contexts.Context + +/** + * This trait implements `isHidden` do that multiple messages per position + * are suppressed, unless they are of increasing severity. + */ +trait UniqueMessagePositions extends Reporter { + + private val positions = + new mutable.HashMap[(SourceFile, Int), Severity] + + /** Logs a position and returns true if it was already logged. + * @note Two positions are considered identical for logging if they have the same point. + */ + override def isHidden(severity: Severity, pos: Position)(implicit ctx: Context): Boolean = + pos.exists && { + positions get (ctx.source, pos.point) match { + case Some(level) if level >= severity => true + case _ => positions((ctx.source, pos.point)) = severity; false + } + } + + override def reset(): Unit = { + super.reset() + positions.clear() + } +} diff --git a/src/dotty/tools/io/package.scala b/src/dotty/tools/io/package.scala index 2543c38d2..584819c58 100644 --- a/src/dotty/tools/io/package.scala +++ b/src/dotty/tools/io/package.scala @@ -14,6 +14,8 @@ package object io { // Forwarders from scala.reflect.io type AbstractFile = scala.reflect.io.AbstractFile val AbstractFile = scala.reflect.io.AbstractFile + type SourceFile = AbstractFile // for now + val NoSource = scala.reflect.io.NoAbstractFile // for now type Directory = scala.reflect.io.Directory val Directory = scala.reflect.io.Directory type File = scala.reflect.io.File |