Skip to content
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

Position.point on NoPosition when using: macro implicit, Wmacros:both and Xlint:unused #12895

Closed
MateuszKubuszok opened this issue Oct 20, 2023 · 3 comments · Fixed by scala/scala#10710

Comments

@MateuszKubuszok
Copy link

Reproduction steps

Scala version: I reproduced it on were 2.13.3 and 2.13.12.

//> using scala 2.13.3
//> using options -Wmacros:both -Xlint:unused
//> using javaOpt -Xss64m
//> using dep io.scalaland::chimney::0.8.0

import io.scalaland.chimney.dsl._

object ChimneyBug {
  private def handleEvent(state: State, event: Event) =
    (state, event) match {
      case (active: State.Active, updated: Event.A) =>
        active.patchUsing(updated)
    }

  sealed trait Event
  object Event {
    case class A(
                  a: String,
                ) extends Event
  }

  sealed trait State
  object State {
    case class Active(
                       a: String,
                     ) extends State
  }

  def test = handleEvent(ChimneyBug.State.Active("A"), ChimneyBug.Event.A("B"))
}

object Main {
  def main(args: Array[String]): Unit =
    println(ChimneyBug.test)
}

Problem

User reported that updating Chimney the newest version resulted in compilation errors. After discussion I managed to reproduce the error:

[error] ## Exception when compiling 1 sources to /Users/dev/Workspaces/GitHub/toescik2/dest/target/scala-2.13/classes
[error] java.lang.UnsupportedOperationException: Position.point on NoPosition
[error] scala.reflect.internal.util.Position.fail(Position.scala:24)
[error] scala.reflect.internal.util.UndefinedPosition.point(Position.scala:102)
[error] scala.reflect.internal.util.UndefinedPosition.point(Position.scala:97)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$UnusedPrivates.sympos(TypeDiagnostics.scala:623)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$UnusedPrivates.$anonfun$unusedParams$2(TypeDiagnostics.scala:642)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$UnusedPrivates.$anonfun$unusedParams$2$adapted(TypeDiagnostics.scala:642)
[error] scala.math.Ordering$$anon$1.compare(Ordering.scala:140)
[error] java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
[error] java.base/java.util.TimSort.sort(TimSort.java:220)
[error] java.base/java.util.Arrays.sort(Arrays.java:1233)
[error] scala.collection.SeqOps.sorted(Seq.scala:705)
[error] scala.collection.SeqOps.sorted$(Seq.scala:697)
[error] scala.collection.immutable.List.scala$collection$immutable$StrictOptimizedSeqOps$$super$sorted(List.scala:79)
[error] scala.collection.immutable.StrictOptimizedSeqOps.sorted(StrictOptimizedSeqOps.scala:78)
[error] scala.collection.immutable.StrictOptimizedSeqOps.sorted$(StrictOptimizedSeqOps.scala:78)
[error] scala.collection.immutable.List.sorted(List.scala:79)
[error] scala.collection.SeqOps.sortBy(Seq.scala:759)
[error] scala.collection.SeqOps.sortBy$(Seq.scala:759)
[error] scala.collection.AbstractSeq.sortBy(Seq.scala:1154)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$UnusedPrivates.unusedParams(TypeDiagnostics.scala:642)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$checkUnused.run(TypeDiagnostics.scala:748)
[error] scala.tools.nsc.typechecker.TypeDiagnostics$checkUnused.apply(TypeDiagnostics.scala:759)
[error] scala.tools.nsc.typechecker.Analyzer$typerFactory$TyperPhase.apply(Analyzer.scala:123)
[error] scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:454)
[error] scala.tools.nsc.typechecker.Analyzer$typerFactory$TyperPhase.run(Analyzer.scala:105)
[error] scala.tools.nsc.Global$Run.compileUnitsInternal(Global.scala:1515)
[error] scala.tools.nsc.Global$Run.compileUnits(Global.scala:1499)
[error] scala.tools.nsc.Global$Run.compileSources(Global.scala:1491)
[error] scala.tools.nsc.Global$Run.compileFiles(Global.scala:1605)
[error] xsbt.CachedCompiler0.run(CompilerBridge.scala:163)
[error] xsbt.CachedCompiler0.run(CompilerBridge.scala:134)
[error] xsbt.CompilerBridge.run(CompilerBridge.scala:39)
[error] sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$7(MixedAnalyzingCompiler.scala:193)
[error] scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:248)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4(MixedAnalyzingCompiler.scala:183)
[error] sbt.internal.inc.MixedAnalyzingCompiler.$anonfun$compile$4$adapted(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.JarUtils$.withPreviousJar(JarUtils.scala:239)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileScala$1(MixedAnalyzingCompiler.scala:163)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:211)
[error] sbt.internal.inc.IncrementalCompilerImpl.$anonfun$compileInternal$1(IncrementalCompilerImpl.scala:534)
...

Despite my best efforts I couldn't find any relation with what Chimney does, and this error. Using flags for debugging the compilation like -Xlog-implicits, -verbose, -Yquasiquote-debug, -Xprint-pos showed nothing, as if error happened before the macro expansion even started. Increasing stack with -Xss64m doesn't change the outcome.

It might be an error in Chimney, or it might be a particular combination of: an implicit provided by a macro, checking for unused definitions and putting macros into checking unused. Stack trace suggest that error happens in the typer while checking for unused private definitions. Removing any the the flags (-Wmacros:both, -Xlint:unused) makes the error disappear. That's why I created this ticket because I think that without a compiler developer's help I will not be able to tell if the bug is in Chimney or on the compiler.

@som-snytt
Copy link

Thanks for the report and the diagnostic work. -Wmacros:both says also lint the tree produced by the macro; I see from the stack trace that it is sorting the warnings by position; presumably it's not careful enough about unpositioned trees.

I see some safety checks for pos.isDefined.

https://github.com/scala/scala/blame/2.13.x/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala#L645

The workaround of course would be not to lint trees that are unpositioned.

@SethTisue SethTisue added this to the Backlog milestone Jan 26, 2024
@som-snytt
Copy link

The unpositioned symbol is the unused active$macro$1 parameter, and the bug is to try to use its referenced which is NoSymbol and has no position either.

The broader question is whether it's doing too much work just to sort by position; positions should be ordered even if "undefined".

{
          final class $anon extends AnyRef with io.scalaland.chimney.Patcher[ChimneyBug.State.Active,ChimneyBug.Event.A] {
            def <init>(): <$anon: io.scalaland.chimney.Patcher[ChimneyBug.State.Active,ChimneyBug.Event.A]> = {
              $anon.super.<init>();
              ()
            };
            def patch(active$macro$1: ChimneyBug.State.Active, a$macro$1: ChimneyBug.Event.A): ChimneyBug.State.Active = new ChimneyBug.State.Active(a$macro$1.a)
          };
          new $anon()
        }

@som-snytt
Copy link

Worth adding that for 2.13.14, -Wmacros:default does not check the synthetic parameter introduced by the expansion, so that would pass even without the fix.

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.

3 participants