scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.82k stars 1.05k forks source link

Type bound is not inferred inside quotation (type variable escapes?) #16121

Open DmytroMitin opened 2 years ago

DmytroMitin commented 2 years ago

Compiler version

3.1.3 3.2.2-RC1-bin-20220925-562ab85-NIGHTLY

Minimized code

import scala.quoted.*

object Macro {
  inline def fooMacro[A, B]: Unit = ${fooMacroImpl[A, B]}

  def fooMacroImpl[A: Type, B: Type](using Quotes): Expr[Unit] = {
    import quotes.reflect.*

    val res = '{tag[A, B]} match {
      case '{
          type a
          type b <: `a`
          tag[`a`, `b`]
        } => '{foo[a, b]}
    }

    println(res.show)

    res
  }

  def tag[A, B] = ???

  def foo[A, B <: A]: Unit = ???
}

Output

Type argument b does not conform to upper bound a
        } => '{foo[a, b]}

Expectation

The macro should typecheck.

Comment

If I replace => '{foo[a, b]} with => '{foo[a, b & a]} then Macro.fooMacro[AnyVal, Int] typechecks but prints

Macro.foo[scala.AnyVal | b, scala.&[scala.Int, scala.AnyVal | b]]

instead of

Macro.foo[scala.AnyVal, scala.&[scala.Int, scala.AnyVal]]

Can be similar to

https://github.com/lampepfl/dotty/issues/13527

https://github.com/lampepfl/dotty/issues/14708

Motivated by https://stackoverflow.com/questions/70311751/what-scala-3-syntax-can-match-on-a-type-and-its-type-parameters-in-the-context-o

coreyoconnor commented 3 weeks ago

Using Scala 3.4.1 the example type checks and works as expected. Close?

[~]$ scala-cli 
Welcome to Scala 3.4.1 (21.0.3, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> import scala.quoted.*
     | 
     | object Macro {
     |   inline def fooMacro[A, B]: Unit = ${fooMacroImpl[A, B]}
     | 
     |   def fooMacroImpl[A: Type, B: Type](using Quotes): Expr[Unit] = {
     |     import quotes.reflect.*
     | 
     |     val res = '{tag[A, B]} match {
     |       case '{
     |           type a
     |           type b <: `a`
     |           tag[`a`, `b`]
     |         } => '{foo[a, b]}
     |     }
     | 
     |     println(res.show)
     | 
     |     res
     |   }
     | 
     |   def tag[A, B] = ???
     | 
     |   def foo[A, B <: A]: Unit = ???
     | }
// defined object Macro

scala> Macro.fooMacro[String, String]
rs$line$1.Macro.foo[b, java.lang.String]
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:344)
  at rs$line$1$Macro$.foo(rs$line$1:24)
  ... 30 elided
coreyoconnor commented 3 weeks ago

Or is this the wrong output?

scala> Macro.fooMacro[AnyVal, Int]
rs$line$1.Macro.foo[scala.AnyVal | b, scala.Int]

seems odd that b is still there.