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 @@ -12,6 +12,7 @@ import {
SourceLocation,
} from '..';
import {
ArrayExpression,
CallExpression,
Effect,
Environment,
Expand All @@ -38,7 +39,6 @@ import {printSourceLocationLine} from '../HIR/PrintHIR';

/*
* TODO(jmbrown):
* - rewrite dep arrays
* - traverse object methods
* - method calls
* - React.useEffect calls
Expand Down Expand Up @@ -125,11 +125,58 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
}
rewriteInstrs.set(loadUseEffectInstrId, newInstrs);
}
ensureNoRemainingCalleeCaptures(
lambda.loweredFunc.func,
context,
capturedCallees,
}
ensureNoRemainingCalleeCaptures(
lambda.loweredFunc.func,
context,
capturedCallees,
);

if (
value.args.length > 1 &&
value.args[1] != null &&
value.args[1].kind === 'Identifier'
) {
const depArray = value.args[1];
const depArrayExpression = context.getArrayExpression(
depArray.identifier.id,
);
if (depArrayExpression != null) {
for (const dependency of depArrayExpression.elements) {
if (dependency.kind === 'Identifier') {
const loadOfDependency = context.getLoadLocalInstr(
dependency.identifier.id,
);
if (loadOfDependency != null) {
const replacedDepArrayItem = capturedCallees.get(
loadOfDependency.place.identifier.id,
);
if (replacedDepArrayItem != null) {
loadOfDependency.place =
replacedDepArrayItem.fireFunctionBinding;
}
}
}
}
} else {
context.pushError({
loc: value.args[1].loc,
description:
'You must use an array literal for an effect dependency array when that effect uses `fire()`',
severity: ErrorSeverity.Invariant,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
} else if (value.args.length > 1 && value.args[1].kind === 'Spread') {
context.pushError({
loc: value.args[1].place.loc,
description:
'You must use an array literal for an effect dependency array when that effect uses `fire()`',
severity: ErrorSeverity.Invariant,
reason: CANNOT_COMPILE_FIRE,
suggestions: null,
});
}
}
} else if (
Expand Down Expand Up @@ -231,6 +278,8 @@ function replaceFireFunctions(fn: HIRFunction, context: Context): void {
deleteInstrs.add(instr.id);
} else if (value.kind === 'LoadGlobal') {
context.addLoadGlobalInstrId(lvalue.identifier.id, instr.id);
} else if (value.kind === 'ArrayExpression') {
context.addArrayExpression(lvalue.identifier.id, value);
}
}
block.instructions = rewriteInstructions(rewriteInstrs, block.instructions);
Expand Down Expand Up @@ -561,6 +610,12 @@ class Context {
this.#env = env;
}

/*
* We keep track of array expressions so we can rewrite dependency arrays passed to useEffect
* to use the fire functions
*/
#arrayExpressions = new Map<IdentifierId, ArrayExpression>();

pushError(error: CompilerErrorDetailOptions): void {
this.#errors.push(error);
}
Expand Down Expand Up @@ -655,6 +710,14 @@ class Context {
return this.#loadGlobalInstructionIds.get(id);
}

addArrayExpression(id: IdentifierId, array: ArrayExpression): void {
this.#arrayExpressions.set(id, array);
}

getArrayExpression(id: IdentifierId): ArrayExpression | undefined {
return this.#arrayExpressions.get(id);
}

hasErrors(): boolean {
return this.#errors.hasErrors();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

## Input

```javascript
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};

const deps = [foo, props];

useEffect(() => {
fire(foo(props));
}, deps);

return null;
}

```


## Error

```
11 | useEffect(() => {
12 | fire(foo(props));
> 13 | }, deps);
| ^^^^ Invariant: Cannot compile `fire`. You must use an array literal for an effect dependency array when that effect uses `fire()` (13:13)
14 |
15 | return null;
16 | }
```


Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};

const deps = [foo, props];

useEffect(() => {
fire(foo(props));
}, deps);

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

## Input

```javascript
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};

const deps = [foo, props];

useEffect(() => {
fire(foo(props));
}, ...deps);

return null;
}

```


## Error

```
11 | useEffect(() => {
12 | fire(foo(props));
> 13 | }, ...deps);
| ^^^^ Invariant: Cannot compile `fire`. You must use an array literal for an effect dependency array when that effect uses `fire()` (13:13)
14 |
15 | return null;
16 | }
```


Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};

const deps = [foo, props];

useEffect(
() => {
fire(foo(props));
},
...deps
);

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@

## Input

```javascript
// @enableFire @inferEffectDependencies
import {fire, useEffect} from 'react';

function Component(props) {
const foo = arg => {
console.log(arg, props.bar);
};
useEffect(() => {
fire(foo(props));
});

return null;
}

```

## Code

```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire @inferEffectDependencies
import { fire, useEffect } from "react";

function Component(props) {
const $ = _c(5);
let t0;
if ($[0] !== props.bar) {
t0 = (arg) => {
console.log(arg, props.bar);
};
$[0] = props.bar;
$[1] = t0;
} else {
t0 = $[1];
}
const foo = t0;
const t1 = useFire(foo);
let t2;
if ($[2] !== props || $[3] !== t1) {
t2 = () => {
t1(props);
};
$[2] = props;
$[3] = t1;
$[4] = t2;
} else {
t2 = $[4];
}
useEffect(t2, [t1, props]);
return null;
}

```

### Eval output
(kind: exception) Fixture not implemented
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @enableFire @inferEffectDependencies
import {fire, useEffect} from 'react';

function Component(props) {
const foo = arg => {
console.log(arg, props.bar);
};
useEffect(() => {
fire(foo(props));
});

return null;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

## Input

```javascript
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
}, [foo, props]);

return null;
}

```

## Code

```javascript
import { useFire } from "react/compiler-runtime";
import { c as _c } from "react/compiler-runtime"; // @enableFire
import { fire } from "react";

function Component(props) {
const $ = _c(4);
const foo = _temp;
const t0 = useFire(foo);
let t1;
let t2;
if ($[0] !== props || $[1] !== t0) {
t1 = () => {
t0(props);
};
t2 = [t0, props];
$[0] = props;
$[1] = t0;
$[2] = t1;
$[3] = t2;
} else {
t1 = $[2];
t2 = $[3];
}
useEffect(t1, t2);
return null;
}
function _temp(props_0) {
console.log(props_0);
}

```

### Eval output
(kind: exception) Fixture not implemented
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @enableFire
import {fire} from 'react';

function Component(props) {
const foo = props => {
console.log(props);
};
useEffect(() => {
fire(foo(props));
}, [foo, props]);

return null;
}
Loading