diff --git a/proposals/exception-handling/Exceptions.md b/proposals/exception-handling/Exceptions.md index ee89a25b..c0120fca 100644 --- a/proposals/exception-handling/Exceptions.md +++ b/proposals/exception-handling/Exceptions.md @@ -274,10 +274,10 @@ try label and delegates exception handling to a `catch`/`catch_all`/`delegate` specified by the `try` label. For example, consider this code: ``` -try $l1 +try $l0 try call $foo - delegate $l1 ;; (= delegate 0) + delegate $l0 ;; (= delegate 0) catch ... catch_all @@ -288,28 +288,109 @@ end If `call $foo` throws, searching for a catching block first finds `delegate`, and because it delegates exception handling to catching instructions associated with `$l1`, it will be next checked by the outer `catch` and then `catch_all` -instructions. When the specified label within a `delegate` instruction does not -correspond to a `try` instruction, it is a validation failure. +instructions. + +`delegate` can also target `catch`-less `try`s or non-`try` block constructs +like `block`s or `loop`s, in which case the delegated exception is assumed to +propagate to the outer scope and will be caught by the next matching +try-catches, or rethrown to the caller if there is no outer try block. In the +examples, catches are annotated with `($label_name)` to clarify which `try` it +belongs to for clarification; it is not the official syntax. +``` +try $l0 + block $l1 + try + call $foo + delegate $l1 ;; delegates to 'catch ($l0)' + end +catch ($l0) +end +``` + +Like branches, `delegate` can only target outer blocks, and effectively +rethrows the exception in that block. Consequently, delegating to a specific +`catch` or `catch_all` handler requires targeting the respective label from +within the associated `try` block. Delegating to a label from within a `catch` +block does delegate the exception to the next enclosing handler -- analogous to +performing a `throw` within a `catch` block, that handler is no longer active +at that point. Here is another example: -Note that the example below is a validation failure: ``` -try $l1 -catch +try $l0 + try $l1 + catch ($l1) + try + call $foo + delegate $l1 ;; delegates to 'catch ($l0)' + catch_all + ... + end +catch ($l0) +``` + +Here the `delegate` is targeting `catch ($l1)`, which exists before the +`delegate`. So in case an exception occurs, it propagates out and ends up +targetting `catch ($l0)`, if the catch has a matching tag. If not, it will +propagate further out. Even if the `catch_all` is below the `delegate`, +`delegate` targets catches of a `try` as a whole and does not target an +individual `catch`/`catch_all`, so it doesn't apply. + +If `delegate` targets the implicit function body block, then in effect it +delegates the exception to the caller of the current function. For example: +``` +(func $test try - call $foo - delegate $l1 ;; (= delegate 0) -catch_all - ... -end + try + call $foo + delegate 1 ;; delegates to the caller + catch + ... + catch_all + ... + end +) +``` +In case `foo` throws, `delegate 1` here delegates the exception handling to the +caller, i.e., the exception escapes the current function. If the immediate is +greater than or equal to the number of block nesting including the implicit +function-level block, it is a validation failure. In this example, any number +equal to or greater than 2 is not allowed. + +The below is an example that includes all the cases explained. The numbers +within `()` after `delegate`s are the label operands in immediate values. +``` +(func $test + try $lA + block $lB + try $lC + try + delegate $lC (0) ;; delegates to 'catch ($lC)' + try + delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' + try + delegate $lA (2) ;; delegates to 'catch ($lA)' + try + delegate 3 ;; propagates to the caller + try + delegate 4 ;; validation failure + catch ($lC) + try + delegate $lC (0) ;; 'catch ($lC)' is above this instruction, + ;; so delegates to 'catch ($lA)' + try + delegate $lB (1) ;; $lB is a block, so delegates to 'catch ($lA)' + try + delegate $lA (2) ;; delegates to 'catch ($lA)' + try + delegate 3 ;; propagates to the caller + try + delegate 4 ;; validation failure + end ;; try $lC + end ;; block $lB + catch ($lA) + end ;; try $lA +) ``` -Here `delegate` is trying to delegate to `catch`, which exists before the -`delegate`. The `delegate` instruction can only target `try` label whose -catching instructions (`catch`/`catch_all`/`delegate`) come after the -`delegate` instruction. - -`delegate` can also target `catch`-less `try`, in which case the effect is the -same as if the `try` has catches but none of the catches are able to handle the -exception. ### JS API