Skip to content

Commit ef830ca

Browse files
committed
encode packages in tasty and signatures
1 parent 2333316 commit ef830ca

File tree

18 files changed

+110
-27
lines changed

18 files changed

+110
-27
lines changed

compiler/src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import java.nio.CharBuffer
77
import scala.io.Codec
88
import Int.MaxValue
99
import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._, Types._
10+
import SymDenotations.PrefixSeparator
1011
import util.Chars.{isOperatorPart, digit2int}
1112
import Definitions._
1213
import nme._
@@ -141,7 +142,7 @@ object NameOps {
141142
* followed by `kind` and the name.
142143
*/
143144
def expandedName(base: Symbol, kind: QualifiedNameKind = ExpandedName)(using Context): N =
144-
likeSpacedN { base.fullNameSeparated(ExpandPrefixName, kind, name) }
145+
likeSpacedN { base.fullNameSeparated(PrefixSeparator.ExpandPrefix, kind, name) }
145146

146147
/** Revert the expanded name. */
147148
def unexpandedName: N = likeSpacedN {

compiler/src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -455,17 +455,18 @@ object SymDenotations {
455455
final def originalOwner(using Context): Symbol = initial.maybeOwner
456456

457457
/** The encoded full path name of this denotation, where outer names and inner names
458-
* are separated by `separator` strings as indicated by the given name kind.
458+
* are separated by `separator` strings as indicated by the given prefix separator.
459459
* Drops package objects. Represents each term in the owner chain by a simple `_$`.
460460
*/
461-
def fullNameSeparated(kind: QualifiedNameKind)(using Context): Name =
462-
maybeOwner.fullNameSeparated(kind, kind, name)
461+
def fullNameSeparated(prefixSep: PrefixSeparator)(using Context): Name =
462+
val doEncodeName = prefixSep.encodePackages && is(Package) && !isEffectiveRoot
463+
maybeOwner.fullNameSeparated(prefixSep, prefixSep.kind, if doEncodeName then name.encode else name)
463464

464-
/** The encoded full path name of this denotation (separated by `prefixKind`),
465+
/** The encoded full path name of this denotation (separated by `prefixSep.kind`),
465466
* followed by the separator implied by `kind` and the given `name`.
466467
* Drops package objects. Represents each term in the owner chain by a simple `_$`.
467468
*/
468-
def fullNameSeparated(prefixKind: QualifiedNameKind, kind: QualifiedNameKind, name: Name)(using Context): Name =
469+
def fullNameSeparated(prefixSep: PrefixSeparator, kind: QualifiedNameKind, name: Name)(using Context): Name =
469470
if (symbol == NoSymbol || isEffectiveRoot || kind == FlatName && is(PackageClass))
470471
name
471472
else {
@@ -475,7 +476,7 @@ object SymDenotations {
475476
encl = encl.owner
476477
filler += "_$"
477478
}
478-
var prefix = encl.fullNameSeparated(prefixKind)
479+
var prefix = encl.fullNameSeparated(prefixSep)
479480
if (kind.separator == "$")
480481
// duplicate scalac's behavior: don't write a double '$$' for module class members.
481482
prefix = prefix.exclude(ModuleClassName)
@@ -490,10 +491,13 @@ object SymDenotations {
490491
}
491492

492493
/** The encoded flat name of this denotation, where joined names are separated by `separator` characters. */
493-
def flatName(using Context): Name = fullNameSeparated(FlatName)
494+
def flatName(using Context): Name = fullNameSeparated(PrefixSeparator.Flat)
494495

495496
/** `fullName` where `.' is the separator character */
496-
def fullName(using Context): Name = fullNameSeparated(QualifiedName)
497+
def fullName(using Context): Name = fullNameSeparated(PrefixSeparator.Full)
498+
499+
/** `fullName` where `.' is the separator character, and package names are encoded */
500+
def tastyCompatibleFullName(using Context): Name = fullNameSeparated(PrefixSeparator.TastyCompatibleFull)
497501

498502
private var myTargetName: Name = null
499503

@@ -1685,6 +1689,12 @@ object SymDenotations {
16851689
final def sealedDescendants(using Context): List[Symbol] = this.symbol :: sealedStrictDescendants
16861690
}
16871691

1692+
enum PrefixSeparator(final val kind: QualifiedNameKind, final val encodePackages: Boolean):
1693+
case TastyCompatibleFull extends PrefixSeparator(QualifiedName, encodePackages = true)
1694+
case Full extends PrefixSeparator(QualifiedName, encodePackages = false)
1695+
case Flat extends PrefixSeparator(FlatName, encodePackages = false)
1696+
case ExpandPrefix extends PrefixSeparator(ExpandPrefixName, encodePackages = false)
1697+
16881698
/** The contents of a class definition during a period
16891699
*/
16901700
class ClassDenotation private[SymDenotations] (
@@ -1701,7 +1711,7 @@ object SymDenotations {
17011711
// ----- caches -------------------------------------------------------
17021712

17031713
private var myTypeParams: List[TypeSymbol] = null
1704-
private var fullNameCache: SimpleIdentityMap[QualifiedNameKind, Name] = SimpleIdentityMap.empty
1714+
private var fullNameCache: SimpleIdentityMap[PrefixSeparator, Name] = SimpleIdentityMap.empty
17051715

17061716
private var myMemberCache: EqHashMap[Name, PreDenotation] = null
17071717
private var myMemberCachePeriod: Period = Nowhere
@@ -2252,12 +2262,12 @@ object SymDenotations {
22522262
}
22532263
}
22542264

2255-
override final def fullNameSeparated(kind: QualifiedNameKind)(using Context): Name = {
2256-
val cached = fullNameCache(kind)
2265+
override final def fullNameSeparated(prefixKind: PrefixSeparator)(using Context): Name = {
2266+
val cached = fullNameCache(prefixKind)
22572267
if (cached != null) cached
22582268
else {
2259-
val fn = super.fullNameSeparated(kind)
2260-
fullNameCache = fullNameCache.updated(kind, fn)
2269+
val fn = super.fullNameSeparated(prefixKind)
2270+
fullNameCache = fullNameCache.updated(prefixKind, fn)
22612271
fn
22622272
}
22632273
}

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -799,15 +799,15 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
799799
sigName(defn.functionTypeErasure(sym))
800800
else
801801
val cls = normalizeClass(sym.asClass)
802-
val fullName =
802+
val tastyCompatibleFullName =
803803
if !ctx.erasedTypes then
804804
// It's important to use the initial symbol to compute the full name
805805
// because the current symbol might have a different name or owner
806806
// and signatures are required to be stable before erasure.
807-
cls.initial.fullName
807+
cls.initial.tastyCompatibleFullName
808808
else
809-
cls.fullName
810-
fullName.asTypeName
809+
cls.tastyCompatibleFullName
810+
tastyCompatibleFullName.asTypeName
811811
case tp: AppliedType =>
812812
val sym = tp.tycon.typeSymbol
813813
sigName( // todo: what about repeatedParam?

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class TreePickler(pickler: TastyPickler) {
191191
}
192192
if (sym.is(Flags.Package)) {
193193
writeByte(if (tpe.isType) TYPEREFpkg else TERMREFpkg)
194-
pickleName(sym.fullName)
194+
pickleName(sym.tastyCompatibleFullName)
195195
}
196196
else if (tpe.prefix == NoPrefix) {
197197
writeByte(if (tpe.isType) TYPEREFdirect else TERMREFdirect)
@@ -397,7 +397,8 @@ class TreePickler(pickler: TastyPickler) {
397397
|| tree.denot.asSingleDenotation.isRefinedMethod // refined methods have no defining class symbol
398398
if selectFromQualifier then
399399
writeByte(if name.isTypeName then SELECTtpt else SELECT)
400-
pickleNameAndSig(name, sig, ename)
400+
val isPackage = tree.symbol.is(Package)
401+
pickleNameAndSig(if isPackage then name.encode else name, sig, ename)
401402
pickleTree(qual)
402403
else // select from owner
403404
writeByte(SELECTin)

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
270270
ParamRefNameString(param.binder.paramNames(param.paramNum))
271271

272272
/** The name of the symbol without a unique id. */
273-
protected def simpleNameString(sym: Symbol): String = nameString(sym.name)
273+
protected def simpleNameString(sym: Symbol): String =
274+
val doEncode = homogenizedView && sym.is(Package)
275+
nameString(if doEncode then sym.name.encode else sym.name)
274276

275277
/** If -uniqid is set, the hashcode of the lambda type, after a # */
276278
protected def lambdaHash(pt: LambdaType): Text =
@@ -308,7 +310,13 @@ class PlainPrinter(_ctx: Context) extends Printer {
308310

309311
protected def selectionString(tp: NamedType): String = {
310312
val sym = if (homogenizedView) tp.symbol else tp.currentSymbol
311-
if (sym.exists) nameString(sym) else nameString(tp.name)
313+
if sym.exists then
314+
if homogenizedView && sym.is(Flags.Package) && !sym.isEffectiveRoot then
315+
nameString(sym.name.encode)
316+
else
317+
nameString(sym)
318+
else
319+
nameString(tp.name)
312320
}
313321

314322
/** The string representation of this type used as a prefix */
@@ -674,4 +682,3 @@ class PlainPrinter(_ctx: Context) extends Printer {
674682
protected def coloredText(text: Text, color: String): Text =
675683
if (ctx.useColors) color ~ text ~ SyntaxHighlighting.NoColor else text
676684
}
677-

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
8282
else super.nameString(strippedName)
8383

8484
override protected def simpleNameString(sym: Symbol): String =
85-
nameString(if (ctx.property(XprintMode).isEmpty) sym.initial.name else sym.name)
85+
val theSym: SymDenotation = if (ctx.property(XprintMode).isEmpty) sym.initial else sym
86+
nameString(if homogenizedView && theSym.is(Package) then theSym.name.encode else theSym.name)
8687

8788
override def fullNameString(sym: Symbol): String =
8889
if !sym.exists || isEmptyPrefix(sym.effectiveOwner) then nameString(sym)

compiler/src/dotty/tools/dotc/transform/Splicer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import dotty.tools.dotc.ast.tpd
88
import dotty.tools.dotc.core.Contexts._
99
import dotty.tools.dotc.core.Decorators._
1010
import dotty.tools.dotc.core.Flags._
11-
import dotty.tools.dotc.core.NameKinds.FlatName
1211
import dotty.tools.dotc.core.Names.Name
1312
import dotty.tools.dotc.core.StdNames._
1413
import dotty.tools.dotc.core.Types._
1514
import dotty.tools.dotc.core.Symbols._
15+
import dotty.tools.dotc.core.SymDenotations.PrefixSeparator
1616
import dotty.tools.dotc.core.Denotations.staticRef
1717
import dotty.tools.dotc.core.TypeErasure
1818
import dotty.tools.dotc.core.Constants.Constant
@@ -508,7 +508,7 @@ object Splicer {
508508
// Take the flatten name of the class and the full package name
509509
val pack = tpe.classSymbol.topLevelClass.owner
510510
val packageName = if (pack == defn.EmptyPackageClass) "" else s"${pack.fullName}."
511-
packageName + tpe.classSymbol.fullNameSeparated(FlatName).toString
511+
packageName + tpe.classSymbol.fullNameSeparated(PrefixSeparator.Flat).toString
512512
}
513513

514514
val sym = param.classSymbol

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2483,7 +2483,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
24832483
else None
24842484

24852485
def name: String = self.denot.name.toString
2486-
def fullName: String = self.denot.fullName.toString
2486+
def fullName: String = self.denot.tastyCompatibleFullName.toString
24872487

24882488
def pos: Option[Position] =
24892489
if self.exists then Some(self.sourcePos) else None

tests/neg/symbolic-packages/App.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package example
2+
3+
class Example:
4+
5+
def foo: symbolic_>> = ??? // error: No type found
6+
def bar: _root_.symbolic_>> = ??? // ok - will "mock superclass"

tests/neg/symbolic-packages/Lib.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package symbolic_>>
2+
3+
class |+|
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package example
2+
3+
class Example:
4+
5+
def inferred = new fully_+.symbolic_>>.package_*.|+|()
6+
def explicit: fully_+.symbolic_>>.package_*.|+| = new fully_+.symbolic_>>.package_*.|+|()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package fully_+.symbolic_>>.package_*
2+
3+
class |+|

tests/pos/symbolic-packages/App.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package example
2+
3+
class Example:
4+
5+
def inferred = new fully_+.symbolic_>>.package_*.|+|()
6+
def explicit: fully_+.symbolic_>>.package_*.|+| = new fully_+.symbolic_>>.package_*.|+|()

tests/pos/symbolic-packages/Lib.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package fully_+.symbolic_>>.package_*
2+
3+
class |+|
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fully_$plus.symbolic_$greater$greater.package_$times.|+|
2+
fully_+.symbolic_>>.package_*.|+|
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package fully_+.symbolic_>>.package_*
2+
3+
class |+|
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@main def Test =
2+
type Queried = fully_+.symbolic_>>.package_*.|+|
3+
println(getFullName[Queried](decoded = false))
4+
println(getFullName[Queried](decoded = true))
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.quoted.*
2+
import scala.reflect.NameTransformer
3+
4+
inline def getFullName[T](inline decoded: Boolean) = ${ Macro.getFullName[T]('decoded) }
5+
6+
object Macro:
7+
def getFullName[T: Type](decodedExpr: Expr[Boolean])(using Quotes): Expr[String] =
8+
import quotes.reflect.*
9+
10+
val decode = decodedExpr.valueOrAbort
11+
12+
val tpe = TypeRepr.of[T]
13+
14+
val cls = tpe.classSymbol match
15+
case Some(cls) => cls
16+
case _ =>
17+
report.error("Not a class")
18+
return '{"<?>"}
19+
20+
val name = cls.fullName
21+
22+
if decode then
23+
val parts = name.split('.').toSeq
24+
val decoded = (parts.init.map(NameTransformer.decode) :+ parts.last).mkString(".")
25+
Expr(decoded)
26+
else
27+
Expr(name)

0 commit comments

Comments
 (0)