From e410815aeb10bbef6406e09cf0783187fae34d2f Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Sun, 4 Jun 2023 20:27:24 -0400 Subject: [PATCH] Infer more primitive types Handles three more cases: * Template literals * deletion (property/computed) * type casts Only the latter has an observable impact, though i added tests for deletion just in case and found a bug. For type casts, they're reasonably common internally for fixmes, so this PR will help to ensure we don't drop type information just because of a cast. --- .../src/Inference/InferReferenceEffects.ts | 3 ++- .../forget/src/TypeInference/InferTypes.ts | 16 +++++++++--- .../compiler/infer-computed-delete.expect.md | 25 ++++++++++++++++++ .../compiler/infer-computed-delete.js | 6 +++++ .../compiler/infer-property-delete.expect.md | 23 ++++++++++++++++ .../compiler/infer-property-delete.js | 5 ++++ ...fer-types-through-type-cast.flow.expect.md | 26 +++++++++++++++++++ .../infer-types-through-type-cast.flow.js | 9 +++++++ 8 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.js create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.js create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.expect.md create mode 100644 compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.js diff --git a/compiler/forget/src/Inference/InferReferenceEffects.ts b/compiler/forget/src/Inference/InferReferenceEffects.ts index 700e8c462c..91b4fcd879 100644 --- a/compiler/forget/src/Inference/InferReferenceEffects.ts +++ b/compiler/forget/src/Inference/InferReferenceEffects.ts @@ -837,7 +837,8 @@ function inferBlock( state.reference(instrValue.object, Effect.Mutate); state.reference(instrValue.property, Effect.Read); state.initialize(instrValue, ValueKind.Immutable); - state.reference(instr.lvalue, Effect.Mutate); + state.define(instr.lvalue, instrValue); + instr.lvalue.effect = Effect.Mutate; continue; } case "ComputedLoad": { diff --git a/compiler/forget/src/TypeInference/InferTypes.ts b/compiler/forget/src/TypeInference/InferTypes.ts index a00cb5b5f6..058b16a697 100644 --- a/compiler/forget/src/TypeInference/InferTypes.ts +++ b/compiler/forget/src/TypeInference/InferTypes.ts @@ -108,6 +108,7 @@ function* generateInstructionTypes( const left = lvalue.identifier.type; switch (value.kind) { + case "TemplateLiteral": case "JSXText": case "Primitive": { yield equation(left, { kind: "Primitive" }); @@ -232,21 +233,28 @@ function* generateInstructionTypes( break; } + case "TypeCastExpression": { + yield equation(left, value.value.identifier.type); + break; + } + + case "PropertyDelete": + case "ComputedDelete": { + yield equation(left, { kind: "Primitive" }); + break; + } + case "DeclareLocal": case "DeclareContext": case "NewExpression": - case "TypeCastExpression": case "JsxExpression": case "JsxFragment": case "RegExpLiteral": case "PropertyStore": - case "PropertyDelete": case "ComputedStore": case "ComputedLoad": - case "ComputedDelete": case "FunctionExpression": case "TaggedTemplateExpression": - case "TemplateLiteral": case "Await": case "NextIterableOf": case "ExpressionStatement": diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.expect.md new file mode 100644 index 0000000000..258371afec --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.expect.md @@ -0,0 +1,25 @@ + +## Input + +```javascript +// @debug +function Component(props) { + const x = makeObject(); + const y = delete x[props.value]; + return y; +} + +``` + +## Code + +```javascript +// @debug +function Component(props) { + const x = makeObject(); + const y = delete x[props.value]; + return y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.js b/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.js new file mode 100644 index 0000000000..187e797f40 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-computed-delete.js @@ -0,0 +1,6 @@ +// @debug +function Component(props) { + const x = makeObject(); + const y = delete x[props.value]; + return y; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.expect.md new file mode 100644 index 0000000000..4f1fb2d492 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.expect.md @@ -0,0 +1,23 @@ + +## Input + +```javascript +function Component(props) { + const x = makeObject(); + const y = delete x.value; + return y; +} + +``` + +## Code + +```javascript +function Component(props) { + const x = makeObject(); + const y = delete x.value; + return y; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.js b/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.js new file mode 100644 index 0000000000..b854004444 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-property-delete.js @@ -0,0 +1,5 @@ +function Component(props) { + const x = makeObject(); + const y = delete x.value; + return y; +} diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.expect.md b/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.expect.md new file mode 100644 index 0000000000..67de8c28c9 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.expect.md @@ -0,0 +1,26 @@ + +## Input + +```javascript +// @flow +function Component(props) { + // We can infer that `x` is a primitive bc it is aliased to `y`, + // which is used in a binary expression + const x = foo(); + const y = (x: any); + y + 1; + return x; +} +``` + +## Code + +```javascript +// @flow +function Component(props) { + const x = foo(); + return x; +} + +``` + \ No newline at end of file diff --git a/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.js b/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.js new file mode 100644 index 0000000000..eaac49f9a2 --- /dev/null +++ b/compiler/forget/src/__tests__/fixtures/compiler/infer-types-through-type-cast.flow.js @@ -0,0 +1,9 @@ +// @flow +function Component(props) { + // We can infer that `x` is a primitive bc it is aliased to `y`, + // which is used in a binary expression + const x = foo(); + const y = (x: any); + y + 1; + return x; +} \ No newline at end of file