eslint-plugin-react-hooks 7.1.0-canary-257b033f-20251113 → 7.1.0-canary-0972e239-20251118
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.
|
@@ -18957,9 +18957,18 @@ function isRefOrRefLikeMutableType(type) {
|
|
|
18957
18957
|
function isSetStateType(id) {
|
|
18958
18958
|
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState';
|
|
18959
18959
|
}
|
|
18960
|
+
function isUseActionStateType(id) {
|
|
18961
|
+
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseActionState');
|
|
18962
|
+
}
|
|
18960
18963
|
function isStartTransitionType(id) {
|
|
18961
18964
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition');
|
|
18962
18965
|
}
|
|
18966
|
+
function isUseOptimisticType(id) {
|
|
18967
|
+
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseOptimistic');
|
|
18968
|
+
}
|
|
18969
|
+
function isSetOptimisticType(id) {
|
|
18970
|
+
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetOptimistic');
|
|
18971
|
+
}
|
|
18963
18972
|
function isSetActionStateType(id) {
|
|
18964
18973
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState');
|
|
18965
18974
|
}
|
|
@@ -18981,7 +18990,8 @@ function isStableType(id) {
|
|
|
18981
18990
|
isSetActionStateType(id) ||
|
|
18982
18991
|
isDispatcherType(id) ||
|
|
18983
18992
|
isUseRefType(id) ||
|
|
18984
|
-
isStartTransitionType(id)
|
|
18993
|
+
isStartTransitionType(id) ||
|
|
18994
|
+
isSetOptimisticType(id));
|
|
18985
18995
|
}
|
|
18986
18996
|
function isStableTypeContainer(id) {
|
|
18987
18997
|
const type_ = id.type;
|
|
@@ -18989,8 +18999,9 @@ function isStableTypeContainer(id) {
|
|
|
18989
18999
|
return false;
|
|
18990
19000
|
}
|
|
18991
19001
|
return (isUseStateType(id) ||
|
|
18992
|
-
|
|
19002
|
+
isUseActionStateType(id) ||
|
|
18993
19003
|
isUseReducerType(id) ||
|
|
19004
|
+
isUseOptimisticType(id) ||
|
|
18994
19005
|
type_.shapeId === 'BuiltInUseTransition');
|
|
18995
19006
|
}
|
|
18996
19007
|
function evaluatesToStableTypeOrContainer(env, { value }) {
|
|
@@ -19003,6 +19014,7 @@ function evaluatesToStableTypeOrContainer(env, { value }) {
|
|
|
19003
19014
|
case 'useActionState':
|
|
19004
19015
|
case 'useRef':
|
|
19005
19016
|
case 'useTransition':
|
|
19017
|
+
case 'useOptimistic':
|
|
19006
19018
|
return true;
|
|
19007
19019
|
}
|
|
19008
19020
|
}
|
|
@@ -19851,6 +19863,29 @@ function* eachInstructionLValue(instr) {
|
|
|
19851
19863
|
}
|
|
19852
19864
|
yield* eachInstructionValueLValue(instr.value);
|
|
19853
19865
|
}
|
|
19866
|
+
function* eachInstructionLValueWithKind(instr) {
|
|
19867
|
+
switch (instr.value.kind) {
|
|
19868
|
+
case 'DeclareContext':
|
|
19869
|
+
case 'StoreContext':
|
|
19870
|
+
case 'DeclareLocal':
|
|
19871
|
+
case 'StoreLocal': {
|
|
19872
|
+
yield [instr.value.lvalue.place, instr.value.lvalue.kind];
|
|
19873
|
+
break;
|
|
19874
|
+
}
|
|
19875
|
+
case 'Destructure': {
|
|
19876
|
+
const kind = instr.value.lvalue.kind;
|
|
19877
|
+
for (const place of eachPatternOperand(instr.value.lvalue.pattern)) {
|
|
19878
|
+
yield [place, kind];
|
|
19879
|
+
}
|
|
19880
|
+
break;
|
|
19881
|
+
}
|
|
19882
|
+
case 'PostfixUpdate':
|
|
19883
|
+
case 'PrefixUpdate': {
|
|
19884
|
+
yield [instr.value.lvalue, InstructionKind.Reassign];
|
|
19885
|
+
break;
|
|
19886
|
+
}
|
|
19887
|
+
}
|
|
19888
|
+
}
|
|
19854
19889
|
function* eachInstructionValueLValue(value) {
|
|
19855
19890
|
switch (value.kind) {
|
|
19856
19891
|
case 'DeclareContext':
|
|
@@ -22081,12 +22116,15 @@ const BuiltInUseReducerId = 'BuiltInUseReducer';
|
|
|
22081
22116
|
const BuiltInDispatchId = 'BuiltInDispatch';
|
|
22082
22117
|
const BuiltInUseContextHookId = 'BuiltInUseContextHook';
|
|
22083
22118
|
const BuiltInUseTransitionId = 'BuiltInUseTransition';
|
|
22119
|
+
const BuiltInUseOptimisticId = 'BuiltInUseOptimistic';
|
|
22120
|
+
const BuiltInSetOptimisticId = 'BuiltInSetOptimistic';
|
|
22084
22121
|
const BuiltInStartTransitionId = 'BuiltInStartTransition';
|
|
22085
22122
|
const BuiltInFireId = 'BuiltInFire';
|
|
22086
22123
|
const BuiltInFireFunctionId = 'BuiltInFireFunction';
|
|
22087
22124
|
const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
|
|
22088
|
-
const
|
|
22125
|
+
const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
|
|
22089
22126
|
const BuiltInAutodepsId = 'BuiltInAutoDepsId';
|
|
22127
|
+
const BuiltInEventHandlerId = 'BuiltInEventHandlerId';
|
|
22090
22128
|
const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
|
|
22091
22129
|
const BUILTIN_SHAPES = new Map();
|
|
22092
22130
|
addObject(BUILTIN_SHAPES, BuiltInPropsId, [
|
|
@@ -22694,6 +22732,19 @@ addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
|
|
|
22694
22732
|
}, BuiltInStartTransitionId),
|
|
22695
22733
|
],
|
|
22696
22734
|
]);
|
|
22735
|
+
addObject(BUILTIN_SHAPES, BuiltInUseOptimisticId, [
|
|
22736
|
+
['0', { kind: 'Poly' }],
|
|
22737
|
+
[
|
|
22738
|
+
'1',
|
|
22739
|
+
addFunction(BUILTIN_SHAPES, [], {
|
|
22740
|
+
positionalParams: [],
|
|
22741
|
+
restParam: Effect.Freeze,
|
|
22742
|
+
returnType: PRIMITIVE_TYPE,
|
|
22743
|
+
calleeEffect: Effect.Read,
|
|
22744
|
+
returnValueKind: ValueKind.Primitive,
|
|
22745
|
+
}, BuiltInSetOptimisticId),
|
|
22746
|
+
],
|
|
22747
|
+
]);
|
|
22697
22748
|
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
|
|
22698
22749
|
['0', { kind: 'Poly' }],
|
|
22699
22750
|
[
|
|
@@ -22733,7 +22784,14 @@ addFunction(BUILTIN_SHAPES, [], {
|
|
|
22733
22784
|
returnType: { kind: 'Poly' },
|
|
22734
22785
|
calleeEffect: Effect.ConditionallyMutate,
|
|
22735
22786
|
returnValueKind: ValueKind.Mutable,
|
|
22736
|
-
},
|
|
22787
|
+
}, BuiltInEffectEventId);
|
|
22788
|
+
addFunction(BUILTIN_SHAPES, [], {
|
|
22789
|
+
positionalParams: [],
|
|
22790
|
+
restParam: Effect.ConditionallyMutate,
|
|
22791
|
+
returnType: { kind: 'Poly' },
|
|
22792
|
+
calleeEffect: Effect.ConditionallyMutate,
|
|
22793
|
+
returnValueKind: ValueKind.Mutable,
|
|
22794
|
+
}, BuiltInEventHandlerId);
|
|
22737
22795
|
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
|
22738
22796
|
[
|
|
22739
22797
|
'toString',
|
|
@@ -31088,6 +31146,18 @@ const REACT_APIS = [
|
|
|
31088
31146
|
returnValueKind: ValueKind.Frozen,
|
|
31089
31147
|
}),
|
|
31090
31148
|
],
|
|
31149
|
+
[
|
|
31150
|
+
'useOptimistic',
|
|
31151
|
+
addHook(DEFAULT_SHAPES, {
|
|
31152
|
+
positionalParams: [],
|
|
31153
|
+
restParam: Effect.Freeze,
|
|
31154
|
+
returnType: { kind: 'Object', shapeId: BuiltInUseOptimisticId },
|
|
31155
|
+
calleeEffect: Effect.Read,
|
|
31156
|
+
hookKind: 'useOptimistic',
|
|
31157
|
+
returnValueKind: ValueKind.Frozen,
|
|
31158
|
+
returnValueReason: ValueReason.State,
|
|
31159
|
+
}),
|
|
31160
|
+
],
|
|
31091
31161
|
[
|
|
31092
31162
|
'use',
|
|
31093
31163
|
addFunction(DEFAULT_SHAPES, [], {
|
|
@@ -31121,7 +31191,7 @@ const REACT_APIS = [
|
|
|
31121
31191
|
returnType: {
|
|
31122
31192
|
kind: 'Function',
|
|
31123
31193
|
return: { kind: 'Poly' },
|
|
31124
|
-
shapeId:
|
|
31194
|
+
shapeId: BuiltInEffectEventId,
|
|
31125
31195
|
isConstructor: false,
|
|
31126
31196
|
},
|
|
31127
31197
|
calleeEffect: Effect.Read,
|
|
@@ -32144,6 +32214,7 @@ const EnvironmentConfigSchema = v4.z.object({
|
|
|
32144
32214
|
validateNoVoidUseMemo: v4.z.boolean().default(true),
|
|
32145
32215
|
validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
|
|
32146
32216
|
enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
|
|
32217
|
+
enableInferEventHandlers: v4.z.boolean().default(false),
|
|
32147
32218
|
});
|
|
32148
32219
|
class Environment {
|
|
32149
32220
|
constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
@@ -38115,33 +38186,11 @@ function codegenInstructionNullable(cx, instr) {
|
|
|
38115
38186
|
}
|
|
38116
38187
|
else {
|
|
38117
38188
|
lvalue = instr.value.lvalue.pattern;
|
|
38118
|
-
let hasReassign = false;
|
|
38119
|
-
let hasDeclaration = false;
|
|
38120
38189
|
for (const place of eachPatternOperand(lvalue)) {
|
|
38121
38190
|
if (kind !== InstructionKind.Reassign &&
|
|
38122
38191
|
place.identifier.name === null) {
|
|
38123
38192
|
cx.temp.set(place.identifier.declarationId, null);
|
|
38124
38193
|
}
|
|
38125
|
-
const isDeclared = cx.hasDeclared(place.identifier);
|
|
38126
|
-
hasReassign || (hasReassign = isDeclared);
|
|
38127
|
-
hasDeclaration || (hasDeclaration = !isDeclared);
|
|
38128
|
-
}
|
|
38129
|
-
if (hasReassign && hasDeclaration) {
|
|
38130
|
-
CompilerError.invariant(false, {
|
|
38131
|
-
reason: 'Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)',
|
|
38132
|
-
description: null,
|
|
38133
|
-
details: [
|
|
38134
|
-
{
|
|
38135
|
-
kind: 'error',
|
|
38136
|
-
loc: instr.loc,
|
|
38137
|
-
message: null,
|
|
38138
|
-
},
|
|
38139
|
-
],
|
|
38140
|
-
suggestions: null,
|
|
38141
|
-
});
|
|
38142
|
-
}
|
|
38143
|
-
else if (hasReassign) {
|
|
38144
|
-
kind = InstructionKind.Reassign;
|
|
38145
38194
|
}
|
|
38146
38195
|
value = codegenPlaceToExpression(cx, instr.value.value);
|
|
38147
38196
|
}
|
|
@@ -39345,10 +39394,13 @@ let Visitor$9 = class Visitor extends ReactiveFunctionTransform {
|
|
|
39345
39394
|
}
|
|
39346
39395
|
transformInstruction(instruction, state) {
|
|
39347
39396
|
this.visitInstruction(instruction, state);
|
|
39397
|
+
let instructionsToProcess = [instruction];
|
|
39398
|
+
let result = { kind: 'keep' };
|
|
39348
39399
|
if (instruction.value.kind === 'Destructure') {
|
|
39349
39400
|
const transformed = transformDestructuring(state, instruction, instruction.value);
|
|
39350
39401
|
if (transformed) {
|
|
39351
|
-
|
|
39402
|
+
instructionsToProcess = transformed;
|
|
39403
|
+
result = {
|
|
39352
39404
|
kind: 'replace-many',
|
|
39353
39405
|
value: transformed.map(instruction => ({
|
|
39354
39406
|
kind: 'instruction',
|
|
@@ -39357,7 +39409,14 @@ let Visitor$9 = class Visitor extends ReactiveFunctionTransform {
|
|
|
39357
39409
|
};
|
|
39358
39410
|
}
|
|
39359
39411
|
}
|
|
39360
|
-
|
|
39412
|
+
for (const instr of instructionsToProcess) {
|
|
39413
|
+
for (const [place, kind] of eachInstructionLValueWithKind(instr)) {
|
|
39414
|
+
if (kind !== InstructionKind.Reassign) {
|
|
39415
|
+
state.declared.add(place.identifier.declarationId);
|
|
39416
|
+
}
|
|
39417
|
+
}
|
|
39418
|
+
}
|
|
39419
|
+
return result;
|
|
39361
39420
|
}
|
|
39362
39421
|
};
|
|
39363
39422
|
function transformDestructuring(state, instr, destructure) {
|
|
@@ -39368,9 +39427,12 @@ function transformDestructuring(state, instr, destructure) {
|
|
|
39368
39427
|
if (isDeclared) {
|
|
39369
39428
|
reassigned.add(place.identifier.id);
|
|
39370
39429
|
}
|
|
39371
|
-
|
|
39430
|
+
else {
|
|
39431
|
+
hasDeclaration = true;
|
|
39432
|
+
}
|
|
39372
39433
|
}
|
|
39373
|
-
if (
|
|
39434
|
+
if (!hasDeclaration) {
|
|
39435
|
+
destructure.lvalue.kind = InstructionKind.Reassign;
|
|
39374
39436
|
return null;
|
|
39375
39437
|
}
|
|
39376
39438
|
const instructions = [];
|
|
@@ -41052,6 +41114,7 @@ function applyEffect(context, state, _effect, initialized, effects) {
|
|
|
41052
41114
|
case ValueKind.Primitive: {
|
|
41053
41115
|
break;
|
|
41054
41116
|
}
|
|
41117
|
+
case ValueKind.MaybeFrozen:
|
|
41055
41118
|
case ValueKind.Frozen: {
|
|
41056
41119
|
sourceType = 'frozen';
|
|
41057
41120
|
break;
|
|
@@ -44792,6 +44855,85 @@ function findOptionalPlaces(fn) {
|
|
|
44792
44855
|
return optionals;
|
|
44793
44856
|
}
|
|
44794
44857
|
|
|
44858
|
+
function createControlDominators(fn, isControlVariable) {
|
|
44859
|
+
const postDominators = computePostDominatorTree(fn, {
|
|
44860
|
+
includeThrowsAsExitNode: false,
|
|
44861
|
+
});
|
|
44862
|
+
const postDominatorFrontierCache = new Map();
|
|
44863
|
+
function isControlledBlock(id) {
|
|
44864
|
+
let controlBlocks = postDominatorFrontierCache.get(id);
|
|
44865
|
+
if (controlBlocks === undefined) {
|
|
44866
|
+
controlBlocks = postDominatorFrontier(fn, postDominators, id);
|
|
44867
|
+
postDominatorFrontierCache.set(id, controlBlocks);
|
|
44868
|
+
}
|
|
44869
|
+
for (const blockId of controlBlocks) {
|
|
44870
|
+
const controlBlock = fn.body.blocks.get(blockId);
|
|
44871
|
+
switch (controlBlock.terminal.kind) {
|
|
44872
|
+
case 'if':
|
|
44873
|
+
case 'branch': {
|
|
44874
|
+
if (isControlVariable(controlBlock.terminal.test)) {
|
|
44875
|
+
return true;
|
|
44876
|
+
}
|
|
44877
|
+
break;
|
|
44878
|
+
}
|
|
44879
|
+
case 'switch': {
|
|
44880
|
+
if (isControlVariable(controlBlock.terminal.test)) {
|
|
44881
|
+
return true;
|
|
44882
|
+
}
|
|
44883
|
+
for (const case_ of controlBlock.terminal.cases) {
|
|
44884
|
+
if (case_.test !== null && isControlVariable(case_.test)) {
|
|
44885
|
+
return true;
|
|
44886
|
+
}
|
|
44887
|
+
}
|
|
44888
|
+
break;
|
|
44889
|
+
}
|
|
44890
|
+
}
|
|
44891
|
+
}
|
|
44892
|
+
return false;
|
|
44893
|
+
}
|
|
44894
|
+
return isControlledBlock;
|
|
44895
|
+
}
|
|
44896
|
+
function postDominatorFrontier(fn, postDominators, targetId) {
|
|
44897
|
+
const visited = new Set();
|
|
44898
|
+
const frontier = new Set();
|
|
44899
|
+
const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
|
|
44900
|
+
for (const blockId of [...targetPostDominators, targetId]) {
|
|
44901
|
+
if (visited.has(blockId)) {
|
|
44902
|
+
continue;
|
|
44903
|
+
}
|
|
44904
|
+
visited.add(blockId);
|
|
44905
|
+
const block = fn.body.blocks.get(blockId);
|
|
44906
|
+
for (const pred of block.preds) {
|
|
44907
|
+
if (!targetPostDominators.has(pred)) {
|
|
44908
|
+
frontier.add(pred);
|
|
44909
|
+
}
|
|
44910
|
+
}
|
|
44911
|
+
}
|
|
44912
|
+
return frontier;
|
|
44913
|
+
}
|
|
44914
|
+
function postDominatorsOf(fn, postDominators, targetId) {
|
|
44915
|
+
var _a;
|
|
44916
|
+
const result = new Set();
|
|
44917
|
+
const visited = new Set();
|
|
44918
|
+
const queue = [targetId];
|
|
44919
|
+
while (queue.length) {
|
|
44920
|
+
const currentId = queue.shift();
|
|
44921
|
+
if (visited.has(currentId)) {
|
|
44922
|
+
continue;
|
|
44923
|
+
}
|
|
44924
|
+
visited.add(currentId);
|
|
44925
|
+
const current = fn.body.blocks.get(currentId);
|
|
44926
|
+
for (const pred of current.preds) {
|
|
44927
|
+
const predPostDominator = (_a = postDominators.get(pred)) !== null && _a !== void 0 ? _a : pred;
|
|
44928
|
+
if (predPostDominator === targetId || result.has(predPostDominator)) {
|
|
44929
|
+
result.add(pred);
|
|
44930
|
+
}
|
|
44931
|
+
queue.push(pred);
|
|
44932
|
+
}
|
|
44933
|
+
}
|
|
44934
|
+
return result;
|
|
44935
|
+
}
|
|
44936
|
+
|
|
44795
44937
|
class StableSidemap {
|
|
44796
44938
|
constructor(env) {
|
|
44797
44939
|
this.map = new Map();
|
|
@@ -44867,42 +45009,7 @@ function inferReactivePlaces(fn) {
|
|
|
44867
45009
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
44868
45010
|
reactiveIdentifiers.markReactive(place);
|
|
44869
45011
|
}
|
|
44870
|
-
const
|
|
44871
|
-
includeThrowsAsExitNode: false,
|
|
44872
|
-
});
|
|
44873
|
-
const postDominatorFrontierCache = new Map();
|
|
44874
|
-
function isReactiveControlledBlock(id) {
|
|
44875
|
-
let controlBlocks = postDominatorFrontierCache.get(id);
|
|
44876
|
-
if (controlBlocks === undefined) {
|
|
44877
|
-
controlBlocks = postDominatorFrontier(fn, postDominators, id);
|
|
44878
|
-
postDominatorFrontierCache.set(id, controlBlocks);
|
|
44879
|
-
}
|
|
44880
|
-
for (const blockId of controlBlocks) {
|
|
44881
|
-
const controlBlock = fn.body.blocks.get(blockId);
|
|
44882
|
-
switch (controlBlock.terminal.kind) {
|
|
44883
|
-
case 'if':
|
|
44884
|
-
case 'branch': {
|
|
44885
|
-
if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
44886
|
-
return true;
|
|
44887
|
-
}
|
|
44888
|
-
break;
|
|
44889
|
-
}
|
|
44890
|
-
case 'switch': {
|
|
44891
|
-
if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
44892
|
-
return true;
|
|
44893
|
-
}
|
|
44894
|
-
for (const case_ of controlBlock.terminal.cases) {
|
|
44895
|
-
if (case_.test !== null &&
|
|
44896
|
-
reactiveIdentifiers.isReactive(case_.test)) {
|
|
44897
|
-
return true;
|
|
44898
|
-
}
|
|
44899
|
-
}
|
|
44900
|
-
break;
|
|
44901
|
-
}
|
|
44902
|
-
}
|
|
44903
|
-
}
|
|
44904
|
-
return false;
|
|
44905
|
-
}
|
|
45012
|
+
const isReactiveControlledBlock = createControlDominators(fn, place => reactiveIdentifiers.isReactive(place));
|
|
44906
45013
|
do {
|
|
44907
45014
|
for (const [, block] of fn.body.blocks) {
|
|
44908
45015
|
let hasReactiveControl = isReactiveControlledBlock(block.id);
|
|
@@ -45020,46 +45127,6 @@ function inferReactivePlaces(fn) {
|
|
|
45020
45127
|
}
|
|
45021
45128
|
propagateReactivityToInnerFunctions(fn, true);
|
|
45022
45129
|
}
|
|
45023
|
-
function postDominatorFrontier(fn, postDominators, targetId) {
|
|
45024
|
-
const visited = new Set();
|
|
45025
|
-
const frontier = new Set();
|
|
45026
|
-
const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
|
|
45027
|
-
for (const blockId of [...targetPostDominators, targetId]) {
|
|
45028
|
-
if (visited.has(blockId)) {
|
|
45029
|
-
continue;
|
|
45030
|
-
}
|
|
45031
|
-
visited.add(blockId);
|
|
45032
|
-
const block = fn.body.blocks.get(blockId);
|
|
45033
|
-
for (const pred of block.preds) {
|
|
45034
|
-
if (!targetPostDominators.has(pred)) {
|
|
45035
|
-
frontier.add(pred);
|
|
45036
|
-
}
|
|
45037
|
-
}
|
|
45038
|
-
}
|
|
45039
|
-
return frontier;
|
|
45040
|
-
}
|
|
45041
|
-
function postDominatorsOf(fn, postDominators, targetId) {
|
|
45042
|
-
var _a;
|
|
45043
|
-
const result = new Set();
|
|
45044
|
-
const visited = new Set();
|
|
45045
|
-
const queue = [targetId];
|
|
45046
|
-
while (queue.length) {
|
|
45047
|
-
const currentId = queue.shift();
|
|
45048
|
-
if (visited.has(currentId)) {
|
|
45049
|
-
continue;
|
|
45050
|
-
}
|
|
45051
|
-
visited.add(currentId);
|
|
45052
|
-
const current = fn.body.blocks.get(currentId);
|
|
45053
|
-
for (const pred of current.preds) {
|
|
45054
|
-
const predPostDominator = (_a = postDominators.get(pred)) !== null && _a !== void 0 ? _a : pred;
|
|
45055
|
-
if (predPostDominator === targetId || result.has(predPostDominator)) {
|
|
45056
|
-
result.add(pred);
|
|
45057
|
-
}
|
|
45058
|
-
queue.push(pred);
|
|
45059
|
-
}
|
|
45060
|
-
}
|
|
45061
|
-
return result;
|
|
45062
|
-
}
|
|
45063
45130
|
class ReactivityMap {
|
|
45064
45131
|
constructor(aliasedIdentifiers) {
|
|
45065
45132
|
this.hasChanges = false;
|
|
@@ -48306,6 +48373,25 @@ function* generateInstructionTypes(env, names, instr) {
|
|
|
48306
48373
|
}
|
|
48307
48374
|
}
|
|
48308
48375
|
}
|
|
48376
|
+
if (env.config.enableInferEventHandlers) {
|
|
48377
|
+
if (value.kind === 'JsxExpression' &&
|
|
48378
|
+
value.tag.kind === 'BuiltinTag' &&
|
|
48379
|
+
!value.tag.name.includes('-')) {
|
|
48380
|
+
for (const prop of value.props) {
|
|
48381
|
+
if (prop.kind === 'JsxAttribute' &&
|
|
48382
|
+
prop.name.startsWith('on') &&
|
|
48383
|
+
prop.name.length > 2 &&
|
|
48384
|
+
prop.name[2] === prop.name[2].toUpperCase()) {
|
|
48385
|
+
yield equation(prop.place.identifier.type, {
|
|
48386
|
+
kind: 'Function',
|
|
48387
|
+
shapeId: BuiltInEventHandlerId,
|
|
48388
|
+
return: makeType(),
|
|
48389
|
+
isConstructor: false,
|
|
48390
|
+
});
|
|
48391
|
+
}
|
|
48392
|
+
}
|
|
48393
|
+
}
|
|
48394
|
+
}
|
|
48309
48395
|
yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
|
|
48310
48396
|
break;
|
|
48311
48397
|
}
|
|
@@ -49229,6 +49315,10 @@ function refTypeOfType(place) {
|
|
|
49229
49315
|
return { kind: 'None' };
|
|
49230
49316
|
}
|
|
49231
49317
|
}
|
|
49318
|
+
function isEventHandlerType(identifier) {
|
|
49319
|
+
const type = identifier.type;
|
|
49320
|
+
return type.kind === 'Function' && type.shapeId === BuiltInEventHandlerId;
|
|
49321
|
+
}
|
|
49232
49322
|
function tyEqual(a, b) {
|
|
49233
49323
|
if (a.kind !== b.kind) {
|
|
49234
49324
|
return false;
|
|
@@ -49515,8 +49605,10 @@ function validateNoRefAccessInRenderImpl(fn, env) {
|
|
|
49515
49605
|
}
|
|
49516
49606
|
if (!didError) {
|
|
49517
49607
|
const isRefLValue = isUseRefType(instr.lvalue.identifier);
|
|
49608
|
+
const isEventHandlerLValue = isEventHandlerType(instr.lvalue.identifier);
|
|
49518
49609
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
49519
49610
|
if (isRefLValue ||
|
|
49611
|
+
isEventHandlerLValue ||
|
|
49520
49612
|
(hookKind != null &&
|
|
49521
49613
|
hookKind !== 'useState' &&
|
|
49522
49614
|
hookKind !== 'useReducer')) {
|
|
@@ -51015,20 +51107,84 @@ function validateNoSetStateInEffects(fn, env) {
|
|
|
51015
51107
|
return errors.asResult();
|
|
51016
51108
|
}
|
|
51017
51109
|
function getSetStateCall(fn, setStateFunctions, env) {
|
|
51110
|
+
const enableAllowSetStateFromRefsInEffects = env.config.enableAllowSetStateFromRefsInEffects;
|
|
51018
51111
|
const refDerivedValues = new Set();
|
|
51019
51112
|
const isDerivedFromRef = (place) => {
|
|
51020
51113
|
return (refDerivedValues.has(place.identifier.id) ||
|
|
51021
51114
|
isUseRefType(place.identifier) ||
|
|
51022
51115
|
isRefValueType(place.identifier));
|
|
51023
51116
|
};
|
|
51117
|
+
const isRefControlledBlock = enableAllowSetStateFromRefsInEffects
|
|
51118
|
+
? createControlDominators(fn, place => isDerivedFromRef(place))
|
|
51119
|
+
: () => false;
|
|
51024
51120
|
for (const [, block] of fn.body.blocks) {
|
|
51121
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
51122
|
+
for (const phi of block.phis) {
|
|
51123
|
+
if (isDerivedFromRef(phi.place)) {
|
|
51124
|
+
continue;
|
|
51125
|
+
}
|
|
51126
|
+
let isPhiDerivedFromRef = false;
|
|
51127
|
+
for (const [, operand] of phi.operands) {
|
|
51128
|
+
if (isDerivedFromRef(operand)) {
|
|
51129
|
+
isPhiDerivedFromRef = true;
|
|
51130
|
+
break;
|
|
51131
|
+
}
|
|
51132
|
+
}
|
|
51133
|
+
if (isPhiDerivedFromRef) {
|
|
51134
|
+
refDerivedValues.add(phi.place.identifier.id);
|
|
51135
|
+
}
|
|
51136
|
+
else {
|
|
51137
|
+
for (const [pred] of phi.operands) {
|
|
51138
|
+
if (isRefControlledBlock(pred)) {
|
|
51139
|
+
refDerivedValues.add(phi.place.identifier.id);
|
|
51140
|
+
break;
|
|
51141
|
+
}
|
|
51142
|
+
}
|
|
51143
|
+
}
|
|
51144
|
+
}
|
|
51145
|
+
}
|
|
51025
51146
|
for (const instr of block.instructions) {
|
|
51026
|
-
if (
|
|
51147
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
51027
51148
|
const hasRefOperand = Iterable_some(eachInstructionValueOperand(instr.value), isDerivedFromRef);
|
|
51028
51149
|
if (hasRefOperand) {
|
|
51029
51150
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
51030
51151
|
refDerivedValues.add(lvalue.identifier.id);
|
|
51031
51152
|
}
|
|
51153
|
+
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
51154
|
+
switch (operand.effect) {
|
|
51155
|
+
case Effect.Capture:
|
|
51156
|
+
case Effect.Store:
|
|
51157
|
+
case Effect.ConditionallyMutate:
|
|
51158
|
+
case Effect.ConditionallyMutateIterator:
|
|
51159
|
+
case Effect.Mutate: {
|
|
51160
|
+
if (isMutable(instr, operand)) {
|
|
51161
|
+
refDerivedValues.add(operand.identifier.id);
|
|
51162
|
+
}
|
|
51163
|
+
break;
|
|
51164
|
+
}
|
|
51165
|
+
case Effect.Freeze:
|
|
51166
|
+
case Effect.Read: {
|
|
51167
|
+
break;
|
|
51168
|
+
}
|
|
51169
|
+
case Effect.Unknown: {
|
|
51170
|
+
CompilerError.invariant(false, {
|
|
51171
|
+
reason: 'Unexpected unknown effect',
|
|
51172
|
+
description: null,
|
|
51173
|
+
details: [
|
|
51174
|
+
{
|
|
51175
|
+
kind: 'error',
|
|
51176
|
+
loc: operand.loc,
|
|
51177
|
+
message: null,
|
|
51178
|
+
},
|
|
51179
|
+
],
|
|
51180
|
+
suggestions: null,
|
|
51181
|
+
});
|
|
51182
|
+
}
|
|
51183
|
+
default: {
|
|
51184
|
+
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
51185
|
+
}
|
|
51186
|
+
}
|
|
51187
|
+
}
|
|
51032
51188
|
}
|
|
51033
51189
|
if (instr.value.kind === 'PropertyLoad' &&
|
|
51034
51190
|
instr.value.property === 'current' &&
|
|
@@ -51055,13 +51211,16 @@ function getSetStateCall(fn, setStateFunctions, env) {
|
|
|
51055
51211
|
const callee = instr.value.callee;
|
|
51056
51212
|
if (isSetStateType(callee.identifier) ||
|
|
51057
51213
|
setStateFunctions.has(callee.identifier.id)) {
|
|
51058
|
-
if (
|
|
51214
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
51059
51215
|
const arg = instr.value.args.at(0);
|
|
51060
51216
|
if (arg !== undefined &&
|
|
51061
51217
|
arg.kind === 'Identifier' &&
|
|
51062
51218
|
refDerivedValues.has(arg.identifier.id)) {
|
|
51063
51219
|
return null;
|
|
51064
51220
|
}
|
|
51221
|
+
else if (isRefControlledBlock(block.id)) {
|
|
51222
|
+
continue;
|
|
51223
|
+
}
|
|
51065
51224
|
}
|
|
51066
51225
|
return callee;
|
|
51067
51226
|
}
|
|
@@ -18948,9 +18948,18 @@ function isRefOrRefLikeMutableType(type) {
|
|
|
18948
18948
|
function isSetStateType(id) {
|
|
18949
18949
|
return id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetState';
|
|
18950
18950
|
}
|
|
18951
|
+
function isUseActionStateType(id) {
|
|
18952
|
+
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseActionState');
|
|
18953
|
+
}
|
|
18951
18954
|
function isStartTransitionType(id) {
|
|
18952
18955
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInStartTransition');
|
|
18953
18956
|
}
|
|
18957
|
+
function isUseOptimisticType(id) {
|
|
18958
|
+
return (id.type.kind === 'Object' && id.type.shapeId === 'BuiltInUseOptimistic');
|
|
18959
|
+
}
|
|
18960
|
+
function isSetOptimisticType(id) {
|
|
18961
|
+
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetOptimistic');
|
|
18962
|
+
}
|
|
18954
18963
|
function isSetActionStateType(id) {
|
|
18955
18964
|
return (id.type.kind === 'Function' && id.type.shapeId === 'BuiltInSetActionState');
|
|
18956
18965
|
}
|
|
@@ -18972,7 +18981,8 @@ function isStableType(id) {
|
|
|
18972
18981
|
isSetActionStateType(id) ||
|
|
18973
18982
|
isDispatcherType(id) ||
|
|
18974
18983
|
isUseRefType(id) ||
|
|
18975
|
-
isStartTransitionType(id)
|
|
18984
|
+
isStartTransitionType(id) ||
|
|
18985
|
+
isSetOptimisticType(id));
|
|
18976
18986
|
}
|
|
18977
18987
|
function isStableTypeContainer(id) {
|
|
18978
18988
|
const type_ = id.type;
|
|
@@ -18980,8 +18990,9 @@ function isStableTypeContainer(id) {
|
|
|
18980
18990
|
return false;
|
|
18981
18991
|
}
|
|
18982
18992
|
return (isUseStateType(id) ||
|
|
18983
|
-
|
|
18993
|
+
isUseActionStateType(id) ||
|
|
18984
18994
|
isUseReducerType(id) ||
|
|
18995
|
+
isUseOptimisticType(id) ||
|
|
18985
18996
|
type_.shapeId === 'BuiltInUseTransition');
|
|
18986
18997
|
}
|
|
18987
18998
|
function evaluatesToStableTypeOrContainer(env, { value }) {
|
|
@@ -18994,6 +19005,7 @@ function evaluatesToStableTypeOrContainer(env, { value }) {
|
|
|
18994
19005
|
case 'useActionState':
|
|
18995
19006
|
case 'useRef':
|
|
18996
19007
|
case 'useTransition':
|
|
19008
|
+
case 'useOptimistic':
|
|
18997
19009
|
return true;
|
|
18998
19010
|
}
|
|
18999
19011
|
}
|
|
@@ -19842,6 +19854,29 @@ function* eachInstructionLValue(instr) {
|
|
|
19842
19854
|
}
|
|
19843
19855
|
yield* eachInstructionValueLValue(instr.value);
|
|
19844
19856
|
}
|
|
19857
|
+
function* eachInstructionLValueWithKind(instr) {
|
|
19858
|
+
switch (instr.value.kind) {
|
|
19859
|
+
case 'DeclareContext':
|
|
19860
|
+
case 'StoreContext':
|
|
19861
|
+
case 'DeclareLocal':
|
|
19862
|
+
case 'StoreLocal': {
|
|
19863
|
+
yield [instr.value.lvalue.place, instr.value.lvalue.kind];
|
|
19864
|
+
break;
|
|
19865
|
+
}
|
|
19866
|
+
case 'Destructure': {
|
|
19867
|
+
const kind = instr.value.lvalue.kind;
|
|
19868
|
+
for (const place of eachPatternOperand(instr.value.lvalue.pattern)) {
|
|
19869
|
+
yield [place, kind];
|
|
19870
|
+
}
|
|
19871
|
+
break;
|
|
19872
|
+
}
|
|
19873
|
+
case 'PostfixUpdate':
|
|
19874
|
+
case 'PrefixUpdate': {
|
|
19875
|
+
yield [instr.value.lvalue, InstructionKind.Reassign];
|
|
19876
|
+
break;
|
|
19877
|
+
}
|
|
19878
|
+
}
|
|
19879
|
+
}
|
|
19845
19880
|
function* eachInstructionValueLValue(value) {
|
|
19846
19881
|
switch (value.kind) {
|
|
19847
19882
|
case 'DeclareContext':
|
|
@@ -22072,12 +22107,15 @@ const BuiltInUseReducerId = 'BuiltInUseReducer';
|
|
|
22072
22107
|
const BuiltInDispatchId = 'BuiltInDispatch';
|
|
22073
22108
|
const BuiltInUseContextHookId = 'BuiltInUseContextHook';
|
|
22074
22109
|
const BuiltInUseTransitionId = 'BuiltInUseTransition';
|
|
22110
|
+
const BuiltInUseOptimisticId = 'BuiltInUseOptimistic';
|
|
22111
|
+
const BuiltInSetOptimisticId = 'BuiltInSetOptimistic';
|
|
22075
22112
|
const BuiltInStartTransitionId = 'BuiltInStartTransition';
|
|
22076
22113
|
const BuiltInFireId = 'BuiltInFire';
|
|
22077
22114
|
const BuiltInFireFunctionId = 'BuiltInFireFunction';
|
|
22078
22115
|
const BuiltInUseEffectEventId = 'BuiltInUseEffectEvent';
|
|
22079
|
-
const
|
|
22116
|
+
const BuiltInEffectEventId = 'BuiltInEffectEventFunction';
|
|
22080
22117
|
const BuiltInAutodepsId = 'BuiltInAutoDepsId';
|
|
22118
|
+
const BuiltInEventHandlerId = 'BuiltInEventHandlerId';
|
|
22081
22119
|
const ReanimatedSharedValueId = 'ReanimatedSharedValueId';
|
|
22082
22120
|
const BUILTIN_SHAPES = new Map();
|
|
22083
22121
|
addObject(BUILTIN_SHAPES, BuiltInPropsId, [
|
|
@@ -22685,6 +22723,19 @@ addObject(BUILTIN_SHAPES, BuiltInUseTransitionId, [
|
|
|
22685
22723
|
}, BuiltInStartTransitionId),
|
|
22686
22724
|
],
|
|
22687
22725
|
]);
|
|
22726
|
+
addObject(BUILTIN_SHAPES, BuiltInUseOptimisticId, [
|
|
22727
|
+
['0', { kind: 'Poly' }],
|
|
22728
|
+
[
|
|
22729
|
+
'1',
|
|
22730
|
+
addFunction(BUILTIN_SHAPES, [], {
|
|
22731
|
+
positionalParams: [],
|
|
22732
|
+
restParam: Effect.Freeze,
|
|
22733
|
+
returnType: PRIMITIVE_TYPE,
|
|
22734
|
+
calleeEffect: Effect.Read,
|
|
22735
|
+
returnValueKind: ValueKind.Primitive,
|
|
22736
|
+
}, BuiltInSetOptimisticId),
|
|
22737
|
+
],
|
|
22738
|
+
]);
|
|
22688
22739
|
addObject(BUILTIN_SHAPES, BuiltInUseActionStateId, [
|
|
22689
22740
|
['0', { kind: 'Poly' }],
|
|
22690
22741
|
[
|
|
@@ -22724,7 +22775,14 @@ addFunction(BUILTIN_SHAPES, [], {
|
|
|
22724
22775
|
returnType: { kind: 'Poly' },
|
|
22725
22776
|
calleeEffect: Effect.ConditionallyMutate,
|
|
22726
22777
|
returnValueKind: ValueKind.Mutable,
|
|
22727
|
-
},
|
|
22778
|
+
}, BuiltInEffectEventId);
|
|
22779
|
+
addFunction(BUILTIN_SHAPES, [], {
|
|
22780
|
+
positionalParams: [],
|
|
22781
|
+
restParam: Effect.ConditionallyMutate,
|
|
22782
|
+
returnType: { kind: 'Poly' },
|
|
22783
|
+
calleeEffect: Effect.ConditionallyMutate,
|
|
22784
|
+
returnValueKind: ValueKind.Mutable,
|
|
22785
|
+
}, BuiltInEventHandlerId);
|
|
22728
22786
|
addObject(BUILTIN_SHAPES, BuiltInMixedReadonlyId, [
|
|
22729
22787
|
[
|
|
22730
22788
|
'toString',
|
|
@@ -30915,6 +30973,18 @@ const REACT_APIS = [
|
|
|
30915
30973
|
returnValueKind: ValueKind.Frozen,
|
|
30916
30974
|
}),
|
|
30917
30975
|
],
|
|
30976
|
+
[
|
|
30977
|
+
'useOptimistic',
|
|
30978
|
+
addHook(DEFAULT_SHAPES, {
|
|
30979
|
+
positionalParams: [],
|
|
30980
|
+
restParam: Effect.Freeze,
|
|
30981
|
+
returnType: { kind: 'Object', shapeId: BuiltInUseOptimisticId },
|
|
30982
|
+
calleeEffect: Effect.Read,
|
|
30983
|
+
hookKind: 'useOptimistic',
|
|
30984
|
+
returnValueKind: ValueKind.Frozen,
|
|
30985
|
+
returnValueReason: ValueReason.State,
|
|
30986
|
+
}),
|
|
30987
|
+
],
|
|
30918
30988
|
[
|
|
30919
30989
|
'use',
|
|
30920
30990
|
addFunction(DEFAULT_SHAPES, [], {
|
|
@@ -30948,7 +31018,7 @@ const REACT_APIS = [
|
|
|
30948
31018
|
returnType: {
|
|
30949
31019
|
kind: 'Function',
|
|
30950
31020
|
return: { kind: 'Poly' },
|
|
30951
|
-
shapeId:
|
|
31021
|
+
shapeId: BuiltInEffectEventId,
|
|
30952
31022
|
isConstructor: false,
|
|
30953
31023
|
},
|
|
30954
31024
|
calleeEffect: Effect.Read,
|
|
@@ -31971,6 +32041,7 @@ const EnvironmentConfigSchema = v4.z.object({
|
|
|
31971
32041
|
validateNoVoidUseMemo: v4.z.boolean().default(true),
|
|
31972
32042
|
validateNoDynamicallyCreatedComponentsOrHooks: v4.z.boolean().default(false),
|
|
31973
32043
|
enableAllowSetStateFromRefsInEffects: v4.z.boolean().default(true),
|
|
32044
|
+
enableInferEventHandlers: v4.z.boolean().default(false),
|
|
31974
32045
|
});
|
|
31975
32046
|
class Environment {
|
|
31976
32047
|
constructor(scope, fnType, compilerMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
@@ -37942,33 +38013,11 @@ function codegenInstructionNullable(cx, instr) {
|
|
|
37942
38013
|
}
|
|
37943
38014
|
else {
|
|
37944
38015
|
lvalue = instr.value.lvalue.pattern;
|
|
37945
|
-
let hasReassign = false;
|
|
37946
|
-
let hasDeclaration = false;
|
|
37947
38016
|
for (const place of eachPatternOperand(lvalue)) {
|
|
37948
38017
|
if (kind !== InstructionKind.Reassign &&
|
|
37949
38018
|
place.identifier.name === null) {
|
|
37950
38019
|
cx.temp.set(place.identifier.declarationId, null);
|
|
37951
38020
|
}
|
|
37952
|
-
const isDeclared = cx.hasDeclared(place.identifier);
|
|
37953
|
-
hasReassign || (hasReassign = isDeclared);
|
|
37954
|
-
hasDeclaration || (hasDeclaration = !isDeclared);
|
|
37955
|
-
}
|
|
37956
|
-
if (hasReassign && hasDeclaration) {
|
|
37957
|
-
CompilerError.invariant(false, {
|
|
37958
|
-
reason: 'Encountered a destructuring operation where some identifiers are already declared (reassignments) but others are not (declarations)',
|
|
37959
|
-
description: null,
|
|
37960
|
-
details: [
|
|
37961
|
-
{
|
|
37962
|
-
kind: 'error',
|
|
37963
|
-
loc: instr.loc,
|
|
37964
|
-
message: null,
|
|
37965
|
-
},
|
|
37966
|
-
],
|
|
37967
|
-
suggestions: null,
|
|
37968
|
-
});
|
|
37969
|
-
}
|
|
37970
|
-
else if (hasReassign) {
|
|
37971
|
-
kind = InstructionKind.Reassign;
|
|
37972
38021
|
}
|
|
37973
38022
|
value = codegenPlaceToExpression(cx, instr.value.value);
|
|
37974
38023
|
}
|
|
@@ -39172,10 +39221,13 @@ let Visitor$9 = class Visitor extends ReactiveFunctionTransform {
|
|
|
39172
39221
|
}
|
|
39173
39222
|
transformInstruction(instruction, state) {
|
|
39174
39223
|
this.visitInstruction(instruction, state);
|
|
39224
|
+
let instructionsToProcess = [instruction];
|
|
39225
|
+
let result = { kind: 'keep' };
|
|
39175
39226
|
if (instruction.value.kind === 'Destructure') {
|
|
39176
39227
|
const transformed = transformDestructuring(state, instruction, instruction.value);
|
|
39177
39228
|
if (transformed) {
|
|
39178
|
-
|
|
39229
|
+
instructionsToProcess = transformed;
|
|
39230
|
+
result = {
|
|
39179
39231
|
kind: 'replace-many',
|
|
39180
39232
|
value: transformed.map(instruction => ({
|
|
39181
39233
|
kind: 'instruction',
|
|
@@ -39184,7 +39236,14 @@ let Visitor$9 = class Visitor extends ReactiveFunctionTransform {
|
|
|
39184
39236
|
};
|
|
39185
39237
|
}
|
|
39186
39238
|
}
|
|
39187
|
-
|
|
39239
|
+
for (const instr of instructionsToProcess) {
|
|
39240
|
+
for (const [place, kind] of eachInstructionLValueWithKind(instr)) {
|
|
39241
|
+
if (kind !== InstructionKind.Reassign) {
|
|
39242
|
+
state.declared.add(place.identifier.declarationId);
|
|
39243
|
+
}
|
|
39244
|
+
}
|
|
39245
|
+
}
|
|
39246
|
+
return result;
|
|
39188
39247
|
}
|
|
39189
39248
|
};
|
|
39190
39249
|
function transformDestructuring(state, instr, destructure) {
|
|
@@ -39195,9 +39254,12 @@ function transformDestructuring(state, instr, destructure) {
|
|
|
39195
39254
|
if (isDeclared) {
|
|
39196
39255
|
reassigned.add(place.identifier.id);
|
|
39197
39256
|
}
|
|
39198
|
-
|
|
39257
|
+
else {
|
|
39258
|
+
hasDeclaration = true;
|
|
39259
|
+
}
|
|
39199
39260
|
}
|
|
39200
|
-
if (
|
|
39261
|
+
if (!hasDeclaration) {
|
|
39262
|
+
destructure.lvalue.kind = InstructionKind.Reassign;
|
|
39201
39263
|
return null;
|
|
39202
39264
|
}
|
|
39203
39265
|
const instructions = [];
|
|
@@ -40879,6 +40941,7 @@ function applyEffect(context, state, _effect, initialized, effects) {
|
|
|
40879
40941
|
case ValueKind.Primitive: {
|
|
40880
40942
|
break;
|
|
40881
40943
|
}
|
|
40944
|
+
case ValueKind.MaybeFrozen:
|
|
40882
40945
|
case ValueKind.Frozen: {
|
|
40883
40946
|
sourceType = 'frozen';
|
|
40884
40947
|
break;
|
|
@@ -44619,6 +44682,85 @@ function findOptionalPlaces(fn) {
|
|
|
44619
44682
|
return optionals;
|
|
44620
44683
|
}
|
|
44621
44684
|
|
|
44685
|
+
function createControlDominators(fn, isControlVariable) {
|
|
44686
|
+
const postDominators = computePostDominatorTree(fn, {
|
|
44687
|
+
includeThrowsAsExitNode: false,
|
|
44688
|
+
});
|
|
44689
|
+
const postDominatorFrontierCache = new Map();
|
|
44690
|
+
function isControlledBlock(id) {
|
|
44691
|
+
let controlBlocks = postDominatorFrontierCache.get(id);
|
|
44692
|
+
if (controlBlocks === undefined) {
|
|
44693
|
+
controlBlocks = postDominatorFrontier(fn, postDominators, id);
|
|
44694
|
+
postDominatorFrontierCache.set(id, controlBlocks);
|
|
44695
|
+
}
|
|
44696
|
+
for (const blockId of controlBlocks) {
|
|
44697
|
+
const controlBlock = fn.body.blocks.get(blockId);
|
|
44698
|
+
switch (controlBlock.terminal.kind) {
|
|
44699
|
+
case 'if':
|
|
44700
|
+
case 'branch': {
|
|
44701
|
+
if (isControlVariable(controlBlock.terminal.test)) {
|
|
44702
|
+
return true;
|
|
44703
|
+
}
|
|
44704
|
+
break;
|
|
44705
|
+
}
|
|
44706
|
+
case 'switch': {
|
|
44707
|
+
if (isControlVariable(controlBlock.terminal.test)) {
|
|
44708
|
+
return true;
|
|
44709
|
+
}
|
|
44710
|
+
for (const case_ of controlBlock.terminal.cases) {
|
|
44711
|
+
if (case_.test !== null && isControlVariable(case_.test)) {
|
|
44712
|
+
return true;
|
|
44713
|
+
}
|
|
44714
|
+
}
|
|
44715
|
+
break;
|
|
44716
|
+
}
|
|
44717
|
+
}
|
|
44718
|
+
}
|
|
44719
|
+
return false;
|
|
44720
|
+
}
|
|
44721
|
+
return isControlledBlock;
|
|
44722
|
+
}
|
|
44723
|
+
function postDominatorFrontier(fn, postDominators, targetId) {
|
|
44724
|
+
const visited = new Set();
|
|
44725
|
+
const frontier = new Set();
|
|
44726
|
+
const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
|
|
44727
|
+
for (const blockId of [...targetPostDominators, targetId]) {
|
|
44728
|
+
if (visited.has(blockId)) {
|
|
44729
|
+
continue;
|
|
44730
|
+
}
|
|
44731
|
+
visited.add(blockId);
|
|
44732
|
+
const block = fn.body.blocks.get(blockId);
|
|
44733
|
+
for (const pred of block.preds) {
|
|
44734
|
+
if (!targetPostDominators.has(pred)) {
|
|
44735
|
+
frontier.add(pred);
|
|
44736
|
+
}
|
|
44737
|
+
}
|
|
44738
|
+
}
|
|
44739
|
+
return frontier;
|
|
44740
|
+
}
|
|
44741
|
+
function postDominatorsOf(fn, postDominators, targetId) {
|
|
44742
|
+
var _a;
|
|
44743
|
+
const result = new Set();
|
|
44744
|
+
const visited = new Set();
|
|
44745
|
+
const queue = [targetId];
|
|
44746
|
+
while (queue.length) {
|
|
44747
|
+
const currentId = queue.shift();
|
|
44748
|
+
if (visited.has(currentId)) {
|
|
44749
|
+
continue;
|
|
44750
|
+
}
|
|
44751
|
+
visited.add(currentId);
|
|
44752
|
+
const current = fn.body.blocks.get(currentId);
|
|
44753
|
+
for (const pred of current.preds) {
|
|
44754
|
+
const predPostDominator = (_a = postDominators.get(pred)) !== null && _a !== void 0 ? _a : pred;
|
|
44755
|
+
if (predPostDominator === targetId || result.has(predPostDominator)) {
|
|
44756
|
+
result.add(pred);
|
|
44757
|
+
}
|
|
44758
|
+
queue.push(pred);
|
|
44759
|
+
}
|
|
44760
|
+
}
|
|
44761
|
+
return result;
|
|
44762
|
+
}
|
|
44763
|
+
|
|
44622
44764
|
class StableSidemap {
|
|
44623
44765
|
constructor(env) {
|
|
44624
44766
|
this.map = new Map();
|
|
@@ -44694,42 +44836,7 @@ function inferReactivePlaces(fn) {
|
|
|
44694
44836
|
const place = param.kind === 'Identifier' ? param : param.place;
|
|
44695
44837
|
reactiveIdentifiers.markReactive(place);
|
|
44696
44838
|
}
|
|
44697
|
-
const
|
|
44698
|
-
includeThrowsAsExitNode: false,
|
|
44699
|
-
});
|
|
44700
|
-
const postDominatorFrontierCache = new Map();
|
|
44701
|
-
function isReactiveControlledBlock(id) {
|
|
44702
|
-
let controlBlocks = postDominatorFrontierCache.get(id);
|
|
44703
|
-
if (controlBlocks === undefined) {
|
|
44704
|
-
controlBlocks = postDominatorFrontier(fn, postDominators, id);
|
|
44705
|
-
postDominatorFrontierCache.set(id, controlBlocks);
|
|
44706
|
-
}
|
|
44707
|
-
for (const blockId of controlBlocks) {
|
|
44708
|
-
const controlBlock = fn.body.blocks.get(blockId);
|
|
44709
|
-
switch (controlBlock.terminal.kind) {
|
|
44710
|
-
case 'if':
|
|
44711
|
-
case 'branch': {
|
|
44712
|
-
if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
44713
|
-
return true;
|
|
44714
|
-
}
|
|
44715
|
-
break;
|
|
44716
|
-
}
|
|
44717
|
-
case 'switch': {
|
|
44718
|
-
if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
|
|
44719
|
-
return true;
|
|
44720
|
-
}
|
|
44721
|
-
for (const case_ of controlBlock.terminal.cases) {
|
|
44722
|
-
if (case_.test !== null &&
|
|
44723
|
-
reactiveIdentifiers.isReactive(case_.test)) {
|
|
44724
|
-
return true;
|
|
44725
|
-
}
|
|
44726
|
-
}
|
|
44727
|
-
break;
|
|
44728
|
-
}
|
|
44729
|
-
}
|
|
44730
|
-
}
|
|
44731
|
-
return false;
|
|
44732
|
-
}
|
|
44839
|
+
const isReactiveControlledBlock = createControlDominators(fn, place => reactiveIdentifiers.isReactive(place));
|
|
44733
44840
|
do {
|
|
44734
44841
|
for (const [, block] of fn.body.blocks) {
|
|
44735
44842
|
let hasReactiveControl = isReactiveControlledBlock(block.id);
|
|
@@ -44847,46 +44954,6 @@ function inferReactivePlaces(fn) {
|
|
|
44847
44954
|
}
|
|
44848
44955
|
propagateReactivityToInnerFunctions(fn, true);
|
|
44849
44956
|
}
|
|
44850
|
-
function postDominatorFrontier(fn, postDominators, targetId) {
|
|
44851
|
-
const visited = new Set();
|
|
44852
|
-
const frontier = new Set();
|
|
44853
|
-
const targetPostDominators = postDominatorsOf(fn, postDominators, targetId);
|
|
44854
|
-
for (const blockId of [...targetPostDominators, targetId]) {
|
|
44855
|
-
if (visited.has(blockId)) {
|
|
44856
|
-
continue;
|
|
44857
|
-
}
|
|
44858
|
-
visited.add(blockId);
|
|
44859
|
-
const block = fn.body.blocks.get(blockId);
|
|
44860
|
-
for (const pred of block.preds) {
|
|
44861
|
-
if (!targetPostDominators.has(pred)) {
|
|
44862
|
-
frontier.add(pred);
|
|
44863
|
-
}
|
|
44864
|
-
}
|
|
44865
|
-
}
|
|
44866
|
-
return frontier;
|
|
44867
|
-
}
|
|
44868
|
-
function postDominatorsOf(fn, postDominators, targetId) {
|
|
44869
|
-
var _a;
|
|
44870
|
-
const result = new Set();
|
|
44871
|
-
const visited = new Set();
|
|
44872
|
-
const queue = [targetId];
|
|
44873
|
-
while (queue.length) {
|
|
44874
|
-
const currentId = queue.shift();
|
|
44875
|
-
if (visited.has(currentId)) {
|
|
44876
|
-
continue;
|
|
44877
|
-
}
|
|
44878
|
-
visited.add(currentId);
|
|
44879
|
-
const current = fn.body.blocks.get(currentId);
|
|
44880
|
-
for (const pred of current.preds) {
|
|
44881
|
-
const predPostDominator = (_a = postDominators.get(pred)) !== null && _a !== void 0 ? _a : pred;
|
|
44882
|
-
if (predPostDominator === targetId || result.has(predPostDominator)) {
|
|
44883
|
-
result.add(pred);
|
|
44884
|
-
}
|
|
44885
|
-
queue.push(pred);
|
|
44886
|
-
}
|
|
44887
|
-
}
|
|
44888
|
-
return result;
|
|
44889
|
-
}
|
|
44890
44957
|
class ReactivityMap {
|
|
44891
44958
|
constructor(aliasedIdentifiers) {
|
|
44892
44959
|
this.hasChanges = false;
|
|
@@ -48133,6 +48200,25 @@ function* generateInstructionTypes(env, names, instr) {
|
|
|
48133
48200
|
}
|
|
48134
48201
|
}
|
|
48135
48202
|
}
|
|
48203
|
+
if (env.config.enableInferEventHandlers) {
|
|
48204
|
+
if (value.kind === 'JsxExpression' &&
|
|
48205
|
+
value.tag.kind === 'BuiltinTag' &&
|
|
48206
|
+
!value.tag.name.includes('-')) {
|
|
48207
|
+
for (const prop of value.props) {
|
|
48208
|
+
if (prop.kind === 'JsxAttribute' &&
|
|
48209
|
+
prop.name.startsWith('on') &&
|
|
48210
|
+
prop.name.length > 2 &&
|
|
48211
|
+
prop.name[2] === prop.name[2].toUpperCase()) {
|
|
48212
|
+
yield equation(prop.place.identifier.type, {
|
|
48213
|
+
kind: 'Function',
|
|
48214
|
+
shapeId: BuiltInEventHandlerId,
|
|
48215
|
+
return: makeType(),
|
|
48216
|
+
isConstructor: false,
|
|
48217
|
+
});
|
|
48218
|
+
}
|
|
48219
|
+
}
|
|
48220
|
+
}
|
|
48221
|
+
}
|
|
48136
48222
|
yield equation(left, { kind: 'Object', shapeId: BuiltInJsxId });
|
|
48137
48223
|
break;
|
|
48138
48224
|
}
|
|
@@ -49056,6 +49142,10 @@ function refTypeOfType(place) {
|
|
|
49056
49142
|
return { kind: 'None' };
|
|
49057
49143
|
}
|
|
49058
49144
|
}
|
|
49145
|
+
function isEventHandlerType(identifier) {
|
|
49146
|
+
const type = identifier.type;
|
|
49147
|
+
return type.kind === 'Function' && type.shapeId === BuiltInEventHandlerId;
|
|
49148
|
+
}
|
|
49059
49149
|
function tyEqual(a, b) {
|
|
49060
49150
|
if (a.kind !== b.kind) {
|
|
49061
49151
|
return false;
|
|
@@ -49342,8 +49432,10 @@ function validateNoRefAccessInRenderImpl(fn, env) {
|
|
|
49342
49432
|
}
|
|
49343
49433
|
if (!didError) {
|
|
49344
49434
|
const isRefLValue = isUseRefType(instr.lvalue.identifier);
|
|
49435
|
+
const isEventHandlerLValue = isEventHandlerType(instr.lvalue.identifier);
|
|
49345
49436
|
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
49346
49437
|
if (isRefLValue ||
|
|
49438
|
+
isEventHandlerLValue ||
|
|
49347
49439
|
(hookKind != null &&
|
|
49348
49440
|
hookKind !== 'useState' &&
|
|
49349
49441
|
hookKind !== 'useReducer')) {
|
|
@@ -50842,20 +50934,84 @@ function validateNoSetStateInEffects(fn, env) {
|
|
|
50842
50934
|
return errors.asResult();
|
|
50843
50935
|
}
|
|
50844
50936
|
function getSetStateCall(fn, setStateFunctions, env) {
|
|
50937
|
+
const enableAllowSetStateFromRefsInEffects = env.config.enableAllowSetStateFromRefsInEffects;
|
|
50845
50938
|
const refDerivedValues = new Set();
|
|
50846
50939
|
const isDerivedFromRef = (place) => {
|
|
50847
50940
|
return (refDerivedValues.has(place.identifier.id) ||
|
|
50848
50941
|
isUseRefType(place.identifier) ||
|
|
50849
50942
|
isRefValueType(place.identifier));
|
|
50850
50943
|
};
|
|
50944
|
+
const isRefControlledBlock = enableAllowSetStateFromRefsInEffects
|
|
50945
|
+
? createControlDominators(fn, place => isDerivedFromRef(place))
|
|
50946
|
+
: () => false;
|
|
50851
50947
|
for (const [, block] of fn.body.blocks) {
|
|
50948
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
50949
|
+
for (const phi of block.phis) {
|
|
50950
|
+
if (isDerivedFromRef(phi.place)) {
|
|
50951
|
+
continue;
|
|
50952
|
+
}
|
|
50953
|
+
let isPhiDerivedFromRef = false;
|
|
50954
|
+
for (const [, operand] of phi.operands) {
|
|
50955
|
+
if (isDerivedFromRef(operand)) {
|
|
50956
|
+
isPhiDerivedFromRef = true;
|
|
50957
|
+
break;
|
|
50958
|
+
}
|
|
50959
|
+
}
|
|
50960
|
+
if (isPhiDerivedFromRef) {
|
|
50961
|
+
refDerivedValues.add(phi.place.identifier.id);
|
|
50962
|
+
}
|
|
50963
|
+
else {
|
|
50964
|
+
for (const [pred] of phi.operands) {
|
|
50965
|
+
if (isRefControlledBlock(pred)) {
|
|
50966
|
+
refDerivedValues.add(phi.place.identifier.id);
|
|
50967
|
+
break;
|
|
50968
|
+
}
|
|
50969
|
+
}
|
|
50970
|
+
}
|
|
50971
|
+
}
|
|
50972
|
+
}
|
|
50852
50973
|
for (const instr of block.instructions) {
|
|
50853
|
-
if (
|
|
50974
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
50854
50975
|
const hasRefOperand = Iterable_some(eachInstructionValueOperand(instr.value), isDerivedFromRef);
|
|
50855
50976
|
if (hasRefOperand) {
|
|
50856
50977
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
50857
50978
|
refDerivedValues.add(lvalue.identifier.id);
|
|
50858
50979
|
}
|
|
50980
|
+
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
50981
|
+
switch (operand.effect) {
|
|
50982
|
+
case Effect.Capture:
|
|
50983
|
+
case Effect.Store:
|
|
50984
|
+
case Effect.ConditionallyMutate:
|
|
50985
|
+
case Effect.ConditionallyMutateIterator:
|
|
50986
|
+
case Effect.Mutate: {
|
|
50987
|
+
if (isMutable(instr, operand)) {
|
|
50988
|
+
refDerivedValues.add(operand.identifier.id);
|
|
50989
|
+
}
|
|
50990
|
+
break;
|
|
50991
|
+
}
|
|
50992
|
+
case Effect.Freeze:
|
|
50993
|
+
case Effect.Read: {
|
|
50994
|
+
break;
|
|
50995
|
+
}
|
|
50996
|
+
case Effect.Unknown: {
|
|
50997
|
+
CompilerError.invariant(false, {
|
|
50998
|
+
reason: 'Unexpected unknown effect',
|
|
50999
|
+
description: null,
|
|
51000
|
+
details: [
|
|
51001
|
+
{
|
|
51002
|
+
kind: 'error',
|
|
51003
|
+
loc: operand.loc,
|
|
51004
|
+
message: null,
|
|
51005
|
+
},
|
|
51006
|
+
],
|
|
51007
|
+
suggestions: null,
|
|
51008
|
+
});
|
|
51009
|
+
}
|
|
51010
|
+
default: {
|
|
51011
|
+
assertExhaustive$1(operand.effect, `Unexpected effect kind \`${operand.effect}\``);
|
|
51012
|
+
}
|
|
51013
|
+
}
|
|
51014
|
+
}
|
|
50859
51015
|
}
|
|
50860
51016
|
if (instr.value.kind === 'PropertyLoad' &&
|
|
50861
51017
|
instr.value.property === 'current' &&
|
|
@@ -50882,13 +51038,16 @@ function getSetStateCall(fn, setStateFunctions, env) {
|
|
|
50882
51038
|
const callee = instr.value.callee;
|
|
50883
51039
|
if (isSetStateType(callee.identifier) ||
|
|
50884
51040
|
setStateFunctions.has(callee.identifier.id)) {
|
|
50885
|
-
if (
|
|
51041
|
+
if (enableAllowSetStateFromRefsInEffects) {
|
|
50886
51042
|
const arg = instr.value.args.at(0);
|
|
50887
51043
|
if (arg !== undefined &&
|
|
50888
51044
|
arg.kind === 'Identifier' &&
|
|
50889
51045
|
refDerivedValues.has(arg.identifier.id)) {
|
|
50890
51046
|
return null;
|
|
50891
51047
|
}
|
|
51048
|
+
else if (isRefControlledBlock(block.id)) {
|
|
51049
|
+
continue;
|
|
51050
|
+
}
|
|
50892
51051
|
}
|
|
50893
51052
|
return callee;
|
|
50894
51053
|
}
|
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": "7.1.0-canary-
|
|
4
|
+
"version": "7.1.0-canary-0972e239-20251118",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/facebook/react.git",
|