diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeAsmCommon.scala b/compiler/src/dotty/tools/backend/jvm/BCodeAsmCommon.scala index d4474e857c07..bdf74558a760 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeAsmCommon.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeAsmCommon.scala @@ -7,7 +7,7 @@ package jvm * the compiler cake (Global). */ final class BCodeAsmCommon[I <: BackendInterface](val interface: I) { -import interface._ + import interface._ /** * True if `classSym` is an anonymous class or a local class. I.e., false if `classSym` is a diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala index 2f12d68ef4bb..1f5c35c1db20 100644 --- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala +++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala @@ -84,488 +84,487 @@ class GenBCodePipeline(val int: DottyBackendInterface)(implicit val ctx: Context final class PlainClassBuilder(cunit: CompilationUnit) extends SyncAndTryBuilder(cunit) - // class BCodePhase() { - private[this] var bytecodeWriter : BytecodeWriter = null - private[this] var mirrorCodeGen : JMirrorBuilder = null - - /* ---------------- q1 ---------------- */ + private[this] var bytecodeWriter : BytecodeWriter = null + private[this] var mirrorCodeGen : JMirrorBuilder = null - case class Item1(arrivalPos: Int, cd: TypeDef, cunit: CompilationUnit) { - def isPoison: Boolean = { arrivalPos == Int.MaxValue } - } - private val poison1 = Item1(Int.MaxValue, null, ctx.compilationUnit) - private val q1 = new java.util.LinkedList[Item1] + /* ---------------- q1 ---------------- */ - /* ---------------- q2 ---------------- */ + case class Item1(arrivalPos: Int, cd: TypeDef, cunit: CompilationUnit) { + def isPoison: Boolean = { arrivalPos == Int.MaxValue } + } + private val poison1 = Item1(Int.MaxValue, null, ctx.compilationUnit) + private val q1 = new java.util.LinkedList[Item1] - case class SubItem2(classNode: asm.tree.ClassNode, - file: dotty.tools.io.AbstractFile) + /* ---------------- q2 ---------------- */ - case class Item2(arrivalPos: Int, - mirror: SubItem2, - plain: SubItem2) { - def isPoison: Boolean = { arrivalPos == Int.MaxValue } - } + case class SubItem2(classNode: asm.tree.ClassNode, + file: dotty.tools.io.AbstractFile) - private val poison2 = Item2(Int.MaxValue, null, null) - private val q2 = new _root_.java.util.LinkedList[Item2] - - /* ---------------- q3 ---------------- */ + case class Item2(arrivalPos: Int, + mirror: SubItem2, + plain: SubItem2) { + def isPoison: Boolean = { arrivalPos == Int.MaxValue } + } - /* - * An item of queue-3 (the last queue before serializing to disk) contains three of these - * (one for each of mirror and plain classes). - * - * @param jclassName internal name of the class - * @param jclassBytes bytecode emitted for the class SubItem3 represents - */ - case class SubItem3( - jclassName: String, - jclassBytes: Array[Byte], - jclassFile: dotty.tools.io.AbstractFile - ) - - case class Item3(arrivalPos: Int, - mirror: SubItem3, - plain: SubItem3) { - - def isPoison: Boolean = { arrivalPos == Int.MaxValue } + private val poison2 = Item2(Int.MaxValue, null, null) + private val q2 = new _root_.java.util.LinkedList[Item2] + + /* ---------------- q3 ---------------- */ + + /* + * An item of queue-3 (the last queue before serializing to disk) contains three of these + * (one for each of mirror and plain classes). + * + * @param jclassName internal name of the class + * @param jclassBytes bytecode emitted for the class SubItem3 represents + */ + case class SubItem3( + jclassName: String, + jclassBytes: Array[Byte], + jclassFile: dotty.tools.io.AbstractFile + ) + + case class Item3(arrivalPos: Int, + mirror: SubItem3, + plain: SubItem3) { + + def isPoison: Boolean = { arrivalPos == Int.MaxValue } + } + private val i3comparator = new java.util.Comparator[Item3] { + override def compare(a: Item3, b: Item3) = { + if (a.arrivalPos < b.arrivalPos) -1 + else if (a.arrivalPos == b.arrivalPos) 0 + else 1 } - private val i3comparator = new java.util.Comparator[Item3] { - override def compare(a: Item3, b: Item3) = { - if (a.arrivalPos < b.arrivalPos) -1 - else if (a.arrivalPos == b.arrivalPos) 0 - else 1 + } + private val poison3 = Item3(Int.MaxValue, null, null) + private val q3 = new java.util.PriorityQueue[Item3](1000, i3comparator) + + /* + * Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2 + */ + class Worker1(needsOutFolder: Boolean) { + + private val lowerCaseNames = mutable.HashMap.empty[String, Symbol] + private def checkForCaseConflict(javaClassName: String, classSymbol: Symbol) = { + val lowerCaseName = javaClassName.toLowerCase + lowerCaseNames.get(lowerCaseName) match { + case None => + lowerCaseNames.put(lowerCaseName, classSymbol) + case Some(dupClassSym) => + // Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting + val (cl1, cl2) = + if (classSymbol.effectiveName.toString < dupClassSym.effectiveName.toString) (classSymbol, dupClassSym) + else (dupClassSym, classSymbol) + val same = classSymbol.effectiveName.toString == dupClassSym.effectiveName.toString + ctx.atPhase(ctx.typerPhase) { + if (same) + the[Context].warning( // FIXME: This should really be an error, but then FromTasty tests fail + s"${cl1.show} and ${cl2.showLocated} produce classes that overwrite one another", cl1.sourcePos) + else + the[Context].warning(s"${cl1.show} differs only in case from ${cl2.showLocated}. " + + "Such classes will overwrite one another on case-insensitive filesystems.", cl1.sourcePos) + } } } - private val poison3 = Item3(Int.MaxValue, null, null) - private val q3 = new java.util.PriorityQueue[Item3](1000, i3comparator) - /* - * Pipeline that takes ClassDefs from queue-1, lowers them into an intermediate form, placing them on queue-2 - */ - class Worker1(needsOutFolder: Boolean) { - - private val lowerCaseNames = mutable.HashMap.empty[String, Symbol] - private def checkForCaseConflict(javaClassName: String, classSymbol: Symbol) = { - val lowerCaseName = javaClassName.toLowerCase - lowerCaseNames.get(lowerCaseName) match { - case None => - lowerCaseNames.put(lowerCaseName, classSymbol) - case Some(dupClassSym) => - // Order is not deterministic so we enforce lexicographic order between the duplicates for error-reporting - val (cl1, cl2) = - if (classSymbol.effectiveName.toString < dupClassSym.effectiveName.toString) (classSymbol, dupClassSym) - else (dupClassSym, classSymbol) - val same = classSymbol.effectiveName.toString == dupClassSym.effectiveName.toString - ctx.atPhase(ctx.typerPhase) { - if (same) - the[Context].warning( // FIXME: This should really be an error, but then FromTasty tests fail - s"${cl1.show} and ${cl2.showLocated} produce classes that overwrite one another", cl1.sourcePos) - else - the[Context].warning(s"${cl1.show} differs only in case from ${cl2.showLocated}. " + - "Such classes will overwrite one another on case-insensitive filesystems.", cl1.sourcePos) - } + def run(): Unit = { + while (true) { + val item = q1.poll + if (item.isPoison) { + q2 add poison2 + return } - } - - def run(): Unit = { - while (true) { - val item = q1.poll - if (item.isPoison) { - q2 add poison2 - return - } - else { - try { /*withCurrentUnit(item.cunit)*/(visit(item)) } - catch { - case ex: Throwable => - println(s"Error while emitting ${int.sourceFileFor(item.cunit)}") - throw ex - } + else { + try { /*withCurrentUnit(item.cunit)*/(visit(item)) } + catch { + case ex: Throwable => + println(s"Error while emitting ${int.sourceFileFor(item.cunit)}") + throw ex } } } + } - /* - * Checks for duplicate internal names case-insensitively, - * builds ASM ClassNodes for mirror and plain classes; - * enqueues them in queue-2. - * - */ - def visit(item: Item1): Boolean = { - val Item1(arrivalPos, cd, cunit) = item - val claszSymbol = cd.symbol - - // -------------- mirror class, if needed -------------- - val mirrorC = - if (int.symHelper(claszSymbol).isTopLevelModuleClass) { - if (claszSymbol.companionClass == NoSymbol) { - mirrorCodeGen.genMirrorClass(claszSymbol, cunit) + /* + * Checks for duplicate internal names case-insensitively, + * builds ASM ClassNodes for mirror and plain classes; + * enqueues them in queue-2. + * + */ + def visit(item: Item1): Boolean = { + val Item1(arrivalPos, cd, cunit) = item + val claszSymbol = cd.symbol + + // -------------- mirror class, if needed -------------- + val mirrorC = + if (int.symHelper(claszSymbol).isTopLevelModuleClass) { + if (claszSymbol.companionClass == NoSymbol) { + mirrorCodeGen.genMirrorClass(claszSymbol, cunit) + } else { + ctx.log(s"No mirror class for module with linked class: ${claszSymbol.fullName}") + null + } + } else null + + // -------------- "plain" class -------------- + val pcb = new PlainClassBuilder(cunit) + pcb.genPlainClass(cd) + val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null; + val plainC = pcb.cnode + + if (claszSymbol.isClass) // @DarkDimius is this test needed here? + for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) { + val store = if (mirrorC ne null) mirrorC else plainC + val tasty = + if (!ctx.settings.YemitTastyInClass.value) { + val outTastyFile = getFileForClassfile(outF, store.name, ".tasty") + val outstream = new DataOutputStream(outTastyFile.bufferedOutput) + try outstream.write(binary) + finally outstream.close() + + val uuid = new TastyHeaderUnpickler(binary).readHeader() + val lo = uuid.getMostSignificantBits + val hi = uuid.getLeastSignificantBits + + // TASTY attribute is created but only the UUID bytes are stored in it. + // A TASTY attribute has length 16 if and only if the .tasty file exists. + val buffer = new TastyBuffer(16) + buffer.writeUncompressedLong(lo) + buffer.writeUncompressedLong(hi) + buffer.bytes } else { - ctx.log(s"No mirror class for module with linked class: ${claszSymbol.fullName}") - null + // Create an empty file to signal that a tasty section exist in the corresponding .class + // This is much cheaper and simpler to check than doing classfile parsing + getFileForClassfile(outF, store.name, ".hasTasty") + binary } - } else null - - // -------------- "plain" class -------------- - val pcb = new PlainClassBuilder(cunit) - pcb.genPlainClass(cd) - val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null; - val plainC = pcb.cnode - - if (claszSymbol.isClass) // @DarkDimius is this test needed here? - for (binary <- ctx.compilationUnit.pickled.get(claszSymbol.asClass)) { - val store = if (mirrorC ne null) mirrorC else plainC - val tasty = - if (!ctx.settings.YemitTastyInClass.value) { - val outTastyFile = getFileForClassfile(outF, store.name, ".tasty") - val outstream = new DataOutputStream(outTastyFile.bufferedOutput) - try outstream.write(binary) - finally outstream.close() - - val uuid = new TastyHeaderUnpickler(binary).readHeader() - val lo = uuid.getMostSignificantBits - val hi = uuid.getLeastSignificantBits - - // TASTY attribute is created but only the UUID bytes are stored in it. - // A TASTY attribute has length 16 if and only if the .tasty file exists. - val buffer = new TastyBuffer(16) - buffer.writeUncompressedLong(lo) - buffer.writeUncompressedLong(hi) - buffer.bytes - } else { - // Create an empty file to signal that a tasty section exist in the corresponding .class - // This is much cheaper and simpler to check than doing classfile parsing - getFileForClassfile(outF, store.name, ".hasTasty") - binary - } - val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, tasty) - store.visitAttribute(dataAttr) - } + val dataAttr = new CustomAttr(nme.TASTYATTR.mangledString, tasty) + store.visitAttribute(dataAttr) + } - // ----------- create files + // ----------- create files - val classNodes = List(mirrorC, plainC) - val classFiles = classNodes.map(cls => - if (outF != null && cls != null) { - try { - checkForCaseConflict(cls.name, claszSymbol) - getFileForClassfile(outF, cls.name, ".class") - } catch { - case e: FileConflictException => - ctx.error(s"error writing ${cls.name}: ${e.getMessage}") - null - } - } else null - ) + val classNodes = List(mirrorC, plainC) + val classFiles = classNodes.map(cls => + if (outF != null && cls != null) { + try { + checkForCaseConflict(cls.name, claszSymbol) + getFileForClassfile(outF, cls.name, ".class") + } catch { + case e: FileConflictException => + ctx.error(s"error writing ${cls.name}: ${e.getMessage}") + null + } + } else null + ) - // ----------- compiler and sbt's callbacks + // ----------- compiler and sbt's callbacks - val (fullClassName, isLocal) = ctx.atPhase(ctx.sbtExtractDependenciesPhase) { - (ExtractDependencies.classNameAsString(claszSymbol), claszSymbol.isLocal) - } + val (fullClassName, isLocal) = ctx.atPhase(ctx.sbtExtractDependenciesPhase) { + (ExtractDependencies.classNameAsString(claszSymbol), claszSymbol.isLocal) + } - for ((cls, clsFile) <- classNodes.zip(classFiles)) { - if (cls != null) { - val className = cls.name.replace('/', '.') - if (ctx.compilerCallback != null) - ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className) - if (ctx.sbtCallback != null) { - if (isLocal) - ctx.sbtCallback.generatedLocalClass(sourceFile.jfile.orElse(null), clsFile.file) - else { - ctx.sbtCallback.generatedNonLocalClass(sourceFile.jfile.orElse(null), clsFile.file, - className, fullClassName) - } + for ((cls, clsFile) <- classNodes.zip(classFiles)) { + if (cls != null) { + val className = cls.name.replace('/', '.') + if (ctx.compilerCallback != null) + ctx.compilerCallback.onClassGenerated(sourceFile, convertAbstractFile(clsFile), className) + if (ctx.sbtCallback != null) { + if (isLocal) + ctx.sbtCallback.generatedLocalClass(sourceFile.jfile.orElse(null), clsFile.file) + else { + ctx.sbtCallback.generatedNonLocalClass(sourceFile.jfile.orElse(null), clsFile.file, + className, fullClassName) } } } + } - // ----------- hand over to pipeline-2 + // ----------- hand over to pipeline-2 - val item2 = - Item2(arrivalPos, - SubItem2(mirrorC, classFiles(0)), - SubItem2(plainC, classFiles(1))) + val item2 = + Item2(arrivalPos, + SubItem2(mirrorC, classFiles(0)), + SubItem2(plainC, classFiles(1))) - q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done. + q2 add item2 // at the very end of this method so that no Worker2 thread starts mutating before we're done. - } // end of method visit(Item1) + } // end of method visit(Item1) - } // end of class BCodePhase.Worker1 + } // end of class BCodePhase.Worker1 - /* - * Pipeline that takes ClassNodes from queue-2. The unit of work depends on the optimization level: - * - * (a) no optimization involves: - * - converting the plain ClassNode to byte array and placing it on queue-3 - */ - class Worker2 { - // lazy val localOpt = new LocalOpt(new Settings()) - - private def localOptimizations(classNode: ClassNode): Unit = { - // BackendStats.timed(BackendStats.methodOptTimer)(localOpt.methodOptimizations(classNode)) - } + /* + * Pipeline that takes ClassNodes from queue-2. The unit of work depends on the optimization level: + * + * (a) no optimization involves: + * - converting the plain ClassNode to byte array and placing it on queue-3 + */ + class Worker2 { + // lazy val localOpt = new LocalOpt(new Settings()) + private def localOptimizations(classNode: ClassNode): Unit = { + // BackendStats.timed(BackendStats.methodOptTimer)(localOpt.methodOptimizations(classNode)) + } - /* Return an array of all serializable lambdas in this class */ - private def collectSerializableLambdas(classNode: ClassNode): Array[Handle] = { - val indyLambdaBodyMethods = new mutable.ArrayBuffer[Handle] - for (m <- classNode.methods.asScala) { - val iter = m.instructions.iterator - while (iter.hasNext) { - val insn = iter.next() - insn match { - case indy: InvokeDynamicInsnNode - // No need to check the exact bsmArgs because we only generate - // altMetafactory indy calls for serializable lambdas. - if indy.bsm == BCodeBodyBuilder.lambdaMetaFactoryAltMetafactoryHandle => - val implMethod = indy.bsmArgs(1).asInstanceOf[Handle] - indyLambdaBodyMethods += implMethod - case _ => - } + + /* Return an array of all serializable lambdas in this class */ + private def collectSerializableLambdas(classNode: ClassNode): Array[Handle] = { + val indyLambdaBodyMethods = new mutable.ArrayBuffer[Handle] + for (m <- classNode.methods.asScala) { + val iter = m.instructions.iterator + while (iter.hasNext) { + val insn = iter.next() + insn match { + case indy: InvokeDynamicInsnNode + // No need to check the exact bsmArgs because we only generate + // altMetafactory indy calls for serializable lambdas. + if indy.bsm == BCodeBodyBuilder.lambdaMetaFactoryAltMetafactoryHandle => + val implMethod = indy.bsmArgs(1).asInstanceOf[Handle] + indyLambdaBodyMethods += implMethod + case _ => } } - indyLambdaBodyMethods.toArray } + indyLambdaBodyMethods.toArray + } - /* - * Add: - * - * private static Object $deserializeLambda$(SerializedLambda l) { - * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$0](l) - * catch { - * case i: IllegalArgumentException => - * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$1](l) - * catch { - * case i: IllegalArgumentException => - * ... - * return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup${NUM_GROUPS-1}](l) - * } - * - * We use invokedynamic here to enable caching within the deserializer without needing to - * host a static field in the enclosing class. This allows us to add this method to interfaces - * that define lambdas in default methods. - * - * SI-10232 we can't pass arbitrary number of method handles to the final varargs parameter of the bootstrap - * method due to a limitation in the JVM. Instead, we emit a separate invokedynamic bytecode for each group of target - * methods. - */ - private def addLambdaDeserialize(classNode: ClassNode, implMethodsArray: Array[Handle]): Unit = { - import asm.Opcodes._ - import BCodeBodyBuilder._ - import bTypes._ - import coreBTypes._ - - val cw = classNode - - // Make sure to reference the ClassBTypes of all types that are used in the code generated - // here (e.g. java/util/Map) are initialized. Initializing a ClassBType adds it to - // `classBTypeFromInternalNameMap`. When writing the classfile, the asm ClassWriter computes - // stack map frames and invokes the `getCommonSuperClass` method. This method expects all - // ClassBTypes mentioned in the source code to exist in the map. - - val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectReference).descriptor - - val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null) - def emitLambdaDeserializeIndy(targetMethods: Seq[Handle]): Unit = { - mv.visitVarInsn(ALOAD, 0) - mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, targetMethods: _*) - } + /* + * Add: + * + * private static Object $deserializeLambda$(SerializedLambda l) { + * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$0](l) + * catch { + * case i: IllegalArgumentException => + * try return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup$1](l) + * catch { + * case i: IllegalArgumentException => + * ... + * return indy[scala.runtime.LambdaDeserialize.bootstrap, targetMethodGroup${NUM_GROUPS-1}](l) + * } + * + * We use invokedynamic here to enable caching within the deserializer without needing to + * host a static field in the enclosing class. This allows us to add this method to interfaces + * that define lambdas in default methods. + * + * SI-10232 we can't pass arbitrary number of method handles to the final varargs parameter of the bootstrap + * method due to a limitation in the JVM. Instead, we emit a separate invokedynamic bytecode for each group of target + * methods. + */ + private def addLambdaDeserialize(classNode: ClassNode, implMethodsArray: Array[Handle]): Unit = { + import asm.Opcodes._ + import BCodeBodyBuilder._ + import bTypes._ + import coreBTypes._ + + val cw = classNode + + // Make sure to reference the ClassBTypes of all types that are used in the code generated + // here (e.g. java/util/Map) are initialized. Initializing a ClassBType adds it to + // `classBTypeFromInternalNameMap`. When writing the classfile, the asm ClassWriter computes + // stack map frames and invokes the `getCommonSuperClass` method. This method expects all + // ClassBTypes mentioned in the source code to exist in the map. + + val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectReference).descriptor + + val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null) + def emitLambdaDeserializeIndy(targetMethods: Seq[Handle]): Unit = { + mv.visitVarInsn(ALOAD, 0) + mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle, targetMethods: _*) + } - val targetMethodGroupLimit = 255 - 1 - 3 // JVM limit. See See MAX_MH_ARITY in CallSite.java - val groups: Array[Array[Handle]] = implMethodsArray.grouped(targetMethodGroupLimit).toArray - val numGroups = groups.length + val targetMethodGroupLimit = 255 - 1 - 3 // JVM limit. See See MAX_MH_ARITY in CallSite.java + val groups: Array[Array[Handle]] = implMethodsArray.grouped(targetMethodGroupLimit).toArray + val numGroups = groups.length - import scala.tools.asm.Label - val initialLabels = Array.fill(numGroups - 1)(new Label()) - val terminalLabel = new Label - def nextLabel(i: Int) = if (i == numGroups - 2) terminalLabel else initialLabels(i + 1) + import scala.tools.asm.Label + val initialLabels = Array.fill(numGroups - 1)(new Label()) + val terminalLabel = new Label + def nextLabel(i: Int) = if (i == numGroups - 2) terminalLabel else initialLabels(i + 1) - for ((label, i) <- initialLabels.iterator.zipWithIndex) { - mv.visitTryCatchBlock(label, nextLabel(i), nextLabel(i), jlIllegalArgExceptionRef.internalName) - } - for ((label, i) <- initialLabels.iterator.zipWithIndex) { - mv.visitLabel(label) - emitLambdaDeserializeIndy(groups(i).toIndexedSeq) - mv.visitInsn(ARETURN) - } - mv.visitLabel(terminalLabel) - emitLambdaDeserializeIndy(groups(numGroups - 1).toIndexedSeq) + for ((label, i) <- initialLabels.iterator.zipWithIndex) { + mv.visitTryCatchBlock(label, nextLabel(i), nextLabel(i), jlIllegalArgExceptionRef.internalName) + } + for ((label, i) <- initialLabels.iterator.zipWithIndex) { + mv.visitLabel(label) + emitLambdaDeserializeIndy(groups(i).toIndexedSeq) mv.visitInsn(ARETURN) } + mv.visitLabel(terminalLabel) + emitLambdaDeserializeIndy(groups(numGroups - 1).toIndexedSeq) + mv.visitInsn(ARETURN) + } - def run(): Unit = { - while (true) { - val item = q2.poll - if (item.isPoison) { - q3 add poison3 - return - } - else { - try { - val plainNode = item.plain.classNode - localOptimizations(plainNode) - val serializableLambdas = collectSerializableLambdas(plainNode) - if (serializableLambdas.nonEmpty) - addLambdaDeserialize(plainNode, serializableLambdas) - addToQ3(item) - } catch { - case ex: Throwable => - println(s"Error while emitting ${item.plain.classNode.name}") - throw ex - } + def run(): Unit = { + while (true) { + val item = q2.poll + if (item.isPoison) { + q3 add poison3 + return + } + else { + try { + val plainNode = item.plain.classNode + localOptimizations(plainNode) + val serializableLambdas = collectSerializableLambdas(plainNode) + if (serializableLambdas.nonEmpty) + addLambdaDeserialize(plainNode, serializableLambdas) + addToQ3(item) + } catch { + case ex: Throwable => + println(s"Error while emitting ${item.plain.classNode.name}") + throw ex } } } + } - private def addToQ3(item: Item2) = { - - def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = { - val cw = new CClassWriter(extraProc) - cn.accept(cw) - cw.toByteArray - } + private def addToQ3(item: Item2) = { - val Item2(arrivalPos, SubItem2(mirror, mirrorFile), SubItem2(plain, plainFile)) = item + def getByteArray(cn: asm.tree.ClassNode): Array[Byte] = { + val cw = new CClassWriter(extraProc) + cn.accept(cw) + cw.toByteArray + } - val mirrorC = if (mirror == null) null else SubItem3(mirror.name, getByteArray(mirror), mirrorFile) - val plainC = SubItem3(plain.name, getByteArray(plain), plainFile) + val Item2(arrivalPos, SubItem2(mirror, mirrorFile), SubItem2(plain, plainFile)) = item - if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) { - if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes) - AsmUtils.traceClass(plainC.jclassBytes) - } + val mirrorC = if (mirror == null) null else SubItem3(mirror.name, getByteArray(mirror), mirrorFile) + val plainC = SubItem3(plain.name, getByteArray(plain), plainFile) - q3 add Item3(arrivalPos, mirrorC, plainC) + if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) { + if (mirrorC != null) AsmUtils.traceClass(mirrorC.jclassBytes) + AsmUtils.traceClass(plainC.jclassBytes) } - } // end of class BCodePhase.Worker2 - - var arrivalPos: Int = 0 - - /* - * A run of the BCodePhase phase comprises: - * - * (a) set-up steps (most notably supporting maps in `BCodeTypes`, - * but also "the" writer where class files in byte-array form go) - * - * (b) building of ASM ClassNodes, their optimization and serialization. - * - * (c) tear down (closing the classfile-writer and clearing maps) - * - */ - def run(t: Tree): Unit = { - this.tree = t - - // val bcodeStart = Statistics.startTimer(BackendStats.bcodeTimer) - - // val initStart = Statistics.startTimer(BackendStats.bcodeInitTimer) - arrivalPos = 0 // just in case - // scalaPrimitives.init() - bTypes.intializeCoreBTypes() - // Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart) - - // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated. - bytecodeWriter = initBytecodeWriter() - mirrorCodeGen = new JMirrorBuilder - - val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter] - buildAndSendToDisk(needsOutfileForSymbol) - - // closing output files. - bytecodeWriter.close() - // Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart) - - if (ctx.compilerCallback != null) - ctx.compilerCallback.onSourceCompiled(sourceFile) - - /* TODO Bytecode can be verified (now that all classfiles have been written to disk) - * - * (1) asm.util.CheckAdapter.verify() - * public static void verify(ClassReader cr, ClassLoader loader, boolean dump, PrintWriter pw) - * passing a custom ClassLoader to verify inter-dependent classes. - * Alternatively, - * - an offline-bytecode verifier could be used (e.g. Maxine brings one as separate tool). - * - -Xverify:all - * - * (2) if requested, check-java-signatures, over and beyond the syntactic checks in `getGenericSignature()` - * - */ + q3 add Item3(arrivalPos, mirrorC, plainC) } - /* - * Sequentially: - * (a) place all ClassDefs in queue-1 - * (b) dequeue one at a time from queue-1, convert it to ASM ClassNode, place in queue-2 - * (c) dequeue one at a time from queue-2, convert it to byte-array, place in queue-3 - * (d) serialize to disk by draining queue-3. - */ - private def buildAndSendToDisk(needsOutFolder: Boolean) = { + } // end of class BCodePhase.Worker2 + + var arrivalPos: Int = 0 + + /* + * A run of the BCodePhase phase comprises: + * + * (a) set-up steps (most notably supporting maps in `BCodeTypes`, + * but also "the" writer where class files in byte-array form go) + * + * (b) building of ASM ClassNodes, their optimization and serialization. + * + * (c) tear down (closing the classfile-writer and clearing maps) + * + */ + def run(t: Tree): Unit = { + this.tree = t + + // val bcodeStart = Statistics.startTimer(BackendStats.bcodeTimer) + + // val initStart = Statistics.startTimer(BackendStats.bcodeInitTimer) + arrivalPos = 0 // just in case + // scalaPrimitives.init() + bTypes.intializeCoreBTypes() + // Statistics.stopTimer(BackendStats.bcodeInitTimer, initStart) + + // initBytecodeWriter invokes fullName, thus we have to run it before the typer-dependent thread is activated. + bytecodeWriter = initBytecodeWriter() + mirrorCodeGen = new JMirrorBuilder + + val needsOutfileForSymbol = bytecodeWriter.isInstanceOf[ClassBytecodeWriter] + buildAndSendToDisk(needsOutfileForSymbol) + + // closing output files. + bytecodeWriter.close() + // Statistics.stopTimer(BackendStats.bcodeTimer, bcodeStart) + + if (ctx.compilerCallback != null) + ctx.compilerCallback.onSourceCompiled(sourceFile) + + /* TODO Bytecode can be verified (now that all classfiles have been written to disk) + * + * (1) asm.util.CheckAdapter.verify() + * public static void verify(ClassReader cr, ClassLoader loader, boolean dump, PrintWriter pw) + * passing a custom ClassLoader to verify inter-dependent classes. + * Alternatively, + * - an offline-bytecode verifier could be used (e.g. Maxine brings one as separate tool). + * - -Xverify:all + * + * (2) if requested, check-java-signatures, over and beyond the syntactic checks in `getGenericSignature()` + * + */ + } - feedPipeline1() - // val genStart = Statistics.startTimer(BackendStats.bcodeGenStat) - (new Worker1(needsOutFolder)).run() - // Statistics.stopTimer(BackendStats.bcodeGenStat, genStart) + /* + * Sequentially: + * (a) place all ClassDefs in queue-1 + * (b) dequeue one at a time from queue-1, convert it to ASM ClassNode, place in queue-2 + * (c) dequeue one at a time from queue-2, convert it to byte-array, place in queue-3 + * (d) serialize to disk by draining queue-3. + */ + private def buildAndSendToDisk(needsOutFolder: Boolean) = { - (new Worker2).run() + feedPipeline1() + // val genStart = Statistics.startTimer(BackendStats.bcodeGenStat) + (new Worker1(needsOutFolder)).run() + // Statistics.stopTimer(BackendStats.bcodeGenStat, genStart) - // val writeStart = Statistics.startTimer(BackendStats.bcodeWriteTimer) - drainQ3() - // Statistics.stopTimer(BackendStats.bcodeWriteTimer, writeStart) + (new Worker2).run() - } + // val writeStart = Statistics.startTimer(BackendStats.bcodeWriteTimer) + drainQ3() + // Statistics.stopTimer(BackendStats.bcodeWriteTimer, writeStart) - /* Feed pipeline-1: place all ClassDefs on q1, recording their arrival position. */ - private def feedPipeline1() = { - def gen(tree: Tree): Unit = { - tree match { - case EmptyTree => () - case PackageDef(_, stats) => stats foreach gen - case ValDef(name, tpt, rhs) => () // module val not emitted - case cd: TypeDef => - q1 add Item1(arrivalPos, cd, int.currentUnit) - arrivalPos += 1 - } + } + + /* Feed pipeline-1: place all ClassDefs on q1, recording their arrival position. */ + private def feedPipeline1() = { + def gen(tree: Tree): Unit = { + tree match { + case EmptyTree => () + case PackageDef(_, stats) => stats foreach gen + case ValDef(name, tpt, rhs) => () // module val not emitted + case cd: TypeDef => + q1 add Item1(arrivalPos, cd, int.currentUnit) + arrivalPos += 1 } - gen(tree) - q1 add poison1 } + gen(tree) + q1 add poison1 + } - /* Pipeline that writes classfile representations to disk. */ - private def drainQ3() = { + /* Pipeline that writes classfile representations to disk. */ + private def drainQ3() = { - def sendToDisk(cfr: SubItem3): Unit = { - if (cfr != null){ - val SubItem3(jclassName, jclassBytes, jclassFile) = cfr - bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, jclassFile) - } + def sendToDisk(cfr: SubItem3): Unit = { + if (cfr != null){ + val SubItem3(jclassName, jclassBytes, jclassFile) = cfr + bytecodeWriter.writeClass(jclassName, jclassName, jclassBytes, jclassFile) } + } - var moreComing = true - // `expected` denotes the arrivalPos whose Item3 should be serialized next - var expected = 0 - - while (moreComing) { - val incoming = q3.poll - moreComing = !incoming.isPoison - if (moreComing) { - val item = incoming - sendToDisk(item.mirror) - sendToDisk(item.plain) - expected += 1 - } + var moreComing = true + // `expected` denotes the arrivalPos whose Item3 should be serialized next + var expected = 0 + + while (moreComing) { + val incoming = q3.poll + moreComing = !incoming.isPoison + if (moreComing) { + val item = incoming + sendToDisk(item.mirror) + sendToDisk(item.plain) + expected += 1 } + } - // we're done - assert(q1.isEmpty, s"Some ClassDefs remained in the first queue: $q1") - assert(q2.isEmpty, s"Some classfiles remained in the second queue: $q2") - assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3") + // we're done + assert(q1.isEmpty, s"Some ClassDefs remained in the first queue: $q1") + assert(q2.isEmpty, s"Some classfiles remained in the second queue: $q2") + assert(q3.isEmpty, s"Some classfiles weren't written to disk: $q3") - } + } //} // end of class BCodePhase } diff --git a/compiler/src/dotty/tools/dotc/Driver.scala b/compiler/src/dotty/tools/dotc/Driver.scala index 924a9162bdb9..b1089b066cdb 100644 --- a/compiler/src/dotty/tools/dotc/Driver.scala +++ b/compiler/src/dotty/tools/dotc/Driver.scala @@ -72,22 +72,21 @@ class Driver { // Resolve classpath and class names of tasty files val (classPaths, classNames) = fileNames0.flatMap { name => val path = Paths.get(name) - if (name.endsWith(".jar")) { + if (name.endsWith(".jar")) new dotty.tools.io.Jar(File(name)).toList.collect { case e if e.getName.endsWith(".tasty") => (name, e.getName.stripSuffix(".tasty").replace("/", ".")) } - } else if (!name.endsWith(".tasty")) ("", name) :: Nil - else if (Files.exists(path)) { + else if (Files.exists(path)) TastyFileUtil.getClassName(path) match { case Some(res) => res:: Nil case _ => ctx0.error(s"Could not load classname from $name.") ("", name) :: Nil } - } else { + else { ctx0.error(s"File $name does not exist.") ("", name) :: Nil } diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index ec3df458b67b..fbdacce2e28b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -454,8 +454,9 @@ object desugar { if (isCaseClass) ctx.error(CaseClassMissingParamList(cdef), namePos) ListOfNil - } else if (isCaseClass && originalVparamss.head.exists(_.mods.isOneOf(GivenOrImplicit))) { - ctx.error("Case classes should have a non-implicit parameter list", namePos) + } + else if (isCaseClass && originalVparamss.head.exists(_.mods.isOneOf(GivenOrImplicit))) { + ctx.error("Case classes should have a non-implicit parameter list", namePos) ListOfNil } else originalVparamss.nestedMap(toDefParam(_, keepAnnotations = false)) @@ -717,12 +718,11 @@ object desugar { } else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum) companionDefs(anyRef, companionMembers) - else if (isValueClass) { + else if (isValueClass) impl.constr.vparamss match { case (_ :: Nil) :: _ => companionDefs(anyRef, Nil) case _ => Nil // error will be emitted in typer } - } else Nil enumCompanionRef match { @@ -1133,12 +1133,11 @@ object desugar { case tree: MemberDef => var tested: MemberDef = tree def fail(msg: String) = ctx.error(msg, tree.sourcePos) - def checkApplicable(flag: Flag, test: MemberDefTest): Unit = { + def checkApplicable(flag: Flag, test: MemberDefTest): Unit = if (tested.mods.is(flag) && !test.applyOrElse(tree, (md: MemberDef) => false)) { fail(i"modifier `${flag.flagsString}` is not allowed for this definition") tested = tested.withMods(tested.mods.withoutFlags(flag)) } - } checkApplicable(Opaque, legalOpaque) tested case _ => diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index e23e899a91b9..333a4caf49d3 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -42,7 +42,8 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => if (param.info.isRepeatedParam) { for (arg <- args) f(param, arg) true - } else args match { + } + else args match { case Nil => false case arg :: args1 => f(param, args.head) diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 6b7c92b6d09e..fad5cfc14811 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -1468,7 +1468,7 @@ object Trees { case _ => foldMoreCases(x, tree) } - } + } def foldMoreCases(x: X, tree: Tree)(implicit ctx: Context): X = { assert(ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), tree) diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala index 0195da7a4f6c..de3673501a59 100644 --- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala +++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala @@ -107,7 +107,8 @@ class CheckRealizable(implicit ctx: Context) { if (tp.info.isStable && tpInfoRealizable == Realizable) { sym.setFlag(StableRealizable) Realizable - } else r + } + else r } } case _: SingletonType | NoPrefix => diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index d14fcb34ab7f..0a1a1071c866 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -371,9 +371,8 @@ object Comments { superComment(sym) foreach { sc => val superSections = tagIndex(sc) replaceWith(sc.substring(3, startTag(sc, superSections))) - for (sec @ (start, end) <- superSections) { + for (sec @ (start, end) <- superSections) if (!isMovable(sc, sec)) out append sc.substring(start, end) - } } case "" => idx += 1 case vname => diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 163ebe4a0639..a2678ce98189 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -390,7 +390,7 @@ object Names { override def toString: String = if (length == 0) "" else { - if (Config.checkBackendNames) { + if (Config.checkBackendNames) if (!toStringOK) { // We print the stacktrace instead of doing an assert directly, // because asserts are caught in exception handlers which might @@ -400,7 +400,6 @@ object Names { Thread.dumpStack() assert(false) } - } new String(chrs, start, length) } diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala index 20de65ec0949..e578d5f0032e 100644 --- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala +++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala @@ -484,12 +484,11 @@ class OrderingConstraint(private val boundsMap: ParamBounds, def foreachTypeVar(op: TypeVar => Unit): Unit = boundsMap.foreachBinding { (poly, entries) => - for (i <- 0 until paramCount(entries)) { + for (i <- 0 until paramCount(entries)) typeVar(entries, i) match { case tv: TypeVar if !tv.inst.exists => op(tv) case _ => } - } } def & (other: Constraint, otherHasErrors: Boolean)(implicit ctx: Context): OrderingConstraint = { diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 9563015a09f3..be885758046e 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -86,18 +86,19 @@ trait SymDenotations { this: Context => else { implicit val ctx = this val initial = denot.initial - if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) { + if ((initial ne denot) || ctx.phaseId != initial.validFor.firstPhaseId) ctx.withPhase(initial.validFor.firstPhaseId).traceInvalid(initial) - } else try { + else try { val owner = denot.owner.denot if (!traceInvalid(owner)) explainSym("owner is invalid") else if (!owner.isClass || owner.isRefinementClass || denot.isSelfSym) true else if (owner.unforcedDecls.lookupAll(denot.name) contains denot.symbol) true else explainSym(s"decls of ${show(owner)} are ${owner.unforcedDecls.lookupAll(denot.name).toList}, do not contain ${denot.symbol}") - } catch { + } + catch { case ex: StaleSymbol => explainSym(s"$ex was thrown") } - } + } case _ => explain("denotation is not a SymDenotation") } diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index 89bb068edff3..6c5239293db0 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -466,7 +466,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w case _ => val cls2 = tp2.symbol - if (cls2.isClass) { + if (cls2.isClass) if (cls2.typeParams.isEmpty) { if (cls2 eq AnyKindClass) return true if (tp1.isRef(NothingClass)) return true @@ -485,7 +485,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w } else if (tp1.isLambdaSub && !tp1.isRef(AnyKindClass)) return recur(tp1, EtaExpansion(cls2.typeRef)) - } fourthTry } diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index a51d27311e26..15c3537de67c 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -68,7 +68,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. case pre: SuperType => toPrefix(pre.thistpe, cls, thiscls) case _ => if (thiscls.derivesFrom(cls) && pre.baseType(thiscls).exists) - if (variance <= 0 && !isLegalPrefix(pre)) { + if (variance <= 0 && !isLegalPrefix(pre)) if (variance < 0) { approximated = true defn.NothingType @@ -80,7 +80,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object. // is not possible, then `expandBounds` will end up being // called which we override to set the `approximated` flag. range(defn.NothingType, pre) - } else pre else if ((pre.termSymbol is Package) && !(thiscls is Package)) toPrefix(pre.select(nme.PACKAGE), cls, thiscls) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index d1aaf780ccdd..eae0aa9cd8cb 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -646,9 +646,8 @@ object Types { else tp rt.opened = true try go(rt.parent).mapInfo(_.substRecThis(rt, pre)) - finally { + finally if (!rt.openedTwice) rt.opened = false - } } def goRefined(tp: RefinedType) = { @@ -1359,11 +1358,10 @@ object Types { case tp @ AppliedType(tycon, args) if tycon.typeSymbol.isClass => tycon.parents.map(_.subst(tycon.typeSymbol.typeParams, args)) case tp: TypeRef => - if (tp.info.isInstanceOf[TempClassInfo]) { + if (tp.info.isInstanceOf[TempClassInfo]) tp.recomputeDenot() // We usually should have `!tp.info.isInstanceOf[TempClassInfo]` here, but // this can be falsified for code with illegal cyclic references. See neg/i7107.scala. - } tp.info.parents case tp: TypeProxy => tp.superType.parents @@ -2104,9 +2102,9 @@ object Types { try { ctx.pendingUnderlying += this op - } finally { - ctx.pendingUnderlying -= this } + finally + ctx.pendingUnderlying -= this } finally ctx.base.underlyingRecursions -= 1 @@ -4768,7 +4766,7 @@ object Types { case _ => tp.derivedRefinedType(parent, tp.refinedName, info) } - } + } override protected def derivedRecType(tp: RecType, parent: Type): Type = if (parent eq tp.parent) tp @@ -4802,7 +4800,7 @@ object Types { case Range(tyconLo, tyconHi) => range(derivedAppliedType(tp, tyconLo, args), derivedAppliedType(tp, tyconHi, args)) case _ => - if (args.exists(isRange)) { + if (args.exists(isRange)) if (variance > 0) tp.derivedAppliedType(tycon, args.map(rangeToBounds)) else { val loBuf, hiBuf = new mutable.ListBuffer[Type] @@ -4834,7 +4832,6 @@ object Types { else range(defn.NothingType, defn.AnyType) // TODO: can we give a better bound than `topType`? } - } else tp.derivedAppliedType(tycon, args) } diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index e69c2cae6bae..ad1f764417c2 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -655,6 +655,7 @@ object Parsers { } def needsBraces(t: Any): Boolean = t match { + case Match(EmptyTree, _) => true case Block(stats, expr) => stats.nonEmpty || needsBraces(expr) case expr: Tree => @@ -712,8 +713,9 @@ object Parsers { val (startOpening, endOpening) = startingElimRegion(colonRequired) val isOutermost = in.currentRegion.isOutermost def allBraces(r: Region): Boolean = r match { + case r: Indented => r.isOutermost || allBraces(r.enclosing) case r: InBraces => allBraces(r.enclosing) - case _ => r.isOutermost + case _ => false } var canRewrite = allBraces(in.currentRegion) && // test (1) !testChars(in.lastOffset - 3, " =>") // test(6) @@ -1176,6 +1178,11 @@ object Parsers { newLineOptWhenFollowedBy(LBRACE) } + def possibleTemplateStart(): Unit = { + in.observeIndented() + newLineOptWhenFollowedBy(LBRACE) + } + def indentRegion[T](tag: EndMarkerTag)(op: => T): T = { val iw = in.currentRegion.indentWidth val t = op @@ -1843,7 +1850,7 @@ object Parsers { def matchExpr(t: Tree, start: Offset, mkMatch: (Tree, List[CaseDef]) => Match) = indentRegion(MATCH) { atSpan(start, in.skipToken()) { - inBracesOrIndented(mkMatch(t, caseClauses(caseClause))) + mkMatch(t, inBracesOrIndented(caseClauses(caseClause))) } } @@ -3328,7 +3335,7 @@ object Parsers { if (in.token == LPAREN) try paramClause(prefix = true) :: Nil finally { - possibleBracesStart() + possibleTemplateStart() if (!in.isNestedStart) syntaxErrorOrIncomplete("`{' expected") } else Nil @@ -3346,7 +3353,7 @@ object Parsers { DefDef(name, tparams, vparamss, parents.head, expr()) } else { - possibleBracesStart() + possibleTemplateStart() val (tparams1, vparamss1) = if (leadingParamss.nonEmpty) (tparams, leadingParamss) @@ -3446,7 +3453,7 @@ object Parsers { */ def template(constr: DefDef, isEnum: Boolean = false): Template = { val (parents, derived) = inheritClauses() - possibleBracesStart() + possibleTemplateStart() if (isEnum) { val (self, stats) = withinEnum(templateBody()) Template(constr, parents, derived, self, stats) @@ -3456,13 +3463,15 @@ object Parsers { /** TemplateOpt = [Template] */ - def templateOpt(constr: DefDef): Template = { + def templateOpt(constr: DefDef): Template = possibleBracesStart() - if (in.token == EXTENDS || isIdent(nme.derives) || in.isNestedStart) + if (in.token == EXTENDS || isIdent(nme.derives)) template(constr) - else - Template(constr, Nil, Nil, EmptyValDef, Nil) - } + else { + possibleTemplateStart() + if (in.isNestedStart) template(constr) + else Template(constr, Nil, Nil, EmptyValDef, Nil) + } /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' */ @@ -3494,7 +3503,7 @@ object Parsers { def packaging(start: Int): Tree = { val pkg = qualId() indentRegion(pkg) { - possibleBracesStart() + possibleTemplateStart() val stats = inDefScopeBraces(topStatSeq()) makePackaging(start, pkg, stats) } @@ -3700,7 +3709,7 @@ object Parsers { else { val pkg = qualId() indentRegion(pkg) { - possibleBracesStart() + possibleTemplateStart() if (in.token == EOF) ts += makePackaging(start, pkg, List()) else if (in.isNestedStart) { diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 2dbcf42ab278..59decddfa97c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -28,6 +28,8 @@ object Scanners { type Token = Int + private val identity: IndentWidth => IndentWidth = Predef.identity + trait TokenData { /** the next token */ @@ -372,7 +374,7 @@ object Scanners { def isLeadingInfixOperator() = ( allowLeadingInfixOperators && ( token == BACKQUOTED_IDENT - || token == IDENTIFIER && isOperatorPart(name(name.length - 1))) + || token == IDENTIFIER && isOperatorPart(name(name.length - 1))) && ch == ' ' && !pastBlankLine && { @@ -392,25 +394,24 @@ object Scanners { } ) - /** The indentation width of the given offset. - * It is assumed that only blank characters are between the start of the line and the offset. - */ + /** The indentation width of the given offset */ def indentWidth(offset: Offset): IndentWidth = { import IndentWidth.{Run, Conc} - def recur(idx: Int, ch: Char, n: Int): IndentWidth = - if (idx < 0) Run(ch, n) + def recur(idx: Int, ch: Char, n: Int, k: IndentWidth => IndentWidth): IndentWidth = + if (idx < 0) k(Run(ch, n)) else { val nextChar = buf(idx) - if (nextChar == ' ' || nextChar == '\t') + if (nextChar == LF) k(Run(ch, n)) + else if (nextChar == ' ' || nextChar == '\t') if (nextChar == ch) - recur(idx - 1, ch, n + 1) + recur(idx - 1, ch, n + 1, k) else { - val prefix = recur(idx - 1, nextChar, 1) - if (n == 0) prefix else Conc(prefix, Run(ch, n)) + val k1: IndentWidth => IndentWidth = if (n == 0) k else Conc(_, Run(ch, n)) + recur(idx - 1, nextChar, 1, k1) } - else Run(ch, n) + else recur(idx - 1, ' ', 0, identity) } - recur(offset - 1, ' ', 0) + recur(offset - 1, ' ', 0, identity) } /** Handle newlines, possibly inserting an INDENT, OUTDENT, NEWLINE, or NEWLINES token @@ -531,6 +532,25 @@ object Scanners { } } + def observeIndented(): Unit = + if (indentSyntax && isAfterLineEnd && token != INDENT) { + val newLineInserted = token == NEWLINE || token == NEWLINES + val nextOffset = if (newLineInserted) next.offset else offset + val nextWidth = indentWidth(nextOffset) + val lastWidth = currentRegion match { + case r: Indented => r.width + case r: InBraces => r.width + case _ => nextWidth + } + + if (lastWidth < nextWidth) { + currentRegion = Indented(nextWidth, Set(), COLONEOL, currentRegion) + if (!newLineInserted) next.copyFrom(this) + offset = nextOffset + token = INDENT + } + } + /** - Join CASE + CLASS => CASECLASS, CASE + OBJECT => CASEOBJECT, SEMI + ELSE => ELSE, COLON + => COLONEOL * - Insert missing OUTDENTs at EOF */ @@ -1267,6 +1287,7 @@ object Scanners { /* Initialization: read first char, then first token */ nextChar() nextToken() + currentRegion = Indented(indentWidth(offset), Set(), EMPTY, null) } // end Scanner @@ -1342,6 +1363,7 @@ object Scanners { } } } + object IndentWidth { private inline val MaxCached = 40 private val spaces = Array.tabulate(MaxCached + 1)(new Run(' ', _)) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 2de86ab1d550..0304fe7ccdd3 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -742,12 +742,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { def tparamsText[T >: Untyped](params: List[Tree[T]]): Text = "[" ~ toText(params, ", ") ~ "]" provided params.nonEmpty - def addVparamssText[T >: Untyped](leading: Text, vparamss: List[List[ValDef[T]]]): Text = { + def addVparamssText[T >: Untyped](leading: Text, vparamss: List[List[ValDef[T]]]): Text = vparamss.foldLeft(leading)((txt, params) => txt ~ (Str(" given ") provided params.nonEmpty && params.head.mods.is(Given)) ~ paramsText(params)) - } protected def valDefToText[T >: Untyped](tree: ValDef[T]): Text = { import untpd.{modsDeco => _} dclTextOr(tree) { diff --git a/compiler/src/dotty/tools/dotc/reporting/trace.scala b/compiler/src/dotty/tools/dotc/reporting/trace.scala index 02e75d55e0de..bf85dc8de82d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/trace.scala +++ b/compiler/src/dotty/tools/dotc/reporting/trace.scala @@ -91,13 +91,12 @@ abstract class TraceSyntax { if (ctx.mode.is(Mode.Printing)) op else { var finalized = false - def finalize(result: Any, note: String) = { + def finalize(result: Any, note: String) = if (!finalized) { ctx.base.indent -= 1 log(s"${ctx.base.indentTab * ctx.base.indent}${trailing(result)}$note") finalized = true } - } try { log(s"${ctx.base.indentTab * ctx.base.indent}$leading") ctx.base.indent += 1 diff --git a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala index 9c26de87d227..37eebce9ac55 100644 --- a/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala +++ b/compiler/src/dotty/tools/dotc/transform/CapturedVars.scala @@ -82,9 +82,8 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase = */ def refClass(cls: Symbol, isVolatile: Boolean)(implicit ctx: Context): Symbol = { val refMap = if (isVolatile) refInfo.volatileRefClass else refInfo.refClass - if (cls.isClass) { + if (cls.isClass) refMap.getOrElse(cls, refMap(defn.ObjectClass)) - } else refMap(defn.ObjectClass) } @@ -108,7 +107,8 @@ class CapturedVars extends MiniPhase with IdentityDenotTransformer { thisPhase = cpy.ValDef(vdef)( rhs = boxMethod(nme.create).appliedTo(vdef.rhs), tpt = TypeTree(vble.info).withSpan(vdef.tpt.span)) - } else vdef + } + else vdef } override def transformIdent(id: Ident)(implicit ctx: Context): Tree = { diff --git a/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala index d0f36a185150..140940820553 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckReentrant.scala @@ -55,12 +55,12 @@ class CheckReentrant extends MiniPhase { finally indent -= 1 } - def addVars(cls: ClassSymbol)(implicit ctx: Context): Unit = { + def addVars(cls: ClassSymbol)(implicit ctx: Context): Unit = if (!seen.contains(cls) && !isIgnored(cls)) { seen += cls scanning(cls) { - for (sym <- cls.classInfo.decls) { - if (sym.isTerm && !sym.isSetter && !isIgnored(sym)) { + for (sym <- cls.classInfo.decls) + if (sym.isTerm && !sym.isSetter && !isIgnored(sym)) if (sym.is(Mutable)) { ctx.error( i"""possible data race involving globally reachable ${sym.showLocated}: ${sym.info} @@ -71,13 +71,10 @@ class CheckReentrant extends MiniPhase { scanning(sym) { sym.info.widenExpr.classSymbols.foreach(addVars) } - } - } for (parent <- cls.classInfo.classParents) addVars(parent.classSymbol.asClass) } } - } override def transformTemplate(tree: Template)(implicit ctx: Context): Tree = { if (ctx.settings.YcheckReentrant.value && tree.symbol.owner.isStaticOwner) diff --git a/compiler/src/dotty/tools/dotc/transform/Constructors.scala b/compiler/src/dotty/tools/dotc/transform/Constructors.scala index a7671194f574..49e3c4805d67 100644 --- a/compiler/src/dotty/tools/dotc/transform/Constructors.scala +++ b/compiler/src/dotty/tools/dotc/transform/Constructors.scala @@ -74,7 +74,7 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = } else retain() case _ => retain() - } + } } } @@ -159,14 +159,12 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = if (noDirectRefsFrom(tree)) tree else super.transform(tree) } - def apply(tree: Tree, prevOwner: Symbol)(implicit ctx: Context): Tree = { + def apply(tree: Tree, prevOwner: Symbol)(implicit ctx: Context): Tree = transform(tree).changeOwnerAfter(prevOwner, constr.symbol, thisPhase) - } } - def isRetained(acc: Symbol) = { + def isRetained(acc: Symbol) = !mightBeDropped(acc) || retainedPrivateVals(acc) - } val constrStats, clsStats = new mutable.ListBuffer[Tree] @@ -223,7 +221,8 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = if (!isRetained(acc)) { dropped += acc Nil - } else { + } + else { if (acc.hasAnnotation(defn.TransientParamAnnot)) ctx.error(em"transient parameter $acc is retained as field in class ${acc.owner}", acc.sourcePos) val target = if (acc.is(Method)) acc.field else acc @@ -250,7 +249,6 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase = cls.copy( info = clsInfo.derivedClassInfo( decls = clsInfo.decls.filteredScope(!dropped.contains(_)))) - // TODO: this happens to work only because Constructors is the last phase in group } diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 5aa109bbb9a6..dcb680e77b7d 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -54,7 +54,8 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase => if (paramTypes.nonEmpty && paramTypes.last.isRepeatedParam) { val last = paramTypes.last.underlyingIfRepeated(tp.isJavaMethod) paramTypes.init :+ last - } else paramTypes + } + else paramTypes tp.derivedLambdaType(paramNames, paramTypes1, resultType1) case tp: PolyType => tp.derivedLambdaType(tp.paramNames, tp.paramInfos, elimRepeated(tp.resultType)) diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index f71818aabeaa..27e903e488e0 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -54,9 +54,8 @@ class Erasure extends Phase with DenotTransformer { // After erasure, all former Any members are now Object members val ClassInfo(pre, _, ps, decls, selfInfo) = ref.info val extendedScope = decls.cloneScope - for (decl <- defn.AnyClass.classInfo.decls) { + for (decl <- defn.AnyClass.classInfo.decls) if (!decl.isConstructor) extendedScope.enter(decl) - } ref.copySymDenotation( info = transformInfo(ref.symbol, ClassInfo(pre, defn.ObjectClass, ps, extendedScope, selfInfo)) diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala index 04f2cf02e90e..d026a805144f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandPrivate.scala @@ -39,23 +39,20 @@ class ExpandPrivate extends MiniPhase with IdentityDenotTransformer { thisPhase override def changesMembers: Boolean = true // the phase introduces new members with mangled names - override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { + override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match { case t: DefDef => val sym = t.symbol - def hasWeakerAccess(other: Symbol) = { + def hasWeakerAccess(other: Symbol) = // public > protected > /* default */ > private if (sym.is(Private)) other.is(Private) else if (sym.is(Protected)) other.isOneOf(Protected | Private) else true // sym is public - } val fail = sym.allOverriddenSymbols.findSymbol(x => !hasWeakerAccess(x)) - if (fail.exists) { + if (fail.exists) assert(false, i"${sym.showFullName}: ${sym.info} has weaker access than superclass method ${fail.showFullName}: ${fail.info}") - } case _ => } - } private def isVCPrivateParamAccessor(d: SymDenotation)(implicit ctx: Context) = d.isTerm && d.isAllOf(PrivateParamAccessor) && isDerivedValueClass(d.owner) diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 432dbc4b5db3..86b15800f548 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -80,7 +80,7 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => if (clsHasOuter || cls.mixins.exists(needsOuterIfReferenced)) { val newDefs = new mutable.ListBuffer[Tree] - if (clsHasOuter) { + if (clsHasOuter) if (isTrait) newDefs += DefDef(outerAccessor(cls).asTerm, EmptyTree) else { @@ -88,22 +88,19 @@ class ExplicitOuter extends MiniPhase with InfoTransformer { thisPhase => newDefs += ValDef(outerParamAcc, EmptyTree) newDefs += DefDef(outerAccessor(cls).asTerm, ref(outerParamAcc)) } - } - for (parentTrait <- cls.mixins) { + for (parentTrait <- cls.mixins) if (needsOuterIfReferenced(parentTrait)) { val parentTp = cls.denot.thisType.baseType(parentTrait) val outerAccImpl = newOuterAccessor(cls, parentTrait).enteredAfter(thisPhase) newDefs += DefDef(outerAccImpl, singleton(fixThis(outerPrefix(parentTp)))) } - } val parents1 = for (parent <- impl.parents) yield { val parentCls = parent.tpe.classSymbol.asClass - if (parentCls.is(Trait)) { + if (parentCls.is(Trait)) parent - } else parent match { // ensure class parent is a constructor case parent: TypeTree => New(parent.tpe, Nil).withSpan(impl.span) case _ => parent diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala index e62ca5079ff3..c6b53b158123 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -108,10 +108,9 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete } // Drop the Local flag from all private[this] and protected[this] members // that will be moved to the companion object. - if (ref.is(Local) && isDerivedValueClass(ref.owner)) { + if (ref.is(Local) && isDerivedValueClass(ref.owner)) if (ref1 ne ref) ref1.resetFlag(Local) else ref1 = ref1.copySymDenotation(initFlags = ref1.flags &~ Local) - } ref1 case _ => ref.info match { @@ -145,13 +144,13 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete // TODO: this is state and should be per-run // todo: check that when transformation finished map is empty - override def transformTemplate(tree: tpd.Template)(implicit ctx: Context): tpd.Tree = { - if (isDerivedValueClass(ctx.owner)) { + override def transformTemplate(tree: tpd.Template)(implicit ctx: Context): tpd.Tree = + if (isDerivedValueClass(ctx.owner)) /* This is currently redundant since value classes may not wrap over other value classes anyway. checkNonCyclic(ctx.owner.pos, Set(), ctx.owner) */ tree - } else if (ctx.owner.isStaticOwner) { + else if (ctx.owner.isStaticOwner) extensionDefs remove tree.symbol.owner match { case Some(defns) if defns.nonEmpty => cpy.Template(tree)(body = tree.body ++ @@ -159,10 +158,9 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete case _ => tree } - } else tree - } + else tree - override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context): tpd.Tree = { + override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context): tpd.Tree = if (isMethodWithExtension(tree.symbol)) { val origMeth = tree.symbol val origClass = ctx.owner.asClass @@ -173,8 +171,8 @@ class ExtensionMethods extends MiniPhase with DenotTransformer with FullParamete val store = extensionDefs.getOrElseUpdate(staticClass, new mutable.ListBuffer[Tree]) store += fullyParameterizedDef(extensionMeth, tree) cpy.DefDef(tree)(rhs = forwarder(extensionMeth, tree)) - } else tree - } + } + else tree } object ExtensionMethods { diff --git a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala index 2fc953cfdad2..18a31b12cbf2 100644 --- a/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/compiler/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -47,7 +47,7 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => override protected def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym.isClass - override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { + override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = tree match { case Select(qual, name) if !name.is(OuterSelectName) && tree.symbol.exists => assert( @@ -59,7 +59,6 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => assert(false, i"illegal tree: $tree") case _ => } - } /** Reorder statements so that module classes always come after their companion classes */ private def reorderAndComplete(stats: List[Tree])(implicit ctx: Context): List[Tree] = { @@ -78,7 +77,8 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => singleClassDefs -= stat.name.stripModuleClassSuffix val stats1r = reorder(stats1, Nil) pushOnTop(revPrefix, if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r) - } else { + } + else reorder( stats1, moduleClassDefs remove stat.name.moduleClassName match { @@ -89,7 +89,6 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => stat :: revPrefix } ) - } case stat :: stats1 => reorder(stats1, stat :: revPrefix) case Nil => revPrefix.reverse } @@ -98,9 +97,8 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => } /** eliminate self in Template */ - override def transformTemplate(impl: Template)(implicit ctx: Context): Tree = { + override def transformTemplate(impl: Template)(implicit ctx: Context): Tree = cpy.Template(impl)(self = EmptyValDef) - } override def transformDefDef(ddef: DefDef)(implicit ctx: Context): Tree = { val meth = ddef.symbol.asTerm @@ -109,8 +107,8 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase => polyDefDef(meth, _ => _ => ref(defn.Sys_error.termRef).withSpan(ddef.span) .appliedTo(Literal(Constant(s"native method stub")))) - } + else ddef } diff --git a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala index 1b15b4adfe97..513e08ccf258 100644 --- a/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala +++ b/compiler/src/dotty/tools/dotc/transform/GenericSignatures.scala @@ -79,13 +79,12 @@ object GenericSignatures { boundsSig(hiBounds(param.paramInfo.bounds)) } - def polyParamSig(tparams: List[LambdaParam]): Unit = { + def polyParamSig(tparams: List[LambdaParam]): Unit = if (tparams.nonEmpty) { builder.append('<') tparams.foreach(paramSig) builder.append('>') } - } def typeParamSig(name: Name): Unit = { builder.append(ClassfileConstants.TVAR_TAG) @@ -270,7 +269,7 @@ object GenericSignatures { jsig(intersectionDominator(tp1 :: tp2 :: Nil), primitiveOK = primitiveOK) case ci: ClassInfo => - def polyParamSig(tparams: List[TypeParamInfo]): Unit = { + def polyParamSig(tparams: List[TypeParamInfo]): Unit = if (tparams.nonEmpty) { builder.append('<') tparams.foreach { tp => @@ -279,7 +278,6 @@ object GenericSignatures { } builder.append('>') } - } val tParams = tp.typeParams if (toplevel) polyParamSig(tParams) superSig(ci.typeSymbol, ci.parents) diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 910086b23712..a53d3bc9b368 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -92,7 +92,7 @@ object LambdaLift { /** Set `liftedOwner(sym)` to `owner` if `owner` is more deeply nested * than the previous value of `liftedowner(sym)`. */ - def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context): Unit = { + def narrowLiftedOwner(sym: Symbol, owner: Symbol)(implicit ctx: Context): Unit = if (sym.maybeOwner.isTerm && owner.isProperlyContainedIn(liftedOwner(sym)) && owner != sym) { @@ -100,7 +100,6 @@ object LambdaLift { changedLiftedOwner = true liftedOwner(sym) = owner } - } /** Mark symbol `sym` as being free in `enclosure`, unless `sym` is defined * in `enclosure` or there is an intermediate class properly containing `enclosure` @@ -156,17 +155,15 @@ object LambdaLift { else if (enclosure.isConstructor) markFree(sym, enclosure.owner.enclosure) else markFree(sym, enclosure.enclosure) if (intermediate.exists) narrowLiftedOwner(enclosure, intermediate) - if (!intermediate.isRealClass || enclosure.isConstructor) { + if (!intermediate.isRealClass || enclosure.isConstructor) // Constructors and methods nested inside traits get the free variables // of the enclosing trait or class. // Conversely, local traits do not get free variables. - if (!enclosure.is(Trait)) { + if (!enclosure.is(Trait)) if (symSet(free, enclosure).add(sym)) { changedFreeVars = true ctx.log(i"$sym is free in $enclosure") } - } - } if (intermediate.isRealClass) intermediate else if (enclosure.isRealClass) enclosure else if (intermediate.isClass) intermediate @@ -203,10 +200,9 @@ object LambdaLift { tree match { case tree: Ident => - if (isLocal(sym)) { + if (isLocal(sym)) if (sym is Method) markCalled(sym, enclosure) else if (sym.isTerm) markFree(sym, enclosure) - } def captureImplicitThis(x: Type): Unit = x match { case tr@TermRef(x, _) if (!tr.termSymbol.isStatic) => captureImplicitThis(x) @@ -361,10 +357,9 @@ object LambdaLift { initFlags = initFlags, info = liftedInfo(local)).installAfter(thisPhase) } - for (local <- free.keys) { + for (local <- free.keys) if (!liftedOwner.contains(local)) local.copySymDenotation(info = liftedInfo(local)).installAfter(thisPhase) - } } // initialization diff --git a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala index 62d055e60e3c..d97d51142012 100644 --- a/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala +++ b/compiler/src/dotty/tools/dotc/transform/LinkScala2Impls.scala @@ -56,10 +56,9 @@ class LinkScala2Impls extends MiniPhase with IdentityDenotTransformer { thisPhas info = staticInfo(mold.info) ) } - for (sym <- mixin.info.decls) { + for (sym <- mixin.info.decls) if (needsMixinForwarder(sym) || sym.isConstructor || sym.isGetter && sym.is(Lazy) || sym.is(Method, butNot = Deferred)) newImpl(sym.asTerm).enteredAfter(thisPhase) - } // The trait is now fully augmented so the flag isn't needed anymore. mixin.resetFlag(Scala2xPartiallyAugmented) } diff --git a/compiler/src/dotty/tools/dotc/transform/Memoize.scala b/compiler/src/dotty/tools/dotc/transform/Memoize.scala index 65263544c3ab..98b9a0c532da 100644 --- a/compiler/src/dotty/tools/dotc/transform/Memoize.scala +++ b/compiler/src/dotty/tools/dotc/transform/Memoize.scala @@ -105,7 +105,7 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => val NoFieldNeeded = Lazy | Deferred | JavaDefined | (if (ctx.settings.YnoInline.value) EmptyFlags else Inline) - def erasedBottomTree(sym: Symbol) = { + def erasedBottomTree(sym: Symbol) = if (sym eq defn.NothingClass) Throw(nullLiteral) else if (sym eq defn.NullClass) nullLiteral else if (sym eq defn.BoxedUnitClass) ref(defn.BoxedUnit_UNIT) @@ -113,7 +113,6 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => assert(false, s"$sym has no erased bottom tree") EmptyTree } - } if (sym.is(Accessor, butNot = NoFieldNeeded)) { val field = sym.field.orElse(newField).asTerm @@ -136,7 +135,8 @@ class Memoize extends MiniPhase with IdentityDenotTransformer { thisPhase => addAnnotations(fieldDef.denot) removeAnnotations(sym) Thicket(fieldDef, getterDef) - } else if (sym.isSetter) { + } + else if (sym.isSetter) { if (!sym.is(ParamAccessor)) { val Literal(Constant(())) = tree.rhs } // This is intended as an assertion field.setFlag(Mutable) // Necessary for vals mixed in from Scala2 traits val initializer = diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 9e20dd13abd1..2dd7af23f804 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -200,10 +200,9 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => else call :: Nil case None => if (baseCls.isAllOf(NoInitsTrait) || defn.NoInitClasses.contains(baseCls) || defn.isFunctionClass(baseCls)) Nil - else { + else //println(i"synth super call ${baseCls.primaryConstructor}: ${baseCls.primaryConstructor.info}") transformFollowingDeep(superRef(baseCls.primaryConstructor).appliedToNone) :: Nil - } } def wasOneOf(sym: Symbol, flags: FlagSet) = @@ -236,14 +235,13 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => val rhs = if (wasOneOf(getter, ParamAccessor)) nextArgument() - else if (isScala2x) { + else if (isScala2x) if (getter.is(Lazy, butNot = Module)) initial else if (getter.is(Module)) New(getter.info.resultType, List(This(cls))) else Underscore(getter.info.resultType) - } else initial // transformFollowing call is needed to make memoize & lazy vals run diff --git a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala index b89fef2aad1d..ba57008bb0a8 100644 --- a/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala +++ b/compiler/src/dotty/tools/dotc/transform/OverridingPairs.scala @@ -102,7 +102,7 @@ object OverridingPairs { * overriding = curEntry.sym */ private def nextOverriding(): Unit = { - @tailrec def loop(): Unit = { + @tailrec def loop(): Unit = if (curEntry ne null) { overriding = curEntry.sym if (visited.contains(overriding)) { @@ -110,7 +110,6 @@ object OverridingPairs { loop() } } - } loop() nextEntry = curEntry } @@ -120,7 +119,7 @@ object OverridingPairs { * overriding = overriding member of the pair, provided hasNext is true * overridden = overridden member of the pair, provided hasNext is true */ - @tailrec final def next(): Unit = { + @tailrec final def next(): Unit = if (nextEntry ne null) { nextEntry = decls.lookupNextEntry(nextEntry) if (nextEntry ne null) @@ -143,7 +142,6 @@ object OverridingPairs { } next() } - } nextOverriding() next() diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 589a9c523120..8a2e610b649b 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -903,7 +903,7 @@ object PatternMatcher { case TypeTest(tpt, trusted) => i"TypeTest($tpt, trusted=$trusted)" case _ => test.toString } - def showPlan(plan: Plan): Unit = { + def showPlan(plan: Plan): Unit = if (!seen.contains(plan.id)) { seen += plan.id sb append s"\n${plan.id}: " @@ -929,7 +929,6 @@ object PatternMatcher { sb.append(tree.show) } } - } showPlan(plan) sb.toString } diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index 954d63d36c68..21e748ec594e 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -116,7 +116,7 @@ class Pickler extends Phase { } } - private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(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) @@ -124,5 +124,4 @@ class Pickler extends Phase { | | diff before-pickling.txt after-pickling.txt""".stripMargin) } - } } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index a2fcdc4ee3e7..377ad8a63ceb 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -212,10 +212,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase } case tree: TypeApply => val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) - if (fn.symbol != defn.ChildAnnot.primaryConstructor) { + if (fn.symbol != defn.ChildAnnot.primaryConstructor) // Make an exception for ChildAnnot, which should really have AnyKind bounds Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) - } fn match { case sel: Select => val args1 = transform(args) @@ -243,13 +242,12 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase processMemberDef(superAcc.wrapDefDef(tree1)(super.transform(tree1).asInstanceOf[DefDef])) case tree: TypeDef => val sym = tree.symbol - if (sym.isClass) { + if (sym.isClass) // Add SourceFile annotation to top-level classes if (sym.owner.is(Package) && ctx.compilationUnit.source.exists && sym != defn.SourceFileAnnot) sym.addAnnotation(Annotation.makeSourceFile(ctx.compilationUnit.source.file.path)) - } processMemberDef(super.transform(tree)) case tree: New if isCheckable(tree) => Checking.checkInstantiable(tree.tpe, tree.posd) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index bd1f48e1a45d..bbfc39bf603f 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -85,9 +85,8 @@ class ReifyQuotes extends MacroTransform { case _ => } - override def run(implicit ctx: Context): Unit = { + override def run(implicit ctx: Context): Unit = if (ctx.compilationUnit.needsStaging) super.run(freshStagingContext) - } protected def newTransformer(implicit ctx: Context): Transformer = new Transformer { override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = @@ -186,7 +185,7 @@ class ReifyQuotes extends MacroTransform { // Optimization: avoid the full conversion when capturing `x` // in '{ x } to '{ ${x$1} } and go directly to `x$1` capturers(body.symbol)(body) - case _=> + case _ => val (body1, splices) = nested(isQuote = true).splitQuote(body)(quoteContext) if (level == 0) { val body2 = @@ -194,9 +193,8 @@ class ReifyQuotes extends MacroTransform { else Inlined(Inliner.inlineCallTrace(ctx.owner, quote.sourcePos), Nil, body1) pickledQuote(body2, splices, body.tpe, isType).withSpan(quote.span) } - else { + else body - } } } @@ -213,7 +211,7 @@ class ReifyQuotes extends MacroTransform { .select(name).appliedToType(originalTp) .select("toExpr".toTermName).appliedTo(Literal(Constant(value))) - def pickleAsValue[T](value: T) = { + def pickleAsValue[T](value: T) = value match { case null => ref(defn.QuotedExprModule).select("nullExpr".toTermName) case _: Unit => ref(defn.QuotedExprModule).select("unitExpr".toTermName) @@ -227,7 +225,6 @@ class ReifyQuotes extends MacroTransform { case _: Char => liftedValue(value, "Liftable_Char_delegate".toTermName) case _: String => liftedValue(value, "Liftable_String_delegate".toTermName) } - } def pickleAsTasty() = { val meth = @@ -256,7 +253,7 @@ class ReifyQuotes extends MacroTransform { * and make a hole from these parts. Otherwise issue an error, unless we * are in the body of an inline method. */ - protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = { + protected def transformSplice(body: Tree, splice: Tree)(implicit ctx: Context): Tree = if (level > 1) { val body1 = nested(isQuote = false).transform(body)(spliceContext) splice match { @@ -276,7 +273,6 @@ class ReifyQuotes extends MacroTransform { if (splice.isType || outer.embedded.isLiftedSymbol(body.symbol)) hole else Inlined(EmptyTree, Nil, hole).withSpan(splice.span) } - } /** Transforms the contents of a nested splice * Assuming @@ -389,7 +385,7 @@ class ReifyQuotes extends MacroTransform { Hole(idx, splices).withType(tpe).asInstanceOf[Hole] } - override def transform(tree: Tree)(implicit ctx: Context): Tree = { + override def transform(tree: Tree)(implicit ctx: Context): Tree = if (tree.source != ctx.source && tree.source.exists) transform(tree)(ctx.withSource(tree.source)) else reporting.trace(i"Reifier.transform $tree at $level", show = true) { @@ -419,13 +415,11 @@ class ReifyQuotes extends MacroTransform { super.transform(tree) } } - } - private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = { + private def liftList(list: List[Tree], tpe: Type)(implicit ctx: Context): Tree = list.foldRight[Tree](ref(defn.NilModule)) { (x, acc) => acc.select("::".toTermName).appliedToType(tpe).appliedTo(x) } - } } } diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index b77b27fc305c..9330c524987d 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -49,7 +49,7 @@ class ResolveSuper extends MiniPhase with IdentityDenotTransformer { thisPhase = yield { util.Stats.record("super accessors") polyDefDef(mkForwarderSym(superAcc.asTerm), forwarderRhsFn(rebindSuper(cls, superAcc))) - } + } val overrides = mixins.flatMap(superAccessors) diff --git a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala index 39ef97865da7..bee4d38e2baf 100644 --- a/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala +++ b/compiler/src/dotty/tools/dotc/transform/ShortcutImplicits.scala @@ -96,7 +96,8 @@ class ShortcutImplicits extends MiniPhase with IdentityDenotTransformer { thisPh .withType(tree.tpe.asInstanceOf[NamedType].prefix.select(directMethod(tree.symbol))) } directQual(tree.qualifier) - } else tree + } + else tree /** Transform methods with implicit function type result according to rewrite rule (1) above */ override def transformDefDef(mdef: DefDef)(implicit ctx: Context): Tree = { diff --git a/compiler/src/dotty/tools/dotc/transform/Staging.scala b/compiler/src/dotty/tools/dotc/transform/Staging.scala index 6b9cc00ff23e..929a2a056fce 100644 --- a/compiler/src/dotty/tools/dotc/transform/Staging.scala +++ b/compiler/src/dotty/tools/dotc/transform/Staging.scala @@ -37,7 +37,7 @@ class Staging extends MacroTransform { override def allowsImplicitSearch: Boolean = true - override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { + override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = if (ctx.phase <= ctx.reifyQuotesPhase) { // Recheck that PCP holds but do not heal any inconsistent types as they should already have been heald tree match { @@ -71,11 +71,9 @@ class Staging extends MacroTransform { // OK } } - } - override def run(implicit ctx: Context): Unit = { + override def run(implicit ctx: Context): Unit = if (ctx.compilationUnit.needsStaging) super.run(freshStagingContext) - } protected def newTransformer(implicit ctx: Context): Transformer = new Transformer { override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 81a980167303..ee1285281d1d 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -93,11 +93,10 @@ class SyntheticMembers(thisPhase: DenotTransformer) { val isEnumCase = clazz.derivesFrom(defn.EnumClass) && clazz != defn.EnumClass val symbolsToSynthesize: List[Symbol] = - if (clazz.is(Case)) { + if (clazz.is(Case)) if (clazz.is(Module)) caseModuleSymbols else if (isEnumCase) caseSymbols ++ enumCaseSymbols else caseSymbols - } else if (isEnumCase) enumCaseSymbols else if (isDerivedValueClass(clazz)) valueSymbols else Nil @@ -284,14 +283,13 @@ class SyntheticMembers(thisPhase: DenotTransformer) { * * else if either `T` or `U` are primitive, gets the `hashCode` method implemented by [[caseHashCodeBody]] */ - def chooseHashcode(implicit ctx: Context) = { + def chooseHashcode(implicit ctx: Context) = if (clazz.is(ModuleClass)) Literal(Constant(clazz.name.stripModuleClassSuffix.toString.hashCode)) else if (accessors.exists(_.info.finalResultType.classSymbol.isPrimitiveValueClass)) caseHashCodeBody else ref(defn.ScalaRuntime__hashCode).appliedTo(This(clazz)) - } /** The class * @@ -380,51 +378,51 @@ class SyntheticMembers(thisPhase: DenotTransformer) { Nil } - /** The class - * - * ``` - * case class C[T <: U](x: T, y: String*) - * ``` - * - * gets the `fromProduct` method: - * - * ``` - * def fromProduct(x$0: Product): MirroredMonoType = - * new C[U]( - * x$0.productElement(0).asInstanceOf[U], - * x$0.productElement(1).asInstanceOf[Seq[String]]: _*) - * ``` - * where - * ``` - * type MirroredMonoType = C[?] - * ``` - */ - def fromProductBody(caseClass: Symbol, param: Tree)(implicit ctx: Context): Tree = { - val (classRef, methTpe) = - caseClass.primaryConstructor.info match { - case tl: PolyType => - val (tl1, tpts) = constrained(tl, untpd.EmptyTree, alwaysAddTypeVars = true) - val targs = - for (tpt <- tpts) yield - tpt.tpe match { - case tvar: TypeVar => tvar.instantiate(fromBelow = false) - } - (caseClass.typeRef.appliedTo(targs), tl.instantiate(targs)) - case methTpe => - (caseClass.typeRef, methTpe) - } - methTpe match { - case methTpe: MethodType => - val elems = - for ((formal, idx) <- methTpe.paramInfos.zipWithIndex) yield { - val elem = - param.select(defn.Product_productElement).appliedTo(Literal(Constant(idx))) - .ensureConforms(formal.underlyingIfRepeated(isJava = false)) - if (formal.isRepeatedParam) ctx.typer.seqToRepeated(elem) else elem - } - New(classRef, elems) + /** The class + * + * ``` + * case class C[T <: U](x: T, y: String*) + * ``` + * + * gets the `fromProduct` method: + * + * ``` + * def fromProduct(x$0: Product): MirroredMonoType = + * new C[U]( + * x$0.productElement(0).asInstanceOf[U], + * x$0.productElement(1).asInstanceOf[Seq[String]]: _*) + * ``` + * where + * ``` + * type MirroredMonoType = C[?] + * ``` + */ + def fromProductBody(caseClass: Symbol, param: Tree)(implicit ctx: Context): Tree = { + val (classRef, methTpe) = + caseClass.primaryConstructor.info match { + case tl: PolyType => + val (tl1, tpts) = constrained(tl, untpd.EmptyTree, alwaysAddTypeVars = true) + val targs = + for (tpt <- tpts) yield + tpt.tpe match { + case tvar: TypeVar => tvar.instantiate(fromBelow = false) + } + (caseClass.typeRef.appliedTo(targs), tl.instantiate(targs)) + case methTpe => + (caseClass.typeRef, methTpe) } + methTpe match { + case methTpe: MethodType => + val elems = + for ((formal, idx) <- methTpe.paramInfos.zipWithIndex) yield { + val elem = + param.select(defn.Product_productElement).appliedTo(Literal(Constant(idx))) + .ensureConforms(formal.underlyingIfRepeated(isJava = false)) + if (formal.isRepeatedParam) ctx.typer.seqToRepeated(elem) else elem + } + New(classRef, elems) } + } /** For an enum T: * diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 4f6d03f5e8db..6727ebe3d56d 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -411,10 +411,9 @@ class TailRec extends MiniPhase { if (inTailPosition) tailPositionLabeledSyms += bind.symbol try cpy.Labeled(tree)(bind, transform(expr)) - finally { + finally if (inTailPosition) tailPositionLabeledSyms -= bind.symbol - } case Return(expr, from) => val fromSym = from.symbol diff --git a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala index e1129dd04cde..1835012e8d7a 100644 --- a/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala +++ b/compiler/src/dotty/tools/dotc/transform/TransformByNameApply.scala @@ -39,26 +39,26 @@ abstract class TransformByNameApply extends MiniPhase { thisPhase: DenotTransfor override def transformApply(tree: Apply)(implicit ctx: Context): Tree = trace(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) { - def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match { - case formalExpr: ExprType => - var argType = arg.tpe.widenIfUnstable - if (defn.isBottomType(argType)) argType = formal.widenExpr - def wrap(arg: Tree) = - ref(defn.cbnArg).appliedToType(argType).appliedTo(arg).withSpan(arg.span) - arg match { - case Apply(Select(qual, nme.apply), Nil) - if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) => - wrap(qual) - case _ => - if (isByNameRef(arg) || arg.symbol == defn.cbnArg) arg - else wrap(mkByNameClosure(arg, argType)) - } - case _ => - arg - } + def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match { + case formalExpr: ExprType => + var argType = arg.tpe.widenIfUnstable + if (defn.isBottomType(argType)) argType = formal.widenExpr + def wrap(arg: Tree) = + ref(defn.cbnArg).appliedToType(argType).appliedTo(arg).withSpan(arg.span) + arg match { + case Apply(Select(qual, nme.apply), Nil) + if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) => + wrap(qual) + case _ => + if (isByNameRef(arg) || arg.symbol == defn.cbnArg) arg + else wrap(mkByNameClosure(arg, argType)) + } + case _ => + arg + } - val mt @ MethodType(_) = tree.fun.tpe.widen - val args1 = tree.args.zipWithConserve(mt.paramInfos)(transformArg) - cpy.Apply(tree)(tree.fun, args1) - } + val mt @ MethodType(_) = tree.fun.tpe.widen + val args1 = tree.args.zipWithConserve(mt.paramInfos)(transformArg) + cpy.Apply(tree)(tree.fun, args1) + } } diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 70368d7c5ee4..f42011a3e261 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -87,12 +87,11 @@ class TreeChecker extends Phase with SymTransformer { def phaseName: String = "Ycheck" - def run(implicit ctx: Context): Unit = { + def run(implicit ctx: Context): Unit = if (ctx.settings.YtestPickler.value && ctx.phase.prev.isInstanceOf[Pickler]) ctx.echo("Skipping Ycheck after pickling with -Ytest-pickler, the returned tree contains stale symbols") else if (ctx.phase.prev.isCheckable) check(ctx.base.allPhases.toIndexedSeq, ctx) - } private def previousPhases(phases: List[Phase])(implicit ctx: Context): List[Phase] = phases match { case (phase: MegaPhase) :: phases1 => diff --git a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala index 2a13e72a2fd4..525537e90fe3 100644 --- a/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala +++ b/compiler/src/dotty/tools/dotc/transform/YCheckPositions.scala @@ -27,12 +27,11 @@ class YCheckPositions extends Phases.Phase { // Check current context is correct assert(ctx.source == sources.head) - if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) { + if (!tree.isEmpty && !tree.isInstanceOf[untpd.TypedSplice] && ctx.typerState.isGlobalCommittable) if (!tree.isType) { // TODO also check types, currently we do not add Inlined(EmptyTree, _, _) for types. We should. val currentSource = sources.head assert(tree.source == currentSource, i"wrong source set for $tree # ${tree.uniqueId} of ${tree.getClass}, set to ${tree.source} but context had $currentSource") } - } // Recursivlely check children while keeping track of current source tree match { diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 339556f62d2b..f92b15ee6fe5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1006,13 +1006,12 @@ trait Applications extends Compatibility { case typedFn => typedFn.tpe.widen match { case pt: PolyType => - if (typedArgs.length <= pt.paramInfos.length && !isNamed) { + if (typedArgs.length <= pt.paramInfos.length && !isNamed) if (typedFn.symbol == defn.Predef_classOf && typedArgs.nonEmpty) { val arg = typedArgs.head if (!arg.symbol.is(Module)) // Allow `classOf[Foo.type]` if `Foo` is an object checkClassType(arg.tpe, arg.sourcePos, traitReq = false, stablePrefixReq = false) } - } case _ => } def tryDynamicTypeApply(): Tree = typedFn match { @@ -1322,8 +1321,7 @@ trait Applications extends Compatibility { tp1.paramInfos.isEmpty && tp2.isInstanceOf[LambdaType] case tp1: PolyType => // (2) val nestedCtx = ctx.fresh.setExploreTyperState() - - { + locally { implicit val ctx = nestedCtx // Fully define the PolyType parameters so that the infos of the diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 7814881c8670..b3756a61613d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -558,9 +558,8 @@ trait ImplicitRunInfo { } val comps = new TermRefSet - def addCompanion(pre: Type, companion: Symbol) = { + def addCompanion(pre: Type, companion: Symbol) = if (companion.exists && !companion.isAbsent()) comps += TermRef(pre, companion) - } def addPath(pre: Type): Unit = pre.dealias match { case pre: ThisType if pre.cls.is(Module) && pre.cls.isStaticOwner => @@ -735,12 +734,11 @@ trait Implicits { self: Typer => lazy val synthesizedTupleFunction: SpecialHandler = (formal, span) => implicit ctx => formal match { case AppliedType(_, funArgs @ fun :: tupled :: Nil) => - def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = { + def functionTypeEqual(baseFun: Type, actualArgs: List[Type], actualRet: Type, expected: Type) = expected =:= defn.FunctionOf(actualArgs, actualRet, defn.isImplicitFunctionType(baseFun), defn.isErasedFunctionType(baseFun)) - } - val arity: Int = { + val arity: Int = if (defn.isErasedFunctionType(fun) || defn.isErasedFunctionType(fun)) -1 // TODO support? - else if (defn.isFunctionType(fun)) { + else if (defn.isFunctionType(fun)) // TupledFunction[(...) => R, ?] fun.dropDependentRefinement.dealias.argInfos match { case funArgs :+ funRet if functionTypeEqual(fun, defn.tupleType(funArgs) :: Nil, funRet, tupled) => @@ -748,7 +746,7 @@ trait Implicits { self: Typer => funArgs.size case _ => -1 } - } else if (defn.isFunctionType(tupled)) { + else if (defn.isFunctionType(tupled)) // TupledFunction[?, (...) => R] tupled.dropDependentRefinement.dealias.argInfos match { case tupledArgs :: funRet :: Nil => @@ -760,12 +758,9 @@ trait Implicits { self: Typer => } case _ => -1 } - } - else { + else // TupledFunction[?, ?] -1 - } - } if (arity == -1) EmptyTree else if (arity <= Definitions.MaxImplementedFunctionArity) @@ -1003,7 +998,7 @@ trait Implicits { self: Typer => assert(caseClass.is(Case)) if (caseClass.is(Module)) caseClass.sourceModule.termRef - else { + else caseClass.primaryConstructor.info match { case info: PolyType => // Compute the the full child type by solving the subtype constraint @@ -1031,7 +1026,6 @@ trait Implicits { self: Typer => case _ => caseClass.typeRef } - } case child => child.termRef } @@ -1054,7 +1048,8 @@ trait Implicits { self: Typer => if (cls.linkedClass.exists && !cls.is(Scala2x)) companionPath(mirroredType, span) else anonymousMirror(monoType, ExtendsSumMirror, span) mirrorRef.cast(mirrorType) - } else EmptyTree + } + else EmptyTree case _ => EmptyTree } } @@ -1109,10 +1104,9 @@ trait Implicits { self: Typer => } val base = baseWithRefinements(formal) val result = - if (base <:< formal.widenExpr) { + if (base <:< formal.widenExpr) // With the subtype test we enforce that the searched type `formal` is of the right form handler(base, span)(ctx) - } else EmptyTree result.orElse(trySpecialCases(rest)) case Nil => @@ -1303,9 +1297,9 @@ trait Implicits { self: Typer => if (argument.isEmpty) i"missing implicit parameter of type $pt after typer" else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}") val result0 = - try { + try new ImplicitSearch(pt, argument, span).bestImplicit(contextual = true) - } catch { + catch { case ce: CyclicReference => ce.inImplicitSearch = true throw ce @@ -1322,7 +1316,7 @@ trait Implicits { self: Typer => case result: SearchFailure if result.isAmbiguous => val deepPt = pt.deepenProto if (deepPt ne pt) inferImplicit(deepPt, argument, span) - else if (ctx.scala2Mode && !ctx.mode.is(Mode.OldOverloadingResolution)) { + else if (ctx.scala2Mode && !ctx.mode.is(Mode.OldOverloadingResolution)) inferImplicit(pt, argument, span)(ctx.addMode(Mode.OldOverloadingResolution)) match { case altResult: SearchSuccess => ctx.migrationWarning( @@ -1332,7 +1326,6 @@ trait Implicits { self: Typer => case _ => result } - } else result case NoMatchingImplicitsFailure => SearchFailure(new NoMatchingImplicits(pt, argument, ctx.typerState.constraint)) @@ -1402,9 +1395,9 @@ trait Implicits { self: Typer => ctx.error(em"ambiguous implicit: $generated is eligible both as an implicit conversion and as an extension method container") } result - } - else tryConversion } + else tryConversion + } if (ctx.reporter.hasErrors) { ctx.reporter.removeBufferedMessages SearchFailure { @@ -1497,7 +1490,7 @@ trait Implicits { self: Typer => * - otherwise add the failure to `rfailures` and continue testing the other candidates. */ def rank(pending: List[Candidate], found: SearchResult, rfailures: List[SearchFailure]): SearchResult = - pending match { + pending match { case cand :: remaining => negateIfNot(tryImplicit(cand, contextual)) match { case fail: SearchFailure => diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index dbf633f6095f..96aea1c65745 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -222,9 +222,7 @@ object Inliner { case _ => EmptyTree } - } - } } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index b2585dc7e591..34be6ad819bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -22,9 +22,9 @@ import transform.TypeUtils._ import transform.SymUtils._ import reporting.diagnostic.messages._ -trait NamerContextOps { +trait NamerContextOps { this: Context => - + import NamerContextOps._ def typer: Typer = ctx.typeAssigner match { @@ -140,9 +140,8 @@ trait NamerContextOps { else (params.head.is(Given), params.head.is(Implicit), params.head.is(Erased)) val make = MethodType.companion(isJava = isJava, isContextual = isContextual, isImplicit = isImplicit, isErased = isErased) if (isJava) - for (param <- params) { + for (param <- params) if (param.info.isDirectRef(defn.ObjectClass)) param.info = defn.AnyType - } make.fromSymbols(params, resultType) } if (typeParams.nonEmpty) PolyType.fromParams(typeParams.asInstanceOf[List[TypeSymbol]], monotpe) @@ -760,7 +759,8 @@ class Namer { typer: Typer => try { val expr1 = typedAheadExpr(imp.expr, AnySelectionProto) ImportType(expr1) - } catch { + } + catch { case ex: CyclicReference => typr.println(s"error while completing ${imp.expr}") throw ex @@ -955,7 +955,7 @@ class Namer { typer: Typer => other => cls.derivesFrom(other.owner) && !other.is(Deferred)) match { case Some(other) => i"overrides ${other.showLocated}, which is already a member of $cls" case None => "" - } + } else "" } @@ -1022,8 +1022,10 @@ class Namer { typer: Typer => } def addForwardersExcept(seen: List[TermName], span: Span): Unit = - for (mbr <- path.tpe.membersBasedOnFlags( - required = EmptyFlags, excluded = PrivateOrSynthetic)) { + for { + mbr <- path.tpe.membersBasedOnFlags(required = EmptyFlags, excluded = PrivateOrSynthetic) + } + { val alias = mbr.name.toTermName if (!seen.contains(alias)) addForwarder(alias, mbr, span) } diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 8e2d0d949747..9e379c6f7367 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -313,10 +313,9 @@ object ProtoTypes { if (!args1.exists(arg => isUndefined(arg.tpe))) state.typedArgs = args1 args1 } - finally { + finally if (this.ctx.typerState.constraint ne prevConstraint) ctx.typerState.mergeConstraintWith(this.ctx.typerState) - } } /** Type single argument and remember the unadapted result in `myTypedArg`. diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 19eeca6d0fd3..c8e76126870b 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -665,11 +665,10 @@ object RefChecks { */ def checkCaseClassInheritanceInvariant() = for (caseCls <- clazz.info.baseClasses.tail.find(_.is(Case))) - for (baseCls <- caseCls.info.baseClasses.tail) { + for (baseCls <- caseCls.info.baseClasses.tail) if (baseCls.typeParams.exists(_.paramVariance != 0)) for (problem <- variantInheritanceProblems(baseCls, caseCls, "non-variant", "case ")) ctx.errorOrMigrationWarning(problem(), clazz.sourcePos) - } checkNoAbstractMembers() if (abstractErrors.isEmpty) checkNoAbstractDecls(clazz) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index a7bf1dacee77..8e3adf71addb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -322,9 +322,8 @@ class Typer extends Namer else { // find import val outer = ctx.outer val curImport = ctx.importInfo - def updateUnimported() = { + def updateUnimported() = if (curImport.unimported.exists) unimported += curImport.unimported - } if (ctx.owner.is(Package) && curImport != null && curImport.isRootImport && previous.exists) previous // no more conflicts possible in this case else if (isPossibleImport(NamedImport) && (curImport ne outer.importInfo)) { diff --git a/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala index a456633f1bc5..b5d2b840c5e7 100644 --- a/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala +++ b/compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala @@ -163,9 +163,8 @@ object SimpleIdentityMap { return { if (size == CompactifyThreshold) { var m: SimpleIdentityMap[K, V] = Empty[K] - for (j <- 0 until bindings.length by 2) { + for (j <- 0 until bindings.length by 2) if (j != i) m = m.updated(key(j), value(j)) - } m } else { diff --git a/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala b/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala index b27fbf0a6e40..35cc29d303f9 100644 --- a/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala +++ b/language-server/test/dotty/tools/languageserver/DocumentSymbolTest.scala @@ -34,7 +34,7 @@ class DocumentSymbolTest { @Test def documentSymbolShowClassAndCompanion: Unit = { code"""object ${m1}Foo${m2} - class ${m3}Foo${m4}""".withSource + |class ${m3}Foo${m4}""".withSource .documentSymbol(m1, (m1 to m2).symInfo("Foo", SymbolKind.Module), (m3 to m4).symInfo("Foo", SymbolKind.Class)) } diff --git a/language-server/test/dotty/tools/languageserver/ReferencesTest.scala b/language-server/test/dotty/tools/languageserver/ReferencesTest.scala index b99947bfe9bb..365e3fe00aa4 100644 --- a/language-server/test/dotty/tools/languageserver/ReferencesTest.scala +++ b/language-server/test/dotty/tools/languageserver/ReferencesTest.scala @@ -37,7 +37,7 @@ class ReferencesTest { @Test def classReferenceCompanion: Unit = { code"""class ${m1}Foo${m2}(x: Any) - object ${m3}Foo${m4} { val bar = new ${m5}Foo${m6}(${m7}Foo${m8}) }""".withSource + |object ${m3}Foo${m4} { val bar = new ${m5}Foo${m6}(${m7}Foo${m8}) }""".withSource .references(m1 to m2, List(m1 to m2, m5 to m6), withDecl = true) .references(m1 to m2, List(m5 to m6), withDecl = false) .references(m3 to m4, List(m3 to m4, m7 to m8), withDecl = true) @@ -50,9 +50,9 @@ class ReferencesTest { @Test def anonClassTrait: Unit = { code"""trait ${m1}Foo${m2} - object O { - val foo = new ${m3}Foo${m4} {} - }""".withSource + |object O { + | val foo = new ${m3}Foo${m4} {} + |}""".withSource .references(m1 to m2, List(m1 to m2, m3 to m4), withDecl = true) .references(m1 to m2, List(m3 to m4), withDecl = false) .references(m3 to m4, List(m1 to m2, m3 to m4), withDecl = true) @@ -170,12 +170,12 @@ class ReferencesTest { val p1 = Project.dependingOn(p0).withSources( code"""class B { - val a = new A() - val z = new a.Z() - val y = new z.Y() - val x = new y.X() - x.${m3}x${m4} - }""" + | val a = new A() + | val z = new a.Z() + | val y = new z.Y() + | val x = new y.X() + | x.${m3}x${m4} + |}""" ) withProjects(p0, p1) @@ -204,12 +204,12 @@ class ReferencesTest { @Test def findReferencesInUntouchedProject: Unit = { val p0 = Project.withSources( code"""package hello - object A { def ${m1}foo${m2} = 1 }""" + |object A { def ${m1}foo${m2} = 1 }""" ) val p1 = Project.dependingOn(p0).withSources( tasty"""package hello - object B { def bar = A.${m3}foo${m4} }""" + |object B { def bar = A.${m3}foo${m4} }""" ) withProjects(p0, p1) @@ -219,8 +219,8 @@ class ReferencesTest { @Test def importReference1: Unit = { code"""import ${m1}Foo${m2}._ - object ${m3}Foo${m4} { def ${m5}bar${m6}: Int = 0 } - trait Bar { def buzz = ${m7}bar${m8} }""".withSource + |object ${m3}Foo${m4} { def ${m5}bar${m6}: Int = 0 } + |trait Bar { def buzz = ${m7}bar${m8} }""".withSource .references(m1 to m2, List(m1 to m2, m3 to m4), withDecl = true) .references(m1 to m2, List(m1 to m2), withDecl = false) @@ -266,7 +266,7 @@ class ReferencesTest { @Test def importReferenceClassAndCompanion: Unit = { code"""object Foo { object ${m1}Bar${m2}; class ${m3}Bar${m4} } - trait Buzz { import Foo.${m5}Bar${m6} }""".withSource + |trait Buzz { import Foo.${m5}Bar${m6} }""".withSource .references(m1 to m2, List(m1 to m2, m5 to m6), withDecl = true) .references(m1 to m2, List(m5 to m6), withDecl = false) .references(m3 to m4, List(m3 to m4, m5 to m6), withDecl = true) @@ -277,7 +277,7 @@ class ReferencesTest { @Test def importReferenceWithRename: Unit = { code"""object ${m1}Foo${m2} { object ${m3}Bar${m4} { object ${m5}Baz${m6} } } - trait Buzz { import ${m7}Foo${m8}.${m9}Bar${m10}.{${m11}Baz${m12} => ${m13}Quux${m14}}""".withSource + |trait Buzz { import ${m7}Foo${m8}.${m9}Bar${m10}.{${m11}Baz${m12} => ${m13}Quux${m14}}""".withSource .references(m1 to m2, List(m1 to m2, m7 to m8), withDecl = true) .references(m1 to m2, List(m7 to m8), withDecl = false) @@ -297,7 +297,7 @@ class ReferencesTest { @Test def importReferenceClassAndCompanionWithRename: Unit = { code"""object ${m1}Foo${m2} { object ${m3}Bar${m4}; class ${m5}Bar${m6} } - trait Buzz { import ${m7}Foo${m8}.{${m9}Bar${m10} => ${m11}Baz${m12}} }""".withSource + |trait Buzz { import ${m7}Foo${m8}.{${m9}Bar${m10} => ${m11}Baz${m12}} }""".withSource .references(m1 to m2, List(m1 to m2, m7 to m8), withDecl = true) .references(m1 to m2, List(m7 to m8), withDecl = false) @@ -315,7 +315,7 @@ class ReferencesTest { @Test def importReferenceMembers: Unit = { code"""object Foo { def ${m1}bar${m2} = 2; type ${m3}bar${m4} = fizz; class fizz } - trait Quux { import Foo.{${m5}bar${m6} => ${m7}buzz${m8}} }""".withSource + |trait Quux { import Foo.{${m5}bar${m6} => ${m7}buzz${m8}} }""".withSource .references(m1 to m2, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true) .references(m1 to m2, List(m5 to m6, m7 to m8), withDecl = false) @@ -331,7 +331,7 @@ class ReferencesTest { withSources( code"""object A { class ${m1}B${m2}; class ${m3}C${m4} }""", code"""import A.{${m5}B${m6} => ${m7}B2${m8}, ${m9}C${m10} => ${m11}C2${m12}} - class E""" + |class E""" ).references(m1 to m2, List(m1 to m2, m5 to m6, m7 to m8), withDecl = true) .references(m1 to m2, List(m5 to m6, m7 to m8), withDecl = false) .references(m3 to m4, List(m3 to m4, m9 to m10, m11 to m12), withDecl = true) diff --git a/language-server/test/dotty/tools/languageserver/SymbolTest.scala b/language-server/test/dotty/tools/languageserver/SymbolTest.scala index a46bd10b80a5..ff40223434fc 100644 --- a/language-server/test/dotty/tools/languageserver/SymbolTest.scala +++ b/language-server/test/dotty/tools/languageserver/SymbolTest.scala @@ -35,7 +35,7 @@ class SymbolTest { @Test def symbolShowClassAndCompanion: Unit = { code"""object ${m1}Foo${m2} - class ${m3}Foo${m4}""".withSource + |class ${m3}Foo${m4}""".withSource .symbol("Foo", (m1 to m2).symInfo("Foo", SymbolKind.Module), (m3 to m4).symInfo("Foo", SymbolKind.Class)) } diff --git a/language-server/test/dotty/tools/languageserver/WorksheetTest.scala b/language-server/test/dotty/tools/languageserver/WorksheetTest.scala index ac9438238e55..d5a9773a0bc2 100644 --- a/language-server/test/dotty/tools/languageserver/WorksheetTest.scala +++ b/language-server/test/dotty/tools/languageserver/WorksheetTest.scala @@ -42,7 +42,7 @@ class WorksheetTest { @Test def defineCaseClass: Unit = { ws"""${m1}case class Foo(x: Int)${m2} - ${m3}Foo(1)${m4}""".withSource + |${m3}Foo(1)${m4}""".withSource .run(m1, ((m1 to m2), "// defined case class Foo"), ((m3 to m4), "val res0: Foo = Foo(1)")) @@ -68,10 +68,10 @@ class WorksheetTest { @Test def defineAnonymousClass1: Unit = { ws"""${m1}class Foo${m2} - ${m3}trait Bar${m4} - ${m5}new Foo with Bar { - override def toString: String = "Foo" - }${m6}""".withSource + |${m3}trait Bar${m4} + |${m5}new Foo with Bar { + | override def toString: String = "Foo" + |}${m6}""".withSource .run(m1, ((m1 to m2), "// defined class Foo"), ((m3 to m4), "// defined trait Bar"), diff --git a/tests/neg/endmarkers.scala b/tests/neg/endmarkers.scala index f371c05bb6cd..40a2a731b2cf 100644 --- a/tests/neg/endmarkers.scala +++ b/tests/neg/endmarkers.scala @@ -1,4 +1,4 @@ -object Test: +object Test locally: var x = 0 @@ -52,11 +52,11 @@ object Test: x < 10 do () -class Test2: +class Test2 self => def foo = 1 - object x: + object x new Test2: override def foo = 2 end new // error: end of statement expected but new found // error: not found: end @@ -64,16 +64,16 @@ class Test2: end Test2 // error: misaligned end marker end Test2 -class Test3: +class Test3 self => def foo = 1 end Test3 // error: not found: end import collection.mutable.HashMap -class Coder(words: List[String]): +class Coder(words: List[String]) - class Foo: + class Foo println() end Foo // error: not found: end diff --git a/tests/neg/exports.check b/tests/neg/exports.check index b29ff65e9c2a..23aa778a70bd 100644 --- a/tests/neg/exports.check +++ b/tests/neg/exports.check @@ -31,19 +31,19 @@ | final def status: => List[String] in class Copier at line 23 and | final def status: => List[String] in class Copier at line 24 | have the same type after erasure. --- Error: tests/neg/exports.scala:35:15 -------------------------------------------------------------------------------- -35 | export this.{concat => ++} // error: no eligible member - | ^^^^^^ - | no eligible member concat at this - | this.concat cannot be exported because it is already a member of trait IterableOps --- Error: tests/neg/exports.scala:41:13 -------------------------------------------------------------------------------- -41 | export foo.foo // error: no eligible member - | ^^^ - | no eligible member foo at this.foo - | this.foo.foo cannot be exported because it is already a member of class Foo --- [E120] Duplicate Symbol Error: tests/neg/exports.scala:46:13 -------------------------------------------------------- -46 | export bar._ // error: double definition - | ^ - | Double definition: - | val bar: Bar in class Baz at line 45 and - | final def bar: => => Bar(Baz.this.bar.baz.bar)(Baz.this.bar.bar) in class Baz at line 46 +-- Error: tests/neg/exports.scala:35:17 -------------------------------------------------------------------------------- +35 | export this.{concat => ++} // error: no eligible member + | ^^^^^^ + | no eligible member concat at this + | this.concat cannot be exported because it is already a member of trait IterableOps +-- Error: tests/neg/exports.scala:41:15 -------------------------------------------------------------------------------- +41 | export foo.foo // error: no eligible member + | ^^^ + | no eligible member foo at this.foo + | this.foo.foo cannot be exported because it is already a member of class Foo +-- [E120] Duplicate Symbol Error: tests/neg/exports.scala:46:15 -------------------------------------------------------- +46 | export bar._ // error: double definition + | ^ + | Double definition: + | val bar: Bar in class Baz at line 45 and + | final def bar: => => Bar(Baz.this.bar.baz.bar)(Baz.this.bar.bar) in class Baz at line 46 diff --git a/tests/neg/exports.scala b/tests/neg/exports.scala index e94cb3a246ce..f9841fd70119 100644 --- a/tests/neg/exports.scala +++ b/tests/neg/exports.scala @@ -28,24 +28,24 @@ def status: List[String] = printUnit.status ++ scanUnit.status } -trait IterableOps[+A, +CC[_], +C] { + trait IterableOps[+A, +CC[_], +C] { - def concat[B >: A](other: List[B]): CC[B] + def concat[B >: A](other: List[B]): CC[B] - export this.{concat => ++} // error: no eligible member + export this.{concat => ++} // error: no eligible member -} + } -class Foo { - val foo : Foo = new Foo - export foo.foo // error: no eligible member -} + class Foo { + val foo : Foo = new Foo + export foo.foo // error: no eligible member + } -class Baz { - val bar: Bar = new Bar - export bar._ // error: double definition -} -class Bar { - val baz: Baz = new Baz - export baz._ -} + class Baz { + val bar: Bar = new Bar + export bar._ // error: double definition + } + class Bar { + val baz: Baz = new Baz + export baz._ + } diff --git a/tests/neg/parser-stability-12.scala b/tests/neg/parser-stability-12.scala index 706235f4ab4a..ae0a15204530 100644 --- a/tests/neg/parser-stability-12.scala +++ b/tests/neg/parser-stability-12.scala @@ -1,4 +1,4 @@ trait x0[] // error trait x1[x1 <:x0] - extends x1[ + extends x1[ // error // error \ No newline at end of file diff --git a/tests/neg/parser-stability-19.scala b/tests/neg/parser-stability-19.scala index 42f2005d6060..d5005634a521 100644 --- a/tests/neg/parser-stability-19.scala +++ b/tests/neg/parser-stability-19.scala @@ -1,5 +1,5 @@ object x0 { - case class x0[]() // error // error - def x0( ) ] // error // error + case class x0[]() // error + def x0( ) ] // error def x0 ( x0:x0 ):x0.type = x1 x0 // error // error // error \ No newline at end of file diff --git a/tests/neg/spaces-vs-tabs.scala b/tests/neg/spaces-vs-tabs.scala index daa89af7a7fe..cf24f8290904 100644 --- a/tests/neg/spaces-vs-tabs.scala +++ b/tests/neg/spaces-vs-tabs.scala @@ -1,4 +1,4 @@ -object Test: +object Test if true then println(1) // ok @@ -7,7 +7,7 @@ object Test: println(4) // error else () // error // error - object Test2: + object Test2 if true then 1 diff --git a/tests/patmat/t11620.scala b/tests/patmat/t11620.scala index cc20696cd387..05dfc1e0e437 100644 --- a/tests/patmat/t11620.scala +++ b/tests/patmat/t11620.scala @@ -1,6 +1,6 @@ sealed trait A[+T] - case class A1[+T](t : T ) extends A[T] - case class A2[+T](t1: T, t2: T) extends A[T] +case class A1[+T](t : T ) extends A[T] +case class A2[+T](t1: T, t2: T) extends A[T] sealed trait B[+T] { type AA[+U] <: A[U] diff --git a/tests/pos/i6146.scala b/tests/pos/i6146.scala index c0a98c910018..e13707dcdea3 100644 --- a/tests/pos/i6146.scala +++ b/tests/pos/i6146.scala @@ -1,5 +1,5 @@ trait BS[T, S <: BS[T, S]] - trait IS extends BS[Int, IS] +trait IS extends BS[Int, IS] sealed trait BSElem[T, S <: BS[_, S]] // old error: Type argument S does not conform to upper bound BS[Any, LazyRef(S)] diff --git a/tests/pos/indent.scala b/tests/pos/indent.scala index 8b31d002ca9e..ef9af5044174 100644 --- a/tests/pos/indent.scala +++ b/tests/pos/indent.scala @@ -1,4 +1,4 @@ -object Test: +object Test locally: var x = 0 @@ -56,7 +56,7 @@ object Test: x < 10 do () -class Test2: +class Test2 self => def foo = 1 @@ -67,15 +67,15 @@ class Test2: end x end Test2 -class Test3: +class Test3 self => def foo = 1 import collection.mutable.HashMap -class Coder(words: List[String]): +class Coder(words: List[String]) - class Foo: + class Foo println() end Foo diff --git a/tests/pos/indent2.scala b/tests/pos/indent2.scala index bee3d9f8fd2a..0452cef66327 100644 --- a/tests/pos/indent2.scala +++ b/tests/pos/indent2.scala @@ -1,7 +1,12 @@ -object testindent: - if 1 > 0 then +object testindent + + class C + val x = 0 + + val c = new C + if 1 > c.x then println println else println - println \ No newline at end of file + println diff --git a/tests/pos/indent3.scala b/tests/pos/indent3.scala new file mode 100644 index 000000000000..8cb455385b4a --- /dev/null +++ b/tests/pos/indent3.scala @@ -0,0 +1,7 @@ +object testindent + + class A + + /* foo */ class B + + class C diff --git a/tests/printing/i620.scala b/tests/printing/i620.scala index a4e1be9261e3..21c9254f22d1 100644 --- a/tests/printing/i620.scala +++ b/tests/printing/i620.scala @@ -22,7 +22,7 @@ class D { protected[D] class H protected class I protected[A] class J - class K + /* public */ class K protected[D] val a: Int = 0 private[D] val b: Int = 0 diff --git a/tests/run/tcpoly_parseridioms.scala b/tests/run/tcpoly_parseridioms.scala index e86af0caa90a..b9b8b56823f3 100644 --- a/tests/run/tcpoly_parseridioms.scala +++ b/tests/run/tcpoly_parseridioms.scala @@ -5,8 +5,8 @@ trait Parsers { type Input = List[Char] sealed class ParseResult[+t](val next: Input) - case class Success[+t](override val next: Input, result: t) extends ParseResult[t](next) - case class Failure(override val next: Input, msg: String) extends ParseResult[Nothing](next) + case class Success[+t](override val next: Input, result: t) extends ParseResult[t](next) + case class Failure(override val next: Input, msg: String) extends ParseResult[Nothing](next) abstract class Parser[+t] { def apply(in: Input): ParseResult[t]