-
Notifications
You must be signed in to change notification settings - Fork 161
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
Overhaul tracking of current statement, fixing several bugs where the break loop error message referenced the wrong statement #2520
Conversation
tst/test-error/debug-var.g.out
Outdated
@@ -109,7 +109,7 @@ brk_2> IsBound(y); | |||
true | |||
brk_2> unbound_higher; | |||
Error, Variable: <debug-variable-64-4> must have a value in | |||
<corrupted statement> called from | |||
Error( "foobar" ); at *stdin*:20 called from |
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 is a clear improvement, I'd say
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.
Yup!
@@ -2,7 +2,7 @@ gap> # test returning from a 'method not found' error | |||
gap> f:=a->a+a;; f(()); | |||
Error, no method found! For debugging hints type ?Recovery from NoMethodFound | |||
Error, no 1st choice method found for `+' on 2 arguments at GAPROOT/lib/methsel2.g:250 called from | |||
a + a at *stdin*:3 called from | |||
return a + a; at *stdin*:3 called from |
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.
Hm.... Is this new behaviour OK? Or do we want the old back? Opinions, anybody?
Codecov Report
@@ Coverage Diff @@
## master #2520 +/- ##
=========================================
+ Coverage 83.06% 83.76% +0.7%
=========================================
Files 680 681 +1
Lines 346665 346339 -326
=========================================
+ Hits 287941 290105 +2164
+ Misses 58724 56234 -2490
|
ddea702
to
a022172
Compare
7653a7d
to
369a079
Compare
331c98e
to
6340070
Compare
a3b9d61
to
6d71dc4
Compare
There is still much more that should be done on this subject, but I think instead of letting this rot, we should just merge it. To this end, I cleaned up the PR and rebased it again. |
@@ -253,7 +254,7 @@ Obj FuncCALL_WITH_CATCH(Obj self, Obj func, volatile Obj args) | |||
CHANGED_BAG(res); | |||
STATE(ThrownObject) = 0; | |||
SWITCH_TO_OLD_LVARS(currLVars); | |||
STATE(CurrStat) = currStat; | |||
GAP_ASSERT(currStat == BRK_CALL_TO()); |
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 is a paranoia check, to verify I did not break anything fundamental in the refactoring. It could/should likely be removed eventually.
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.
I personally don't think you can have too many asserting paranoia checks :)
src/stats.c
Outdated
// HACK: point current "statement" at the condition expression, so | ||
// that if there is an error in it, it resp. its location is printed, | ||
// not the whole loop statement. | ||
SET_BRK_CALL_TO(cond); |
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 might want to add a few more of these "hacks" for now. The purpose of these hacks is as follows: Without them, you might see:
Error, Rational operations: <divisor> must not be zero in
if true = 1 / 0 then
return 1;
fi; at *stdin*:9 called from
with the hacks, you get:
Error, Rational operations: <divisor> must not be zero in
1 / 0 at *stdin*:9 called from
I.e. it's the difference between printing the condition expression of a loop or if
clause, vs. printing the whole loop resp. if
statement. Now, a better approach probably would be to either print the actual line(s) containing the expression (as e.g. GDB would do it); or else add a way to print just the "head" of a loop or if
(resp.: print the loop, but with the body replaced by, say ...
). The former can be difficult because a single expression can of course span many lines, including comments; also, the source file may be modified, leading to output that's not right (just as can happen with gdb); if we wanted to avoid that, we'd have to store the whole file in memory.
The second approach seems much simpler to me, and shouldn't be too hard to implement... (famous last words)
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.
BTW, these HACKS are also limited in so far as they break down if cond
is an "immediate" expression, i.e., an INTEXPR
or a REFLVAR
I'll look into implementing the second approach now
6d71dc4
to
d2d073f
Compare
tst/testspecial/backtrace.g.out
Outdated
gap> f:=function() if 1 < 0 then return 1; elif 1 then return 2; fi; return 3; end;; | ||
gap> f(); | ||
Error, <expr> must be 'true' or 'false' (not a integer) in | ||
1 < 0 at *stdin*:18 called from |
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 is wrong, and right now I am not quite sure why it is...
But what is the right thing to print? In a previous comment, I suggested that for loops and if clauses, one could just hide the "bodies", and so e.g. print while 1 do ... od;
instead of the full loop. But for if/elif/fi
clauses with multiple conditions, this still doesn't seem quite good enough: ideally, we only want to print the if
resp. elif
with the expression that was executed. But there is no separate statement for that -- we are "in the middle" of a single statement here! I don't see a simple solution for that right now, so I opted to drop both approaches I tried from this PR right now, to be revisited in a future PR. For now, we are at least not doing worse than we were before.
fc17548
to
58101f8
Compare
58101f8
to
7277104
Compare
7277104
to
9704d53
Compare
I have rebased this now again, to resolve conflicts. Would be nice if this could be either merged, or rejected, so that I can move on. My guess is that nobody is looking at it because it is has fallen of the first page of PRs. But if @ChrisJefferson or @stevelinton (who wrote a lot of the affected code) could just have a look at it... |
This way, we always know which statement was executed last. The price we pay is a small performance overhead.
Instead of storing the current statement both in `STATE(CurrStat)` and in `STAT_LVARS_PTR(STATE(PtrLVars))`, store them only in the latter location. That allows us to get rid of code for copying between these two locations, too. This means `SET_BRK_CURR_STAT` etc. can be removed, but to keep the patch small, we leave most of them in for now, and just #define them to do nothing. In a few cases, code is changed to use `SET_BRK_CALL_TO` instead.
9704d53
to
832d7d0
Compare
This reverts commit 70ee840.
In a few select spaces, we insert `SET_BRK_CALL_TO` calls instead, in order to improve certain backtraces.
After evaluating the body of a loop resp. an if-statmeent, and before evaluating the next condition expression, reset the current statement to point to the loop resp. if-statement again.
832d7d0
to
9764cee
Compare
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.
Having reviewed this PR with @fingolfin and @ChrisJefferson I am happy to approve it.
This PR unifies the code we use to track the current statement and expression. It resolves various bugs where backtraces indicated the wrong statement as the current one, ans also gets rid of some cases where "" was printed.
This needs more work on the long run (in future PRs), in particular for the case where there is an error in the condition expression of an
if
statement or a loop: then what should we print? Just the expression in which the error occurred? But that could be a simple integer (inif 1 then ... fi
), which is not helpful (and in this particular case, would even lead to a "corrupt statement" message for technical reasons).Or perhaps the whole statement should be printed? But that could span dozens of lines. Slightly better is to print, say, a while loop as
while COND do ... od;
, i.e. replace the body by...
. But (a) the condition still could be multiple lines long, and (b) this does not work very well for anif/elif/elif/.../else/fi
with multiple branches.Or "just the line on which the error occurred" -- but that then depends on the on-disk representation of the data, which opens its own can of worms, so I'd rather avoid it.
For now, I think my favorite would be to just print
while COND do
(no...
orod;
), resp.if COND then
orelif COND then
etc. But we lack the facilities for that -- esp. for theelif
we currently don't even have place where to store on which of the various "branches" of a "multi-condition if statement" we are.So, this needs work, but not today... I plan to turn the above into an issue later.
Resolves #616
Fixes #2656