Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
sageserpent-open opened this issue Nov 19, 2024 · 0 comments

Comments

@sageserpent-open
Copy link

sageserpent-open commented Nov 19, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant