Skip to content

Macro expansion raises an error when type of field is written in long hand. #1482

@sageserpent-open

Description

@sageserpent-open

A Scastie is provided here...

Scala 3.3.4,

SBT includes Monocle dependency of:

    libraryDependencies ++= Seq(
      "dev.optics" %% "monocle-core"  % "3.3.0",
      "dev.optics" %% "monocle-macro" % "3.3.0"
    )
import monocle.syntax.all.*

trait Algebra[Result[_], Element]:
  def empty: Result[Element]
  def addSomething(
      partialResult: Result[Element],
      newData: String
  ): Result[Element]
end Algebra

def weeklyGrind[Result[_], Element](
    algebra: Algebra[Result, Element]
): Result[Element] =
  val monday = algebra.empty
  val tuesday = algebra.addSomething(monday, "A hard working day.")
  // Long weekend follows...
  tuesday
end weeklyGrind

type Steps[Element] =
  Vector[[Result[Element]] => Algebra[Result, Element] => Result[
    Element
  ] => Result[Element]] 
// Polymorphic because we don't know what kind of result
// the downstream algebra will work with.

case class Recording[Element](steps: Vector[[Result[Element]] => Algebra[Result, Element] => Result[
    Element
  ] => Result[Element]]):
  // Changing to the commented out definition fixes the Monocle error...
/*case class Recording[Element](steps: Steps[Element]):*/
  def playback[Result[Element]](
      algebra: Algebra[Result, Element]
  ): Result[Element] =
    steps.foldLeft(algebra.empty)((partialResult, step) =>
      step(algebra)(partialResult)
    )

class RecordingAlgebra[Element] extends Algebra[Recording, Element]:
  def empty: Recording[Element] =
    Recording(steps = Vector.empty)
  def addSomething(
      partialResult: Recording[Element],
      newData: String
  ): Recording[Element] =
    partialResult
      .focus(_.steps)
      .modify(
        _.appended(
          [Result[_]] =>
            (downstreamAlgebra: Algebra[Result, Element]) =>
              downstreamAlgebra.addSomething(_, newData)
        )
      )
end RecordingAlgebra

val onTheRecord = weeklyGrind(new RecordingAlgebra)

Note the alternative definition of Recording:

case class Recording[Element](steps: Vector[[Result[Element]] => Algebra[Result, Element] => Result[
    Element
  ] => Result[Element]]):
  // Changing to the commented out definition fixes the Monocle error...
/*case class Recording[Element](steps: Steps[Element]):*/

In the uncommented form, the macro expansion of the .focus(_.steps).modify(...) call in RecordingAlgebra fails with:

Exception occurred while executing macro expansion.
scala.quoted.runtime.impl.ExprCastException: 
  Expected type: 
    scala.collection.immutable.Vector[scala.PolyFunction {
      val apply: [Result _ >: scala.Nothing <: [Element >: scala.Nothing <: scala.Any] => scala.Any](x$1: Playground.Algebra[Result, Recording.this.Element])scala.Function1[Result[Recording.this.Element], Result[Recording.this.Element]]
    }]

  Actual type: from.steps
  Expression: from.steps

	at scala.quoted.runtime.impl.ExprCastException$.apply(ExprCastException.scala:15)
	at scala.quoted.runtime.impl.QuotesImpl.asExprOf(QuotesImpl.scala:75)
	at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:123)
	at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:122)
	at monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldGenerator.generateSelectOnlyField$$anonfun$1$$anonfun$1(SelectOnlyFieldGenerator.scala:24)
	at monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldGenerator.generateSelectOnlyField$$anonfun$1(SelectOnlyFieldGenerator.scala:24)
	at monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldGenerator.generateSelectOnlyField$$anonfun$adapted$1(SelectOnlyFieldGenerator.scala:25)
	at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:110)

Using the commented form uses an equivalent type alias, and compiles correctly.

I'm not sure if this is down to Monocle, or is an issue with the Scala compiler itself.

The workaround is available (and looks better anyway), but I've raised this in case there is a deeper issue - but it's not urgent for me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions