Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Make it easier to combine abstract values via operators. Part 1. #937

Closed
wants to merge 1 commit into from
Closed

Conversation

hermanventer
Copy link
Contributor

In this part, the code for creating an abstract value that results from a binary operator is centralized into AbstractValue.createFromBinaryOp. As part of this, TypeDomain and ValuesDomain now have transfer functions for computing the domain values that result from binary operations.

If this pattern is acceptable, I'll extend it to the other operators.

return new ValuesDomain(resultSet);
}

static computeBinary(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried to just keep this where it was in BinaryExpression, but that causes the Flow cycle length to increase. Arguably, this is the better place for it anyway.

@@ -36,6 +40,50 @@ export default class TypesDomain {
return this._type || Value;
}

// return the type of the result in the case where there is no exception
static binaryOp(op: BabelBinaryOperator, left: TypesDomain, right: TypesDomain) {
Copy link
Contributor

Choose a reason for hiding this comment

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

is it possible to Flow-type the result?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

op: BabelBinaryOperator,
lval: ConcreteValue,
rval: ConcreteValue,
lloc: ?BabelNodeSourceLocation,
Copy link
Contributor

Choose a reason for hiding this comment

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

These parameters seem to be unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yes, copy pasta. Will remove.

static binaryOp(realm: Realm, op: BabelBinaryOperator, left: ValuesDomain, right: ValuesDomain): ValuesDomain {
let leftElements = left._elements;
let rightElements = right._elements;
if (!leftElements || !rightElements || leftElements.size > 100 || rightElements.size > 100)
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought you prefer === undefined over !?

Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reasoning behind the > 100? I have no clue, and don't see a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ugliness of the pretty version of line 77 made me swallow ! for this instance.

I'll add a comment. The reason for the size restriction is that the larger a value set becomes, the less useful it becomes while at the same time it becomes computationally expensive.


// 5. If Type(rval) is not Object, throw a TypeError exception.
if (!(rval instanceof ObjectValue)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError);
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this object allocation and field initialization create some entries that are tracked by the realm? Just pointing it out, because the catch-logic in binaryOp seems to assume that computeBinary is pure. I'd prefer to make computeBinary truly pure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. This should throw a FatalError.

Copy link
Contributor

@NTillmann NTillmann left a comment

Choose a reason for hiding this comment

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

Nice refactoring! The Cartesian product computations seems to be truly new code. Any tests that exercise it?

@hermanventer
Copy link
Contributor Author

The Cartesian product computation code is pretty well covered by the existing tests, but I don't think any of them will fail if the value set is actually wrong. Coming up with such tests in the current state of the Abstract Interpreter is non trivial and I'd prefer to hold of a bit until it is easier to do so.

@facebook-github-bot
Copy link

@hermanventer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants