Skip to content

Regression: inferred types with @retains cause previous macro implementations to crash #24006

@jchyb

Description

@jchyb

Found in https://github.com/VirtusLab/community-build3/actions/runs/17687960136/job/50279371271

Compiler version

3.8.0-RC1-bin-20250912-c4c48e3-NIGHTLY

Minimized code

@main def main() = eval(List(1) :+ 4)
import scala.quoted._

inline def eval[T](x: List[T]) = ${ evalImpl[T]('x) }
def evalImpl[A](x: Expr[List[A]])(using Quotes): Expr[Unit] =
  import quotes.reflect.*
  println(x.asTerm.tpe.widen)
  x.asTerm.tpe.widen.typeArgs.head
  '{()}

Output

AnnotatedType(AppliedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class collection)),object immutable),class List),List(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int))),ConcreteAnnotation(Apply(TypeApply(Select(New(Select(Select(Select(Ident(_root_),scala),annotation),retains)),<init>),List(SingletonTypeTree(This(Ident())))),List())))-- Error: /Users/jchyb/workspace/community-build3/repo/a.scala:1:23 ------------
1 |@main def main() = eval(List(1) :+ 4)
  |                   ^^^^^^^^^^^^^^^^^^
  |                  Exception occurred while executing macro expansion.
  |                  java.util.NoSuchElementException: head of empty list
  |                     at scala.collection.immutable.Nil$.head(List.scala:669)
  |                     at scala.collection.immutable.Nil$.head(List.scala:669)
  |                     at b$package$.evalImpl(b.scala:7)
  |
  |-----------------------------------------------------------------------------
  |Inline stack trace
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  |This location contains code that was inlined from b.scala:3
3 |inline def eval[T](x: List[T]) = ${ evalImpl[T]('x) }
  |                                 ^^^^^^^^^^^^^^^^^^^^
   -----------------------------------------------------------------------------

Expectation

Ideally behavior like in 3.7.3, and before:
Output:

AppliedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class collection)),object immutable),class List),List(TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)))

and no crash.

Would it be possible to not have the retains when we use capture checking? I wonder if it's even intentional here, considerng :+ must be used to trigger it (I do not know much about capture checking yet).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions