-
-
Notifications
You must be signed in to change notification settings - Fork 671
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
[js] rework exception handling (closes #6458) #6713
Conversation
@@ -26,6 +26,7 @@ | |||
return js.Object.prototype.hasOwnProperty.call(o, field); | |||
} | |||
|
|||
@:pure |
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 (and other similar ones) are not inferred as pure anymore, because the filter adds haxe.CallStack.lastException
assignment. It might make sense to move injection of that assignment into a separate post-analyzer/dce filter.
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.
Probably should do that...
|
||
Calling this is only possible inside a catch statement. | ||
**/ | ||
public static function getOriginalException():Dynamic { |
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 one allows for implementing functions like this:
static function catchToCallback<T>(fn:()->T, callback:(error:Any, result:Null<T>)->Void) {
var result =
try
fn()
catch (e:Any)
return callback(js.Lib.getOriginalException(), null);
callback(null, result);
}
which will be compiled nicely into
Main.catchToCallback = function(fn,callback) {
var result;
try {
result = fn();
} catch( e ) {
callback(e,null);
return;
}
callback(null,result);
};
(note how we don't unwrap e
here, because we requested "original exception")
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 looks like you will lose haxe.CallStack.exceptionsStack()
functionality.
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.
Not really, it's just not generated in a simple case where haxe.CallStack
is not used.
tests/optimization/src/TestJs.hx
Outdated
@@ -172,12 +172,12 @@ class TestJs { | |||
try throw false catch (e:Dynamic) {} | |||
} | |||
|
|||
@:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {if (e instanceof js__$Boot_HaxeError) e = e.val;TestJs.use(e);}') | |||
@:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {var e1 = (e instanceof js__$Boot_HaxeError) ? e.val : e;var e2 = e1;TestJs.use(e2);}') |
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 var e2 = e1;
is unfortunate, but I think that's something the analyzer should handle.
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 probably considers the variable to be a user-var. Try adding Meta.CompilerGenerated
to 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.
Will try, thanks!
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 helped!
tests/optimization/src/TestJs.hx
Outdated
static function testHaxeErrorUnwrappingWhenUsed() { | ||
try throw false catch (e:Dynamic) use(e); | ||
} | ||
|
||
@:js("try {throw new js__$Boot_HaxeError(false);} catch( e ) {if (e instanceof js__$Boot_HaxeError) e = e.val;if( js_Boot.__instanceof(e,Bool) ) {} else throw(e);}") | ||
@:js('try {throw new js__$Boot_HaxeError(false);} catch( e ) {var e1 = (e instanceof js__$Boot_HaxeError) ? e.val : e;if(typeof(e1) != "boolean") {throw e;}}') |
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 was actually incorrect before (an instance of #6458)
tests/optimization/src/TestJs.hx
Outdated
@@ -62,7 +62,7 @@ class TestJs { | |||
return v + v2; | |||
} | |||
|
|||
@:js("var a = [];var tmp;try {tmp = a[0];} catch( e ) {tmp = null;}tmp;") | |||
@:js("var a = [];var tmp;try {tmp = a[0];} catch( e ) {var e1 = (e instanceof js__$Boot_HaxeError) ? e.val : e;var e2 = e1;tmp = null;}tmp;") |
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.
More generated code because @:analyzer(no_local_dce)
is being respected, since this is now inserted as proper AST instead of doing some checks at the generator level.
src/filters/jsExceptions.ml
Outdated
*) | ||
|
||
(* | ||
This filter handles everything related to expressions for the JavaScript target: |
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.
Maybe "related to exceptions"?
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.
Oops, yeah :)
src/filters/jsExceptions.ml
Outdated
let follow = Abstract.follow_with_abstracts | ||
|
||
let rec is_js_error t = | ||
match t with |
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.
Looks like follow_with_abstracts
should be used 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.
We should add a test that catches something which is typedeffed to/abstracts over js.Error.
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 function is meant to run with a followed type already. In fact it should be called with a tclass
, hmmm...
… filter, so it doesn't interfere with purity inference and can make more informed decision whether it's actually needed
I think it's pretty good now. I moved |
This reworks JS exception handling in a pre-analyzer/pre-dce filter that handles wrapping/unwrapping, single-catch + Std.is transformation, rethrowing, haxe.CallStack, etc.
E.g.
is now generated as
Let's see what travis has to say about this...