Skip to content

Compiler crash with annotation on main method #22364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lrytz opened this issue Jan 14, 2025 · 3 comments · Fixed by #22582
Closed

Compiler crash with annotation on main method #22364

lrytz opened this issue Jan 14, 2025 · 3 comments · Fixed by #22582

Comments

@lrytz
Copy link
Member

lrytz commented Jan 14, 2025

//> using scala 3.6.2

import util.chaining.*

class ann(x: Int = 1, y: Int) extends annotation.Annotation

@ann(y = 22.tap(println)) @main def main = ()
Error: scala.MatchError: Block(List(ValDef(y$1,TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)],Apply(TypeApply(Select(Apply(TypeApply(TypedSplice(Ident(scalaUtilChainingOps)),List(TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)])),List(Literal(Constant(22)))),tap),List(TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Unit)])),List(Block(List(DefDef($anonfun,List(List(ValDef(x,TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Any)],EmptyTree))),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Unit)],Apply(TypedSplice(Ident(println)),List(TypedSplice(Ident(x)))))),Closure(List(),TypedSplice(Ident($anonfun)),EmptyTree))))), ValDef(x$1,TypeTree[AnnotatedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Int),ConcreteAnnotation(Apply(Select(New(TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class unchecked)),class uncheckedVariance)]),<init>),List())))],Select(TypedSplice(Ident(ann)),$lessinit$greater$default$1))),Apply(Select(New(TypedSplice(Ident(ann))),<init>),List(TypedSplice(Ident(x$1)), NamedArg(y,TypedSplice(Ident(y$1)))))) (of class dotty.tools.dotc.ast.Trees$Block)
	at dotty.tools.dotc.typer.Namer.typedAheadAnnotationClass(Namer.scala:1774)
	at dotty.tools.dotc.typer.Namer$Completer.addAnnotations$$anonfun$1(Namer.scala:883)
@lrytz lrytz added itype:bug itype:crash stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 14, 2025
@Gedochao Gedochao added area:annotations and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jan 15, 2025
@bracevac bracevac assigned mbovel and unassigned bracevac Jan 29, 2025
@mbovel
Copy link
Member

mbovel commented Feb 10, 2025

Not a crash anymore (probably following my fixes for default arguments):

bovel@laraserver4:/localhome/bovel/scala3$ scala -S 3.7.nightly tests/pos/22364.scala
Downloading Scala 3.7.0-RC1-bin-20250207-d60a914-NIGHTLY compiler
Downloading Scala 3.7.0-RC1-bin-20250207-d60a914-NIGHTLY bridge
Compiling project (Scala 3.7.0-RC1-bin-20250207-d60a914-NIGHTLY, JVM (17))
[error] ./tests/pos/22364.scala:5:10
[error] cannot infer type; expected type <?> is not fully defined
[error] @ann(y = 22.tap(println)) @main def main = ()
[error]          ^^^^^^
Error compiling project (Scala 3.7.0-RC1-bin-20250207-d60a914-NIGHTLY, JVM (17))
Compilation failed

But it should also not be an error.

@mbovel
Copy link
Member

mbovel commented Feb 10, 2025

The essential ingredients here seem to be @main and a type parameter:

def id[T](x: T): T = x

class ann(x: Int) extends annotation.Annotation

@ann(id(22)) @main def main = ()

Which becomes:

sbt:scala3> scalac -Xprint:typer tests/pos/22364.scala
...
-- Error: tests/pos/22364.scala:5:5 --------------------------------------------
5 |@ann(id(22)) @main def main = ()
  |     ^^
  |     cannot infer type; expected type <?> is not fully defined
[[syntax trees at end of                     typer]] // tests/pos/22364.scala
package <empty> {
  class ann(x: Int) extends annotation.Annotation() {
    private[this] val x: Int
  }
  final lazy module val 22364$package: 22364$package = new 22364$package()
  final module class 22364$package() extends Object() {
    this: 22364$package.type =>
    def id[T >: Nothing <: Any](x: T): T = x
    @main @ann(id[Int](22)) def main: Unit = ()
  }
  final class main() extends Object() {
    @ann(
      id[<error cannot infer type; expected type <?> is not fully defined>](22))
       <static> def main(args: Array[String]): Unit =
      try main catch 
        {
          case error @ _:scala.util.CommandLineParser.ParseError =>
            scala.util.CommandLineParser.showError(error)
        }
  }
}

The same example without @main type-checks:

def id[T](x: T): T = x

class ann(x: Int) extends annotation.Annotation

@ann(id(22)) @ann(id(22)) def main = ()

@mbovel
Copy link
Member

mbovel commented Feb 10, 2025

The root problem is how we copy annotations when we generate the @main proxy in

/** Replace typed `Ident`s that have been typed with a TypeSplice with the reference to the symbol.
* The annotations will be retype-checked in another scope that may not have the same imports.
*/
def insertTypeSplices = new TreeMap {
override def transform(tree: Tree)(using Context): Tree = tree match
case tree: tpd.Ident @unchecked => TypedSplice(tree)
case tree => super.transform(tree)
}
val annots = mainFun.annotations
.filterNot(_.matches(defn.MainAnnot))
.map(annot => insertTypeSplices.transform(annot.tree))

This logic was introduced in #13858.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants