Skip to content
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

Undo the extra expressions added by PR #2783 #3179

Merged
merged 11 commits into from
Dec 15, 2022
Merged

Conversation

atomb
Copy link
Member

@atomb atomb commented Dec 12, 2022

This uses FormatTokens to keep track of the beginning of a sequence of expressions prefixed by && or || instead of a synthetic identity expression.

Fixes a performance regression caused by #2783.

By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

This uses `FormatTokens` to keep track of the beginning of a sequence
of expressions prefixed by `&&` or `||` instead of a synthetic identity
expression.

Not quite complete, as it causes occasional null pointer exceptions
when retrieving the range of certain `TokenWrapper` instances that
seem to be wrapped around null.
{ IF(IsAndOp()) /* read a conjunction as far as possible */
AndOp (. x = t; .)
RelationalExpression<out e1, allowLemma, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1); .)
RelationalExpression<out e1, allowLemma, allowLambda, allowBitwiseOps> (. e0 = new BinaryExpr(x, BinaryExpr.Opcode.And, e0, e1, prefixOp); .)
Copy link
Member

Choose a reason for hiding this comment

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

Yes right, it's the outermost && that gets the prefix, as you guessed &&1 ((a &&2 b) &&1 c)

@atomb atomb marked this pull request as ready for review December 14, 2022 21:04
@@ -1928,21 +1929,25 @@ public enum AccumulationOperand { None, Left, Right }
Contract.Invariant(E1 != null);
}

public BinaryExpr(IToken tok, Opcode op, Expression e0, Expression e1)
public BinaryExpr(IToken tok, Opcode op, Expression e0, Expression e1, IToken prefixOp)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
public BinaryExpr(IToken tok, Opcode op, Expression e0, Expression e1, IToken prefixOp)
public BinaryExpr(IToken tok, Opcode op, Expression e0, Expression e1, IToken prefixOp = null)

Wouldn't this be less invasive?

Copy link
Member Author

Choose a reason for hiding this comment

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

It would be, and that's how I originally wrote it, but @MikaelMayer pointed out that it would make it easier to make mistakes during cloning by not cloning the prefixOp. Does avoiding those mistakes outweigh the extra change complexity? I'm undecided.

@@ -92,6 +92,8 @@ class PrecedenceLinterVisitor : TopDownVisitor<LeftMargin> {
// a SeqSelectExpr is the open-bracket). To avoid looking at that internal structure, we instead
// use the .StartToken for these expressions.
column = expr.StartToken.col;
} else if (expr is BinaryExpr binaryExpr && binaryExpr.PrefixOp is not null) {
Copy link
Member

Choose a reason for hiding this comment

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

Are you not able to do something like binaryExpr.E0.RangeToken.EndToken.Next so you don't need binaryExpr.PrefixOp and all the related changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that you're right that this entire branch of the condition isn't necessary.

The prefixOp parameter is still necessary, I think, to ensure that it can go into the FormatTokens property (which is used to compute the StartToken property used in the previous branch).

Copy link
Member

Choose a reason for hiding this comment

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

Then this comment applies to where FormatTokens is updated 😄

@atomb atomb enabled auto-merge (squash) December 14, 2022 23:51
@atomb atomb merged commit 7d7490e into dafny-lang:master Dec 15, 2022
: base(tok) {
Contract.Requires(tok != null);
Contract.Requires(e0 != null);
Contract.Requires(e1 != null);
this.Op = op;
this.E0 = e0;
this.E1 = e1;
this.PrefixOp = prefixOp;
if (prefixOp != null) {
Copy link
Member

@keyboardDrummer keyboardDrummer Dec 15, 2022

Choose a reason for hiding this comment

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

Can't you compute prefixOp using e0.RangeToken.End.Next ? Not having prefixOp as an extra parameter seems quite valuable. It seems wrong to me to have custom fields for tokens in our AST when we already have generic fields that contain all tokens.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, that may be possible. That's an artifact of doing most of this work before merging with PR #3070. Previously, RangeToken wasn't updated to include the leading || or &&, but now it is. I'll investigate.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is in fact possible to remove prefixOp, and it's much nicer that way. Thanks for pointing it out!

@@ -69,6 +69,10 @@ public abstract class INode {
}

void updateStartEndTokRecursive(INode node) {
if (node is null) {
Copy link
Member

Choose a reason for hiding this comment

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

I purposedly not included the check because it should never be called on null node. Well I guess we can now put a breakpoint in this if for later!

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I suspect one of the elements of Children winds up being null, even though I agree it should be left out in that case.

I'm not too worried about this, because, if we decided to allow null children, this is clearly the right thing to do with them. :)

keyboardDrummer pushed a commit that referenced this pull request Dec 17, 2022
Simplifies the fix from PR #3179 significantly, removing the need for an
extra parameter to the constructor for `BinaryExpr`.

<small>By submitting this pull request, I confirm that my contribution
is made under the terms of the [MIT
license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants