main
ts 54 lines 2.25 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 import {CompilerDiagnostic} from '..';
9 import {ErrorCategory} from '../CompilerError';
10 import {HIRFunction} from '../HIR';
11 import {getFunctionCallSignature} from '../Inference/InferMutationAliasingEffects';
12
13 /**
14 * Checks that known-impure functions are not called during render. Examples of invalid functions to
15 * call during render are `Math.random()` and `Date.now()`. Users may extend this set of
16 * impure functions via a module type provider and specifying functions with `impure: true`.
17 *
18 * TODO: add best-effort analysis of functions which are called during render. We have variations of
19 * this in several of our validation passes and should unify those analyses into a reusable helper
20 * and use it here.
21 */
22 export function validateNoImpureFunctionsInRender(fn: HIRFunction): void {
23 for (const [, block] of fn.body.blocks) {
24 for (const instr of block.instructions) {
25 const value = instr.value;
26 if (value.kind === 'MethodCall' || value.kind == 'CallExpression') {
27 const callee =
28 value.kind === 'MethodCall' ? value.property : value.callee;
29 const signature = getFunctionCallSignature(
30 fn.env,
31 callee.identifier.type,
32 );
33 if (signature != null && signature.impure === true) {
34 fn.env.recordError(
35 CompilerDiagnostic.create({
36 category: ErrorCategory.Purity,
37 reason: 'Cannot call impure function during render',
38 description:
39 (signature.canonicalName != null
40 ? `\`${signature.canonicalName}\` is an impure function. `
41 : '') +
42 'Calling an impure function can produce unstable results that update unpredictably when the component happens to re-render. (https://react.dev/reference/rules/components-and-hooks-must-be-pure#components-and-hooks-must-be-idempotent)',
43 suggestions: null,
44 }).withDetails({
45 kind: 'error',
46 loc: callee.loc,
47 message: 'Cannot call impure function',
48 }),
49 );
50 }
51 }
52 }
53 }
54 }