eslint-plugin-react-hooks 7.1.0-canary-eb89912e-20251118 → 7.1.0-canary-40b4a5bf-20251120
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.
|
@@ -17816,6 +17816,22 @@ class CompilerErrorDetail {
|
|
|
17816
17816
|
}
|
|
17817
17817
|
}
|
|
17818
17818
|
class CompilerError extends Error {
|
|
17819
|
+
static simpleInvariant(condition, options) {
|
|
17820
|
+
var _a;
|
|
17821
|
+
if (!condition) {
|
|
17822
|
+
const errors = new CompilerError();
|
|
17823
|
+
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
17824
|
+
reason: options.reason,
|
|
17825
|
+
description: (_a = options.description) !== null && _a !== void 0 ? _a : null,
|
|
17826
|
+
category: ErrorCategory.Invariant,
|
|
17827
|
+
}).withDetails({
|
|
17828
|
+
kind: 'error',
|
|
17829
|
+
loc: options.loc,
|
|
17830
|
+
message: options.reason,
|
|
17831
|
+
}));
|
|
17832
|
+
throw errors;
|
|
17833
|
+
}
|
|
17834
|
+
}
|
|
17819
17835
|
static invariant(condition, options) {
|
|
17820
17836
|
if (!condition) {
|
|
17821
17837
|
const errors = new CompilerError();
|
|
@@ -18016,7 +18032,8 @@ function printErrorSummary(category, message) {
|
|
|
18016
18032
|
case ErrorCategory.Suppression:
|
|
18017
18033
|
case ErrorCategory.Syntax:
|
|
18018
18034
|
case ErrorCategory.UseMemo:
|
|
18019
|
-
case ErrorCategory.VoidUseMemo:
|
|
18035
|
+
case ErrorCategory.VoidUseMemo:
|
|
18036
|
+
case ErrorCategory.MemoDependencies: {
|
|
18020
18037
|
heading = 'Error';
|
|
18021
18038
|
break;
|
|
18022
18039
|
}
|
|
@@ -18050,6 +18067,7 @@ var ErrorCategory;
|
|
|
18050
18067
|
ErrorCategory["VoidUseMemo"] = "VoidUseMemo";
|
|
18051
18068
|
ErrorCategory["Factories"] = "Factories";
|
|
18052
18069
|
ErrorCategory["PreserveManualMemo"] = "PreserveManualMemo";
|
|
18070
|
+
ErrorCategory["MemoDependencies"] = "MemoDependencies";
|
|
18053
18071
|
ErrorCategory["IncompatibleLibrary"] = "IncompatibleLibrary";
|
|
18054
18072
|
ErrorCategory["Immutability"] = "Immutability";
|
|
18055
18073
|
ErrorCategory["Globals"] = "Globals";
|
|
@@ -18323,6 +18341,15 @@ function getRuleForCategoryImpl(category) {
|
|
|
18323
18341
|
preset: LintRulePreset.RecommendedLatest,
|
|
18324
18342
|
};
|
|
18325
18343
|
}
|
|
18344
|
+
case ErrorCategory.MemoDependencies: {
|
|
18345
|
+
return {
|
|
18346
|
+
category,
|
|
18347
|
+
severity: ErrorSeverity.Error,
|
|
18348
|
+
name: 'memo-dependencies',
|
|
18349
|
+
description: 'Validates that useMemo() and useCallback() specify comprehensive dependencies without extraneous values. See [`useMemo()` docs](https://react.dev/reference/react/useMemo) for more information.',
|
|
18350
|
+
preset: LintRulePreset.RecommendedLatest,
|
|
18351
|
+
};
|
|
18352
|
+
}
|
|
18326
18353
|
case ErrorCategory.IncompatibleLibrary: {
|
|
18327
18354
|
return {
|
|
18328
18355
|
category,
|
|
@@ -18831,6 +18858,11 @@ function areEqualPaths(a, b) {
|
|
|
18831
18858
|
return (a.length === b.length &&
|
|
18832
18859
|
a.every((item, ix) => item.property === b[ix].property && item.optional === b[ix].optional));
|
|
18833
18860
|
}
|
|
18861
|
+
function isSubPath(subpath, path) {
|
|
18862
|
+
return (subpath.length <= path.length &&
|
|
18863
|
+
subpath.every((item, ix) => item.property === path[ix].property &&
|
|
18864
|
+
item.optional === path[ix].optional));
|
|
18865
|
+
}
|
|
18834
18866
|
function getPlaceScope(id, place) {
|
|
18835
18867
|
const scope = place.identifier.scope;
|
|
18836
18868
|
if (scope !== null && isScopeActive(scope, id)) {
|
|
@@ -18922,6 +18954,9 @@ function isObjectMethodType(id) {
|
|
|
18922
18954
|
function isPrimitiveType(id) {
|
|
18923
18955
|
return id.type.kind === 'Primitive';
|
|
18924
18956
|
}
|
|
18957
|
+
function isPlainObjectType(id) {
|
|
18958
|
+
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInObject';
|
|
18959
|
+
}
|
|
18925
18960
|
function isArrayType(id) {
|
|
18926
18961
|
return id.type.kind === 'Object' && id.type.shapeId === 'BuiltInArray';
|
|
18927
18962
|
}
|
|
@@ -19599,7 +19634,7 @@ function printInstructionValue(instrValue) {
|
|
|
19599
19634
|
break;
|
|
19600
19635
|
}
|
|
19601
19636
|
case 'StartMemoize': {
|
|
19602
|
-
value = `StartMemoize deps=${(_e = (_d = instrValue.deps) === null || _d === void 0 ? void 0 : _d.map(dep => printManualMemoDependency(dep, false))) !== null && _e !== void 0 ? _e : '(none)'}`;
|
|
19637
|
+
value = `StartMemoize deps=${(_e = (_d = instrValue.deps) === null || _d === void 0 ? void 0 : _d.map(dep => printManualMemoDependency$1(dep, false))) !== null && _e !== void 0 ? _e : '(none)'}`;
|
|
19603
19638
|
break;
|
|
19604
19639
|
}
|
|
19605
19640
|
case 'FinishMemoize': {
|
|
@@ -19687,7 +19722,7 @@ function printName(name) {
|
|
|
19687
19722
|
function printScope(scope) {
|
|
19688
19723
|
return `${scope !== null ? `_@${scope.id}` : ''}`;
|
|
19689
19724
|
}
|
|
19690
|
-
function printManualMemoDependency(val, nameOnly) {
|
|
19725
|
+
function printManualMemoDependency$1(val, nameOnly) {
|
|
19691
19726
|
var _a;
|
|
19692
19727
|
let rootStr;
|
|
19693
19728
|
if (val.root.kind === 'Global') {
|
|
@@ -32163,6 +32198,7 @@ const EnvironmentConfigSchema = v4.z.object({
|
|
|
32163
32198
|
enableResetCacheOnSourceFileChanges: v4.z.nullable(v4.z.boolean()).default(null),
|
|
32164
32199
|
enablePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
32165
32200
|
validatePreserveExistingMemoizationGuarantees: v4.z.boolean().default(true),
|
|
32201
|
+
validateExhaustiveMemoizationDependencies: v4.z.boolean().default(false),
|
|
32166
32202
|
enablePreserveExistingManualUseMemo: v4.z.boolean().default(false),
|
|
32167
32203
|
enableForest: v4.z.boolean().default(false),
|
|
32168
32204
|
enableUseTypeAnnotations: v4.z.boolean().default(false),
|
|
@@ -32217,7 +32253,7 @@ const EnvironmentConfigSchema = v4.z.object({
|
|
|
32217
32253
|
enableInferEventHandlers: v4.z.boolean().default(false),
|
|
32218
32254
|
});
|
|
32219
32255
|
class Environment {
|
|
32220
|
-
constructor(scope, fnType,
|
|
32256
|
+
constructor(scope, fnType, outputMode, config, contextIdentifiers, parentFunction, logger, filename, code, programContext) {
|
|
32221
32257
|
_Environment_instances.add(this);
|
|
32222
32258
|
_Environment_globals.set(this, void 0);
|
|
32223
32259
|
_Environment_shapes.set(this, void 0);
|
|
@@ -32233,7 +32269,7 @@ class Environment {
|
|
|
32233
32269
|
_Environment_flowTypeEnvironment.set(this, void 0);
|
|
32234
32270
|
__classPrivateFieldSet(this, _Environment_scope, scope, "f");
|
|
32235
32271
|
this.fnType = fnType;
|
|
32236
|
-
this.
|
|
32272
|
+
this.outputMode = outputMode;
|
|
32237
32273
|
this.config = config;
|
|
32238
32274
|
this.filename = filename;
|
|
32239
32275
|
this.code = code;
|
|
@@ -32317,8 +32353,52 @@ class Environment {
|
|
|
32317
32353
|
});
|
|
32318
32354
|
return __classPrivateFieldGet(this, _Environment_flowTypeEnvironment, "f");
|
|
32319
32355
|
}
|
|
32320
|
-
get
|
|
32321
|
-
|
|
32356
|
+
get enableDropManualMemoization() {
|
|
32357
|
+
switch (this.outputMode) {
|
|
32358
|
+
case 'lint': {
|
|
32359
|
+
return true;
|
|
32360
|
+
}
|
|
32361
|
+
case 'client':
|
|
32362
|
+
case 'ssr': {
|
|
32363
|
+
return true;
|
|
32364
|
+
}
|
|
32365
|
+
case 'client-no-memo': {
|
|
32366
|
+
return false;
|
|
32367
|
+
}
|
|
32368
|
+
default: {
|
|
32369
|
+
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
32370
|
+
}
|
|
32371
|
+
}
|
|
32372
|
+
}
|
|
32373
|
+
get enableMemoization() {
|
|
32374
|
+
switch (this.outputMode) {
|
|
32375
|
+
case 'client':
|
|
32376
|
+
case 'lint': {
|
|
32377
|
+
return true;
|
|
32378
|
+
}
|
|
32379
|
+
case 'ssr':
|
|
32380
|
+
case 'client-no-memo': {
|
|
32381
|
+
return false;
|
|
32382
|
+
}
|
|
32383
|
+
default: {
|
|
32384
|
+
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
32385
|
+
}
|
|
32386
|
+
}
|
|
32387
|
+
}
|
|
32388
|
+
get enableValidations() {
|
|
32389
|
+
switch (this.outputMode) {
|
|
32390
|
+
case 'client':
|
|
32391
|
+
case 'lint':
|
|
32392
|
+
case 'ssr': {
|
|
32393
|
+
return true;
|
|
32394
|
+
}
|
|
32395
|
+
case 'client-no-memo': {
|
|
32396
|
+
return false;
|
|
32397
|
+
}
|
|
32398
|
+
default: {
|
|
32399
|
+
assertExhaustive$1(this.outputMode, `Unexpected output mode '${this.outputMode}'`);
|
|
32400
|
+
}
|
|
32401
|
+
}
|
|
32322
32402
|
}
|
|
32323
32403
|
get nextIdentifierId() {
|
|
32324
32404
|
var _a, _b;
|
|
@@ -34431,9 +34511,10 @@ function deadCodeElimination(fn) {
|
|
|
34431
34511
|
retainWhere(fn.context, contextVar => state.isIdOrNameUsed(contextVar.identifier));
|
|
34432
34512
|
}
|
|
34433
34513
|
let State$2 = class State {
|
|
34434
|
-
constructor() {
|
|
34514
|
+
constructor(env) {
|
|
34435
34515
|
this.named = new Set();
|
|
34436
34516
|
this.identifiers = new Set();
|
|
34517
|
+
this.env = env;
|
|
34437
34518
|
}
|
|
34438
34519
|
reference(identifier) {
|
|
34439
34520
|
this.identifiers.add(identifier.id);
|
|
@@ -34455,7 +34536,7 @@ let State$2 = class State {
|
|
|
34455
34536
|
function findReferencedIdentifiers(fn) {
|
|
34456
34537
|
const hasLoop = hasBackEdge(fn);
|
|
34457
34538
|
const reversedBlocks = [...fn.body.blocks.values()].reverse();
|
|
34458
|
-
const state = new State$2();
|
|
34539
|
+
const state = new State$2(fn.env);
|
|
34459
34540
|
let size = state.count;
|
|
34460
34541
|
do {
|
|
34461
34542
|
size = state.count;
|
|
@@ -34602,12 +34683,25 @@ function pruneableValue(value, state) {
|
|
|
34602
34683
|
case 'Debugger': {
|
|
34603
34684
|
return false;
|
|
34604
34685
|
}
|
|
34605
|
-
case 'Await':
|
|
34606
34686
|
case 'CallExpression':
|
|
34687
|
+
case 'MethodCall': {
|
|
34688
|
+
if (state.env.outputMode === 'ssr') {
|
|
34689
|
+
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
34690
|
+
const hookKind = getHookKind(state.env, calleee.identifier);
|
|
34691
|
+
switch (hookKind) {
|
|
34692
|
+
case 'useState':
|
|
34693
|
+
case 'useReducer':
|
|
34694
|
+
case 'useRef': {
|
|
34695
|
+
return true;
|
|
34696
|
+
}
|
|
34697
|
+
}
|
|
34698
|
+
}
|
|
34699
|
+
return false;
|
|
34700
|
+
}
|
|
34701
|
+
case 'Await':
|
|
34607
34702
|
case 'ComputedDelete':
|
|
34608
34703
|
case 'ComputedStore':
|
|
34609
34704
|
case 'PropertyDelete':
|
|
34610
|
-
case 'MethodCall':
|
|
34611
34705
|
case 'PropertyStore':
|
|
34612
34706
|
case 'StoreGlobal': {
|
|
34613
34707
|
return false;
|
|
@@ -37402,7 +37496,7 @@ function codegenFunction(fn, { uniqueIdentifiers, fbtOperands, }) {
|
|
|
37402
37496
|
}
|
|
37403
37497
|
const compiled = compileResult.unwrap();
|
|
37404
37498
|
const hookGuard = fn.env.config.enableEmitHookGuards;
|
|
37405
|
-
if (hookGuard != null && fn.env.
|
|
37499
|
+
if (hookGuard != null && fn.env.outputMode === 'client') {
|
|
37406
37500
|
compiled.body = libExports$1.blockStatement([
|
|
37407
37501
|
createHookGuard(hookGuard, fn.env.programContext, compiled.body.body, GuardKind.PushHookGuard, GuardKind.PopHookGuard),
|
|
37408
37502
|
]);
|
|
@@ -37432,7 +37526,7 @@ function codegenFunction(fn, { uniqueIdentifiers, fbtOperands, }) {
|
|
|
37432
37526
|
const emitInstrumentForget = fn.env.config.enableEmitInstrumentForget;
|
|
37433
37527
|
if (emitInstrumentForget != null &&
|
|
37434
37528
|
fn.id != null &&
|
|
37435
|
-
fn.env.
|
|
37529
|
+
fn.env.outputMode === 'client') {
|
|
37436
37530
|
const gating = emitInstrumentForget.gating != null
|
|
37437
37531
|
? libExports$1.identifier(fn.env.programContext.addImportSpecifier(emitInstrumentForget.gating).name)
|
|
37438
37532
|
: null;
|
|
@@ -37670,7 +37764,8 @@ function codegenBlockNoReset(cx, block) {
|
|
|
37670
37764
|
return libExports$1.blockStatement(statements);
|
|
37671
37765
|
}
|
|
37672
37766
|
function wrapCacheDep(cx, value) {
|
|
37673
|
-
if (cx.env.config.enableEmitFreeze != null &&
|
|
37767
|
+
if (cx.env.config.enableEmitFreeze != null &&
|
|
37768
|
+
cx.env.outputMode === 'client') {
|
|
37674
37769
|
const emitFreezeIdentifier = cx.env.programContext.addImportSpecifier(cx.env.config.enableEmitFreeze).name;
|
|
37675
37770
|
cx.env.programContext
|
|
37676
37771
|
.assertGlobalBinding(EMIT_FREEZE_GLOBAL_GATING, cx.env.scope)
|
|
@@ -38516,7 +38611,7 @@ function createCallExpression(env, callee, args, loc, isHook) {
|
|
|
38516
38611
|
callExpr.loc = loc;
|
|
38517
38612
|
}
|
|
38518
38613
|
const hookGuard = env.config.enableEmitHookGuards;
|
|
38519
|
-
if (hookGuard != null && isHook && env.
|
|
38614
|
+
if (hookGuard != null && isHook && env.outputMode === 'client') {
|
|
38520
38615
|
const iife = libExports$1.functionExpression(null, [], libExports$1.blockStatement([
|
|
38521
38616
|
createHookGuard(hookGuard, env.programContext, [libExports$1.returnStatement(callExpr)], GuardKind.AllowHook, GuardKind.DisallowHook),
|
|
38522
38617
|
]));
|
|
@@ -42214,7 +42309,7 @@ function computeEffectsForLegacySignature(state, signature, lvalue, receiver, ar
|
|
|
42214
42309
|
}),
|
|
42215
42310
|
});
|
|
42216
42311
|
}
|
|
42217
|
-
if (signature.knownIncompatible != null && state.env.
|
|
42312
|
+
if (signature.knownIncompatible != null && state.env.enableValidations) {
|
|
42218
42313
|
const errors = new CompilerError();
|
|
42219
42314
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
42220
42315
|
category: ErrorCategory.IncompatibleLibrary,
|
|
@@ -44583,7 +44678,10 @@ function collectTemporaries(instr, env, sidemap) {
|
|
|
44583
44678
|
}
|
|
44584
44679
|
case 'ArrayExpression': {
|
|
44585
44680
|
if (value.elements.every(e => e.kind === 'Identifier')) {
|
|
44586
|
-
sidemap.maybeDepsLists.set(instr.lvalue.identifier.id,
|
|
44681
|
+
sidemap.maybeDepsLists.set(instr.lvalue.identifier.id, {
|
|
44682
|
+
loc: value.loc,
|
|
44683
|
+
deps: value.elements,
|
|
44684
|
+
});
|
|
44587
44685
|
}
|
|
44588
44686
|
break;
|
|
44589
44687
|
}
|
|
@@ -44593,7 +44691,7 @@ function collectTemporaries(instr, env, sidemap) {
|
|
|
44593
44691
|
sidemap.maybeDeps.set(lvalue.identifier.id, maybeDep);
|
|
44594
44692
|
}
|
|
44595
44693
|
}
|
|
44596
|
-
function makeManualMemoizationMarkers(fnExpr, env, depsList, memoDecl, manualMemoId) {
|
|
44694
|
+
function makeManualMemoizationMarkers(fnExpr, env, depsList, depsLoc, memoDecl, manualMemoId) {
|
|
44597
44695
|
return [
|
|
44598
44696
|
{
|
|
44599
44697
|
id: makeInstructionId(0),
|
|
@@ -44602,6 +44700,7 @@ function makeManualMemoizationMarkers(fnExpr, env, depsList, memoDecl, manualMem
|
|
|
44602
44700
|
kind: 'StartMemoize',
|
|
44603
44701
|
manualMemoId,
|
|
44604
44702
|
deps: depsList,
|
|
44703
|
+
depsLoc,
|
|
44605
44704
|
loc: fnExpr.loc,
|
|
44606
44705
|
},
|
|
44607
44706
|
effects: null,
|
|
@@ -44646,71 +44745,69 @@ function getManualMemoizationReplacement(fn, loc, kind) {
|
|
|
44646
44745
|
}
|
|
44647
44746
|
function extractManualMemoizationArgs(instr, kind, sidemap, errors) {
|
|
44648
44747
|
const [fnPlace, depsListPlace] = instr.value.args;
|
|
44649
|
-
if (fnPlace == null) {
|
|
44748
|
+
if (fnPlace == null || fnPlace.kind !== 'Identifier') {
|
|
44650
44749
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
44651
44750
|
category: ErrorCategory.UseMemo,
|
|
44652
44751
|
reason: `Expected a callback function to be passed to ${kind}`,
|
|
44653
|
-
description:
|
|
44752
|
+
description: kind === 'useCallback'
|
|
44753
|
+
? 'The first argument to useCallback() must be a function to cache'
|
|
44754
|
+
: 'The first argument to useMemo() must be a function that calculates a result to cache',
|
|
44654
44755
|
suggestions: null,
|
|
44655
44756
|
}).withDetails({
|
|
44656
44757
|
kind: 'error',
|
|
44657
44758
|
loc: instr.value.loc,
|
|
44658
|
-
message:
|
|
44759
|
+
message: kind === 'useCallback'
|
|
44760
|
+
? `Expected a callback function`
|
|
44761
|
+
: `Expected a memoization function`,
|
|
44659
44762
|
}));
|
|
44660
|
-
return
|
|
44763
|
+
return null;
|
|
44764
|
+
}
|
|
44765
|
+
if (depsListPlace == null) {
|
|
44766
|
+
return {
|
|
44767
|
+
fnPlace,
|
|
44768
|
+
depsList: null,
|
|
44769
|
+
depsLoc: null,
|
|
44770
|
+
};
|
|
44661
44771
|
}
|
|
44662
|
-
|
|
44772
|
+
const maybeDepsList = depsListPlace.kind === 'Identifier'
|
|
44773
|
+
? sidemap.maybeDepsLists.get(depsListPlace.identifier.id)
|
|
44774
|
+
: null;
|
|
44775
|
+
if (maybeDepsList == null) {
|
|
44663
44776
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
44664
44777
|
category: ErrorCategory.UseMemo,
|
|
44665
|
-
reason: `
|
|
44666
|
-
description: `
|
|
44778
|
+
reason: `Expected the dependency list for ${kind} to be an array literal`,
|
|
44779
|
+
description: `Expected the dependency list for ${kind} to be an array literal`,
|
|
44667
44780
|
suggestions: null,
|
|
44668
44781
|
}).withDetails({
|
|
44669
44782
|
kind: 'error',
|
|
44670
|
-
loc:
|
|
44671
|
-
message: `
|
|
44783
|
+
loc: (depsListPlace === null || depsListPlace === void 0 ? void 0 : depsListPlace.kind) === 'Identifier' ? depsListPlace.loc : instr.loc,
|
|
44784
|
+
message: `Expected the dependency list for ${kind} to be an array literal`,
|
|
44672
44785
|
}));
|
|
44673
|
-
return
|
|
44786
|
+
return null;
|
|
44674
44787
|
}
|
|
44675
|
-
|
|
44676
|
-
|
|
44677
|
-
const
|
|
44678
|
-
if (
|
|
44788
|
+
const depsList = [];
|
|
44789
|
+
for (const dep of maybeDepsList.deps) {
|
|
44790
|
+
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
|
44791
|
+
if (maybeDep == null) {
|
|
44679
44792
|
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
44680
44793
|
category: ErrorCategory.UseMemo,
|
|
44681
|
-
reason: `Expected the dependency list
|
|
44682
|
-
description: `Expected the dependency list
|
|
44794
|
+
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44795
|
+
description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44683
44796
|
suggestions: null,
|
|
44684
44797
|
}).withDetails({
|
|
44685
44798
|
kind: 'error',
|
|
44686
|
-
loc:
|
|
44687
|
-
message: `Expected the dependency list
|
|
44799
|
+
loc: dep.loc,
|
|
44800
|
+
message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44688
44801
|
}));
|
|
44689
|
-
return { fnPlace, depsList: null };
|
|
44690
44802
|
}
|
|
44691
|
-
|
|
44692
|
-
|
|
44693
|
-
const maybeDep = sidemap.maybeDeps.get(dep.identifier.id);
|
|
44694
|
-
if (maybeDep == null) {
|
|
44695
|
-
errors.pushDiagnostic(CompilerDiagnostic.create({
|
|
44696
|
-
category: ErrorCategory.UseMemo,
|
|
44697
|
-
reason: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44698
|
-
description: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44699
|
-
suggestions: null,
|
|
44700
|
-
}).withDetails({
|
|
44701
|
-
kind: 'error',
|
|
44702
|
-
loc: dep.loc,
|
|
44703
|
-
message: `Expected the dependency list to be an array of simple expressions (e.g. \`x\`, \`x.y.z\`, \`x?.y?.z\`)`,
|
|
44704
|
-
}));
|
|
44705
|
-
}
|
|
44706
|
-
else {
|
|
44707
|
-
depsList.push(maybeDep);
|
|
44708
|
-
}
|
|
44803
|
+
else {
|
|
44804
|
+
depsList.push(maybeDep);
|
|
44709
44805
|
}
|
|
44710
44806
|
}
|
|
44711
44807
|
return {
|
|
44712
44808
|
fnPlace,
|
|
44713
44809
|
depsList,
|
|
44810
|
+
depsLoc: maybeDepsList.loc,
|
|
44714
44811
|
};
|
|
44715
44812
|
}
|
|
44716
44813
|
function dropManualMemoization(func) {
|
|
@@ -44718,7 +44815,7 @@ function dropManualMemoization(func) {
|
|
|
44718
44815
|
const isValidationEnabled = func.env.config.validatePreserveExistingMemoizationGuarantees ||
|
|
44719
44816
|
func.env.config.validateNoSetStateInRender ||
|
|
44720
44817
|
func.env.config.enablePreserveExistingMemoizationGuarantees;
|
|
44721
|
-
const optionals = findOptionalPlaces(func);
|
|
44818
|
+
const optionals = findOptionalPlaces$1(func);
|
|
44722
44819
|
const sidemap = {
|
|
44723
44820
|
functions: new Map(),
|
|
44724
44821
|
manualMemos: new Map(),
|
|
@@ -44739,10 +44836,11 @@ function dropManualMemoization(func) {
|
|
|
44739
44836
|
: instr.value.property.identifier.id;
|
|
44740
44837
|
const manualMemo = sidemap.manualMemos.get(id);
|
|
44741
44838
|
if (manualMemo != null) {
|
|
44742
|
-
const
|
|
44743
|
-
if (
|
|
44839
|
+
const memoDetails = extractManualMemoizationArgs(instr, manualMemo.kind, sidemap, errors);
|
|
44840
|
+
if (memoDetails == null) {
|
|
44744
44841
|
continue;
|
|
44745
44842
|
}
|
|
44843
|
+
const { fnPlace, depsList, depsLoc } = memoDetails;
|
|
44746
44844
|
instr.value = getManualMemoizationReplacement(fnPlace, instr.value.loc, manualMemo.kind);
|
|
44747
44845
|
if (isValidationEnabled) {
|
|
44748
44846
|
if (!sidemap.functions.has(fnPlace.identifier.id)) {
|
|
@@ -44767,7 +44865,7 @@ function dropManualMemoization(func) {
|
|
|
44767
44865
|
reactive: false,
|
|
44768
44866
|
loc: fnPlace.loc,
|
|
44769
44867
|
};
|
|
44770
|
-
const [startMarker, finishMarker] = makeManualMemoizationMarkers(fnPlace, func.env, depsList, memoDecl, nextManualMemoId++);
|
|
44868
|
+
const [startMarker, finishMarker] = makeManualMemoizationMarkers(fnPlace, func.env, depsList, depsLoc, memoDecl, nextManualMemoId++);
|
|
44771
44869
|
queuedInserts.set(manualMemo.loadInstr.id, startMarker);
|
|
44772
44870
|
queuedInserts.set(instr.id, finishMarker);
|
|
44773
44871
|
}
|
|
@@ -44805,7 +44903,7 @@ function dropManualMemoization(func) {
|
|
|
44805
44903
|
}
|
|
44806
44904
|
return errors.asResult();
|
|
44807
44905
|
}
|
|
44808
|
-
function findOptionalPlaces(fn) {
|
|
44906
|
+
function findOptionalPlaces$1(fn) {
|
|
44809
44907
|
const optionals = new Set();
|
|
44810
44908
|
for (const [, block] of fn.body.blocks) {
|
|
44811
44909
|
if (block.terminal.kind === 'optional' && block.terminal.optional) {
|
|
@@ -46178,7 +46276,7 @@ function propagateScopeDependenciesHIR(fn) {
|
|
|
46178
46276
|
const temporaries = collectTemporariesSidemap$1(fn, usedOutsideDeclaringScope);
|
|
46179
46277
|
const { temporariesReadInOptional, processedInstrsInOptional, hoistableObjects, } = collectOptionalChainSidemap(fn);
|
|
46180
46278
|
const hoistablePropertyLoads = keyByScopeId(fn, collectHoistablePropertyLoads(fn, temporaries, hoistableObjects));
|
|
46181
|
-
const scopeDeps = collectDependencies(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
|
|
46279
|
+
const scopeDeps = collectDependencies$1(fn, usedOutsideDeclaringScope, new Map([...temporaries, ...temporariesReadInOptional]), processedInstrsInOptional);
|
|
46182
46280
|
for (const [scope, deps] of scopeDeps) {
|
|
46183
46281
|
if (deps.length === 0) {
|
|
46184
46282
|
continue;
|
|
@@ -46529,7 +46627,7 @@ function handleInstruction(instr, context) {
|
|
|
46529
46627
|
}
|
|
46530
46628
|
}
|
|
46531
46629
|
}
|
|
46532
|
-
function collectDependencies(fn, usedOutsideDeclaringScope, temporaries, processedInstrsInOptional) {
|
|
46630
|
+
function collectDependencies$1(fn, usedOutsideDeclaringScope, temporaries, processedInstrsInOptional) {
|
|
46533
46631
|
const context = new DependencyCollectionContext(usedOutsideDeclaringScope, temporaries, processedInstrsInOptional);
|
|
46534
46632
|
for (const param of fn.params) {
|
|
46535
46633
|
if (param.kind === 'Identifier') {
|
|
@@ -50141,7 +50239,7 @@ function validateInferredDep(dep, temporaries, declsWithinMemoBlock, validDepsIn
|
|
|
50141
50239
|
'The inferred dependencies did not match the manually specified dependencies, which could cause the value to change more or less frequently than expected. ',
|
|
50142
50240
|
(dep.identifier.name != null && dep.identifier.name.kind === 'named')
|
|
50143
50241
|
? `The inferred dependency was \`${prettyPrintScopeDependency(dep)}\`, but the source dependencies were [${validDepsInMemoBlock
|
|
50144
|
-
.map(dep => printManualMemoDependency(dep, true))
|
|
50242
|
+
.map(dep => printManualMemoDependency$1(dep, true))
|
|
50145
50243
|
.join(', ')}]. ${errorDiagnostic
|
|
50146
50244
|
? getCompareDependencyResultDescription(errorDiagnostic)
|
|
50147
50245
|
: 'Inferred dependency not present in source'}`
|
|
@@ -52448,6 +52546,7 @@ function validateEffect$1(effectFunction, effectDeps, errors) {
|
|
|
52448
52546
|
}
|
|
52449
52547
|
}
|
|
52450
52548
|
|
|
52549
|
+
const MAX_FIXPOINT_ITERATIONS = 100;
|
|
52451
52550
|
class DerivationCache {
|
|
52452
52551
|
constructor() {
|
|
52453
52552
|
this.hasChanges = false;
|
|
@@ -52567,6 +52666,7 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
|
|
|
52567
52666
|
});
|
|
52568
52667
|
}
|
|
52569
52668
|
}
|
|
52669
|
+
let iterationCount = 0;
|
|
52570
52670
|
do {
|
|
52571
52671
|
context.derivationCache.takeSnapshot();
|
|
52572
52672
|
for (const block of fn.body.blocks.values()) {
|
|
@@ -52576,6 +52676,18 @@ function validateNoDerivedComputationsInEffects_exp(fn) {
|
|
|
52576
52676
|
}
|
|
52577
52677
|
}
|
|
52578
52678
|
context.derivationCache.checkForChanges();
|
|
52679
|
+
iterationCount++;
|
|
52680
|
+
CompilerError.invariant(iterationCount < MAX_FIXPOINT_ITERATIONS, {
|
|
52681
|
+
reason: '[ValidateNoDerivedComputationsInEffects] Fixpoint iteration failed to converge.',
|
|
52682
|
+
description: `Fixpoint iteration exceeded ${MAX_FIXPOINT_ITERATIONS} iterations while tracking derivations. This suggests a cyclic dependency in the derivation cache.`,
|
|
52683
|
+
details: [
|
|
52684
|
+
{
|
|
52685
|
+
kind: 'error',
|
|
52686
|
+
loc: fn.loc,
|
|
52687
|
+
message: `Exceeded ${MAX_FIXPOINT_ITERATIONS} iterations in ValidateNoDerivedComputationsInEffects`,
|
|
52688
|
+
},
|
|
52689
|
+
],
|
|
52690
|
+
});
|
|
52579
52691
|
} while (context.derivationCache.snapshot());
|
|
52580
52692
|
for (const [, effect] of effectsCache) {
|
|
52581
52693
|
validateEffect(effect.effect, effect.dependencies, context);
|
|
@@ -52670,7 +52782,7 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
|
|
|
52670
52782
|
});
|
|
52671
52783
|
}
|
|
52672
52784
|
}
|
|
52673
|
-
else if (isUseStateType(lvalue.identifier)
|
|
52785
|
+
else if (isUseStateType(lvalue.identifier)) {
|
|
52674
52786
|
typeOfValue = 'fromState';
|
|
52675
52787
|
context.derivationCache.addDerivationEntry(lvalue, new Set(), typeOfValue, true);
|
|
52676
52788
|
return;
|
|
@@ -52699,6 +52811,9 @@ function recordInstructionDerivations(instr, context, isFirstPass) {
|
|
|
52699
52811
|
for (const lvalue of eachInstructionLValue(instr)) {
|
|
52700
52812
|
context.derivationCache.addDerivationEntry(lvalue, sources, typeOfValue, isSource);
|
|
52701
52813
|
}
|
|
52814
|
+
if (value.kind === 'FunctionExpression') {
|
|
52815
|
+
return;
|
|
52816
|
+
}
|
|
52702
52817
|
for (const operand of eachInstructionOperand(instr)) {
|
|
52703
52818
|
switch (operand.effect) {
|
|
52704
52819
|
case Effect.Capture:
|
|
@@ -52760,6 +52875,17 @@ function buildTreeNode(sourceId, context, visited = new Set()) {
|
|
|
52760
52875
|
const children = [];
|
|
52761
52876
|
const namedSiblings = new Set();
|
|
52762
52877
|
for (const childId of sourceMetadata.sourcesIds) {
|
|
52878
|
+
CompilerError.invariant(childId !== sourceId, {
|
|
52879
|
+
reason: 'Unexpected self-reference: a value should not have itself as a source',
|
|
52880
|
+
description: null,
|
|
52881
|
+
details: [
|
|
52882
|
+
{
|
|
52883
|
+
kind: 'error',
|
|
52884
|
+
loc: sourceMetadata.place.loc,
|
|
52885
|
+
message: null,
|
|
52886
|
+
},
|
|
52887
|
+
],
|
|
52888
|
+
});
|
|
52763
52889
|
const childNodes = buildTreeNode(childId, context, new Set([
|
|
52764
52890
|
...visited,
|
|
52765
52891
|
...(isNamedIdentifier(sourceMetadata.place)
|
|
@@ -53106,6 +53232,765 @@ function nameAnonymousFunctionsImpl(fn) {
|
|
|
53106
53232
|
return nodes;
|
|
53107
53233
|
}
|
|
53108
53234
|
|
|
53235
|
+
function optimizeForSSR(fn) {
|
|
53236
|
+
const inlinedState = new Map();
|
|
53237
|
+
for (const block of fn.body.blocks.values()) {
|
|
53238
|
+
for (const instr of block.instructions) {
|
|
53239
|
+
const { value } = instr;
|
|
53240
|
+
switch (value.kind) {
|
|
53241
|
+
case 'Destructure': {
|
|
53242
|
+
if (inlinedState.has(value.value.identifier.id) &&
|
|
53243
|
+
value.lvalue.pattern.kind === 'ArrayPattern' &&
|
|
53244
|
+
value.lvalue.pattern.items.length >= 1 &&
|
|
53245
|
+
value.lvalue.pattern.items[0].kind === 'Identifier') {
|
|
53246
|
+
continue;
|
|
53247
|
+
}
|
|
53248
|
+
break;
|
|
53249
|
+
}
|
|
53250
|
+
case 'MethodCall':
|
|
53251
|
+
case 'CallExpression': {
|
|
53252
|
+
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
53253
|
+
const hookKind = getHookKind(fn.env, calleee.identifier);
|
|
53254
|
+
switch (hookKind) {
|
|
53255
|
+
case 'useReducer': {
|
|
53256
|
+
if (value.args.length === 2 &&
|
|
53257
|
+
value.args[1].kind === 'Identifier') {
|
|
53258
|
+
const arg = value.args[1];
|
|
53259
|
+
const replace = {
|
|
53260
|
+
kind: 'LoadLocal',
|
|
53261
|
+
place: arg,
|
|
53262
|
+
loc: arg.loc,
|
|
53263
|
+
};
|
|
53264
|
+
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
53265
|
+
}
|
|
53266
|
+
else if (value.args.length === 3 &&
|
|
53267
|
+
value.args[1].kind === 'Identifier' &&
|
|
53268
|
+
value.args[2].kind === 'Identifier') {
|
|
53269
|
+
const arg = value.args[1];
|
|
53270
|
+
const initializer = value.args[2];
|
|
53271
|
+
const replace = {
|
|
53272
|
+
kind: 'CallExpression',
|
|
53273
|
+
callee: initializer,
|
|
53274
|
+
args: [arg],
|
|
53275
|
+
loc: value.loc,
|
|
53276
|
+
};
|
|
53277
|
+
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
53278
|
+
}
|
|
53279
|
+
break;
|
|
53280
|
+
}
|
|
53281
|
+
case 'useState': {
|
|
53282
|
+
if (value.args.length === 1 &&
|
|
53283
|
+
value.args[0].kind === 'Identifier') {
|
|
53284
|
+
const arg = value.args[0];
|
|
53285
|
+
if (isPrimitiveType(arg.identifier) ||
|
|
53286
|
+
isPlainObjectType(arg.identifier) ||
|
|
53287
|
+
isArrayType(arg.identifier)) {
|
|
53288
|
+
const replace = {
|
|
53289
|
+
kind: 'LoadLocal',
|
|
53290
|
+
place: arg,
|
|
53291
|
+
loc: arg.loc,
|
|
53292
|
+
};
|
|
53293
|
+
inlinedState.set(instr.lvalue.identifier.id, replace);
|
|
53294
|
+
}
|
|
53295
|
+
}
|
|
53296
|
+
break;
|
|
53297
|
+
}
|
|
53298
|
+
}
|
|
53299
|
+
}
|
|
53300
|
+
}
|
|
53301
|
+
if (inlinedState.size !== 0) {
|
|
53302
|
+
for (const operand of eachInstructionValueOperand(value)) {
|
|
53303
|
+
inlinedState.delete(operand.identifier.id);
|
|
53304
|
+
}
|
|
53305
|
+
}
|
|
53306
|
+
}
|
|
53307
|
+
if (inlinedState.size !== 0) {
|
|
53308
|
+
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
53309
|
+
inlinedState.delete(operand.identifier.id);
|
|
53310
|
+
}
|
|
53311
|
+
}
|
|
53312
|
+
}
|
|
53313
|
+
for (const block of fn.body.blocks.values()) {
|
|
53314
|
+
for (const instr of block.instructions) {
|
|
53315
|
+
const { value } = instr;
|
|
53316
|
+
switch (value.kind) {
|
|
53317
|
+
case 'FunctionExpression': {
|
|
53318
|
+
if (hasKnownNonRenderCall(value.loweredFunc.func)) {
|
|
53319
|
+
instr.value = {
|
|
53320
|
+
kind: 'Primitive',
|
|
53321
|
+
value: undefined,
|
|
53322
|
+
loc: value.loc,
|
|
53323
|
+
};
|
|
53324
|
+
}
|
|
53325
|
+
break;
|
|
53326
|
+
}
|
|
53327
|
+
case 'JsxExpression': {
|
|
53328
|
+
if (value.tag.kind === 'BuiltinTag' &&
|
|
53329
|
+
value.tag.name.indexOf('-') === -1) {
|
|
53330
|
+
const tag = value.tag.name;
|
|
53331
|
+
retainWhere(value.props, prop => {
|
|
53332
|
+
return (prop.kind === 'JsxSpreadAttribute' ||
|
|
53333
|
+
(!isKnownEventHandler(tag, prop.name) && prop.name !== 'ref'));
|
|
53334
|
+
});
|
|
53335
|
+
}
|
|
53336
|
+
break;
|
|
53337
|
+
}
|
|
53338
|
+
case 'Destructure': {
|
|
53339
|
+
if (inlinedState.has(value.value.identifier.id)) {
|
|
53340
|
+
CompilerError.invariant(value.lvalue.pattern.kind === 'ArrayPattern' &&
|
|
53341
|
+
value.lvalue.pattern.items.length >= 1 &&
|
|
53342
|
+
value.lvalue.pattern.items[0].kind === 'Identifier', {
|
|
53343
|
+
reason: 'Expected a valid destructuring pattern for inlined state',
|
|
53344
|
+
description: null,
|
|
53345
|
+
details: [
|
|
53346
|
+
{
|
|
53347
|
+
kind: 'error',
|
|
53348
|
+
message: 'Expected a valid destructuring pattern',
|
|
53349
|
+
loc: value.loc,
|
|
53350
|
+
},
|
|
53351
|
+
],
|
|
53352
|
+
});
|
|
53353
|
+
const store = {
|
|
53354
|
+
kind: 'StoreLocal',
|
|
53355
|
+
loc: value.loc,
|
|
53356
|
+
type: null,
|
|
53357
|
+
lvalue: {
|
|
53358
|
+
kind: value.lvalue.kind,
|
|
53359
|
+
place: value.lvalue.pattern.items[0],
|
|
53360
|
+
},
|
|
53361
|
+
value: value.value,
|
|
53362
|
+
};
|
|
53363
|
+
instr.value = store;
|
|
53364
|
+
}
|
|
53365
|
+
break;
|
|
53366
|
+
}
|
|
53367
|
+
case 'MethodCall':
|
|
53368
|
+
case 'CallExpression': {
|
|
53369
|
+
const calleee = value.kind === 'CallExpression' ? value.callee : value.property;
|
|
53370
|
+
const hookKind = getHookKind(fn.env, calleee.identifier);
|
|
53371
|
+
switch (hookKind) {
|
|
53372
|
+
case 'useEffectEvent': {
|
|
53373
|
+
if (value.args.length === 1 &&
|
|
53374
|
+
value.args[0].kind === 'Identifier') {
|
|
53375
|
+
const load = {
|
|
53376
|
+
kind: 'LoadLocal',
|
|
53377
|
+
place: value.args[0],
|
|
53378
|
+
loc: value.loc,
|
|
53379
|
+
};
|
|
53380
|
+
instr.value = load;
|
|
53381
|
+
}
|
|
53382
|
+
break;
|
|
53383
|
+
}
|
|
53384
|
+
case 'useEffect':
|
|
53385
|
+
case 'useLayoutEffect':
|
|
53386
|
+
case 'useInsertionEffect': {
|
|
53387
|
+
instr.value = {
|
|
53388
|
+
kind: 'Primitive',
|
|
53389
|
+
value: undefined,
|
|
53390
|
+
loc: value.loc,
|
|
53391
|
+
};
|
|
53392
|
+
break;
|
|
53393
|
+
}
|
|
53394
|
+
case 'useReducer':
|
|
53395
|
+
case 'useState': {
|
|
53396
|
+
const replace = inlinedState.get(instr.lvalue.identifier.id);
|
|
53397
|
+
if (replace != null) {
|
|
53398
|
+
instr.value = replace;
|
|
53399
|
+
}
|
|
53400
|
+
break;
|
|
53401
|
+
}
|
|
53402
|
+
}
|
|
53403
|
+
}
|
|
53404
|
+
}
|
|
53405
|
+
}
|
|
53406
|
+
}
|
|
53407
|
+
}
|
|
53408
|
+
function hasKnownNonRenderCall(fn) {
|
|
53409
|
+
for (const block of fn.body.blocks.values()) {
|
|
53410
|
+
for (const instr of block.instructions) {
|
|
53411
|
+
if (instr.value.kind === 'CallExpression' &&
|
|
53412
|
+
(isSetStateType(instr.value.callee.identifier) ||
|
|
53413
|
+
isStartTransitionType(instr.value.callee.identifier))) {
|
|
53414
|
+
return true;
|
|
53415
|
+
}
|
|
53416
|
+
}
|
|
53417
|
+
}
|
|
53418
|
+
return false;
|
|
53419
|
+
}
|
|
53420
|
+
const EVENT_HANDLER_PATTERN = /^on[A-Z]/;
|
|
53421
|
+
function isKnownEventHandler(_tag, prop) {
|
|
53422
|
+
return EVENT_HANDLER_PATTERN.test(prop);
|
|
53423
|
+
}
|
|
53424
|
+
|
|
53425
|
+
function validateExhaustiveDependencies(fn) {
|
|
53426
|
+
const reactive = collectReactiveIdentifiersHIR(fn);
|
|
53427
|
+
const temporaries = new Map();
|
|
53428
|
+
for (const param of fn.params) {
|
|
53429
|
+
const place = param.kind === 'Identifier' ? param : param.place;
|
|
53430
|
+
temporaries.set(place.identifier.id, {
|
|
53431
|
+
kind: 'Local',
|
|
53432
|
+
identifier: place.identifier,
|
|
53433
|
+
path: [],
|
|
53434
|
+
context: false,
|
|
53435
|
+
loc: place.loc,
|
|
53436
|
+
});
|
|
53437
|
+
}
|
|
53438
|
+
const error = new CompilerError();
|
|
53439
|
+
let startMemo = null;
|
|
53440
|
+
function onStartMemoize(value, dependencies, locals) {
|
|
53441
|
+
CompilerError.simpleInvariant(startMemo == null, {
|
|
53442
|
+
reason: 'Unexpected nested memo calls',
|
|
53443
|
+
loc: value.loc,
|
|
53444
|
+
});
|
|
53445
|
+
startMemo = value;
|
|
53446
|
+
dependencies.clear();
|
|
53447
|
+
locals.clear();
|
|
53448
|
+
}
|
|
53449
|
+
function onFinishMemoize(value, dependencies, locals) {
|
|
53450
|
+
var _b, _c, _d;
|
|
53451
|
+
CompilerError.simpleInvariant(startMemo != null && startMemo.manualMemoId === value.manualMemoId, {
|
|
53452
|
+
reason: 'Found FinishMemoize without corresponding StartMemoize',
|
|
53453
|
+
loc: value.loc,
|
|
53454
|
+
});
|
|
53455
|
+
visitCandidateDependency(value.decl, temporaries, dependencies, locals);
|
|
53456
|
+
const inferred = Array.from(dependencies);
|
|
53457
|
+
inferred.sort((a, b) => {
|
|
53458
|
+
var _a, _b;
|
|
53459
|
+
if (a.kind === 'Global' && b.kind == 'Global') {
|
|
53460
|
+
return a.binding.name.localeCompare(b.binding.name);
|
|
53461
|
+
}
|
|
53462
|
+
else if (a.kind == 'Local' && b.kind == 'Local') {
|
|
53463
|
+
CompilerError.simpleInvariant(a.identifier.name != null &&
|
|
53464
|
+
a.identifier.name.kind === 'named' &&
|
|
53465
|
+
b.identifier.name != null &&
|
|
53466
|
+
b.identifier.name.kind === 'named', {
|
|
53467
|
+
reason: 'Expected dependencies to be named variables',
|
|
53468
|
+
loc: a.loc,
|
|
53469
|
+
});
|
|
53470
|
+
if (a.identifier.id !== b.identifier.id) {
|
|
53471
|
+
return a.identifier.name.value.localeCompare(b.identifier.name.value);
|
|
53472
|
+
}
|
|
53473
|
+
if (a.path.length !== b.path.length) {
|
|
53474
|
+
return a.path.length - b.path.length;
|
|
53475
|
+
}
|
|
53476
|
+
for (let i = 0; i < a.path.length; i++) {
|
|
53477
|
+
const aProperty = a.path[i];
|
|
53478
|
+
const bProperty = b.path[i];
|
|
53479
|
+
const aOptional = aProperty.optional ? 0 : 1;
|
|
53480
|
+
const bOptional = bProperty.optional ? 0 : 1;
|
|
53481
|
+
if (aOptional !== bOptional) {
|
|
53482
|
+
return aOptional - bOptional;
|
|
53483
|
+
}
|
|
53484
|
+
else if (aProperty.property !== bProperty.property) {
|
|
53485
|
+
return String(aProperty.property).localeCompare(String(bProperty.property));
|
|
53486
|
+
}
|
|
53487
|
+
}
|
|
53488
|
+
return 0;
|
|
53489
|
+
}
|
|
53490
|
+
else {
|
|
53491
|
+
const aName = a.kind === 'Global' ? a.binding.name : (_a = a.identifier.name) === null || _a === void 0 ? void 0 : _a.value;
|
|
53492
|
+
const bName = b.kind === 'Global' ? b.binding.name : (_b = b.identifier.name) === null || _b === void 0 ? void 0 : _b.value;
|
|
53493
|
+
if (aName != null && bName != null) {
|
|
53494
|
+
return aName.localeCompare(bName);
|
|
53495
|
+
}
|
|
53496
|
+
return 0;
|
|
53497
|
+
}
|
|
53498
|
+
});
|
|
53499
|
+
retainWhere(inferred, (dep, ix) => {
|
|
53500
|
+
const match = inferred.findIndex(prevDep => {
|
|
53501
|
+
return (isEqualTemporary(prevDep, dep) ||
|
|
53502
|
+
(prevDep.kind === 'Local' &&
|
|
53503
|
+
dep.kind === 'Local' &&
|
|
53504
|
+
prevDep.identifier.id === dep.identifier.id &&
|
|
53505
|
+
isSubPath(prevDep.path, dep.path)));
|
|
53506
|
+
});
|
|
53507
|
+
return match === -1 || match >= ix;
|
|
53508
|
+
});
|
|
53509
|
+
const manualDependencies = (_b = startMemo.deps) !== null && _b !== void 0 ? _b : [];
|
|
53510
|
+
const matched = new Set();
|
|
53511
|
+
const missing = [];
|
|
53512
|
+
const extra = [];
|
|
53513
|
+
for (const inferredDependency of inferred) {
|
|
53514
|
+
if (inferredDependency.kind === 'Global') {
|
|
53515
|
+
for (const manualDependency of manualDependencies) {
|
|
53516
|
+
if (manualDependency.root.kind === 'Global' &&
|
|
53517
|
+
manualDependency.root.identifierName ===
|
|
53518
|
+
inferredDependency.binding.name) {
|
|
53519
|
+
matched.add(manualDependency);
|
|
53520
|
+
extra.push(manualDependency);
|
|
53521
|
+
}
|
|
53522
|
+
}
|
|
53523
|
+
continue;
|
|
53524
|
+
}
|
|
53525
|
+
CompilerError.simpleInvariant(inferredDependency.kind === 'Local', {
|
|
53526
|
+
reason: 'Unexpected function dependency',
|
|
53527
|
+
loc: value.loc,
|
|
53528
|
+
});
|
|
53529
|
+
const isRequiredDependency = reactive.has(inferredDependency.identifier.id) ||
|
|
53530
|
+
!isStableType(inferredDependency.identifier);
|
|
53531
|
+
let hasMatchingManualDependency = false;
|
|
53532
|
+
for (const manualDependency of manualDependencies) {
|
|
53533
|
+
if (manualDependency.root.kind === 'NamedLocal' &&
|
|
53534
|
+
manualDependency.root.value.identifier.id ===
|
|
53535
|
+
inferredDependency.identifier.id &&
|
|
53536
|
+
(areEqualPaths(manualDependency.path, inferredDependency.path) ||
|
|
53537
|
+
isSubPath(manualDependency.path, inferredDependency.path))) {
|
|
53538
|
+
hasMatchingManualDependency = true;
|
|
53539
|
+
matched.add(manualDependency);
|
|
53540
|
+
if (!isRequiredDependency) {
|
|
53541
|
+
extra.push(manualDependency);
|
|
53542
|
+
}
|
|
53543
|
+
}
|
|
53544
|
+
}
|
|
53545
|
+
if (isRequiredDependency && !hasMatchingManualDependency) {
|
|
53546
|
+
missing.push(inferredDependency);
|
|
53547
|
+
}
|
|
53548
|
+
}
|
|
53549
|
+
for (const dep of (_c = startMemo.deps) !== null && _c !== void 0 ? _c : []) {
|
|
53550
|
+
if (matched.has(dep)) {
|
|
53551
|
+
continue;
|
|
53552
|
+
}
|
|
53553
|
+
extra.push(dep);
|
|
53554
|
+
}
|
|
53555
|
+
if (missing.length !== 0 || extra.length !== 0) {
|
|
53556
|
+
let suggestions = null;
|
|
53557
|
+
if (startMemo.depsLoc != null && typeof startMemo.depsLoc !== 'symbol') {
|
|
53558
|
+
suggestions = [
|
|
53559
|
+
{
|
|
53560
|
+
description: 'Update dependencies',
|
|
53561
|
+
range: [startMemo.depsLoc.start.index, startMemo.depsLoc.end.index],
|
|
53562
|
+
op: CompilerSuggestionOperation.Replace,
|
|
53563
|
+
text: `[${inferred.map(printInferredDependency).join(', ')}]`,
|
|
53564
|
+
},
|
|
53565
|
+
];
|
|
53566
|
+
}
|
|
53567
|
+
if (missing.length !== 0) {
|
|
53568
|
+
const diagnostic = CompilerDiagnostic.create({
|
|
53569
|
+
category: ErrorCategory.MemoDependencies,
|
|
53570
|
+
reason: 'Found non-exhaustive dependencies',
|
|
53571
|
+
description: 'Missing dependencies can cause a value not to update when those inputs change, ' +
|
|
53572
|
+
'resulting in stale UI',
|
|
53573
|
+
suggestions,
|
|
53574
|
+
});
|
|
53575
|
+
for (const dep of missing) {
|
|
53576
|
+
let reactiveStableValueHint = '';
|
|
53577
|
+
if (isStableType(dep.identifier)) {
|
|
53578
|
+
reactiveStableValueHint =
|
|
53579
|
+
'. Refs, setState functions, and other "stable" values generally do not need to be added as dependencies, but this variable may change over time to point to different values';
|
|
53580
|
+
}
|
|
53581
|
+
diagnostic.withDetails({
|
|
53582
|
+
kind: 'error',
|
|
53583
|
+
message: `Missing dependency \`${printInferredDependency(dep)}\`${reactiveStableValueHint}`,
|
|
53584
|
+
loc: dep.loc,
|
|
53585
|
+
});
|
|
53586
|
+
}
|
|
53587
|
+
error.pushDiagnostic(diagnostic);
|
|
53588
|
+
}
|
|
53589
|
+
else if (extra.length !== 0) {
|
|
53590
|
+
const diagnostic = CompilerDiagnostic.create({
|
|
53591
|
+
category: ErrorCategory.MemoDependencies,
|
|
53592
|
+
reason: 'Found unnecessary memoization dependencies',
|
|
53593
|
+
description: 'Unnecessary dependencies can cause a value to update more often than necessary, ' +
|
|
53594
|
+
'which can cause effects to run more than expected',
|
|
53595
|
+
});
|
|
53596
|
+
diagnostic.withDetails({
|
|
53597
|
+
kind: 'error',
|
|
53598
|
+
message: `Unnecessary dependencies ${extra.map(dep => `\`${printManualMemoDependency(dep)}\``).join(', ')}`,
|
|
53599
|
+
loc: (_d = startMemo.depsLoc) !== null && _d !== void 0 ? _d : value.loc,
|
|
53600
|
+
});
|
|
53601
|
+
error.pushDiagnostic(diagnostic);
|
|
53602
|
+
}
|
|
53603
|
+
}
|
|
53604
|
+
dependencies.clear();
|
|
53605
|
+
locals.clear();
|
|
53606
|
+
startMemo = null;
|
|
53607
|
+
}
|
|
53608
|
+
collectDependencies(fn, temporaries, {
|
|
53609
|
+
onStartMemoize,
|
|
53610
|
+
onFinishMemoize,
|
|
53611
|
+
}, false);
|
|
53612
|
+
return error.asResult();
|
|
53613
|
+
}
|
|
53614
|
+
function addDependency(dep, dependencies, locals) {
|
|
53615
|
+
if (dep.kind === 'Function') {
|
|
53616
|
+
for (const x of dep.dependencies) {
|
|
53617
|
+
addDependency(x, dependencies, locals);
|
|
53618
|
+
}
|
|
53619
|
+
}
|
|
53620
|
+
else if (dep.kind === 'Global') {
|
|
53621
|
+
dependencies.add(dep);
|
|
53622
|
+
}
|
|
53623
|
+
else if (!locals.has(dep.identifier.id)) {
|
|
53624
|
+
dependencies.add(dep);
|
|
53625
|
+
}
|
|
53626
|
+
}
|
|
53627
|
+
function visitCandidateDependency(place, temporaries, dependencies, locals) {
|
|
53628
|
+
const dep = temporaries.get(place.identifier.id);
|
|
53629
|
+
if (dep != null) {
|
|
53630
|
+
addDependency(dep, dependencies, locals);
|
|
53631
|
+
}
|
|
53632
|
+
}
|
|
53633
|
+
function collectDependencies(fn, temporaries, callbacks, isFunctionExpression) {
|
|
53634
|
+
var _a;
|
|
53635
|
+
const optionals = findOptionalPlaces(fn);
|
|
53636
|
+
const locals = new Set();
|
|
53637
|
+
if (isFunctionExpression) {
|
|
53638
|
+
for (const param of fn.params) {
|
|
53639
|
+
const place = param.kind === 'Identifier' ? param : param.place;
|
|
53640
|
+
locals.add(place.identifier.id);
|
|
53641
|
+
}
|
|
53642
|
+
}
|
|
53643
|
+
const dependencies = new Set();
|
|
53644
|
+
function visit(place) {
|
|
53645
|
+
visitCandidateDependency(place, temporaries, dependencies, locals);
|
|
53646
|
+
}
|
|
53647
|
+
for (const block of fn.body.blocks.values()) {
|
|
53648
|
+
for (const phi of block.phis) {
|
|
53649
|
+
let deps = null;
|
|
53650
|
+
for (const operand of phi.operands.values()) {
|
|
53651
|
+
const dep = temporaries.get(operand.identifier.id);
|
|
53652
|
+
if (dep == null) {
|
|
53653
|
+
continue;
|
|
53654
|
+
}
|
|
53655
|
+
if (deps == null) {
|
|
53656
|
+
deps = [dep];
|
|
53657
|
+
}
|
|
53658
|
+
else {
|
|
53659
|
+
deps.push(dep);
|
|
53660
|
+
}
|
|
53661
|
+
}
|
|
53662
|
+
if (deps == null) {
|
|
53663
|
+
continue;
|
|
53664
|
+
}
|
|
53665
|
+
else if (deps.length === 1) {
|
|
53666
|
+
temporaries.set(phi.place.identifier.id, deps[0]);
|
|
53667
|
+
}
|
|
53668
|
+
else {
|
|
53669
|
+
temporaries.set(phi.place.identifier.id, {
|
|
53670
|
+
kind: 'Function',
|
|
53671
|
+
dependencies: new Set(deps),
|
|
53672
|
+
});
|
|
53673
|
+
}
|
|
53674
|
+
}
|
|
53675
|
+
for (const instr of block.instructions) {
|
|
53676
|
+
const { lvalue, value } = instr;
|
|
53677
|
+
switch (value.kind) {
|
|
53678
|
+
case 'LoadGlobal': {
|
|
53679
|
+
temporaries.set(lvalue.identifier.id, {
|
|
53680
|
+
kind: 'Global',
|
|
53681
|
+
binding: value.binding,
|
|
53682
|
+
});
|
|
53683
|
+
break;
|
|
53684
|
+
}
|
|
53685
|
+
case 'LoadContext':
|
|
53686
|
+
case 'LoadLocal': {
|
|
53687
|
+
if (locals.has(value.place.identifier.id)) {
|
|
53688
|
+
break;
|
|
53689
|
+
}
|
|
53690
|
+
const temp = temporaries.get(value.place.identifier.id);
|
|
53691
|
+
if (temp != null) {
|
|
53692
|
+
if (temp.kind === 'Local') {
|
|
53693
|
+
const local = Object.assign(Object.assign({}, temp), { loc: value.place.loc });
|
|
53694
|
+
temporaries.set(lvalue.identifier.id, local);
|
|
53695
|
+
}
|
|
53696
|
+
else {
|
|
53697
|
+
temporaries.set(lvalue.identifier.id, temp);
|
|
53698
|
+
}
|
|
53699
|
+
}
|
|
53700
|
+
break;
|
|
53701
|
+
}
|
|
53702
|
+
case 'DeclareLocal': {
|
|
53703
|
+
const local = {
|
|
53704
|
+
kind: 'Local',
|
|
53705
|
+
identifier: value.lvalue.place.identifier,
|
|
53706
|
+
path: [],
|
|
53707
|
+
context: false,
|
|
53708
|
+
loc: value.lvalue.place.loc,
|
|
53709
|
+
};
|
|
53710
|
+
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
53711
|
+
locals.add(value.lvalue.place.identifier.id);
|
|
53712
|
+
break;
|
|
53713
|
+
}
|
|
53714
|
+
case 'StoreLocal': {
|
|
53715
|
+
if (value.lvalue.place.identifier.name == null) {
|
|
53716
|
+
const temp = temporaries.get(value.value.identifier.id);
|
|
53717
|
+
if (temp != null) {
|
|
53718
|
+
temporaries.set(value.lvalue.place.identifier.id, temp);
|
|
53719
|
+
}
|
|
53720
|
+
break;
|
|
53721
|
+
}
|
|
53722
|
+
visit(value.value);
|
|
53723
|
+
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
53724
|
+
const local = {
|
|
53725
|
+
kind: 'Local',
|
|
53726
|
+
identifier: value.lvalue.place.identifier,
|
|
53727
|
+
path: [],
|
|
53728
|
+
context: false,
|
|
53729
|
+
loc: value.lvalue.place.loc,
|
|
53730
|
+
};
|
|
53731
|
+
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
53732
|
+
locals.add(value.lvalue.place.identifier.id);
|
|
53733
|
+
}
|
|
53734
|
+
break;
|
|
53735
|
+
}
|
|
53736
|
+
case 'DeclareContext': {
|
|
53737
|
+
const local = {
|
|
53738
|
+
kind: 'Local',
|
|
53739
|
+
identifier: value.lvalue.place.identifier,
|
|
53740
|
+
path: [],
|
|
53741
|
+
context: true,
|
|
53742
|
+
loc: value.lvalue.place.loc,
|
|
53743
|
+
};
|
|
53744
|
+
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
53745
|
+
break;
|
|
53746
|
+
}
|
|
53747
|
+
case 'StoreContext': {
|
|
53748
|
+
visit(value.value);
|
|
53749
|
+
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
53750
|
+
const local = {
|
|
53751
|
+
kind: 'Local',
|
|
53752
|
+
identifier: value.lvalue.place.identifier,
|
|
53753
|
+
path: [],
|
|
53754
|
+
context: true,
|
|
53755
|
+
loc: value.lvalue.place.loc,
|
|
53756
|
+
};
|
|
53757
|
+
temporaries.set(value.lvalue.place.identifier.id, local);
|
|
53758
|
+
locals.add(value.lvalue.place.identifier.id);
|
|
53759
|
+
}
|
|
53760
|
+
break;
|
|
53761
|
+
}
|
|
53762
|
+
case 'Destructure': {
|
|
53763
|
+
visit(value.value);
|
|
53764
|
+
if (value.lvalue.kind !== InstructionKind.Reassign) {
|
|
53765
|
+
for (const lvalue of eachInstructionValueLValue(value)) {
|
|
53766
|
+
const local = {
|
|
53767
|
+
kind: 'Local',
|
|
53768
|
+
identifier: lvalue.identifier,
|
|
53769
|
+
path: [],
|
|
53770
|
+
context: false,
|
|
53771
|
+
loc: lvalue.loc,
|
|
53772
|
+
};
|
|
53773
|
+
temporaries.set(lvalue.identifier.id, local);
|
|
53774
|
+
locals.add(lvalue.identifier.id);
|
|
53775
|
+
}
|
|
53776
|
+
}
|
|
53777
|
+
break;
|
|
53778
|
+
}
|
|
53779
|
+
case 'PropertyLoad': {
|
|
53780
|
+
if (typeof value.property === 'number' ||
|
|
53781
|
+
(isUseRefType(value.object.identifier) &&
|
|
53782
|
+
value.property === 'current')) {
|
|
53783
|
+
visit(value.object);
|
|
53784
|
+
break;
|
|
53785
|
+
}
|
|
53786
|
+
const object = temporaries.get(value.object.identifier.id);
|
|
53787
|
+
if (object != null && object.kind === 'Local') {
|
|
53788
|
+
const optional = (_a = optionals.get(value.object.identifier.id)) !== null && _a !== void 0 ? _a : false;
|
|
53789
|
+
const local = {
|
|
53790
|
+
kind: 'Local',
|
|
53791
|
+
identifier: object.identifier,
|
|
53792
|
+
context: object.context,
|
|
53793
|
+
path: [
|
|
53794
|
+
...object.path,
|
|
53795
|
+
{
|
|
53796
|
+
optional,
|
|
53797
|
+
property: value.property,
|
|
53798
|
+
},
|
|
53799
|
+
],
|
|
53800
|
+
loc: value.loc,
|
|
53801
|
+
};
|
|
53802
|
+
temporaries.set(lvalue.identifier.id, local);
|
|
53803
|
+
}
|
|
53804
|
+
break;
|
|
53805
|
+
}
|
|
53806
|
+
case 'FunctionExpression':
|
|
53807
|
+
case 'ObjectMethod': {
|
|
53808
|
+
const functionDeps = collectDependencies(value.loweredFunc.func, temporaries, null, true);
|
|
53809
|
+
temporaries.set(lvalue.identifier.id, functionDeps);
|
|
53810
|
+
addDependency(functionDeps, dependencies, locals);
|
|
53811
|
+
break;
|
|
53812
|
+
}
|
|
53813
|
+
case 'StartMemoize': {
|
|
53814
|
+
const onStartMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onStartMemoize;
|
|
53815
|
+
if (onStartMemoize != null) {
|
|
53816
|
+
onStartMemoize(value, dependencies, locals);
|
|
53817
|
+
}
|
|
53818
|
+
break;
|
|
53819
|
+
}
|
|
53820
|
+
case 'FinishMemoize': {
|
|
53821
|
+
const onFinishMemoize = callbacks === null || callbacks === void 0 ? void 0 : callbacks.onFinishMemoize;
|
|
53822
|
+
if (onFinishMemoize != null) {
|
|
53823
|
+
onFinishMemoize(value, dependencies, locals);
|
|
53824
|
+
}
|
|
53825
|
+
break;
|
|
53826
|
+
}
|
|
53827
|
+
case 'MethodCall': {
|
|
53828
|
+
for (const operand of eachInstructionValueOperand(value)) {
|
|
53829
|
+
if (operand.identifier.id === value.property.identifier.id) {
|
|
53830
|
+
continue;
|
|
53831
|
+
}
|
|
53832
|
+
visit(operand);
|
|
53833
|
+
}
|
|
53834
|
+
break;
|
|
53835
|
+
}
|
|
53836
|
+
default: {
|
|
53837
|
+
for (const operand of eachInstructionValueOperand(value)) {
|
|
53838
|
+
visit(operand);
|
|
53839
|
+
}
|
|
53840
|
+
for (const lvalue of eachInstructionLValue(instr)) {
|
|
53841
|
+
locals.add(lvalue.identifier.id);
|
|
53842
|
+
}
|
|
53843
|
+
}
|
|
53844
|
+
}
|
|
53845
|
+
}
|
|
53846
|
+
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
53847
|
+
if (optionals.has(operand.identifier.id)) {
|
|
53848
|
+
continue;
|
|
53849
|
+
}
|
|
53850
|
+
visit(operand);
|
|
53851
|
+
}
|
|
53852
|
+
}
|
|
53853
|
+
return { kind: 'Function', dependencies };
|
|
53854
|
+
}
|
|
53855
|
+
function printInferredDependency(dep) {
|
|
53856
|
+
switch (dep.kind) {
|
|
53857
|
+
case 'Global': {
|
|
53858
|
+
return dep.binding.name;
|
|
53859
|
+
}
|
|
53860
|
+
case 'Local': {
|
|
53861
|
+
CompilerError.simpleInvariant(dep.identifier.name != null && dep.identifier.name.kind === 'named', {
|
|
53862
|
+
reason: 'Expected dependencies to be named variables',
|
|
53863
|
+
loc: dep.loc,
|
|
53864
|
+
});
|
|
53865
|
+
return `${dep.identifier.name.value}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
|
|
53866
|
+
}
|
|
53867
|
+
}
|
|
53868
|
+
}
|
|
53869
|
+
function printManualMemoDependency(dep) {
|
|
53870
|
+
let identifierName;
|
|
53871
|
+
if (dep.root.kind === 'Global') {
|
|
53872
|
+
identifierName = dep.root.identifierName;
|
|
53873
|
+
}
|
|
53874
|
+
else {
|
|
53875
|
+
const name = dep.root.value.identifier.name;
|
|
53876
|
+
CompilerError.simpleInvariant(name != null && name.kind === 'named', {
|
|
53877
|
+
reason: 'Expected manual dependencies to be named variables',
|
|
53878
|
+
loc: dep.root.value.loc,
|
|
53879
|
+
});
|
|
53880
|
+
identifierName = name.value;
|
|
53881
|
+
}
|
|
53882
|
+
return `${identifierName}${dep.path.map(p => (p.optional ? '?' : '') + '.' + p.property).join('')}`;
|
|
53883
|
+
}
|
|
53884
|
+
function isEqualTemporary(a, b) {
|
|
53885
|
+
switch (a.kind) {
|
|
53886
|
+
case 'Function': {
|
|
53887
|
+
return false;
|
|
53888
|
+
}
|
|
53889
|
+
case 'Global': {
|
|
53890
|
+
return b.kind === 'Global' && a.binding.name === b.binding.name;
|
|
53891
|
+
}
|
|
53892
|
+
case 'Local': {
|
|
53893
|
+
return (b.kind === 'Local' &&
|
|
53894
|
+
a.identifier.id === b.identifier.id &&
|
|
53895
|
+
areEqualPaths(a.path, b.path));
|
|
53896
|
+
}
|
|
53897
|
+
}
|
|
53898
|
+
}
|
|
53899
|
+
function collectReactiveIdentifiersHIR(fn) {
|
|
53900
|
+
const reactive = new Set();
|
|
53901
|
+
for (const block of fn.body.blocks.values()) {
|
|
53902
|
+
for (const instr of block.instructions) {
|
|
53903
|
+
for (const lvalue of eachInstructionLValue(instr)) {
|
|
53904
|
+
if (lvalue.reactive) {
|
|
53905
|
+
reactive.add(lvalue.identifier.id);
|
|
53906
|
+
}
|
|
53907
|
+
}
|
|
53908
|
+
for (const operand of eachInstructionValueOperand(instr.value)) {
|
|
53909
|
+
if (operand.reactive) {
|
|
53910
|
+
reactive.add(operand.identifier.id);
|
|
53911
|
+
}
|
|
53912
|
+
}
|
|
53913
|
+
}
|
|
53914
|
+
for (const operand of eachTerminalOperand(block.terminal)) {
|
|
53915
|
+
if (operand.reactive) {
|
|
53916
|
+
reactive.add(operand.identifier.id);
|
|
53917
|
+
}
|
|
53918
|
+
}
|
|
53919
|
+
}
|
|
53920
|
+
return reactive;
|
|
53921
|
+
}
|
|
53922
|
+
function findOptionalPlaces(fn) {
|
|
53923
|
+
const optionals = new Map();
|
|
53924
|
+
const visited = new Set();
|
|
53925
|
+
for (const [, block] of fn.body.blocks) {
|
|
53926
|
+
if (visited.has(block.id)) {
|
|
53927
|
+
continue;
|
|
53928
|
+
}
|
|
53929
|
+
if (block.terminal.kind === 'optional') {
|
|
53930
|
+
visited.add(block.id);
|
|
53931
|
+
const optionalTerminal = block.terminal;
|
|
53932
|
+
let testBlock = fn.body.blocks.get(block.terminal.test);
|
|
53933
|
+
const queue = [block.terminal.optional];
|
|
53934
|
+
loop: while (true) {
|
|
53935
|
+
visited.add(testBlock.id);
|
|
53936
|
+
const terminal = testBlock.terminal;
|
|
53937
|
+
switch (terminal.kind) {
|
|
53938
|
+
case 'branch': {
|
|
53939
|
+
const isOptional = queue.pop();
|
|
53940
|
+
CompilerError.simpleInvariant(isOptional !== undefined, {
|
|
53941
|
+
reason: 'Expected an optional value for each optional test condition',
|
|
53942
|
+
loc: terminal.test.loc,
|
|
53943
|
+
});
|
|
53944
|
+
if (isOptional != null) {
|
|
53945
|
+
optionals.set(terminal.test.identifier.id, isOptional);
|
|
53946
|
+
}
|
|
53947
|
+
if (terminal.fallthrough === optionalTerminal.fallthrough) {
|
|
53948
|
+
const consequent = fn.body.blocks.get(terminal.consequent);
|
|
53949
|
+
const last = consequent.instructions.at(-1);
|
|
53950
|
+
if (last !== undefined && last.value.kind === 'StoreLocal') {
|
|
53951
|
+
if (isOptional != null) {
|
|
53952
|
+
optionals.set(last.value.value.identifier.id, isOptional);
|
|
53953
|
+
}
|
|
53954
|
+
}
|
|
53955
|
+
break loop;
|
|
53956
|
+
}
|
|
53957
|
+
else {
|
|
53958
|
+
testBlock = fn.body.blocks.get(terminal.fallthrough);
|
|
53959
|
+
}
|
|
53960
|
+
break;
|
|
53961
|
+
}
|
|
53962
|
+
case 'optional': {
|
|
53963
|
+
queue.push(terminal.optional);
|
|
53964
|
+
testBlock = fn.body.blocks.get(terminal.test);
|
|
53965
|
+
break;
|
|
53966
|
+
}
|
|
53967
|
+
case 'logical':
|
|
53968
|
+
case 'ternary': {
|
|
53969
|
+
queue.push(null);
|
|
53970
|
+
testBlock = fn.body.blocks.get(terminal.test);
|
|
53971
|
+
break;
|
|
53972
|
+
}
|
|
53973
|
+
case 'sequence': {
|
|
53974
|
+
testBlock = fn.body.blocks.get(terminal.block);
|
|
53975
|
+
break;
|
|
53976
|
+
}
|
|
53977
|
+
default: {
|
|
53978
|
+
CompilerError.simpleInvariant(false, {
|
|
53979
|
+
reason: `Unexpected terminal in optional`,
|
|
53980
|
+
loc: terminal.loc,
|
|
53981
|
+
});
|
|
53982
|
+
}
|
|
53983
|
+
}
|
|
53984
|
+
}
|
|
53985
|
+
CompilerError.simpleInvariant(queue.length === 0, {
|
|
53986
|
+
reason: 'Expected a matching number of conditional blocks and branch points',
|
|
53987
|
+
loc: block.terminal.loc,
|
|
53988
|
+
});
|
|
53989
|
+
}
|
|
53990
|
+
}
|
|
53991
|
+
return optionals;
|
|
53992
|
+
}
|
|
53993
|
+
|
|
53109
53994
|
function run(func, config, fnType, mode, programContext, logger, filename, code) {
|
|
53110
53995
|
var _a, _b;
|
|
53111
53996
|
const contextIdentifiers = findContextIdentifiers(func);
|
|
@@ -53128,7 +54013,7 @@ function runWithEnvironment(func, env) {
|
|
|
53128
54013
|
log({ kind: 'hir', name: 'PruneMaybeThrows', value: hir });
|
|
53129
54014
|
validateContextVariableLValues(hir);
|
|
53130
54015
|
validateUseMemo(hir).unwrap();
|
|
53131
|
-
if (env.
|
|
54016
|
+
if (env.enableDropManualMemoization &&
|
|
53132
54017
|
!env.config.enablePreserveExistingManualUseMemo &&
|
|
53133
54018
|
!env.config.disableMemoizationForDebugging &&
|
|
53134
54019
|
!env.config.enableChangeDetectionForDebugging) {
|
|
@@ -53154,7 +54039,7 @@ function runWithEnvironment(func, env) {
|
|
|
53154
54039
|
log({ kind: 'hir', name: 'ConstantPropagation', value: hir });
|
|
53155
54040
|
inferTypes(hir);
|
|
53156
54041
|
log({ kind: 'hir', name: 'InferTypes', value: hir });
|
|
53157
|
-
if (env.
|
|
54042
|
+
if (env.enableValidations) {
|
|
53158
54043
|
if (env.config.validateHooksUsage) {
|
|
53159
54044
|
validateHooksUsage(hir).unwrap();
|
|
53160
54045
|
}
|
|
@@ -53175,11 +54060,15 @@ function runWithEnvironment(func, env) {
|
|
|
53175
54060
|
log({ kind: 'hir', name: 'AnalyseFunctions', value: hir });
|
|
53176
54061
|
const mutabilityAliasingErrors = inferMutationAliasingEffects(hir);
|
|
53177
54062
|
log({ kind: 'hir', name: 'InferMutationAliasingEffects', value: hir });
|
|
53178
|
-
if (env.
|
|
54063
|
+
if (env.enableValidations) {
|
|
53179
54064
|
if (mutabilityAliasingErrors.isErr()) {
|
|
53180
54065
|
throw mutabilityAliasingErrors.unwrapErr();
|
|
53181
54066
|
}
|
|
53182
54067
|
}
|
|
54068
|
+
if (env.outputMode === 'ssr') {
|
|
54069
|
+
optimizeForSSR(hir);
|
|
54070
|
+
log({ kind: 'hir', name: 'OptimizeForSSR', value: hir });
|
|
54071
|
+
}
|
|
53183
54072
|
deadCodeElimination(hir);
|
|
53184
54073
|
log({ kind: 'hir', name: 'DeadCodeElimination', value: hir });
|
|
53185
54074
|
if (env.config.enableInstructionReordering) {
|
|
@@ -53192,13 +54081,13 @@ function runWithEnvironment(func, env) {
|
|
|
53192
54081
|
isFunctionExpression: false,
|
|
53193
54082
|
});
|
|
53194
54083
|
log({ kind: 'hir', name: 'InferMutationAliasingRanges', value: hir });
|
|
53195
|
-
if (env.
|
|
54084
|
+
if (env.enableValidations) {
|
|
53196
54085
|
if (mutabilityAliasingRangeErrors.isErr()) {
|
|
53197
54086
|
throw mutabilityAliasingRangeErrors.unwrapErr();
|
|
53198
54087
|
}
|
|
53199
54088
|
validateLocalsNotReassignedAfterRender(hir);
|
|
53200
54089
|
}
|
|
53201
|
-
if (env.
|
|
54090
|
+
if (env.enableValidations) {
|
|
53202
54091
|
if (env.config.assertValidMutableRanges) {
|
|
53203
54092
|
assertValidMutableRanges(hir);
|
|
53204
54093
|
}
|
|
@@ -53227,16 +54116,19 @@ function runWithEnvironment(func, env) {
|
|
|
53227
54116
|
}
|
|
53228
54117
|
inferReactivePlaces(hir);
|
|
53229
54118
|
log({ kind: 'hir', name: 'InferReactivePlaces', value: hir });
|
|
54119
|
+
if (env.config.validateExhaustiveMemoizationDependencies) {
|
|
54120
|
+
validateExhaustiveDependencies(hir).unwrap();
|
|
54121
|
+
}
|
|
53230
54122
|
rewriteInstructionKindsBasedOnReassignment(hir);
|
|
53231
54123
|
log({
|
|
53232
54124
|
kind: 'hir',
|
|
53233
54125
|
name: 'RewriteInstructionKindsBasedOnReassignment',
|
|
53234
54126
|
value: hir,
|
|
53235
54127
|
});
|
|
53236
|
-
if (env.
|
|
53237
|
-
|
|
53238
|
-
|
|
53239
|
-
|
|
54128
|
+
if (env.enableValidations && env.config.validateStaticComponents) {
|
|
54129
|
+
env.logErrors(validateStaticComponents(hir));
|
|
54130
|
+
}
|
|
54131
|
+
if (env.enableMemoization) {
|
|
53240
54132
|
inferReactiveScopeVariables(hir);
|
|
53241
54133
|
log({ kind: 'hir', name: 'InferReactiveScopeVariables', value: hir });
|
|
53242
54134
|
}
|
|
@@ -53816,7 +54708,7 @@ function isFilePartOfSources(sources, filename) {
|
|
|
53816
54708
|
return false;
|
|
53817
54709
|
}
|
|
53818
54710
|
function compileProgram(program, pass) {
|
|
53819
|
-
var _a;
|
|
54711
|
+
var _a, _b;
|
|
53820
54712
|
if (shouldSkipCompilation(program, pass)) {
|
|
53821
54713
|
return null;
|
|
53822
54714
|
}
|
|
@@ -53837,9 +54729,10 @@ function compileProgram(program, pass) {
|
|
|
53837
54729
|
});
|
|
53838
54730
|
const queue = findFunctionsToCompile(program, pass, programContext);
|
|
53839
54731
|
const compiledFns = [];
|
|
54732
|
+
const outputMode = (_b = pass.opts.outputMode) !== null && _b !== void 0 ? _b : (pass.opts.noEmit ? 'lint' : 'client');
|
|
53840
54733
|
while (queue.length !== 0) {
|
|
53841
54734
|
const current = queue.shift();
|
|
53842
|
-
const compiled = processFn(current.fn, current.fnType, programContext);
|
|
54735
|
+
const compiled = processFn(current.fn, current.fnType, programContext, outputMode);
|
|
53843
54736
|
if (compiled != null) {
|
|
53844
54737
|
for (const outlined of compiled.outlined) {
|
|
53845
54738
|
CompilerError.invariant(outlined.fn.outlined.length === 0, {
|
|
@@ -53921,7 +54814,7 @@ function findFunctionsToCompile(program, pass, programContext) {
|
|
|
53921
54814
|
}, Object.assign(Object.assign({}, pass), { opts: Object.assign(Object.assign({}, pass.opts), pass.opts), filename: (_a = pass.filename) !== null && _a !== void 0 ? _a : null }));
|
|
53922
54815
|
return queue;
|
|
53923
54816
|
}
|
|
53924
|
-
function processFn(fn, fnType, programContext) {
|
|
54817
|
+
function processFn(fn, fnType, programContext, outputMode) {
|
|
53925
54818
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
53926
54819
|
let directives;
|
|
53927
54820
|
if (fn.node.body.type !== 'BlockStatement') {
|
|
@@ -53942,7 +54835,7 @@ function processFn(fn, fnType, programContext) {
|
|
|
53942
54835
|
};
|
|
53943
54836
|
}
|
|
53944
54837
|
let compiledFn;
|
|
53945
|
-
const compileResult = tryCompileFunction(fn, fnType, programContext);
|
|
54838
|
+
const compileResult = tryCompileFunction(fn, fnType, programContext, outputMode);
|
|
53946
54839
|
if (compileResult.kind === 'error') {
|
|
53947
54840
|
if (directives.optOut != null) {
|
|
53948
54841
|
logError(compileResult.error, programContext, (_b = fn.node.loc) !== null && _b !== void 0 ? _b : null);
|
|
@@ -53950,11 +54843,16 @@ function processFn(fn, fnType, programContext) {
|
|
|
53950
54843
|
else {
|
|
53951
54844
|
handleError(compileResult.error, programContext, (_c = fn.node.loc) !== null && _c !== void 0 ? _c : null);
|
|
53952
54845
|
}
|
|
53953
|
-
|
|
53954
|
-
|
|
54846
|
+
if (outputMode === 'client') {
|
|
54847
|
+
const retryResult = retryCompileFunction(fn, fnType, programContext);
|
|
54848
|
+
if (retryResult == null) {
|
|
54849
|
+
return null;
|
|
54850
|
+
}
|
|
54851
|
+
compiledFn = retryResult;
|
|
54852
|
+
}
|
|
54853
|
+
else {
|
|
53955
54854
|
return null;
|
|
53956
54855
|
}
|
|
53957
|
-
compiledFn = retryResult;
|
|
53958
54856
|
}
|
|
53959
54857
|
else {
|
|
53960
54858
|
compiledFn = compileResult.compiledFn;
|
|
@@ -53982,7 +54880,7 @@ function processFn(fn, fnType, programContext) {
|
|
|
53982
54880
|
if (programContext.hasModuleScopeOptOut) {
|
|
53983
54881
|
return null;
|
|
53984
54882
|
}
|
|
53985
|
-
else if (programContext.opts.
|
|
54883
|
+
else if (programContext.opts.outputMode === 'lint') {
|
|
53986
54884
|
for (const loc of compiledFn.inferredEffectLocations) {
|
|
53987
54885
|
if (loc !== GeneratedSource) {
|
|
53988
54886
|
programContext.inferredEffectLocations.add(loc);
|
|
@@ -53998,7 +54896,7 @@ function processFn(fn, fnType, programContext) {
|
|
|
53998
54896
|
return compiledFn;
|
|
53999
54897
|
}
|
|
54000
54898
|
}
|
|
54001
|
-
function tryCompileFunction(fn, fnType, programContext) {
|
|
54899
|
+
function tryCompileFunction(fn, fnType, programContext, outputMode) {
|
|
54002
54900
|
const suppressionsInFunction = filterSuppressionsThatAffectFunction(programContext.suppressions, fn);
|
|
54003
54901
|
if (suppressionsInFunction.length > 0) {
|
|
54004
54902
|
return {
|
|
@@ -54009,7 +54907,7 @@ function tryCompileFunction(fn, fnType, programContext) {
|
|
|
54009
54907
|
try {
|
|
54010
54908
|
return {
|
|
54011
54909
|
kind: 'compile',
|
|
54012
|
-
compiledFn: compileFn(fn, programContext.opts.environment, fnType,
|
|
54910
|
+
compiledFn: compileFn(fn, programContext.opts.environment, fnType, outputMode, programContext, programContext.opts.logger, programContext.filename, programContext.code),
|
|
54013
54911
|
};
|
|
54014
54912
|
}
|
|
54015
54913
|
catch (err) {
|
|
@@ -54022,7 +54920,7 @@ function retryCompileFunction(fn, fnType, programContext) {
|
|
|
54022
54920
|
return null;
|
|
54023
54921
|
}
|
|
54024
54922
|
try {
|
|
54025
|
-
const retryResult = compileFn(fn, environment, fnType, '
|
|
54923
|
+
const retryResult = compileFn(fn, environment, fnType, 'client-no-memo', programContext, programContext.opts.logger, programContext.filename, programContext.code);
|
|
54026
54924
|
if (!retryResult.hasFireRewrite && !retryResult.hasInferredEffect) {
|
|
54027
54925
|
return null;
|
|
54028
54926
|
}
|
|
@@ -54698,6 +55596,12 @@ v4.z.enum([
|
|
|
54698
55596
|
'annotation',
|
|
54699
55597
|
'all',
|
|
54700
55598
|
]);
|
|
55599
|
+
v4.z.enum([
|
|
55600
|
+
'ssr',
|
|
55601
|
+
'client',
|
|
55602
|
+
'client-no-memo',
|
|
55603
|
+
'lint',
|
|
55604
|
+
]);
|
|
54701
55605
|
const defaultOptions = {
|
|
54702
55606
|
compilationMode: 'infer',
|
|
54703
55607
|
panicThreshold: 'none',
|
|
@@ -54705,6 +55609,7 @@ const defaultOptions = {
|
|
|
54705
55609
|
logger: null,
|
|
54706
55610
|
gating: null,
|
|
54707
55611
|
noEmit: false,
|
|
55612
|
+
outputMode: null,
|
|
54708
55613
|
dynamicGating: null,
|
|
54709
55614
|
eslintSuppressionRules: null,
|
|
54710
55615
|
flowSuppressions: true,
|
|
@@ -55123,7 +56028,7 @@ function BabelPluginReactCompiler(_babel) {
|
|
|
55123
56028
|
|
|
55124
56029
|
var _LRUCache_values, _LRUCache_headIdx;
|
|
55125
56030
|
const COMPILER_OPTIONS = {
|
|
55126
|
-
|
|
56031
|
+
outputMode: 'lint',
|
|
55127
56032
|
panicThreshold: 'none',
|
|
55128
56033
|
flowSuppressions: false,
|
|
55129
56034
|
environment: {
|