Skip to content

Commit a888e09

Browse files
committed
Fix compilation of lenses with context bounds in Scala 3
Fixes #1259
1 parent 21a37a0 commit a888e09

File tree

5 files changed

+60
-20
lines changed

5 files changed

+60
-20
lines changed

core/shared/src/main/scala-3.x/monocle/internal/focus/features/GeneratorLoop.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import scala.quoted.Type
1414

1515
private[focus] trait AllFeatureGenerators
1616
extends FocusBase
17+
with SelectGeneratorBase
1718
with SelectFieldGenerator
1819
with SelectOnlyFieldGenerator
1920
with SomeGenerator
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package monocle.internal.focus.features
2+
3+
import monocle.internal.focus.FocusBase
4+
import scala.annotation.tailrec
5+
6+
private[focus] trait SelectGeneratorBase {
7+
this: FocusBase =>
8+
9+
import this.macroContext.reflect._
10+
11+
def generateGetter(from: Term, fieldName: String): Term =
12+
Select.unique(from, fieldName) // o.field
13+
14+
@tailrec
15+
final def etaExpandIfNecessary(term: Term): Term = {
16+
if (term.isExpr) {
17+
term
18+
} else {
19+
val expanded: Term = term.etaExpand(Symbol.spliceOwner)
20+
21+
val implicits: List[Term] = expanded match {
22+
case Block(List(DefDef(_, List(params), _, _)), _) =>
23+
params.params.map {
24+
case ValDef(_, t, _) =>
25+
val typeRepr: TypeRepr = t.tpe.dealias
26+
Implicits.search(typeRepr) match {
27+
case success: ImplicitSearchSuccess => success.tree
28+
case _ => report.errorAndAbort(
29+
s"Couldn't find assumed implicit for ${typeRepr.show}. Neither " +
30+
s"multiple (non-implicit) parameter sets nor default arguments for implicits are supported."
31+
)
32+
}
33+
case other => report.errorAndAbort(
34+
s"Expected a value definition as parameter but found $other."
35+
)
36+
}
37+
case other => report.errorAndAbort(
38+
s"Expected code block with eta expanded function but found $other."
39+
)
40+
}
41+
42+
etaExpandIfNecessary(Apply(term, implicits))
43+
}
44+
}
45+
}

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectfield/SelectFieldGenerator.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
package monocle.internal.focus.features.selectfield
22

33
import monocle.internal.focus.FocusBase
4+
import monocle.internal.focus.features.SelectGeneratorBase
45
import monocle.Lens
5-
import scala.quoted.Quotes
66

77
private[focus] trait SelectFieldGenerator {
8-
this: FocusBase =>
8+
this: FocusBase with SelectGeneratorBase =>
99

1010
import macroContext.reflect._
1111

1212
def generateSelectField(action: FocusAction.SelectField): Term = {
1313
import action.{fieldName, fromType, fromTypeArgs, toType}
1414

15-
def generateGetter(from: Term): Term =
16-
Select.unique(from, fieldName) // o.field
17-
1815
def generateSetter(from: Term, to: Term): Term =
19-
Select.overloaded(from, "copy", fromTypeArgs, NamedArg(fieldName, to) :: Nil) // o.copy(field = value)
16+
// o.copy(field = value)(implicits)*
17+
etaExpandIfNecessary(Select.overloaded(from, "copy", fromTypeArgs, NamedArg(fieldName, to) :: Nil))
2018

2119
(fromType.asType, toType.asType) match {
2220
case ('[f], '[t]) =>
2321
'{
24-
Lens.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm).asExprOf[t] })((to: t) =>
22+
Lens.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm, fieldName).asExprOf[t] })((to: t) =>
2523
(from: f) => ${ generateSetter('{ from }.asTerm, '{ to }.asTerm).asExprOf[f] }
2624
)
2725
}.asTerm

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectonlyfield/SelectOnlyFieldGenerator.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,25 @@
11
package monocle.internal.focus.features.selectonlyfield
22

33
import monocle.internal.focus.FocusBase
4+
import monocle.internal.focus.features.SelectGeneratorBase
45
import monocle.Iso
5-
import scala.quoted.Quotes
66

77
private[focus] trait SelectOnlyFieldGenerator {
8-
this: FocusBase =>
8+
this: FocusBase with SelectGeneratorBase =>
99

1010
import macroContext.reflect._
1111

1212
def generateSelectOnlyField(action: FocusAction.SelectOnlyField): Term = {
1313
import action.{fieldName, fromType, fromTypeArgs, fromCompanion, toType}
1414

15-
def generateGetter(from: Term): Term =
16-
Select.unique(from, fieldName) // o.field
17-
1815
def generateReverseGet(to: Term): Term =
19-
Select.overloaded(fromCompanion, "apply", fromTypeArgs, List(to)) // Companion.apply(value)
16+
// Companion.apply(value)(implicits)*
17+
etaExpandIfNecessary(Select.overloaded(fromCompanion, "apply", fromTypeArgs, List(to)))
2018

2119
(fromType.asType, toType.asType) match {
2220
case ('[f], '[t]) =>
2321
'{
24-
Iso.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm).asExprOf[t] })((to: t) =>
22+
Iso.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm, fieldName).asExprOf[t] })((to: t) =>
2523
${ generateReverseGet('{ to }.asTerm).asExprOf[f] }
2624
)
2725
}.asTerm

macro/src/test/scala-2.x/monocle/macros/internal/ContextBoundCompilationIssueSpec.scala renamed to macro/src/test/scala/monocle/macros/internal/ContextBoundCompilationIssueSpec.scala

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,16 @@ class ContextBoundCompilationIssueSpec extends DisciplineSuite {
99
private trait Foo[T]
1010
private trait Bar[T]
1111

12-
private case class A[T: Foo](s: A.S[T]) {
13-
val lens: Lens[A.S[T], Bar[T]] = GenLens[A.S[T]](_.bar)
12+
private case class A[T: Foo](s: S[T]) {
13+
val lens: Lens[S[T], Bar[T]] = GenLens[S[T]](_.bar)
1414
}
1515

16-
private object A {
17-
case class S[T: Foo](bar: Bar[T])
18-
}
16+
private case class S[T: Foo](bar: Bar[T])
1917

2018
private case object FooImpl extends Foo[Unit]
2119
private case object BarImpl extends Bar[Unit]
2220

23-
private val a: A[Unit] = A(A.S(BarImpl)(FooImpl))(FooImpl)
21+
private val a: A[Unit] = A(S(BarImpl)(FooImpl))(FooImpl)
2422

2523
test("context.bound.compilation") {
2624
assertEquals(a.lens.get(a.s), BarImpl)

0 commit comments

Comments
 (0)