zio / izumi-reflect

TypeTag without scala-reflect. Supports Scala 2 and Scala 3.
https://zio.dev/izumi-reflect
Other
140 stars 35 forks source link

Subtype relation for refined type fails #481

Open thierry-st opened 2 weeks ago

thierry-st commented 2 weeks ago

izumi.reflect.Tag subtype relationship is not faithful to compiled ones.

Here is a minimal repro (Scala 2 syntax to allow testing various versions):

import izumi.reflect.Tag

trait A {
  type T
}

trait AInt extends A {
  override type T = Int
}

object App extends App {
  implicitly[AInt <:< A { type T = Int }] // true
  println(Tag[AInt].tag <:< Tag[A { type T = Int }].tag) // false
}

Scastie link

It might be more efficient to tackle this issue and #469 both at once, but they seemed different enough to me to warrant different posts.

It might help to know that the issue is not present for Scala >= 3.2 and izumi-reflect =< 2.2.5. But the issue is present if violating any of these bounds (Scala 2 and/or izumi-reflect >= 2.3.0).

I will report soon the corresponding issue on the ZIO repo.

thierry-st commented 2 weeks ago

Here is the link to the corresponding ZIO issue: #9210

pshirshov commented 2 weeks ago

We would need to preserve full member information in order to support this. Doable but not easy. My primary concerns are tag size and performance.

neko-kai commented 2 weeks ago

@thierry-st Version 2.3.0 is the one that added structural type / refinement support to Scala 3 version. Before that, the comparison on Scala 3 was only between AInt and A, ignoring the refinement, that's why it succeeded on previous versions.

Currently type/value members are not present at all in izumi-reflect type model for concrete types - they only arise when comparisons between refinements happen.

Since there's no data about type T in AInt tag, the comparison with any refinement will fail.

Changing the design and adding type member data is possible, but not trivial.

(#469 is unfortunately not related)

neko-kai commented 2 weeks ago

@thierry-st Does this limitation of the model make some real-world usages too painful? If not, we'll probably not work on fixing this – although we will accept pull requests.

For now, I've added this issue to the list of known limitations.

Note that the more common opposite case, e.g. Aux pattern, where a refinement is a subtype of a concrete type, is supported.

thierry-st commented 2 weeks ago

Thanks very much for the clear explanations and the addition to known limitations!

As for painfulness of real-world usages, in the ZIO environment, the limitation can easily be overcome. So the only downside is cognitive cost (ZIO users need to be aware of this issue). Since nobody reacted so far on the ZIO issue, I'm inclined to leave it as is.

Just to let people know, I'm not going to attempt a PR for this, so feel free to go for it!