Skip to content

Commit

Permalink
Merge pull request #102 from scalacenter/tasty/upgrade-v23
Browse files Browse the repository at this point in the history
Support TASTy version 23 [Dotty 0.25.0-RC2]
  • Loading branch information
bishabosha authored Jun 17, 2020
2 parents 1e5143e + 0b7ccc5 commit bf20733
Show file tree
Hide file tree
Showing 33 changed files with 434 additions and 41 deletions.
4 changes: 2 additions & 2 deletions project/DottySupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import sbt.librarymanagement.{
* Settings to support validation of TastyUnpickler against the release of dotty with the matching TASTy version
*/
object TastySupport {
val supportedTASTyRelease = "0.24.0-RC1" // TASTy version 22
val dottyCompiler = "ch.epfl.lamp" % "dotty-compiler_0.24" % supportedTASTyRelease
val supportedTASTyRelease = "0.25.0-RC2" // TASTy version 23
val dottyCompiler = "ch.epfl.lamp" % "dotty-compiler_0.25" % supportedTASTyRelease
}

/** Settings needed to compile with Dotty,
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/scala/tools/nsc/tasty/TastyModes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ object TastyModes {
final val ReadParents: TastyMode = TastyMode(1 << 0)
final val ReadAnnotation: TastyMode = TastyMode(1 << 1)
final val OuterTerm: TastyMode = TastyMode(1 << 2)
final val ReadMacro: TastyMode = TastyMode(1 << 3)
final val IndexBody: TastyMode = TastyMode(1 << 4)

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

Expand All @@ -39,6 +41,8 @@ object TastyModes {
if (mode.is(ReadParents)) sb += "ReadParents"
if (mode.is(ReadAnnotation)) sb += "ReadAnnotation"
if (mode.is(OuterTerm)) sb += "OuterTerm"
if (mode.is(ReadMacro)) sb += "ReadMacro"
if (mode.is(IndexBody)) sb += "IndexBody"
sb.mkString("|")
}
}
Expand Down
61 changes: 39 additions & 22 deletions src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ class TreeUnpickler[Tasty <: TastyUniverse](
if (isClass && flags.is(Trait)) flags |= Abstract
if (tag === DEFDEF) flags |= Method
if (tag === VALDEF) {
if (flags.is(Inline) || owner.is(Trait)) flags |= FieldAccessor
if (flags.not(Mutable)) flags |= Stable
if (owner.is(Trait)) flags |= FieldAccessor
}
if (tastyFlags.is(Object))
flags = flags | (if (tag === VALDEF) ObjectCreationFlags else ObjectClassCreationFlags)
Expand Down Expand Up @@ -521,16 +521,11 @@ class TreeUnpickler[Tasty <: TastyUniverse](
sym.setAnnotations(annotFns.map(_(sym)))
ctx.owner match {
case cls if cls.isClass && canEnterInClass =>
if (ctx.mode.is(IndexBody) && ctx.isLatentCandidate(sym))
ctx.registerLatent(sym)
val decl = if (flags.is(Object) && isClass) sym.sourceObject else sym
val decls = cls.rawInfo.decls
if (allowsOverload(decl)) {
if (ctx.canEnterOverload(decl)) {
decls.enter(decl)
}
}
else {
decls.enterIfNew(decl)
}
if (ctx.canEnter(decl))
ctx.enter(cls, decl)
case _ =>
}
registerSym(start, sym)
Expand Down Expand Up @@ -581,6 +576,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
case STATIC => addFlag(Static)
case OBJECT => addFlag(Object)
case TRAIT => addFlag(Trait)
case SUPERTRAIT => addFlag(SuperTrait)
case ENUM => addFlag(Enum)
case LOCAL => addFlag(Local)
case SYNTHETIC => addFlag(Synthetic)
Expand Down Expand Up @@ -721,11 +717,12 @@ class TreeUnpickler[Tasty <: TastyUniverse](
val localCtx = ctx.withOwner(sym)
tag match {
case DEFDEF =>
val unsupported = completer.tastyFlagSet &~ (Extension | Inline | Macro | Exported)
val unsupported = completer.tastyFlagSet &~ (Extension | Inline | Exported | Erased)
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
if (completer.tastyFlagSet.is(Extension)) ctx.log(s"$tname is a Scala 3 extension method.")
unsupportedWhen(completer.tastyFlagSet.is(Inline, butNot = Macro), s"inline $sym")
unsupportedWhen(completer.tastyFlagSet.is(Inline | Macro), s"macro $sym")
unsupportedWhen(completer.tastyFlagSet.is(Inline), s"${if (sym.is(Macro)) "" else "inline "}$sym")
val isMacroDef = completer.tastyFlagSet.is(Erased) && sym.is(Macro)
unsupportedWhen(completer.tastyFlagSet.is(Erased) && !isMacroDef, s"erased $sym")
val isCtor = sym.isClassConstructor
val typeParams = {
if (isCtor) {
Expand All @@ -738,6 +735,10 @@ class TreeUnpickler[Tasty <: TastyUniverse](
}
val vparamss = readParamss(localCtx)
val tpt = readTpt()(localCtx)
if (isMacroDef) {
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
sym.addAnnotation(symbolTable.AnnotationInfo(symbolTable.definitions.MacroTastyImplAnnotation.tpe, List(impl), Nil))
}
val valueParamss = normalizeIfConstructor(vparamss.map(_.map(symFromNoCycle)), isCtor)
val resType = effectiveResultType(sym, typeParams, tpt.tpe)
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
Expand All @@ -746,14 +747,16 @@ class TreeUnpickler[Tasty <: TastyUniverse](
val unsupported = completer.tastyFlagSet &~ (Inline | Enum | Extension | Exported)
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
val tpe = readTpt()(localCtx).tpe
if (isInline) unsupportedWhen(!isConstantType(tpe), s"inline val ${sym.nameString} with non-constant type $tpe")
val isConstant = isConstantType(tpe)
if (isInline) unsupportedWhen(!isConstant, s"inline val ${sym.nameString} with non-constant type $tpe")
ctx.setInfo(sym,
if (completer.tastyFlagSet.is(Enum)) defn.ConstantType(tpd.Constant((sym, tpe))).tap(_.typeSymbol.set(Final))
else if (isInline && isConstant) defn.InlineExprType(tpe)
else if (sym.isMethod) defn.ExprType(tpe)
else tpe
)
case TYPEDEF | TYPEPARAM =>
val unsupported = completer.tastyFlagSet &~ (Enum | Open | Opaque | Exported)
val unsupported = completer.tastyFlagSet &~ (Enum | Open | Opaque | Exported | SuperTrait)
unsupportedWhen(unsupported.hasFlags, s"flags on $sym: ${showTasty(unsupported)}")
if (sym.isClass) {
sym.owner.ensureCompleted()
Expand All @@ -777,7 +780,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
else defn.ExprType(tpt.tpe))
}
ctx.log(s"$symAddr typeOf(${showSym(sym)}) =:= ${if (sym.isType) sym.tpe else sym.info}; owned by ${location(sym.owner)}")
ctx.log(s"$symAddr @@@ ${showSym(sym)}.tpe =:= '[${if (sym.isType) sym.tpe else sym.info}]; owned by ${location(sym.owner)}")
goto(end)
NoCycle(at = symAddr)
} catch ctx.onCompletionError(sym)
Expand All @@ -800,8 +803,10 @@ class TreeUnpickler[Tasty <: TastyUniverse](
// ** MEMBERS **
ctx.log(s"$symAddr Template: indexing members of $cls:")
val bodyIndexer = fork
val bodyCtx = ctx.addMode(IndexBody)
while (bodyIndexer.reader.nextByte != DEFDEF) bodyIndexer.skipTree() // skip until primary ctor
bodyIndexer.indexStats(end)
bodyIndexer.indexStats(end)(bodyCtx)
bodyCtx.enterLatents()

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

def completeSelect(name: TastyName)(implicit ctx: Context): Tree = {
val localCtx = ctx.selectionCtx(name)
val qual = readTerm()(localCtx)
val qualType = qual.tpe
tpd.Select(qual, name)(namedMemberOfPrefix(qualType, name)(localCtx))
val qual = readTerm()
val qualType = qual.tpe // TODO [tasty]: qual.tpe.widenIfUnstable
tpd.Select(qual, name)(namedMemberOfPrefix(qualType, name))
}

def completeSelectionParent(name: TastyName)(implicit ctx: Context): Tree = {
Expand Down Expand Up @@ -931,6 +935,19 @@ class TreeUnpickler[Tasty <: TastyUniverse](
val end = readEnd()
val result =
(tag: @switch) match {
case SELECTin =>
val sname = readTastyName()
val qual = readTerm()
if (inParentCtor) {
assert(sname.isSignedConstructor, s"Parent of ${ctx.owner} is not a constructor.")
skipTree()
qual
}
else {
val owner = readType()
val qualTpe = qual.tpe // qual.tpe.widenIfUnstable
tpd.Select(qual, sname)(namedMemberOfTypeWithPrefix(qualTpe, owner, sname))
}
case SUPER =>
val qual = readTerm()
val (mixId, mixTpe) = ifBefore(end)(readQualId(), (untpd.EmptyTypeIdent, defn.NoType))
Expand Down Expand Up @@ -975,7 +992,7 @@ class TreeUnpickler[Tasty <: TastyUniverse](
if (alias != untpd.EmptyTree) alias // only for opaque type alias
else tpd.TypeBoundsTree(lo, hi)
case BLOCK =>
if (inParentCtor) {
if (inParentCtor | ctx.mode.is(ReadMacro)) {
val exprReader = fork
skipTree()
until(end)(skipTree()) //val stats = readStats(ctx.owner, end)
Expand Down
59 changes: 58 additions & 1 deletion src/compiler/scala/tools/nsc/tasty/bridge/ContextOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import scala.reflect.io.AbstractFile
import scala.tools.tasty.{TastyName, TastyFlags}, TastyFlags._, TastyName.ObjectName
import scala.tools.nsc.tasty.{TastyUniverse, TastyModes, SafeEq}, TastyModes._
import scala.reflect.internal.MissingRequirementError
import scala.collection.mutable

trait ContextOps { self: TastyUniverse =>
import self.{symbolTable => u}, u.{internal => ui}
Expand Down Expand Up @@ -67,6 +68,25 @@ trait ContextOps { self: TastyUniverse =>
final def ignoreAnnotations: Boolean = u.settings.YtastyNoAnnotations
final def verboseDebug: Boolean = u.settings.debug

def isScala3Macro(sym: Symbol): Boolean = isScala3Inline(sym) && sym.is(Macro)
def isScala3Inline(sym: Symbol): Boolean = sym.completer.tastyFlagSet.is(Inline)
def isScala2Macro(sym: Symbol): Boolean = sym.completer.tastyFlagSet.is(Erased) && sym.is(Macro)

def isLatentCandidate(sym: Symbol): Boolean = isScala3Inline(sym) || isScala2Macro(sym)

def canEnter(decl: Symbol): Boolean = !isScala3Macro(decl)
def enter(clazz: Symbol, decl: Symbol): Unit = enter(clazz.rawInfo.decls, decl)
private[ContextOps] def enter(decls: u.Scope, decl: Symbol): Unit = {
if (allowsOverload(decl)) {
if (canEnterOverload(decl)) {
decls.enter(decl)
}
}
else {
decls.enterIfNew(decl)
}
}

def canEnterOverload(decl: Symbol): Boolean = {
!(decl.isModule && isSymbol(findObject(decl.name)))
}
Expand All @@ -92,6 +112,9 @@ trait ContextOps { self: TastyUniverse =>
def source: AbstractFile
def mode: TastyMode

def registerLatent(sym: Symbol): Unit
def enterLatents(): Unit

private final def loadingMirror: u.Mirror = u.mirrorThatLoaded(owner)

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

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

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

final class FreshContext(val owner: Symbol, val outer: Context, val mode: TastyMode) extends Context {
private[this] var mySource: AbstractFile = null
private[this] var myLatentDefs: mutable.ArrayBuffer[Symbol] = null
private[this] var myMacros: mutable.ArrayBuffer[Symbol] = null
def atSource(source: AbstractFile): this.type = { mySource = source ; this }
def source: AbstractFile = if (mySource == null) outer.source else mySource
def registerLatent(sym: Symbol): Unit = {
if (isScala2Macro(sym)) {
val macros = {
if (myMacros == null) myMacros = mutable.ArrayBuffer.empty
myMacros
}
macros += sym
} else {
val defs = {
if (myLatentDefs == null) myLatentDefs = mutable.ArrayBuffer.empty
myLatentDefs
}
defs += sym
}
}
def enterLatents(): Unit = {
for {
owner <- Option.when(owner.isClass)(owner)
defs <- Option(myLatentDefs)
} {
val macros = Option(myMacros).getOrElse(mutable.ArrayBuffer.empty)
val decls = owner.rawInfo.decls
for (d <- defs if !macros.exists(_.name == d.name)) {
enter(decls, d)
}
defs.clear()
macros.clear()
}
myLatentDefs = null
myMacros = null
}
}
}
7 changes: 4 additions & 3 deletions src/compiler/scala/tools/nsc/tasty/bridge/FlagOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ trait FlagOps { self: TastyUniverse =>

object FlagSets {
val TastyOnlyFlags: TastyFlagSet = (
Erased | Internal | Inline | InlineProxy | Opaque | Extension | Given | Exported | Macro | Enum | Open
| ParamAlias
Erased | Internal | Inline | InlineProxy | Opaque | Extension | Given | Exported | SuperTrait | Enum
| Open | ParamAlias
)
val TermParamOrAccessor: TastyFlagSet = Param | ParamSetter
val ObjectCreationFlags: TastyFlagSet = Object | Lazy | Final | Stable
Expand All @@ -42,6 +42,7 @@ trait FlagOps { self: TastyUniverse =>
if (tflags.is(Case)) flags |= Flag.CASE
if (tflags.is(Implicit)) flags |= ModifierFlags.IMPLICIT
if (tflags.is(Lazy)) flags |= Flag.LAZY
if (tflags.is(Macro)) flags |= Flag.MACRO
if (tflags.is(Override)) flags |= Flag.OVERRIDE
if (tflags.is(Static)) flags |= ModifierFlags.STATIC
if (tflags.is(Object)) flags |= Flags.MODULE
Expand Down Expand Up @@ -76,7 +77,7 @@ trait FlagOps { self: TastyUniverse =>
case Extension => "<extension>"
case Given => "given"
case Exported => "<exported>"
case Macro => "<tastymacro>"
case SuperTrait => "<supertrait>"
case Enum => "enum"
case Open => "open"
case ParamAlias => "<paramalias>"
Expand Down
10 changes: 6 additions & 4 deletions src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ trait SymbolOps { self: TastyUniverse =>
}

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

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

private def signedMemberOfSpace(space: Type, qual: TastyName, sig: MethodSignature[ErasedTypeRef])(implicit ctx: Context): Symbol = {
ctx.log(s"""<<< looking for overload member[$space] @@ $qual: ${showSig(sig)}""")
ctx.log(s"""<<< looking for overload in symbolOf[$space] @@ $qual: ${showSig(sig)}""")
val member = space.member(encodeTermName(qual))
if (!(isSymbol(member) && hasType(member))) errorMissing(space, qual)
val (tyParamCount, argTpeRefs) = {
Expand All @@ -133,9 +133,11 @@ trait SymbolOps { self: TastyUniverse =>
}
def compareSym(sym: Symbol): Boolean = sym match {
case sym: u.MethodSymbol =>
val params = sym.paramss.flatten
val method = sym.tpe.asSeenFrom(space, sym.owner)
ctx.log(s">>> trying $sym: $method")
val params = method.paramss.flatten
val isJava = sym.isJavaDefined
NameErasure.sigName(sym.returnType, isJava) === sig.result &&
NameErasure.sigName(method.finalResultType, isJava) === sig.result &&
params.length === argTpeRefs.length &&
(qual === TastyName.Constructor && tyParamCount === member.owner.typeParams.length
|| tyParamCount === sym.typeParams.length) &&
Expand Down
23 changes: 23 additions & 0 deletions src/compiler/scala/tools/nsc/tasty/bridge/TreeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package scala.tools.nsc.tasty.bridge
import scala.tools.nsc.tasty.TastyUniverse

import scala.tools.tasty.TastyName
import scala.reflect.internal.Flags


trait TreeOps { self: TastyUniverse =>
Expand Down Expand Up @@ -56,6 +57,28 @@ trait TreeOps { self: TastyUniverse =>
u.TypeTree(defn.LambdaFromParams(tparams, body.tpe))
}

def Macro(impl: Tree): Tree = impl match {
case tree @ u.TypeApply(qual, args) =>
u.TypeApply(Macro(qual), args).setType(tree.tpe)
case tree @ u.Select(pre, sel) =>
val sym = if (sel.isTermName) tree.tpe.termSymbol else tree.tpe.typeSymbol
u.Select(Macro(pre), sym).setType(tree.tpe)
case tree: u.TypeTree if tree.tpe.prefix !== u.NoType =>
val sym = tree.tpe match {
case u.SingleType(_, sym) => sym
case u.TypeRef(_, sym, _) => sym
}
if (tree.tpe.prefix === u.NoPrefix && (sym.hasFlag(Flags.PACKAGE) && !sym.isPackageObjectOrClass || sym.isLocalToBlock)) {
if (sym.isLocalToBlock) u.Ident(sym).setType(tree.tpe)
else u.This(sym).setType(tree.tpe)
}
else {
u.Select(Macro(u.TypeTree(tree.tpe.prefix)), sym).setType(tree.tpe)
}
case tree =>
tree
}

def Typed(expr: Tree, tpt: Tree): Tree = u.Typed(expr, tpt).setType(tpt.tpe)

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

0 comments on commit bf20733

Please sign in to comment.