Skip to content

Commit

Permalink
Merge pull request #9501 from scalacenter/tasty/support-3.0.0-RC1
Browse files Browse the repository at this point in the history
  • Loading branch information
SethTisue committed Feb 16, 2021
2 parents bda0115 + 78e5e05 commit 5919594
Show file tree
Hide file tree
Showing 14 changed files with 474 additions and 188 deletions.
4 changes: 2 additions & 2 deletions project/DottySupport.scala
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 = "3.0.0-M3" // TASTy version 26.1
val scala3Compiler = "org.scala-lang" % "scala3-compiler_3.0.0-M3" % supportedTASTyRelease
val supportedTASTyRelease = "3.0.0-RC1" // TASTy version 28.0.1
val scala3Compiler = "org.scala-lang" % "scala3-compiler_3.0.0-RC1" % supportedTASTyRelease
}

/** Settings needed to compile with Dotty,
Expand Down
231 changes: 131 additions & 100 deletions src/compiler/scala/tools/nsc/tasty/TreeUnpickler.scala
Expand Up @@ -123,12 +123,9 @@ class TreeUnpickler[Tasty <: TastyUniverse](
def skipParams(): Unit =
while ({
val tag = nextByte
tag == PARAM || tag == TYPEPARAM || tag == PARAMEND
tag == PARAM || tag == TYPEPARAM || tag == EMPTYCLAUSE || tag == SPLITCLAUSE
}) skipTree()

def skipTypeParams(): Unit =
while (nextByte === TYPEPARAM) skipTree()

/** Record all directly nested definitions and templates in current tree
* as `OwnerTree`s in `buf`.
* A complication concerns member definitions. These are lexically nested in a
Expand Down Expand Up @@ -689,118 +686,152 @@ class TreeUnpickler[Tasty <: TastyUniverse](
case _ =>
val start = currentAddr
cycleAtAddr(start) = Tombstone
val noCycle = readNewMember()
val noCycle = initializeMember()
cycleAtAddr.remove(start)
noCycle
}

private def readNewMember()(implicit ctx: Context): NoCycle = {
val symAddr = currentAddr
val tag = readByte()
val end = readEnd()
val tname = readTastyName()
val sym = symAtAddr(symAddr)
val repr = sym.repr
private def initializeMember()(implicit ctx: Context): NoCycle = {
val symAddr = currentAddr
val tag = readByte()
val end = readEnd()
val tname = readTastyName()
val sym = symAtAddr(symAddr)

def readParamss()(implicit ctx: Context): List[List[NoCycle]] = {
def readRest() = {
if (nextByte == SPLITCLAUSE) readByte()
readParamss()
}
nextByte match {
case PARAM => readParams[NoCycle](PARAM) :: readRest()
case TYPEPARAM => readParams[NoCycle](TYPEPARAM) :: readRest()
case EMPTYCLAUSE => readByte(); Nil :: readRest()
case _ => Nil
}
}

ctx.log(s"$symAddr completing ${showSym(sym)} in scope ${showSym(ctx.owner)}")
def checkUnsupportedFlags(unsupported: TastyFlagSet)(implicit ctx: Context): Unit = {
unsupportedWhen(unsupported.hasFlags, s"${showTasty(unsupported)} ${sym.kindString} $tname")
}

def readParamss(implicit ctx: Context): List[List[NoCycle/*ValDef*/]] = nextByte match {
case PARAM | PARAMEND =>
readParams[NoCycle](PARAM) ::
(if (nextByte == PARAMEND) { readByte(); readParamss } else Nil)
def DefDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
val isMacro = repr.originalFlagSet.is(Erased | Macro)
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Extension | Exported | Infix | optFlag(isMacro)(Erased)))
val isCtor = sym.isConstructor
val paramDefss = readParamss()(localCtx).map(_.map(symFromNoCycle))
val typeParams = {
// A type parameter list must be non-empty and with type symbols
val first = paramDefss.take(1)
if (first.exists(_.exists(_.isType))) first.head else Nil
}
val vparamss = {
// A value parameter list may be empty, or filled with term symbols
val valueClauses = paramDefss.drop(if (typeParams.isEmpty) 0 else 1)
val hasTypeParams = valueClauses.exists(_.exists(_.isType))
unsupportedWhen(hasTypeParams, {
val noun = (
if (isCtor) "constructor"
else if (repr.tastyOnlyFlags.is(Extension)) "extension method"
else "method"
)
s"$noun with unmergeable type parameters: $tname"
})
valueClauses
}
val tpt = readTpt()(localCtx)
if (isMacro) {
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
val annot = symbolTable.AnnotationInfo(
atp = symbolTable.definitions.MacroImplLocationAnnotation.tpe,
args = List(impl),
assocs = Nil
)
sym.addAnnotation(annot)
}
val valueParamss = normalizeIfConstructor(vparamss, isCtor)
val resType = effectiveResultType(sym, typeParams, tpt.tpe)
ctx.setInfo(sym, defn.DefDefType(if (isCtor) Nil else typeParams, valueParamss, resType))
}

