aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dotty/annotation/internal/SourceFile.scala10
-rw-r--r--src/dotty/runtime/Arrays.scala35
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala9
-rw-r--r--src/dotty/tools/backend/sjs/JSCodeGen.scala44
-rw-r--r--src/dotty/tools/backend/sjs/JSPrimitives.scala12
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/FromTasty.scala7
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala31
-rw-r--r--src/dotty/tools/dotc/core/Annotations.scala3
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala11
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala11
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala41
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala6
-rw-r--r--src/dotty/tools/dotc/core/Symbols.scala28
-rw-r--r--src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala15
-rw-r--r--src/dotty/tools/dotc/core/tasty/TastyFormat.scala4
-rw-r--r--src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala19
-rw-r--r--src/dotty/tools/dotc/transform/ArrayConstructors.scala57
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala23
-rw-r--r--src/dotty/tools/dotc/transform/ExpandPrivate.scala16
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala17
-rw-r--r--src/dotty/tools/dotc/transform/PostTyper.scala10
-rw-r--r--src/dotty/tools/dotc/transform/TreeChecker.scala14
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala33
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala29
25 files changed, 294 insertions, 194 deletions
diff --git a/src/dotty/annotation/internal/SourceFile.scala b/src/dotty/annotation/internal/SourceFile.scala
new file mode 100644
index 000000000..c49fc2c8d
--- /dev/null
+++ b/src/dotty/annotation/internal/SourceFile.scala
@@ -0,0 +1,10 @@
+package dotty.annotation.internal
+
+import scala.annotation.Annotation
+
+/** An annotation to record a Scala2 pickled alias.
+ * @param aliased A TermRef pointing to the aliased field.
+ */
+class SourceFile(path: String) extends Annotation {
+
+}
diff --git a/src/dotty/runtime/Arrays.scala b/src/dotty/runtime/Arrays.scala
index 4469dced7..9ec5512ad 100644
--- a/src/dotty/runtime/Arrays.scala
+++ b/src/dotty/runtime/Arrays.scala
@@ -2,6 +2,8 @@ package dotty.runtime
import scala.reflect.ClassTag
+import java.lang.{reflect => jlr}
+
/** All but the first two operations should be short-circuited and implemented specially by
* the backend.
*/
@@ -22,35 +24,8 @@ object Arrays {
arr
}
- /** Create an array of type T. T must be of form Array[E], with
- * E being a reference type.
+ /** Create an array of a reference type T.
*/
- def newRefArray[T](length: Int): T = ???
-
- /** Create a Byte[] array */
- def newByteArray(length: Int): Array[Byte] = ???
-
- /** Create a Short[] array */
- def newShortArray(length: Int): Array[Short] = ???
-
- /** Create a Char[] array */
- def newCharArray(length: Int): Array[Char] = ???
-
- /** Create an Int[] array */
- def newIntArray(length: Int): Array[Int] = ???
-
- /** Create a Long[] array */
- def newLongArray(length: Int): Array[Long] = ???
-
- /** Create a Float[] array */
- def newFloatArray(length: Int): Array[Float] = ???
-
- /** Create a Double[] array */
- def newDoubleArray(length: Int): Array[Double] = ???
-
- /** Create a Boolean[] array */
- def newBooleanArray(length: Int): Array[Boolean] = ???
-
- /** Create a scala.runtime.BoxedUnit[] array */
- def newUnitArray(length: Int): Array[Unit] = ???
+ def newArray[Arr](componentType: Class[_], returnType: Class[Arr], dimensions: Array[Int]): Arr =
+ jlr.Array.newInstance(componentType, dimensions: _*).asInstanceOf[Arr]
}
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index ef8e4997f..a64ce5900 100644
--- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -153,15 +153,8 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context
}.toMap
def unboxMethods: Map[Symbol, Symbol] = defn.ScalaValueClasses().map(x => (x, Erasure.Boxing.unboxMethod(x.asClass))).toMap
- private val mkArrayNames: Set[Name] = Set("Byte", "Float", "Char", "Double", "Boolean", "Unit", "Long", "Int", "Short", "Ref").map{ x=>
- ("new" + x + "Array").toTermName
- }
-
- val dottyArraysModuleClass = toDenot(defn.DottyArraysModule).moduleClass.asClass
-
-
override def isSyntheticArrayConstructor(s: Symbol) = {
- (toDenot(s).maybeOwner eq dottyArraysModuleClass) && mkArrayNames.contains(s.name)
+ s eq defn.newArrayMethod
}
def isBox(sym: Symbol): Boolean = Erasure.Boxing.isBox(sym)
diff --git a/src/dotty/tools/backend/sjs/JSCodeGen.scala b/src/dotty/tools/backend/sjs/JSCodeGen.scala
index ec75a1c4d..401e01784 100644
--- a/src/dotty/tools/backend/sjs/JSCodeGen.scala
+++ b/src/dotty/tools/backend/sjs/JSCodeGen.scala
@@ -718,9 +718,9 @@ class JSCodeGen()(implicit ctx: Context) {
if (sym.is(Module)) {
assert(!sym.is(Package), "Cannot use package as value: " + tree)
genLoadModule(sym)
- } else /*if (sym.isStaticMember) {
- genStaticMember(sym)
- } else if (paramAccessorLocals contains sym) {
+ } else if (sym.is(JavaStatic)) {
+ genLoadStaticField(sym)
+ } else /*if (paramAccessorLocals contains sym) {
paramAccessorLocals(sym).ref
} else if (isScalaJSDefinedJSClass(sym.owner)) {
val genQual = genExpr(qualifier)
@@ -1036,8 +1036,6 @@ class JSCodeGen()(implicit ctx: Context) {
genStringConcat(tree, receiver, args)
else if (code == HASH)
genScalaHash(tree, receiver)
- else if (isArrayNew(code))
- genArrayNew(tree, code)
else if (isArrayOp(code))
genArrayOp(tree, code)
else if (code == SYNCHRONIZED)
@@ -1409,24 +1407,6 @@ class JSCodeGen()(implicit ctx: Context) {
List(genExpr(receiver)))
}
- /** Gen JS code for a new array operation. */
- private def genArrayNew(tree: Tree, code: Int): js.Tree = {
- import scala.tools.nsc.backend.ScalaPrimitives._
-
- implicit val pos: Position = tree.pos
-
- val Apply(fun, args) = tree
- val genLength = genExpr(args.head)
-
- toIRType(tree.tpe) match {
- case arrayType: jstpe.ArrayType =>
- js.NewArray(arrayType, List(genLength))
-
- case irTpe =>
- throw new FatalError(s"ArrayNew $tree must have an array type but was $irTpe")
- }
- }
-
/** Gen JS code for an array operation (get, set or length) */
private def genArrayOp(tree: Tree, code: Int): js.Tree = {
import scala.tools.nsc.backend.ScalaPrimitives._
@@ -2328,6 +2308,24 @@ class JSCodeGen()(implicit ctx: Context) {
}
}
+ /** Gen JS code for loading a Java static field.
+ */
+ private def genLoadStaticField(sym: Symbol)(implicit pos: Position): js.Tree = {
+ /* Actually, there is no static member in Scala.js. If we come here, that
+ * is because we found the symbol in a Java-emitted .class in the
+ * classpath. But the corresponding implementation in Scala.js will
+ * actually be a val in the companion module.
+ */
+
+ if (sym == defn.BoxedUnit_UNIT) {
+ js.Undefined()
+ } else {
+ val instance = genLoadModule(sym.owner)
+ val method = encodeStaticMemberSym(sym)
+ js.Apply(instance, method, Nil)(toIRType(sym.info))
+ }
+ }
+
/** Gen JS code for loading a module.
*
* Can be given either the module symbol, or its module class symbol.
diff --git a/src/dotty/tools/backend/sjs/JSPrimitives.scala b/src/dotty/tools/backend/sjs/JSPrimitives.scala
index 52b5dc4b9..6c3c5715c 100644
--- a/src/dotty/tools/backend/sjs/JSPrimitives.scala
+++ b/src/dotty/tools/backend/sjs/JSPrimitives.scala
@@ -80,18 +80,6 @@ class JSPrimitives(ctx: Context) extends DottyPrimitives(ctx) {
val jsdefn = JSDefinitions.jsdefn
- // For some reason, the JVM primitive set does not register those
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newBooleanArray")), NEW_ZARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newByteArray")), NEW_BARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newShortArray")), NEW_SARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newCharArray")), NEW_CARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newIntArray")), NEW_IARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newLongArray")), NEW_LARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newFloatArray")), NEW_FARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newDoubleArray")), NEW_DARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newRefArray")), NEW_OARRAY)
- addPrimitive(defn.DottyArraysModule.requiredMethod(Names.termName("newUnitArray")), NEW_OARRAY)
-
addPrimitive(defn.Any_getClass, GETCLASS)
for (i <- 0 to 22)
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index fe48ac30e..b63e0236d 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -66,7 +66,8 @@ class Compiler {
new Getters, // Replace non-private vals and vars with getter defs (fields are added later)
new ElimByName, // Expand by-name parameters and arguments
new AugmentScala2Traits, // Expand traits defined in Scala 2.11 to simulate old-style rewritings
- new ResolveSuper), // Implement super accessors and add forwarders to trait methods
+ new ResolveSuper, // Implement super accessors and add forwarders to trait methods
+ new ArrayConstructors), // Intercept creation of (non-generic) arrays and intrinsify.
List(new Erasure), // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements.
List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types
new VCElideAllocations, // Peep-hole optimization to eliminate unnecessary value class allocations
diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala
index 8f29c882c..05e97f30a 100644
--- a/src/dotty/tools/dotc/FromTasty.scala
+++ b/src/dotty/tools/dotc/FromTasty.scala
@@ -64,6 +64,9 @@ object FromTasty extends Driver {
}
class ReadTastyTreesFromClasses extends FrontEnd {
+
+ override def isTyper = false
+
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
units.map(readTASTY)
@@ -83,8 +86,8 @@ object FromTasty extends Driver {
case info: ClassfileLoader =>
info.load(clsd) match {
case Some(unpickler: DottyUnpickler) =>
- val (List(unpickled), source) = unpickler.body(readPositions = true)
- val unit1 = new CompilationUnit(source)
+ val List(unpickled) = unpickler.body(readPositions = true)
+ val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
unit1.tpdTree = unpickled
unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler)
force.traverse(unit1.tpdTree)
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 8d21953ae..5e5c842a8 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -125,8 +125,8 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def SeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral =
ta.assignType(untpd.SeqLiteral(elems, elemtpt), elems, elemtpt)
- def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): SeqLiteral =
- ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt)
+ def JavaSeqLiteral(elems: List[Tree], elemtpt: Tree)(implicit ctx: Context): JavaSeqLiteral =
+ ta.assignType(new untpd.JavaSeqLiteral(elems, elemtpt), elems, elemtpt).asInstanceOf[JavaSeqLiteral]
def TypeTree(original: Tree)(implicit ctx: Context): TypeTree =
TypeTree(original.tpe, original)
@@ -362,18 +362,16 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
* kind for the given element type in `typeArg`. No type arguments or
* `length` arguments are given.
*/
- def newArray(typeArg: Tree, pos: Position)(implicit ctx: Context): Tree = {
- val elemType = typeArg.tpe
- val elemClass = elemType.classSymbol
- def newArr(kind: String) =
- ref(defn.DottyArraysModule).select(s"new${kind}Array".toTermName).withPos(pos)
- if (TypeErasure.isUnboundedGeneric(elemType))
- newArr("Generic").appliedToTypeTrees(typeArg :: Nil)
- else if (elemClass.isPrimitiveValueClass)
- newArr(elemClass.name.toString)
- else
- newArr("Ref").appliedToTypeTrees(
- TypeTree(defn.ArrayOf(elemType)).withPos(typeArg.pos) :: Nil)
+ def newArray(elemTpe: Type, returnTpe: Type, pos: Position, dims: JavaSeqLiteral)(implicit ctx: Context): Tree = {
+ val elemClass = elemTpe.classSymbol
+ def newArr =
+ ref(defn.DottyArraysModule).select(defn.newArrayMethod).withPos(pos)
+
+ if (!ctx.erasedTypes) {
+ assert(!TypeErasure.isUnboundedGeneric(elemTpe)) //needs to be done during typer. See Applications.convertNewGenericArray
+ newArr.appliedToTypeTrees(TypeTree(returnTpe) :: Nil).appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos)
+ } else // after erasure
+ newArr.appliedToArgs(clsOf(elemTpe) :: clsOf(returnTpe) :: dims :: Nil).withPos(pos)
}
// ------ Creating typed equivalents of trees that exist only in untyped form -------
@@ -835,7 +833,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
case tpnme.Float => TYPE(defn.BoxedFloatModule)
case tpnme.Double => TYPE(defn.BoxedDoubleModule)
case tpnme.Unit => TYPE(defn.BoxedUnitModule)
- case _ => Literal(Constant(TypeErasure.erasure(tp)))
+ case _ =>
+ if(ctx.erasedTypes || !tp.derivesFrom(defn.ArrayClass))
+ Literal(Constant(TypeErasure.erasure(tp)))
+ else Literal(Constant(tp))
}
}
diff --git a/src/dotty/tools/dotc/core/Annotations.scala b/src/dotty/tools/dotc/core/Annotations.scala
index dc4897233..5f96a60e6 100644
--- a/src/dotty/tools/dotc/core/Annotations.scala
+++ b/src/dotty/tools/dotc/core/Annotations.scala
@@ -94,6 +94,9 @@ object Annotations {
def makeChild(sym: Symbol)(implicit ctx: Context) =
deferred(defn.ChildAnnot,
implicit ctx => New(defn.ChildAnnotType.appliedTo(sym.owner.thisType.select(sym.name, sym)), Nil))
+
+ def makeSourceFile(path: String)(implicit ctx: Context) =
+ apply(defn.SourceFileAnnot, Literal(Constant(path)))
}
def ThrowsAnnotation(cls: ClassSymbol)(implicit ctx: Context) = {
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index ad3a0057d..bbe8e920c 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -336,13 +336,17 @@ object Contexts {
def thisCallArgContext: Context = {
assert(owner.isClassConstructor)
val constrCtx = outersIterator.dropWhile(_.outer.owner == owner).next
- superOrThisCallContext(owner, constrCtx.scope).setTyperState(typerState)
+ superOrThisCallContext(owner, constrCtx.scope)
+ .setTyperState(typerState)
+ .setGadt(gadt)
}
- /** The super= or this-call context with given owner and locals. */
+ /** The super- or this-call context with given owner and locals. */
private def superOrThisCallContext(owner: Symbol, locals: Scope): FreshContext = {
var classCtx = outersIterator.dropWhile(!_.isClassDefContext).next
- classCtx.outer.fresh.setOwner(owner).setScope(locals).setMode(classCtx.mode | Mode.InSuperCall)
+ classCtx.outer.fresh.setOwner(owner)
+ .setScope(locals)
+ .setMode(classCtx.mode | Mode.InSuperCall)
}
/** The context of expression `expr` seen as a member of a statement sequence */
@@ -438,6 +442,7 @@ object Contexts {
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
def setRunInfo(runInfo: RunInfo): this.type = { this.runInfo = runInfo; this }
def setDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this }
+ def setGadt(gadt: GADTMap): this.type = { this.gadt = gadt; this }
def setTypeComparerFn(tcfn: Context => TypeComparer): this.type = { this.typeComparer = tcfn(this); this }
def setSearchHistory(searchHistory: SearchHistory): this.type = { this.searchHistory = searchHistory; this }
def setFreshNames(freshNames: FreshNameCreator): this.type = { this.freshNames = freshNames; this }
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index d8c882d5c..5376ed591 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -246,8 +246,8 @@ class Definitions {
def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol
lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays")
def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol
-
- def newRefArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newRefArray")
+ def newGenericArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newGenericArray")
+ def newArrayMethod(implicit ctx: Context) = DottyArraysModule.requiredMethod("newArray")
lazy val NilModuleRef = ctx.requiredModuleRef("scala.collection.immutable.Nil")
def NilModule(implicit ctx: Context) = NilModuleRef.symbol
@@ -279,6 +279,9 @@ class Definitions {
def Array_clone(implicit ctx: Context) = Array_cloneR.symbol
lazy val ArrayConstructorR = ArrayClass.requiredMethodRef(nme.CONSTRUCTOR)
def ArrayConstructor(implicit ctx: Context) = ArrayConstructorR.symbol
+ lazy val ArrayModuleType = ctx.requiredModuleRef("scala.Array")
+ def ArrayModule(implicit ctx: Context) = ArrayModuleType.symbol.moduleClass.asClass
+
lazy val UnitType: TypeRef = valueTypeRef("scala.Unit", BoxedUnitType, java.lang.Void.TYPE, UnitEnc)
def UnitClass(implicit ctx: Context) = UnitType.symbol.asClass
@@ -456,6 +459,8 @@ class Definitions {
def RemoteAnnot(implicit ctx: Context) = RemoteAnnotType.symbol.asClass
lazy val RepeatedAnnotType = ctx.requiredClassRef("dotty.annotation.internal.Repeated")
def RepeatedAnnot(implicit ctx: Context) = RepeatedAnnotType.symbol.asClass
+ lazy val SourceFileAnnotType = ctx.requiredClassRef("dotty.annotation.internal.SourceFile")
+ def SourceFileAnnot(implicit ctx: Context) = SourceFileAnnotType.symbol.asClass
lazy val ScalaSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaSignature")
def ScalaSignatureAnnot(implicit ctx: Context) = ScalaSignatureAnnotType.symbol.asClass
lazy val ScalaLongSignatureAnnotType = ctx.requiredClassRef("scala.reflect.ScalaLongSignature")
@@ -620,7 +625,7 @@ class Definitions {
lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass)
def isPolymorphicAfterErasure(sym: Symbol) =
- (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf) || (sym eq newRefArrayMethod)
+ (sym eq Any_isInstanceOf) || (sym eq Any_asInstanceOf)
def isTupleType(tp: Type)(implicit ctx: Context) = {
val arity = tp.dealias.argInfos.length
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 218fb8561..6e7eed3bc 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -655,8 +655,7 @@ object Denotations {
next.resetFlag(Frozen)
case _ =>
}
- next.nextInRun = cur.nextInRun
- cur.nextInRun = next
+ next.insertAfter(cur)
cur = next
}
cur.validFor = Period(currentPeriod.runId, startPid, transformer.lastPhaseId)
@@ -672,6 +671,10 @@ object Denotations {
while (!(cur.validFor contains currentPeriod)) {
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
cur = cur.nextInRun
+ // Note: One might be tempted to add a `prev` field to get to the new denotation
+ // more directly here. I tried that, but it degrades rather than improves
+ // performance: Test setup: Compile everything in dotc and immediate subdirectories
+ // 10 times. Best out of 10: 18154ms with `prev` field, 17777ms without.
cnt += 1
if (cnt > MaxPossiblePhaseId) return NotDefinedHereDenotation
}
@@ -708,12 +711,10 @@ object Denotations {
// printPeriods(current)
this.validFor = Period(ctx.runId, targetId, current.validFor.lastPhaseId)
if (current.validFor.firstPhaseId >= targetId)
- replaceDenotation(current)
+ insertInsteadOf(current)
else {
- // insert this denotation after current
current.validFor = Period(ctx.runId, current.validFor.firstPhaseId, targetId - 1)
- this.nextInRun = current.nextInRun
- current.nextInRun = this
+ insertAfter(current)
}
// printPeriods(this)
}
@@ -731,19 +732,35 @@ object Denotations {
val current1: SingleDenotation = f(current.asSymDenotation)
if (current1 ne current) {
current1.validFor = current.validFor
- current1.replaceDenotation(current)
+ current1.insertInsteadOf(current)
}
hasNext = current1.nextInRun.validFor.code > current1.validFor.code
current = current1.nextInRun
}
}
- private def replaceDenotation(current: SingleDenotation): Unit = {
- var prev = current
- while (prev.nextInRun ne current) prev = prev.nextInRun
+ /** Insert this denotation so that it follows `prev`. */
+ private def insertAfter(prev: SingleDenotation) = {
+ this.nextInRun = prev.nextInRun
prev.nextInRun = this
- this.nextInRun = current.nextInRun
- current.validFor = Nowhere
+ }
+
+ /** Insert this denotation instead of `old`.
+ * Also ensure that `old` refers with `nextInRun` to this denotation
+ * and set its `validFor` field to `NoWhere`. This is necessary so that
+ * references to the old denotation can be brought forward via `current`
+ * to a valid denotation.
+ *
+ * The code to achieve this is subtle in that it works correctly
+ * whether the replaced denotation is the only one in its cycle or not.
+ */
+ private def insertInsteadOf(old: SingleDenotation): Unit = {
+ var prev = old
+ while (prev.nextInRun ne old) prev = prev.nextInRun
+ // order of next two assignments is important!
+ prev.nextInRun = this
+ this.nextInRun = old.nextInRun
+ old.validFor = Nowhere
}
def staleSymbolError(implicit ctx: Context) = {
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index ce87506ae..4b2861452 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -291,7 +291,11 @@ object Phases {
*/
def relaxedTyping: Boolean = false
- /** Overridden by FrontEnd */
+ /** Is this phase the standard typerphase? True for FrontEnd, but
+ * not for other first phases (such as FromTasty). The predicate
+ * is tested in some places that perform checks and corrections. It's
+ * different from isAfterTyper (and cheaper to test).
+ */
def isTyper = false
def exists: Boolean = true
diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala
index 2a76f18d8..d40acdfa7 100644
--- a/src/dotty/tools/dotc/core/Symbols.scala
+++ b/src/dotty/tools/dotc/core/Symbols.scala
@@ -21,6 +21,7 @@ import StdNames._
import NameOps._
import ast.tpd.Tree
import ast.TreeTypeMap
+import Constants.Constant
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import io.AbstractFile
@@ -463,20 +464,23 @@ object Symbols {
denot.topLevelClass.symbol.associatedFile
/** The class file from which this class was generated, null if not applicable. */
- final def binaryFile(implicit ctx: Context): AbstractFile =
- pickFile(associatedFile, classFile = true)
+ final def binaryFile(implicit ctx: Context): AbstractFile = {
+ val file = associatedFile
+ if (file != null && file.path.endsWith("class")) file else null
+ }
/** The source file from which this class was generated, null if not applicable. */
- final def sourceFile(implicit ctx: Context): AbstractFile =
- pickFile(associatedFile, classFile = false)
-
- /** Desire to re-use the field in ClassSymbol which stores the source
- * file to also store the classfile, but without changing the behavior
- * of sourceFile (which is expected at least in the IDE only to
- * return actual source code.) So sourceFile has classfiles filtered out.
- */
- private def pickFile(file: AbstractFile, classFile: Boolean): AbstractFile =
- if ((file eq null) || classFile != (file.path endsWith ".class")) null else file
+ final def sourceFile(implicit ctx: Context): AbstractFile = {
+ val file = associatedFile
+ if (file != null && !file.path.endsWith("class")) file
+ else denot.topLevelClass.getAnnotation(defn.SourceFileAnnot) match {
+ case Some(sourceAnnot) => sourceAnnot.argumentConstant(0) match {
+ case Some(Constant(path: String)) => AbstractFile.getFile(path)
+ case none => null
+ }
+ case none => null
+ }
+ }
/** The position of this symbol, or NoPosition is symbol was not loaded
* from source.
diff --git a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
index d62762571..0ad5d6966 100644
--- a/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala
@@ -3,13 +3,13 @@ package dotc
package core
package tasty
-import Contexts._, SymDenotations._
+import Contexts._, SymDenotations._, Symbols._
import dotty.tools.dotc.ast.tpd
import TastyUnpickler._, TastyBuffer._
-import dotty.tools.dotc.core.tasty.DottyUnpickler.{SourceFileUnpickler, TreeSectionUnpickler, PositionsSectionUnpickler}
import util.Positions._
import util.{SourceFile, NoSource}
import PositionUnpickler._
+import Annotations.Annotation
import classfile.ClassfileParser
object DottyUnpickler {
@@ -17,11 +17,6 @@ object DottyUnpickler {
/** Exception thrown if classfile is corrupted */
class BadSignature(msg: String) extends RuntimeException(msg)
- class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") {
- def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
- new SourceFile(tastyName(reader.readNameRef()).toString, Seq())
- }
-
class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") {
def unpickle(reader: TastyReader, tastyName: TastyName.Table) =
new TreeUnpickler(reader, tastyName)
@@ -38,6 +33,7 @@ object DottyUnpickler {
*/
class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
import tpd._
+ import DottyUnpickler._
val unpickler = new TastyUnpickler(bytes)
private val treeUnpickler = unpickler.unpickle(new TreeSectionUnpickler).get
@@ -51,11 +47,10 @@ class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded {
/** The unpickled trees, and the source file they come from
* @param readPositions if true, trees get decorated with position information.
*/
- def body(readPositions: Boolean = false)(implicit ctx: Context): (List[Tree], SourceFile) = {
- val source = unpickler.unpickle(new SourceFileUnpickler).getOrElse(NoSource)
+ def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = {
if (readPositions)
for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler))
treeUnpickler.usePositions(totalRange, positions)
- (treeUnpickler.unpickle(), source)
+ treeUnpickler.unpickle()
}
}
diff --git a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
index f3dabb517..ea7e985c9 100644
--- a/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
+++ b/src/dotty/tools/dotc/core/tasty/TastyFormat.scala
@@ -84,7 +84,7 @@ Standard-Section: "ASTs" TopLevelStat*
MATCH Length sel_Term CaseDef*
TRY Length expr_Term CaseDef* finalizer_Term?
RETURN Length meth_ASTRef expr_Term?
- REPEATED Length elem_Term*
+ REPEATED Length elem_Type elem_Term*
BIND Length boundName_NameRef patType_Type pat_Term
ALTERNATIVE Length alt_Term*
UNAPPLY Length fun_Term ImplicitArg* pat_Type pat_Term*
@@ -184,8 +184,6 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t
Category 4 (tags 112-127): tag Nat AST
Category 5 (tags 128-255): tag Length <payload>
-Standard Section: "Sourcefile" sourcefile_NameRef
-
Standard Section: "Positions" sourceLength_Nat Assoc*
Assoc = addr_Delta offset_Delta offset_Delta?
diff --git a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
index 3a9803346..535ddd216 100644
--- a/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
+++ b/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
@@ -598,6 +598,11 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
vparamss.nestedMap(_.symbol), name == nme.CONSTRUCTOR)
val resType = ctx.effectiveResultType(sym, typeParams, tpt.tpe)
sym.info = ctx.methodType(typeParams, valueParamss, resType)
+ if (sym.isSetter && sym.accessedFieldOrGetter.is(ParamAccessor)) {
+ // reconstitute ParamAccessor flag of setters for var parameters, which is not pickled
+ sym.setFlag(ParamAccessor)
+ sym.resetFlag(Deferred)
+ }
DefDef(tparams, vparamss, tpt)
case VALDEF =>
sym.info = readType()
@@ -804,9 +809,10 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
tpd.Super(qual, mixName, ctx.mode.is(Mode.InSuperCall), mixClass)
case APPLY =>
val fn = readTerm()
- val isJava = fn.tpe.isInstanceOf[JavaMethodType]
+ val isJava = fn.symbol.is(JavaDefined)
def readArg() = readTerm() match {
- case SeqLiteral(elems, elemtpt) if isJava => JavaSeqLiteral(elems, elemtpt)
+ case SeqLiteral(elems, elemtpt) if isJava =>
+ JavaSeqLiteral(elems, elemtpt)
case arg => arg
}
tpd.Apply(fn, until(end)(readArg()))
@@ -815,7 +821,14 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) {
case PAIR =>
Pair(readTerm(), readTerm())
case TYPED =>
- Typed(readTerm(), readTpt())
+ val expr = readTerm()
+ val tpt = readTpt()
+ val expr1 = expr match {
+ case SeqLiteral(elems, elemtpt) if tpt.tpe.isRef(defn.ArrayClass) =>
+ JavaSeqLiteral(elems, elemtpt)
+ case expr => expr
+ }
+ Typed(expr1, tpt)
case NAMEDARG =>
NamedArg(readName(), readTerm())
case ASSIGN =>
diff --git a/src/dotty/tools/dotc/transform/ArrayConstructors.scala b/src/dotty/tools/dotc/transform/ArrayConstructors.scala
new file mode 100644
index 000000000..ec3bfa47f
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/ArrayConstructors.scala
@@ -0,0 +1,57 @@
+package dotty.tools.dotc
+package transform
+
+import core._
+import TreeTransforms._
+import Contexts.Context
+import Flags._
+import SymUtils._
+import Symbols._
+import SymDenotations._
+import Types._
+import Decorators._
+import DenotTransformers._
+import StdNames._
+import NameOps._
+import ast.Trees._
+import dotty.tools.dotc.ast.tpd
+import util.Positions._
+import Names._
+
+import collection.mutable
+import ResolveSuper._
+
+import scala.collection.immutable.::
+
+
+/** This phase rewrites calls to array constructors to newArray method in Dotty.runtime.Arrays module.
+ *
+ * It assummes that generic arrays have already been handled by typer(see Applications.convertNewGenericArray).
+ * Additionally it optimizes calls to scala.Array.ofDim functions by replacing them with calls to newArray with specific dimensions
+ */
+class ArrayConstructors extends MiniPhaseTransform { thisTransform =>
+ import ast.tpd._
+
+ override def phaseName: String = "arrayConstructors"
+
+ override def transformApply(tree: tpd.Apply)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
+ def rewrite(elemType: Type, dims: List[Tree]) =
+ tpd.newArray(elemType, tree.tpe, tree.pos, JavaSeqLiteral(dims, TypeTree(defn.IntClass.typeRef)))
+
+ if (tree.fun.symbol eq defn.ArrayConstructor) {
+ val TypeApply(tycon, targ :: Nil) = tree.fun
+ rewrite(targ.tpe, tree.args)
+ } else if ((tree.fun.symbol.maybeOwner eq defn.ArrayModule) && (tree.fun.symbol.name eq nme.ofDim) && !tree.tpe.isInstanceOf[MethodicType]) {
+
+ tree.fun match {
+ case Apply(TypeApply(t: Ident, targ), dims) if !TypeErasure.isUnboundedGeneric(targ.head.tpe) =>
+ rewrite(targ.head.tpe, dims)
+ case Apply(TypeApply(t: Select, targ), dims) if !TypeErasure.isUnboundedGeneric(targ.head.tpe) =>
+ Block(t.qualifier :: Nil, rewrite(targ.head.tpe, dims))
+ case _ => tree
+ }
+
+ } else tree
+ }
+}
+
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 7acb14af4..0b3a07f65 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -21,7 +21,7 @@ import core.Decorators._
import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import ast.Trees._
import scala.collection.mutable.ListBuffer
-import dotty.tools.dotc.core.Flags
+import dotty.tools.dotc.core.{Constants, Flags}
import ValueClasses._
import TypeUtils._
import ExplicitOuter._
@@ -299,8 +299,9 @@ object Erasure extends TypeTestsCasts{
assignType(untpd.cpy.Typed(tree)(expr1, tpt1), tpt1)
}
- override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal =
+ override def typedLiteral(tree: untpd.Literal)(implicit ctx: Context): Literal =
if (tree.typeOpt.isRef(defn.UnitClass)) tree.withType(tree.typeOpt)
+ else if (tree.const.tag == Constants.ClazzTag) Literal(Constant(erasure(tree.const.typeValue)))
else super.typedLiteral(tree)
/** Type check select nodes, applying the following rewritings exhaustively
@@ -467,28 +468,18 @@ object Erasure extends TypeTestsCasts{
tpt = untpd.TypedSplice(TypeTree(sym.info).withPos(vdef.tpt.pos))), sym)
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = {
- var effectiveSym = sym
- if (sym == defn.newRefArrayMethod) {
- // newRefArray is treated specially: It's the only source-defined method
- // that has a polymorphic type after erasure. But treating its (dummy) definition
- // with a polymorphic type at and after erasure is an awkward special case.
- // We therefore rewrite the method definition with a new Symbol of type
- // (length: Int)Object
- val MethodType(pnames, ptypes) = sym.info.resultType
- effectiveSym = sym.copy(info = MethodType(pnames, ptypes, defn.ObjectType))
- }
val restpe =
- if (effectiveSym.isConstructor) defn.UnitType
- else effectiveSym.info.resultType
+ if (sym.isConstructor) defn.UnitType
+ else sym.info.resultType
val ddef1 = untpd.cpy.DefDef(ddef)(
tparams = Nil,
- vparamss = (outer.paramDefs(effectiveSym) ::: ddef.vparamss.flatten) :: Nil,
+ vparamss = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil,
tpt = untpd.TypedSplice(TypeTree(restpe).withPos(ddef.tpt.pos)),
rhs = ddef.rhs match {
case id @ Ident(nme.WILDCARD) => untpd.TypedSplice(id.withType(restpe))
case _ => ddef.rhs
})
- super.typedDefDef(ddef1, effectiveSym)
+ super.typedDefDef(ddef1, sym)
}
/** After erasure, we may have to replace the closure method by a bridge.
diff --git a/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/src/dotty/tools/dotc/transform/ExpandPrivate.scala
index a6f203478..2e0759b89 100644
--- a/src/dotty/tools/dotc/transform/ExpandPrivate.scala
+++ b/src/dotty/tools/dotc/transform/ExpandPrivate.scala
@@ -16,6 +16,7 @@ import TreeTransforms._
import Decorators._
import ast.Trees._
import TreeTransforms._
+import java.io.File.separatorChar
/** Make private term members that are accessed from another class
* non-private by resetting the Private flag and expanding their name.
@@ -58,7 +59,20 @@ class ExpandPrivate extends MiniPhaseTransform with IdentityDenotTransformer { t
*/
private def ensurePrivateAccessible(d: SymDenotation)(implicit ctx: Context) =
if (d.is(PrivateTerm) && d.owner != ctx.owner.enclosingClass) {
- assert(d.symbol.sourceFile == ctx.source.file,
+ // Paths `p1` and `p2` are similar if they have a common suffix that follows
+ // possibly different directory paths. That is, their common suffix extends
+ // in both cases either to the start of the path or to a file separator character.
+ def isSimilar(p1: String, p2: String): Boolean = {
+ var i = p1.length - 1
+ var j = p2.length - 1
+ while (i >= 0 && j >= 0 && p1(i) == p2(j) && p1(i) != separatorChar) {
+ i -= 1
+ j -= 1
+ }
+ (i < 0 || p1(i) == separatorChar) &&
+ (j < 0 || p1(j) == separatorChar)
+ }
+ assert(isSimilar(d.symbol.sourceFile.path, ctx.source.file.path),
i"private ${d.symbol.showLocated} in ${d.symbol.sourceFile} accessed from ${ctx.owner.showLocated} in ${ctx.source.file}")
d.ensureNotPrivate.installAfter(thisTransform)
}
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index c5b223d53..e8d6d03bf 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -11,7 +11,6 @@ import Periods._
import Phases._
import Symbols._
import Flags.Module
-import util.SourceFile
import collection.mutable
/** This phase pickles trees */
@@ -48,8 +47,6 @@ class Pickler extends Phase {
treePkl.pickle(tree :: Nil)
pickler.addrOfTree = treePkl.buf.addrOfTree
pickler.addrOfSym = treePkl.addrOfSym
- if (unit.source.exists)
- pickleSourcefile(pickler, unit.source)
if (tree.pos.exists)
new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
@@ -65,12 +62,6 @@ class Pickler extends Phase {
}
}
- private def pickleSourcefile(pickler: TastyPickler, source: SourceFile): Unit = {
- val buf = new TastyBuffer(10)
- pickler.newSection("Sourcefile", buf)
- buf.writeNat(pickler.nameBuffer.nameIndex(source.file.path).index)
- }
-
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
val result = super.runOn(units)
if (ctx.settings.YtestPickler.value)
@@ -89,16 +80,16 @@ class Pickler extends Phase {
}
pickling.println("************* entered toplevel ***********")
for ((cls, unpickler) <- unpicklers) {
- val (unpickled, source) = unpickler.body(readPositions = true)
- testSame(i"$unpickled%\n%", beforePickling(cls), cls, source)
+ val unpickled = unpickler.body(readPositions = true)
+ testSame(i"$unpickled%\n%", beforePickling(cls), cls)
}
}
- private def testSame(unpickled: String, previous: String, cls: ClassSymbol, source: SourceFile)(implicit ctx: Context) =
+ private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) =
if (previous != unpickled) {
output("before-pickling.txt", previous)
output("after-pickling.txt", unpickled)
- ctx.error(s"""pickling difference for ${cls.fullName} in $source, for details:
+ ctx.error(s"""pickling difference for ${cls.fullName} in ${cls.sourceFile}, for details:
|
| diff before-pickling.txt after-pickling.txt""".stripMargin)
}
diff --git a/src/dotty/tools/dotc/transform/PostTyper.scala b/src/dotty/tools/dotc/transform/PostTyper.scala
index 01f9f6317..fcde59b24 100644
--- a/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -36,6 +36,8 @@ import Symbols._, TypeUtils._
*
* (8) Replaces self references by name with `this`
*
+ * (9) Adds SourceFile annotations to all top-level classes and objects
+ *
* The reason for making this a macro transform is that some functions (in particular
* super and protected accessors and instantiation checks) are naturally top-down and
* don't lend themselves to the bottom-up approach of a mini phase. The other two functions
@@ -224,7 +226,13 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisTran
transformMemberDef(tree)
val sym = tree.symbol
val tree1 =
- if (sym.isClass) tree
+ if (sym.isClass) {
+ if (sym.owner.is(Package) &&
+ ctx.compilationUnit.source.exists &&
+ sym != defn.SourceFileAnnot)
+ sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path))
+ tree
+ }
else {
Checking.typeChecker.traverse(tree.rhs)
cpy.TypeDef(tree)(rhs = TypeTree(tree.symbol.info))
diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala
index 39f407f9b..f11789c9a 100644
--- a/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -311,6 +311,13 @@ class TreeChecker extends Phase with SymTransformer {
tree
}
+ /** Check that all methods have MethodicType */
+ def isMethodType(pt: Type)(implicit ctx: Context): Boolean = pt match {
+ case at: AnnotatedType => isMethodType(at.tpe)
+ case _: MethodicType => true // MethodType, ExprType, PolyType
+ case _ => false
+ }
+
override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = {
assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase)
assert(tree.isType || !needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree # ${tree.uniqueId}")
@@ -352,8 +359,7 @@ class TreeChecker extends Phase with SymTransformer {
def isNonMagicalMethod(x: Symbol) =
x.is(Method) &&
!x.isCompanionMethod &&
- !x.isValueClassConvertMethod &&
- x != defn.newRefArrayMethod
+ !x.isValueClassConvertMethod
val symbolsNotDefined = cls.classInfo.decls.toSet.filter(isNonMagicalMethod) -- impl.body.map(_.symbol) - constr.symbol
@@ -369,7 +375,9 @@ class TreeChecker extends Phase with SymTransformer {
withDefinedSyms(ddef.tparams) {
withDefinedSymss(ddef.vparamss) {
if (!sym.isClassConstructor) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm")
- super.typedDefDef(ddef, sym)
+ val tpdTree = super.typedDefDef(ddef, sym)
+ assert(isMethodType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}")
+ tpdTree
}
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index f3903e539..37a9f0ba0 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -531,12 +531,16 @@ trait Applications extends Compatibility { self: Typer =>
def treeToArg(arg: Tree): Tree = arg
}
+ /** If `app` is a `this(...)` constructor call, the this-call argument context,
+ * otherwise the current context.
+ */
+ def argCtx(app: untpd.Tree)(implicit ctx: Context): Context =
+ if (untpd.isSelfConstrCall(app)) ctx.thisCallArgContext else ctx
+
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
def realApply(implicit ctx: Context): Tree = track("realApply") {
- def argCtx(implicit ctx: Context) =
- if (untpd.isSelfConstrCall(tree)) ctx.thisCallArgContext else ctx
- var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx)
+ var proto = new FunProto(tree.args, IgnoredProto(pt), this)(argCtx(tree))
val fun1 = typedExpr(tree.fun, proto)
// Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as
@@ -554,9 +558,9 @@ trait Applications extends Compatibility { self: Typer =>
tryEither { implicit ctx =>
val app =
if (proto.argsAreTyped) new ApplyToTyped(tree, fun1, funRef, proto.typedArgs, pt)
- else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx)
+ else new ApplyToUntyped(tree, fun1, funRef, proto, pt)(argCtx(tree))
val result = app.result
- convertNewArray(ConstFold(result))
+ convertNewGenericArray(ConstFold(result))
} { (failedVal, failedState) =>
val fun2 = tryInsertImplicitOnQualifier(fun1, proto)
if (fun1 eq fun2) {
@@ -632,11 +636,22 @@ trait Applications extends Compatibility { self: Typer =>
def adaptTypeArg(tree: tpd.Tree, bound: Type)(implicit ctx: Context): tpd.Tree =
tree.withType(tree.tpe.etaExpandIfHK(bound))
- /** Rewrite `new Array[T](....)` trees to calls of newXYZArray methods. */
- def convertNewArray(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
- case Apply(TypeApply(tycon, targ :: Nil), args) if tycon.symbol == defn.ArrayConstructor =>
+ /** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.
+ * It is performed during typer as creation of generic arrays needs a classTag.
+ * we rely on implicit search to find one.
+ */
+ def convertNewGenericArray(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
+ case Apply(TypeApply(tycon, targs@(targ :: Nil)), args) if tycon.symbol == defn.ArrayConstructor =>
fullyDefinedType(tree.tpe, "array", tree.pos)
- tpd.cpy.Apply(tree)(newArray(targ, tree.pos), args)
+
+ def newGenericArrayCall =
+ ref(defn.DottyArraysModule)
+ .select(defn.newGenericArrayMethod).withPos(tree.pos)
+ .appliedToTypeTrees(targs).appliedToArgs(args)
+
+ if (TypeErasure.isUnboundedGeneric(targ.tpe))
+ newGenericArrayCall
+ else tree
case _ =>
tree
}
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 84abf85e0..53296f9c9 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1022,17 +1022,20 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val DefDef(name, tparams, vparamss, tpt, _) = ddef
completeAnnotations(ddef, sym)
val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef])
- // for secondary constructors we need to use that their type parameters
- // are aliases of the class type parameters. See pos/i941.scala
- if (sym.isConstructor && !sym.isPrimaryConstructor)
- (sym.owner.typeParams, tparams1).zipped.foreach {(tparam, tdef) =>
- tdef.symbol.info = TypeAlias(tparam.typeRef)
- }
-
val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef])
if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1)
val tpt1 = checkSimpleKinded(typedType(tpt))
- val rhs1 = typedExpr(ddef.rhs, tpt1.tpe)
+
+ var rhsCtx = ctx
+ if (sym.isConstructor && !sym.isPrimaryConstructor && tparams1.nonEmpty) {
+ // for secondary constructors we need a context that "knows"
+ // that their type parameters are aliases of the class type parameters.
+ // See pos/i941.scala
+ rhsCtx = ctx.fresh.setFreshGADTBounds
+ (tparams1, sym.owner.typeParams).zipped.foreach ((tdef, tparam) =>
+ rhsCtx.gadt.setBounds(tdef.symbol, TypeAlias(tparam.typeRef)))
+ }
+ val rhs1 = typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx)
assignType(cpy.DefDef(ddef)(name, tparams1, vparamss1, tpt1, rhs1), sym)
//todo: make sure dependent method types do not depend on implicits or by-name params
}
@@ -1518,7 +1521,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
val tvarsToInstantiate = tvarsInParams(tree)
wtp.paramTypes.foreach(instantiateSelected(_, tvarsToInstantiate))
val constr = ctx.typerState.constraint
- def addImplicitArgs = {
+ def addImplicitArgs(implicit ctx: Context) = {
val errors = new mutable.ListBuffer[() => String]
def implicitArgError(msg: => String) = {
errors += (() => msg)
@@ -1565,9 +1568,9 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
else adapt(tpd.Apply(tree, args), pt)
}
- if ((pt eq WildcardType) || original.isEmpty) addImplicitArgs
+ if ((pt eq WildcardType) || original.isEmpty) addImplicitArgs(argCtx(tree))
else
- ctx.typerState.tryWithFallback(addImplicitArgs) {
+ ctx.typerState.tryWithFallback(addImplicitArgs(argCtx(tree))) {
adapt(typed(original, WildcardType), pt, EmptyTree)
}
case wtp: MethodType if !pt.isInstanceOf[SingletonType] =>
@@ -1677,11 +1680,11 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (pt.isInstanceOf[PolyProto]) tree
else {
var typeArgs = tree match {
- case Select(New(tpt), nme.CONSTRUCTOR) => tpt.tpe.dealias.argTypesLo
+ case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo
case _ => Nil
}
if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2
- convertNewArray(
+ convertNewGenericArray(
adaptInterpolated(tree.appliedToTypes(typeArgs), pt, original))
}
case wtp =>