Skip to content

ListFromExpr fails when list has inline element #10914

Closed
@deusaquilus

Description

@deusaquilus

Minimized code

(Note: Full code sample available here: https://github.com/deusaquilus/list_inline_bug)

Let's first create some objects to hold something with non-trivial content.

case class Entity(value: String)
case class Input(ent: Entity)
case class Container(ents: List[Entity])

Let's make a macro that pulls out Entity from Input assuming Input was created via the standard .apply function.

  inline def container(inline c: Input):Container = ${ containerImpl('c) }
  def containerImpl(c: Expr[Input])(using Quotes): Expr[Container] =
    import quotes.reflect._
    val entExpr = c match
      case '{ Input($ent) } => ent
      case _ => report.throwError("Cannot Extract Entity from Input")
    '{ Container(List($entExpr)) }

Then let's make a second function to take the result of the first, pull out the entity from the container, and then do a ListFromExpr on the list. This involves writing a FromExpr for Entity:

  given FromExpr[Entity] with
    def unapply(expr: Expr[Entity])(using Quotes) = expr match
      case '{ Entity(${Expr(value)}) } => Some(Entity(value))
      case _ => None

... and then the actual function that will do list.valueOrError.

  inline def pull(inline c: Container): Entity = ${ pullImpl('c) }
  def pullImpl(c: Expr[Container])(using Quotes): Expr[Entity] =
    import quotes.reflect._
    val inputs = c match
      case '{ Container($list) } => 
        println("List Value: " + Printer.TreeStructure.show(list.asTerm))
        list.valueOrError
      case _ => report.throwError("Cannot Extract List from Container")
    '{ Entity(${Expr(inputs.head.value)}) }

Now let's run the application:

  def makeEnt = Entity("foo")

  inline def input = Input(makeEnt)
  inline def contained = container(input)
  inline def output = pull(contained)

  def main(args: Array[String]): Unit = {
    println( output )
  }

Output

This will fail with the following error

[error] 16 |    println( output )
[error]    |             ^^^^^^
[error]    |Expected a known value. 
[error]    |
[error]    |The value of: scala.List.apply[io.getquill.Entity](io.getquill.Test.makeEnt)
[error]    |could not be extracted using scala.quoted.FromExpr$ListFromExpr@3b76a5b3
[error]    | This location contains code that was inlined from Dsl.scala:17
[error]    | This location contains code that was inlined from Test.scala:13

The source of the problem seems to be that there is an Inlined node in the list apply:

Apply(TypeApply(
  Select(Ident("List"), "apply"), List(Inferred())
), List(Typed(Repeated(
    List(/* Here */ Inlined(None, Nil, Ident("makeEnt"))), Inferred()), Inferred())))

If I change makeEnt into an inline def then the problem will go away.

Expectation

The code should compile and return the Entity object.

Repository

Repo with full code sample available here:
https://github.com/deusaquilus/list_inline_bug

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions