You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by mb...@apache.org on 2025/02/27 05:37:20 UTC
(daffodil) 01/03: Checkpoint on Scala 3 conversion
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 <mb...@apache.org>
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",