This is an automated email from the ASF dual-hosted git repository. mbeckerle pushed a commit to branch daf-2975 in repository https://gitbox.apache.org/repos/asf/daffodil.git
commit 2d4d80ef3732dceb1bed09a6aff14ebf414835f5 Author: Michael Beckerle <[email protected]> AuthorDate: Wed Feb 26 22:29:30 2025 -0500 Checkpoint on Scala 3 conversion DAFFODIL-2975 --- build.sbt | 26 ++++- .../apache/daffodil/lib/exceptions/Assert.scala | 65 +++++++----- .../daffodil/lib/exceptions/AssertMacros.scala | 113 --------------------- project/Dependencies.scala | 1 + 4 files changed, 60 insertions(+), 145 deletions(-) diff --git a/build.sbt b/build.sbt index 3361c050a..fee1231ed 100644 --- a/build.sbt +++ b/build.sbt @@ -238,8 +238,10 @@ val minSupportedJavaVersion: String = lazy val commonSettings = Seq( organization := "org.apache.daffodil", version := "4.0.0-SNAPSHOT", - scalaVersion := "2.13.16", - crossScalaVersions := Seq("2.13.16", "2.12.20"), + scalaVersion := "3.6.3", + crossScalaVersions := Seq("3.6.3"), + // Ensure any transitive dependency that asks for scala-reflect resolves correctly + dependencyOverrides += "org.scala-lang" % "scala-reflect" % "2.13.16", scalacOptions ++= buildScalacOptions(scalaVersion.value), Test / scalacOptions ++= buildTestScalacOptions(scalaVersion.value), Compile / compile / javacOptions ++= buildJavacOptions(), @@ -274,8 +276,11 @@ def buildScalacOptions(scalaVersion: String) = { s"-release:$minSupportedJavaVersion", // scala 2.12 can only do Java 8, regardless of this setting. "-feature", "-deprecation", - "-language:experimental.macros", "-unchecked", + ) + + val scala212And213Options = Seq( + "-language:experimental.macros", "-Xfatal-warnings", "-Xxml:-coalescing", "-Ywarn-unused:imports" @@ -289,7 +294,7 @@ def buildScalacOptions(scalaVersion: String) = { "-Ywarn-inaccessible" // "-Ywarn-nullary-unit", // we cannot use this. It interferes with the Uniform Access Principle. // See https://stackoverflow.com/questions/7600910/difference-between-function-with-parentheses-and-without. - ) + ) ++ scala212And213Options case Some((2, 13)) => Seq( "-Xlint:inaccessible", @@ -301,6 +306,19 @@ def buildScalacOptions(scalaVersion: String) = { "-Wconf:origin=scala.collection.compat.*:s", // suppress nullary-unit warning in the specific trait "-Wconf:cat=lint-nullary-unit:silent,site=org.apache.daffodil.junit.tdml.TdmlTests:silent" + ) ++ scala212And213Options + case Some((3, 6)) => + Seq( + "-source:3.0-migration", + "-no-indent", + "-Xignore-scala2-macros", + // "-Xlint", + "-Wunused:explicits", + "-Wnonunit-statement", + // "-Wconf:cat=nullary-unit&site=org.apache.daffodil.junit.tdml.TdmlTests:silent", + // "-Werror", + "-Wunused:imports", + "-Wunused:locals" ) case _ => Seq.empty } diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/lib/exceptions/Assert.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/lib/exceptions/Assert.scala index bbcdaee94..f96610c05 100644 --- a/daffodil-lib/src/main/scala/org/apache/daffodil/lib/exceptions/Assert.scala +++ b/daffodil-lib/src/main/scala/org/apache/daffodil/lib/exceptions/Assert.scala @@ -101,35 +101,38 @@ class Assert { object Assert extends Assert { - /* - * Note that in macro definitions, the argument names here must match the argument names - * in the macro implementations. - */ + implicit class CodeString(val sc: StringContext) extends AnyVal { + def code(args: Any*): String = sc.parts.mkString + } + + inline def usageErrorUnless(testAbortsIfFalse: => Boolean, message: String): Unit = + if (!testAbortsIfFalse) usageError2(message, code"testAbortsIfFalse") + + inline def usageErrorUnless(testAbortsIfFalse: => Boolean, cause: Throwable): Unit = + if (!testAbortsIfFalse) usageError(cause) + + inline def usageErrorUnless(testAbortsIfFalse: => Boolean): Unit = + if (!testAbortsIfFalse) usageError(code"testAbortsIfFalse") - /** - * Verbose name helps you get the sense of the predicate right. - */ - def usageErrorUnless(testAbortsIfFalse: Boolean, message: String): Unit = - macro AssertMacros.usageMacro2 - def usageErrorUnless(testAbortsIfFalse: Boolean, cause: Throwable): Unit = - macro AssertMacros.usageMacro2Cause - def usageErrorUnless(testAbortsIfFalse: Boolean): Unit = macro AssertMacros.usageMacro1 /** * Brief form */ - def usage(testAbortsIfFalse: Boolean, message: String): Unit = macro AssertMacros.usageMacro2 - def usage(testAbortsIfFalse: Boolean, cause: Throwable): Unit = - macro AssertMacros.usageMacro2Cause - def usage(testAbortsIfFalse: Boolean): Unit = - macro AssertMacros.usageMacro1 + inline def usage(testAbortsIfFalse: => Boolean, message: String): Unit = + usageErrorUnless(testAbortsIfFalse, message) + inline def usage(testAbortsIfFalse: => Boolean, cause: Throwable): Unit = + usageErrorUnless(testAbortsIfFalse, cause) + inline def usage(testAbortsIfFalse: => Boolean): Unit = + usageErrorUnless(testAbortsIfFalse) /** * test for something that the program is supposed to be ensuring. * * This is for more complex invariants than the simple 'impossible' case. */ - def invariant(testAbortsIfFalse: Boolean): Unit = macro AssertMacros.invariantMacro1 + inline def invariant(testAbortsIfFalse: => Boolean): Unit = + if (!(testAbortsIfFalse)) { + Assert.abort("Invariant broken: " + code"testAbortsIfFalse") /** * test for something that the program is supposed to be ensuring, with a custom error message. @@ -139,19 +142,24 @@ object Assert extends Assert { * The msg parameter is only evaluated if the test fails */ def invariant(testAbortsIfFalse: Boolean, msg: String): Unit = - macro AssertMacros.invariantMacro2 + if (!(testAbortsIfFalse)) + Assert.abort("Invariant broken: " + msg + "(" + code"testAbortsIfFalse" + ")") /** * Conditional behavior for NYIs */ - def notYetImplemented(testThatWillThrowIfTrue: Boolean): Unit = - macro AssertMacros.notYetImplementedMacro1 - def notYetImplemented(testThatWillThrowIfTrue: Boolean, msg: String): Unit = - macro AssertMacros.notYetImplementedMacro2 + inline def notYetImplemented(testThatWillThrowIfTrue: => Boolean): Unit = + if(testThatWillThrowIfTrue) + Assert.nyi(code"testThatWillThrowIfTrue") + + inline def notYetImplemented(testThatWillThrowIfTrue: => Boolean, msg: String): Unit = + if(testThatWillThrowIfTrue) + Assert.nyi(msg + "(" + code"testThatWillThrowIfTrue" + ")") + // $COVERAGE-OFF$ These unconditional assertions should never get executed by tests. - def notYetImplemented(): Nothing = macro AssertMacros.notYetImplementedMacro0 + def notYetImplemented(): Nothing = Assert.nyi() // // Throughout this file, specifying return type Nothing // gets rid of many spurious (scala compiler bug) dead code @@ -160,13 +168,14 @@ object Assert extends Assert { // to be enabled. // - def usageError(message: String = "Usage error."): Nothing = { + def usageError(message: String = "Usage error."): Nothing = toss(new UsageException(message)) - } - def usageError(cause: Throwable): Nothing = { + def usageError(cause: Throwable): Nothing = toss(new UsageException(cause)) - } + + def usageError(message: String, cause: Throwable): Nothing = + toss(new UsageException(message, cause)) def usageError2(message: String = "Usage error.", testAsString: String): Nothing = { usageError(message + " (" + testAsString + ")") diff --git a/daffodil-macro-lib/src/main/scala/org/apache/daffodil/lib/exceptions/AssertMacros.scala b/daffodil-macro-lib/src/main/scala/org/apache/daffodil/lib/exceptions/AssertMacros.scala deleted file mode 100644 index a28e3495b..000000000 --- a/daffodil-macro-lib/src/main/scala/org/apache/daffodil/lib/exceptions/AssertMacros.scala +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.daffodil.lib.exceptions - -import scala.reflect.macros.blackbox.Context - -object AssertMacros { - - def usageMacro2(c: Context)(testAbortsIfFalse: c.Tree, message: c.Tree): c.Tree = { - import c.universe._ - - val testAsString = testAbortsIfFalse.toString - - q""" - if (!($testAbortsIfFalse)) { - Assert.usageError2("Usage error: " + $message, $testAsString) - } - """ - } - - def usageMacro2Cause(c: Context)(testAbortsIfFalse: c.Tree, cause: c.Tree): c.Tree = { - import c.universe._ - - q""" - if (!($testAbortsIfFalse)) { - Assert.usageError($cause) - } - """ - } - - def usageMacro1(c: Context)(testAbortsIfFalse: c.Tree): c.Tree = { - import c.universe._ - - val testAsString = testAbortsIfFalse.toString - - q""" - if (!($testAbortsIfFalse)) { - Assert.usageError("Usage error: " + $testAsString) - } - """ - } - - def invariantMacro1(c: Context)(testAbortsIfFalse: c.Tree): c.Tree = { - import c.universe._ - - val testAsString = testAbortsIfFalse.toString - - q""" - if (!($testAbortsIfFalse)) { - Assert.abort("Invariant broken: " + $testAsString) - } - """ - } - - def invariantMacro2(c: Context)(testAbortsIfFalse: c.Tree, msg: c.Tree): c.Tree = { - import c.universe._ - - q""" - if (!($testAbortsIfFalse)) { - Assert.abort("Invariant broken. " + { $msg }) - } - """ - } - - def notYetImplementedMacro0(c: Context)(): c.Tree = { - import c.universe._ - - q""" - Assert.nyi() - """ - } - - def notYetImplementedMacro1(c: Context)(testThatWillThrowIfTrue: c.Tree): c.Tree = { - import c.universe._ - - val testAsString = testThatWillThrowIfTrue.toString - - q""" - if ($testThatWillThrowIfTrue){ - Assert.nyi($testAsString) - } - """ - } - - def notYetImplementedMacro2( - c: Context - )(testThatWillThrowIfTrue: c.Tree, msg: c.Tree): c.Tree = { - import c.universe._ - - val testAsString = testThatWillThrowIfTrue.toString - - q""" - if ($testThatWillThrowIfTrue){ - Assert.nyi($msg + " (" + $testAsString + ")") - } - """ - } -} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 0e5d25c11..c65404278 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -23,6 +23,7 @@ object Dependencies { lazy val common = core ++ infoset ++ test ++ compat lazy val core = Seq( + "org.scala-lang" % "scala-reflect" % "2.13.16" % Provided, "com.lihaoyi" %% "os-lib" % "0.11.3", // for writing/compiling C source files "org.scala-lang.modules" %% "scala-xml" % "2.3.0", "org.scala-lang.modules" %% "scala-parser-combinators" % "2.4.0",
