From 123d3a2d7d1e2fb81ad75d227423c5e442625a11 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 19 Aug 2020 12:07:48 +0200 Subject: [PATCH 1/6] Reduce allocations when loading packages from classpath This is a port of the following PR in scalac: https://github.com/scala/scala/pull/8927 --- .../tools/dotc/classpath/ClassPath.scala | 21 ++++++----- .../src/dotty/tools/dotc/core/Contexts.scala | 12 +++++++ .../dotty/tools/dotc/core/Definitions.scala | 2 +- .../dotty/tools/dotc/core/SymbolLoaders.scala | 36 +++++++++++-------- compiler/src/dotty/tools/io/ClassPath.scala | 13 +++++++ 5 files changed, 60 insertions(+), 24 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala b/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala index 1c95589d3fb7..9557a55e25d2 100644 --- a/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala +++ b/compiler/src/dotty/tools/dotc/classpath/ClassPath.scala @@ -23,24 +23,27 @@ trait PackageEntry { } private[dotty] case class ClassFileEntryImpl(file: AbstractFile) extends ClassFileEntry { - override def name: String = FileUtils.stripClassExtension(file.name) // class name + final def fileName: String = file.name + def name: String = FileUtils.stripClassExtension(file.name) // class name - override def binary: Option[AbstractFile] = Some(file) - override def source: Option[AbstractFile] = None + def binary: Option[AbstractFile] = Some(file) + def source: Option[AbstractFile] = None } private[dotty] case class SourceFileEntryImpl(file: AbstractFile) extends SourceFileEntry { - override def name: String = FileUtils.stripSourceExtension(file.name) + final def fileName: String = file.name + def name: String = FileUtils.stripSourceExtension(file.name) - override def binary: Option[AbstractFile] = None - override def source: Option[AbstractFile] = Some(file) + def binary: Option[AbstractFile] = None + def source: Option[AbstractFile] = Some(file) } private[dotty] case class ClassAndSourceFilesEntry(classFile: AbstractFile, srcFile: AbstractFile) extends ClassRepresentation { - override def name: String = FileUtils.stripClassExtension(classFile.name) + final def fileName: String = classFile.name + def name: String = FileUtils.stripClassExtension(classFile.name) - override def binary: Option[AbstractFile] = Some(classFile) - override def source: Option[AbstractFile] = Some(srcFile) + def binary: Option[AbstractFile] = Some(classFile) + def source: Option[AbstractFile] = Some(srcFile) } private[dotty] case class PackageEntryImpl(name: String) extends PackageEntry diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index fdba7003a9d1..5db5335912d9 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -89,6 +89,16 @@ object Contexts { inline def withoutMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T = inMode(ctx.mode &~ mode)(op) + private[dotc] inline def withNameBuffer(inline op: Array[Char] => Int)(using ctx: Context): Names.TermName = { + val base = ctx.base + var len = op(base.nameCharBuffer) + while(len == -1) { + base.nameCharBuffer = new Array[Char](base.nameCharBuffer.length * 2) + len = op(base.nameCharBuffer) + } + Names.termName(base.nameCharBuffer, 0, len) + } + /** A context is passed basically everywhere in dotc. * This is convenient but carries the risk of captured contexts in * objects that turn into space leaks. To combat this risk, here are some @@ -894,6 +904,8 @@ object Contexts { private[Contexts] val comparers = new mutable.ArrayBuffer[TypeComparer] private[Contexts] var comparersInUse: Int = 0 + private[dotc] var nameCharBuffer = new Array[Char](256) + def reset(): Unit = { for ((_, set) <- uniqueSets) set.clear() errorTypeMsg.clear() diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 418d7f3027c9..dde6baa47325 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -682,10 +682,10 @@ class Definitions { @tu lazy val NonLocalReturnControlClass: ClassSymbol = requiredClass("scala.runtime.NonLocalReturnControl") @tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable") + @tu lazy val ReflectPackageClass: Symbol = requiredPackage("scala.reflect.package").moduleClass @tu lazy val ClassTagClass: ClassSymbol = requiredClass("scala.reflect.ClassTag") @tu lazy val ClassTagModule: Symbol = ClassTagClass.companionModule @tu lazy val ClassTagModule_apply: Symbol = ClassTagModule.requiredMethod(nme.apply) - @tu lazy val ReflectPackageClass: Symbol = requiredPackage("scala.reflect.package").moduleClass @tu lazy val QuotedExprClass: ClassSymbol = requiredClass("scala.quoted.Expr") diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 0d23f0df1d51..a122e1959e6b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -4,24 +4,29 @@ package core import java.io.{IOException, File} import java.nio.channels.ClosedByInterruptException + import scala.compat.Platform.currentTime +import scala.util.control.NonFatal + import dotty.tools.io.{ ClassPath, ClassRepresentation, AbstractFile } -import config.Config +import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions + import Contexts._, Symbols._, Flags._, SymDenotations._, Types._, Scopes._, Names._ import NameOps._ -import StdNames.str -import Decorators._ +import StdNames._ import classfile.ClassfileParser -import util.Stats import Decorators._ -import scala.util.control.NonFatal + +import util.Stats +import reporting.trace +import config.Config + import ast.Trees._ +import ast.desugar + import parsing.JavaParsers.OutlineJavaParser import parsing.Parsers.OutlineParser -import reporting.trace -import ast.desugar -import dotty.tools.backend.jvm.DottyBackendInterface.symExtensions object SymbolLoaders { import ast.untpd._ @@ -178,27 +183,30 @@ object SymbolLoaders { * Note: We do a name-base comparison here because the method is called before we even * have ReflectPackage defined. */ - def binaryOnly(owner: Symbol, name: String)(using Context): Boolean = - name == "package" && + def binaryOnly(owner: Symbol, name: TermName)(using Context): Boolean = + name == nme.PACKAGEkw && (owner.fullName.toString == "scala" || owner.fullName.toString == "scala.reflect") /** Initialize toplevel class and module symbols in `owner` from class path representation `classRep` */ def initializeFromClassPath(owner: Symbol, classRep: ClassRepresentation)(using Context): Unit = ((classRep.binary, classRep.source): @unchecked) match { - case (Some(bin), Some(src)) if needCompile(bin, src) && !binaryOnly(owner, classRep.name) => + case (Some(bin), Some(src)) if needCompile(bin, src) && !binaryOnly(owner, nameOf(classRep)) => if (ctx.settings.verbose.value) report.inform("[symloader] picked up newer source file for " + src.path) - enterToplevelsFromSource(owner, classRep.name, src) + enterToplevelsFromSource(owner, nameOf(classRep), src) case (None, Some(src)) => if (ctx.settings.verbose.value) report.inform("[symloader] no class, picked up source file for " + src.path) - enterToplevelsFromSource(owner, classRep.name, src) + enterToplevelsFromSource(owner, nameOf(classRep), src) case (Some(bin), _) => - enterClassAndModule(owner, classRep.name, ctx.platform.newClassLoader(bin)) + enterClassAndModule(owner, nameOf(classRep), ctx.platform.newClassLoader(bin)) } def needCompile(bin: AbstractFile, src: AbstractFile): Boolean = src.lastModified >= bin.lastModified + private def nameOf(classRep: ClassRepresentation)(using Context): TermName = + withNameBuffer(classRep.nameChars) + /** Load contents of a package */ class PackageLoader(_sourceModule: TermSymbol, classPath: ClassPath) diff --git a/compiler/src/dotty/tools/io/ClassPath.scala b/compiler/src/dotty/tools/io/ClassPath.scala index f8fa6c2c35be..b3d75001838f 100644 --- a/compiler/src/dotty/tools/io/ClassPath.scala +++ b/compiler/src/dotty/tools/io/ClassPath.scala @@ -170,9 +170,22 @@ object ClassPath { } trait ClassRepresentation { + def fileName: String def name: String def binary: Option[AbstractFile] def source: Option[AbstractFile] + + /** Low level way to extract the entry name without allocation. */ + final def nameChars(buffer: Array[Char]): Int = { + val ix = fileName.lastIndexOf('.') + val nameLength = if (ix < 0) fileName.length else ix + if (nameLength > buffer.length) + -1 + else { + fileName.getChars(0, nameLength, buffer, 0) + nameLength + } + } } @deprecated("shim for sbt's compiler interface", since = "2.12.0") From cfd2937dd3fc21a18a667e89e756e371ac0637a7 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 19 Aug 2020 16:14:46 +0200 Subject: [PATCH 2/6] Avoid string equality --- compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index a122e1959e6b..9f1b6a8ca44f 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -185,7 +185,7 @@ object SymbolLoaders { */ def binaryOnly(owner: Symbol, name: TermName)(using Context): Boolean = name == nme.PACKAGEkw && - (owner.fullName.toString == "scala" || owner.fullName.toString == "scala.reflect") + (owner.name == nme.scala || owner.name == nme.reflect && owner.owner.name == nme.scala) /** Initialize toplevel class and module symbols in `owner` from class path representation `classRep` */ From 1fd0844d5e976bb4a5080906c9b3562aa15c2f2c Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Wed, 19 Aug 2020 19:11:29 +0200 Subject: [PATCH 3/6] Generalize buffering for Name construction from substring --- compiler/src/dotty/tools/dotc/core/Contexts.scala | 10 ---------- compiler/src/dotty/tools/dotc/core/Names.scala | 13 +++++++++++++ .../src/dotty/tools/dotc/core/SymbolLoaders.scala | 2 +- compiler/src/dotty/tools/io/ClassPath.scala | 15 ++++++--------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 5db5335912d9..c805be876868 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -89,16 +89,6 @@ object Contexts { inline def withoutMode[T](mode: Mode)(inline op: Context ?=> T)(using ctx: Context): T = inMode(ctx.mode &~ mode)(op) - private[dotc] inline def withNameBuffer(inline op: Array[Char] => Int)(using ctx: Context): Names.TermName = { - val base = ctx.base - var len = op(base.nameCharBuffer) - while(len == -1) { - base.nameCharBuffer = new Array[Char](base.nameCharBuffer.length * 2) - len = op(base.nameCharBuffer) - } - Names.termName(base.nameCharBuffer, 0, len) - } - /** A context is passed basically everywhere in dotc. * This is convenient but carries the risk of captured contexts in * objects that turn into space leaks. To combat this risk, here are some diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index cd58977f9dda..674c3c721f01 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -644,6 +644,19 @@ object Names { /** Create a type name from a string, without encoding operators */ def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length) + def termName(s: String, from: Int, len: Int)(using ctx: Contexts.Context): TermName = { + val base = ctx.base + + while (len > base.nameCharBuffer.length) + base.nameCharBuffer = new Array[Char](base.nameCharBuffer.length * 2) + + s.getChars(from, from + len, base.nameCharBuffer, 0) + termName(base.nameCharBuffer, 0, len) + } + + def typeName(s: String, from: Int, len: Int)(using ctx: Contexts.Context): TypeName = + termName(s, from, len).toTypeName + table(0) = new SimpleName(-1, 0, null) /** The term name represented by the empty string */ diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 9f1b6a8ca44f..b53ab7c885bf 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -205,7 +205,7 @@ object SymbolLoaders { src.lastModified >= bin.lastModified private def nameOf(classRep: ClassRepresentation)(using Context): TermName = - withNameBuffer(classRep.nameChars) + termName(classRep.fileName, 0, classRep.nameLength) /** Load contents of a package */ diff --git a/compiler/src/dotty/tools/io/ClassPath.scala b/compiler/src/dotty/tools/io/ClassPath.scala index b3d75001838f..97d678901a6d 100644 --- a/compiler/src/dotty/tools/io/ClassPath.scala +++ b/compiler/src/dotty/tools/io/ClassPath.scala @@ -175,16 +175,13 @@ trait ClassRepresentation { def binary: Option[AbstractFile] def source: Option[AbstractFile] - /** Low level way to extract the entry name without allocation. */ - final def nameChars(buffer: Array[Char]): Int = { + /** returns the length of `name` by stripping the extension of `fileName` + * + * Used to avoid creating String instance of `name`. + */ + final def nameLength: Int = { val ix = fileName.lastIndexOf('.') - val nameLength = if (ix < 0) fileName.length else ix - if (nameLength > buffer.length) - -1 - else { - fileName.getChars(0, nameLength, buffer, 0) - nameLength - } + if (ix < 0) fileName.length else ix } } From 6ccfdc18c4684383e5b4a00e7a564014d6a91659 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 20 Aug 2020 11:19:35 +0200 Subject: [PATCH 4/6] Add some explaining comments --- compiler/src/dotty/tools/dotc/core/Names.scala | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index 674c3c721f01..f84eca7b88bb 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -11,6 +11,7 @@ import scala.internal.Chars.isIdentifierStart import collection.immutable import config.Config import java.util.HashMap +import Contexts.{Context, ctx} import scala.annotation.internal.sharable @@ -638,12 +639,18 @@ object Names { def typeName(bs: Array[Byte], offset: Int, len: Int): TypeName = termName(bs, offset, len).toTypeName - /** Create a term name from a string, without encoding operators */ + /** Create a term name from a string. + * See `termName(s: String, from: Int, len: Int) for a more efficient version + * which however requires a Context for its operation + */ def termName(s: String): SimpleName = termName(s.toCharArray, 0, s.length) - /** Create a type name from a string, without encoding operators */ + /** Create a type name from a string */ def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length) + /** Create a term name from a string slice, using a common buffer. + * This avoids some allocation relative to `termName(s: String)` + */ def termName(s: String, from: Int, len: Int)(using ctx: Contexts.Context): TermName = { val base = ctx.base @@ -654,7 +661,10 @@ object Names { termName(base.nameCharBuffer, 0, len) } - def typeName(s: String, from: Int, len: Int)(using ctx: Contexts.Context): TypeName = + /** Create a type name from a string slice, using a common buffer. + * This avoids some allocation relative to `typeName(s: String)` + */ + def typeName(s: String, from: Int, len: Int)(using Context): TypeName = termName(s, from, len).toTypeName table(0) = new SimpleName(-1, 0, null) From fb736068d52ed00b4196f8da67a759b557e390da Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 20 Aug 2020 11:50:23 +0200 Subject: [PATCH 5/6] Move sliceToTermName logic to Decorators That way we can keep Contexts out of Names. --- .../src/dotty/tools/dotc/config/Feature.scala | 2 +- .../tools/dotc/config/SourceVersion.scala | 2 +- .../dotty/tools/dotc/core/Decorators.scala | 28 +++++++++++++------ .../src/dotty/tools/dotc/core/Names.scala | 24 ++-------------- .../dotty/tools/dotc/core/SymbolLoaders.scala | 2 +- 5 files changed, 25 insertions(+), 33 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index ed804ff4a7af..63ac69b94eba 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -5,7 +5,7 @@ package config import core._ import Contexts._, Symbols._, Names._, NameOps._, Phases._ import StdNames.nme -import Decorators.{given _} +import Decorators.{_, given _} import util.SrcPos import SourceVersion._ import reporting.Message diff --git a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala index cc9221bad6cf..e7b39ac769ac 100644 --- a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala +++ b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala @@ -5,7 +5,7 @@ package config import core.Contexts._ import core.Names.TermName import core.StdNames.nme -import core.Decorators.{given _} +import core.Decorators.{_, given _} import util.Property enum SourceVersion: diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index afb356db2d52..f695923d517b 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -20,22 +20,34 @@ object Decorators { * with a normal wildcard. In the future, once #9255 is in trunk, replace with * a simple collective extension. */ - implicit object PreNamedString: - extension (pn: PreName) def toTypeName: TypeName = pn match - case s: String => typeName(s) - case n: Name => n.toTypeName - extension (pn: PreName) def toTermName: TermName = pn match + extension (pn: PreName) + def toTermName: TermName = pn match case s: String => termName(s) case n: Name => n.toTermName + def toTypeName: TypeName = pn match + case s: String => typeName(s) + case n: Name => n.toTypeName extension (s: String): - def splitWhere(f: Char => Boolean, doDropIndex: Boolean): Option[(String, String)] = { + def splitWhere(f: Char => Boolean, doDropIndex: Boolean): Option[(String, String)] = def splitAt(idx: Int, doDropIndex: Boolean): Option[(String, String)] = if (idx == -1) None else Some((s.take(idx), s.drop(if (doDropIndex) idx + 1 else idx))) - splitAt(s.indexWhere(f), doDropIndex) - } + + /** Create a term name from a string slice, using a common buffer. + * This avoids some allocation relative to `termName(s)` + */ + def sliceToTermName(start: Int, end: Int)(using Context): SimpleName = + val base = ctx.base + val len = end - start + while len > base.nameCharBuffer.length do + base.nameCharBuffer = new Array[Char](base.nameCharBuffer.length * 2) + s.getChars(start, end, base.nameCharBuffer, 0) + termName(base.nameCharBuffer, 0, len) + + def sliceToTypeName(start: Int, end: Int)(using Context): TypeName = + sliceToTermName(start, end).toTypeName /** Implements a findSymbol method on iterators of Symbols that * works like find but avoids Option, replacing None with NoSymbol. diff --git a/compiler/src/dotty/tools/dotc/core/Names.scala b/compiler/src/dotty/tools/dotc/core/Names.scala index f84eca7b88bb..89adab098abb 100644 --- a/compiler/src/dotty/tools/dotc/core/Names.scala +++ b/compiler/src/dotty/tools/dotc/core/Names.scala @@ -11,7 +11,6 @@ import scala.internal.Chars.isIdentifierStart import collection.immutable import config.Config import java.util.HashMap -import Contexts.{Context, ctx} import scala.annotation.internal.sharable @@ -640,33 +639,14 @@ object Names { termName(bs, offset, len).toTypeName /** Create a term name from a string. - * See `termName(s: String, from: Int, len: Int) for a more efficient version - * which however requires a Context for its operation + * See `sliceToTermName` in `Decorators` for a more efficient version + * which however requires a Context for its operation. */ def termName(s: String): SimpleName = termName(s.toCharArray, 0, s.length) /** Create a type name from a string */ def typeName(s: String): TypeName = typeName(s.toCharArray, 0, s.length) - /** Create a term name from a string slice, using a common buffer. - * This avoids some allocation relative to `termName(s: String)` - */ - def termName(s: String, from: Int, len: Int)(using ctx: Contexts.Context): TermName = { - val base = ctx.base - - while (len > base.nameCharBuffer.length) - base.nameCharBuffer = new Array[Char](base.nameCharBuffer.length * 2) - - s.getChars(from, from + len, base.nameCharBuffer, 0) - termName(base.nameCharBuffer, 0, len) - } - - /** Create a type name from a string slice, using a common buffer. - * This avoids some allocation relative to `typeName(s: String)` - */ - def typeName(s: String, from: Int, len: Int)(using Context): TypeName = - termName(s, from, len).toTypeName - table(0) = new SimpleName(-1, 0, null) /** The term name represented by the empty string */ diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index b53ab7c885bf..52431854f64b 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -205,7 +205,7 @@ object SymbolLoaders { src.lastModified >= bin.lastModified private def nameOf(classRep: ClassRepresentation)(using Context): TermName = - termName(classRep.fileName, 0, classRep.nameLength) + classRep.fileName.sliceToTermName(0, classRep.nameLength) /** Load contents of a package */ From aebb209604cda8cfd6c9a4cd00b92a3e7372a92d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 20 Aug 2020 12:32:59 +0200 Subject: [PATCH 6/6] Fix test --- .../test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala b/compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala index 62d95843e0f3..28779fe9b697 100644 --- a/compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala +++ b/compiler/test/dotty/tools/dotc/core/tasty/CommentPicklingTest.scala @@ -5,7 +5,7 @@ import dotty.tools.dotc.ast.tpd.TreeOps import dotty.tools.dotc.{Driver, Main} import dotty.tools.dotc.core.Comments.CommentsContext import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Decorators.PreNamedString +import dotty.tools.dotc.core.Decorators.{toTermName, toTypeName} import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Names.Name import dotty.tools.dotc.interfaces.Diagnostic.ERROR