Repository: scalameta/scalameta
Pull request #3456 (2024-01-03 05:29:07)

TokenStreamPosition: move inline in Origin.Parsed
Helps with #3425. Extracted from #3454.


Patch:
diff --git a/scalameta/common/shared/src/main/scala/org/scalameta/adt/Liftables.scala b/scalameta/common/shared/src/main/scala/org/scalameta/adt/Liftables.scala
index 3a97cfca0..f1b2adbe9 100644
--- a/scalameta/common/shared/src/main/scala/org/scalameta/adt/Liftables.scala
+++ b/scalameta/common/shared/src/main/scala/org/scalameta/adt/Liftables.scala
@@ -1,6 +1,7 @@
 package org.scalameta.adt
 
 import scala.language.experimental.macros
+import scala.language.implicitConversions
 import scala.meta.internal.trees.AstNamerMacros
 import scala.reflect.macros.blackbox.Context
 import org.scalameta.adt.Metadata.Adt
@@ -9,7 +10,8 @@ import org.scalameta.adt.{Reflection => AdtReflection}
 // Implementation of the scala.reflect.api.Universe#Liftable interface for adts.
 trait Liftables {
   val u: scala.reflect.macros.Universe
-  implicit def materializeAdt[T <: Adt]: u.Liftable[T] = macro LiftableMacros.impl[T]
+  implicit def materializeAdt[T <: Adt](isPrivateOKExpr: Boolean): u.Liftable[T] =
+    macro LiftableMacros.impl[T]
 }
 
 class LiftableMacros(val c: Context) extends AdtReflection {
@@ -20,7 +22,8 @@ class LiftableMacros(val c: Context) extends AdtReflection {
   def customMatcher(adt: Adt, defName: TermName, localName: TermName): Option[DefDef] = None
   def customWrapper(adt: Adt, defName: TermName, localName: TermName, body: Tree): Option[Tree] =
     None
-  def impl[T: WeakTypeTag]: c.Tree = {
+  def impl[T: WeakTypeTag](isPrivateOKExpr: c.Expr[Boolean]): c.Tree = {
+    val isPrivateOK = c.eval(isPrivateOKExpr)
     val root = weakTypeOf[T].typeSymbol.asAdt.root
     val unsortedAdts = customAdts(root).getOrElse(root.allLeafs)
     val adts = {
@@ -66,7 +69,7 @@ class LiftableMacros(val c: Context) extends AdtReflection {
           parts.foldLeft(init) { (acc, part) => q"$u.Select($acc, $u.TermName($part))" }
         val nameParts = adt.sym.fullName.split('.')
         val body = if (adt.sym.isClass) {
-          val fields = adt match { case leaf: Leaf => leaf.fields; case _ => Nil }
+          val fields = adt match { case leaf: Leaf => leaf.fields(isPrivateOK); case _ => Nil }
           val args = fields.map { f =>
             q"_root_.scala.Predef.implicitly[$u.Liftable[${f.tpe}]].apply($localName.${f.name})"
             // NOTE: we can't really use AssignOrNamedArg here, sorry
@@ -83,7 +86,7 @@ class LiftableMacros(val c: Context) extends AdtReflection {
             latestAfterVersion :: Nil
           } else Nil
           val namePath = getNamePath(nameParts ++ latestAfterVersion)
-          q"""$u.Apply($namePath, $args)"""
+          q"$u.Apply($namePath, $args)"
         } else getNamePath(nameParts)
         q"def $defName($localName: ${adt.tpe}): $u.Tree = $body"
       }
@@ -109,6 +112,7 @@ class LiftableMacros(val c: Context) extends AdtReflection {
           implicit def $mainMethod[T <: ${root.sym}]: $u.Liftable[T] = $u.Liftable(($localName: T) => {
             $localName match {
               case ..$clauses
+              case null => null
               case _ => sys.error("none of leafs matched " + $localName.getClass)
             }
           })
diff --git a/scalameta/common/shared/src/main/scala/scala/meta/internal/trees/Liftables.scala b/scalameta/common/shared/src/main/scala/scala/meta/internal/trees/Liftables.scala
index 3896cc04b..64814463b 100644
--- a/scalameta/common/shared/src/main/scala/scala/meta/internal/trees/Liftables.scala
+++ b/scalameta/common/shared/src/main/scala/scala/meta/internal/trees/Liftables.scala
@@ -3,6 +3,7 @@ package internal
 package trees
 
 import scala.language.experimental.macros
+import scala.language.implicitConversions
 import scala.reflect.macros.blackbox.Context
 import org.scalameta.adt.{LiftableMacros => AdtLiftableMacros}
 import scala.meta.internal.trees.{Reflection => AstReflection}
@@ -11,7 +12,8 @@ import scala.meta.internal.trees.Metadata.Ast
 // Implementation of the scala.reflect.api.Universe#Liftable interface for asts.
 trait Liftables {
   val u: scala.reflect.macros.Universe
-  implicit def materializeAst[T <: Ast]: u.Liftable[T] = macro LiftableMacros.impl[T]
+  implicit def materializeAst[T <: Ast](isPrivateOKExpr: Boolean): u.Liftable[T] =
+    macro LiftableMacros.impl[T]
 }
 
 class LiftableMacros(override val c: Context) extends AdtLiftableMacros(c) with AstReflection {
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/Pos.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/Pos.scala
index 9733b7743..558f03108 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/Pos.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/Pos.scala
@@ -24,8 +24,7 @@ class IndexPos(index: => Int) extends Pos {
 class TreePos(tree: Tree) extends Pos {
   val (startTokenPos, endTokenPos) = tree.origin match {
     case x: Origin.Parsed =>
-      val pos = x.pos
-      (pos.start, pos.end - 1)
+      (x.begTokenIdx, x.endTokenIdx - 1)
     case _ =>
       sys.error(s"internal error: unpositioned prototype ${tree.syntax}: ${tree.structure}")
   }
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
index 9790d9acc..d0ed02e27 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
@@ -353,8 +353,7 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
     val start = getStart(startPos)
     val end = if (endPos < startPos) startPos - 1 else getEnd(endPos)
     val endExcl = if (start == end && tokens(start).is[Trivia]) end else end + 1
-    val pos = TokenStreamPosition(start, endExcl)
-    body.withOrigin(Origin.Parsed(originSource, pos))
+    body.withOrigin(Origin.Parsed(originSource, start, endExcl))
   }
 
   def atPosTry[T <: Tree](start: StartPos, end: EndPos)(body: => Try[T]): Try[T] = {
diff --git a/scalameta/quasiquotes/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala b/scalameta/quasiquotes/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala
index 84583f7e4..7e9effe74 100644
--- a/scalameta/quasiquotes/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala
+++ b/scalameta/quasiquotes/shared/src/main/scala/scala/meta/internal/quasiquotes/ReificationMacros.scala
@@ -14,7 +14,6 @@ import org.scalameta.invariants._
 
 import scala.annotation.tailrec
 import scala.meta.dialects
-import scala.meta.internal.tokens.TokenStreamPosition
 import scala.meta.internal.trees.{Liftables => AstLiftables, Reflection => AstReflection, _}
 import scala.meta.internal.parsers.Messages
 import scala.meta.internal.parsers.Absolutize._
@@ -363,24 +362,20 @@ class ReificationMacros(val c: Context) extends AstReflection with AdtLiftables
       val liftOrigin: Origin => ReflectTree =
         if (mode.holes.isEmpty) // otherwise, syntax will not make much sense
           _ match {
-            case x: Origin.Parsed =>
-              q"""
-                _root_.scala.meta.internal.trees.Origin.Parsed(
-                  $sourceName,
-                  ${liftTokenStreamPosition(x.pos)}
-                )
-              """
+            case Origin.Parsed(_, beg, end) =>
+              q"_root_.scala.meta.internal.trees.Origin.Parsed($sourceName, $beg, $end)"
             case _ => originNone
           }
         else _ => originNone
-      def liftTokenStreamPosition(obj: TokenStreamPosition): ReflectTree =
-        q"_root_.scala.meta.internal.tokens.TokenStreamPosition(${obj.start}, ${obj.end})"
     }
     object Liftables {
       // NOTE: we could write just `implicitly[Liftable[MetaTree]].apply(meta)`
       // but that would bloat the code significantly with duplicated instances for denotations and sigmas
-      implicit def liftableSubTree[T <: MetaTree]: Liftable[T] =
-        Liftable((tree: T) => materializeAst[MetaTree].apply(tree))
+      implicit val liftableSubTree: Liftable[MetaTree] =
+        if (isTerm)
+          materializeAst[MetaTree](true)
+        else
+          materializeAst[MetaTree](false)
       implicit def liftableSubSeqTree[T <: MetaTree]: Liftable[Seq[T]] =
         Liftable((trees: Seq[T]) => Lifts.liftTrees(trees))
       implicit def liftableSubTrees[T <: MetaTree]: Liftable[List[T]] =
@@ -393,8 +388,6 @@ class ReificationMacros(val c: Context) extends AstReflection with AdtLiftables
         Liftable((x: Option[T]) => Lifts.liftOptionTree(x))
       implicit def liftableOrigin[T <: Origin]: Liftable[T] =
         Liftable((x: T) => Lifts.liftOrigin(x))
-      implicit def liftableTokenStreamPosition[T <: TokenStreamPosition]: Liftable[T] =
-        Liftable((x: T) => Lifts.liftTokenStreamPosition(x))
     }
     mode match {
       case Mode.Term(_, _) =>
diff --git a/scalameta/tokens/shared/src/main/scala/scala/meta/internal/tokens/TokenStreamPosition.scala b/scalameta/tokens/shared/src/main/scala/scala/meta/internal/tokens/TokenStreamPosition.scala
deleted file mode 100644
index 1c3143595..000000000
--- a/scalameta/tokens/shared/src/main/scala/scala/meta/internal/tokens/TokenStreamPosition.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-package scala.meta
-package internal
-package tokens
-
-import org.scalameta.data._
-
-// NOTE: `start` and `end` are not characters offsets,
-// but token indices in the underlying token stream.
-// Also `start` and `end` are String.substring-style,
-// i.e. `start` is inclusive and `end` is not.
-// Therefore TokenStreamPosition.end can point to the last token plus one.
-@data class TokenStreamPosition(start: Int, end: Int)
diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
index e70ad4561..b0c979f51 100644
--- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
+++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/prettyprinters/TreeSyntax.scala
@@ -1136,9 +1136,6 @@ object TreeSyntax {
     // I expect to improve on this in the nearest future, because we had it much better until recently.
     Syntax { (x: T) =>
       x.origin match {
-        // NOTE: Options don't really matter,
-        // because if we've parsed a tree, it's not gonna contain lazy seqs anyway.
-        // case Origin.Parsed(_, originalDialect, _) if dialect == originalDialect && options == Options.Eager =>
         case o: Origin.Parsed if o.dialect eq dialect => s(o.position.text)
         case _ => reprint(x)(dialect)
       }
diff --git a/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/Origin.scala b/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/Origin.scala
index 9b97b79a1..4af9a5db2 100644
--- a/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/Origin.scala
+++ b/scalameta/trees/shared/src/main/scala/scala/meta/internal/trees/Origin.scala
@@ -6,7 +6,6 @@ import org.scalameta.adt
 
 import scala.meta.common._
 import scala.meta.inputs._
-import scala.meta.internal.tokens._
 import scala.meta.tokenizers._
 import scala.meta.tokens._
 
@@ -21,19 +20,20 @@ object Origin {
     val position: Position = Position.None
   }
 
+  // `begTokenIdx` and `endTokenIdx` are half-open interval of index range
   @adt.leaf
-  class Parsed(source: ParsedSource, pos: TokenStreamPosition) extends Origin {
+  class Parsed(source: ParsedSource, begTokenIdx: Int, endTokenIdx: Int) extends Origin {
     @inline private def tokenize() = source.tokens
 
     def position: Position = {
       val tokens = tokenize()
-      val start = tokens(pos.start).start
-      val end = tokens(pos.end - 1).end
+      val start = tokens(begTokenIdx).start
+      val end = tokens(endTokenIdx - 1).end
       Position.Range(input, start, end)
     }
 
     def tokens: Tokens = {
-      tokenize().slice(pos.start, pos.end)
+      tokenize().slice(begTokenIdx, endTokenIdx)
     }
 
     @inline def input: Input = source.input


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
index b97b68c17..7b9d1f1e7 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/prettyprinters/SyntacticSuite.scala
@@ -2,7 +2,6 @@ package scala.meta.tests
 package prettyprinters
 
 import scala.meta._
-import scala.meta.internal.tokens.TokenStreamPosition
 import scala.meta.internal.trees.Origin
 import scala.meta.prettyprinters.Show
 
@@ -1823,8 +1822,7 @@ class SyntacticSuite extends scala.meta.tests.parsers.ParseSuite {
     val syntax = "('\\n', '\\n')"
     val tree = super.term(expr)
     val charN = Lit.Char('\n')
-    val originSource = new Origin.ParsedSource(Input.String(exprU))
-    val origin = Origin.Parsed(originSource, TokenStreamPosition(1, 2))
+    val origin = Origin.Parsed(new Origin.ParsedSource(Input.String(exprU)), 1, 2)
     val charU = charN.withOrigin(origin)
     checkTree(tree, expr) {
       Term.Tuple(List(charN, charU))