Skip to content

Commit a35af3e

Browse files
[hack pipes] Inline topic token when possible (#14278)
* Optimize away `|> #` pipes * Inline topic token when it's used once and there are no side effects * Fix deferred topic evaluation * Update standalone tests
1 parent 1937284 commit a35af3e

158 files changed

Lines changed: 459 additions & 386 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/babel-plugin-proposal-pipeline-operator/src/hackVisitor.ts

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
import { types as t } from "@babel/core";
2+
import type { NodePath, Visitor } from "@babel/traverse";
23

3-
const topicReferenceReplacementVisitor = {
4-
TopicReference(path) {
5-
path.replaceWith(t.cloneNode(this.topicVariable));
4+
const topicReferenceVisitor: Visitor<{
5+
topicReferences: NodePath<t.TopicReference>[];
6+
sideEffectsBeforeFirstTopicReference: boolean;
7+
}> = {
8+
exit(path, state) {
9+
if (path.isTopicReference()) {
10+
state.topicReferences.push(path);
11+
} else {
12+
if (
13+
state.topicReferences.length === 0 &&
14+
!state.sideEffectsBeforeFirstTopicReference &&
15+
!path.isPure()
16+
) {
17+
state.sideEffectsBeforeFirstTopicReference = true;
18+
}
19+
}
20+
},
21+
"ClassBody|Function"(_, state) {
22+
if (state.topicReferences.length === 0) {
23+
state.sideEffectsBeforeFirstTopicReference = true;
24+
}
625
},
726
};
827

@@ -22,22 +41,41 @@ export default {
2241
return;
2342
}
2443

25-
const topicVariable = scope.generateUidIdentifierBasedOnNode(node);
2644
const pipeBodyPath = path.get("right");
27-
28-
scope.push({ id: topicVariable });
29-
3045
if (pipeBodyPath.node.type === "TopicReference") {
3146
// If the pipe body is itself a lone topic reference,
32-
// then replace it with the topic variable.
33-
pipeBodyPath.replaceWith(t.cloneNode(topicVariable));
34-
} else {
35-
// Replace topic references with the topic variable.
36-
pipeBodyPath.traverse(topicReferenceReplacementVisitor, {
37-
topicVariable,
38-
});
47+
// then replace the whole expression with its left operand.
48+
path.replaceWith(node.left);
49+
return;
50+
}
51+
52+
const visitorState = {
53+
topicReferences: [],
54+
// pipeBodyPath might be a function, and it won't be visited by
55+
// topicReferenceVisitor because traverse() skips the top-level
56+
// node. We must handle that case here manually.
57+
sideEffectsBeforeFirstTopicReference: pipeBodyPath.isFunction(),
58+
};
59+
pipeBodyPath.traverse(topicReferenceVisitor, visitorState);
60+
61+
if (
62+
visitorState.topicReferences.length === 1 &&
63+
(!visitorState.sideEffectsBeforeFirstTopicReference ||
64+
path.scope.isPure(node.left, true))
65+
) {
66+
visitorState.topicReferences[0].replaceWith(node.left);
67+
path.replaceWith(node.right);
68+
return;
3969
}
4070

71+
const topicVariable = scope.generateUidIdentifierBasedOnNode(node);
72+
scope.push({ id: topicVariable });
73+
74+
// Replace topic references with the topic variable.
75+
visitorState.topicReferences.forEach(path =>
76+
path.replaceWith(t.cloneNode(topicVariable)),
77+
);
78+
4179
// Replace the pipe expression itself with an assignment expression.
4280
path.replaceWith(
4381
t.sequenceExpression([
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
var _ref;
2-
31
Tuple(0);
4-
_ref = 1, Tuple(0, _ref);
2+
Tuple(0, 1);
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
var _ref;
2-
3-
const result = (_ref = 5, _ref);
1+
const result = 5;
42
expect(result).toBe(5);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
const result = 5 |> ^ + 1 |> ^ + ^;
1+
const result = 5 |> ^ + 1 |> 2 + ^ |> ^ + ^;
22

33
expect(result).toBe(12);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var _ref, _ref2;
1+
var _ref;
22

3-
const result = (_ref2 = 5, (_ref = _ref2 + 1, _ref + _ref));
3+
const result = (_ref = 2 + (5 + 1), _ref + _ref);
44
expect(result).toBe(12);
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
var _ref4, _ref5, _ref6;
1+
var _ref2;
22

3-
const result = (_ref6 = 5, (_ref5 = Math.pow(_ref6, 2), (_ref4 = [1, 2, 3].map(n => {
4-
var _ref, _ref2, _ref3;
3+
const result = (_ref2 = Math.pow(5, 2), [1, 2, 3].map(n => {
4+
var _ref;
55

6-
return _ref3 = n + _ref5, (_ref2 = _ref3 * 2, (_ref = `${_ref2} apples`, _ref.toUpperCase()));
7-
}), _ref4.join())));
6+
return _ref = (n + _ref2) * 2, `${_ref} apples`.toUpperCase();
7+
}).join());
88
expect(result).toEqual('52 APPLES,54 APPLES,56 APPLES');
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
var _ref, _ref2, _ref3;
1+
var _ref;
22

3-
const result = (_ref3 = -2.2 // -2.2
4-
, (_ref2 = Math.floor(_ref3) // -3
5-
, (_ref = () => Math.pow(_ref2, 5) // () => -243
6-
, _ref()))); // -243
3+
const result = (_ref = Math.floor(-2.2 // -2.2
4+
) // -3
5+
, (() => Math.pow(_ref, 5) // () => -243
6+
)()); // -243
77

88
expect(result).toBe(-243);

packages/babel-plugin-proposal-pipeline-operator/test/fixtures/hack-caret/pipe-body-with-await/output.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ function triple(x) {
33
}
44

55
async function asyncFunction(n) {
6-
var _ref, _ref2, _ref3;
6+
var _ref;
77

8-
return _ref3 = n, (_ref2 = Math.abs(_ref3), (_ref = await Promise.resolve(_ref2), triple(_ref)));
8+
return _ref = Math.abs(n), triple(await Promise.resolve(_ref));
99
}
1010

1111
asyncFunction(-7).then(result => {
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
var _ref, _ref2, _ref3;
2-
3-
const result = (_ref3 = 1, (_ref2 = class {
1+
const result = new class {
42
#baz;
53

64
constructor() {
7-
this.#baz = _ref3;
5+
this.#baz = 1;
86
}
97

108
#bar() {
@@ -15,5 +13,5 @@ const result = (_ref3 = 1, (_ref2 = class {
1513
return this.#bar() + 3;
1614
}
1715

18-
}, (_ref = new _ref2(), _ref.foo())));
16+
}().foo();
1917
expect(result).toBe(1 + 2 + 3);
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
var _ref;
2-
31
const program = '(function() { return this; })()';
4-
const result = (_ref = program, eval(_ref));
2+
const result = eval(program);
53
expect(result).not.toBeUndefined();

0 commit comments

Comments
 (0)