I will collect here other issues if I will find them.

Looking in Context methods which I mentioned here I found that debugger is
broken for stepping through warnings. And it means that debugging
deprecated methods can hang debugger.

I will create another thread on this issue because it has more questions on
current exceptions design.

чт, 19 дек. 2019 г. в 18:39, Denis Kudriashov <dionisi...@gmail.com>:

> The solution to problem is to resignal UnhandledError instead of simple
> signalling. Resignal uses original signalContext as a starting point for
> handlers lookup:
>
> UnhandledError>>signalForException: anError
>
> ^anError resignalAs: (self new
>
> exception: anError;
>
> yourself)
>
>
> I played with some of debugger issues and this code really fixes them.
> For example try debug following script in playground:
>
> [
>  self methodWithError
> ] on: Error do: [ :e | e logCr. e pass ]
>
> With error method:
>
>
> Object>>methodWithError
>
> 1/0
>
> Step into #methodWithError and then stepThrough "1/0".
> In current image it will hands for a while and then it will open another
> debugger with single error item. The current debugger process will be
> broken.
> Now try to apply proposed change for UnhandledError>>signalForException:
> and repeat experiment. StepThrough "1/0" will move debugger to ZeroDivide
> signal showing correct stack.
>
>
> Notice that debugging separate "self methodWithError" without outer
> handler works correctly in both cases. But you should be in clean stack
> without hidden outer handlers. And in Playground or when you use debugIt it
> is clean.
> But you can try in "bad" environment. Execute in browser editor "self
> halt. self methodWithError". And in debugger just Step Through
> #methodWithError. It will hangs. Proposed change fixes that.
>
> I will prepare PR with tests. But it would be nice to find other broken
> places which will be fixed
>
> чт, 19 дек. 2019 г. в 00:42, Denis Kudriashov <dionisi...@gmail.com>:
>
>> I think this problem could lead to debugger issues with stepOver and
>> stepThrough. For example:
>>
>> Context>>#stepToHome:
>>      ...
>>      context := aContext insertSender: (Context
>>           contextOn: UnhandledError do: [:ex | ... ])
>>
>> It is a method which is used for stepThrough. If current method has outer
>> handler for Error then the UnhandledError logic will be ignored.
>>
>> Step over is based on following method:
>>
>> Context>>runUntilErrorOrReturnFrom: aSender
>>            ...
>>
>> context := aSender insertSender: (Context
>>
>> contextOn: Error do: [:ex |
>>
>>    error ifNil: [
>>
>>    "this is ugly but it fixes the side-effects of not sending an
>> Unhandled error on Halt"
>>
>>    error := (ex isKindOf: UnhandledError) ifTrue: [ ex exception ]
>> ifFalse: [ ex ].
>> ...
>>
>> I think UnhandledError branch will never be true:
>>
>> [ 1/0 ] on: Error do: [:e | e logCr. e3 pass ]
>>
>> Handler here is executed only once with ZeroDivide error.
>> Previous version was based on UnhandledError handler:
>>
>>
>> context := aSender insertSender: (Context
>>           contextOn: UnhandledError, Halt do: [:ex | ...]
>>
>>
>> which had the same issue when there is an outer error handler.
>> And we have such general error handler (probably introduced in Pharo 6):
>>
>> WorldMorph>>becomeActiveDuring: aBlock
>>
>> ...
>>
>> aBlock
>>
>> on: Error
>>
>> do: [ :ex | ... ex pass ]
>>
>>
>> Any UI event is processed under this method.
>>
>> ср, 18 дек. 2019 г. в 22:31, Denis Kudriashov <dionisi...@gmail.com>:
>>
>>> Users of UnhandledError definitely shows that it is a critical bug.
>>>
>>> For example we rely on UnhandledError in Announcer to ensure that all
>>> subscriptions will be processed independently on errors signalled by any of
>>> them:
>>>
>>> ann := Announcer new.
>>> ann when: ValueChanged do: [:ann | 1 logCr. 1/0 ].
>>> ann when: ValueChanged do: [:ann | 2 logCr. 2/0 ].
>>> ann when: ValueChanged do: [:ann | 3 logCr. 3/0 ].
>>>
>>>
>>> ann announce: ValueChanged new
>>>
>>>
>>> It will show 1, 2, 3 in transcript and open 3 debuggers. Each error is
>>> deferred to the background process allowing the delivery to continue:
>>>
>>> AnnouncementSubscription>>deliver: anAnnouncement
>>>
>>> " deliver an announcement to receiver. In case of failure, it will be
>>> handled in separate process"
>>>
>>>
>>> ^ (self handlesAnnouncement: anAnnouncement ) ifTrue: [
>>>
>>> [action cull: anAnnouncement cull: announcer]
>>>
>>> on: UnhandledError fork: [:ex | ex pass ]]
>>>
>>>
>>> Now if you will try to wrap #announce: into handler block the deliver
>>> will be interrupted by first error:
>>>
>>> [ann announce: ValueChanged new] on: ZeroDivide do: [ :err | err logCr.
>>> err pass ].
>>>
>>>
>>> It will open single debugger at first handler error.
>>>
>>> ср, 18 дек. 2019 г. в 20:44, Denis Kudriashov <dionisi...@gmail.com>:
>>>
>>>> Hi.
>>>>
>>>> I played a bit with exceptions trying to detect that given block will
>>>> open the debugger. My idea was to simply catch UnhandledError which
>>>> normally means that no outer code handles given error and therefore
>>>> debugger is appeared.
>>>> For my surprise the following example works from playground but not
>>>> from the browser editor:
>>>>
>>>>
>>>> [MyTestError signal ] on: UnhandledError do: [ :e | self halt ]
>>>>
>>>>
>>>> In playground you will see the halt. But from the browser the debugger
>>>> will show MyTestError.
>>>>
>>>> After breaking my head I found that there is a difference how
>>>> scripts are executed in those tools. In Playground it is a deferred action.
>>>> But in the browser it is evaluated as a deep event processing code (keymap
>>>> processing) and there is an outer error handler (on: Error do: ) which does
>>>> some work and passes the exception further (err pass).
>>>> Following script demonstrates the difference in the error processing
>>>> logic when there is an outer handler:
>>>>
>>>>
>>>> [
>>>>
>>>> [MyTestError signal ] on: UnhandledError do: [ :e | self halt ]
>>>>
>>>>  ] on: MyTestError do: [ :z | z pass]
>>>>
>>>>
>>>> Try it from playground. Second line separately will show the halt while
>>>> all together it will stop at MyTestError signal.
>>>>
>>>> Debugging shows that when the outer handler is processed it sets the
>>>> handler context into the exception and it skips the existing handler for
>>>> UnhandledError.
>>>>
>>>> The question: is it a feature or a bug?
>>>> Think also how following code should work (unrelated to UnhandledError
>>>> logic):
>>>>
>>>> [
>>>>
>>>> [ 1/0 ] on: MyTestError do: [ :e | self halt ]
>>>>
>>>>  ] on: ZeroDivide do: [ :z | MyTestError signal ]
>>>>
>>>>
>>>> Currently it will show MyTestError signal.
>>>>
>>>> Best regards,
>>>> Denis
>>>>
>>>

Reply via email to