Throw CompilerError (todo) for unused conditional/logical

If a logical or conditional expression is unused, then a phi node isn't created 
for the identifier it assigns to. Then when we leave SSA form the two branches 
will assign to separate values, and we aren't sure which identifier to use as 
the lvalue of the resulting ReactiveInstruction (remember that 
logicals/conditionals decompose into control flow in HIR, but are a single 
compound instruction in ReactiveFunction). If the two sides don't assign to the 
same location, it could be because of a bug in the compiler or because the value 
wasn't used. Ideally we'd represent this explicitly, but for now i'm just making 
this a TODO since most logicals/conditionals should have their value used.
This commit is contained in:
Joe Savona
2023-03-15 09:39:23 -07:00
parent 7537df3d4e
commit 9200ad027d
6 changed files with 77 additions and 8 deletions
+13
View File
@@ -115,6 +115,19 @@ export class CompilerError extends Error {
throw errors;
}
static todo(reason: string, loc: SourceLocation): never {
const errors = new CompilerError();
errors.pushErrorDetail(
new CompilerErrorDetail({
codeframe: null,
loc: typeof loc === "symbol" ? null : loc,
reason,
severity: ErrorSeverity.Todo,
})
);
throw errors;
}
constructor(...args: any[]) {
super(...args);
}
@@ -6,6 +6,7 @@
*/
import invariant from "invariant";
import { CompilerError } from "../CompilerError";
import {
BasicBlock,
BlockId,
@@ -681,10 +682,12 @@ class Driver {
testBlock.terminal.alternate,
terminal.loc
);
invariant(
leftFinal.place.identifier === right.place.identifier,
"Expected the left and right side of a logical expression to store a value to the same place"
);
if (leftFinal.place.identifier !== right.place.identifier) {
CompilerError.todo(
"TODO: Support LogicalExpression whose value is unused",
leftFinal.place.loc
);
}
const value: ReactiveLogicalValue = {
kind: "LogicalExpression",
operator: terminal.operator,
@@ -722,10 +725,13 @@ class Driver {
alternate: alternate.value,
loc: terminal.loc,
};
invariant(
consequent.place.identifier === alternate.place.identifier,
"Expected the consequent and alternate of a ternary to store a value to the same place"
);
if (consequent.place.identifier !== alternate.place.identifier) {
CompilerError.todo(
"TODO: Support ConditionalExpression whose value is unused",
consequent.place.loc
);
}
return {
place: { ...consequent.place },
value,
@@ -0,0 +1,20 @@
## Input
```javascript
function Component(props) {
let x = 0;
(x = 1) && (x = 2);
return x;
}
```
## Error
```
[ReactForget] Todo: TODO: Support LogicalExpression whose value is unused (3:3)
```
@@ -0,0 +1,5 @@
function Component(props) {
let x = 0;
(x = 1) && (x = 2);
return x;
}
@@ -0,0 +1,20 @@
## Input
```javascript
function Component(props) {
let x = 0;
props.cond ? (x = 1) : (x = 2);
return x;
}
```
## Error
```
[ReactForget] Todo: TODO: Support ConditionalExpression whose value is unused (3:3)
```
@@ -0,0 +1,5 @@
function Component(props) {
let x = 0;
props.cond ? (x = 1) : (x = 2);
return x;
}