Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,8 @@ addObject(BUILTIN_SHAPES, BuiltInRefValueId, [
['*', {kind: 'Object', shapeId: BuiltInRefValueId}],
]);

addObject(BUILTIN_SHAPES, ReanimatedSharedValueId, []);
Copy link
Member Author

Choose a reason for hiding this comment

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

Without this i got errors trying to resolve properties, because we have a shape id defined for reanimated but no shape definition. I'm not sure how we didn't run into that error before but it seems like it easily could have occurred.

Copy link
Member Author

Choose a reason for hiding this comment

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

Note that the error was an invariant which i don't think we report in eslint, so the compiler may have just been silently failing for folks using reanimated


addFunction(
BUILTIN_SHAPES,
[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
isStableType,
isStableTypeContainer,
isUseOperator,
isUseRefType,
} from '../HIR';
import {PostDominator} from '../HIR/Dominator';
import {
Expand Down Expand Up @@ -70,13 +69,6 @@ class StableSidemap {
isStable: false,
});
}
} else if (
this.env.config.enableTreatRefLikeIdentifiersAsRefs &&
isUseRefType(lvalue.identifier)
) {
this.map.set(lvalue.identifier.id, {
isStable: true,
});
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,36 @@ function* generateInstructionTypes(
yield equation(left, returnType);
break;
}
case 'PropertyStore':
case 'PropertyStore': {
/**
* Infer types based on assignments to known object properties
* This is important for refs, where assignment to `<maybeRef>.current`
* can help us infer that an object itself is a ref
*/
yield equation(
/**
* Our property type declarations are best-effort and we haven't tested
* using them to drive inference of rvalues from lvalues. We want to emit
* a Property type in order to infer refs from `.current` accesses, but
* stay conservative by not otherwise inferring anything about rvalues.
* So we use a dummy type here.
*
* TODO: consider using the rvalue type here
*/
makeType(),
// unify() only handles properties in the second position
{
kind: 'Property',
objectType: value.object.identifier.type,
objectName: getName(names, value.object.identifier.id),
propertyName: {
kind: 'literal',
value: value.property,
},
},
);
break;
}
case 'DeclareLocal':
case 'RegExpLiteral':
case 'MetaProperty':
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

## Input

```javascript
// @flow @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {makeObject_Primitives} from 'shared-runtime';

component Example() {
const fooRef = makeObject_Primitives();
fooRef.current = true;

return <Stringify foo={fooRef} />;
}

```


## Error

```
Found 1 error:

Error: Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)

4 | component Example() {
5 | const fooRef = makeObject_Primitives();
> 6 | fooRef.current = true;
| ^^^^^^^^^^^^^^ Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)
7 |
8 | return <Stringify foo={fooRef} />;
9 | }
```


Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @flow @enableTreatRefLikeIdentifiersAsRefs @validateRefAccessDuringRender
import {makeObject_Primitives} from 'shared-runtime';

component Example() {
const fooRef = makeObject_Primitives();
fooRef.current = true;

return <Stringify foo={fooRef} />;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

```javascript
// @enableCustomTypeDefinitionForReanimated
import {useAnimatedProps} from 'react-native-reanimated';
import {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
function Component() {
const radius = useSharedValue(50);

Expand Down Expand Up @@ -39,7 +39,7 @@ export const FIXTURE_ENTRYPOINT = {

```javascript
import { c as _c } from "react/compiler-runtime"; // @enableCustomTypeDefinitionForReanimated
import { useAnimatedProps } from "react-native-reanimated";
import { useAnimatedProps, useSharedValue } from "react-native-reanimated";
function Component() {
const $ = _c(2);
const radius = useSharedValue(50);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @enableCustomTypeDefinitionForReanimated
import {useAnimatedProps} from 'react-native-reanimated';
import {useAnimatedProps, useSharedValue} from 'react-native-reanimated';
function Component() {
const radius = useSharedValue(50);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,32 @@ function useCustomRef() {
function _temp() {}

function Foo() {
const $ = _c(3);
const $ = _c(4);
const ref = useCustomRef();
let t0;
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
if ($[0] !== ref) {
t0 = () => {
ref.current?.click();
};
$[0] = ref;
$[1] = t0;
} else {
t0 = $[1];
}
let t1;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t1 = [];
$[0] = t0;
$[1] = t1;
$[2] = t1;
} else {
t0 = $[0];
t1 = $[1];
t1 = $[2];
}
useEffect(t0, t1);
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t2 = <div>foo</div>;
$[2] = t2;
$[3] = t2;
} else {
t2 = $[2];
t2 = $[3];
}
return t2;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function Foo() {

const onClick = useCallback(() => {
ref.current?.click();
}, []);
}, [ref]);

return <button onClick={onClick} />;
}
Expand Down Expand Up @@ -47,24 +47,26 @@ function useCustomRef() {
function _temp() {}

function Foo() {
const $ = _c(2);
const $ = _c(4);
const ref = useCustomRef();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
if ($[0] !== ref) {
t0 = () => {
ref.current?.click();
};
$[0] = t0;
$[0] = ref;
$[1] = t0;
} else {
t0 = $[0];
t0 = $[1];
}
const onClick = t0;
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
if ($[2] !== onClick) {
t1 = <button onClick={onClick} />;
$[1] = t1;
$[2] = onClick;
$[3] = t1;
} else {
t1 = $[1];
t1 = $[3];
}
return t1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function Foo() {

const onClick = useCallback(() => {
ref.current?.click();
}, []);
}, [ref]);
Copy link
Member

Choose a reason for hiding this comment

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

out of curiosity what was this for?

Copy link
Member Author

Choose a reason for hiding this comment

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

same as below, the ref could change over time


return <button onClick={onClick} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function Foo() {

const onClick = useCallback(() => {
customRef.current?.click();
}, []);
}, [customRef]);

return <button onClick={onClick} />;
}
Expand Down Expand Up @@ -47,24 +47,26 @@ function useCustomRef() {
function _temp() {}

function Foo() {
const $ = _c(2);
const $ = _c(4);
const customRef = useCustomRef();
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
if ($[0] !== customRef) {
Copy link
Member

Choose a reason for hiding this comment

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

I get that this is functionally equivalent since the box identity never changes, but shouldn't refs be ignored as dependencies for memo blocks?

Copy link
Member Author

Choose a reason for hiding this comment

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

we don't know that useCustomRef() returns a stable ref. it could create two refs and state, and toggle between which ref it returns on each render

t0 = () => {
customRef.current?.click();
};
$[0] = t0;
$[0] = customRef;
$[1] = t0;
} else {
t0 = $[0];
t0 = $[1];
}
const onClick = t0;
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
if ($[2] !== onClick) {
t1 = <button onClick={onClick} />;
$[1] = t1;
$[2] = onClick;
$[3] = t1;
} else {
t1 = $[1];
t1 = $[3];
}
return t1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ function Foo() {

const onClick = useCallback(() => {
customRef.current?.click();
}, []);
}, [customRef]);

return <button onClick={onClick} />;
}
Expand Down
Loading