eslint-plugin-react-hooks 6.1.0-canary-19baee81-20250725 → 6.1.0-canary-9be531cd-20250729

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18676,7 +18676,7 @@ function printTerminal(terminal) {
18676
18676
  break;
18677
18677
  }
18678
18678
  case 'return': {
18679
- value = `[${terminal.id}] Return${terminal.value != null ? ' ' + printPlace(terminal.value) : ''}`;
18679
+ value = `[${terminal.id}] Return ${terminal.returnVariant}${terminal.value != null ? ' ' + printPlace(terminal.value) : ''}`;
18680
18680
  if (terminal.effects != null) {
18681
18681
  value += `\n ${terminal.effects.map(printAliasingEffect).join('\n ')}`;
18682
18682
  }
@@ -20025,6 +20025,7 @@ function mapTerminalSuccessors(terminal, fn) {
20025
20025
  case 'return': {
20026
20026
  return {
20027
20027
  kind: 'return',
20028
+ returnVariant: terminal.returnVariant,
20028
20029
  loc: terminal.loc,
20029
20030
  value: terminal.value,
20030
20031
  id: makeInstructionId(0),
@@ -22388,6 +22389,7 @@ function lower$1(func, env, bindings = null, capturedRefs = new Map()) {
22388
22389
  const fallthrough = builder.reserve('block');
22389
22390
  const terminal = {
22390
22391
  kind: 'return',
22392
+ returnVariant: 'Implicit',
22391
22393
  loc: GeneratedSource,
22392
22394
  value: lowerExpressionToTemporary(builder, body),
22393
22395
  id: makeInstructionId(0),
@@ -22415,6 +22417,7 @@ function lower$1(func, env, bindings = null, capturedRefs = new Map()) {
22415
22417
  }
22416
22418
  builder.terminate({
22417
22419
  kind: 'return',
22420
+ returnVariant: 'Void',
22418
22421
  loc: GeneratedSource,
22419
22422
  value: lowerValueToTemporary(builder, {
22420
22423
  kind: 'Primitive',
@@ -22482,6 +22485,7 @@ function lowerStatement(builder, stmtPath, label = null) {
22482
22485
  }
22483
22486
  const terminal = {
22484
22487
  kind: 'return',
22488
+ returnVariant: 'Explicit',
22485
22489
  loc: (_c = stmt.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
22486
22490
  value,
22487
22491
  id: makeInstructionId(0),
@@ -30680,6 +30684,7 @@ const EnvironmentConfigSchema = zod.z.object({
30680
30684
  hookPattern: zod.z.string().nullable().default(null),
30681
30685
  enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(false),
30682
30686
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
30687
+ validateNoVoidUseMemo: zod.z.boolean().default(false),
30683
30688
  });
30684
30689
  class Environment {
30685
30690
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -43797,43 +43802,69 @@ function getManualMemoizationReplacement(fn, loc, kind) {
43797
43802
  };
43798
43803
  }
43799
43804
  }
43800
- function extractManualMemoizationArgs(instr, kind, sidemap) {
43805
+ function extractManualMemoizationArgs(instr, kind, sidemap, errors) {
43801
43806
  const [fnPlace, depsListPlace] = instr.value.args;
43802
43807
  if (fnPlace == null) {
43803
- CompilerError.throwInvalidReact({
43804
- reason: `Expected a callback function to be passed to ${kind}`,
43805
- loc: instr.value.loc,
43808
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43809
+ severity: ErrorSeverity.InvalidReact,
43810
+ category: `Expected a callback function to be passed to ${kind}`,
43811
+ description: `Expected a callback function to be passed to ${kind}`,
43806
43812
  suggestions: null,
43807
- });
43813
+ }).withDetail({
43814
+ kind: 'error',
43815
+ loc: instr.value.loc,
43816
+ message: `Expected a callback function to be passed to ${kind}`,
43817
+ }));
43818
+ return { fnPlace: null, depsList: null };
43808
43819
  }
43809
43820
  if (fnPlace.kind === 'Spread' || (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Spread') {
43810
- CompilerError.throwInvalidReact({
43811
- reason: `Unexpected spread argument to ${kind}`,
43812
- loc: instr.value.loc,
43821
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43822
+ severity: ErrorSeverity.InvalidReact,
43823
+ category: `Unexpected spread argument to ${kind}`,
43824
+ description: `Unexpected spread argument to ${kind}`,
43813
43825
  suggestions: null,
43814
- });
43826
+ }).withDetail({
43827
+ kind: 'error',
43828
+ loc: instr.value.loc,
43829
+ message: `Unexpected spread argument to ${kind}`,
43830
+ }));
43831
+ return { fnPlace: null, depsList: null };
43815
43832
  }
43816
43833
  let depsList = null;
43817
43834
  if (depsListPlace != null) {
43818
43835
  const maybeDepsList = sidemap.maybeDepsLists.get(depsListPlace.identifier.id);
43819
43836
  if (maybeDepsList == null) {
43820
- CompilerError.throwInvalidReact({
43821
- reason: `Expected the dependency list for ${kind} to be an array literal`,
43837
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43838
+ severity: ErrorSeverity.InvalidReact,
43839
+ category: `Expected the dependency list for ${kind} to be an array literal`,
43840
+ description: `Expected the dependency list for ${kind} to be an array literal`,
43822
43841
  suggestions: null,
43842
+ }).withDetail({
43843
+ kind: 'error',
43823
43844
  loc: depsListPlace.loc,
43824
- });
43845
+ message: `Expected the dependency list for ${kind} to be an array literal`,
43846
+ }));
43847
+ return { fnPlace, depsList: null };
43825
43848
  }
43826
- depsList = maybeDepsList.map(dep => {
43849
+ depsList = [];
43850
+ for (const dep of maybeDepsList) {
43827
43851
  const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
43828
43852
  if (maybeDep == null) {
43829
- CompilerError.throwInvalidReact({
43830
- reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43853
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43854
+ severity: ErrorSeverity.InvalidReact,
43855
+ category: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43856
+ description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43831
43857
  suggestions: null,
43858
+ }).withDetail({
43859
+ kind: 'error',
43832
43860
  loc: dep.loc,
43833
- });
43861
+ message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43862
+ }));
43834
43863
  }
43835
- return maybeDep;
43836
- });
43864
+ else {
43865
+ depsList.push(maybeDep);
43866
+ }
43867
+ }
43837
43868
  }
43838
43869
  return {
43839
43870
  fnPlace,
@@ -43841,6 +43872,8 @@ function extractManualMemoizationArgs(instr, kind, sidemap) {
43841
43872
  };
43842
43873
  }
43843
43874
  function dropManualMemoization(func) {
43875
+ var _a;
43876
+ const errors = new CompilerError();
43844
43877
  const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
43845
43878
  func.env.config.validateNoSetStateInRender ||
43846
43879
  func.env.config.enablePreserveExistingMemoizationGuarantees;
@@ -43865,15 +43898,44 @@ function dropManualMemoization(func) {
43865
43898
  : instr.value.property.identifier.id;
43866
43899
  const manualMemo = sidemap.manualMemos.get(id);
43867
43900
  if (manualMemo != null) {
43868
- const { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap);
43901
+ const { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
43902
+ if (fnPlace == null) {
43903
+ continue;
43904
+ }
43905
+ if (func.env.config.validateNoVoidUseMemo &&
43906
+ manualMemo.kind === 'useMemo') {
43907
+ const funcToCheck = (_a = sidemap.functions.get(fnPlace.identifier.id)) === null || _a === void 0 ? void 0 : _a.value;
43908
+ if (funcToCheck !== undefined && funcToCheck.loweredFunc.func) {
43909
+ if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) {
43910
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43911
+ severity: ErrorSeverity.InvalidReact,
43912
+ category: 'useMemo() callbacks must return a value',
43913
+ description: `This ${manualMemo.loadInstr.value.kind === 'PropertyLoad'
43914
+ ? 'React.useMemo'
43915
+ : 'useMemo'} callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.`,
43916
+ suggestions: null,
43917
+ }).withDetail({
43918
+ kind: 'error',
43919
+ loc: instr.value.loc,
43920
+ message: 'useMemo() callbacks must return a value',
43921
+ }));
43922
+ }
43923
+ }
43924
+ }
43869
43925
  instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
43870
43926
  if (isValidationEnabled) {
43871
43927
  if (!sidemap.functions.has(fnPlace.identifier.id)) {
43872
- CompilerError.throwInvalidReact({
43873
- reason: `Expected the first argument to be an inline function expression`,
43928
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43929
+ severity: ErrorSeverity.InvalidReact,
43930
+ category: `Expected the first argument to be an inline function expression`,
43931
+ description: `Expected the first argument to be an inline function expression`,
43874
43932
  suggestions: [],
43933
+ }).withDetail({
43934
+ kind: 'error',
43875
43935
  loc: fnPlace.loc,
43876
- });
43936
+ message: `Expected the first argument to be an inline function expression`,
43937
+ }));
43938
+ continue;
43877
43939
  }
