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

FromExpr of a Tuple fails to compile when matched via quotes #16536

Closed
hmf opened this issue Dec 15, 2022 · 1 comment
Closed

FromExpr of a Tuple fails to compile when matched via quotes #16536

hmf opened this issue Dec 15, 2022 · 1 comment
Labels
area:metaprogramming:quotes Issues related to quotes and splices

Comments

@hmf
Copy link

hmf commented Dec 15, 2022

Compiler version

Scala versions 3.2.0, 3.2.1-RC2 and 3.2.1

Minimized code

Code below shows my attempts to obtain the values of a Tuple2 (available in scastie). Was unable to do this via quotes for the generic types of the tuple element.

import scala.quoted.*

def getTuple2_0[T: Type](q: Expr[Tuple2[_,_]])(using Quotes): Any =
  import quotes.reflect.*
  import scala.quoted.FromExpr.given
  q match
    case '{$pair: Tuple2[String,Int]} =>
      // All work
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[String,Int]] = pair
      val key = pair.valueOrAbort
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[String, Int])
      val k2 = quoted.FromExpr.Tuple2FromExpr[String,Int].unapply(pair)
      ???
    case '{Tuple2[k1,v1]($h,$t)} =>
		  // All fail
      val key = h.value
      val value = t.value
      ???
    case '{$pair: Tuple2[k1,v1]} =>
		  // All fail
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[k1,v1]] = pair
      val key = pair.valueOrAbort
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[k1, v1])
      val k2 = quoted.FromExpr.Tuple2FromExpr[k1,v1].unapply(pair)
      ???
  ???


def getTuple2_1[T <: Tuple](q: Expr[T])(using t: Type[T], qt: Quotes): Any =
  import quotes.reflect.*
  import scala.quoted.FromExpr.given
  q match
    case '{$pair: Tuple2[String,Int]} =>
      // Fails if we use T <: Tuple
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[String,Int]] = pair
      // Fails if we use T <: Tuple
      val key = pair.valueOrAbort
			// Works
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[String, Int])
      val k2 = quoted.FromExpr.Tuple2FromExpr[String,Int].unapply(pair)
      ???
    case '{Tuple2[k1,v1]($h,$t)} =>
      // All fail. Same as in getTuple2_0
      val key = h.value
      val value = t.value
      ???
    case '{$pair: Tuple2[k1,v1]} =>
      // All fail. Same as in getTuple2_0
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[k1,v1]] = pair
      val key = pair.valueOrAbort
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[k1, v1])
      val k2 = quoted.FromExpr.Tuple2FromExpr[k1,v1].unapply(pair)
      ???
  ???

Output

These are two of the errors I get:

[error] 147 |        val key = h.value
[error]     |                  ^^^^^^^
[error]     |value value is not a member of scala.quoted.Expr[k1].
[error]     |An extension method was tried, but could not be fully constructed:
[error]     |
[error]     |    x$2.value[k1](h)(
[error]     |      quoted.FromExpr.Tuple22FromExpr[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, 
[error]     |        T12
[error]     |      , T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]
[error]     |    )


[error]     |value valueOrAbort is not a member of scala.quoted.Expr[(k1, v1)].
[error]     |An extension method was tried, but could not be fully constructed:
[error]     |
[error]     |    x$2.valueOrAbort[(k1, v1)](pair)(
[error]     |      quoted.FromExpr.Tuple2FromExpr[k1, v1](quoted.Type.of[k1](x$2), 
[error]     |        quoted.Type.of[v1](x$2)
[error]     |      , 
[error]     |        quoted.FromExpr.Tuple22FromExpr[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11
[error]     |          , 
[error]     |        T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]
[error]     |      , ???)
[error]     |    )

Expectation

I expected the code above to compile and work.

@hmf hmf added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Dec 15, 2022
@anatoliykmetyuk anatoliykmetyuk added area:metaprogramming:quotes Issues related to quotes and splices and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Dec 19, 2022
@nicolasstucki
Copy link
Contributor

Why this will not work

Consider this simpler version

def f(x: Expr[Any])(using Quotes) = 
  x match
    case '{ $x: t } =>
      summon[FromExpr[t]]

In this case, we have an existential type t for which we do not know anything statically. Depending on the type of the expression, it could require a FromExpr[Int], FromExpr[(Int, Int)] or even FromExpr[A] for an A defined in some downstream library or app. We cannot chose one because it would be the wrong one for most type and it is impossible to get them all at once.

Similarly, we would not be able to do the following

def f(xs: List[Any]) = 
  xs match
    case xs: List[t] =>
      summon[Ordering[t]]

How could this code work

One way to make this work is to resolve the FromExpr outside of this function where we have more information about the types.

import scala.quoted.*

def getTuple2_0[T1: Type: FromExpr, T2: Type: FromExpr](q: Expr[Tuple2[_,_]])(using Quotes): Any =
  q match
    case '{$pair: Tuple2[T1,T2]} =>
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[T1,T2]] = pair
      val key = pair.valueOrAbort
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[T1, T2])
      val k2 = quoted.FromExpr.Tuple2FromExpr[T1,T2].unapply(pair)
      ???
    case '{Tuple2[T1,T2]($h,$t)} =>
      val key = h.value
      val value = t.value
      ???
    case '{$pair: Tuple2[T1,T2]} =>
      val k0 = Expr.unapply(pair)
      val kk : Expr[Tuple2[T1,T2]] = pair
      val key = pair.valueOrAbort
      val k1 = kk.valueOrAbort(using quoted.FromExpr.Tuple2FromExpr[T1, T2])
      val k2 = quoted.FromExpr.Tuple2FromExpr[T1,T2].unapply(pair)
      ???
  ???


def getTuple2_1[T <: Tuple : Type : FromExpr](q: Expr[T])(using Quotes): Any =
  q.value // Uses the provided `FromExpr[T]`

def getTuple2_2[T1 : Type: FromExpr, T2: Type : FromExpr](q: Expr[Tuple2[T1,T2]])(using Quotes): Any =
  q.value // Uses Tuple2FromExpr[T1, T2] which requires `FromExpr[T1]` and `FromExpr[T2]`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:metaprogramming:quotes Issues related to quotes and splices
Projects
None yet
Development

No branches or pull requests

3 participants