optics-dev / optics-dev/Monocle

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

Open
#1,482 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Scala
Stars
1.7k
Forks
207
Avg merge
7h 59m
Merged PRs (30d)
5

Description

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.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the Scastie example with Scala 3.3.4 and Monocle 3.3.0, focusing on the .focus(_.steps).modify(...) expansion. Start with monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldGenerator.scala at the stack-trace location and compare the explicit field type with the Steps alias. Done means identifying whether the failure belongs to Monocle or the Scala compiler and adding a regression test or documented conclusion.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.