Merge 69d25a8b39 into sapling-pr-archive-josephsavona

This commit is contained in:
Joseph Savona
2025-06-25 14:55:25 -07:00
committed by GitHub
5 changed files with 70 additions and 1 deletions
@@ -893,7 +893,8 @@ export function printType(type: Type): string {
if (type.kind === 'Object' && type.shapeId != null) {
return `:T${type.kind}<${type.shapeId}>`;
} else if (type.kind === 'Function' && type.shapeId != null) {
return `:T${type.kind}<${type.shapeId}>`;
const returnType = printType(type.return);
return `:T${type.kind}<${type.shapeId}>()${returnType !== '' ? returnType : ''}`;
} else {
return `:T${type.kind}`;
}
@@ -25,6 +25,7 @@ import {
InstructionKind,
InstructionValue,
isArrayType,
isJsxType,
isMapType,
isPrimitiveType,
isRefOrRefValue,
@@ -1847,6 +1848,19 @@ function computeSignatureForInstruction(
});
}
}
for (const prop of value.props) {
if (
prop.kind === 'JsxAttribute' &&
prop.place.identifier.type.kind === 'Function' &&
isJsxType(prop.place.identifier.type.return)
) {
// Any props which return jsx are assumed to be called during render
effects.push({
kind: 'Render',
place: prop.place,
});
}
}
}
break;
}
@@ -712,6 +712,15 @@ class Unifier {
return {kind: 'Phi', operands: type.operands.map(o => this.get(o))};
}
if (type.kind === 'Function') {
return {
kind: 'Function',
isConstructor: type.isConstructor,
shapeId: type.shapeId,
return: this.get(type.return),
};
}
return type;
}
}
@@ -0,0 +1,33 @@
## Input
```javascript
function Component() {
const renderItem = item => {
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}
```
## Error
```
6 | // called during render, and thus it's unsafe to mutate globals or call
7 | // other impure code.
> 8 | global.property = true;
| ^^^^^^ InvalidReact: Writing to a variable defined outside a component or hook is not allowed. Consider using an effect (8:8)
9 | return <Item item={item} value={rand} />;
10 | };
11 | return <ItemList renderItem={renderItem} />;
```
@@ -0,0 +1,12 @@
function Component() {
const renderItem = item => {
// Normally we assume that it's safe to mutate globals in a function passed
// as a prop, because the prop could be used as an event handler or effect.
// But if the function returns JSX we can assume it's a render helper, ie
// called during render, and thus it's unsafe to mutate globals or call
// other impure code.
global.property = true;
return <Item item={item} value={rand} />;
};
return <ItemList renderItem={renderItem} />;
}