case _ => Nil
def ValDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
// valdef in TASTy is either a singleton object or a method forwarder to a local value.
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Enum | Extension | Exported))
val tpe = readTpt()(localCtx).tpe
ctx.setInfo(sym,
if (repr.originalFlagSet.is(SingletonEnumFlags)) {
val enumClass = sym.objectImplementation
val selfTpe = defn.SingleType(sym.owner.thisPrefix, sym)
val ctor = ctx.unsafeNewSymbol(
owner = enumClass,
name = TastyName.Constructor,
flags = Method,
info = defn.DefDefType(Nil, Nil :: Nil, selfTpe)
)
enumClass.typeOfThis = selfTpe
ctx.setInfo(enumClass, defn.ClassInfoType(intersectionParts(tpe), ctor :: Nil, enumClass))
prefixedRef(sym.owner.thisPrefix, enumClass)
}
else if (sym.isFinal && isConstantType(tpe)) defn.InlineExprType(tpe)
else if (sym.isMethod) defn.ExprType(tpe)
else tpe
)
}

def checkUnsupportedFlags(unsupported: TastyFlagSet)(implicit ctx: Context): Unit = {
unsupportedWhen(unsupported.hasFlags, s"${showTasty(unsupported)} ${sym.kindString} $tname")
def TypeDef(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
val allowedShared = Enum | Opaque | Infix
val allowedTypeFlags = allowedShared | Exported
val allowedClassFlags = allowedShared | Open | Transparent
if (sym.isClass) {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedClassFlags)
sym.owner.ensureCompleted()
readTemplate()(localCtx)
}
else {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedTypeFlags)
val rhs = readTpt()(if (repr.originalFlagSet.is(Opaque)) localCtx.addMode(OpaqueTypeDef) else localCtx)
val info =
if (repr.originalFlagSet.is(Opaque)) {
val (info, alias) = defn.OpaqueTypeToBounds(rhs.tpe)
ctx.markAsOpaqueType(sym, alias)
info
}
else rhs.tpe
ctx.setInfo(sym, defn.NormalisedBounds(info, sym))
if (sym.is(Param)) sym.reset(Private | Protected)
}
}

try {
def TermParam(repr: TastyRepr, localCtx: Context)(implicit ctx: Context): Unit = {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (ParamAlias | Exported))
val tpt = readTpt()(localCtx)
ctx.setInfo(sym,
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
else defn.ExprType(tpt.tpe))
}

