Monocle icon indicating copy to clipboard operation
Monocle copied to clipboard

Ambient `opaque type` breaks `MkFocus`

Open armanbilge opened this issue 2 years ago • 4 comments

//> using scala "3.2.0"
//> using lib "dev.optics::monocle-macro::3.1.0"

trait Qux

object Foo {

  opaque type Bar = Qux

  case class Baz(id: String)
  object Baz {
    implicit val bazId: monocle.Lens[Foo.Baz, String] = new monocle.Focus.MkFocus[Foo.Baz].apply(_.id)
  }

}
[error] ./bug.scala:12:57: Found:    monocle.PIso[?1.CAP, ?2.CAP, String, String]
[error] Required: monocle.Lens[Foo.Baz, String]
[error] 
[error] where:    ?1 is an unknown value of type scala.runtime.TypeBox[Nothing, Foo.type{Bar = Qux}#Baz]
[error]           ?2 is an unknown value of type scala.runtime.TypeBox[Nothing, Foo.type{Bar = Qux}#Baz]
[error]     implicit val bazId: monocle.Lens[Foo.Baz, String] = new monocle.Focus.MkFocus[Foo.Baz].apply(_.id)
[error]                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

armanbilge avatar Oct 11 '22 19:10 armanbilge

Workaround.

//> using scala "3.2.0"
//> using lib "dev.optics::monocle-macro::3.1.0"

trait Qux

object Foo {

  opaque type Bar = Qux

  case class Baz(id: String)
  object Baz {
    implicit val bazId: monocle.Lens[Foo.Baz, String] = {
      type Bla = Foo.Baz // <-- workaround
      new monocle.Focus.MkFocus[Bla].apply(_.id)
    }
  }

}

armanbilge avatar Oct 12 '22 16:10 armanbilge

Users aren't expected to use MkFocus directly. Do you have the same issue with Focus?

Focus[Foo.Baz, String](_.id)

It is really weird that a useless opaque type break the macro. Was it also the case in previous version of Scala 3?

Thanks for reporting the issue.

julien-truffaut avatar Oct 13 '22 14:10 julien-truffaut

Users aren't expected to use MkFocus directly. Do you have the same issue with Focus?

Right, sorry :) if you check the edit history the initial report was in terms of GenLens. Switching to MkFocus was intended as minimization.

It is really weird that a useless opaque type break the macro. Was it also the case in previous version of Scala 3?

I think so, but I will doube-check. Edit: I can reproduce with Scala 3.1.0.

FWIW this is likely a compiler bug.

armanbilge avatar Oct 13 '22 14:10 armanbilge

I think this is possibly intended behaviour by the compiler but weird as heck.

Here's the error message which we get in 3.3:

[error] 10 |    implicit val bazId: monocle.Lens[Foo.Baz, String] = monocle.Focus[Foo.Baz](_.id)
[error]    |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |               Found:    monocle.PIso[? <: Foo.type{type Bar = Qux}#Baz,
[error]    |                 ? <: Foo.type{type Bar = Qux}#Baz, String, String]
[error]    |               Required: monocle.Lens[Foo.Baz, String]

It looks as though we capture the opaque type within the Foo type (widen and dealias don't do anything btw) and since PIso doesn't have variance, we get issues with the explicit type ascription. I think that Foo{ ... }#Baz is a subtype of Foo.Baz but I'm not entirely sure about subtyping rules in this case honestly and need to double check.

The real fix is to add variance properly if it works imo, but I think we ran into issues with that previously with inference problems in scala 2. @julien-truffaut will remember better than me.

We could probably strip the captured opaque type for now.

yilinwei avatar Dec 22 '23 12:12 yilinwei