Skip to content

Commit 362ea1b

Browse files
authored
Merge pull request #102 from scalacenter/tasty/upgrade-v23
Support TASTy version 23 [Dotty 0.25.0-RC2]
2 parents fb0ef91 + 3419d50 commit 362ea1b

33 files changed

+434
-41
lines changed

project/DottySupport.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import sbt.librarymanagement.{
1212
* Settings to support validation of TastyUnpickler against the release of dotty with the matching TASTy version
1313
*/
1414
object TastySupport {
15-
val supportedTASTyRelease = "0.24.0-RC1" // TASTy version 22
16-
val dottyCompiler = "ch.epfl.lamp" % "dotty-compiler_0.24" % supportedTASTyRelease
15+
val supportedTASTyRelease = "0.25.0-RC2" // TASTy version 23
16+
val dottyCompiler = "ch.epfl.lamp" % "dotty-compiler_0.25" % supportedTASTyRelease
1717
}
1818

1919
/** Settings needed to compile with Dotty,

src/compiler/scala/tools/nsc/tasty/TastyModes.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ object TastyModes {
2222
final val ReadParents: TastyMode = TastyMode(1 << 0)
2323
final val ReadAnnotation: TastyMode = TastyMode(1 << 1)
2424
final val OuterTerm: TastyMode = TastyMode(1 << 2)
25+
final val ReadMacro: TastyMode = TastyMode(1 << 3)
26+
final val IndexBody: TastyMode = TastyMode(1 << 4)
2527

2628
case class TastyMode(val toInt: Int) extends AnyVal { mode =>
2729

@@ -39,6 +41,8 @@ object TastyModes {
3941
if (mode.is(ReadParents)) sb += "ReadParents"
4042
if (mode.is(ReadAnnotation)) sb += "ReadAnnotation"
4143
if (mode.is(OuterTerm)) sb += "OuterTerm"
44+
if (mode.is(ReadMacro)) sb += "ReadMacro"
45+
if (mode.is(IndexBody)) sb += "IndexBody"
4246
sb.mkString("|")
4347
}
4448
}

src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,8 @@ class TreeUnpickler[Tasty <: TastyUniverse](
407407
if (isClass && flags.is(Trait)) flags |= Abstract
408408
if (tag === DEFDEF) flags |= Method
409409
if (tag === VALDEF) {
410+
if (flags.is(Inline) || owner.is(Trait)) flags |= FieldAccessor
410411
if (flags.not(Mutable)) flags |= Stable
411-
if (owner.is(Trait)) flags |= FieldAccessor
412412
}
413413
if (tastyFlags.is(Object))
414414
flags = flags | (if (tag === VALDEF) ObjectCreationFlags else ObjectClassCreationFlags)
@@ -521,16 +521,11 @@ class TreeUnpickler[Tasty <: TastyUniverse](
521521
sym.setAnnotations(annotFns.map(_(sym)))
522522
ctx.owner match {
523523
case cls if cls.isClass && canEnterInClass =>
524+
if (ctx.mode.is(IndexBody) && ctx.isLatentCandidate(sym))
525+
ctx.registerLatent(sym)
524526
val decl = if (flags.is(Object) && isClass) sym.sourceObject else sym
525-
val decls = cls.rawInfo.decls
526-
if (allowsOverload(decl)) {
527-
if (ctx.canEnterOverload(decl)) {
528-
decls.enter(decl)
529-
}
530-
}
531-
else {
532-
decls.enterIfNew(decl)
533-
}
527+
if (ctx.canEnter(decl))
528+
ctx.enter(cls, decl)
534529
case _ =>
535530
}
536531
registerSym(start, sym)
@@ -581,6 +576,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
581576
case STATIC => addFlag(Static)
582577
case OBJECT => addFlag(Object)
583578
case TRAIT => addFlag(Trait)
579+
case SUPERTRAIT => addFlag(SuperTrait)
584580
case ENUM => addFlag(Enum)
585581
case LOCAL => addFlag(Local)
586582
case SYNTHETIC => addFlag(Synthetic)
@@ -721,11 +717,12 @@ class TreeUnpickler[Tasty <: TastyUniverse](
721717
val localCtx = ctx.withOwner(sym)
722718
tag match {
723719
case DEFDEF =>
724-
val unsupported = completer.tastyFlagSet &~ (Extension | Inline | Macro | Exported)
720+
val unsupported = completer.tastyFlagSet &~ (Extension | Inline | Exported | Erased)
725721
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
726722
if (completer.tastyFlagSet.is(Extension)) ctx.log(s"$tname is a Scala 3 extension method.")
727-
unsupportedWhen(completer.tastyFlagSet.is(Inline, butNot = Macro), s"inline $sym")
728-
unsupportedWhen(completer.tastyFlagSet.is(Inline | Macro), s"macro $sym")
723+
unsupportedWhen(completer.tastyFlagSet.is(Inline), s"${if (sym.is(Macro)) "" else "inline "}$sym")
724+
val isMacroDef = completer.tastyFlagSet.is(Erased) && sym.is(Macro)
725+
unsupportedWhen(completer.tastyFlagSet.is(Erased) && !isMacroDef, s"erased $sym")
729726
val isCtor = sym.isClassConstructor
730727
val typeParams = {
731728
if (isCtor) {
@@ -738,6 +735,10 @@ class TreeUnpickler[Tasty <: TastyUniverse](
738735
}
739736
val vparamss = readParamss(localCtx)
740737
val tpt = readTpt()(localCtx)
738+
if (isMacroDef) {
739+
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
740+
sym.addAnnotation(symbolTable.AnnotationInfo(symbolTable.definitions.MacroTastyImplAnnotation.tpe, List(impl), Nil))
741+
}
741742
val valueParamss = normalizeIfConstructor(vparamss.map(_.map(symFromNoCycle)), isCtor)
742743
val resType = effectiveResultType(sym, typeParams, tpt.tpe)
743744
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
@@ -746,14 +747,16 @@ class TreeUnpickler[Tasty <: TastyUniverse](
746747
val unsupported = completer.tastyFlagSet &~ (Inline | Enum | Extension | Exported)
747748
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
748749
val tpe = readTpt()(localCtx).tpe
749-
if (isInline) unsupportedWhen(!isConstantType(tpe), s"inline val ${sym.nameString} with non-constant type $tpe")
750+
val isConstant = isConstantType(tpe)
751+
if (isInline) unsupportedWhen(!isConstant, s"inline val ${sym.nameString} with non-constant type $tpe")
750752
ctx.setInfo(sym,
751753
if (completer.tastyFlagSet.is(Enum)) defn.ConstantType(tpd.Constant((sym, tpe))).tap(_.typeSymbol.set(Final))
754+
else if (isInline && isConstant) defn.InlineExprType(tpe)
752755
else if (sym.isMethod) defn.ExprType(tpe)
753756
else tpe
754757
)
755758
case TYPEDEF | TYPEPARAM =>
756-
val unsupported = completer.tastyFlagSet &~ (Enum | Open | Opaque | Exported)
759+
val unsupported = completer.tastyFlagSet &~ (Enum | Open | Opaque | Exported | SuperTrait)
757760
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
758761
if (sym.isClass) {
759762
sym.owner.ensureCompleted()
@@ -777,7 +780,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
777780
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
778781
else defn.ExprType(tpt.tpe))
779782
}
780-
ctx.log(s"$symAddr typeOf(${showSym(sym)}) =:= ${if (sym.isType) sym.tpe else sym.info}; owned by ${location(sym.owner)}")
783+
ctx.log(s"$symAddr @@@ ${showSym(sym)}.tpe =:= '[${if (sym.isType) sym.tpe else sym.info}]; owned by ${location(sym.owner)}")
781784
goto(end)
782785
NoCycle(at = symAddr)
783786
} catch ctx.onCompletionError(sym)
@@ -800,8 +803,10 @@ class TreeUnpickler[Tasty <: TastyUniverse](
800803
// ** MEMBERS **
801804
ctx.log(s"$symAddr Template: indexing members of $cls:")
802805
val bodyIndexer = fork
806+
val bodyCtx = ctx.addMode(IndexBody)
803807
while (bodyIndexer.reader.nextByte != DEFDEF) bodyIndexer.skipTree() // skip until primary ctor
804-
bodyIndexer.indexStats(end)
808+
bodyIndexer.indexStats(end)(bodyCtx)
809+
bodyCtx.enterLatents()
805810

806811
// ** PARENTS **
807812
ctx.log(s"$symAddr Template: adding parents of $cls:")
@@ -897,10 +902,9 @@ class TreeUnpickler[Tasty <: TastyUniverse](
897902
def completeSelectType(name: TastyName.TypeName)(implicit ctx: Context): Tree = completeSelect(name)
898903

899904
def completeSelect(name: TastyName)(implicit ctx: Context): Tree = {
900-
val localCtx = ctx.selectionCtx(name)
901-
val qual = readTerm()(localCtx)
902-
val qualType = qual.tpe
903-
tpd.Select(qual, name)(namedMemberOfPrefix(qualType, name)(localCtx))
905+
val qual = readTerm()
906+
val qualType = qual.tpe // TODO [tasty]: qual.tpe.widenIfUnstable
907+
tpd.Select(qual, name)(namedMemberOfPrefix(qualType, name))
904908
}
905909

906910
def completeSelectionParent(name: TastyName)(implicit ctx: Context): Tree = {
@@ -931,6 +935,19 @@ class TreeUnpickler[Tasty <: TastyUniverse](
931935
val end = readEnd()
932936
val result =
933937
(tag: @switch) match {
938+
case SELECTin =>
939+
val sname = readTastyName()
940+
val qual = readTerm()
941+
if (inParentCtor) {
942+
assert(sname.isSignedConstructor, s"Parent of ${ctx.owner} is not a constructor.")
943+
skipTree()
944+
qual
945+
}
946+
else {
947+
val owner = readType()
948+
val qualTpe = qual.tpe // qual.tpe.widenIfUnstable
949+
tpd.Select(qual, sname)(namedMemberOfTypeWithPrefix(qualTpe, owner, sname))
950+
}
934951
case SUPER =>
935952
val qual = readTerm()
936953
val (mixId, mixTpe) = ifBefore(end)(readQualId(), (untpd.EmptyTypeIdent, defn.NoType))
@@ -975,7 +992,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
975992
if (alias != untpd.EmptyTree) alias // only for opaque type alias
976993
else tpd.TypeBoundsTree(lo, hi)
977994
case BLOCK =>
978-
if (inParentCtor) {
995+
if (inParentCtor | ctx.mode.is(ReadMacro)) {
979996
val exprReader = fork
980997
skipTree()
981998
until(end)(skipTree()) //val stats = readStats(ctx.owner, end)

src/compiler/scala/tools/nsc/tasty/bridge/ContextOps.scala

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import scala.reflect.io.AbstractFile
1818
import scala.tools.tasty.{TastyName, TastyFlags}, TastyFlags._, TastyName.ObjectName
1919
import scala.tools.nsc.tasty.{TastyUniverse, TastyModes, SafeEq}, TastyModes._
2020
import scala.reflect.internal.MissingRequirementError
21+
import scala.collection.mutable
2122

2223
trait ContextOps { self: TastyUniverse =>
2324
import self.{symbolTable => u}, u.{internal => ui}
@@ -67,6 +68,25 @@ trait ContextOps { self: TastyUniverse =>
6768
final def ignoreAnnotations: Boolean = u.settings.YtastyNoAnnotations
6869
final def verboseDebug: Boolean = u.settings.debug
6970

71+
def isScala3Macro(sym: Symbol): Boolean = isScala3Inline(sym) && sym.is(Macro)
72+
def isScala3Inline(sym: Symbol): Boolean = sym.completer.tastyFlagSet.is(Inline)
73+
def isScala2Macro(sym: Symbol): Boolean = sym.completer.tastyFlagSet.is(Erased) && sym.is(Macro)
74+
75+
def isLatentCandidate(sym: Symbol): Boolean = isScala3Inline(sym) || isScala2Macro(sym)
76+
77+
def canEnter(decl: Symbol): Boolean = !isScala3Macro(decl)
78+
def enter(clazz: Symbol, decl: Symbol): Unit = enter(clazz.rawInfo.decls, decl)
79+
private[ContextOps] def enter(decls: u.Scope, decl: Symbol): Unit = {
80+
if (allowsOverload(decl)) {
81+
if (canEnterOverload(decl)) {
82+
decls.enter(decl)
83+
}
84+
}
85+
else {
86+
decls.enterIfNew(decl)
87+
}
88+
}
89+
7090
def canEnterOverload(decl: Symbol): Boolean = {
7191
!(decl.isModule && isSymbol(findObject(decl.name)))
7292
}
@@ -92,6 +112,9 @@ trait ContextOps { self: TastyUniverse =>
92112
def source: AbstractFile
93113
def mode: TastyMode
94114

115+
def registerLatent(sym: Symbol): Unit
116+
def enterLatents(): Unit
117+
95118
private final def loadingMirror: u.Mirror = u.mirrorThatLoaded(owner)
96119

97120
final def requiredPackage(fullname: TastyName): Symbol = {
@@ -344,7 +367,6 @@ trait ContextOps { self: TastyUniverse =>
344367
final def withNewScope: Context =
345368
fresh(newLocalDummy)
346369

347-
final def selectionCtx(name: TastyName): Context = this // if (name.isConstructorName) this.addMode(Mode.InSuperCall) else this
348370
final def fresh(owner: Symbol): FreshContext = new FreshContext(owner, this, this.mode)
349371

350372
private def sibling(mode: TastyMode): FreshContext = new FreshContext(this.owner, outerOrThis, mode)
@@ -391,11 +413,46 @@ trait ContextOps { self: TastyUniverse =>
391413
final class InitialContext(val topLevelClass: Symbol, val source: AbstractFile) extends Context {
392414
def mode: TastyMode = EmptyTastyMode
393415
def owner: Symbol = topLevelClass.owner
416+
def registerLatent(sym: Symbol): Unit = ()
417+
def enterLatents(): Unit = ()
394418
}
395419

396420
final class FreshContext(val owner: Symbol, val outer: Context, val mode: TastyMode) extends Context {
397421
private[this] var mySource: AbstractFile = null
422+
private[this] var myLatentDefs: mutable.ArrayBuffer[Symbol] = null
423+
private[this] var myMacros: mutable.ArrayBuffer[Symbol] = null
398424
def atSource(source: AbstractFile): this.type = { mySource = source ; this }
399425
def source: AbstractFile = if (mySource == null) outer.source else mySource
426+
def registerLatent(sym: Symbol): Unit = {
427+
if (isScala2Macro(sym)) {
428+
val macros = {
429+
if (myMacros == null) myMacros = mutable.ArrayBuffer.empty
430+
myMacros
431+
}
432+
macros += sym
433+
} else {
434+
val defs = {
435+
if (myLatentDefs == null) myLatentDefs = mutable.ArrayBuffer.empty
436+
myLatentDefs
437+
}
438+
defs += sym
439+
}
440+
}
441+
def enterLatents(): Unit = {
442+
for {
443+
owner <- Option.when(owner.isClass)(owner)
444+
defs <- Option(myLatentDefs)
445+
} {
446+
val macros = Option(myMacros).getOrElse(mutable.ArrayBuffer.empty)
447+
val decls = owner.rawInfo.decls
448+
for (d <- defs if !macros.exists(_.name == d.name)) {
449+
enter(decls, d)
450+
}
451+
defs.clear()
452+
macros.clear()
453+
}
454+
myLatentDefs = null
455+
myMacros = null
456+
}
400457
}
401458
}

src/compiler/scala/tools/nsc/tasty/bridge/FlagOps.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ trait FlagOps { self: TastyUniverse =>
2121

2222
object FlagSets {
2323
val TastyOnlyFlags: TastyFlagSet = (
24-
Erased | Internal | Inline | InlineProxy | Opaque | Extension | Given | Exported | Macro | Enum | Open
25-
| ParamAlias
24+
Erased | Internal | Inline | InlineProxy | Opaque | Extension | Given | Exported | SuperTrait | Enum
25+
| Open | ParamAlias
2626
)
2727
val TermParamOrAccessor: TastyFlagSet = Param | ParamSetter
2828
val ObjectCreationFlags: TastyFlagSet = Object | Lazy | Final | Stable
@@ -42,6 +42,7 @@ trait FlagOps { self: TastyUniverse =>
4242
if (tflags.is(Case)) flags |= Flag.CASE
4343
if (tflags.is(Implicit)) flags |= ModifierFlags.IMPLICIT
4444
if (tflags.is(Lazy)) flags |= Flag.LAZY
45+
if (tflags.is(Macro)) flags |= Flag.MACRO
4546
if (tflags.is(Override)) flags |= Flag.OVERRIDE
4647
if (tflags.is(Static)) flags |= ModifierFlags.STATIC
4748
if (tflags.is(Object)) flags |= Flags.MODULE
@@ -76,7 +77,7 @@ trait FlagOps { self: TastyUniverse =>
7677
case Extension => "<extension>"
7778
case Given => "given"
7879
case Exported => "<exported>"
79-
case Macro => "<tastymacro>"
80+
case SuperTrait => "<supertrait>"
8081
case Enum => "enum"
8182
case Open => "open"
8283
case ParamAlias => "<paramalias>"

src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ trait SymbolOps { self: TastyUniverse =>
9494
}
9595

9696
private def hasType(member: Symbol)(implicit ctx: Context) = {
97-
ctx.mode.is(ReadAnnotation) || (member.rawInfo `ne` u.NoType)
97+
ctx.mode.is(ReadAnnotation) || ctx.mode.is(ReadMacro) && (member.info `ne` u.NoType) || (member.rawInfo `ne` u.NoType)
9898
}
9999

100100
private def errorMissing[T](space: Type, tname: TastyName)(implicit ctx: Context) = {
@@ -121,7 +121,7 @@ trait SymbolOps { self: TastyUniverse =>
121121
}
122122

123123
private def signedMemberOfSpace(space: Type, qual: TastyName, sig: MethodSignature[ErasedTypeRef])(implicit ctx: Context): Symbol = {
124-
ctx.log(s"""<<< looking for overload member[$space] @@ $qual: ${showSig(sig)}""")
124+
ctx.log(s"""<<< looking for overload in symbolOf[$space] @@ $qual: ${showSig(sig)}""")
125125
val member = space.member(encodeTermName(qual))
126126
if (!(isSymbol(member) && hasType(member))) errorMissing(space, qual)
127127
val (tyParamCount, argTpeRefs) = {
@@ -133,9 +133,11 @@ trait SymbolOps { self: TastyUniverse =>
133133
}
134134
def compareSym(sym: Symbol): Boolean = sym match {
135135
case sym: u.MethodSymbol =>
136-
val params = sym.paramss.flatten
136+
val method = sym.tpe.asSeenFrom(space, sym.owner)
137+
ctx.log(s">>> trying $sym: $method")
138+
val params = method.paramss.flatten
137139
val isJava = sym.isJavaDefined
138-
NameErasure.sigName(sym.returnType, isJava) === sig.result &&
140+
NameErasure.sigName(method.finalResultType, isJava) === sig.result &&
139141
params.length === argTpeRefs.length &&
140142
(qual === TastyName.Constructor && tyParamCount === member.owner.typeParams.length
141143
|| tyParamCount === sym.typeParams.length) &&

src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package scala.tools.nsc.tasty.bridge
1515
import scala.tools.nsc.tasty.TastyUniverse
1616

1717
import scala.tools.tasty.TastyName
18+
import scala.reflect.internal.Flags
1819

1920

2021
trait TreeOps { self: TastyUniverse =>
@@ -56,6 +57,28 @@ trait TreeOps { self: TastyUniverse =>
5657
u.TypeTree(defn.LambdaFromParams(tparams, body.tpe))
5758
}
5859

60+
def Macro(impl: Tree): Tree = impl match {
61+
case tree @ u.TypeApply(qual, args) =>
62+
u.TypeApply(Macro(qual), args).setType(tree.tpe)
63+
case tree @ u.Select(pre, sel) =>
64+
val sym = if (sel.isTermName) tree.tpe.termSymbol else tree.tpe.typeSymbol
65+
u.Select(Macro(pre), sym).setType(tree.tpe)
66+
case tree: u.TypeTree if tree.tpe.prefix !== u.NoType =>
67+
val sym = tree.tpe match {
68+
case u.SingleType(_, sym) => sym
69+
case u.TypeRef(_, sym, _) => sym
70+
}
71+
if (tree.tpe.prefix === u.NoPrefix && (sym.hasFlag(Flags.PACKAGE) && !sym.isPackageObjectOrClass || sym.isLocalToBlock)) {
72+
if (sym.isLocalToBlock) u.Ident(sym).setType(tree.tpe)
73+
else u.This(sym).setType(tree.tpe)
74+
}
75+
else {
76+
u.Select(Macro(u.TypeTree(tree.tpe.prefix)), sym).setType(tree.tpe)
77+
}
78+
case tree =>
79+
tree
80+
}
81+
5982
def Typed(expr: Tree, tpt: Tree): Tree = u.Typed(expr, tpt).setType(tpt.tpe)
6083

6184
def Apply(fun: Tree, args: List[Tree]): Tree = u.Apply(fun, args).setType(fnResult(fun.tpe))

0 commit comments

Comments
 (0)