mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 11:41:56 +03:00
Custom type conversion to double from large long (#4099)
When a large long would be passed to a host call expecting a double, it would crash with a ``` Cannot convert '<some long>'(language: Java, type: java.lang.Long) to Java type 'double': Invalid or lossy primitive coercion ``` That is unlikely to be expected by users. It also came up in the Statistics examples during Sum. One could workaround it by forcing the conversion manually with `.to_decimal` but it is not a permanent solution. Instead this change adds a custom type mapping from Long to Double that will do it behind the scenes with no user interaction. The mapping kicks in only for really large longs. # Important Notes Note that the _safe_ range is hardcoded in Truffle and it is not accessible in enso packages. Therefore a simple c&p for that max safe long value was necessary.
This commit is contained in:
parent
945aa2b2d7
commit
d3b350f460
@ -547,6 +547,7 @@
|
|||||||
- [Resolve Fully Qualified Names][4056]
|
- [Resolve Fully Qualified Names][4056]
|
||||||
- [Optimize Atom storage layouts][3862]
|
- [Optimize Atom storage layouts][3862]
|
||||||
- [Make instance methods callable like statics for builtin types][4077]
|
- [Make instance methods callable like statics for builtin types][4077]
|
||||||
|
- [Convert large longs to doubles, safely, for host calls][4099]
|
||||||
|
|
||||||
[3227]: https://github.com/enso-org/enso/pull/3227
|
[3227]: https://github.com/enso-org/enso/pull/3227
|
||||||
[3248]: https://github.com/enso-org/enso/pull/3248
|
[3248]: https://github.com/enso-org/enso/pull/3248
|
||||||
@ -636,6 +637,7 @@
|
|||||||
[4049]: https://github.com/enso-org/enso/pull/4049
|
[4049]: https://github.com/enso-org/enso/pull/4049
|
||||||
[4056]: https://github.com/enso-org/enso/pull/4056
|
[4056]: https://github.com/enso-org/enso/pull/4056
|
||||||
[4077]: https://github.com/enso-org/enso/pull/4077
|
[4077]: https://github.com/enso-org/enso/pull/4077
|
||||||
|
[4099]: https://github.com/enso-org/enso/pull/4099
|
||||||
|
|
||||||
# Enso 2.0.0-alpha.18 (2021-10-12)
|
# Enso 2.0.0-alpha.18 (2021-10-12)
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ import org.enso.librarymanager.published.PublishedLibraryCache
|
|||||||
import org.enso.lockmanager.server.LockManagerService
|
import org.enso.lockmanager.server.LockManagerService
|
||||||
import org.enso.logger.masking.Masking
|
import org.enso.logger.masking.Masking
|
||||||
import org.enso.loggingservice.{JavaLoggingLogHandler, LogLevel}
|
import org.enso.loggingservice.{JavaLoggingLogHandler, LogLevel}
|
||||||
import org.enso.polyglot.{RuntimeOptions, RuntimeServerInfo}
|
import org.enso.polyglot.{HostAccessFactory, RuntimeOptions, RuntimeServerInfo}
|
||||||
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
||||||
import org.enso.text.{ContentBasedVersioning, Sha3_224VersionCalculator}
|
import org.enso.text.{ContentBasedVersioning, Sha3_224VersionCalculator}
|
||||||
import org.graalvm.polyglot.Context
|
import org.graalvm.polyglot.Context
|
||||||
@ -270,6 +270,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
|||||||
val context = Context
|
val context = Context
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.allowAllAccess(true)
|
.allowAllAccess(true)
|
||||||
|
.allowHostAccess(new HostAccessFactory().allWithTypeMapping())
|
||||||
.allowExperimentalOptions(true)
|
.allowExperimentalOptions(true)
|
||||||
.option(RuntimeServerInfo.ENABLE_OPTION, "true")
|
.option(RuntimeServerInfo.ENABLE_OPTION, "true")
|
||||||
.option(RuntimeOptions.INTERACTIVE_MODE, "true")
|
.option(RuntimeOptions.INTERACTIVE_MODE, "true")
|
||||||
|
@ -5,7 +5,7 @@ import org.enso.libraryupload.DependencyExtractor
|
|||||||
import org.enso.loggingservice.{JavaLoggingLogHandler, LogLevel}
|
import org.enso.loggingservice.{JavaLoggingLogHandler, LogLevel}
|
||||||
import org.enso.pkg.Package
|
import org.enso.pkg.Package
|
||||||
import org.enso.pkg.SourceFile
|
import org.enso.pkg.SourceFile
|
||||||
import org.enso.polyglot.{PolyglotContext, RuntimeOptions}
|
import org.enso.polyglot.{HostAccessFactory, PolyglotContext, RuntimeOptions}
|
||||||
import org.graalvm.polyglot.Context
|
import org.graalvm.polyglot.Context
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -55,6 +55,7 @@ class CompilerBasedDependencyExtractor(logLevel: LogLevel)
|
|||||||
.newBuilder()
|
.newBuilder()
|
||||||
.allowExperimentalOptions(true)
|
.allowExperimentalOptions(true)
|
||||||
.allowAllAccess(true)
|
.allowAllAccess(true)
|
||||||
|
.allowHostAccess(new HostAccessFactory().allWithTypeMapping())
|
||||||
.option(RuntimeOptions.PROJECT_ROOT, pkg.root.getCanonicalPath)
|
.option(RuntimeOptions.PROJECT_ROOT, pkg.root.getCanonicalPath)
|
||||||
.option("js.foreign-object-prototype", "true")
|
.option("js.foreign-object-prototype", "true")
|
||||||
.option(
|
.option(
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.enso.polyglot;
|
||||||
|
|
||||||
|
import org.graalvm.polyglot.HostAccess;
|
||||||
|
|
||||||
|
/** Utility class for creating HostAccess object. */
|
||||||
|
public class HostAccessFactory {
|
||||||
|
|
||||||
|
// Copied from com.oracle.truffle.api.interop.NumberUtils
|
||||||
|
// since the latter is inaccessible
|
||||||
|
private static final long LONG_MAX_SAFE_DOUBLE = 9007199254740991L; // 2 ** 53 - 1
|
||||||
|
|
||||||
|
public HostAccess allWithTypeMapping() {
|
||||||
|
return HostAccess.newBuilder()
|
||||||
|
.allowPublicAccess(true)
|
||||||
|
.allowAllImplementations(true)
|
||||||
|
.allowAllClassImplementations(true)
|
||||||
|
.allowArrayAccess(true)
|
||||||
|
.allowListAccess(true)
|
||||||
|
.allowBufferAccess(true)
|
||||||
|
.allowIterableAccess(true)
|
||||||
|
.allowIteratorAccess(true)
|
||||||
|
.allowMapAccess(true)
|
||||||
|
.allowAccessInheritance(true)
|
||||||
|
.targetTypeMapping(
|
||||||
|
Long.class,
|
||||||
|
Double.class,
|
||||||
|
(v) -> v != null && !longInSafeDoubleRange(v, LONG_MAX_SAFE_DOUBLE),
|
||||||
|
(v) -> Double.longBitsToDouble(v))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean longInSafeDoubleRange(Long v, Long max) {
|
||||||
|
return v >= -max && v <= max;
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import org.enso.polyglot.debugger.{
|
|||||||
DebugServerInfo,
|
DebugServerInfo,
|
||||||
DebuggerSessionManagerEndpoint
|
DebuggerSessionManagerEndpoint
|
||||||
}
|
}
|
||||||
import org.enso.polyglot.{PolyglotContext, RuntimeOptions}
|
import org.enso.polyglot.{HostAccessFactory, PolyglotContext, RuntimeOptions}
|
||||||
import org.graalvm.polyglot.Context
|
import org.graalvm.polyglot.Context
|
||||||
|
|
||||||
import java.io.{InputStream, OutputStream}
|
import java.io.{InputStream, OutputStream}
|
||||||
@ -46,6 +46,7 @@ class ContextFactory {
|
|||||||
.newBuilder()
|
.newBuilder()
|
||||||
.allowExperimentalOptions(true)
|
.allowExperimentalOptions(true)
|
||||||
.allowAllAccess(true)
|
.allowAllAccess(true)
|
||||||
|
.allowHostAccess(new HostAccessFactory().allWithTypeMapping())
|
||||||
.option(RuntimeOptions.PROJECT_ROOT, projectRoot)
|
.option(RuntimeOptions.PROJECT_ROOT, projectRoot)
|
||||||
.option(RuntimeOptions.STRICT_ERRORS, strictErrors.toString)
|
.option(RuntimeOptions.STRICT_ERRORS, strictErrors.toString)
|
||||||
.option(RuntimeOptions.WAIT_FOR_PENDING_SERIALIZATION_JOBS, "true")
|
.option(RuntimeOptions.WAIT_FOR_PENDING_SERIALIZATION_JOBS, "true")
|
||||||
|
@ -12,6 +12,7 @@ polyglot java import java.lang.StringBuilder as Java_String_Builder
|
|||||||
polyglot java import java.util.ArrayList
|
polyglot java import java.util.ArrayList
|
||||||
polyglot java import java.time.LocalDate
|
polyglot java import java.time.LocalDate
|
||||||
polyglot java import java.time.LocalTime
|
polyglot java import java.time.LocalTime
|
||||||
|
polyglot java import org.enso.base.statistics.Moments
|
||||||
|
|
||||||
Any.test_me self x = x.is_nothing
|
Any.test_me self x = x.is_nothing
|
||||||
|
|
||||||
@ -43,6 +44,12 @@ spec =
|
|||||||
x = Integer.valueOf 1
|
x = Integer.valueOf 1
|
||||||
x.test_me x . should_equal False
|
x.test_me x . should_equal False
|
||||||
|
|
||||||
|
Test.group "Numeric values" <|
|
||||||
|
Test.specify "can be passed in host calls without lossy coercion exception" <|
|
||||||
|
large_long = 6907338656278321365
|
||||||
|
moments = Moments.new 1
|
||||||
|
moments.add large_long
|
||||||
|
|
||||||
Test.group "Java/Enso Date" <|
|
Test.group "Java/Enso Date" <|
|
||||||
Test.specify "Java date has Enso properties" <|
|
Test.specify "Java date has Enso properties" <|
|
||||||
april1st = LocalDate.of 2022 04 01
|
april1st = LocalDate.of 2022 04 01
|
||||||
|
Loading…
Reference in New Issue
Block a user