Repository: facebook/react
File: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts (TypeScript)

Code before:
      ? parentNameExpr.node.name
      : '<anonymous>';

  const validateNestedFunction = (
    nestedFn: NodePath<
      t.FunctionDeclaration | t.FunctionExpression | t.ArrowFunctionExpression
    >,
  ): void => {
    if (
      nestedFn.node === fn.node ||
      programContext.alreadyCompiled.has(nestedFn.node)
    ) {
      return;
    }

    const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
    if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
      const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
      const nestedName =
        nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
          ? nestedFnNameExpr.node.name
          : '<anonymous>';

      CompilerError.throwInvalidReact({
        category: ErrorCategory.Factories,
        reason: `Cannot compile nested ${nestedFnType.toLowerCase()} inside a non-React function`,
        description:
          `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, ` +
          `but it's defined inside \`${parentName}\`, which is not a React component or hook. ` +
          `The compiler cannot optimize nested React functions when the parent function is not compiled, ` +
          `as this leads to scope reference errors. Either move \`${nestedName}\` to the module level, ` +
          `or ensure the parent function follows React naming conventions (PascalCase for components, ` +
          `"use" prefix for hooks)`,
        loc: nestedFn.node.loc ?? null,
      });
    }

    nestedFn.skip();
  };

  fn.traverse({
    FunctionDeclaration: validateNestedFunction,
    FunctionExpression: validateNestedFunction,
    ArrowFunctionExpression: validateNestedFunction,
  });
}

function getReactFunctionType(
  fn: BabelFn,
  pass: CompilerPass,
): ReactFunctionType | null {

Review comment (suggestion):
A couple things here:
* The message feels a bit unclear as to whether it's user error or a compiler todo. How about something like "Components and hooks cannot be created dynamically"
* For aggregation purposes we've tried to keep `reason` as a static string and put all the dynamic bits into the description or the `withDetails()` calls. 
* Using the new CompilerDiagnostic type for the error would allow controlling the output more, and let us point to multiple locations. I can imagine something like:

```
Error: Components and hooks cannot be created dynamically

Components and hooks must be static functions. Dynamically created components or hooks can result in those component or hook changing over time, leading to unnecessary re-renders and resetting state unexpectedly.

file.js:0:0
1 | function factory() {
    ^^^^^^ this function dynamically created a component/hook
2 |   return Component() { 
           ^^^^^ the component is created here
```

(with the arrows pointing to the right place)

Code after:
  ): void => {
    if (
      nestedFn.node === fn.node ||
      programContext.alreadyCompiled.has(nestedFn.node)
    ) {
      return;
    }

    if (nestedFn.scope.getProgramParent() !== nestedFn.scope.parent) {
      const nestedFnType = getReactFunctionType(nestedFn as BabelFn, pass);
      const nestedFnNameExpr = getFunctionName(nestedFn as BabelFn);
      const nestedName =
        nestedFnNameExpr !== null && nestedFnNameExpr.isIdentifier()
          ? nestedFnNameExpr.node.name
          : '<anonymous>';
      if (nestedFnType === 'Component' || nestedFnType === 'Hook') {
        CompilerError.throwDiagnostic({
          category: ErrorCategory.Factories,
          severity: ErrorSeverity.InvalidReact,
          reason: `Components and hooks cannot be created dynamically`,
          description: `The function \`${nestedName}\` appears to be a React ${nestedFnType.toLowerCase()}, but it's defined inside \`${parentName}\`. Components and Hooks should always be declared at module scope`,
          details: [
            {
              kind: 'error',
              message: 'this function dynamically created a component/hook',
              loc: parentNameExpr?.node.loc ?? fn.node.loc ?? null,
            },
            {
              kind: 'error',
              message: 'the component is created here',
              loc: nestedFnNameExpr?.node.loc ?? nestedFn.node.loc ?? null,
            },
          ],
        });
      }
    }

    nestedFn.skip();
  };

  fn.traverse({
    FunctionDeclaration: validateNestedFunction,
    FunctionExpression: validateNestedFunction,
    ArrowFunctionExpression: validateNestedFunction,
  });
}

function getReactFunctionType(
  fn: BabelFn,
  pass: CompilerPass,
): ReactFunctionType | null {