def initialize()(implicit ctx: Context): Unit = {
val repr = sym.rawInfo match {
case repr: TastyRepr => repr
case _ => return () // nothing to do here (assume correctly initalised)
}
ctx.log(s"$symAddr completing ${showSym(sym)} in scope ${showSym(ctx.owner)}")
val localCtx = ctx.withOwner(sym)
tag match {
case DEFDEF =>
val isMacro = repr.originalFlagSet.is(Erased | Macro)
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Extension | Exported | Infix | optFlag(isMacro)(Erased)))
val isCtor = sym.isConstructor
val typeParams = {
if (isCtor) {
skipTypeParams()
sym.owner.typeParams
}
else {
readParams[NoCycle](TYPEPARAM)(localCtx).map(symFromNoCycle)
}
}
val vparamss = readParamss(localCtx)
val tpt = readTpt()(localCtx)
if (isMacro) {
val impl = tpd.Macro(readTerm()(ctx.addMode(ReadMacro)))
val annot = symbolTable.AnnotationInfo(
atp = symbolTable.definitions.MacroImplLocationAnnotation.tpe,
args = List(impl),
assocs = Nil
)
sym.addAnnotation(annot)
}
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))
case VALDEF => // valdef in TASTy is either a singleton object or a method forwarder to a local value.
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (Enum | Extension | Exported))
val tpe = readTpt()(localCtx).tpe
ctx.setInfo(sym,
if (repr.originalFlagSet.is(SingletonEnumFlags)) {
val enumClass = sym.objectImplementation
val selfTpe = defn.SingleType(sym.owner.thisPrefix, sym)
val ctor = ctx.unsafeNewSymbol(
owner = enumClass,
name = TastyName.Constructor,
flags = Method,
info = defn.DefDefType(Nil, Nil :: Nil, selfTpe)
)
enumClass.typeOfThis = selfTpe
ctx.setInfo(enumClass, defn.ClassInfoType(intersectionParts(tpe), ctor :: Nil, enumClass))
prefixedRef(sym.owner.thisPrefix, enumClass)
}
else if (sym.isFinal && isConstantType(tpe)) defn.InlineExprType(tpe)
else if (sym.isMethod) defn.ExprType(tpe)
else tpe
)
case TYPEDEF | TYPEPARAM =>
val allowedShared = Enum | Opaque | Infix
val allowedTypeFlags = allowedShared | Exported
val allowedClassFlags = allowedShared | Open | Transparent
if (sym.isClass) {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedClassFlags)
sym.owner.ensureCompleted()
readTemplate()(localCtx)
}
else {
checkUnsupportedFlags(repr.tastyOnlyFlags &~ allowedTypeFlags)
val rhs = readTpt()(if (repr.originalFlagSet.is(Opaque)) localCtx.addMode(OpaqueTypeDef) else localCtx)
val info =
if (repr.originalFlagSet.is(Opaque)) {
val (info, alias) = defn.OpaqueTypeToBounds(rhs.tpe)
ctx.markAsOpaqueType(sym, alias)
info
}
else rhs.tpe
ctx.setInfo(sym, defn.NormalisedBounds(info, sym))
if (sym.is(Param)) sym.reset(Private | Protected)
// sym.resetFlag(Provisional)
}
case PARAM =>
checkUnsupportedFlags(repr.tastyOnlyFlags &~ (ParamAlias | Exported))
val tpt = readTpt()(localCtx)
ctx.setInfo(sym,
if (nothingButMods(end) && sym.not(ParamSetter)) tpt.tpe
else defn.ExprType(tpt.tpe))
case DEFDEF => DefDef(repr, localCtx)
case VALDEF => ValDef(repr, localCtx)
case TYPEDEF | TYPEPARAM => TypeDef(repr, localCtx)
case PARAM => TermParam(repr, localCtx)
}
}

try {
initialize()
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)
}
catch ctx.onCompletionError(sym)
finally goto(end)
}

private def readTemplate()(implicit ctx: Context): Unit = {
Expand Down
9 changes: 7 additions & 2 deletions src/compiler/scala/tools/nsc/tasty/bridge/SymbolOps.scala
Expand Up @@ -64,8 +64,13 @@ trait SymbolOps { self: TastyUniverse =>
* @todo adapt callsites and type so that this property is more safe to call (barring mutation from uncontrolled code)
*/
def repr: TastyRepr = {
require(sym.rawInfo.isInstanceOf[TastyRepr], s"Expected ${u.typeOf[TastyRepr]}, is ${u.showRaw(sym.rawInfo)} ")
sym.rawInfo.asInstanceOf[TastyRepr]
try sym.rawInfo.asInstanceOf[TastyRepr]
catch {
case err: ClassCastException =>
val raw = u.showRaw(sym.rawInfo)
val tastyRepr = u.typeOf[TastyRepr]
throw new AssertionError(s"$sym is already completed. Expected $tastyRepr, is $raw.")
}
}

def ensureCompleted(): Unit = {
Expand Down

0 comments on commit 5919594

Please sign in to comment.