262
env.set(place.identifier.id, type);
263
}
264
265
+ const interpolatedAsJsx = new Set<IdentifierId>();
266
+ for (const block of fn.body.blocks.values()) {
267
+ for (const instr of block.instructions) {
268
+ const {value} = instr;
269
+ if (value.kind === 'JsxExpression' || value.kind === 'JsxFragment') {
270
+ if (value.children != null) {
271
+ for (const child of value.children) {
272
+ interpolatedAsJsx.add(child.identifier.id);
273
+ }
274
+ }
275
+ }
276
+ }
277
+ }
278
+
279
for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
280
env.resetChanged();
281
returnValues = [];
428
if (!didError) {
429
const isRefLValue = isUseRefType(instr.lvalue.identifier);
430
for (const operand of eachInstructionValueOperand(instr.value)) {
417
- if (hookKind != null) {
431
+ /**
432
+ * By default we check that function call operands are not refs,
433
+ * ref values, or functions that can access refs.
434
+ */
435
+ if (
436
+ isRefLValue ||
437
+ interpolatedAsJsx.has(instr.lvalue.identifier.id) ||
438
+ hookKind != null
439
+ ) {
440
+ /**
441
+ * Special cases:
442
+ *
443
+ * 1) the lvalue is a ref
444
+ * In general passing a ref to a function may access that ref
445
+ * value during render, so we disallow it.
446
+ *
447
+ * The main exception is the "mergeRefs" pattern, ie a function
448
+ * that accepts multiple refs as arguments (or an array of refs)
449
+ * and returns a new, aggregated ref. If the lvalue is a ref,
450
+ * we assume that the user is doing this pattern and allow passing
451
+ * refs.
452
+ *
453
+ * Eg `const mergedRef = mergeRefs(ref1, ref2)`
454
+ *
455
+ * 2) the lvalue is passed as a jsx child
456
+ *
457
+ * For example `<Foo>{renderHelper(ref)}</Foo>`. Here we have more
458
+ * context and infer that the ref is being passed to a component-like
459
+ * render function which attempts to obey the rules.
460
+ *
461
+ * 3) hooks
462
+ *
463
+ * Hooks are independently checked to ensure they don't access refs
464
+ * during render.
465
+ */
466
validateNoDirectRefValueAccess(errors, operand, env);
467
} else if (!isRefLValue) {
468
/**