From 3d65f79a9bb7f9c2d864db5208bd41b30be5cda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Sat, 21 Dec 2024 10:45:06 +0100 Subject: [PATCH 1/3] Improve test suite error messages when `HashersTest` fails. --- ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala b/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala index 4115c19c81..c92f911f11 100644 --- a/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala +++ b/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala @@ -38,11 +38,9 @@ class HashersTest { out.close() out.toByteArray() } + val actualString = actualBytes.map(b => "%02x".format(b & 0xff)).mkString - val expectedBytes = expected.grouped(2) - .map(Integer.parseInt(_, 16).toByte).toArray - - assertArrayEquals(expectedBytes, actualBytes) + assertEquals(expected, actualString) } private val bodyWithInterestingStuff = Block( From 5dc41278c02a03e2f6312f177236122f48c84efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Sat, 21 Dec 2024 11:17:44 +0100 Subject: [PATCH 2/3] Directly store a LocalName inside VarRef, instead of a LocalIdent. The only point of a `LocalIdent` is to keep track of a position in addition to the local name. However, in a `VarRef`, the position should always be the same as the `VarRef` itself. Storing a separate instance of `LocalIdent` is therefore wasteful. --- .../org/scalajs/nscplugin/GenJSCode.scala | 64 +++++++++---------- .../org/scalajs/nscplugin/GenJSExports.scala | 10 +-- .../org/scalajs/nscplugin/JSEncoding.scala | 7 +- .../main/scala/org/scalajs/ir/Hashers.scala | 4 +- .../main/scala/org/scalajs/ir/Printers.scala | 4 +- .../scala/org/scalajs/ir/Serializers.scala | 9 ++- .../src/main/scala/org/scalajs/ir/Trees.scala | 6 +- .../scala/org/scalajs/ir/HashersTest.scala | 4 +- .../scala/org/scalajs/ir/TestIRBuilder.scala | 4 +- .../backend/emitter/FunctionEmitter.scala | 29 +++++---- .../backend/wasmemitter/ClassEmitter.scala | 2 +- .../backend/wasmemitter/FunctionEmitter.scala | 6 +- .../linker/checker/ClassDefChecker.scala | 4 +- .../frontend/optimizer/IncOptimizer.scala | 2 +- .../frontend/optimizer/OptimizerCore.scala | 41 ++++++------ .../org/scalajs/linker/OptimizerTest.scala | 4 +- project/BinaryIncompatibilities.scala | 1 + project/JavaLangObject.scala | 2 +- project/JavalibIRCleaner.scala | 2 +- 19 files changed, 108 insertions(+), 97 deletions(-) diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala index 41b035fde2..23981dcaba 100644 --- a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala +++ b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala @@ -179,7 +179,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) // Per method body private val currentMethodSym = new ScopedVar[Symbol] - private val thisLocalVarIdent = new ScopedVar[Option[js.LocalIdent]] + private val thisLocalVarName = new ScopedVar[Option[LocalName]] private val enclosingLabelDefInfos = new ScopedVar[Map[Symbol, EnclosingLabelDefInfo]] private val isModuleInitialized = new ScopedVar[VarBox[Boolean]] private val undefinedDefaultParams = new ScopedVar[mutable.Set[Symbol]] @@ -187,11 +187,11 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) private val mutatedLocalVars = new ScopedVar[mutable.Set[Symbol]] private def withPerMethodBodyState[A](methodSym: Symbol, - initThisLocalVarIdent: Option[js.LocalIdent] = None)(body: => A): A = { + initThisLocalVarName: Option[LocalName] = None)(body: => A): A = { withScopedVars( currentMethodSym := methodSym, - thisLocalVarIdent := initThisLocalVarIdent, + thisLocalVarName := initThisLocalVarName, enclosingLabelDefInfos := Map.empty, isModuleInitialized := new VarBox(false), undefinedDefaultParams := mutable.Set.empty, @@ -241,7 +241,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) generatedSAMWrapperCount := new VarBox(0), delambdafyTargetDefDefs := mutable.Map.empty, currentMethodSym := null, - thisLocalVarIdent := null, + thisLocalVarName := null, enclosingLabelDefInfos := null, isModuleInitialized := null, undefinedDefaultParams := null, @@ -999,9 +999,9 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) * FIXME This could clash with a local variable of the constructor or a JS * class capture. How do we avoid this? */ - val selfName = freshLocalIdent("this")(pos) + val selfIdent = freshLocalIdent("this")(pos) def selfRef(implicit pos: ir.Position) = - js.VarRef(selfName)(jstpe.AnyType) + js.VarRef(selfIdent.name)(jstpe.AnyType) def memberLambda(params: List[js.ParamDef], restParam: Option[js.ParamDef], body: js.Tree)(implicit pos: ir.Position) = { @@ -1101,7 +1101,8 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) js.JSNew(jsSuperClassRef, args) } - val selfVarDef = js.VarDef(selfName, thisOriginalName, jstpe.AnyType, mutable = false, newTree) + val selfVarDef = js.VarDef(selfIdent.copy(), // copy for the correct `pos` + thisOriginalName, jstpe.AnyType, mutable = false, newTree) selfVarDef :: memberDefinitions } @@ -2040,12 +2041,12 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) * Other (normal) methods are emitted with `genMethodDef()`. */ def genMethodWithCurrentLocalNameScope(dd: DefDef, - initThisLocalVarIdent: Option[js.LocalIdent] = None): js.MethodDef = { + initThisLocalVarName: Option[LocalName] = None): js.MethodDef = { implicit val pos = dd.pos val sym = dd.symbol - withPerMethodBodyState(sym, initThisLocalVarIdent) { + withPerMethodBodyState(sym, initThisLocalVarName) { val methodName = encodeMethodSym(sym) val originalName = originalNameOfMethod(sym) @@ -2112,8 +2113,8 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) methodDef } else { val patches = ( - unmutatedMutableLocalVars.map(encodeLocalSym(_).name -> false) ::: - mutatedImmutableLocalVals.map(encodeLocalSym(_).name -> true) + unmutatedMutableLocalVars.map(encodeLocalSymName(_) -> false) ::: + mutatedImmutableLocalVals.map(encodeLocalSymName(_) -> true) ).toMap patchMutableFlagOfLocals(methodDef, patches) } @@ -2195,15 +2196,15 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) private def patchTypeOfParamDefs(methodDef: js.MethodDef, patches: Map[LocalName, jstpe.Type]): js.MethodDef = { - def newType(name: js.LocalIdent, oldType: jstpe.Type): jstpe.Type = - patches.getOrElse(name.name, oldType) + def newType(name: LocalName, oldType: jstpe.Type): jstpe.Type = + patches.getOrElse(name, oldType) val js.MethodDef(flags, methodName, originalName, params, resultType, body) = methodDef val newParams = for { p @ js.ParamDef(name, originalName, ptpe, mutable) <- params } yield { - js.ParamDef(name, originalName, newType(name, ptpe), mutable)(p.pos) + js.ParamDef(name, originalName, newType(name.name, ptpe), mutable)(p.pos) } val transformer = new ir.Transformers.Transformer { override def transform(tree: js.Tree): js.Tree = tree match { @@ -2292,7 +2293,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val innerBody = { withScopedVars( - thisLocalVarIdent := Some(thisLocalIdent) + thisLocalVarName := Some(thisLocalIdent.name) ) { js.Block(otherStats.map(genStat) :+ ( if (bodyIsStat) genStat(rhs) @@ -2371,7 +2372,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val thisLocalIdent = freshLocalIdent("this") withScopedVars( - thisLocalVarIdent := Some(thisLocalIdent) + thisLocalVarName := Some(thisLocalIdent.name) ) { val staticNamespace = if (namespace.isPrivate) js.MemberNamespace.PrivateStatic @@ -2782,7 +2783,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) case _ => mutatedLocalVars += sym js.Assign( - js.VarRef(encodeLocalSym(sym))(toIRType(sym.tpe)), + js.VarRef(encodeLocalSymName(sym))(toIRType(sym.tpe)), genRhs) } @@ -2832,15 +2833,14 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) * is one. */ private def genThis()(implicit pos: Position): js.Tree = { - thisLocalVarIdent.fold[js.Tree] { + thisLocalVarName.fold[js.Tree] { if (tryingToGenMethodAsJSFunction) { throw new CancelGenMethodAsJSFunction( "Trying to generate `this` inside the body") } js.This()(currentThisType) - } { thisLocalIdent => - // .copy() to get the correct position - js.VarRef(thisLocalIdent.copy())(currentThisTypeNullable) + } { thisLocalName => + js.VarRef(thisLocalName)(currentThisTypeNullable) } } @@ -3093,7 +3093,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) implicit pos: Position): js.Tree = { val exceptIdent = freshLocalIdent("e") - val origExceptVar = js.VarRef(exceptIdent)(jstpe.AnyType) + val origExceptVar = js.VarRef(exceptIdent.name)(jstpe.AnyType) val mightCatchJavaScriptException = catches.exists { caseDef => caseDef.pat match { @@ -3486,7 +3486,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) List.newBuilder[(js.VarRef, jstpe.Type, js.LocalIdent, js.Tree)] for ((formalArgSym, arg) <- targetSyms.zip(values)) { - val formalArg = encodeLocalSym(formalArgSym) + val formalArgName = encodeLocalSymName(formalArgSym) val actualArg = genExpr(arg) /* #3267 The formal argument representing the special `this` of a @@ -3511,13 +3511,13 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) else actualArg actualArg match { - case js.VarRef(`formalArg`) => + case js.VarRef(`formalArgName`) => // This is trivial assignment, we don't need it case _ => mutatedLocalVars += formalArgSym - quadruplets += ((js.VarRef(formalArg)(tpe), tpe, - freshLocalIdent(formalArg.name.withPrefix("temp$")), + quadruplets += ((js.VarRef(formalArgName)(tpe), tpe, + freshLocalIdent(formalArgName.withPrefix("temp$")), fixedActualArg)) } } @@ -3538,7 +3538,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) yield js.VarDef(tempArg, NoOriginalName, argType, mutable = false, actualArg) val trueAssignments = for ((formalArg, argType, tempArg, _) <- quadruplets) - yield js.Assign(formalArg, js.VarRef(tempArg)(argType)) + yield js.Assign(formalArg, js.VarRef(tempArg.name)(argType)) tempAssignments ::: trueAssignments } } @@ -5002,7 +5002,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val callTrgIdent = freshLocalIdent() val callTrgVarDef = js.VarDef(callTrgIdent, NoOriginalName, receiverType, mutable = false, genExpr(receiver)) - val callTrg = js.VarRef(callTrgIdent)(receiverType) + val callTrg = js.VarRef(callTrgIdent.name)(receiverType) val arguments = args zip sym.tpe.params map { case (arg, param) => /* No need for enteringPosterasure, because value classes are not @@ -5453,7 +5453,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val fVarDef = js.VarDef(freshLocalIdent("f"), NoOriginalName, jstpe.AnyType, mutable = false, arg2) val keyVarIdent = freshLocalIdent("key") - val keyVarRef = js.VarRef(keyVarIdent)(jstpe.AnyType) + val keyVarRef = js.VarRef(keyVarIdent.name)(jstpe.AnyType) js.Block( objVarDef, fVarDef, @@ -5488,7 +5488,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val handlerVarDef = js.VarDef(freshLocalIdent("handler"), NoOriginalName, jstpe.AnyType, mutable = false, arg2) val exceptionVarIdent = freshLocalIdent("e") - val exceptionVarRef = js.VarRef(exceptionVarIdent)(jstpe.AnyType) + val exceptionVarRef = js.VarRef(exceptionVarIdent.name)(jstpe.AnyType) js.Block( bodyVarDef, handlerVarDef, @@ -6465,7 +6465,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) // Gen the inlined target method body val genMethodDef = { genMethodWithCurrentLocalNameScope(consumeDelambdafyTarget(target), - initThisLocalVarIdent = thisFormalCapture.map(_.name)) + initThisLocalVarName = thisFormalCapture.map(_.name.name)) } val js.MethodDef(methodFlags, _, _, methodParams, _, methodBody) = genMethodDef @@ -6777,7 +6777,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) // Utilities --------------------------------------------------------------- def genVarRef(sym: Symbol)(implicit pos: Position): js.VarRef = - js.VarRef(encodeLocalSym(sym))(toIRType(sym.tpe)) + js.VarRef(encodeLocalSymName(sym))(toIRType(sym.tpe)) def genParamDef(sym: Symbol): js.ParamDef = genParamDef(sym, toIRType(sym.tpe)) diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala index bf668424ae..603a6286d3 100644 --- a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala +++ b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala @@ -684,7 +684,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent { val superClass = { val superClassSym = currentClassSym.superClass if (isNestedJSClass(superClassSym)) { - js.VarRef(js.LocalIdent(JSSuperClassParamName))(jstpe.AnyType) + js.VarRef(JSSuperClassParamName)(jstpe.AnyType) } else { js.LoadJSConstructor(encodeClassName(superClassSym)) } @@ -1053,7 +1053,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent { def genArgRef(index: Int)(implicit pos: Position): js.Tree = { if (index < minArgc) - js.VarRef(js.LocalIdent(fixedParamNames(index)))(jstpe.AnyType) + js.VarRef(fixedParamNames(index))(jstpe.AnyType) else js.JSSelect(genRestArgRef(), js.IntLiteral(index - minArgc)) } @@ -1073,16 +1073,16 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent { def genRestArgRef()(implicit pos: Position): js.Tree = { assert(needsRestParam, s"trying to generate a reference to non-existent rest param at $pos") - js.VarRef(js.LocalIdent(restParamName))(jstpe.AnyType) + js.VarRef(restParamName)(jstpe.AnyType) } def genAllArgsRefsForForwarder()(implicit pos: Position): List[js.TreeOrJSSpread] = { val fixedArgRefs = fixedParamNames.toList.map { paramName => - js.VarRef(js.LocalIdent(paramName))(jstpe.AnyType) + js.VarRef(paramName)(jstpe.AnyType) } if (needsRestParam) { - val restArgRef = js.VarRef(js.LocalIdent(restParamName))(jstpe.AnyType) + val restArgRef = js.VarRef(restParamName)(jstpe.AnyType) fixedArgRefs :+ js.JSSpread(restArgRef) } else { fixedArgRefs diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala b/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala index 51ec7de709..c4d8188c44 100644 --- a/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala +++ b/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala @@ -256,7 +256,10 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent { } } - def encodeLocalSym(sym: Symbol)(implicit pos: Position): js.LocalIdent = { + def encodeLocalSym(sym: Symbol)(implicit pos: Position): js.LocalIdent = + js.LocalIdent(encodeLocalSymName(sym)) + + def encodeLocalSymName(sym: Symbol): LocalName = { /* The isValueParameter case is necessary to work around an internal bug * of scalac: for some @varargs methods, the owner of some parameters is * the enclosing class rather the method, so !sym.owner.isClass fails. @@ -266,7 +269,7 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent { require(sym.isValueParameter || (!sym.owner.isClass && sym.isTerm && !sym.isMethod && !sym.isModule), "encodeLocalSym called with non-local symbol: " + sym) - js.LocalIdent(localSymbolName(sym)) + localSymbolName(sym) } def encodeClassType(sym: Symbol): jstpe.Type = { diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala index 1c159fe9b2..10847a8ba3 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala @@ -524,9 +524,9 @@ object Hashers { mixTag(TagClassOf) mixTypeRef(typeRef) - case VarRef(ident) => + case VarRef(name) => mixTag(TagVarRef) - mixLocalIdent(ident) + mixName(name) mixType(tree.tpe) case This() => diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala index b5bfccc64e..af6ed1023c 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala @@ -869,8 +869,8 @@ object Printers { // Atomic expressions - case VarRef(ident) => - print(ident) + case VarRef(name) => + print(name) case This() => print("this") diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala index 11bafee148..b8fd8790b2 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala @@ -551,9 +551,9 @@ object Serializers { writeTagAndPos(TagClassOf) writeTypeRef(typeRef) - case VarRef(ident) => + case VarRef(name) => writeTagAndPos(TagVarRef) - writeLocalIdent(ident) + writeName(name) writeType(tree.tpe) case This() => @@ -1388,7 +1388,10 @@ object Serializers { case TagClassOf => ClassOf(readTypeRef()) case TagVarRef => - VarRef(readLocalIdent())(readType()) + val name = + if (hacks.use17) readLocalIdent().name + else readLocalName() + VarRef(name)(readType()) case TagThis => val tpe = readType() diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala b/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala index 4b1e58ce12..dfb4671d26 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala @@ -104,13 +104,13 @@ object Trees { implicit val pos: Position) extends Tree { val tpe = VoidType - def ref(implicit pos: Position): VarRef = VarRef(name)(vtpe) + def ref(implicit pos: Position): VarRef = VarRef(name.name)(vtpe) } sealed case class ParamDef(name: LocalIdent, originalName: OriginalName, ptpe: Type, mutable: Boolean)( implicit val pos: Position) extends IRNode { - def ref(implicit pos: Position): VarRef = VarRef(name)(ptpe) + def ref(implicit pos: Position): VarRef = VarRef(name.name)(ptpe) } // Control flow constructs @@ -1088,7 +1088,7 @@ object Trees { // Atomic expressions - sealed case class VarRef(ident: LocalIdent)(val tpe: Type)( + sealed case class VarRef(name: LocalName)(val tpe: Type)( implicit val pos: Position) extends AssignLhs sealed case class This()(val tpe: Type)(implicit val pos: Position) diff --git a/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala b/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala index c92f911f11..612174ffff 100644 --- a/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala +++ b/ir/shared/src/test/scala/org/scalajs/ir/HashersTest.scala @@ -91,7 +91,7 @@ class HashersTest { ) test( - "309805e5680ffa1804811ff5c9ebc77e91846957", + "82df9d6beb7df0ee9f501380323bdb2038cc50cb", MethodDef(MemberFlags.empty, mIIMethodName, NON, List(ParamDef("x", NON, IntType, mutable = false)), IntType, Some(bodyWithInterestingStuff))( @@ -106,7 +106,7 @@ class HashersTest { } test( - "c0f1ef1b22fd1cfdc9bba78bf3e0f433e9f82fc1", + "d0fa6c753502e3d1df34e53ca6f6afb5cbdcd9d4", JSMethodDef(MemberFlags.empty, s("m"), List(ParamDef("x", NON, AnyType, mutable = false)), None, bodyWithInterestingStuff)( diff --git a/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala b/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala index d89d8050a7..8c578c296e 100644 --- a/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala +++ b/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala @@ -37,6 +37,8 @@ object TestIRBuilder { val NoOptHints = OptimizerHints.empty // String -> Name conversions + implicit def string2localName(name: String): LocalName = + LocalName(name) implicit def string2simpleFieldName(name: String): SimpleFieldName = SimpleFieldName(name) implicit def string2className(name: String): ClassName = @@ -79,7 +81,7 @@ object TestIRBuilder { def d(value: Double): DoubleLiteral = DoubleLiteral(value) def s(value: String): StringLiteral = StringLiteral(value) - def ref(ident: LocalIdent, tpe: Type): VarRef = VarRef(ident)(tpe) + def ref(name: LocalName, tpe: Type): VarRef = VarRef(name)(tpe) def arrayType(base: NonArrayTypeRef, dimensions: Int): ArrayType = ArrayType(ArrayTypeRef(base, dimensions), nullable = true) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala index f2847be772..6abeb4dd36 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala @@ -450,7 +450,7 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { implicit pos: Position): js.Ident = { val recIdent = (tree.record: @unchecked) match { - case VarRef(ident) => transformLocalVarIdent(ident) + case record: VarRef => transformLocalVarRefIdent(record) case Transient(JSVarRef(ident, _)) => ident case record: RecordSelect => makeRecordFieldIdentForVarRef(record) } @@ -1456,7 +1456,7 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { lhs.tpe match { case RecordType(fields) => val ident = (lhs: @unchecked) match { - case VarRef(ident) => transformLocalVarIdent(ident) + case lhs: VarRef => transformLocalVarRefIdent(lhs) case Transient(JSVarRef(ident, _)) => ident } val elems = extractRecordElems(rhs) @@ -1495,9 +1495,9 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { case RecordValue(_, elems) => elems - case VarRef(ident) => - val jsIdent = transformLocalVarIdent(ident) - val mutable = env.isLocalMutable(ident) + case recordTree @ VarRef(name) => + val jsIdent = transformLocalVarRefIdent(recordTree) + val mutable = env.isLocalMutable(name) for (RecordType.Field(fName, fOrigName, fTpe, _) <- recordType.fields) yield Transient(JSVarRef(makeRecordFieldIdent(jsIdent, fName, fOrigName), mutable)(fTpe)) @@ -3014,10 +3014,10 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { // Atomic expressions - case VarRef(name) => + case tree @ VarRef(name) => env.varKind(name) match { case VarKind.Mutable | VarKind.Immutable => - js.VarRef(transformLocalVarIdent(name)) + js.VarRef(transformLocalVarRefIdent(tree)) case VarKind.ThisAlias => js.This() @@ -3026,7 +3026,7 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { fileLevelVar(VarField.thiz) case VarKind.ClassCapture => - fileLevelVar(VarField.cc, genName(name.name)) + fileLevelVar(VarField.cc, genName(name)) } case Transient(JSVarRef(name, _)) => @@ -3165,7 +3165,7 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { * For other usages (notably ApplyDynamicImport), we generate the * body, so it's easy to ensure no collision. */ - def permitImplicitNameCapture = forceName.forall(_ == name.name) + def permitImplicitNameCapture = forceName.forall(_ == name) env.varKind(name) match { case VarKind.Immutable if !env.inLoopForVarCapture && permitImplicitNameCapture => @@ -3255,6 +3255,9 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { private def transformLabelIdent(ident: LabelIdent): js.Ident = js.Ident(genName(ident.name))(ident.pos) + private def transformLocalVarRefIdent(varRef: VarRef): js.Ident = + js.Ident(transformLocalName(varRef.name))(varRef.pos) + private def transformLocalVarIdent(ident: LocalIdent): js.Ident = js.Ident(transformLocalName(ident.name))(ident.pos) @@ -3433,13 +3436,13 @@ private object FunctionEmitter { defaultContinueTargets: Set[LabelName], val inLoopForVarCapture: Boolean ) { - def varKind(ident: LocalIdent): VarKind = { + def varKind(name: LocalName): VarKind = { // If we do not know the var, it must be a JS class capture. - vars.getOrElse(ident.name, VarKind.ClassCapture) + vars.getOrElse(name, VarKind.ClassCapture) } - def isLocalMutable(ident: LocalIdent): Boolean = - VarKind.Mutable == varKind(ident) + def isLocalMutable(name: LocalName): Boolean = + VarKind.Mutable == varKind(name) def lhsForLabeledExpr(label: LabelIdent): Lhs = labeledExprLHSes(label.name) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/ClassEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/ClassEmitter.scala index 43409fa133..44d18110fb 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/ClassEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/ClassEmitter.scala @@ -1007,7 +1007,7 @@ class ClassEmitter(coreSpec: CoreSpec) { val helperBuilder = new CustomJSHelperBuilder.WithTreeEval() { protected def evalTreeAtCallSite(tree: Tree, expectedType: Type): Unit = tree match { - case VarRef(LocalIdent(localName)) if classCaptureParamsOfTypeAny.contains(localName) => + case VarRef(localName) if classCaptureParamsOfTypeAny.contains(localName) => /* Common shape for the `jsSuperClass` value * We can only deal with class captures of type `AnyType` in this way, * since otherwise we might need `adapt` to box the values. diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala index 83a6854719..85cc991c39 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala @@ -464,7 +464,7 @@ private class FunctionEmitter private ( val RecordSelect(record, field) = tree val recordStorage = record match { - case VarRef(LocalIdent(name)) => + case VarRef(name) => lookupLocal(name) case record: RecordSelect => lookupRecordSelect(record) @@ -778,7 +778,7 @@ private class FunctionEmitter private ( markPosition(tree) fb += wa.Call(helperID) - case VarRef(LocalIdent(name)) => + case VarRef(name) => genTree(rhs, lhs.tpe) markPosition(tree) genWriteToStorage(lookupLocal(name)) @@ -2336,7 +2336,7 @@ private class FunctionEmitter private ( } private def genVarRef(tree: VarRef): Type = { - val VarRef(LocalIdent(name)) = tree + val VarRef(name) = tree markPosition(tree) if (tree.tpe == NothingType) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala b/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala index 1c4bd11d74..919e2262c6 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala @@ -682,7 +682,7 @@ private final class ClassDefChecker(classDef: ClassDef, checkTree(rhs, env) lhs match { - case VarRef(LocalIdent(name)) => + case VarRef(name) => if (env.locals.get(name).exists(!_.mutable)) reportError(i"Assignment to immutable variable $name.") @@ -964,7 +964,7 @@ private final class ClassDefChecker(classDef: ClassDef, // Atomic expressions - case VarRef(LocalIdent(name)) => + case VarRef(name) => env.locals.get(name).fold[Unit] { reportError(i"Cannot find variable $name in scope") } { localDef => diff --git a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/IncOptimizer.scala b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/IncOptimizer.scala index 38a02b54ad..5b2cf7ad5e 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/IncOptimizer.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/IncOptimizer.scala @@ -1009,7 +1009,7 @@ final class IncOptimizer private[optimizer] (config: CommonPhaseConfig, collOps: case lit: Literal => Some(FieldBody.Literal(lit)) - case VarRef(LocalIdent(valName)) => + case VarRef(valName) => paramBodies.get(valName) case LoadModule(moduleClassName) => diff --git a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala index 0f519afdb2..b280a7776a 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala @@ -923,7 +923,7 @@ private[optimizer] abstract class OptimizerCore( case tree: Block => pretransformBlock(tree)(cont) - case VarRef(LocalIdent(name)) => + case VarRef(name) => val localDef = scope.env.localDefs.getOrElse(name, { throw new AssertionError( s"Cannot find local def '$name' at $pos\n" + @@ -1427,8 +1427,7 @@ private[optimizer] abstract class OptimizerCore( replacement match { case ReplaceWithRecordVarRef(name, recordType, used, cancelFun) => used.value = used.value.inc - PreTransRecordTree( - VarRef(LocalIdent(name))(recordType), tpe, cancelFun) + PreTransRecordTree(VarRef(name)(recordType), tpe, cancelFun) case InlineClassInstanceReplacement(structure, fieldLocalDefs, cancelFun) => val recordType = structure.recordType @@ -1828,8 +1827,8 @@ private[optimizer] abstract class OptimizerCore( override def traverse(tree: Tree): Unit = { super.traverse(tree) tree match { - case Assign(VarRef(ident), _) => mutatedLocalVars += ident.name - case _ => () + case Assign(VarRef(name), _) => mutatedLocalVars += name + case _ => () } } } @@ -1851,10 +1850,10 @@ private[optimizer] abstract class OptimizerCore( implicit val pos = body.pos body match { - case VarRef(ident) => - if (ident.name == valName) + case VarRef(name) => + if (name == valName) Success(valTree) - else if (valTreeInfo.mutatedLocalVars.contains(ident.name)) + else if (valTreeInfo.mutatedLocalVars.contains(name)) Failed else NotFoundPureSoFar @@ -2224,9 +2223,9 @@ private[optimizer] abstract class OptimizerCore( MethodIdent(methodName), normalizedParams.zip(referenceArgs).map { case ((name, ptpe), AsInstanceOf(_, castTpe)) => - AsInstanceOf(VarRef(LocalIdent(name))(ptpe), castTpe) + AsInstanceOf(VarRef(name)(ptpe), castTpe) case ((name, ptpe), _) => - VarRef(LocalIdent(name))(ptpe) + VarRef(name)(ptpe) } )(body.tpe) @@ -2477,7 +2476,7 @@ private[optimizer] abstract class OptimizerCore( cancelFun() used.value = used.value.inc - val module = VarRef(LocalIdent(moduleVarName))(AnyType) + val module = VarRef(moduleVarName)(AnyType) path.foldLeft[Tree](module) { (inner, pathElem) => JSSelect(inner, StringLiteral(pathElem)) } @@ -2691,7 +2690,7 @@ private[optimizer] abstract class OptimizerCore( optQualDeclaredType = Some(optReceiver.get._1), field, isLhsOfAssign = false)(cont) - case Assign(lhs @ Select(This(), field), VarRef(LocalIdent(rhsName))) + case Assign(lhs @ Select(This(), field), VarRef(rhsName)) if formals.size == 1 && formals.head.name.name == rhsName => assert(isStat, "Found Assign in expression position") assert(optReceiver.isDefined, @@ -3501,10 +3500,10 @@ private[optimizer] abstract class OptimizerCore( * the equals() method has been inlined as a reference * equality test. */ - case (BinaryOp(BinaryOp.===, VarRef(lhsIdent), Null()), - BinaryOp(BinaryOp.===, VarRef(rhsIdent), Null()), + case (BinaryOp(BinaryOp.===, VarRef(lhsName), Null()), + BinaryOp(BinaryOp.===, VarRef(rhsName), Null()), BinaryOp(BinaryOp.===, MaybeCast(l: VarRef), r: VarRef)) - if l.ident == lhsIdent && r.ident == rhsIdent => + if l.name == lhsName && r.name == rhsName => BinaryOp(BinaryOp.===, l, r)(elsep.pos) // Example: (x > y) || (x == y) -> (x >= y) @@ -3601,7 +3600,7 @@ private[optimizer] abstract class OptimizerCore( value) withBinding(rtLongBinding) { (scope1, cont1) => implicit val scope = scope1 - val tRef = VarRef(LocalIdent(tName))(rtLongClassType) + val tRef = VarRef(tName)(rtLongClassType) val newTree = New(LongImpl.RuntimeLongClass, MethodIdent(LongImpl.initFromParts), List(Apply(ApplyFlags.empty, tRef, MethodIdent(LongImpl.lo), Nil)(IntType), @@ -5497,7 +5496,7 @@ private[optimizer] abstract class OptimizerCore( buildInner(LocalDef(value.tpe, false, ReplaceWithConstant(literal)), cont) - case PreTransTree(VarRef(LocalIdent(refName)), _) + case PreTransTree(VarRef(refName), _) if !localIsMutable(refName) => buildInner(LocalDef(value.tpe, false, ReplaceWithVarRef(refName, newSimpleState(UsedAtLeastOnce))), cont) @@ -5862,7 +5861,7 @@ private[optimizer] object OptimizerCore { def newReplacement(implicit pos: Position): Tree = this.replacement match { case ReplaceWithVarRef(name, used) => used.value = used.value.inc - VarRef(LocalIdent(name))(tpe.base) + VarRef(name)(tpe.base) /* Allocate an instance of RuntimeLong on the fly. * See the comment in finishTransformExpr about why it is desirable and @@ -5871,7 +5870,7 @@ private[optimizer] object OptimizerCore { case ReplaceWithRecordVarRef(name, recordType, used, _) if tpe.base == ClassType(LongImpl.RuntimeLongClass, nullable = false) => used.value = used.value.inc - createNewLong(VarRef(LocalIdent(name))(recordType)) + createNewLong(VarRef(name)(recordType)) case ReplaceWithRecordVarRef(_, _, _, cancelFun) => cancelFun() @@ -6755,7 +6754,7 @@ private[optimizer] object OptimizerCore { case ApplyStatically(_, This(), className, method, args) => args.size == params.size && args.zip(params).forall { - case (VarRef(LocalIdent(aname)), ParamDef(LocalIdent(pname), _, _, _)) => + case (VarRef(aname), ParamDef(LocalIdent(pname), _, _, _)) => aname == pname case _ => false @@ -6766,7 +6765,7 @@ private[optimizer] object OptimizerCore { !method.name.isReflectiveProxy && (args.size == params.size) && args.zip(params).forall { - case (MaybeUnbox(VarRef(LocalIdent(aname)), _), + case (MaybeUnbox(VarRef(aname), _), ParamDef(LocalIdent(pname), _, _, _)) => aname == pname case _ => false } diff --git a/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala b/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala index 08838c0627..e80affe3bc 100644 --- a/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala +++ b/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala @@ -268,7 +268,7 @@ class OptimizerTest { */ val matchResult1 = LabelIdent("matchResult1") - val x1 = LocalIdent("x1") + val x1 = LocalName("x1") val matchAlts1 = LabelIdent("matchAlts1") val matchAlts2 = LabelIdent("matchAlts2") @@ -475,7 +475,7 @@ class OptimizerTest { traverseMainMethod(moduleSet) { case c: Closure => c.captureValues match { - case List(VarRef(LocalIdent(name))) => + case List(VarRef(name)) => assertEquals(s"unexpected capture name: $c", c.captureParams.head.name.name, name) case _ => diff --git a/project/BinaryIncompatibilities.scala b/project/BinaryIncompatibilities.scala index 133cf0906a..7c373ae05f 100644 --- a/project/BinaryIncompatibilities.scala +++ b/project/BinaryIncompatibilities.scala @@ -8,6 +8,7 @@ object BinaryIncompatibilities { // !!! Breaking, OK in minor release ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$JSLinkingInfo"), ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$JSLinkingInfo$"), + ProblemFilters.exclude[Problem]("org.scalajs.ir.Trees#VarRef.*"), ProblemFilters.exclude[IncompatibleResultTypeProblem]("org.scalajs.ir.Trees#*.tpe"), ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Types$NoType$"), diff --git a/project/JavaLangObject.scala b/project/JavaLangObject.scala index 789d57df73..eb3eedabef 100644 --- a/project/JavaLangObject.scala +++ b/project/JavaLangObject.scala @@ -87,7 +87,7 @@ object JavaLangObject { Some { BinaryOp(BinaryOp.===, This()(ThisType), - VarRef(LocalIdent(LocalName("that")))(AnyType)) + VarRef(LocalName("that"))(AnyType)) })(OptimizerHints.empty.withInline(true), Unversioned), /* protected def clone(): Object = diff --git a/project/JavalibIRCleaner.scala b/project/JavalibIRCleaner.scala index dc0d38d249..6f014a4e93 100644 --- a/project/JavalibIRCleaner.scala +++ b/project/JavalibIRCleaner.scala @@ -215,7 +215,7 @@ final class JavalibIRCleaner(baseDirectoryURI: URI) { def argsCorrespond(args: List[Tree], paramDefs: List[ParamDef]): Boolean = { (args.size == paramDefs.size) && args.zip(paramDefs).forall { - case (VarRef(LocalIdent(argName)), ParamDef(LocalIdent(paramName), _, _, _)) => + case (VarRef(argName), ParamDef(LocalIdent(paramName), _, _, _)) => argName == paramName case _ => false From 2ba9ea710e86b1aa1b62c2e35656faabc3a55754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Sat, 21 Dec 2024 11:55:12 +0100 Subject: [PATCH 3/3] Remove `LabelIdent`. Directly store `LabelName` instead. The position of labels is always irrelevant, as they are synthetic. Therefore, storing them through `LabelIdent`s is wasteful. --- .../org/scalajs/nscplugin/GenJSCode.scala | 28 ++++++------- .../org/scalajs/nscplugin/JSEncoding.scala | 15 +++---- .../nscplugin/test/OptimizationTest.scala | 4 +- .../main/scala/org/scalajs/ir/Hashers.scala | 9 +---- .../main/scala/org/scalajs/ir/Printers.scala | 4 -- .../scala/org/scalajs/ir/Serializers.scala | 24 +++++------ .../src/main/scala/org/scalajs/ir/Trees.scala | 7 +--- .../scala/org/scalajs/ir/TestIRBuilder.scala | 4 +- .../backend/emitter/FunctionEmitter.scala | 40 +++++++++---------- .../backend/wasmemitter/FunctionEmitter.scala | 4 +- .../linker/checker/ClassDefChecker.scala | 10 ++--- .../scalajs/linker/checker/IRChecker.scala | 4 +- .../frontend/optimizer/OptimizerCore.scala | 12 +++--- .../org/scalajs/linker/OptimizerTest.scala | 6 +-- .../linker/testutils/TestIRBuilder.scala | 2 - project/BinaryIncompatibilities.scala | 10 +++++ 16 files changed, 86 insertions(+), 97 deletions(-) diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala index 23981dcaba..674ffc3ba6 100644 --- a/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala +++ b/compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala @@ -29,6 +29,7 @@ import org.scalajs.ir import org.scalajs.ir.{Trees => js, Types => jstpe, ClassKind, Hashers, OriginalName} import org.scalajs.ir.Names.{ LocalName, + LabelName, SimpleFieldName, FieldName, SimpleMethodName, @@ -2890,8 +2891,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) val labelParamSyms = tree.params.map(_.symbol) val info = new EnclosingLabelDefInfoWithResultAsAssigns(labelParamSyms) - val labelIdent = encodeLabelSym(sym) - val labelName = labelIdent.name + val labelName = encodeLabelSym(sym) val transformedRhs = withScopedVars( enclosingLabelDefInfos := enclosingLabelDefInfos.get + (sym -> info) @@ -2906,7 +2906,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) */ object ReturnFromThisLabel { def unapply(tree: js.Return): Option[js.Tree] = { - if (tree.label.name == labelName) Some(exprToStat(tree.expr)) + if (tree.label == labelName) Some(exprToStat(tree.expr)) else None } } @@ -2915,7 +2915,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) if (transformedRhs.tpe == jstpe.NothingType) { // In this case, we do not need the outer block label js.While(js.BooleanLiteral(true), { - js.Labeled(labelIdent, jstpe.VoidType, { + js.Labeled(labelName, jstpe.VoidType, { transformedRhs match { // Eliminate a trailing return@lab case js.Block(stats :+ ReturnFromThisLabel(exprAsStat)) => @@ -2927,17 +2927,17 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) }) } else { // When all else has failed, we need the full machinery - val blockLabelIdent = freshLabelIdent("block") + val blockLabelName = freshLabelName("block") val bodyType = if (isStat) jstpe.VoidType else toIRType(tree.tpe) - js.Labeled(blockLabelIdent, bodyType, { + js.Labeled(blockLabelName, bodyType, { js.While(js.BooleanLiteral(true), { - js.Labeled(labelIdent, jstpe.VoidType, { + js.Labeled(labelName, jstpe.VoidType, { if (isStat) - js.Block(transformedRhs, js.Return(js.Skip(), blockLabelIdent)) + js.Block(transformedRhs, js.Return(js.Skip(), blockLabelName)) else - js.Return(transformedRhs, blockLabelIdent) + js.Return(transformedRhs, blockLabelName) }) }) }) @@ -3901,11 +3901,11 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) var clauses: List[(List[js.MatchableLiteral], js.Tree)] = Nil var optElseClause: Option[js.Tree] = None - var optElseClauseLabel: Option[js.LabelIdent] = None + var optElseClauseLabel: Option[LabelName] = None def genJumpToElseClause(implicit pos: ir.Position): js.Tree = { if (optElseClauseLabel.isEmpty) - optElseClauseLabel = Some(freshLabelIdent("default")) + optElseClauseLabel = Some(freshLabelName("default")) js.Return(js.Skip(), optElseClauseLabel.get) } @@ -4025,7 +4025,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) optElseClauseLabel.fold[js.Tree] { buildMatch(clauses.reverse, elseClause, resultType) } { elseClauseLabel => - val matchResultLabel = freshLabelIdent("matchResult") + val matchResultLabel = freshLabelName("matchResult") val patchedClauses = for ((alts, body) <- clauses) yield { implicit val pos = body.pos val newBody = js.Return(body, matchResultLabel) @@ -4366,7 +4366,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) * all jumps to case labels are already caught upstream by `genCaseBody()` * inside `genTranslatedMatch()`. */ - private def genOptimizedCaseLabeled(label: js.LabelIdent, + private def genOptimizedCaseLabeled(label: LabelName, translatedBody: js.Tree, returnCount: Int)( implicit pos: Position): js.Tree = { @@ -4423,7 +4423,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G) * !!! There is quite of bit of code duplication with * OptimizerCore.tryOptimizePatternMatch. */ - def genOptimizedMatchEndLabeled(label: js.LabelIdent, tpe: jstpe.Type, + def genOptimizedMatchEndLabeled(label: LabelName, tpe: jstpe.Type, translatedCases: List[js.Tree], returnCount: Int)( implicit pos: Position): js.Tree = { def default: js.Tree = diff --git a/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala b/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala index c4d8188c44..b1b4c888f5 100644 --- a/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala +++ b/compiler/src/main/scala/org/scalajs/nscplugin/JSEncoding.scala @@ -91,7 +91,7 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent { case None => inner case Some(labelName) => - js.Labeled(js.LabelIdent(labelName), tpe, inner) + js.Labeled(labelName, tpe, inner) } } } @@ -151,29 +151,26 @@ trait JSEncoding[G <: Global with Singleton] extends SubComponent { private def freshLabelName(base: LabelName): LabelName = freshNameGeneric(base, usedLabelNames)(_.withSuffix(_)) - private def freshLabelName(base: String): LabelName = + def freshLabelName(base: String): LabelName = freshLabelName(LabelName(base)) - def freshLabelIdent(base: String)(implicit pos: ir.Position): js.LabelIdent = - js.LabelIdent(freshLabelName(base)) - private def labelSymbolName(sym: Symbol): LabelName = labelSymbolNames.getOrElseUpdate(sym, freshLabelName(sym.name.toString)) - def getEnclosingReturnLabel()(implicit pos: ir.Position): js.LabelIdent = { + def getEnclosingReturnLabel()(implicit pos: Position): LabelName = { val box = returnLabelName.get if (box == null) throw new IllegalStateException(s"No enclosing returnable scope at $pos") if (box.value.isEmpty) box.value = Some(freshLabelName("_return")) - js.LabelIdent(box.value.get) + box.value.get } // Encoding methods ---------------------------------------------------------- - def encodeLabelSym(sym: Symbol)(implicit pos: Position): js.LabelIdent = { + def encodeLabelSym(sym: Symbol): LabelName = { require(sym.isLabel, "encodeLabelSym called with non-label symbol: " + sym) - js.LabelIdent(labelSymbolName(sym)) + labelSymbolName(sym) } def encodeFieldSym(sym: Symbol)(implicit pos: Position): js.FieldIdent = { diff --git a/compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala b/compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala index 47f843c696..24914ca07b 100644 --- a/compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala +++ b/compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala @@ -250,7 +250,7 @@ class OptimizationTest extends JSASTTest { } } """.hasNot("non-return labeled block") { - case js.Labeled(name, _, _) if !name.name.nameString.startsWith("_return") => + case js.Labeled(name, _, _) if !name.nameString.startsWith("_return") => } } @@ -323,7 +323,7 @@ class OptimizationTest extends JSASTTest { } } """.hasNot("non-return labeled block") { - case js.Labeled(name, _, _) if !name.name.nameString.startsWith("_return") => + case js.Labeled(name, _, _) if !name.nameString.startsWith("_return") => } } diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala index 10847a8ba3..a653c15fce 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Hashers.scala @@ -185,7 +185,7 @@ object Hashers { case Labeled(label, tpe, body) => mixTag(TagLabeled) - mixLabelIdent(label) + mixName(label) mixType(tpe) mixTree(body) @@ -197,7 +197,7 @@ object Hashers { case Return(expr, label) => mixTag(TagReturn) mixTree(expr) - mixLabelIdent(label) + mixName(label) case If(cond, thenp, elsep) => mixTag(TagIf) @@ -646,11 +646,6 @@ object Hashers { mixName(ident.name) } - def mixLabelIdent(ident: LabelIdent): Unit = { - mixPos(ident.pos) - mixName(ident.name) - } - def mixSimpleFieldIdent(ident: SimpleFieldIdent): Unit = { mixPos(ident.pos) mixName(ident.name) diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala index af6ed1023c..4c4401a406 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Printers.scala @@ -122,7 +122,6 @@ object Printers { def printAnyNode(node: IRNode): Unit = { node match { case node: LocalIdent => print(node) - case node: LabelIdent => print(node) case node: SimpleFieldIdent => print(node) case node: FieldIdent => print(node) case node: MethodIdent => print(node) @@ -1138,9 +1137,6 @@ object Printers { def print(ident: LocalIdent): Unit = print(ident.name) - def print(ident: LabelIdent): Unit = - print(ident.name) - def print(ident: SimpleFieldIdent): Unit = print(ident.name) diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala b/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala index b8fd8790b2..da0dc4d01e 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala @@ -265,7 +265,7 @@ object Serializers { case Labeled(label, tpe, body) => writeTagAndPos(TagLabeled) - writeLabelIdent(label); writeType(tpe); writeTree(body) + writeName(label); writeType(tpe); writeTree(body) case Assign(lhs, rhs) => writeTagAndPos(TagAssign) @@ -273,7 +273,7 @@ object Serializers { case Return(expr, label) => writeTagAndPos(TagReturn) - writeTree(expr); writeLabelIdent(label) + writeTree(expr); writeName(label) case If(cond, thenp, elsep) => writeTagAndPos(TagIf) @@ -786,11 +786,6 @@ object Serializers { writeName(ident.name) } - def writeLabelIdent(ident: LabelIdent): Unit = { - writePosition(ident.pos) - writeName(ident.name) - } - def writeSimpleFieldIdent(ident: SimpleFieldIdent): Unit = { writePosition(ident.pos) writeName(ident.name) @@ -1135,7 +1130,7 @@ object Serializers { case TagVarDef => VarDef(readLocalIdent(), readOriginalName(), readType(), readBoolean(), readTree()) case TagSkip => Skip() case TagBlock => Block(readTrees()) - case TagLabeled => Labeled(readLabelIdent(), readType(), readTree()) + case TagLabeled => Labeled(readLabelName(), readType(), readTree()) case TagAssign => val lhs0 = readTree() @@ -1155,7 +1150,7 @@ object Serializers { Assign(lhs.asInstanceOf[AssignLhs], rhs) - case TagReturn => Return(readTree(), readLabelIdent()) + case TagReturn => Return(readTree(), readLabelName()) case TagIf => If(readTree(), readTree(), readTree())(readType()) case TagWhile => While(readTree(), readTree()) @@ -2166,11 +2161,6 @@ object Serializers { LocalIdent(readLocalName()) } - def readLabelIdent(): LabelIdent = { - implicit val pos = readPosition() - LabelIdent(readLabelName()) - } - def readFieldIdent(): FieldIdent = { // For historical reasons, the className comes *before* the position val className = readClassName() @@ -2399,6 +2389,12 @@ object Serializers { } private def readLabelName(): LabelName = { + /* Before 1.18, `LabelName`s were always wrapped in `LabelIdent`s, whose + * encoding was a `Position` followed by the actual `LabelName`. + */ + if (hacks.use17) + readPosition() // intentional discard + val i = readInt() val existing = labelNames(i) if (existing ne null) { diff --git a/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala b/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala index dfb4671d26..917df781ed 100644 --- a/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala +++ b/ir/shared/src/main/scala/org/scalajs/ir/Trees.scala @@ -56,9 +56,6 @@ object Trees { sealed case class LocalIdent(name: LocalName)(implicit val pos: Position) extends IRNode - sealed case class LabelIdent(name: LabelName)(implicit val pos: Position) - extends IRNode - sealed case class SimpleFieldIdent(name: SimpleFieldName)(implicit val pos: Position) extends IRNode @@ -150,7 +147,7 @@ object Trees { def unapply(block: Block): Some[List[Tree]] = Some(block.stats) } - sealed case class Labeled(label: LabelIdent, tpe: Type, body: Tree)( + sealed case class Labeled(label: LabelName, tpe: Type, body: Tree)( implicit val pos: Position) extends Tree sealed trait AssignLhs extends Tree @@ -160,7 +157,7 @@ object Trees { val tpe = VoidType } - sealed case class Return(expr: Tree, label: LabelIdent)( + sealed case class Return(expr: Tree, label: LabelName)( implicit val pos: Position) extends Tree { val tpe = NothingType } diff --git a/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala b/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala index 8c578c296e..44aed0ef4f 100644 --- a/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala +++ b/ir/shared/src/test/scala/org/scalajs/ir/TestIRBuilder.scala @@ -39,6 +39,8 @@ object TestIRBuilder { // String -> Name conversions implicit def string2localName(name: String): LocalName = LocalName(name) + implicit def string2labelName(name: String): LabelName = + LabelName(name) implicit def string2simpleFieldName(name: String): SimpleFieldName = SimpleFieldName(name) implicit def string2className(name: String): ClassName = @@ -47,8 +49,6 @@ object TestIRBuilder { // String -> Ident conversions implicit def string2localIdent(name: String): LocalIdent = LocalIdent(LocalName(name)) - implicit def string2labelIdent(name: String): LabelIdent = - LabelIdent(LabelName(name)) implicit def string2simpleFieldIdent(name: String): SimpleFieldIdent = SimpleFieldIdent(SimpleFieldName(name)) implicit def string2classIdent(name: String): ClassIdent = diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala index 6abeb4dd36..89516298bb 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/FunctionEmitter.scala @@ -710,12 +710,12 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { case Labeled(label, _, innerBody) => val innerBodyEnv = loopEnv .withLabeledExprLHS(label, Lhs.Discard) - .withTurnLabelIntoContinue(label.name) + .withTurnLabelIntoContinue(label) .withDefaultBreakTargets(tailPosLabels) - .withDefaultContinueTargets(Set(label.name)) + .withDefaultContinueTargets(Set(label)) val newBody = - pushLhsInto(Lhs.Discard, innerBody, Set(label.name))(innerBodyEnv) - val optLabel = if (usedLabels.contains(label.name)) + pushLhsInto(Lhs.Discard, innerBody, Set(label))(innerBodyEnv) + val optLabel = if (usedLabels.contains(label)) Some(transformLabelIdent(label)) else None @@ -1536,27 +1536,27 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { } } - def doReturnToLabel(l: LabelIdent): js.Tree = { - val newLhs = env.lhsForLabeledExpr(l) + def doReturnToLabel(label: LabelName): js.Tree = { + val newLhs = env.lhsForLabeledExpr(label) if (newLhs.hasNothingType) { /* A touch of peephole dead code elimination. * This is actually necessary to avoid dangling breaks to eliminated * labels, as in issue #2307. */ pushLhsInto(newLhs, rhs, tailPosLabels) - } else if (tailPosLabels.contains(l.name)) { + } else if (tailPosLabels.contains(label)) { pushLhsInto(newLhs, rhs, tailPosLabels) } else { val body = pushLhsInto(newLhs, rhs, Set.empty) - val jump = if (env.isDefaultBreakTarget(l.name)) { + val jump = if (env.isDefaultBreakTarget(label)) { js.Break(None) - } else if (env.isDefaultContinueTarget(l.name)) { + } else if (env.isDefaultContinueTarget(label)) { js.Continue(None) } else { - usedLabels += l.name - val transformedLabel = Some(transformLabelIdent(l)) - if (env.isLabelTurnedIntoContinue(l.name)) + usedLabels += label + val transformedLabel = Some(transformLabelIdent(label)) + if (env.isLabelTurnedIntoContinue(label)) js.Continue(transformedLabel) else js.Break(transformedLabel) @@ -1649,8 +1649,8 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { extractLet { newLhs => val bodyEnv = env.withLabeledExprLHS(label, newLhs) val newBody = - pushLhsInto(newLhs, body, tailPosLabels + label.name)(bodyEnv) - if (usedLabels.contains(label.name)) + pushLhsInto(newLhs, body, tailPosLabels + label)(bodyEnv) + if (usedLabels.contains(label)) js.Labeled(transformLabelIdent(label), newBody) else newBody @@ -3252,8 +3252,8 @@ private[emitter] class FunctionEmitter(sjsGen: SJSGen) { private def transformParamDef(paramDef: ParamDef): js.ParamDef = js.ParamDef(transformLocalVarIdent(paramDef.name, paramDef.originalName))(paramDef.pos) - private def transformLabelIdent(ident: LabelIdent): js.Ident = - js.Ident(genName(ident.name))(ident.pos) + private def transformLabelIdent(label: LabelName)(implicit pos: Position): js.Ident = + js.Ident(genName(label)) private def transformLocalVarRefIdent(varRef: VarRef): js.Ident = js.Ident(transformLocalName(varRef.name))(varRef.pos) @@ -3401,7 +3401,7 @@ private object FunctionEmitter { override def hasNothingType: Boolean = true } - final case class Return(label: LabelIdent) extends Lhs { + final case class Return(label: LabelName) extends Lhs { override def hasNothingType: Boolean = true } @@ -3444,7 +3444,7 @@ private object FunctionEmitter { def isLocalMutable(name: LocalName): Boolean = VarKind.Mutable == varKind(name) - def lhsForLabeledExpr(label: LabelIdent): Lhs = labeledExprLHSes(label.name) + def lhsForLabeledExpr(label: LabelName): Lhs = labeledExprLHSes(label) def isLabelTurnedIntoContinue(label: LabelName): Boolean = labelsTurnedIntoContinue.contains(label) @@ -3478,8 +3478,8 @@ private object FunctionEmitter { copy(vars = vars + (ident.name -> kind)) } - def withLabeledExprLHS(label: LabelIdent, lhs: Lhs): Env = - copy(labeledExprLHSes = labeledExprLHSes + (label.name -> lhs)) + def withLabeledExprLHS(label: LabelName, lhs: Lhs): Env = + copy(labeledExprLHSes = labeledExprLHSes + (label -> lhs)) def withTurnLabelIntoContinue(label: LabelName): Env = copy(labelsTurnedIntoContinue = labelsTurnedIntoContinue + label) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala index 85cc991c39..22332110ac 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter/FunctionEmitter.scala @@ -3853,7 +3853,7 @@ private class FunctionEmitter private ( } def genLabeled(tree: Labeled, expectedType: Type): Type = { - val Labeled(LabelIdent(labelName), tpe, body) = tree + val Labeled(labelName, tpe, body) = tree val entry = new LabeledEntry(currentUnwindingStackDepth, labelName, expectedType) @@ -4082,7 +4082,7 @@ private class FunctionEmitter private ( } def genReturn(tree: Return): Type = { - val Return(expr, LabelIdent(labelName)) = tree + val Return(expr, labelName) = tree val targetEntry = enclosingLabeledBlocks(labelName) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala b/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala index 919e2262c6..763255f2c1 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala @@ -667,7 +667,7 @@ private final class ClassDefChecker(classDef: ClassDef, case Labeled(label, _, body) => checkDeclareLabel(label) - checkTree(body, env.withLabel(label.name)) + checkTree(body, env.withLabel(label)) case Assign(lhs, rhs) => lhs match { @@ -716,7 +716,7 @@ private final class ClassDefChecker(classDef: ClassDef, } case Return(expr, label) => - if (!env.returnLabels.contains(label.name)) + if (!env.returnLabels.contains(label)) reportError(i"unknown label $label.") checkTree(expr, env) @@ -1057,10 +1057,10 @@ private final class ClassDefChecker(classDef: ClassDef, reportError(i"Duplicate local variable name ${ident.name}.") } - private def checkDeclareLabel(label: LabelIdent)( + private def checkDeclareLabel(label: LabelName)( implicit ctx: ErrorContext): Unit = { - if (!declaredLabelNamesPerMethod.add(label.name)) - reportError(i"Duplicate label named ${label.name}.") + if (!declaredLabelNamesPerMethod.add(label)) + reportError(i"Duplicate label named $label.") } } diff --git a/linker/shared/src/main/scala/org/scalajs/linker/checker/IRChecker.scala b/linker/shared/src/main/scala/org/scalajs/linker/checker/IRChecker.scala index b4b743ee63..dcd87e7c5a 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/checker/IRChecker.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/checker/IRChecker.scala @@ -234,7 +234,7 @@ private final class IRChecker(unit: LinkingUnit, reporter: ErrorReporter, trees.foreach(typecheck(_, env)) case Labeled(label, tpe, body) => - typecheckExpect(body, env.withLabeledReturnType(label.name, tpe), tpe) + typecheckExpect(body, env.withLabeledReturnType(label, tpe), tpe) case Assign(lhs, rhs) => def checkNonStaticField(receiver: Tree, name: FieldName): Unit = { @@ -304,7 +304,7 @@ private final class IRChecker(unit: LinkingUnit, reporter: ErrorReporter, typecheckExpect(rhs, env, expectedRhsTpe) case Return(expr, label) => - typecheckExpect(expr, env, env.returnTypes(label.name)) + typecheckExpect(expr, env, env.returnTypes(label)) case If(cond, thenp, elsep) => val tpe = tree.tpe diff --git a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala index b280a7776a..94a294a4cc 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/frontend/optimizer/OptimizerCore.scala @@ -338,7 +338,7 @@ private[optimizer] abstract class OptimizerCore( case tree: Block => transformBlock(tree, isStat) - case Labeled(ident @ LabelIdent(label), tpe, body) => + case Labeled(label, tpe, body) => trampoline { pretransformLabeled(label, if (isStat) VoidType else tpe, body, isStat, usePreTransform = false)(finishTransform(isStat)) @@ -381,8 +381,8 @@ private[optimizer] abstract class OptimizerCore( } case Return(expr, label) => - val info = scope.env.labelInfos(label.name) - val newLabel = LabelIdent(info.newName) + val info = scope.env.labelInfos(label) + val newLabel = info.newName if (info.isStat) { val newExpr = transformStat(expr) info.returnedTypes.value ::= (VoidType, RefinedType.NoRefinedType) @@ -960,7 +960,7 @@ private[optimizer] abstract class OptimizerCore( transformExpr(default))(tree.tpe).toPreTransform) } - case Labeled(ident @ LabelIdent(label), tpe, body) => + case Labeled(label, tpe, body) => pretransformLabeled(label, tpe, body, isStat = false, usePreTransform = true)(cont) @@ -5169,7 +5169,7 @@ private[optimizer] abstract class OptimizerCore( tryOptimizePatternMatch(oldLabelName, newLabel, refinedType, returnCount, newBody) getOrElse { - Labeled(LabelIdent(newLabel), refinedType, newBody) + Labeled(newLabel, refinedType, newBody) } } @@ -5263,7 +5263,7 @@ private[optimizer] abstract class OptimizerCore( if (revAlts.size == returnCount - 1) { def tryDropReturn(body: Tree): Option[Tree] = body match { - case BlockOrAlone(prep, Return(result, LabelIdent(`newLabelName`))) => + case BlockOrAlone(prep, Return(result, `newLabelName`)) => val result1 = if (refinedType == VoidType) keepOnlySideEffects(result) else result diff --git a/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala b/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala index e80affe3bc..7b37ab5648 100644 --- a/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala +++ b/linker/shared/src/test/scala/org/scalajs/linker/OptimizerTest.scala @@ -267,10 +267,10 @@ class OptimizerTest { * optimized code can be linked all the way to the Emitter. */ - val matchResult1 = LabelIdent("matchResult1") + val matchResult1 = LabelName("matchResult1") val x1 = LocalName("x1") - val matchAlts1 = LabelIdent("matchAlts1") - val matchAlts2 = LabelIdent("matchAlts2") + val matchAlts1 = LabelName("matchAlts1") + val matchAlts2 = LabelName("matchAlts2") val results = for (voidReturnArgument <- List(Undefined(), Skip())) yield { val classDefs = Seq( diff --git a/linker/shared/src/test/scala/org/scalajs/linker/testutils/TestIRBuilder.scala b/linker/shared/src/test/scala/org/scalajs/linker/testutils/TestIRBuilder.scala index 528dfb2fcc..d48649c245 100644 --- a/linker/shared/src/test/scala/org/scalajs/linker/testutils/TestIRBuilder.scala +++ b/linker/shared/src/test/scala/org/scalajs/linker/testutils/TestIRBuilder.scala @@ -181,8 +181,6 @@ object TestIRBuilder { implicit def string2LocalIdent(name: String): LocalIdent = LocalIdent(LocalName(name)) - implicit def string2LabelIdent(name: String): LabelIdent = - LabelIdent(LabelName(name)) implicit def string2SimpleFieldIdent(name: String): SimpleFieldIdent = SimpleFieldIdent(SimpleFieldName(name)) implicit def string2ClassIdent(name: String): ClassIdent = diff --git a/project/BinaryIncompatibilities.scala b/project/BinaryIncompatibilities.scala index 7c373ae05f..ec5063ac59 100644 --- a/project/BinaryIncompatibilities.scala +++ b/project/BinaryIncompatibilities.scala @@ -6,8 +6,13 @@ import com.typesafe.tools.mima.core.ProblemFilters._ object BinaryIncompatibilities { val IR = Seq( // !!! Breaking, OK in minor release + ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Printers#IRTreePrinter.print"), ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$JSLinkingInfo"), ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$JSLinkingInfo$"), + ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$LabelIdent"), + ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Trees$LabelIdent$"), + ProblemFilters.exclude[Problem]("org.scalajs.ir.Trees#Labeled.*"), + ProblemFilters.exclude[Problem]("org.scalajs.ir.Trees#Return.*"), ProblemFilters.exclude[Problem]("org.scalajs.ir.Trees#VarRef.*"), ProblemFilters.exclude[IncompatibleResultTypeProblem]("org.scalajs.ir.Trees#*.tpe"), ProblemFilters.exclude[MissingClassProblem]("org.scalajs.ir.Types$NoType$"), @@ -20,6 +25,11 @@ object BinaryIncompatibilities { ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Transformers#Transformer.transformStats"), ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Trees#Transient#Value.transform"), ProblemFilters.exclude[ReversedMissingMethodProblem]("org.scalajs.ir.Trees#Transient#Value.transform"), + + // private, not an issue + ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Serializers#Deserializer.readLabelIdent"), + ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Serializers#Serializer.writeLabelIdent"), + ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.ir.Hashers#TreeHasher.mixLabelIdent"), ) val Linker = Seq(