babel-plugin-react-compiler 0.0.0-experimental-dc8bd44-20241120 → 0.0.0-experimental-df7b47d-20241124

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.
Files changed (2) hide show
  1. package/dist/index.js +233 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -136714,6 +136714,17 @@ const EnvironmentConfigSchema = z.object({
136714
136714
  enableForest: z.boolean().default(false),
136715
136715
  enableUseTypeAnnotations: z.boolean().default(false),
136716
136716
  enableFunctionDependencyRewrite: z.boolean().default(true),
136717
+ enableOptionalDependencies: z.boolean().default(true),
136718
+ inferEffectDependencies: z
136719
+ .nullable(
136720
+ z.array(
136721
+ z.object({
136722
+ function: ExternalFunctionSchema,
136723
+ numRequiredArgs: z.number(),
136724
+ })
136725
+ )
136726
+ )
136727
+ .default(null),
136717
136728
  inlineJsxTransform: ReactElementSymbolSchema.nullable().default(null),
136718
136729
  validateHooksUsage: z.boolean().default(true),
136719
136730
  validateRefAccessDuringRender: z.boolean().default(true),
@@ -136777,6 +136788,19 @@ const testComplexConfigDefaults = {
136777
136788
  source: 'react-compiler-runtime',
136778
136789
  importSpecifierName: 'useContext_withSelector',
136779
136790
  },
136791
+ inferEffectDependencies: [
136792
+ {
136793
+ function: {source: 'react', importSpecifierName: 'useEffect'},
136794
+ numRequiredArgs: 1,
136795
+ },
136796
+ {
136797
+ function: {
136798
+ source: 'shared-runtime',
136799
+ importSpecifierName: 'useSpecialEffect',
136800
+ },
136801
+ numRequiredArgs: 2,
136802
+ },
136803
+ ],
136780
136804
  };
136781
136805
  function parseConfigPragmaForTests(pragma) {
136782
136806
  const maybeConfig = {};
@@ -141015,25 +141039,25 @@ function rewriteInstruction(instr, state) {
141015
141039
  if (instr.value.kind === 'Destructure') {
141016
141040
  switch (instr.value.lvalue.pattern.kind) {
141017
141041
  case 'ArrayPattern': {
141018
- let nextItems = null;
141019
- const originalItems = instr.value.lvalue.pattern.items;
141020
- for (let i = originalItems.length - 1; i >= 0; i--) {
141021
- const item = originalItems[i];
141042
+ let lastEntryIndex = 0;
141043
+ const items = instr.value.lvalue.pattern.items;
141044
+ for (let i = 0; i < items.length; i++) {
141045
+ const item = items[i];
141022
141046
  if (item.kind === 'Identifier') {
141023
- if (state.isIdOrNameUsed(item.identifier)) {
141024
- nextItems = originalItems.slice(0, i + 1);
141025
- break;
141047
+ if (!state.isIdOrNameUsed(item.identifier)) {
141048
+ items[i] = {kind: 'Hole'};
141049
+ } else {
141050
+ lastEntryIndex = i;
141026
141051
  }
141027
141052
  } else if (item.kind === 'Spread') {
141028
- if (state.isIdOrNameUsed(item.place.identifier)) {
141029
- nextItems = originalItems.slice(0, i + 1);
141030
- break;
141053
+ if (!state.isIdOrNameUsed(item.place.identifier)) {
141054
+ items[i] = {kind: 'Hole'};
141055
+ } else {
141056
+ lastEntryIndex = i;
141031
141057
  }
141032
141058
  }
141033
141059
  }
141034
- if (nextItems !== null) {
141035
- instr.value.lvalue.pattern.items = nextItems;
141036
- }
141060
+ items.length = lastEntryIndex + 1;
141037
141061
  break;
141038
141062
  }
141039
141063
  case 'ObjectPattern': {
@@ -151483,6 +151507,199 @@ function declareTemporary(env, block, result) {
151483
151507
  },
151484
151508
  });
151485
151509
  }
151510
+ function inferEffectDependencies(fn) {
151511
+ let hasRewrite = false;
151512
+ const fnExpressions = new Map();
151513
+ const autodepFnConfigs = new Map();
151514
+ for (const effectTarget of fn.env.config.inferEffectDependencies) {
151515
+ const moduleTargets = getOrInsertWith(
151516
+ autodepFnConfigs,
151517
+ effectTarget.function.source,
151518
+ () => new Map()
151519
+ );
151520
+ moduleTargets.set(
151521
+ effectTarget.function.importSpecifierName,
151522
+ effectTarget.numRequiredArgs
151523
+ );
151524
+ }
151525
+ const autodepFnLoads = new Map();
151526
+ const scopeInfos = new Map();
151527
+ const reactiveIds = inferReactiveIdentifiers(fn);
151528
+ for (const [, block] of fn.body.blocks) {
151529
+ if (
151530
+ block.terminal.kind === 'scope' ||
151531
+ block.terminal.kind === 'pruned-scope'
151532
+ ) {
151533
+ const scopeBlock = fn.body.blocks.get(block.terminal.block);
151534
+ scopeInfos.set(block.terminal.scope.id, {
151535
+ pruned: block.terminal.kind === 'pruned-scope',
151536
+ deps: block.terminal.scope.dependencies,
151537
+ hasSingleInstr:
151538
+ scopeBlock.instructions.length === 1 &&
151539
+ scopeBlock.terminal.kind === 'goto' &&
151540
+ scopeBlock.terminal.block === block.terminal.fallthrough,
151541
+ });
151542
+ }
151543
+ const rewriteInstrs = new Map();
151544
+ for (const instr of block.instructions) {
151545
+ const {value: value, lvalue: lvalue} = instr;
151546
+ if (value.kind === 'FunctionExpression') {
151547
+ fnExpressions.set(lvalue.identifier.id, instr);
151548
+ } else if (
151549
+ value.kind === 'LoadGlobal' &&
151550
+ value.binding.kind === 'ImportSpecifier'
151551
+ ) {
151552
+ const moduleTargets = autodepFnConfigs.get(value.binding.module);
151553
+ if (moduleTargets != null) {
151554
+ const numRequiredArgs = moduleTargets.get(value.binding.imported);
151555
+ if (numRequiredArgs != null) {
151556
+ autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
151557
+ }
151558
+ }
151559
+ } else if (
151560
+ value.kind === 'CallExpression' &&
151561
+ autodepFnLoads.get(value.callee.identifier.id) === value.args.length &&
151562
+ value.args[0].kind === 'Identifier'
151563
+ ) {
151564
+ const fnExpr = fnExpressions.get(value.args[0].identifier.id);
151565
+ if (fnExpr != null) {
151566
+ const scopeInfo =
151567
+ fnExpr.lvalue.identifier.scope != null
151568
+ ? scopeInfos.get(fnExpr.lvalue.identifier.scope.id)
151569
+ : null;
151570
+ CompilerError.invariant(scopeInfo != null, {
151571
+ reason: 'Expected function expression scope to exist',
151572
+ loc: value.loc,
151573
+ });
151574
+ if (scopeInfo.pruned || !scopeInfo.hasSingleInstr) {
151575
+ CompilerError.throwTodo({
151576
+ reason:
151577
+ '[InferEffectDependencies] Expected effect function to have non-pruned scope and its scope to have exactly one instruction',
151578
+ loc: fnExpr.loc,
151579
+ });
151580
+ }
151581
+ const effectDeps = [];
151582
+ const newInstructions = [];
151583
+ for (const dep of scopeInfo.deps) {
151584
+ const {place: place, instructions: instructions} =
151585
+ writeDependencyToInstructions(
151586
+ dep,
151587
+ reactiveIds.has(dep.identifier.id),
151588
+ fn.env,
151589
+ fnExpr.loc
151590
+ );
151591
+ newInstructions.push(...instructions);
151592
+ effectDeps.push(place);
151593
+ }
151594
+ const deps = {
151595
+ kind: 'ArrayExpression',
151596
+ elements: effectDeps,
151597
+ loc: GeneratedSource,
151598
+ };
151599
+ const depsPlace = createTemporaryPlace(fn.env, GeneratedSource);
151600
+ depsPlace.effect = exports.Effect.Read;
151601
+ newInstructions.push({
151602
+ id: makeInstructionId(0),
151603
+ loc: GeneratedSource,
151604
+ lvalue: Object.assign(Object.assign({}, depsPlace), {
151605
+ effect: exports.Effect.Mutate,
151606
+ }),
151607
+ value: deps,
151608
+ });
151609
+ value.args.push(
151610
+ Object.assign(Object.assign({}, depsPlace), {
151611
+ effect: exports.Effect.Freeze,
151612
+ })
151613
+ );
151614
+ rewriteInstrs.set(instr.id, newInstructions);
151615
+ }
151616
+ }
151617
+ }
151618
+ if (rewriteInstrs.size > 0) {
151619
+ hasRewrite = true;
151620
+ const newInstrs = [];
151621
+ for (const instr of block.instructions) {
151622
+ const newInstr = rewriteInstrs.get(instr.id);
151623
+ if (newInstr != null) {
151624
+ newInstrs.push(...newInstr, instr);
151625
+ } else {
151626
+ newInstrs.push(instr);
151627
+ }
151628
+ }
151629
+ block.instructions = newInstrs;
151630
+ }
151631
+ }
151632
+ if (hasRewrite) {
151633
+ markInstructionIds(fn.body);
151634
+ fixScopeAndIdentifierRanges(fn.body);
151635
+ }
151636
+ }
151637
+ function writeDependencyToInstructions(dep, reactive, env, loc) {
151638
+ const instructions = [];
151639
+ let currValue = createTemporaryPlace(env, GeneratedSource);
151640
+ currValue.reactive = reactive;
151641
+ instructions.push({
151642
+ id: makeInstructionId(0),
151643
+ loc: GeneratedSource,
151644
+ lvalue: Object.assign(Object.assign({}, currValue), {
151645
+ effect: exports.Effect.Mutate,
151646
+ }),
151647
+ value: {
151648
+ kind: 'LoadLocal',
151649
+ place: {
151650
+ kind: 'Identifier',
151651
+ identifier: dep.identifier,
151652
+ effect: exports.Effect.Capture,
151653
+ reactive: reactive,
151654
+ loc: loc,
151655
+ },
151656
+ loc: loc,
151657
+ },
151658
+ });
151659
+ for (const path of dep.path) {
151660
+ if (path.optional) {
151661
+ break;
151662
+ }
151663
+ const nextValue = createTemporaryPlace(env, GeneratedSource);
151664
+ nextValue.reactive = reactive;
151665
+ instructions.push({
151666
+ id: makeInstructionId(0),
151667
+ loc: GeneratedSource,
151668
+ lvalue: Object.assign(Object.assign({}, nextValue), {
151669
+ effect: exports.Effect.Mutate,
151670
+ }),
151671
+ value: {
151672
+ kind: 'PropertyLoad',
151673
+ object: Object.assign(Object.assign({}, currValue), {
151674
+ effect: exports.Effect.Capture,
151675
+ }),
151676
+ property: path.property,
151677
+ loc: loc,
151678
+ },
151679
+ });
151680
+ currValue = nextValue;
151681
+ }
151682
+ currValue.effect = exports.Effect.Freeze;
151683
+ return {place: currValue, instructions: instructions};
151684
+ }
151685
+ function inferReactiveIdentifiers(fn) {
151686
+ const reactiveIds = new Set();
151687
+ for (const [, block] of fn.body.blocks) {
151688
+ for (const instr of block.instructions) {
151689
+ for (const place of eachInstructionOperand(instr)) {
151690
+ if (place.reactive) {
151691
+ reactiveIds.add(place.identifier.id);
151692
+ }
151693
+ }
151694
+ }
151695
+ for (const place of eachTerminalOperand(block.terminal)) {
151696
+ if (place.reactive) {
151697
+ reactiveIds.add(place.identifier.id);
151698
+ }
151699
+ }
151700
+ }
151701
+ return reactiveIds;
151702
+ }
151486
151703
  function instructionReordering(fn) {
151487
151704
  var _a;
151488
151705
  const shared = new Map();
@@ -157156,6 +157373,9 @@ function* runWithEnvironment(func, env) {
157156
157373
  assertTerminalPredsExist(hir);
157157
157374
  propagateScopeDependenciesHIR(hir);
157158
157375
  yield log({kind: 'hir', name: 'PropagateScopeDependenciesHIR', value: hir});
157376
+ if (env.config.inferEffectDependencies) {
157377
+ inferEffectDependencies(hir);
157378
+ }
157159
157379
  if (env.config.inlineJsxTransform) {
157160
157380
  inlineJsxTransform(hir, env.config.inlineJsxTransform);
157161
157381
  yield log({kind: 'hir', name: 'inlineJsxTransform', value: hir});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babel-plugin-react-compiler",
3
- "version": "0.0.0-experimental-dc8bd44-20241120",
3
+ "version": "0.0.0-experimental-df7b47d-20241124",
4
4
  "description": "Babel plugin for React Compiler.",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",