Skip to content

Regression in thoughtworksinc / binding.scala #19191

Closed
@WojciechMazur

Description

@WojciechMazur

Regression found in Open Community Build for thoughtworksinc/binding.scala build logs

Compiler version

Last good release: 3.4.0-RC1-bin-20230726-97677cc-NIGHTLY
First bad release: 3.4.0-RC1-bin-20230727-ac69c66-NIGHTLY
Works in 3.3.1
Affects Scala 3.3.2 LTS backports

Bisect was not accurate enough, the commit of bisect result failed with other errors when building compiler
Regression candidate commits:
ac69c66 (bad) Ondřej Lhoták : add test for issue #17997 affecting the global object initialization checker (#18141)
d903d35 Nicolas Stucki: Add regression test (#18287)
cb73f0b EnzeXing: Add test for modifying this to AndType
c04d2db Jędrzej Rochala: Update scala3-presentation-compiler to 39e349e (#18296)
989c55c (bad) Jan Chyb : Fix regression #17245: Overloaded methods with ClassTags (#18286)
4b67b34 (bad, other error) Nicolas Stucki : Set missing expansion span for copied inlined node (#18229)
182331b (good) Nicolas Stucki : Support polymorphic functions with erased parameters (#18293)
5625107 Nicolas Stucki: Support polymorphic functions with erased parameters
f22f9db (bad, other error) Julien Richard-Foy : Set missing expansion span for copied inlined node
101ce3a Jan Chyb: Fix regression with Overloaded methods returning Functions
f5313ae EnzeXing: add fix for issue #17997 affecting the global object initialization checker
96ca0b6 Ondrej Lhotak: add test for issue #17997 affecting the global object initialization checker

Minimized code

// main.scala
trait Binding[+A]:
  def value: A = ???
object Binding:
  inline def apply[A](inline a: A): Binding[A] = ???
  final case class Constant[+A](override val value: A) extends Binding[A]

extension [A](inline binding: Binding[A])
    transparent inline def bind: A = null.asInstanceOf[A]

trait Vars[A] extends BindingSeq[A]
trait BindingSeq[+A]:
  def foreachBinding[U](f: A => Binding[U]): Binding[Unit] = ???

extension [A](inline bindingSeq: BindingSeq[A])
  transparent inline def foreach[U](inline f: A => U): Unit = ${ Macros.foreach('bindingSeq, 'f) }

@main def Test = {
  val vars: Vars[Int] = ???

  val works = vars.foreach { v => () }
  val fails = for (v <- vars) ()
}
// macros.scala
import scala.compiletime._
import scala.deriving._
import scala.quoted._
import scala.annotation.meta.field

object Macros{
    private def bindingFunctionBody[A: quoted.Type, B: quoted.Type](f: quoted.Expr[A => B])(using Quotes) =
      import quoted.quotes.reflect.*
      f.asTerm match
        case inlined @ Inlined(
              call,
              bindings,
              block @ Block(
                List(
                  defDef @ DefDef(
                    name,
                    paramss @ List(TermParamClause(List(param @ ValDef(paramName, paramTpt, _)))),
                    tpt,
                    Some(rhs)
                  )
                ),
                closureIdent
              )
            ) =>
          Inlined
            .copy(inlined)(
              call,
              bindings,
              '{ (a: A) =>
                ${
                  Block(
                    List(
                      ValDef
                        .copy(param)(paramName, paramTpt, Some('a.asTerm))
                        .changeOwner(Symbol.spliceOwner)
                    ),
                    '{
                      Binding(${ rhs.changeOwner(Symbol.spliceOwner).asExprOf[B] })
                    }.asTerm.changeOwner(Symbol.spliceOwner)
                  )
                    .asExprOf[Binding[B]]
                }: Binding[B]
              }.asTerm
            )
            .asExprOf[A => Binding[B]]
        case _ =>
          '{ (a: A) => Binding.Constant($f(a)): Binding[B] }
      end match
    end bindingFunctionBody

    def foreach[A: quoted.Type, U: quoted.Type](self: quoted.Expr[BindingSeq[A]], f: quoted.Expr[A => U])(using
        qctx: Quotes
    ): quoted.Expr[Unit] = '{ $self.foreachBinding(${ bindingFunctionBody(f) }).bind }
}

Output

-- Error: /Users/wmazur/projects/dotty/bisect/main.scala:21:14 -----------------
21 |  val fails = for (v <- vars) ()
   |              ^^^^^^^^^^^^^^^^^^
   |Exception occurred while executing macro expansion.
   |java.lang.Exception: Expr cast exception: ((a: scala.Int) => ({
   |  val v: scala.Int = a
   |  Binding.apply[scala.Unit](())
   |}: Binding[scala.Unit]))
   |of type: scala.Function1[scala.Int, scala.Unit]
   |did not conform to type: scala.Function1[scala.Int, Binding[scala.Unit]]
   |
   |    at scala.quoted.runtime.impl.QuotesImpl.asExprOf(QuotesImpl.scala:76)
   |    at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:119)
   |    at scala.quoted.runtime.impl.QuotesImpl$reflect$TreeMethods$.asExprOf(QuotesImpl.scala:118)
   |    at Macros$.bindingFunctionBody(macros.scala:45)
   |    at Macros$.foreach$$anonfun$1(macros.scala:53)
   |    at Macros$.foreach$$anonfun$adapted$1(macros.scala:53)
   |    at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:110)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1563)
   |    at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1632)
   |    at scala.collection.immutable.List.mapConserve(List.scala:472)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1632)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1529)
   |    at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform$$anonfun$1(Trees.scala:1632)
   |    at scala.collection.immutable.List.mapConserve(List.scala:472)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1632)
   |    at dotty.tools.dotc.ast.Trees$Instance$TreeMap.transform(Trees.scala:1529)
   |    at dotty.tools.dotc.quoted.PickledQuotes$$anon$1.transform(PickledQuotes.scala:135)
   |    at dotty.tools.dotc.quoted.PickledQuotes$.spliceTerms(PickledQuotes.scala:152)
   |    at dotty.tools.dotc.quoted.PickledQuotes$.unpickleTerm(PickledQuotes.scala:88)
   |    at scala.quoted.runtime.impl.QuotesImpl.unpickleExprV2(QuotesImpl.scala:3170)
   |    at Macros$.foreach(macros.scala:53)
   |
   |----------------------------------------------------------------------------
   |Inline stack trace
   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
   |This location contains code that was inlined from main.scala:15
15 |  transparent inline def foreach[U](inline f: A => U): Unit = ${ Macros.foreach('bindingSeq, 'f) }
   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ----------------------------------------------------------------------------

Expectation

Should compile

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions