From 1808a326fc2cdb0c95b97bc581ae58bedb2b8a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Sat, 4 Apr 2026 17:46:47 +0200 Subject: [PATCH] Add support for the into modifier. --- build.sbt | 1 + .../src/main/scala/tastyquery/Flags.scala | 1 + .../src/main/scala/tastyquery/Symbols.scala | 3 +++ .../tastyquery/reader/tasties/TastyFormat.scala | 7 +++++-- .../reader/tasties/TreeUnpickler.scala | 1 + .../test/scala/tastyquery/ReadTreeSuite.scala | 17 +++++++++++++++++ .../main/scala/simple_trees/IntoModifier.scala | 15 +++++++++++++++ 7 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 test-sources/src/main/scala/simple_trees/IntoModifier.scala diff --git a/build.sbt b/build.sbt index 9e4bc030..0672200f 100644 --- a/build.sbt +++ b/build.sbt @@ -80,6 +80,7 @@ lazy val testSources = crossProject(JSPlatform, JVMPlatform) .settings( publish / skip := true, scalacOptions += "-Werror", + scalacOptions += "-preview", javacOptions += "-parameters", ) .dependsOn(scala2TestSources) diff --git a/tasty-query/shared/src/main/scala/tastyquery/Flags.scala b/tasty-query/shared/src/main/scala/tastyquery/Flags.scala index ef857437..eddb662d 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/Flags.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/Flags.scala @@ -60,6 +60,7 @@ private[tastyquery] object Flags: val Infix: Flag = newFlag("Infix") val Inline: Flag = newFlag("Inline") val InlineProxy: Flag = newFlag("InlineProxy") + val Into: Flag = newFlag("Into") val JavaDefined: Flag = newFlag("JavaDefined") val Lazy: Flag = newFlag("Lazy") val Local: Flag = newFlag("Local") diff --git a/tasty-query/shared/src/main/scala/tastyquery/Symbols.scala b/tasty-query/shared/src/main/scala/tastyquery/Symbols.scala index 13aab272..84fa5f3a 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/Symbols.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/Symbols.scala @@ -692,6 +692,9 @@ object Symbols { final def isOpaqueTypeAlias: Boolean = flags.is(Opaque) + /** Is this a type with the `into` modifier? */ + final def isIntoType: Boolean = flags.is(Into) + private[tastyquery] final def topLevelRef: TypeRef = require(owner.isPackage, s"Cannot construct a topLevelRef for non-top-level symbol $this") TypeRef(owner.asPackage.packageRef, this) diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala index 018361ce..245c3309 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TastyFormat.scala @@ -224,6 +224,7 @@ import scala.annotation.switch * EXPORTED -- An export forwarder * OPEN -- an open class * INVISIBLE -- invisible during typechecking + * INTO -- has the `into` modifier * Annotation * * Variance = STABLE -- invariant @@ -489,6 +490,7 @@ private[tasties] object TastyFormat: final val INVISIBLE = 44 final val EMPTYCLAUSE = 45 final val SPLITCLAUSE = 46 + final val INTO = 49 // Cat. 2: tag Nat @@ -614,7 +616,7 @@ private[tasties] object TastyFormat: /** Useful for debugging */ def isLegalTag(tag: Int): Boolean = - firstSimpleTreeTag <= tag && tag <= SPLITCLAUSE + firstSimpleTreeTag <= tag && tag <= INTO || firstNatTreeTag <= tag && tag <= RENAMED || firstASTTreeTag <= tag && tag <= BOUNDED || firstNatASTTreeTag <= tag && tag <= NAMEDARG @@ -628,7 +630,7 @@ private[tasties] object TastyFormat: case PRIVATE | PROTECTED | ABSTRACT | FINAL | SEALED | CASE | IMPLICIT | GIVEN | ERASED | LAZY | OVERRIDE | INLINE | INLINEPROXY | MACRO | OPAQUE | STATIC | OBJECT | TRAIT | TRANSPARENT | INFIX | ENUM | LOCAL | SYNTHETIC | ARTIFACT | MUTABLE | FIELDaccessor | CASEaccessor | COVARIANT | CONTRAVARIANT | HASDEFAULT | STABLE | - EXTENSION | PARAMsetter | PARAMalias | EXPORTED | OPEN | INVISIBLE | ANNOTATION | PRIVATEqualified | + EXTENSION | PARAMsetter | PARAMalias | EXPORTED | OPEN | INVISIBLE | INTO | ANNOTATION | PRIVATEqualified | PROTECTEDqualified => true case _ => @@ -687,6 +689,7 @@ private[tasties] object TastyFormat: case PARAMalias => "PARAMalias" case EMPTYCLAUSE => "EMPTYCLAUSE" case SPLITCLAUSE => "SPLITCLAUSE" + case INTO => "INTO" case SHAREDterm => "SHAREDterm" case SHAREDtype => "SHAREDtype" diff --git a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TreeUnpickler.scala b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TreeUnpickler.scala index 3fcca481..34e9aaa2 100644 --- a/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TreeUnpickler.scala +++ b/tasty-query/shared/src/main/scala/tastyquery/reader/tasties/TreeUnpickler.scala @@ -328,6 +328,7 @@ private[tasties] class TreeUnpickler private ( case INVISIBLE => ignoreFlag() case TRANSPARENT => addFlag(Transparent) case INFIX => addFlag(Infix) + case INTO => addFlag(Into) case PRIVATEqualified => ignoreFlag() skipTree() diff --git a/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala b/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala index fd5105c7..47344440 100644 --- a/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala +++ b/tasty-query/shared/src/test/scala/tastyquery/ReadTreeSuite.scala @@ -2411,4 +2411,21 @@ class ReadTreeSuite extends RestrictedUnpicklingSuite { } assert(containsSubtree(myMapStructure)(clue(myMapDef))) } + + testUnpickle("into-modifier", "simple_trees.IntoModifier") { tree => + val intoClass: StructureCheck = { + case ClassDef(SimpleTypeName("IntoClass"), _, sym) if sym.isIntoType => + } + assert(containsSubtree(intoClass)(clue(tree))) + + val intoTrait: StructureCheck = { + case ClassDef(SimpleTypeName("IntoTrait"), _, sym) if sym.isIntoType => + } + assert(containsSubtree(intoTrait)(clue(tree))) + + val intoEnum: StructureCheck = { + case ClassDef(SimpleTypeName("IntoEnum"), _, sym) if sym.isIntoType => + } + assert(containsSubtree(intoEnum)(clue(tree))) + } } diff --git a/test-sources/src/main/scala/simple_trees/IntoModifier.scala b/test-sources/src/main/scala/simple_trees/IntoModifier.scala new file mode 100644 index 00000000..3abe5118 --- /dev/null +++ b/test-sources/src/main/scala/simple_trees/IntoModifier.scala @@ -0,0 +1,15 @@ +package simple_trees + +import scala.Conversion.into + +class IntoModifier { + def methodWithIntoString(x: into[String]): Unit = () + + into class IntoClass + + into trait IntoTrait + + into enum IntoEnum { + case Foo + } +}