Update detection of pure nodes (Scope#isPure)#14424
Update detection of pure nodes (Scope#isPure)#14424nicolo-ribaudo merged 8 commits intobabel:mainfrom
Scope#isPure)#14424Conversation
| if (!this.isPure(decorator, constantsOnly)) return false; | ||
| } | ||
| } | ||
| if (isObjectProperty(node) || node.static) { |
There was a problem hiding this comment.
Evaluating a non-static field definition should be pure as long as it has no computed keys / fancy decorators, since the field initializer is not executed yet.
|
|
||
| isStatic(node: t.Node): boolean { | ||
| if (isThisExpression(node) || isSuper(node)) { | ||
| if (isThisExpression(node) || isSuper(node) || isTopicReference(node)) { |
There was a problem hiding this comment.
A topic reference should be treated as a constant IdentifierReference, therefore it is static and pure.
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/51637/ |
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/51624/ |
| "class C { static target = new.target }", | ||
| ])(`NodePath(%p).get("body.0").isPure() should be true`, input => { | ||
| const path = getPath(input).get("body.0"); | ||
| expect(path.node).toBeTruthy(); |
There was a problem hiding this comment.
This assertion ensures that the pathRef passed in .get() is correct. In fact our previous tests on "class X { get foo() { return 1 } }" always succeed because path.get(body.0.expression) is an empty NodePath.
|
|
||
| return _ref = (n + _ref2) * 2, `${_ref} apples`.toUpperCase(); | ||
| }).join()); | ||
| const result = (_ref = Math.pow(5, 2), [1, 2, 3].map(n => `${(n + _ref) * 2} apples`.toUpperCase()).join()); |
There was a problem hiding this comment.
Nice. Babel is generating less.
| } | ||
| if (node.decorators) { | ||
| for (const decorator of node.decorators) { | ||
| if (!this.isPure(decorator, constantsOnly)) return false; |
There was a problem hiding this comment.
If there is a decorator, it's never pure.
i.e.
const dec = () => console.log(1);
@dec
class A {}here @dec is pure because dec is a constant, but then it's evaluated.
| expect(path.isPure()).toBe(true); | ||
| }); | ||
|
|
||
| it.each(["let a = 1; `${a}`", `let a = 1; a |> % + %`])( |
There was a problem hiding this comment.
Uh, the first one is definitely not pure:
let a = { toString() { console.log("Hi :)") } };
`${a}`;however, it was already behaving like this before this PR so if we want to change it I'd prefer to do it in another one.
There was a problem hiding this comment.
Good point, we can introduce the pureToString compiler assumption, just like we have pureGetter.
| "class C { @dec foo() {} }", | ||
| "class C { @dec foo }", | ||
| "class C { @dec accessor foo = 1 }", | ||
| "class C { static {} }", |
There was a problem hiding this comment.
This is technically pure, however the only reason to use a static block is to have a side effect so we can err on the side of "it's never pure" and avoid recursing in its contents.
There was a problem hiding this comment.
Exactly, static {} is likely only used in the Babel testcase.
Scope#isPure)
scope#isPureAlso extracted the tests to a separate file.