diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala index 3dea03543393..32b2f1d582b8 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala @@ -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 _ => diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala index 7703108f5d0b..42281f023e8e 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala @@ -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 { @@ -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) } } diff --git a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala index 07737946ba62..5294dd8b89f9 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala @@ -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()) @@ -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)), pt => readType()) }) goto(end) @@ -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()) diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index ae40e14022e5..9ea3966d0f99 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -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) @@ -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 */ @@ -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)" @@ -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 @@ -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" @@ -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 } }