Skip to content

Adds Compiler support for remaining Array methods - sort, reduce, and more #33535

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 275 additions & 1 deletion compiler/packages/babel-plugin-react-compiler/src/HIR/ObjectShape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,281 @@ addObject(BUILTIN_SHAPES, BuiltInArrayId, [
returnValueKind: ValueKind.Primitive,
}),
],
// TODO: rest of Array properties
[
'copyWithin',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
}),
],
[
'fill',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
Comment on lines +460 to +464
Copy link
Member

Choose a reason for hiding this comment

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

this is subtle, but the behavior of fill(value, start, end) is that value is stored into the array (Effect.Capture), while the rest of the args are just read. So a more precise declaration would be:

positionalParams: [Effect.Capture],
restParam: Effect.Read,

}),
],
[
'findLast',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Poly'},
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'findLastIndex',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: PRIMITIVE_TYPE,
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Primitive,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'flat',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Mutable,
}),
],
[
'forEach',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: PRIMITIVE_TYPE,
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Primitive,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'lastIndexOf',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'reduce',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Poly'},
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'reduceRight',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Poly'},
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
noAlias: true,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'reverse',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
}),
],
[
'shift',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Poly'},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
}),
],
[
'sort',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
noAlias: true,
}),
],
[
'splice',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Mutable,
}),
],
[
'toLocaleString',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Read,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'toReversed',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Mutable,
}),
],
[
'toSorted',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.ConditionallyMutate,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
/*
* callee is ConditionallyMutate because items of the array
* flow into the lambda and may be mutated there, even though
* the array object itself is not modified
*/
calleeEffect: Effect.ConditionallyMutate,
returnValueKind: ValueKind.Mutable,
mutableOnlyIfOperandsAreMutable: true,
}),
],
[
'toSpliced',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Mutable,
}),
Comment on lines +623 to +657
Copy link
Member

Choose a reason for hiding this comment

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

These need calleeEffect: Effect.Capture since the items of the original array can be modified through the returned array

],
[
'toString',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Primitive,
}),
],
[
'unshift',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
returnType: PRIMITIVE_TYPE,
calleeEffect: Effect.Store,
returnValueKind: ValueKind.Primitive,
}),
],
[
'with',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: Effect.Capture,
Comment on lines +682 to +683
Copy link
Member

Choose a reason for hiding this comment

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

let's be precise here too, it's with(index, value) so: positionalParams: [Effect.Read, Effect.Capture]

returnType: {kind: 'Object', shapeId: BuiltInArrayId},
calleeEffect: Effect.Read,
returnValueKind: ValueKind.Mutable,
}),
],
/**
* Iterators
*/
[
'entries',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Poly'},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Mutable,
}),
],
[
'keys',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Poly'},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Mutable,
}),
],
[
'values',
addFunction(BUILTIN_SHAPES, [], {
positionalParams: [],
restParam: null,
returnType: {kind: 'Poly'},
calleeEffect: Effect.Capture,
returnValueKind: ValueKind.Mutable,
}),
],
]);

/* Built-in Object shape */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

## Input

```javascript
function Component() {
const array = ['c', 'b', 'a'];
return useMemo(() => {
return [...array].copyWithin(0, 2);
}, [array]);
}

```

## Code

```javascript
import { c as _c } from "react/compiler-runtime";
function Component() {
const $ = _c(2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = ["c", "b", "a"];
$[0] = t0;
} else {
t0 = $[0];
}
const array = t0;
let t1;
let t2;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [...array].copyWithin(0, 2);
$[1] = t2;
} else {
t2 = $[1];
}
t1 = t2;
return t1;
}

```

### Eval output
(kind: exception) Fixture not implemented
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function Component() {
const array = ['c', 'b', 'a'];
return useMemo(() => {
return [...array].copyWithin(0, 2);
}, [array]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

## Input

```javascript
function Component() {
const array = ['c', 'b', 'a'];
return useMemo(() => {
return [...array].fill(0);
}, [array]);
}

```

## Code

```javascript
import { c as _c } from "react/compiler-runtime";
function Component() {
const $ = _c(2);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = ["c", "b", "a"];
$[0] = t0;
} else {
t0 = $[0];
}
const array = t0;
let t1;
let t2;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t2 = [...array].fill(0);
$[1] = t2;
} else {
t2 = $[1];
}
t1 = t2;
return t1;
}

```

### Eval output
(kind: exception) Fixture not implemented
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function Component() {
const array = ['c', 'b', 'a'];
return useMemo(() => {
return [...array].fill(0);
}, [array]);
}
Loading
Loading