Support TypeCastExpression

Support TypeCastExpressions — `(x: TypeAnnotation)`. This is pretty 
straightforward, it's semantically identical to a raw identifier. 

One catch is that our prettier config is hard-coded to use the babel-ts parser, 
i wasn't sure how to make that dynamic based on the file extension so for now i 
just ignored .flow.js files in our pretter config.
This commit is contained in:
Joe Savona
2023-02-01 08:42:33 -08:00
parent 47074a2def
commit 2069269903
12 changed files with 100 additions and 2 deletions
+1
View File
@@ -1,6 +1,7 @@
/packages/demo-*
**/dist
**/__tests__/fixtures/**/*.expect.md
**/__tests__/fixtures/**/*.flow.js
**/.next
test262/
*.md
@@ -36,7 +36,7 @@ export default function runReactForgetBabelPlugin(
ast: result.ast,
code: prettier.format(result.code, {
semi: true,
parser: "babel-ts",
parser: language === "typescript" ? "babel-ts" : "flow",
}),
map: result.map,
};
+9
View File
@@ -1386,6 +1386,15 @@ function lowerExpression(
loc: exprLoc,
};
}
case "TypeCastExpression": {
let expr = exprPath as NodePath<t.TypeCastExpression>;
return {
kind: "TypeCastExpression",
value: lowerExpressionToPlace(builder, expr.get("expression")),
type: expr.get("typeAnnotation").node,
loc: exprLoc,
};
}
default: {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) Handle ${exprPath.type} expressions`,
+1
View File
@@ -416,6 +416,7 @@ export type InstructionData =
args: Array<Place>;
}
| { kind: "UnaryExpression"; operator: string; value: Place }
| { kind: "TypeCastExpression"; value: Place; type: t.TypeAnnotation }
| {
kind: "JsxExpression";
tag: Place;
+4
View File
@@ -259,6 +259,10 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
value = JSON.stringify(instrValue.value);
break;
}
case "TypeCastExpression": {
value = `TypeCast ${printPlace(instrValue.value)}`;
break;
}
case "JsxExpression": {
const propItems = [];
for (const attribute of instrValue.props) {
+8
View File
@@ -123,6 +123,10 @@ export function* eachInstructionValueOperand(
yield instrValue.tag;
break;
}
case "TypeCastExpression": {
yield instrValue.value;
break;
}
case "UnsupportedNode":
case "Primitive":
case "JSXText": {
@@ -243,6 +247,10 @@ export function mapInstructionOperands(
instrValue.tag = fn(instrValue.tag);
break;
}
case "TypeCastExpression": {
instrValue.value = fn(instrValue.value);
break;
}
case "UnsupportedNode":
case "Primitive":
case "JSXText": {
+5 -1
View File
@@ -1,4 +1,3 @@
import DisjointSet from "../Utils/DisjointSet";
import {
HIRFunction,
Identifier,
@@ -7,6 +6,7 @@ import {
LValue,
Place,
} from "../HIR/HIR";
import DisjointSet from "../Utils/DisjointSet";
export type AliasSet = Set<Identifier>;
@@ -44,6 +44,10 @@ function inferInstr(instr: Instruction, state: AliasAnalyser) {
alias = instrValue.object;
break;
}
case "TypeCastExpression": {
alias = instrValue.value;
break;
}
default:
return;
}
@@ -693,6 +693,20 @@ function inferBlock(env: Environment, block: BasicBlock) {
env.define(lvalue.place, instrValue);
continue;
}
case "TypeCastExpression": {
// A type cast expression has no effect at runtime, so it's equivalent to a raw
// identifier:
// ```
// x = (y: type) // is equivalent to...
// x = y
// ```
env.initialize(instrValue, env.kind(instrValue.value));
env.reference(instrValue.value, Effect.Read);
const lvalue = instr.lvalue;
lvalue.place.effect = Effect.Mutate;
env.alias(lvalue.place, instrValue.value);
continue;
}
case "Identifier": {
env.reference(instrValue, Effect.Read);
const lvalue = instr.lvalue;
@@ -672,6 +672,13 @@ function codegenInstructionValue(
);
break;
}
case "TypeCastExpression": {
value = t.typeCastExpression(
codegenInstructionValue(cx, instrValue.value),
instrValue.type
);
break;
}
case "LogicalExpression": {
value = createLogicalExpression(
instrValue.loc,
@@ -167,6 +167,7 @@ function isMutable({ id }: Instruction, place: Place): boolean {
function mayAllocate(value: InstructionValue): boolean {
switch (value.kind) {
case "TypeCastExpression":
case "BinaryExpression":
case "Identifier":
case "PropertyLoad":
@@ -0,0 +1,40 @@
## Input
```javascript
// @flow
type Foo = {bar: string};
function Component(props) {
const x = {bar: props.bar};
const y = (x: Foo);
y.bar = 'hello';
const z = (y: Foo);
return z;
}
```
## Code
```javascript
// @flow
type Foo = { bar: string };
function Component(props) {
const $ = React.useMemoCache();
const c_0 = $[0] !== props.bar;
let y;
if (c_0) {
const x = { bar: props.bar };
y = (x: Foo);
y.bar = "hello";
$[0] = props.bar;
$[1] = y;
} else {
y = $[1];
}
const z = (y: Foo);
return z;
}
```
@@ -0,0 +1,9 @@
// @flow
type Foo = {bar: string};
function Component(props) {
const x = {bar: props.bar};
const y = (x: Foo);
y.bar = 'hello';
const z = (y: Foo);
return z;
}