Skip to content

Instantly share code, notes, and snippets.

@abeppu
Last active December 28, 2023 18:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abeppu/2fa3af1e2a92c9d2ec666229781d0b20 to your computer and use it in GitHub Desktop.
Save abeppu/2fa3af1e2a92c9d2ec666229781d0b20 to your computer and use it in GitHub Desktop.
scala 3 reference example of HOAS pattern matching seems broken

notes

The core pattern matching example was copy-pasted from this example in the official references.

I have tried to make a minimal no-op macro around the copy-pasted example, which receives nothing and returns a canned expression.

On scala 3.3.1, doing scalac -explain ExprMatch*.scala, I get the following output:

-- Error: ExprMatchingPlayground.scala:13:28 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
13 |      case '{ ((y: Int) => $f(y)).apply($z: Int) } =>
   |                            ^
   |                            Type must be fully defined.
   |                            Consider annotating the splice using a type ascription:
   |                              ($<none>(y): XYZ).
-- [E006] Not Found Error: ExprMatchingPlayground.scala:16:8 -----------------------------------------------------------------------------------------------------------------------------------------------
16 |        f(z) // generates '{ 2 + 1 }
   |        ^
   |        Not found: f
   |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   | Explanation (enabled by `-explain`)
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   | The identifier for `f` is not bound, that is,
   | no declaration for this identifier can be found.
   | That can happen, for example, if `f` or its declaration has either been
   | misspelt or if an import is missing.
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- [E006] Not Found Error: ExprMatchingPlayground.scala:16:10 ----------------------------------------------------------------------------------------------------------------------------------------------
16 |        f(z) // generates '{ 2 + 1 }
   |          ^
   |          Not found: z
   |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   | Explanation (enabled by `-explain`)
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   | The identifier for `z` is not bound, that is,
   | no declaration for this identifier can be found.
   | That can happen, for example, if `z` or its declaration has either been
   | misspelt or if an import is missing.
    --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3 errors found

Just to confirm whether this previously worked, I also tried compiling with 3.0.0, and I get essentially the same output:

-- Error: ExprMatchingPlayground.scala:13:27 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
13 |      case '{ ((y: Int) => $f(y)).apply($z: Int) } =>
   |                           ^^
   |                           Type must be fully defined.
-- [E006] Not Found Error: ExprMatchingPlayground.scala:16:8 -----------------------------------------------------------------------------------------------------------------------------------------------
16 |        f(z) // generates '{ 2 + 1 }
   |        ^
   |        Not found: f

Explanation
===========
The identifier for `f` is not bound, that is,
no declaration for this identifier can be found.
That can happen, for example, if `f` or its declaration has either been
misspelt or if an import is missing.

-- [E006] Not Found Error: ExprMatchingPlayground.scala:16:10 ----------------------------------------------------------------------------------------------------------------------------------------------
16 |        f(z) // generates '{ 2 + 1 }
   |          ^
   |          Not found: z

Explanation
===========
The identifier for `z` is not bound, that is,
no declaration for this identifier can be found.
That can happen, for example, if `z` or its declaration has either been
misspelt or if an import is missing.

3 errors found

See also stack overflow question https://stackoverflow.com/questions/77718835/why-does-this-scala-3-macros-reference-example-of-hoas-fail-with-type-must-be-f?r=SearchResults

package exprmatch
object ExprMatchingDemo extends App {
ExprMatchingPlayground.foo()
}
package exprmatch
import scala.quoted.*
object ExprMatchingPlayground {
inline def foo(): Int = ${ scrutinizeHoas }
def scrutinizeHoas(using qctx: Quotes): Expr[Int] = {
// example from https://docs.scala-lang.org/scala3/reference/metaprogramming/macros.html#hoas-patterns-1
// see stack overflow question https://stackoverflow.com/questions/77718835/why-does-this-scala-3-macros-reference-example-of-hoas-fail-with-type-must-be-f
val w = '{ ((x: Int) => x + 1).apply(2) } match {
case '{ ((y: Int) => $f(y)).apply($z: Int) } =>
// f may contain references to `x` (replaced by `$y`)
// f = (y: Expr[Int]) => '{ $y + 1 }
f(z) // generates '{ 2 + 1 }
case _ => '{ 0 } // allow us to detect if compilation succeeds but match fails
}
println(s"w = ${w.asTerm.show(using Printer.TreeCode)}")
'{ 2 }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment