-
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
Runtime check of ascribed types #6790
Conversation
ConversionMethodsTest is failing for polyglot polyglot java import java.util.Map as Java_Map
import Standard.Base.Data.Map.Map
type Foo
Mk_Foo data
Foo.from (that:Map) = Foo.Mk_Foo that
main =
jmap = Java_Map.of "A" 1 "B" 2 "C" 3
Foo.from jmap . data . size the problem is polyglot java import java.util.Map as Java_Map
import Standard.Base.Data.Map.Map
import Standard.Base.Meta
main =
jmap = Java_Map.of "A" 1 "B" 2 "C" 3
r1 = Meta.type_of jmap
r2 = jmap.is_a Java_Map
r3 = jmap.is_a Map
[r1, r2, r3] returns Some consistency is needed:
|
dcc3e87
to
e2c7ed5
Compare
Failure after recent integration: |
...ntime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/IsValueOfTypeNode.java
Outdated
Show resolved
Hide resolved
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.
LGTM minus some stye changes
engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala
Outdated
Show resolved
Hide resolved
engine/runtime/src/main/scala/org/enso/compiler/codegen/IrToTruffle.scala
Outdated
Show resolved
Hide resolved
engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeNames.scala
Outdated
Show resolved
Hide resolved
case fn: IR.Function => verifyAscribedArguments(fn.arguments) | ||
case _ => newMethod | ||
} | ||
arr.getClass() |
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.
?
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.
Workaround for annoying "Unused variable warning" that fails Scala compilation. Left over some experiments.
engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeSignatures.scala
Outdated
Show resolved
Hide resolved
engine/runtime/src/main/scala/org/enso/compiler/pass/resolve/TypeSignatures.scala
Outdated
Show resolved
Hide resolved
private final ConditionProfile defaultingProfile = ConditionProfile.createCountingProfile(); | ||
// XXX: Type in a Node is wrong!!!!! | ||
private final Type expectedType; |
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 wrong as described in
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 looks great and I'm glad we are finally getting some type checking. That should make it so much easier to find many errors! 🎉 🎉
If I understand correctly from our catch-up, @jdunkerley, you suggested that we should raise these Type_Error
s as dataflow errors, not panics? Right?
(I think the rationale was that we don't want exposing panics to the user, at least too often, and these errors are going to happen relatively often if the user does something wrong; so indeed a dataflow error may be safer here).
On other hand I'd be actually cautious. Personally I do prefer the current state of things - panicking on type error. That is because for effectful computations (not common in the GUI but pretty common in our libraries), if the type error is a dataflow error, we may not notice it (if we discard the result) - the only but pretty important difference will be that the function did not actually run. This may lead to hard to debug errors.
I'm quite worried that by using dataflow errors instead of panics, we can make it harder to debug issues in our libraries. If it is a necessary sacrifice, so be it. But is it really necessary?
So I'd propose that maybe we should integrate this change keeping these panics as-is for now and we can see how this plays out in the IDE and if it causes any trouble? And if it causes problems we can revisit turning these into dataflow errors in a separate PR?
One comment about it. The error is:
Can we do something to make Moreover, this is a bit of a nitpick, but to be consistent with the 'Enso-style', we have a proper syntax for sum types, so why write So overall, I think it would be great if we can make the error say:
Can we have that? 🙂 |
And this inspires me that we should have a few more tests, just to make sure the logic works (if something doesn't work and cannot be fixed in this PR, please let's still add a test, mark it as pending and create a follow up ticket) I'd like to see a test for:
with calls
The Also I'm not sure if we have a test for
|
I agree with treating type errors as Panics for now, and we'll see how it goes. It's tricky to have one policy for everything, because we really want our library internals to always type-check perfectly, and we don't want to risk having type errors lost because a dataflow error was missed. But we don't want end users to experience this strictness. |
There is five
addressed in 31dff3c |
There are many failures in
I don't have expertise to know what to do with them. I am adding Update on May 30: Done in 5ca27c6 |
OK, added that as a TCR - a checkbox in the description of the PR.
Feel free to add more tests into my branch. More passing tests is always helpful. (Correct) tests that fail would be useful too.
@radeusgd, the biggest problem of the PR aren't missing test. We wanted these ascribed types to work as an opt-in and they do - for methods. However the syntax is already heavily used for constructors and thus they are opt-out for constructors!
I don't have expertise to fix them. Ideally I need you to go thru the runtime type errors and fix them. Or we need to find a way to make these constructor checks opt-in too. |
Regarding the issues with the tests that you mentioned, they all are related. This is a bit of an issue that we were trying to express stuff that currently Enso does not allow us to. So we either need to add the Let me first describe the concrete problems we saw:
One ugly workaround for 4 could be to do a sum type: Ideally, we need some kind of better abstraction like interfaces or typeclasses with which we can indicate that both Alternatively, I think a solution that is available to us without modifying the language, is to create a facade So as for (3) and (4), I'd suggest a rewrite to this form. IMO it would actually improve the clarity of our libraries. @jdunkerley what do you think about that? I remember that you were a bit skeptical about this idea some time ago, although I'm not sure exactly which parts seemed problematic? As for (1) - I don't know what the right fix is, we probably don't want to move |
This is the way to implement Type classes manually in current Enso. All one needs to do is to have two argument With |
assertEquals("Can read ten", 10, some.getMember("unwrap").asInt()); | ||
var lazy = module.invokeMember("eval_expression", "Maybe.Some (2 * 5)"); | ||
assertEquals("Can read first time ", 10, lazy.getMember("unwrap").asInt()); | ||
assertEquals("Can read second time", 10, lazy.getMember("unwrap").asInt()); |
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.
Further work tracked as #6883
@radeusgd you can use:
to identify the places where I had to opt-out from the runtime type checks. Currently I get 34 lines of output. |
If we can implement a facade type cleanly (not using the map builder set up of Dialect) - and without a massive amount of time as we are very resource light at the moment and velocity is low - am happy for us to prototype for Column. For 3 (and also things requiring "File_Format" types), implementing them as a "Connection" with overrides removes the possibility of having type specific methods. Likewise it made the implementation far less clear as you end up with needing to have things done the way the Dialect is built with maps building up functions and plugging bits and bobs in here and there. I spent a fair while playing with this when we started on Postgres/SQLite connections. For the facade of these type, it needs to be straight forward to add new implementations for things and allow for specific methods for the end types. I think this means a facade wouldn't work here and we are back on needing interfaces/typeclasses (which is the correct solution here). As for 4, we knew that one would bite us when we did it. I think we can restructure the resolve_aggregate easily to return the resolved columns either as a differet type or as a pair with the original Aggregate_Column. |
Pull Request Description
Implements #6682 - by adding a (raw) type check at each ascribed type.
Important Notes
The check is only performed for
(x : X)
ascription - both in constructor definitions as well as function definitions. That means the check is opt-in for functions - as our functions don't use such ascription so far or only at few places.Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
Scala,
Java,
style guides.
column
to beText | Integer
, but gotColumn
. Done in: 89a5150