43878
43940
  const memoDecl = manualMemo.kind === 'useMemo'
43879
43941
  ? instr.lvalue
@@ -43920,6 +43982,7 @@ function dropManualMemoization(func) {
43920
43982
  markInstructionIds(func.body);
43921
43983
  }
43922
43984
  }
43985
+ return errors.asResult();
43923
43986
  }
43924
43987
  function findOptionalPlaces(fn) {
43925
43988
  const optionals = new Set();
@@ -43963,6 +44026,17 @@ function findOptionalPlaces(fn) {
43963
44026
  }
43964
44027
  return optionals;
43965
44028
  }
44029
+ function hasNonVoidReturn(func) {
44030
+ for (const [, block] of func.body.blocks) {
44031
+ if (block.terminal.kind === 'return') {
44032
+ if (block.terminal.returnVariant === 'Explicit' ||
44033
+ block.terminal.returnVariant === 'Implicit') {
44034
+ return true;
44035
+ }
44036
+ }
44037
+ }
44038
+ return false;
44039
+ }
43966
44040
 
43967
44041
  class StableSidemap {
43968
44042
  constructor(env) {
@@ -49406,6 +49480,7 @@ function emitSelectorFn(env, keys) {
49406
49480
  terminal: {
49407
49481
  id: makeInstructionId(0),
49408
49482
  kind: 'return',
49483
+ returnVariant: 'Explicit',
49409
49484
  loc: GeneratedSource,
49410
49485
  value: arrayInstr.lvalue,
49411
49486
  effects: null,
@@ -49837,6 +49912,7 @@ function emitOutlinedFn(env, jsx, oldProps, globals) {
49837
49912
  terminal: {
49838
49913
  id: makeInstructionId(0),
49839
49914
  kind: 'return',
49915
+ returnVariant: 'Explicit',
49840
49916
  loc: GeneratedSource,
49841
49917
  value: instructions.at(-1).lvalue,
49842
49918
  effects: null,
@@ -50657,7 +50733,7 @@ function runWithEnvironment(func, env) {
50657
50733
  !env.config.enablePreserveExistingManualUseMemo &&
50658
50734
  !env.config.disableMemoizationForDebugging &&
50659
50735
  !env.config.enableChangeDetectionForDebugging) {
50660
- dropManualMemoization(hir);
50736
+ dropManualMemoization(hir).unwrap();
50661
50737
  log({ kind: 'hir', name: 'DropManualMemoization', value: hir });
50662
50738
  }
50663
50739
  inlineImmediatelyInvokedFunctionExpressions(hir);
@@ -52607,6 +52683,7 @@ const COMPILER_OPTIONS = {
52607
52683
  validateNoImpureFunctionsInRender: true,
52608
52684
  validateStaticComponents: true,
52609
52685
  validateNoFreezingKnownMutableFunctions: true,
52686
+ validateNoVoidUseMemo: true,
52610
52687
  }),
52611
52688
  };
52612
52689
  const rule$1 = {
@@ -18667,7 +18667,7 @@ function printTerminal(terminal) {
18667
18667
  break;
18668
18668
  }
18669
18669
  case 'return': {
18670
- value = `[${terminal.id}] Return${terminal.value != null ? ' ' + printPlace(terminal.value) : ''}`;
18670
+ value = `[${terminal.id}] Return ${terminal.returnVariant}${terminal.value != null ? ' ' + printPlace(terminal.value) : ''}`;
18671
18671
  if (terminal.effects != null) {
18672
18672
  value += `\n ${terminal.effects.map(printAliasingEffect).join('\n ')}`;
18673
18673
  }
@@ -20016,6 +20016,7 @@ function mapTerminalSuccessors(terminal, fn) {
20016
20016
  case 'return': {
20017
20017
  return {
20018
20018
  kind: 'return',
20019
+ returnVariant: terminal.returnVariant,
20019
20020
  loc: terminal.loc,
20020
20021
  value: terminal.value,
20021
20022
  id: makeInstructionId(0),
@@ -22379,6 +22380,7 @@ function lower$1(func, env, bindings = null, capturedRefs = new Map()) {
22379
22380
  const fallthrough = builder.reserve('block');
22380
22381
  const terminal = {
22381
22382
  kind: 'return',
22383
+ returnVariant: 'Implicit',
22382
22384
  loc: GeneratedSource,
22383
22385
  value: lowerExpressionToTemporary(builder, body),
22384
22386
  id: makeInstructionId(0),
@@ -22406,6 +22408,7 @@ function lower$1(func, env, bindings = null, capturedRefs = new Map()) {
22406
22408
  }
22407
22409
  builder.terminate({
22408
22410
  kind: 'return',
22411
+ returnVariant: 'Void',
22409
22412
  loc: GeneratedSource,
22410
22413
  value: lowerValueToTemporary(builder, {
22411
22414
  kind: 'Primitive',
@@ -22473,6 +22476,7 @@ function lowerStatement(builder, stmtPath, label = null) {
22473
22476
  }
22474
22477
  const terminal = {
22475
22478
  kind: 'return',
22479
+ returnVariant: 'Explicit',
22476
22480
  loc: (_c = stmt.node.loc) !== null && _c !== void 0 ? _c : GeneratedSource,
22477
22481
  value,
22478
22482
  id: makeInstructionId(0),
@@ -30507,6 +30511,7 @@ const EnvironmentConfigSchema = zod.z.object({
30507
30511
  hookPattern: zod.z.string().nullable().default(null),
30508
30512
  enableTreatRefLikeIdentifiersAsRefs: zod.z.boolean().default(false),
30509
30513
  lowerContextAccess: ExternalFunctionSchema.nullable().default(null),
30514
+ validateNoVoidUseMemo: zod.z.boolean().default(false),
30510
30515
  });
30511
30516
  class Environment {
30512
30517
  constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
@@ -43624,43 +43629,69 @@ function getManualMemoizationReplacement(fn, loc, kind) {
43624
43629
  };
43625
43630
  }
43626
43631
  }
43627
- function extractManualMemoizationArgs(instr, kind, sidemap) {
43632
+ function extractManualMemoizationArgs(instr, kind, sidemap, errors) {
43628
43633
  const [fnPlace, depsListPlace] = instr.value.args;
43629
43634
  if (fnPlace == null) {
43630
- CompilerError.throwInvalidReact({
43631
- reason: `Expected a callback function to be passed to ${kind}`,
43632
- loc: instr.value.loc,
43635
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43636
+ severity: ErrorSeverity.InvalidReact,
43637
+ category: `Expected a callback function to be passed to ${kind}`,
43638
+ description: `Expected a callback function to be passed to ${kind}`,
43633
43639
  suggestions: null,
43634
- });
43640
+ }).withDetail({
43641
+ kind: 'error',
43642
+ loc: instr.value.loc,
43643
+ message: `Expected a callback function to be passed to ${kind}`,
43644
+ }));
43645
+ return { fnPlace: null, depsList: null };
43635
43646
  }
43636
43647
  if (fnPlace.kind === 'Spread' || (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Spread') {
43637
- CompilerError.throwInvalidReact({
43638
- reason: `Unexpected spread argument to ${kind}`,
43639
- loc: instr.value.loc,
43648
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43649
+ severity: ErrorSeverity.InvalidReact,
43650
+ category: `Unexpected spread argument to ${kind}`,
43651
+ description: `Unexpected spread argument to ${kind}`,
43640
43652
  suggestions: null,
43641
- });
43653
+ }).withDetail({
43654
+ kind: 'error',
43655
+ loc: instr.value.loc,
43656
+ message: `Unexpected spread argument to ${kind}`,
43657
+ }));
43658
+ return { fnPlace: null, depsList: null };
43642
43659
  }
43643
43660
  let depsList = null;
43644
43661
  if (depsListPlace != null) {
43645
43662
  const maybeDepsList = sidemap.maybeDepsLists.get(depsListPlace.identifier.id);
43646
43663
  if (maybeDepsList == null) {
43647
- CompilerError.throwInvalidReact({
43648
- reason: `Expected the dependency list for ${kind} to be an array literal`,
43664
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43665
+ severity: ErrorSeverity.InvalidReact,
43666
+ category: `Expected the dependency list for ${kind} to be an array literal`,
43667
+ description: `Expected the dependency list for ${kind} to be an array literal`,
43649
43668
  suggestions: null,
43669
+ }).withDetail({
43670
+ kind: 'error',
43650
43671
  loc: depsListPlace.loc,
43651
- });
43672
+ message: `Expected the dependency list for ${kind} to be an array literal`,
43673
+ }));
43674
+ return { fnPlace, depsList: null };
43652
43675
  }
43653
- depsList = maybeDepsList.map(dep => {
43676
+ depsList = [];
43677
+ for (const dep of maybeDepsList) {
43654
43678
  const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
43655
43679
  if (maybeDep == null) {
43656
- CompilerError.throwInvalidReact({
43657
- reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43680
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43681
+ severity: ErrorSeverity.InvalidReact,
43682
+ category: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43683
+ description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43658
43684
  suggestions: null,
43685
+ }).withDetail({
43686
+ kind: 'error',
43659
43687
  loc: dep.loc,
43660
- });
43688
+ message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
43689
+ }));
43661
43690
  }
43662
- return maybeDep;
43663
- });
43691
+ else {
43692
+ depsList.push(maybeDep);
43693
+ }
43694
+ }
43664
43695
  }
43665
43696
  return {
43666
43697
  fnPlace,
@@ -43668,6 +43699,8 @@ function extractManualMemoizationArgs(instr, kind, sidemap) {
43668
43699
  };
43669
43700
  }
43670
43701
  function dropManualMemoization(func) {
43702
+ var _a;
43703
+ const errors = new CompilerError();
43671
43704
  const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
43672
43705
  func.env.config.validateNoSetStateInRender ||
43673
43706
  func.env.config.enablePreserveExistingMemoizationGuarantees;
@@ -43692,15 +43725,44 @@ function dropManualMemoization(func) {
43692
43725
  : instr.value.property.identifier.id;
43693
43726
  const manualMemo = sidemap.manualMemos.get(id);
43694
43727
  if (manualMemo != null) {
43695
- const { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap);
43728
+ const { fnPlace, depsList } = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
43729
+ if (fnPlace == null) {
43730
+ continue;
43731
+ }
43732
+ if (func.env.config.validateNoVoidUseMemo &&
43733
+ manualMemo.kind === 'useMemo') {
43734
+ const funcToCheck = (_a = sidemap.functions.get(fnPlace.identifier.id)) === null || _a === void 0 ? void 0 : _a.value;
43735
+ if (funcToCheck !== undefined && funcToCheck.loweredFunc.func) {
43736
+ if (!hasNonVoidReturn(funcToCheck.loweredFunc.func)) {
43737
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43738
+ severity: ErrorSeverity.InvalidReact,
43739
+ category: 'useMemo() callbacks must return a value',
43740
+ description: `This ${manualMemo.loadInstr.value.kind === 'PropertyLoad'
43741
+ ? 'React.useMemo'
43742
+ : 'useMemo'} callback doesn't return a value. useMemo is for computing and caching values, not for arbitrary side effects.`,
43743
+ suggestions: null,
43744
+ }).withDetail({
43745
+ kind: 'error',
43746
+ loc: instr.value.loc,
43747
+ message: 'useMemo() callbacks must return a value',
43748
+ }));
43749
+ }
43750
+ }
43751
+ }
43696
43752
  instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
43697
43753
  if (isValidationEnabled) {
43698
43754
  if (!sidemap.functions.has(fnPlace.identifier.id)) {
43699
- CompilerError.throwInvalidReact({
43700
- reason: `Expected the first argument to be an inline function expression`,
43755
+ errors.pushDiagnostic(CompilerDiagnostic.create({
43756
+ severity: ErrorSeverity.InvalidReact,
43757
+ category: `Expected the first argument to be an inline function expression`,
43758
+ description: `Expected the first argument to be an inline function expression`,
43701
43759
  suggestions: [],
43760
+ }).withDetail({
43761
+ kind: 'error',
43702
43762
  loc: fnPlace.loc,
43703
- });
43763
+ message: `Expected the first argument to be an inline function expression`,
43764
+ }));
43765
+ continue;
43704
43766
  }
43705
43767
  const memoDecl = manualMemo.kind === 'useMemo'
43706
43768
  ? instr.lvalue
@@ -43747,6 +43809,7 @@ function dropManualMemoization(func) {
43747
43809
  markInstructionIds(func.body);
43748
43810
  }
43749
43811
  }
43812
+ return errors.asResult();
43750
43813
  }
43751
43814
  function findOptionalPlaces(fn) {
43752
43815
  const optionals = new Set();
@@ -43790,6 +43853,17 @@ function findOptionalPlaces(fn) {
43790
43853
  }
43791
43854
  return optionals;
43792
43855
  }
43856
+ function hasNonVoidReturn(func) {
43857
+ for (const [, block] of func.body.blocks) {
43858
+ if (block.terminal.kind === 'return') {
43859
+ if (block.terminal.returnVariant === 'Explicit' ||
43860
+ block.terminal.returnVariant === 'Implicit') {
43861
+ return true;
43862
+ }
43863
+ }
43864
+ }
43865
+ return false;
43866
+ }
43793
43867
 
43794
43868
  class StableSidemap {
43795
43869
  constructor(env) {
@@ -49233,6 +49307,7 @@ function emitSelectorFn(env, keys) {
49233
49307
  terminal: {
49234
49308
  id: makeInstructionId(0),
49235
49309
  kind: 'return',
49310
+ returnVariant: 'Explicit',
49236
49311
  loc: GeneratedSource,
49237
49312
  value: arrayInstr.lvalue,
49238
49313
  effects: null,
@@ -49664,6 +49739,7 @@ function emitOutlinedFn(env, jsx, oldProps, globals) {
49664
49739
  terminal: {
49665
49740
  id: makeInstructionId(0),
49666
49741
  kind: 'return',
49742
+ returnVariant: 'Explicit',
49667
49743
  loc: GeneratedSource,
49668
49744
  value: instructions.at(-1).lvalue,
49669
49745
  effects: null,
@@ -50484,7 +50560,7 @@ function runWithEnvironment(func, env) {
50484
50560
  !env.config.enablePreserveExistingManualUseMemo &&
50485
50561
  !env.config.disableMemoizationForDebugging &&
50486
50562
  !env.config.enableChangeDetectionForDebugging) {
50487
- dropManualMemoization(hir);
50563
+ dropManualMemoization(hir).unwrap();
50488
50564
  log({ kind: 'hir', name: 'DropManualMemoization', value: hir });
50489
50565
  }
50490
50566
  inlineImmediatelyInvokedFunctionExpressions(hir);
@@ -52434,6 +52510,7 @@ const COMPILER_OPTIONS = {
52434
52510
  validateNoImpureFunctionsInRender: true,
52435
52511
  validateStaticComponents: true,
52436
52512
  validateNoFreezingKnownMutableFunctions: true,
52513
+ validateNoVoidUseMemo: true,
52437
52514
  }),
52438
52515
  };
52439
52516
  const rule$1 = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-hooks",
3
3
  "description": "ESLint rules for React Hooks",
4
- "version": "6.1.0-canary-19baee81-20250725",
4
+ "version": "6.1.0-canary-9be531cd-20250729",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/facebook/react.git",