Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[6.d] Attach ex. handler to start in sink context
Per 6.d-prep: https://github.com/perl6/6.d-prep/blob/69a7d9c5e5d8ff3bed69c6f33577ada4bb8470be/TODO/FEATURES.md#make-start-blocks-in-sink-context-attach-an-error-handler

I've used the normal handler instead of `uncaught_handler` the 6.d-prep
notes say because I don't know how to use the latter (and noticed that
note too late). I'm also unsure if the uncaught_handler handles custom
exception handlers; this commit does.

When detecting the `start` was in sink context, we create a thunk
with the call to original block and use the `handle` op to handle the
exception. The thunk is there so the user can use their own `CATCH`.

One problem that I noticed is code like `sub foo { start die }()`
does NOT attach the handler, because sinkage of stuff like that
requires calls to `.sink` method instead of the `unwanted` Actions helper.
  • Loading branch information
zoffixznet committed Sep 21, 2018
1 parent 369068a commit 6ee5f75
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/Perl6/Actions.nqp
Expand Up @@ -325,6 +325,21 @@ sub unwanted($ast, $by) {
$ast.sunk(1);
}
elsif $ast.op eq 'callmethod' {
if $ast.has_ann('promise_starter') && ! $*W.lang-ver-before('d') {
$ast[1] := QAST::WVal.new: value =>
$*W.find_symbol(['&trait_mod:<is>'])(:hidden-from-backtrace,
$*W.create_thunk: $ast.node,
QAST::Op.new: :op<handle>,
QAST::Op.new(:op<call>, $ast[1]), # Promised code block
'CATCH',
QAST::Op.new: :op<callmethod>,
:name<handle-exception>,
QAST::Op.new(:op<getcomp>,
QAST::SVal.new: :value<perl6>),
QAST::Op.new: :op<exception>
);
return $ast;
}
if !$ast.nosink && !$*COMPILING_CORE_SETTING && !%nosink{$ast.name} {
return $ast if $*ALREADY_ADDED_SINK_CALL;
$ast.sunk(1);
Expand Down Expand Up @@ -2736,12 +2751,13 @@ class Perl6::Actions is HLL::Actions does STDActions {
$*W.install_lexical_magical($block, '$!');
}
make QAST::Op.new(
:node($/),
:op('callmethod'),
:name('start'),
:returns($*W.find_symbol(['Promise'])),
QAST::WVal.new( :value($*W.find_symbol(['Promise'])) ),
$<blorst>.ast
);
).annotate_self: 'promise_starter', 1;
}

method statement_prefix:sym<lazy>($/) {
Expand Down
6 changes: 6 additions & 0 deletions src/core/traits.pm6
Expand Up @@ -374,6 +374,12 @@ multi sub trait_mod:<of>(Routine:D $target, Mu:U $type) {
$target.^mixin(Callable.^parameterize($type))
}

multi sub trait_mod:<is>(Code:D $r, :$hidden-from-backtrace!) {
$r.^mixin( role is-hidden-from-backtrace {
method is-hidden-from-backtrace(--> True) { }
}) if $hidden-from-backtrace;
}

multi sub trait_mod:<is>(Routine:D $r, :$hidden-from-backtrace!) {
$r.^mixin( role is-hidden-from-backtrace {
method is-hidden-from-backtrace(--> True) { }
Expand Down

1 comment on commit 6ee5f75

@zoffixznet
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to include in the commit message: I did try changing the Routine:D's trait to Code:D instead, but the setting failed to compile in that case due to some error about Hash, hence why I added it as a separate multi.

Please sign in to comment.