Skip to content

-Xcheck-macros fails in pismute/classy-optics #18353

Closed
@WojciechMazur

Description

@WojciechMazur

Failure found in OpenCB for pismute/classy-optics - build logs

I'm not sure, but it looks like a false-positive. Can we confirm that?

Compiler version

Since 3.3.0

Minimized code

// macros.scala
import scala.compiletime.*
import scala.deriving.*
import scala.quoted.*

trait Getter[S, A]:
  def view: S => A

trait Lens[S, A] extends Getter[S, A]:
  def set: S => A => S

object Lens {
  inline def apply[S, A](_view: S => A)(_set: S => A => S): Lens[S, A] =
    new Lens[S, A]:
      def view: S => A = _view
      def set: S => A => S = _set

  inline given derived[T <: Product, A]: Lens[T, A] = ${
    ProductMacros.genLens[T, A]
  }
}

object ProductMacros {
  private def indexOf[T: Type, A: Type](using Quotes): Int =
    indexOf0[T, A](0)

  private def indexOf0[T: Type, A: Type](acc: Int)(using Quotes): Int =
    Type.of[T] match
      case '[EmptyTuple]  => -1
      case '[A *: tpes]   => acc
      case '[tpe *: tpes] => indexOf0[tpes, A](acc + 1)

  def genLens[T <: Product: Type, A: Type](using
      q: Quotes
  ): Expr[Lens[T, A]] = {
    import quotes.reflect.*

    Expr
      .summon[Mirror.ProductOf[T]]
      .map {
        case '{
              $m: Mirror.ProductOf[T] { type MirroredElemTypes = elementTypes }
            } =>
          val i = indexOf[elementTypes, A]
          if i < 0 then
            report.errorAndAbort(s"has no the field of ${Type.show[A]}")
          else
            val ii: Expr[Int] = Expr(i)
            val view: Expr[T => A] = '{ t =>
              t.productElement($ii).asInstanceOf[A]
            }
            val set: Expr[T => A => T] = '{ t => a =>
              val arr = Tuple.fromProduct(t).toArray
              arr($ii) = a.asInstanceOf[Object]
              // Check-macros fails here probably
              $m.fromTuple(Tuple.fromArray(arr).asInstanceOf[elementTypes])
            }
            '{ Lens[T, A]($view)($set) }
      }
      .getOrElse(
        report.errorAndAbort(s"${Type.show[T]} is not a product type")
      )

  }
}
// main.scala
//> using options -Xcheck-macros

@main def Test = {
  
  type TupleConfig = (Int, String)

  val tConfig = (1, "string")
  val fails = summon[Lens[TupleConfig, Int]].view(tConfig)
}

Output

scala-cli run  --server=false macros.scala main.scala -S 3.3.0    
Warning: setting /Users/wmazur/projects/sandbox as the project root directory for this run.
-- Error: /Users/wmazur/projects/sandbox/main.scala:8:44 -----------------------
 8 |  val fails = summon[Lens[TupleConfig, Int]].view(tConfig)
   |                                            ^
   |Malformed tree was found while expanding macro with -Xcheck-macros.
   |               |The tree does not conform to the compiler's tree invariants.
   |               |
   |               |Macro was:
   |               |scala.quoted.runtime.Expr.splice[Lens[scala.Tuple2[scala.Int, scala.Predef.String], scala.Int]](((evidence$1: scala.quoted.Quotes) ?=> ProductMacros.genLens[scala.Tuple2[scala.Int, scala.Predef.String], scala.Int](scala.quoted.Type.of[scala.Tuple2[scala.Int, scala.Predef.String]](evidence$1), scala.quoted.Type.of[scala.Int](evidence$1), evidence$1)))
   |               |
   |               |The macro returned:
   |               |Lens.apply[scala.Tuple2[scala.Int, scala.Predef.String], scala.Int](((t: scala.Tuple2[scala.Int, scala.Predef.String]) => t.productElement(0).asInstanceOf[scala.Int]))(((`t₂`: scala.Tuple2[scala.Int, scala.Predef.String]) => ((a: scala.Int) => {
   |  val arr: scala.Array[java.lang.Object] = scala.Tuple.fromProduct(`t₂`).toArray
   |  arr.update(0, a.asInstanceOf[java.lang.Object])
   |  scala.deriving.Mirror.fromTuple[scala.Tuple2[scala.Int, scala.Predef.String]](new scala.runtime.TupleMirror(2).$asInstanceOf$[scala.deriving.Mirror.Product {
   |    type MirroredMonoType >: scala.Tuple2[scala.Int, scala.Predef.String] <: scala.Tuple2[scala.Int, scala.Predef.String]
   |    type MirroredType >: scala.Tuple2[scala.Int, scala.Predef.String] <: scala.Tuple2[scala.Int, scala.Predef.String]
   |    type MirroredLabel >: "Tuple2" <: "Tuple2"
   |    type MirroredElemTypes >: scala.*:[scala.Int, scala.*:[scala.Predef.String, scala.Tuple$package.EmptyTuple]] <: scala.*:[scala.Int, scala.*:[scala.Predef.String, scala.Tuple$package.EmptyTuple]]
   |    type MirroredElemLabels >: scala.*:["_1", scala.*:["_2", scala.Tuple$package.EmptyTuple]] <: scala.*:["_1", scala.*:["_2", scala.Tuple$package.EmptyTuple]]
   |  }])(scala.Tuple.fromArray[java.lang.Object](arr).asInstanceOf[scala.*:[scala.Int, scala.*:[scala.Predef.String, scala.Tuple$package.EmptyTuple]]])
   |})))
   |               |
   |               |Error:
   |               |assertion failed: position not set for 
   |  scala.deriving.Mirror.Product{
   |    type MirroredMonoType = (Int, String); type MirroredType = (Int, String);
   |      type MirroredLabel = ("Tuple2" : String);
   |      type MirroredElemTypes = (Int, String);
   |      type MirroredElemLabels = (("_1" : String), ("_2" : String))
   |  }
   | # -1 of class dotty.tools.dotc.ast.Trees$TypeTree in /Users/wmazur/projects/sandbox/main.scala
   |               |
   |               |
   |----------------------------------------------------------------------------
   |Inline stack trace
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |This location contains code that was inlined from macros.scala:17
17 |  inline given derived[T <: Product, A]: Lens[T, A] = ${
   |                                                      ^
18 |    ProductMacros.genLens[T, A]
19 |  }
    ----------------------------------------------------------------------------
1 error found

Expectation

Is it a false-positive? It does not look like one

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions