Skip to content

Commit

Permalink
Fix #21721: make case TypeBlock(_, _) not match non-type Block (#21722)
Browse files Browse the repository at this point in the history
`TypeBlock`s are represented as normal `Blocks` in the Quotes API's
implementation. The current `TypeTest` for `TypeBlock` is exactly the
same as the `TypeTest` for `Block`, which means that `case TypeBlock(_,
_)` "matches" every block.

The implementation of `unapply` on `TypeBlockModule`, however, gives
back `(List[TypeDef], TypeTree)`. It constructs the `List[TypeDef]` by
mapping over every statement of the block, trying to turn it into a
`TypeDef` by using a match with the pattern
```scala
  case alias: TypeDef => alias
```
This seems fine since `TypeBlock`s are supposed to be just a list of
`TypeDefs` followed by a type as the last expression. Since the
`TypeTest` matches any `Block` and not only `Blocks` that are
`TypeBlocks`, the statements can be anything, not just `TypeDef`s, which
lets the whole `case TypeBlock(_, _)` pattern die with a `MatchError`.

This commit fixes the problem by making the `TypeTest` check whether the
`Block` is a type (which in turns checks whether the `Block`s expression
is a type)

Closes #21721
  • Loading branch information
jchyb authored Mar 4, 2025
2 parents 86b59aa + 147f562 commit a97974c
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 1 deletion.
2 changes: 1 addition & 1 deletion compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler

object TypeBlockTypeTest extends TypeTest[Tree, TypeBlock]:
def unapply(x: Tree): Option[TypeBlock & x.type] = x match
case tpt: (tpd.Block & x.type) => Some(tpt)
case tpt: (tpd.Block & x.type) if x.isType => Some(tpt)
case _ => None
end TypeBlockTypeTest

Expand Down
12 changes: 12 additions & 0 deletions tests/pos/i21721/Macro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import quoted.*

object Macro:
inline def impl(inline expr: Any): Any =
${implImpl('expr)}

def implImpl(expr: Expr[Any])(using q: Quotes): Expr[Any] =
import q.reflect.*
expr.asTerm.asInstanceOf[Inlined].body match
// this should not fail with a MatchError
case TypeBlock(_, _) => '{ "TypeBlock" }
case _ => '{ "Nothing" }
5 changes: 5 additions & 0 deletions tests/pos/i21721/Test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Test:
// give a Block(...) to the macro
Macro.impl:
val a = 3
a

0 comments on commit a97974c

Please sign in to comment.