-
Notifications
You must be signed in to change notification settings - Fork 48.8k
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
base: main
Are you sure you want to change the base?
Conversation
Thanks for contributing! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great start! Great job paying attention to the details on how each of these functions may affect the operands and which effects to use. There are a few cases that look like they might need to be addressed. Also, we'll need to make the tests more thorough to ensure that mutation of return values of these functions is correctly connected to mutation of the values within the original array.
I'm also happy to help, this type of testing can definitely be tedious.
positionalParams: [], | ||
restParam: Effect.Capture, | ||
returnType: {kind: 'Object', shapeId: BuiltInArrayId}, | ||
calleeEffect: Effect.Store, | ||
returnValueKind: ValueKind.Mutable, |
There was a problem hiding this comment.
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,
[ | ||
'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, | ||
}), |
There was a problem hiding this comment.
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
positionalParams: [], | ||
restParam: Effect.Capture, |
There was a problem hiding this comment.
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]
@@ -0,0 +1,4 @@ | |||
function Component() { | |||
const array = ['c', 'b', 'a']; | |||
return useMemo(() => array.toSorted(), [array]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the tests, it isn't sufficient to check that the useeMemo is preserved. We also have to check if the result of calling the function propagates mutability in the correct way. For example, we should add a varaint of this fixture (array-to-sorted-mutate) that mutates the result of toStorted. Something like:
function Component(props) {
const sorted = useMemo(() => {
const array = [{value: 'c'}, {value: 'b'}, {value: 'a'}];
const sorted = array.toSorted();
mutate(sorted, props.value);
return sorted;
}, [props.value]);
return <ValidateMemoization inputs={[props.value]} output={sorted} />;
}
Summary
Was discussing some unexpected bailouts I'd run into with the Compiler with @josephsavona on Bluesky https://bsky.app/profile/en-js.bsky.social/post/3lrlh3rdbok2s and he kindly pointed me towards where I could fix them myself 😄
These changes cover the cases of using array methods like
sort
in auseMemo
, the Compiler will keep them memoized and won't bail on optimizing the component as is the current behavior.How did you test this change?