Skip to content

Remove variants of METHODtype tasty tag #8624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 29, 2020
Merged
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
7 changes: 3 additions & 4 deletions compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,10 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
printName(); printTree(); printTrees()
case RETURN | HOLE =>
printNat(); printTrees()
case METHODtype | ERASEDMETHODtype |
GIVENMETHODtype | ERASEDGIVENMETHODtype | IMPLICITMETHODtype |
POLYtype | TYPELAMBDAtype =>
case METHODtype | POLYtype | TYPELAMBDAtype =>
printTree()
until(end) { printName(); printTree() }
while (currentAddr.index < end.index && !isModifierTag(nextByte)) { printTree(); printName(); }
printTrees()
case PARAMtype =>
printNat(); printNat()
case _ =>
Expand Down
19 changes: 10 additions & 9 deletions compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ class TreePickler(pickler: TastyPickler) {
writeByte(BYNAMEtype)
pickleType(tpe.underlying)
case tpe: HKTypeLambda =>
pickleMethodic(TYPELAMBDAtype, tpe)
pickleMethodic(TYPELAMBDAtype, tpe, EmptyFlags)
case tpe: MatchType =>
writeByte(MATCHtype)
withLength {
Expand All @@ -268,26 +268,27 @@ class TreePickler(pickler: TastyPickler) {
tpe.cases.foreach(pickleType(_))
}
case tpe: PolyType if richTypes =>
pickleMethodic(POLYtype, tpe)
pickleMethodic(POLYtype, tpe, EmptyFlags)
case tpe: MethodType if richTypes =>
val tag = methodTypeTag(
isContextual = tpe.isContextualMethod,
isImplicit = tpe.isImplicitMethod && !tpe.isContextualMethod,
isErased = tpe.isErasedMethod)
pickleMethodic(tag, tpe)
var mods = EmptyFlags
if tpe.isContextualMethod then mods |= Given
else if tpe.isImplicitMethod then mods |= Implicit
if tpe.isErasedMethod then mods |= Erased
pickleMethodic(METHODtype, tpe, mods)
case tpe: ParamRef =>
assert(pickleParamRef(tpe), s"orphan parameter reference: $tpe")
case tpe: LazyRef =>
pickleType(tpe.ref)
}

def pickleMethodic(tag: Int, tpe: LambdaType)(implicit ctx: Context): Unit = {
def pickleMethodic(tag: Int, tpe: LambdaType, mods: FlagSet)(implicit ctx: Context): Unit = {
writeByte(tag)
withLength {
pickleType(tpe.resultType, richTypes = true)
tpe.paramNames.lazyZip(tpe.paramInfos).foreach { (name, tpe) =>
pickleName(name); pickleType(tpe)
pickleType(tpe); pickleName(name)
}
if (mods != EmptyFlags) pickleFlags(mods, tpe.isTermLambda)
}
}

Expand Down
63 changes: 37 additions & 26 deletions compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,30 @@ class TreeUnpickler(reader: TastyReader,

// ------ Reading types -----------------------------------------------------

/** Read names in an interleaved sequence of (parameter) names and types/bounds */
def readParamNames(end: Addr): List[Name] =
until(end) {
val name = readName()
skipTree()
name
}

/** Read types or bounds in an interleaved sequence of (parameter) names and types/bounds */
def readParamTypes[T <: Type](end: Addr)(implicit ctx: Context): List[T] =
until(end) { readNat(); readType().asInstanceOf[T] }
/** Read names in an interleaved sequence of types/bounds and (parameter) names,
* possibly followed by a sequence of modifiers.
*/
def readParamNamesAndMods(end: Addr): (List[Name], FlagSet) =
val names =
collectWhile(currentAddr != end && !isModifierTag(nextByte)) {
skipTree()
readName()
}
var mods = EmptyFlags
while currentAddr != end do // avoid boxing the mods
readByte() match
case IMPLICIT => mods |= Implicit
case ERASED => mods |= Erased
case GIVEN => mods |= Given
(names, mods)

/** Read `n` parameter types or bounds which are interleaved with names */
def readParamTypes[T <: Type](n: Int)(implicit ctx: Context): List[T] =
if n == 0 then Nil
else
val t = readType().asInstanceOf[T]
readNat() // skip name
t :: readParamTypes(n - 1)

/** Read reference to definition and return symbol created at that definition */
def readSymRef()(implicit ctx: Context): Symbol = symbolAt(readAddr())
Expand Down Expand Up @@ -290,14 +303,14 @@ class TreeUnpickler(reader: TastyReader,
val end = readEnd()

def readMethodic[N <: Name, PInfo <: Type, LT <: LambdaType]
(companion: LambdaTypeCompanion[N, PInfo, LT], nameMap: Name => N): LT = {
(companionOp: FlagSet => LambdaTypeCompanion[N, PInfo, LT], nameMap: Name => N): LT = {
val result = typeAtAddr.getOrElse(start, {
val nameReader = fork
nameReader.skipTree() // skip result
val paramReader = nameReader.fork
val paramNames = nameReader.readParamNames(end).map(nameMap)
companion(paramNames)(
pt => registeringType(pt, paramReader.readParamTypes[PInfo](end)),
val (paramNames, mods) = nameReader.readParamNamesAndMods(end)
companionOp(mods)(paramNames.map(nameMap))(
pt => registeringType(pt, paramReader.readParamTypes[PInfo](paramNames.length)),
Copy link
Member Author

Choose a reason for hiding this comment

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

I was potentially concerned about traversing the paramNames to get a length versus comparing to an end address, but I guess it is insignificant compared to the logic to traverse types

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, indeed. Generally, we assume that length is free since most lists are small.

pt => readType())
})
goto(end)
Expand Down Expand Up @@ -361,19 +374,17 @@ class TreeUnpickler(reader: TastyReader,
case MATCHtype =>
MatchType(readType(), readType(), until(end)(readType()))
case POLYtype =>
readMethodic(PolyType, _.toTypeName)
readMethodic(_ => PolyType, _.toTypeName)
case METHODtype =>
readMethodic(MethodType, _.toTermName)
case ERASEDMETHODtype =>
readMethodic(ErasedMethodType, _.toTermName)
case GIVENMETHODtype =>
readMethodic(ContextualMethodType, _.toTermName)
case ERASEDGIVENMETHODtype =>
readMethodic(ErasedContextualMethodType, _.toTermName)
case IMPLICITMETHODtype =>
readMethodic(ImplicitMethodType, _.toTermName)
def methodTypeCompanion(mods: FlagSet): MethodTypeCompanion =
if mods.is(Implicit) then ImplicitMethodType
else if mods.isAllOf(Erased | Given) then ErasedContextualMethodType
else if mods.is(Given) then ContextualMethodType
else if mods.is(Erased) then ErasedMethodType
else MethodType
readMethodic(methodTypeCompanion, _.toTermName)
case TYPELAMBDAtype =>
readMethodic(HKTypeLambda, _.toTypeName)
readMethodic(_ => HKTypeLambda, _.toTypeName)
case PARAMtype =>
readTypeRef() match {
case binder: LambdaType => binder.paramRefs(readNat())
Expand Down
40 changes: 8 additions & 32 deletions tasty/src/dotty/tools/tasty/TastyFormat.scala
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,12 @@ Standard-Section: "ASTs" TopLevelStat*
BIND Length boundName_NameRef bounds_Type -- boundName @ bounds, for type-variables defined in a type pattern
BYNAMEtype underlying_Type -- => underlying
PARAMtype Length binder_ASTRef paramNum_Nat -- A reference to parameter # paramNum in lambda type `binder`
POLYtype Length result_Type NamesTypes -- A polymorphic method type `[NamesTypes]result`, used in refinements
METHODtype Length result_Type NamesTypes -- A method type `(NamesTypes)result`, needed for refinements
ERASEDMETHODtype Length result_Type NamesTypes -- A method type `erased (NamesTypes)result`, needed for refinements
GIVENMETHODtype Length result_Type NamesTypes -- A method type `(using NamesTypes)result`, needed for refinements
ERASEDGIVENMETHODtype Length result_Type NamesTypes -- A method type `(using erased NamesTypes)result`, needed for refinements
IMPLICITMETHODtype Length result_Type NamesTypes -- A method type `(implicit NamesTypes)result`, needed for refinements
// TODO: remove ERASEDIMPLICITMETHODtype
TYPELAMBDAtype Length result_Type NamesTypes -- A type lambda `[NamesTypes] => result`
POLYtype Length result_Type TypesNames -- A polymorphic method type `[TypesNames]result`, used in refinements
METHODtype Length result_Type TypesNames Modifier* -- A method type `(Modifier* TypesNames)result`, needed for refinements, with optional modifiers for the parameters
TYPELAMBDAtype Length result_Type TypesNames -- A type lambda `[TypesNames] => result`
SHAREDtype type_ASTRef -- link to previously serialized type
NamesTypes = NameType*
NameType = paramName_NameRef typeOrBounds_ASTRef -- `termName : type` or `typeName bounds`
TypesNames = TypeName*
TypeName = typeOrBounds_ASTRef paramName_NameRef -- (`termName`: `type`) or (`typeName` `bounds`)

Modifier = PRIVATE -- private
INTERNAL -- package private (not yet used)
Expand Down Expand Up @@ -254,7 +249,7 @@ Standard Section: "Comments" Comment*
object TastyFormat {

final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F)
val MajorVersion: Int = 20
val MajorVersion: Int = 21
val MinorVersion: Int = 0

/** Tags used to serialize names, should update [[nameTagToString]] if a new constant is added */
Expand Down Expand Up @@ -305,6 +300,7 @@ object TastyFormat {
case DEFAULTGETTER => "DEFAULTGETTER"
case SUPERACCESSOR => "SUPERACCESSOR"
case INLINEACCESSOR => "INLINEACCESSOR"
case BODYRETAINER => "BODYRETAINER"
case OBJECTCLASS => "OBJECTCLASS"
case SIGNED => "SIGNED"
case id => s"NotANameTag($id)"
Expand Down Expand Up @@ -460,23 +456,10 @@ object TastyFormat {
final val TYPEREFin = 175

final val METHODtype = 180
final val ERASEDMETHODtype = 181
final val GIVENMETHODtype = 182
final val ERASEDGIVENMETHODtype = 183
final val IMPLICITMETHODtype = 184

final val MATCHtype = 190
final val MATCHtpt = 191

def methodTypeTag(isContextual: Boolean, isImplicit: Boolean, isErased: Boolean): Int = {
val implicitOffset =
if (isContextual) 2
else if (isImplicit) { assert(!isErased); 4 }
else 0
val erasedOffset = if (isErased) 1 else 0
METHODtype + erasedOffset + implicitOffset
}

final val HOLE = 255

final val firstNatTreeTag = SHAREDterm
Expand Down Expand Up @@ -680,10 +663,6 @@ object TastyFormat {
case BYNAMEtpt => "BYNAMEtpt"
case POLYtype => "POLYtype"
case METHODtype => "METHODtype"
case ERASEDMETHODtype => "ERASEDMETHODtype"
case GIVENMETHODtype => "GIVENMETHODtype"
case ERASEDGIVENMETHODtype => "ERASEDGIVENMETHODtype"
case IMPLICITMETHODtype => "IMPLICITMETHODtype"
case TYPELAMBDAtype => "TYPELAMBDAtype"
case LAMBDAtpt => "LAMBDAtpt"
case MATCHtype => "MATCHtype"
Expand All @@ -702,10 +681,7 @@ object TastyFormat {
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
SELFDEF | REFINEDtype | TERMREFin | TYPEREFin | HOLE => 1
case RENAMED | PARAMtype => 2
case POLYtype | TYPELAMBDAtype |
METHODtype | ERASEDMETHODtype |
GIVENMETHODtype | ERASEDGIVENMETHODtype |
IMPLICITMETHODtype => -1
case POLYtype | TYPELAMBDAtype | METHODtype => -1
case _ => 0
}
}