Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion compiler/src/dotty/tools/dotc/printing/ReplPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,79 @@ import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.core.Symbols.*
import dotty.tools.dotc.core.Types.*
import dotty.tools.dotc.printing.Texts.*

import dotty.tools.dotc.typer.ImportInfo

class ReplPrinter(_ctx: Context) extends RefinedPrinter(_ctx) {

val debugPrint = _ctx.settings.YprintDebug.value

private def importSiteMatches(site: Type, owner: Symbol)(using Context): Boolean =
site.exists && (site.termSymbol == owner || site.termSymbol.moduleClass == owner)

private def isRootImport(owner: Symbol)(using Context): Boolean =
defn.rootImportTypes.exists(r => r.symbol == owner || r.symbol.moduleClass == owner)

private def importedNameFrom(info: ImportInfo, name: Name)(using Context): Name | Null =
val termName = name.toTermName
if info.forwardMapping.contains(termName) then info.forwardMapping(termName)
else if info.isWildcardImport && !info.excluded.contains(termName) then termName
else null

private def findImportedName(sym: Symbol, owner: Symbol)(using Context): Name | Null =
if isRootImport(owner) then sym.name.toTermName
else
var c = ctx
while c ne NoContext do
if c.isImportContext && importSiteMatches(c.importInfo.nn.site, owner) then
val result = importedNameFrom(c.importInfo.nn, sym.name)
if result != null then return result

c = c.outer
null

private def shortRefNameViaImports(tp: TermRef)(using Context): Name | Null =
if debugPrint then null
else if !tp.symbol.exists then null
else if !tp.prefix.termSymbol.exists then null
else findImportedName(tp.symbol, tp.prefix.termSymbol)

private def getImportedTypeName(sym: Symbol)(using Context): Name | Null =
if !sym.exists then null
else findImportedName(sym, sym.effectiveOwner)

override def toTextRef(tp: SingletonType): Text = controlled {
tp match
case tp: TermRef if !debugPrint =>
val shortName = shortRefNameViaImports(tp)
if shortName != null then nameString(shortName)
else super.toTextRef(tp)

case _ => super.toTextRef(tp)
}

override def toText(tp: Type): Text = tp match
case tp: TypeRef if !debugPrint =>
val importedName = getImportedTypeName(tp.symbol)
if importedName != null then nameString(importedName)
else super.toText(tp)

case _ => super.toText(tp)

/** Override fullNameString to use shorter names based on imports.
* This is called by RefinedPrinter.toTextRef for packages.
*/
override def fullNameString(sym: Symbol): String =
if debugPrint then super.fullNameString(sym)
else
def findShortestPath(s: Symbol): String =
if s.isRoot || s == NoSymbol || s.owner.isEffectiveRoot then nameString(s)
else
val owner = s.effectiveOwner
if findImportedName(s, owner) != null then nameString(s)
else findShortestPath(owner) + "." + nameString(s)

findShortestPath(sym)

override def nameString(name: Name): String =
if (name.isReplAssignName) name.decode.toString.takeWhile(_ != '$')
else super.nameString(name)
Expand Down
2 changes: 1 addition & 1 deletion repl/test-resources/repl-macros/i15104c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
scala> import scala.quoted._
scala> def macroImpl(using Quotes) = Expr(1)
def macroImpl(using x$1: scala.quoted.Quotes): scala.quoted.Expr[Int]
def macroImpl(using x$1: Quotes): Expr[Int]
scala> inline def foo = ${ macroImpl }
def foo: Int
scala> foo
Expand Down
4 changes: 1 addition & 3 deletions repl/test-resources/repl-macros/i5551
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
scala> import scala.quoted._
scala> def assertImpl(expr: Expr[Boolean])(using q: Quotes) = '{ if !($expr) then throw new AssertionError("failed assertion")}
def assertImpl
(expr: scala.quoted.Expr[Boolean])
(using q: scala.quoted.Quotes): scala.quoted.Expr[Unit]
def assertImpl(expr: Expr[Boolean])(using q: Quotes): Expr[Unit]
scala> inline def assert(expr: => Boolean): Unit = ${ assertImpl('{expr}) }
def assert(expr: => Boolean): Unit

Expand Down
8 changes: 2 additions & 6 deletions repl/test-resources/repl/i10355
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
scala> import scala.quoted._
scala> def foo(expr: Expr[Any])(using Quotes) = expr match { case '{ $x: t } => '{ $x: Any } }
def foo
(expr: scala.quoted.Expr[Any])
(using x$2: scala.quoted.Quotes): scala.quoted.Expr[Any]
def foo(expr: Expr[Any])(using x$2: Quotes): Expr[Any]
scala> def bar(expr: Expr[Any])(using Quotes) = expr match { case '{ $x: t } => '{ val a: t = ??? ; ???} }
def bar
(expr: scala.quoted.Expr[Any])
(using x$2: scala.quoted.Quotes): scala.quoted.Expr[Nothing]
def bar(expr: Expr[Any])(using x$2: Quotes): Expr[Nothing]
2 changes: 1 addition & 1 deletion repl/test-resources/repl/i11146
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ scala> object fs2 { class Stream[T] { override def toString = "fs2.Stream(..)" }

scala> import fs2.Stream
scala> Stream(1)
val res1: fs2.Stream[Int] = fs2.Stream(..)
val res1: Stream[Int] = fs2.Stream(..)
4 changes: 2 additions & 2 deletions repl/test-resources/repl/i15493
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ scala> res33.toString
val res34: String = "rs$line$46$Outer$Foo@17"

scala> Vector.unapplySeq(Vector(2))
val res35: scala.collection.SeqFactory.UnapplySeqWrapper[Int] = scala.collection.SeqFactory$UnapplySeqWrapper@df507bfd
val res35: collection.SeqFactory.UnapplySeqWrapper[Int] = scala.collection.SeqFactory$UnapplySeqWrapper@df507bfd

scala> new scala.concurrent.duration.DurationInt(5)
val res36: scala.concurrent.duration.DurationInt = scala.concurrent.duration.package$DurationInt@5
val res36: concurrent.duration.DurationInt = scala.concurrent.duration.package$DurationInt@5
6 changes: 3 additions & 3 deletions repl/test-resources/repl/import
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
scala> import collection.mutable._
scala> val buf = new ListBuffer[Int]
val buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
val buf: ListBuffer[Int] = ListBuffer()
scala> buf += 22
val res0: scala.collection.mutable.ListBuffer[Int] = ListBuffer(22)
val res0: ListBuffer[Int] = ListBuffer(22)
scala> buf ++= List(1, 2, 3)
val res1: scala.collection.mutable.ListBuffer[Int] = ListBuffer(22, 1, 2, 3)
val res1: ListBuffer[Int] = ListBuffer(22, 1, 2, 3)
scala> buf.toList
val res2: List[Int] = List(22, 1, 2, 3)
4 changes: 2 additions & 2 deletions repl/test-resources/repl/importFromObj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
scala> import scala.collection.mutable
scala> val buf = mutable.ListBuffer[Int]()
val buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
val buf: mutable.ListBuffer[Int] = ListBuffer()
scala> object o { val xs = List(1, 2, 3) }
// defined object o
scala> import o._
Expand All @@ -14,7 +14,7 @@ scala> buf += xs
| longer explanation available when compiling with `-explain`
1 error found
scala> buf ++= xs
val res0: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
val res0: mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
scala> import util.foobar
-- [E008] Not Found Error: -----------------------------------------------------
1 | import util.foobar
Expand Down
11 changes: 11 additions & 0 deletions repl/test-resources/repl/type-print-import
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
scala> collection.mutable.Buffer()
val res0: collection.mutable.Buffer[Nothing] = ArrayBuffer()
scala> import collection.mutable
scala> mutable.Buffer()
val res1: mutable.Buffer[Nothing] = ArrayBuffer()
scala> import collection.mutable.ArrayBuffer
scala> ArrayBuffer(1, 2, 3)
val res2: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
scala> import collection.mutable.{Buffer => B}
scala> B()
val res3: B[Nothing] = ArrayBuffer()
2 changes: 1 addition & 1 deletion repl/test-resources/type-printer/vals
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ var y: Int = 2
scala> val xs = List(1)
val xs: List[Int] = List(1)
scala> scala.util.Try(1)
val res0: scala.util.Try[Int] = Success(1)
val res0: util.Try[Int] = Success(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe show the full path when no import was added? This comes from the defaults, but might be confusing, since we also have java.util

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But Java.util and any other util package is likely not imported

Copy link
Contributor Author

@lihaoyi lihaoyi Dec 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I write code like util.Success and collection.Seq pretty frequently, taking advantage of the default imports. These shorthands are based on what symbols actually match, so there shouldn't be any ambiguity in meaning. If someone does import java.util or something it will fall back to the fully qualified name since the imported java.util will not be the same as scala.util

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's likely my personal preference then 😅 Maybe not important

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I often wonder if util is dotc.util. Naming is so hard. If only superscripts could help here? Color-coding? Red for scala, blue for java, green for dotty.

scala> Map(1 -> "one")
val res1: Map[Int, String] = Map(1 -> one)
2 changes: 1 addition & 1 deletion repl/test/dotty/tools/repl/ReplCompilerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ReplCompilerTests extends ReplTest:
assertEquals(1, summon[State].imports.size)
run("""mutable.Map("one" -> 1)""")
assertEquals(
"val res0: scala.collection.mutable.Map[String, Int] = HashMap(one -> 1)",
"val res0: mutable.Map[String, Int] = HashMap(one -> 1)",
storedOutput().trim
)
}
Expand Down
2 changes: 1 addition & 1 deletion repl/test/dotty/tools/repl/ShadowingTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class ShadowingTests extends ReplTest(options = ShadowingTests.options):
|
|scala> import util.Try
|scala> new Try
|val res0: util.Try = you've gotta try!
|val res0: Try = you've gotta try!
|""".stripMargin.linesIterator.toList
)
end ShadowingTests
Loading