ObjectSubject>>evaluate: expression ifCompilerError: onCompilerError <[String]> ifError: onError <[NewspeakDebugging ThreadSubject, Exception]> ^<ObjectMirror> = (
If one tries to debug an expression within this context, all attempts at stepping end up cutting back the stack to this handler *unless* one hacks ContextPart>>runUntilErrorOrReturnFrom:. This hack breaks the debugger's handling of block non-local return.
For example, reproduce thusly:
1. check if ContextPart>>runUntilErrorOrReturnFrom: contains my hack, which reads something like
[ctxt isDead or: [aSender isDead]] whileFalse: [topContext := topContext stepToCallee].
^{aSender isDead
ifTrue:
[| retValue |
retValue := ctxt isUnwindContext ifTrue:
[ctxt tempAt: 3]. "returnValue in ensure: and result in ifCurtailed:"
aSendersSender push: retValue.
aSendersSender]
ifFalse: [topContext].
nil}
the phrase should read simply
[ctxt isDead] whileFalse: [topContext := topContext stepToCallee].
^{topContext. nil}
If it contains the hack you can see that stepping over the value: send in Interval>>do: in e.g. self halt. (1 to: 5) do: [:i| i = 1 ifTrue: [^#ok]]. ^#bad does *not* return. Remove the hack and see that the debugger does execute the non-local return.
So without the hack evaluate e.g.
self halt. (1 to: 5) do: [:i| i = 1 ifTrue: [^#ok]. #bad]
In the resulting debugger inspect the Halt context. In that inspector use Interact to get an evaluator in which one writes e.g.
self halt. self interpretNextInstructionFor: self
Clock on the Halt exception to open a debugger, and therein try any kind of step and the debugger will jump back to the UnhandledError handler in ObjectSubject>>evaluate: ifCompilerError ifError:.
IMO the UnhandledError handler in ObjectSubject>>evaluate:ifCompilerErrorifError: is erroneous. What happens is that when the Halt is raised, the handler catches the exception, allowing it to be passed to the debugger, but the continuation is to return to the enclosing block (the block that receives newProcess in ObjectSubject>>evaluate:ifCompilerErrorifError:.
One question is what was the intent of the UnhandledError handler in the above? Could it be that not all compiler errors were reported through the ifError: arm of evaluate:ifError:? If so, the right fix is to refactor evaluation to split compilation of the doit from execution of the doit, wrap the compilation with an Error handler, and leave the doit's execution unguarded.
Another question is if I make some changes is this likely to affect the JavaScript or Dart back-ends?
--
best,
Eliot