diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts index 59f067787359f..0e5983d6c8dfd 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/PrintHIR.ts @@ -72,6 +72,7 @@ export function printFunction(fn: HIRFunction): string { if (definition.length !== 0) { output.push(definition); } + output.push(printType(fn.returnIdentifier.type)); output.push(printHIR(fn.body)); output.push(...fn.directives); return output.join('\n'); @@ -555,7 +556,8 @@ export function printInstructionValue(instrValue: ReactiveValue): string { } }) .join(', ') ?? ''; - value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]:\n${fn}`; + const type = printType(instrValue.loweredFunc.func.returnIdentifier.type).trim(); + value = `${kind} ${name} @deps[${deps}] @context[${context}] @effects[${effects}]${type!== '' ? ` return${type}` : ''}:\n${fn}`; break; } case 'TaggedTemplateExpression': { diff --git a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts index 2c9004e6ad9a6..1e73697783f0b 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts @@ -481,14 +481,20 @@ function canMergeScopes( } function isAlwaysInvalidatingType(type: Type): boolean { - if (type.kind === 'Object') { - switch (type.shapeId) { - case BuiltInArrayId: - case BuiltInObjectId: - case BuiltInFunctionId: - case BuiltInJsxId: { - return true; + switch (type.kind) { + case 'Object': { + switch (type.shapeId) { + case BuiltInArrayId: + case BuiltInObjectId: + case BuiltInFunctionId: + case BuiltInJsxId: { + return true; + } } + break; + } + case 'Function': { + return true; } } return false; diff --git a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts index 4dfeb676a3d0b..8cf98225af391 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/TypeInference/InferTypes.ts @@ -88,6 +88,7 @@ function apply(func: HIRFunction, unifier: Unifier): void { } } } + func.returnIdentifier.type = unifier.get(func.returnIdentifier.type); } type TypeEquation = { @@ -122,6 +123,7 @@ function* generate( } const names = new Map(); + const returnTypes: Array = []; for (const [_, block] of func.body.blocks) { for (const phi of block.phis) { yield equation(phi.type, { @@ -133,6 +135,18 @@ function* generate( for (const instr of block.instructions) { yield* generateInstructionTypes(func.env, names, instr); } + const terminal = block.terminal; + if (terminal.kind === 'return') { + returnTypes.push(terminal.value.identifier.type); + } + } + if (returnTypes.length > 1) { + yield equation(func.returnIdentifier.type, { + kind: 'Phi', + operands: returnTypes, + }); + } else if (returnTypes.length === 1) { + yield equation(func.returnIdentifier.type, returnTypes[0]!); } } @@ -346,7 +360,7 @@ function* generateInstructionTypes( case 'FunctionExpression': { yield* generate(value.loweredFunc.func); - yield equation(left, {kind: 'Object', shapeId: BuiltInFunctionId}); + yield equation(left, {kind: 'Function', shapeId: BuiltInFunctionId, return: value.loweredFunc.func.returnIdentifier.type}); break; } diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md index 1eb9b98b09529..5205445751249 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.expect.md @@ -13,7 +13,7 @@ component Component() { if (data != null) { return true; } else { - return false; + return {}; } }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js index 02114e26530c5..1621ab41c9050 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/error.todo-repro-missed-memoization-from-capture-in-invoked-function-inferred-as-mutation.js @@ -9,7 +9,7 @@ component Component() { if (data != null) { return true; } else { - return false; + return {}; } }; diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md index ae5bf41e3227c..7939c9143d1d7 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-const-declaration.expect.md @@ -25,18 +25,17 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function hoisting() { const $ = _c(1); - let t0; + let foo; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const foo = () => bar + baz; + foo = () => bar + baz; const bar = 3; const baz = 2; - t0 = foo(); - $[0] = t0; + $[0] = foo; } else { - t0 = $[0]; + foo = $[0]; } - return t0; + return foo(); } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md index 8974664b0515f..8d694a984aed5 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/hoisting-simple-let-declaration.expect.md @@ -25,18 +25,17 @@ export const FIXTURE_ENTRYPOINT = { import { c as _c } from "react/compiler-runtime"; function hoisting() { const $ = _c(1); - let t0; + let foo; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { - const foo = () => bar + baz; + foo = () => bar + baz; let bar = 3; let baz = 2; - t0 = foo(); - $[0] = t0; + $[0] = foo; } else { - t0 = $[0]; + foo = $[0]; } - return t0; + return foo(); } export const FIXTURE_ENTRYPOINT = { diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md index 14913665c5474..6d9183915467f 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/preserve-memo-validation/useCallback-nonescaping-invoked-callback-escaping-return.expect.md @@ -40,7 +40,7 @@ import { c as _c } from "react/compiler-runtime"; // @validatePreserveExistingMe import { useCallback } from "react"; function Component(t0) { - const $ = _c(11); + const $ = _c(9); const { entity, children } = t0; let t1; if ($[0] !== entity) { @@ -51,46 +51,39 @@ function Component(t0) { t1 = $[1]; } const showMessage = t1; + + const shouldShowMessage = showMessage(); let t2; - if ($[2] !== showMessage) { - t2 = showMessage(); - $[2] = showMessage; + if ($[2] !== shouldShowMessage) { + t2 =
{shouldShowMessage}
; + $[2] = shouldShowMessage; $[3] = t2; } else { t2 = $[3]; } - const shouldShowMessage = t2; let t3; - if ($[4] !== shouldShowMessage) { - t3 =
{shouldShowMessage}
; - $[4] = shouldShowMessage; + if ($[4] !== children) { + t3 =
{children}
; + $[4] = children; $[5] = t3; } else { t3 = $[5]; } let t4; - if ($[6] !== children) { - t4 =
{children}
; - $[6] = children; - $[7] = t4; - } else { - t4 = $[7]; - } - let t5; - if ($[8] !== t3 || $[9] !== t4) { - t5 = ( + if ($[6] !== t2 || $[7] !== t3) { + t4 = (
+ {t2} {t3} - {t4}
); - $[8] = t3; - $[9] = t4; - $[10] = t5; + $[6] = t2; + $[7] = t3; + $[8] = t4; } else { - t5 = $[10]; + t4 = $[8]; } - return t5; + return t4; } export const FIXTURE_ENTRYPOINT = {