diff options
Diffstat (limited to 'src')
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 => |