-
Notifications
You must be signed in to change notification settings - Fork 323
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
Mixed Decimal/Float operations throw error or attach warning #10725
Conversation
+ self (that : Decimal) -> Decimal ! Arithmetic_Error = self.add that | ||
+ self (that : Decimal) = self.add that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these return type check being removed? It seems suspicious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I leave the checked annotations in, I get this:
Reason: An unexpected panic was thrown: Type error: expected the result of `+` to be Decimal, but got <ERR>.
I'll be submitting a bug for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, weird. Okay then, I assume we should re-add once the bug is fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a TODO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can reproduce the failure as
sbt:enso> runEngineDistribution --run test/Base_Tests Arithmetic.with.decimal.and.implicitly.converted.float.should.fail
correct? Then the problem is that there is a WithWarning
instance over DataflowError
instance. Do we really want to support attaching warnings to errors? It doesn't make sense to re-attach warnings to DataflowError
. Possible fix:
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
index e1ff24d35c..f750e377d6 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
@@ -73,7 +73,7 @@ public final class Warning implements EnsoObject {
description = "Attaches the given warning to the value.",
autoRegister = false)
@Builtin.Specialize
- public static WithWarnings attach(
+ public static EnsoObject attach(
EnsoContext ctx, WithWarnings value, Object warning, Object origin) {
return value.append(ctx, new Warning(warning, origin, ctx.nextSequenceId()));
}
@@ -83,7 +83,7 @@ public final class Warning implements EnsoObject {
description = "Attaches the given warning to the value.",
autoRegister = false)
@Builtin.Specialize(fallback = true)
- public static WithWarnings attach(EnsoContext ctx, Object value, Object warning, Object origin) {
+ public static EnsoObject attach(EnsoContext ctx, Object value, Object warning, Object origin) {
return WithWarnings.wrap(ctx, value, new Warning(warning, origin, ctx.nextSequenceId()));
}
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
index 2968eaf419..0bb3191157 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
@@ -120,9 +120,11 @@ public final class WithWarnings implements EnsoObject {
return goodValue;
}
- public static WithWarnings wrap(EnsoContext ctx, Object value, Warning... warnings) {
+ public static EnsoObject wrap(EnsoContext ctx, Object value, Warning... warnings) {
if (value instanceof WithWarnings with) {
return with.append(ctx, warnings);
+ } else if (value instanceof DataflowError err) {
+ throw err;
} else {
return new WithWarnings(value, ctx.getWarningsLimit(), warnings);
}
CCing @Akirathan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This warning is attached by propagation, so perhaps this is a case we do need to handle. I can reproduce it like this:
err_warn -> Integer ! Illegal_Argument =
v = Warning.attach (Out_Of_Range.Error "qewr") 12
case v of
_ : Integer -> Error.throw (Illegal_Argument.Error "asdf")
In this case the warning and error are in the same code. But in general, if a value with a warning results in a throw
, the warning will propagate to the thrown error.
For this PR I can remove the warning as a workaround, but in general this seems like something that could happen naturally. I'm surprised it hasn't happened already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This patch is resulting in this:
Execution finished with an error: Wrapped_Dataflow_Error.Error
at <enso> Panic.throw(Internal)
at <enso> Panic.type.rethrow_wrapped_if_error<arg-1>(Panic.enso:223:32-85)
at <enso> Panic.type.rethrow_wrapped_if_error(Panic.enso:223:9-96)
at <enso> Builder.append_vector_range(Vector.enso:1409-1415)
at <enso> case_branch(Suite.enso:99:25-68)
at <enso> Suite.run_with_filter.junit_sb_builder(Suite.enso:95-101)
at <enso> Array_Like_Helpers.each.Array_Like_Helpers.each(Array_Like_Helpers.enso:301:9-24)
at <enso> Range.each.go<arg-1>(Range.enso:262:36-51)
at <enso> Range.each.go<arg-2>(Range.enso:262:21-52)
at <enso> Range.each.go(Range.enso:261-263)
at <enso> Test_Reporter.wrap_junit_testsuites(Test_Reporter.enso:26:14-19)
at <enso> Suite.run_with_filter(Suite.enso:91-101)
at <enso> Decimal_Spec.main(Decimal_Spec.enso:1068:5-32)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what the patch results in. I had no time to investigate where the problem is. I assumed it is in libs....
...case the warning and error are in the same code...
Great example! I turning it into a failing test and I'll play with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instanceof
in a specialization is not correctAny.to
is a "final" method and shouldn't be overriden- what are the benchmarks results?
@@ -100,7 +101,8 @@ boolean equalsAtomsWithCustomComparator( | |||
var args = new Object[] {cachedComparator, self, other}; | |||
var result = invokeNode.execute(compareFn, null, State.create(ctx), args); | |||
assert orderingOrNullOrError(this, ctx, result, compareFn); | |||
return ctx.getBuiltins().ordering().newEqual() == result; | |||
var resultWithWarningRemoved = result instanceof WithWarnings ww ? ww.getValue() : result; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be using instanceof
. We should use WarningsLibrary
.
At minimum add a new @CachedLibrary WarningsLibrary
argument to the specialization method and use it to extract the original value via removeWarnings.
What is the impact on benchmarks? I am afraid just adding this check may slow things down. Maybe we will need a separate specialization...
@@ -442,6 +443,64 @@ type Number | |||
floating point numbers. | |||
@Builtin_Type | |||
type Float | |||
## GROUP Conversions | |||
ICON convert | |||
Generic conversion of an arbitrary Enso value to requested type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arbitrary Enso value!? I guess the whole documentation has just been copied. The documentation doesn't make sense here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is removed.
yields_5 = Complex.Value 3 4 . to Number ignore_im=False | ||
default5 = Complex.Value 3 4 . to Number | ||
to : Any -> Any ! No_Such_Conversion | ||
to self target_type = case target_type of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why there should be a special to
method on Float
? The generic Any.to
method should be good enough.
If there was a way to define a final
method (like in Java), then Any.to
should be final
. If one wants to hook into behavior of Any.to
method, one should do it with from
conversions. Otherwise one cannot guarantee consistency between from
and to
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid the point of this PR is to add an exception to the from
/to
inconsistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is removed.
@@ -89,6 +89,9 @@ type Decimal | |||
## PRIVATE | |||
Value (big_decimal : BigDecimal) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use private
keyword.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see private
keyword is gone. Why? 1381d29 doesn't explain why that has happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I put the private
keyword back, I get this:
Private access error: The project-private method 'null.big_decimal' in unknown project cannot be accessed from project 'Standard.Base'.
This is happening in a method of Decimal, which should have access. I don't know why it calls it an "unknown project".
Full test failure:
- [FAILED] should be able to construct a Decimal with dec [43ms]
Reason: An unexpected panic was thrown: (Private_Access.Error 'Standard.Base' Nothing 'null.big_decimal')
at <enso> Decimal.unscaled_value<arg-0>(/Users/gmt/dev/enso/enso/built-distribution/enso-engine-0.0.0-dev-macos-aarch64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Decimal.enso:1169:38-53)
at <enso> Decimal.unscaled_value(/Users/gmt/dev/enso/enso/built-distribution/enso-engine-0.0.0-dev-macos-aarch64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Decimal.enso:1169:38-67)
at <enso> Decimal.internal_representation(/Users/gmt/dev/enso/enso/built-distribution/enso-engine-0.0.0-dev-macos-aarch64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Decimal.enso:1173:55-73)
at <enso> Decimal.should_have_rep<arg-0>(/Users/gmt/dev/enso/enso/test/Base_Tests/src/Data/Decimal_Spec.enso:14:36-63)
at <enso> Decimal.should_have_rep(/Users/gmt/dev/enso/enso/test/Base_Tests/src/Data/Decimal_Spec.enso:14:36-82)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? Creating `Decimal`s and Converting to `Decimal` | ||
|
||
When creating a `Decimal` from a literal floating-point value, the | ||
preferred method is to express the literal as a string and use | ||
`Decimal.from_text`, since this will give a `Decimal` that matches the | ||
value precisely. | ||
|
||
To convert a `Float` or `Integer` to a `Decimal`, use its `.to_decimal` | ||
method. You can also use `Float.to Decimal` to convert a `Float` to a | ||
`Decimal`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like this is still missing information about when I should expect a warning and when not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is removed. The same documentation exists in Decimal.enso but there it is followed by error/warning documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad to see 9ce1a0a we no longer override to
method. Rather than removing -> Decimal
, consider not attaching warnings to errors as the provided patch does. If the benchmarks are OK, go on and merge.
var result = invokeNode.execute(compareFn, null, State.create(ctx), args); | ||
assert orderingOrNullOrError(this, ctx, result, compareFn); | ||
if (warnings.hasWarnings(result)) { | ||
result = warnings.removeWarnings(result); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is better than instanceof
. The effect on benchmark results remain to be seen. Possibly one could also use BranchProfile to lower the number of generated IR nodes in case without warnings.
+ self (that : Decimal) -> Decimal ! Arithmetic_Error = self.add that | ||
+ self (that : Decimal) = self.add that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can reproduce the failure as
sbt:enso> runEngineDistribution --run test/Base_Tests Arithmetic.with.decimal.and.implicitly.converted.float.should.fail
correct? Then the problem is that there is a WithWarning
instance over DataflowError
instance. Do we really want to support attaching warnings to errors? It doesn't make sense to re-attach warnings to DataflowError
. Possible fix:
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
index e1ff24d35c..f750e377d6 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/error/Warning.java
@@ -73,7 +73,7 @@ public final class Warning implements EnsoObject {
description = "Attaches the given warning to the value.",
autoRegister = false)
@Builtin.Specialize
- public static WithWarnings attach(
+ public static EnsoObject attach(
EnsoContext ctx, WithWarnings value, Object warning, Object origin) {
return value.append(ctx, new Warning(warning, origin, ctx.nextSequenceId()));
}
@@ -83,7 +83,7 @@ public final class Warning implements EnsoObject {
description = "Attaches the given warning to the value.",
autoRegister = false)
@Builtin.Specialize(fallback = true)
- public static WithWarnings attach(EnsoContext ctx, Object value, Object warning, Object origin) {
+ public static EnsoObject attach(EnsoContext ctx, Object value, Object warning, Object origin) {
return WithWarnings.wrap(ctx, value, new Warning(warning, origin, ctx.nextSequenceId()));
}
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
index 2968eaf419..0bb3191157 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/error/WithWarnings.java
@@ -120,9 +120,11 @@ public final class WithWarnings implements EnsoObject {
return goodValue;
}
- public static WithWarnings wrap(EnsoContext ctx, Object value, Warning... warnings) {
+ public static EnsoObject wrap(EnsoContext ctx, Object value, Warning... warnings) {
if (value instanceof WithWarnings with) {
return with.append(ctx, warnings);
+ } else if (value instanceof DataflowError err) {
+ throw err;
} else {
return new WithWarnings(value, ctx.getWarningsLimit(), warnings);
}
CCing @Akirathan.
|
Arithmetic operations throw; comparisons attach warnings.
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
TypeScript,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.