main
ts 90 lines 3.07 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 {
9 CompilerDiagnostic,
10 CompilerError,
11 ErrorCategory,
12 } from '../CompilerError';
13 import {HIRFunction, IdentifierId, SourceLocation} from '../HIR';
14 import {Result} from '../Utils/Result';
15
16 /**
17 * Validates against components that are created dynamically and whose identity is not guaranteed
18 * to be stable (which would cause the component to reset on each re-render).
19 */
20 export function validateStaticComponents(
21 fn: HIRFunction,
22 ): Result<void, CompilerError> {
23 const error = new CompilerError();
24 const knownDynamicComponents = new Map<IdentifierId, SourceLocation>();
25 for (const block of fn.body.blocks.values()) {
26 phis: for (const phi of block.phis) {
27 for (const operand of phi.operands.values()) {
28 const loc = knownDynamicComponents.get(operand.identifier.id);
29 if (loc != null) {
30 knownDynamicComponents.set(phi.place.identifier.id, loc);
31 continue phis;
32 }
33 }
34 }
35 for (const instr of block.instructions) {
36 const {lvalue, value} = instr;
37 switch (value.kind) {
38 case 'FunctionExpression':
39 case 'NewExpression':
40 case 'MethodCall':
41 case 'CallExpression': {
42 knownDynamicComponents.set(lvalue.identifier.id, value.loc);
43 break;
44 }
45 case 'LoadLocal': {
46 const loc = knownDynamicComponents.get(value.place.identifier.id);
47 if (loc != null) {
48 knownDynamicComponents.set(lvalue.identifier.id, loc);
49 }
50 break;
51 }
52 case 'StoreLocal': {
53 const loc = knownDynamicComponents.get(value.value.identifier.id);
54 if (loc != null) {
55 knownDynamicComponents.set(lvalue.identifier.id, loc);
56 knownDynamicComponents.set(value.lvalue.place.identifier.id, loc);
57 }
58 break;
59 }
60 case 'JsxExpression': {
61 if (value.tag.kind === 'Identifier') {
62 const location = knownDynamicComponents.get(
63 value.tag.identifier.id,
64 );
65 if (location != null) {
66 error.pushDiagnostic(
67 CompilerDiagnostic.create({
68 category: ErrorCategory.StaticComponents,
69 reason: 'Cannot create components during render',
70 description: `Components created during render will reset their state each time they are created. Declare components outside of render`,
71 })
72 .withDetails({
73 kind: 'error',
74 loc: value.tag.loc,
75 message: 'This component is created during render',
76 })
77 .withDetails({
78 kind: 'error',
79 loc: location,
80 message: 'The component is created during render here',
81 }),
82 );
83 }
84 }
85 }
86 }
87 }
88 }
89 return error.asResult();
90 }