From a32644dd8531ce25568d4594d7b60bafdc6b2d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Wa=C5=9Bko?= Date: Fri, 13 May 2022 17:38:52 +0200 Subject: [PATCH] Make it possible to run Enso with assertions enabled (#3450) Before, when running Enso with `-ea`, some assertions were broken and the interpreter would not start. This PR fixes two very minor bugs that were the cause of this - now we can successfully run Enso with `-ea`, to test that any assertions in Truffle or in our own libraries are indeed satisfied. Additionally, this PR adds a setting to SBT that ensures that IntelliJ uses the right language level (Java 17) for our projects. --- .github/workflows/scala.yml | 5 ++ build.sbt | 76 ++++++++++++------- .../org/enso/polyglot/RuntimeOptions.java | 4 - .../interpreter/runtime/error/Warning.java | 7 +- .../enso/compiler/codegen/IrToTruffle.scala | 2 +- 5 files changed, 61 insertions(+), 33 deletions(-) diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml index 496c6178178..2ace32fe95a 100644 --- a/.github/workflows/scala.yml +++ b/.github/workflows/scala.yml @@ -255,6 +255,11 @@ jobs: gu install python gu install r + - name: Enable assertions for tests + shell: bash + run: | + echo "JAVA_TOOL_OPTIONS=-ea" >> $GITHUB_ENV + - name: Prepare configuration for the Database tests shell: bash if: runner.os == 'Linux' diff --git a/build.sbt b/build.sbt index 5a953e8e4c1..002a7766b3e 100644 --- a/build.sbt +++ b/build.sbt @@ -5,12 +5,14 @@ import sbt.Keys.{libraryDependencies, scalacOptions} import sbt.addCompilerPlugin import sbt.complete.DefaultParsers._ import sbt.complete.Parser -import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject} -import src.main.scala.licenses.{DistributionDescription, SBTDistributionComponent} +import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType} +import src.main.scala.licenses.{ + DistributionDescription, + SBTDistributionComponent +} import java.io.File - // ============================================================================ // === Global Configuration =================================================== // ============================================================================ @@ -155,10 +157,10 @@ Global / onChangedBuildSource := ReloadOnSourceChanges // ============================================================================ ThisBuild / javacOptions ++= Seq( - "-encoding", // Provide explicit encoding (the next line) - "UTF-8", // Specify character encoding used by Java source files. - "-deprecation",// Shows a description of each use or override of a deprecated member or class. - "-g" // Include debugging information + "-encoding", // Provide explicit encoding (the next line) + "UTF-8", // Specify character encoding used by Java source files. + "-deprecation", // Shows a description of each use or override of a deprecated member or class. + "-g" // Include debugging information ) ThisBuild / scalacOptions ++= Seq( @@ -979,8 +981,8 @@ lazy val `interpreter-dsl` = (project in file("lib/scala/interpreter-dsl")) version := "0.1", frgaalJavaCompilerSetting, libraryDependencies ++= Seq( - "org.apache.commons" % "commons-lang3" % commonsLangVersion, - "org.netbeans.api" % "org-openide-util-lookup" % "RELEASE130" + "org.apache.commons" % "commons-lang3" % commonsLangVersion, + "org.netbeans.api" % "org-openide-util-lookup" % "RELEASE130" ) ) @@ -1150,15 +1152,23 @@ val distributionEnvironmentOverrides = { ) } +val frgaalSourceLevel = "18" + /** A setting to replace javac with Frgaal compiler, allowing to use latest Java features in the code * and still compile down to JDK 11 */ lazy val frgaalJavaCompilerSetting = Seq( - Compile/compile/compilers := FrgaalJavaCompiler.compilers((Compile / dependencyClasspath).value, compilers.value, javaVersion), + Compile / compile / compilers := FrgaalJavaCompiler.compilers( + (Compile / dependencyClasspath).value, + compilers.value, + javaVersion + ), // This dependency is needed only so that developers don't download Frgaal manually. // Sadly it cannot be placed under plugins either because meta dependencies are not easily // accessible from the non-meta build definition. - libraryDependencies += FrgaalJavaCompiler.frgaal + libraryDependencies += FrgaalJavaCompiler.frgaal, + // Ensure that our tooling uses the right Java version for checking the code. + Compile / javacOptions ++= Seq("-source", frgaalSourceLevel) ) lazy val runtime = (project in file("engine/runtime")) @@ -1170,10 +1180,15 @@ lazy val runtime = (project in file("engine/runtime")) cleanInstruments := FixInstrumentsGeneration.cleanInstruments.value, inConfig(Compile)(truffleRunOptionsSettings), inConfig(Benchmark)(Defaults.testSettings), - inConfig(Benchmark)(Defaults.compilersSetting), // Compile benchmarks with javac, due to jmh issues + inConfig(Benchmark)( + Defaults.compilersSetting + ), // Compile benchmarks with javac, due to jmh issues + Benchmark / javacOptions --= Seq("-source", frgaalSourceLevel), Test / parallelExecution := false, Test / logBuffered := false, - Test / testOptions += Tests.Argument("-oD"), // show timings for individual tests + Test / testOptions += Tests.Argument( + "-oD" + ), // show timings for individual tests scalacOptions += "-Ymacro-annotations", scalacOptions ++= Seq("-Ypatmat-exhaust-depth", "off"), libraryDependencies ++= jmh ++ jaxb ++ circe ++ Seq( @@ -1192,8 +1207,8 @@ lazy val runtime = (project in file("engine/runtime")) "org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark, "org.typelevel" %% "cats-core" % catsVersion, "eu.timepit" %% "refined" % refinedVersion, - "junit" % "junit" % "4.12" % Test, - "com.novocode" % "junit-interface" % "0.11" % Test exclude("junit", "junit-dep"), + "junit" % "junit" % "4.12" % Test, + "com.novocode" % "junit-interface" % "0.11" % Test exclude ("junit", "junit-dep") ), // Note [Unmanaged Classpath] Compile / unmanagedClasspath += (`core-definition` / Compile / packageBin).value, @@ -1212,7 +1227,9 @@ lazy val runtime = (project in file("engine/runtime")) s"--upgrade-module-path=${file("engine/runtime/build-cache/truffle-api.jar").absolutePath}" ), Test / fork := true, - Test / envVars ++= distributionEnvironmentOverrides ++ Map("ENSO_TEST_DISABLE_IR_CACHE" -> "false"), + Test / envVars ++= distributionEnvironmentOverrides ++ Map( + "ENSO_TEST_DISABLE_IR_CACHE" -> "false" + ), bootstrap := CopyTruffleJAR.bootstrapJARs.value, Global / onLoad := EnvironmentCheck.addVersionCheck( graalVersion, @@ -1803,12 +1820,14 @@ buildEngineDistribution := { } val stdBitsProjects = List("Base", "Database", "Google_Api", "Image", "Table") -val allStdBits: Parser[String] = stdBitsProjects.map(v => v: Parser[String]).reduce(_ | _) +val allStdBits: Parser[String] = + stdBitsProjects.map(v => v: Parser[String]).reduce(_ | _) -lazy val buildStdLib = inputKey[Unit]("Build an individual standard library package") +lazy val buildStdLib = + inputKey[Unit]("Build an individual standard library package") buildStdLib := Def.inputTaskDyn { val cmd: String = allStdBits.parsed - val root: File = engineDistributionRoot.value + val root: File = engineDistributionRoot.value // Ensure that a complete distribution was built at least once. // Becasuse of `if` in the sbt task definition and usage of `streams.value` one has to // delegate to another task defintion (sbt restriction). @@ -1824,22 +1843,27 @@ pkgStdLibInternal := Def.inputTaskDyn { val log: sbt.Logger = streams.value.log val cacheFactory = streams.value.cacheStoreFactory cmd match { - case "Base" => + case "Base" => (`std-base` / Compile / packageBin).value - case "Database" => + case "Database" => (`std-database` / Compile / packageBin).value case "Google_Api" => (`std-google-api` / Compile / packageBin).value - case "Image" => + case "Image" => (`std-image` / Compile / packageBin).value - case "Table" => + case "Table" => (`std-table` / Compile / packageBin).value - case _ => + case _ => } - StdBits.buildStdLibPackage(cmd, root, cacheFactory, log, defaultDevEnsoVersion) + StdBits.buildStdLibPackage( + cmd, + root, + cacheFactory, + log, + defaultDevEnsoVersion + ) }.evaluated - lazy val buildLauncherDistribution = taskKey[Unit]("Builds the launcher distribution") buildLauncherDistribution := { diff --git a/engine/polyglot-api/src/main/java/org/enso/polyglot/RuntimeOptions.java b/engine/polyglot-api/src/main/java/org/enso/polyglot/RuntimeOptions.java index aec20d8593e..08e5af0fcc1 100644 --- a/engine/polyglot-api/src/main/java/org/enso/polyglot/RuntimeOptions.java +++ b/engine/polyglot-api/src/main/java/org/enso/polyglot/RuntimeOptions.java @@ -29,9 +29,6 @@ public class RuntimeOptions { OptionDescriptor.newBuilder(ENABLE_AUTO_PARALLELISM_KEY, ENABLE_AUTO_PARALLELISM).build(); public static final String LOG_LEVEL = "log.level"; - public static final OptionKey LOG_LEVEL_KEY = new OptionKey<>(Level.INFO.toString()); - private static final OptionDescriptor LOG_LEVEL_DESCRIPTOR = - OptionDescriptor.newBuilder(LOG_LEVEL_KEY, LOG_LEVEL).build(); public static final String LOG_MASKING = optionName("log.masking"); public static final OptionKey LOG_MASKING_KEY = new OptionKey<>(true); @@ -94,7 +91,6 @@ public class RuntimeOptions { Arrays.asList( PROJECT_ROOT_DESCRIPTOR, STRICT_ERRORS_DESCRIPTOR, - LOG_LEVEL_DESCRIPTOR, LOG_MASKING_DESCRIPTOR, DISABLE_INLINE_CACHES_DESCRIPTOR, ENABLE_AUTO_PARALLELISM_DESCRIPTOR, diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java index 7593c42c299..0fb16ca3351 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java @@ -2,13 +2,13 @@ package org.enso.interpreter.runtime.error; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.ExportLibrary; import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; import org.enso.interpreter.runtime.data.ArrayRope; -import org.enso.interpreter.runtime.data.EnsoSourceSection; public class Warning implements TruffleObject { private final Object value; @@ -54,7 +54,10 @@ public class Warning implements TruffleObject { } @ExportMessage - SourceSection getSourceLocation() { + SourceSection getSourceLocation() throws UnsupportedMessageException { + if (location == null) { + throw UnsupportedMessageException.create(); + } return location; } } diff --git a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala index 66c3dbc76d5..f27f21bd0d8 100644 --- a/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala @@ -1504,7 +1504,7 @@ class IrToTruffle( s"argument<${name.map(_.name).getOrElse(String.valueOf(position))}>" val section = value.location - .map(loc => source.createSection(loc.start, loc.end)) + .map(loc => source.createSection(loc.start, loc.length)) .orNull val callTarget = Truffle.getRuntime.createCallTarget(