babel-plugin-react-compiler 0.0.0-experimental-23b8160-20240916 → 0.0.0-experimental-ca8e0be-20240916

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.
package/dist/index.js CHANGED
@@ -139601,6 +139601,8 @@ var InstructionKind;
139601
139601
  InstructionKind['Catch'] = 'Catch';
139602
139602
  InstructionKind['HoistedConst'] = 'HoistedConst';
139603
139603
  InstructionKind['HoistedLet'] = 'HoistedLet';
139604
+ InstructionKind['HoistedFunction'] = 'HoistedFunction';
139605
+ InstructionKind['Function'] = 'Function';
139604
139606
  })(InstructionKind || (InstructionKind = {}));
139605
139607
  function makeTemporaryIdentifier(id, loc) {
139606
139608
  return {
@@ -144017,7 +144019,14 @@ function lowerStatement(builder, stmtPath, label = null) {
144017
144019
  if (builder.environment.isHoistedIdentifier(binding.identifier)) {
144018
144020
  continue;
144019
144021
  }
144020
- if (!binding.path.isVariableDeclarator()) {
144022
+ let kind;
144023
+ if (binding.kind === 'const' || binding.kind === 'var') {
144024
+ kind = InstructionKind.HoistedConst;
144025
+ } else if (binding.kind === 'let') {
144026
+ kind = InstructionKind.HoistedLet;
144027
+ } else if (binding.path.isFunctionDeclaration()) {
144028
+ kind = InstructionKind.HoistedFunction;
144029
+ } else if (!binding.path.isVariableDeclarator()) {
144021
144030
  builder.errors.push({
144022
144031
  severity: exports.ErrorSeverity.Todo,
144023
144032
  reason: 'Unsupported declaration type for hoisting',
@@ -144029,11 +144038,7 @@ function lowerStatement(builder, stmtPath, label = null) {
144029
144038
  : GeneratedSource,
144030
144039
  });
144031
144040
  continue;
144032
- } else if (
144033
- binding.kind !== 'const' &&
144034
- binding.kind !== 'var' &&
144035
- binding.kind !== 'let'
144036
- ) {
144041
+ } else {
144037
144042
  builder.errors.push({
144038
144043
  severity: exports.ErrorSeverity.Todo,
144039
144044
  reason: 'Handle non-const declarations for hoisting',
@@ -144065,12 +144070,6 @@ function lowerStatement(builder, stmtPath, label = null) {
144065
144070
  ? _j
144066
144071
  : GeneratedSource,
144067
144072
  };
144068
- const kind =
144069
- binding.kind === 'const' || binding.kind === 'var'
144070
- ? InstructionKind.HoistedConst
144071
- : binding.kind === 'let'
144072
- ? InstructionKind.HoistedLet
144073
- : assertExhaustive(binding.kind, 'Unexpected binding kind');
144074
144073
  lowerValueToTemporary(builder, {
144075
144074
  kind: 'DeclareContext',
144076
144075
  lvalue: {kind: kind, place: place},
@@ -144615,7 +144614,7 @@ function lowerStatement(builder, stmtPath, label = null) {
144615
144614
  (_10 = stmt.node.loc) !== null && _10 !== void 0
144616
144615
  ? _10
144617
144616
  : GeneratedSource,
144618
- InstructionKind.Let,
144617
+ InstructionKind.Function,
144619
144618
  id,
144620
144619
  fn,
144621
144620
  'Assignment'
@@ -150159,6 +150158,17 @@ const REACT_APIS = [
150159
150158
  returnValueKind: exports.ValueKind.Mutable,
150160
150159
  }),
150161
150160
  ],
150161
+ [
150162
+ 'useImperativeHandle',
150163
+ addHook(DEFAULT_SHAPES, {
150164
+ positionalParams: [],
150165
+ restParam: exports.Effect.Freeze,
150166
+ returnType: {kind: 'Primitive'},
150167
+ calleeEffect: exports.Effect.Read,
150168
+ hookKind: 'useImperativeHandle',
150169
+ returnValueKind: exports.ValueKind.Frozen,
150170
+ }),
150171
+ ],
150162
150172
  [
150163
150173
  'useMemo',
150164
150174
  addHook(DEFAULT_SHAPES, {
@@ -157991,22 +158001,12 @@ function codegenTerminal(cx, terminal) {
157991
158001
  suggestions: null,
157992
158002
  });
157993
158003
  case InstructionKind.Catch:
157994
- CompilerError.invariant(false, {
157995
- reason: 'Unexpected catch variable as for..in collection',
157996
- description: null,
157997
- loc: iterableItem.loc,
157998
- suggestions: null,
157999
- });
158000
158004
  case InstructionKind.HoistedConst:
158001
- CompilerError.invariant(false, {
158002
- reason: 'Unexpected HoistedConst variable in for..in collection',
158003
- description: null,
158004
- loc: iterableItem.loc,
158005
- suggestions: null,
158006
- });
158007
158005
  case InstructionKind.HoistedLet:
158006
+ case InstructionKind.HoistedFunction:
158007
+ case InstructionKind.Function:
158008
158008
  CompilerError.invariant(false, {
158009
- reason: 'Unexpected HoistedLet variable in for..in collection',
158009
+ reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..in collection`,
158010
158010
  description: null,
158011
158011
  loc: iterableItem.loc,
158012
158012
  suggestions: null,
@@ -158080,30 +158080,13 @@ function codegenTerminal(cx, terminal) {
158080
158080
  varDeclKind = 'let';
158081
158081
  break;
158082
158082
  case InstructionKind.Reassign:
158083
- CompilerError.invariant(false, {
158084
- reason:
158085
- 'Destructure should never be Reassign as it would be an Object/ArrayPattern',
158086
- description: null,
158087
- loc: iterableItem.loc,
158088
- suggestions: null,
158089
- });
158090
158083
  case InstructionKind.Catch:
158091
- CompilerError.invariant(false, {
158092
- reason: 'Unexpected catch variable as for..of collection',
158093
- description: null,
158094
- loc: iterableItem.loc,
158095
- suggestions: null,
158096
- });
158097
158084
  case InstructionKind.HoistedConst:
158098
- CompilerError.invariant(false, {
158099
- reason: 'Unexpected HoistedConst variable in for..of collection',
158100
- description: null,
158101
- loc: iterableItem.loc,
158102
- suggestions: null,
158103
- });
158104
158085
  case InstructionKind.HoistedLet:
158086
+ case InstructionKind.HoistedFunction:
158087
+ case InstructionKind.Function:
158105
158088
  CompilerError.invariant(false, {
158106
- reason: 'Unexpected HoistedLet variable in for..of collection',
158089
+ reason: `Unexpected ${iterableItem.value.lvalue.kind} variable in for..of collection`,
158107
158090
  description: null,
158108
158091
  loc: iterableItem.loc,
158109
158092
  suggestions: null,
@@ -158262,6 +158245,39 @@ function codegenInstructionNullable(cx, instr) {
158262
158245
  t__namespace.variableDeclarator(codegenLValue(cx, lvalue), value),
158263
158246
  ]);
158264
158247
  }
158248
+ case InstructionKind.Function: {
158249
+ CompilerError.invariant(instr.lvalue === null, {
158250
+ reason: `Function declaration cannot be referenced as an expression`,
158251
+ description: null,
158252
+ loc: instr.value.loc,
158253
+ suggestions: null,
158254
+ });
158255
+ const genLvalue = codegenLValue(cx, lvalue);
158256
+ CompilerError.invariant(genLvalue.type === 'Identifier', {
158257
+ reason: 'Expected an identifier as a function declaration lvalue',
158258
+ description: null,
158259
+ loc: instr.value.loc,
158260
+ suggestions: null,
158261
+ });
158262
+ CompilerError.invariant(
158263
+ (value === null || value === void 0 ? void 0 : value.type) ===
158264
+ 'FunctionExpression',
158265
+ {
158266
+ reason: 'Expected a function as a function declaration value',
158267
+ description: null,
158268
+ loc: instr.value.loc,
158269
+ suggestions: null,
158270
+ }
158271
+ );
158272
+ return createFunctionDeclaration(
158273
+ instr.loc,
158274
+ genLvalue,
158275
+ value.params,
158276
+ value.body,
158277
+ value.generator,
158278
+ value.async
158279
+ );
158280
+ }
158265
158281
  case InstructionKind.Let: {
158266
158282
  CompilerError.invariant(instr.lvalue === null, {
158267
158283
  reason: `Const declaration cannot be referenced as an expression`,
@@ -158303,19 +158319,11 @@ function codegenInstructionNullable(cx, instr) {
158303
158319
  case InstructionKind.Catch: {
158304
158320
  return t__namespace.emptyStatement();
158305
158321
  }
158306
- case InstructionKind.HoistedLet: {
158322
+ case InstructionKind.HoistedLet:
158323
+ case InstructionKind.HoistedConst:
158324
+ case InstructionKind.HoistedFunction: {
158307
158325
  CompilerError.invariant(false, {
158308
- reason:
158309
- 'Expected HoistedLet to have been pruned in PruneHoistedContexts',
158310
- description: null,
158311
- loc: instr.loc,
158312
- suggestions: null,
158313
- });
158314
- }
158315
- case InstructionKind.HoistedConst: {
158316
- CompilerError.invariant(false, {
158317
- reason:
158318
- 'Expected HoistedConsts to have been pruned in PruneHoistedContexts',
158326
+ reason: `Expected ${kind} to have been pruned in PruneHoistedContexts`,
158319
158327
  description: null,
158320
158328
  loc: instr.loc,
158321
158329
  suggestions: null,
@@ -158463,6 +158471,7 @@ function withLoc(fn) {
158463
158471
  const createBinaryExpression = withLoc(t__namespace.binaryExpression);
158464
158472
  const createExpressionStatement = withLoc(t__namespace.expressionStatement);
158465
158473
  const createVariableDeclaration = withLoc(t__namespace.variableDeclaration);
158474
+ const createFunctionDeclaration = withLoc(t__namespace.functionDeclaration);
158466
158475
  const createTaggedTemplateExpression = withLoc(
158467
158476
  t__namespace.taggedTemplateExpression
158468
158477
  );
@@ -162063,6 +162072,16 @@ let Visitor$8 = class Visitor extends ReactiveFunctionTransform {
162063
162072
  );
162064
162073
  return {kind: 'remove'};
162065
162074
  }
162075
+ if (
162076
+ instruction.value.kind === 'DeclareContext' &&
162077
+ instruction.value.lvalue.kind === 'HoistedFunction'
162078
+ ) {
162079
+ state.set(
162080
+ instruction.value.lvalue.place.identifier.declarationId,
162081
+ InstructionKind.Function
162082
+ );
162083
+ return {kind: 'remove'};
162084
+ }
162066
162085
  if (
162067
162086
  instruction.value.kind === 'StoreContext' &&
162068
162087
  state.has(instruction.value.lvalue.place.identifier.declarationId)
@@ -167172,7 +167191,7 @@ function equation(left, right) {
167172
167191
  return {left: left, right: right};
167173
167192
  }
167174
167193
  function* generate(func) {
167175
- if (func.env.fnType === 'Component') {
167194
+ if (func.fnType === 'Component') {
167176
167195
  const [props, ref] = func.params;
167177
167196
  if (props && props.kind === 'Identifier') {
167178
167197
  yield equation(props.identifier.type, {
@@ -168204,16 +168223,131 @@ function validateNoCapitalizedCalls(fn) {
168204
168223
  }
168205
168224
  }
168206
168225
  }
168226
+ var _Env_changed;
168227
+ class Env extends Map {
168228
+ constructor() {
168229
+ super(...arguments);
168230
+ _Env_changed.set(this, false);
168231
+ }
168232
+ resetChanged() {
168233
+ __classPrivateFieldSet(this, _Env_changed, false, 'f');
168234
+ }
168235
+ hasChanged() {
168236
+ return __classPrivateFieldGet(this, _Env_changed, 'f');
168237
+ }
168238
+ set(key, value) {
168239
+ const cur = this.get(key);
168240
+ const widenedValue = joinRefAccessTypes(
168241
+ value,
168242
+ cur !== null && cur !== void 0 ? cur : {kind: 'None'}
168243
+ );
168244
+ if (
168245
+ !(cur == null && widenedValue.kind === 'None') &&
168246
+ (cur == null || !tyEqual(cur, widenedValue))
168247
+ ) {
168248
+ __classPrivateFieldSet(this, _Env_changed, true, 'f');
168249
+ }
168250
+ return super.set(key, widenedValue);
168251
+ }
168252
+ }
168253
+ _Env_changed = new WeakMap();
168207
168254
  function validateNoRefAccessInRender(fn) {
168208
- const state = {
168209
- refs: new Set(),
168210
- refValues: new Map(),
168211
- refAccessingFunctions: new Set(),
168212
- };
168213
- validateNoRefAccessInRenderImpl(fn, state).unwrap();
168255
+ const env = new Env();
168256
+ validateNoRefAccessInRenderImpl(fn, env).unwrap();
168257
+ }
168258
+ function refTypeOfType(identifier) {
168259
+ if (isRefValueType(identifier)) {
168260
+ return {kind: 'RefValue'};
168261
+ } else if (isUseRefType(identifier)) {
168262
+ return {kind: 'Ref'};
168263
+ } else {
168264
+ return {kind: 'None'};
168265
+ }
168214
168266
  }
168215
- function validateNoRefAccessInRenderImpl(fn, state) {
168216
- var _a, _b;
168267
+ function tyEqual(a, b) {
168268
+ if (a.kind !== b.kind) {
168269
+ return false;
168270
+ }
168271
+ switch (a.kind) {
168272
+ case 'None':
168273
+ return true;
168274
+ case 'Ref':
168275
+ return true;
168276
+ case 'RefValue':
168277
+ CompilerError.invariant(b.kind === 'RefValue', {
168278
+ reason: 'Expected ref value',
168279
+ loc: null,
168280
+ });
168281
+ return a.loc == b.loc;
168282
+ case 'Structure': {
168283
+ CompilerError.invariant(b.kind === 'Structure', {
168284
+ reason: 'Expected structure',
168285
+ loc: null,
168286
+ });
168287
+ const fnTypesEqual =
168288
+ (a.fn === null && b.fn === null) ||
168289
+ (a.fn !== null &&
168290
+ b.fn !== null &&
168291
+ a.fn.readRefEffect === b.fn.readRefEffect &&
168292
+ tyEqual(a.fn.returnType, b.fn.returnType));
168293
+ return (
168294
+ fnTypesEqual &&
168295
+ (a.value === b.value ||
168296
+ (a.value !== null && b.value !== null && tyEqual(a.value, b.value)))
168297
+ );
168298
+ }
168299
+ }
168300
+ }
168301
+ function joinRefAccessTypes(...types) {
168302
+ function joinRefAccessRefTypes(a, b) {
168303
+ if (a.kind === 'RefValue') {
168304
+ return a;
168305
+ } else if (b.kind === 'RefValue') {
168306
+ return b;
168307
+ } else if (a.kind === 'Ref' || b.kind === 'Ref') {
168308
+ return {kind: 'Ref'};
168309
+ } else {
168310
+ CompilerError.invariant(
168311
+ a.kind === 'Structure' && b.kind === 'Structure',
168312
+ {reason: 'Expected structure', loc: null}
168313
+ );
168314
+ const fn =
168315
+ a.fn === null
168316
+ ? b.fn
168317
+ : b.fn === null
168318
+ ? a.fn
168319
+ : {
168320
+ readRefEffect: a.fn.readRefEffect || b.fn.readRefEffect,
168321
+ returnType: joinRefAccessTypes(
168322
+ a.fn.returnType,
168323
+ b.fn.returnType
168324
+ ),
168325
+ };
168326
+ const value =
168327
+ a.value === null
168328
+ ? b.value
168329
+ : b.value === null
168330
+ ? a.value
168331
+ : joinRefAccessRefTypes(a.value, b.value);
168332
+ return {kind: 'Structure', fn: fn, value: value};
168333
+ }
168334
+ }
168335
+ return types.reduce(
168336
+ (a, b) => {
168337
+ if (a.kind === 'None') {
168338
+ return b;
168339
+ } else if (b.kind === 'None') {
168340
+ return a;
168341
+ } else {
168342
+ return joinRefAccessRefTypes(a, b);
168343
+ }
168344
+ },
168345
+ {kind: 'None'}
168346
+ );
168347
+ }
168348
+ function validateNoRefAccessInRenderImpl(fn, env) {
168349
+ var _a, _b, _c, _d, _e, _f;
168350
+ let returnValues = [];
168217
168351
  let place;
168218
168352
  for (const param of fn.params) {
168219
168353
  if (param.kind === 'Identifier') {
@@ -168221,291 +168355,293 @@ function validateNoRefAccessInRenderImpl(fn, state) {
168221
168355
  } else {
168222
168356
  place = param.place;
168223
168357
  }
168224
- if (isRefValueType(place.identifier)) {
168225
- state.refValues.set(place.identifier.id, null);
168226
- }
168227
- if (isUseRefType(place.identifier)) {
168228
- state.refs.add(place.identifier.id);
168229
- }
168358
+ const type = refTypeOfType(place.identifier);
168359
+ env.set(place.identifier.id, type);
168230
168360
  }
168231
- const errors = new CompilerError();
168232
- for (const [, block] of fn.body.blocks) {
168233
- for (const phi of block.phis) {
168234
- phi.operands.forEach(operand => {
168235
- var _a;
168236
- if (state.refs.has(operand.id) || isUseRefType(phi.id)) {
168237
- state.refs.add(phi.id.id);
168238
- }
168239
- const refValue = state.refValues.get(operand.id);
168240
- if (refValue !== undefined || isRefValueType(operand)) {
168241
- state.refValues.set(
168242
- phi.id.id,
168243
- (_a =
168244
- refValue !== null && refValue !== void 0
168245
- ? refValue
168246
- : state.refValues.get(phi.id.id)) !== null && _a !== void 0
168247
- ? _a
168248
- : null
168249
- );
168250
- }
168251
- if (state.refAccessingFunctions.has(operand.id)) {
168252
- state.refAccessingFunctions.add(phi.id.id);
168253
- }
168254
- });
168255
- }
168256
- for (const instr of block.instructions) {
168257
- for (const operand of eachInstructionValueOperand(instr.value)) {
168258
- if (isRefValueType(operand.identifier)) {
168259
- CompilerError.invariant(state.refValues.has(operand.identifier.id), {
168260
- reason: 'Expected ref value to be in state',
168261
- loc: operand.loc,
168262
- });
168263
- }
168264
- if (isUseRefType(operand.identifier)) {
168265
- CompilerError.invariant(state.refs.has(operand.identifier.id), {
168266
- reason: 'Expected ref to be in state',
168267
- loc: operand.loc,
168268
- });
168269
- }
168361
+ for (let i = 0; (i == 0 || env.hasChanged()) && i < 10; i++) {
168362
+ env.resetChanged();
168363
+ returnValues = [];
168364
+ const errors = new CompilerError();
168365
+ for (const [, block] of fn.body.blocks) {
168366
+ for (const phi of block.phis) {
168367
+ env.set(
168368
+ phi.id.id,
168369
+ joinRefAccessTypes(
168370
+ ...Array(...phi.operands.values()).map(operand => {
168371
+ var _a;
168372
+ return (_a = env.get(operand.id)) !== null && _a !== void 0
168373
+ ? _a
168374
+ : {kind: 'None'};
168375
+ })
168376
+ )
168377
+ );
168270
168378
  }
168271
- switch (instr.value.kind) {
168272
- case 'JsxExpression':
168273
- case 'JsxFragment': {
168274
- for (const operand of eachInstructionValueOperand(instr.value)) {
168275
- validateNoDirectRefValueAccess(errors, operand, state);
168276
- }
168277
- break;
168278
- }
168279
- case 'ComputedLoad':
168280
- case 'PropertyLoad': {
168281
- if (typeof instr.value.property !== 'string') {
168282
- validateNoRefValueAccess(errors, state, instr.value.property);
168283
- }
168284
- if (
168285
- state.refAccessingFunctions.has(instr.value.object.identifier.id)
168286
- ) {
168287
- state.refAccessingFunctions.add(instr.lvalue.identifier.id);
168288
- }
168289
- if (state.refs.has(instr.value.object.identifier.id)) {
168290
- state.refs.add(instr.lvalue.identifier.id);
168291
- state.refValues.set(instr.lvalue.identifier.id, instr.loc);
168292
- }
168293
- break;
168294
- }
168295
- case 'LoadContext':
168296
- case 'LoadLocal': {
168297
- if (
168298
- state.refAccessingFunctions.has(instr.value.place.identifier.id)
168299
- ) {
168300
- state.refAccessingFunctions.add(instr.lvalue.identifier.id);
168301
- }
168302
- const refValue = state.refValues.get(instr.value.place.identifier.id);
168303
- if (refValue !== undefined) {
168304
- state.refValues.set(instr.lvalue.identifier.id, refValue);
168379
+ for (const instr of block.instructions) {
168380
+ switch (instr.value.kind) {
168381
+ case 'JsxExpression':
168382
+ case 'JsxFragment': {
168383
+ for (const operand of eachInstructionValueOperand(instr.value)) {
168384
+ validateNoDirectRefValueAccess(errors, operand, env);
168385
+ }
168386
+ break;
168305
168387
  }
168306
- if (state.refs.has(instr.value.place.identifier.id)) {
168307
- state.refs.add(instr.lvalue.identifier.id);
168388
+ case 'ComputedLoad':
168389
+ case 'PropertyLoad': {
168390
+ if (typeof instr.value.property !== 'string') {
168391
+ validateNoDirectRefValueAccess(errors, instr.value.property, env);
168392
+ }
168393
+ const objType = env.get(instr.value.object.identifier.id);
168394
+ let lookupType = null;
168395
+ if (
168396
+ (objType === null || objType === void 0
168397
+ ? void 0
168398
+ : objType.kind) === 'Structure'
168399
+ ) {
168400
+ lookupType = objType.value;
168401
+ } else if (
168402
+ (objType === null || objType === void 0
168403
+ ? void 0
168404
+ : objType.kind) === 'Ref'
168405
+ ) {
168406
+ lookupType = {kind: 'RefValue', loc: instr.loc};
168407
+ }
168408
+ env.set(
168409
+ instr.lvalue.identifier.id,
168410
+ lookupType !== null && lookupType !== void 0
168411
+ ? lookupType
168412
+ : refTypeOfType(instr.lvalue.identifier)
168413
+ );
168414
+ break;
168308
168415
  }
168309
- break;
168310
- }
168311
- case 'StoreContext':
168312
- case 'StoreLocal': {
168313
- if (
168314
- state.refAccessingFunctions.has(instr.value.value.identifier.id)
168315
- ) {
168316
- state.refAccessingFunctions.add(
168317
- instr.value.lvalue.place.identifier.id
168416
+ case 'LoadContext':
168417
+ case 'LoadLocal': {
168418
+ env.set(
168419
+ instr.lvalue.identifier.id,
168420
+ (_a = env.get(instr.value.place.identifier.id)) !== null &&
168421
+ _a !== void 0
168422
+ ? _a
168423
+ : refTypeOfType(instr.lvalue.identifier)
168318
168424
  );
168319
- state.refAccessingFunctions.add(instr.lvalue.identifier.id);
168425
+ break;
168320
168426
  }
168321
- const refValue = state.refValues.get(instr.value.value.identifier.id);
168322
- if (
168323
- refValue !== undefined ||
168324
- isRefValueType(instr.value.lvalue.place.identifier)
168325
- ) {
168326
- state.refValues.set(
168427
+ case 'StoreContext':
168428
+ case 'StoreLocal': {
168429
+ env.set(
168327
168430
  instr.value.lvalue.place.identifier.id,
168328
- refValue !== null && refValue !== void 0 ? refValue : null
168431
+ (_b = env.get(instr.value.value.identifier.id)) !== null &&
168432
+ _b !== void 0
168433
+ ? _b
168434
+ : refTypeOfType(instr.value.lvalue.place.identifier)
168329
168435
  );
168330
- state.refValues.set(
168436
+ env.set(
168331
168437
  instr.lvalue.identifier.id,
168332
- refValue !== null && refValue !== void 0 ? refValue : null
168438
+ (_c = env.get(instr.value.value.identifier.id)) !== null &&
168439
+ _c !== void 0
168440
+ ? _c
168441
+ : refTypeOfType(instr.lvalue.identifier)
168333
168442
  );
168443
+ break;
168334
168444
  }
168335
- if (state.refs.has(instr.value.value.identifier.id)) {
168336
- state.refs.add(instr.value.lvalue.place.identifier.id);
168337
- state.refs.add(instr.lvalue.identifier.id);
168338
- }
168339
- break;
168340
- }
168341
- case 'Destructure': {
168342
- const destructuredFunction = state.refAccessingFunctions.has(
168343
- instr.value.value.identifier.id
168344
- );
168345
- const destructuredRef = state.refs.has(
168346
- instr.value.value.identifier.id
168347
- );
168348
- for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) {
168349
- if (isUseRefType(lval.identifier)) {
168350
- state.refs.add(lval.identifier.id);
168351
- }
168352
- if (destructuredRef || isRefValueType(lval.identifier)) {
168353
- state.refs.add(lval.identifier.id);
168354
- state.refValues.set(lval.identifier.id, null);
168445
+ case 'Destructure': {
168446
+ const objType = env.get(instr.value.value.identifier.id);
168447
+ let lookupType = null;
168448
+ if (
168449
+ (objType === null || objType === void 0
168450
+ ? void 0
168451
+ : objType.kind) === 'Structure'
168452
+ ) {
168453
+ lookupType = objType.value;
168355
168454
  }
168356
- if (destructuredFunction) {
168357
- state.refAccessingFunctions.add(lval.identifier.id);
168455
+ env.set(
168456
+ instr.lvalue.identifier.id,
168457
+ lookupType !== null && lookupType !== void 0
168458
+ ? lookupType
168459
+ : refTypeOfType(instr.lvalue.identifier)
168460
+ );
168461
+ for (const lval of eachPatternOperand(instr.value.lvalue.pattern)) {
168462
+ env.set(
168463
+ lval.identifier.id,
168464
+ lookupType !== null && lookupType !== void 0
168465
+ ? lookupType
168466
+ : refTypeOfType(lval.identifier)
168467
+ );
168358
168468
  }
168469
+ break;
168359
168470
  }
168360
- break;
168361
- }
168362
- case 'ObjectMethod':
168363
- case 'FunctionExpression': {
168364
- if (
168365
- [...eachInstructionValueOperand(instr.value)].some(
168366
- operand =>
168367
- state.refValues.has(operand.identifier.id) ||
168368
- state.refAccessingFunctions.has(operand.identifier.id)
168369
- ) ||
168370
- ([...eachInstructionValueOperand(instr.value)].some(operand =>
168371
- state.refs.has(operand.identifier.id)
168372
- ) &&
168373
- validateNoRefAccessInRenderImpl(
168374
- instr.value.loweredFunc.func,
168375
- state
168376
- ).isErr())
168377
- ) {
168378
- state.refAccessingFunctions.add(instr.lvalue.identifier.id);
168471
+ case 'ObjectMethod':
168472
+ case 'FunctionExpression': {
168473
+ let returnType = {kind: 'None'};
168474
+ let readRefEffect = false;
168475
+ const result = validateNoRefAccessInRenderImpl(
168476
+ instr.value.loweredFunc.func,
168477
+ env
168478
+ );
168479
+ if (result.isOk()) {
168480
+ returnType = result.unwrap();
168481
+ } else if (result.isErr()) {
168482
+ readRefEffect = true;
168483
+ }
168484
+ env.set(instr.lvalue.identifier.id, {
168485
+ kind: 'Structure',
168486
+ fn: {readRefEffect: readRefEffect, returnType: returnType},
168487
+ value: null,
168488
+ });
168489
+ break;
168379
168490
  }
168380
- break;
168381
- }
168382
- case 'MethodCall': {
168383
- if (!isEffectHook(instr.value.property.identifier)) {
168491
+ case 'MethodCall':
168492
+ case 'CallExpression': {
168493
+ const callee =
168494
+ instr.value.kind === 'CallExpression'
168495
+ ? instr.value.callee
168496
+ : instr.value.property;
168497
+ const hookKind = getHookKindForType(fn.env, callee.identifier.type);
168498
+ let returnType = {kind: 'None'};
168499
+ const fnType = env.get(callee.identifier.id);
168500
+ if (
168501
+ (fnType === null || fnType === void 0 ? void 0 : fnType.kind) ===
168502
+ 'Structure' &&
168503
+ fnType.fn !== null
168504
+ ) {
168505
+ returnType = fnType.fn.returnType;
168506
+ if (fnType.fn.readRefEffect) {
168507
+ errors.push({
168508
+ severity: exports.ErrorSeverity.InvalidReact,
168509
+ reason:
168510
+ 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)',
168511
+ loc: callee.loc,
168512
+ description:
168513
+ callee.identifier.name !== null &&
168514
+ callee.identifier.name.kind === 'named'
168515
+ ? `Function \`${callee.identifier.name.value}\` accesses a ref`
168516
+ : null,
168517
+ suggestions: null,
168518
+ });
168519
+ }
168520
+ }
168384
168521
  for (const operand of eachInstructionValueOperand(instr.value)) {
168385
- validateNoRefAccess(errors, state, operand, operand.loc);
168522
+ if (hookKind != null) {
168523
+ validateNoDirectRefValueAccess(errors, operand, env);
168524
+ } else {
168525
+ validateNoRefAccess(errors, env, operand, operand.loc);
168526
+ }
168386
168527
  }
168528
+ env.set(instr.lvalue.identifier.id, returnType);
168529
+ break;
168387
168530
  }
168388
- break;
168389
- }
168390
- case 'CallExpression': {
168391
- const callee = instr.value.callee;
168392
- const isUseEffect = isEffectHook(callee.identifier);
168393
- if (!isUseEffect) {
168394
- if (state.refAccessingFunctions.has(callee.identifier.id)) {
168395
- errors.push({
168396
- severity: exports.ErrorSeverity.InvalidReact,
168397
- reason:
168398
- 'This function accesses a ref value (the `current` property), which may not be accessed during render. (https://react.dev/reference/react/useRef)',
168399
- loc: callee.loc,
168400
- description:
168401
- callee.identifier.name !== null &&
168402
- callee.identifier.name.kind === 'named'
168403
- ? `Function \`${callee.identifier.name.value}\` accesses a ref`
168404
- : null,
168405
- suggestions: null,
168406
- });
168407
- }
168531
+ case 'ObjectExpression':
168532
+ case 'ArrayExpression': {
168533
+ const types = [];
168408
168534
  for (const operand of eachInstructionValueOperand(instr.value)) {
168409
- validateNoRefAccess(
168410
- errors,
168411
- state,
168412
- operand,
168413
- (_a = state.refValues.get(operand.identifier.id)) !== null &&
168414
- _a !== void 0
168415
- ? _a
168416
- : operand.loc
168535
+ validateNoDirectRefValueAccess(errors, operand, env);
168536
+ types.push(
168537
+ (_d = env.get(operand.identifier.id)) !== null && _d !== void 0
168538
+ ? _d
168539
+ : {kind: 'None'}
168417
168540
  );
168418
168541
  }
168419
- }
168420
- break;
168421
- }
168422
- case 'ObjectExpression':
168423
- case 'ArrayExpression': {
168424
- for (const operand of eachInstructionValueOperand(instr.value)) {
168425
- validateNoDirectRefValueAccess(errors, operand, state);
168426
- if (state.refAccessingFunctions.has(operand.identifier.id)) {
168427
- state.refAccessingFunctions.add(instr.lvalue.identifier.id);
168542
+ const value = joinRefAccessTypes(...types);
168543
+ if (value.kind === 'None') {
168544
+ env.set(instr.lvalue.identifier.id, {kind: 'None'});
168545
+ } else {
168546
+ env.set(instr.lvalue.identifier.id, {
168547
+ kind: 'Structure',
168548
+ value: value,
168549
+ fn: null,
168550
+ });
168428
168551
  }
168429
- if (state.refs.has(operand.identifier.id)) {
168430
- state.refs.add(instr.lvalue.identifier.id);
168552
+ break;
168553
+ }
168554
+ case 'PropertyDelete':
168555
+ case 'PropertyStore':
168556
+ case 'ComputedDelete':
168557
+ case 'ComputedStore': {
168558
+ validateNoRefAccess(errors, env, instr.value.object, instr.loc);
168559
+ for (const operand of eachInstructionValueOperand(instr.value)) {
168560
+ if (operand === instr.value.object) {
168561
+ continue;
168562
+ }
168563
+ validateNoRefValueAccess(errors, env, operand);
168431
168564
  }
168432
- const refValue = state.refValues.get(operand.identifier.id);
168433
- if (refValue !== undefined) {
168434
- state.refValues.set(instr.lvalue.identifier.id, refValue);
168565
+ break;
168566
+ }
168567
+ case 'StartMemoize':
168568
+ case 'FinishMemoize':
168569
+ break;
168570
+ default: {
168571
+ for (const operand of eachInstructionValueOperand(instr.value)) {
168572
+ validateNoRefValueAccess(errors, env, operand);
168435
168573
  }
168574
+ break;
168436
168575
  }
168437
- break;
168438
168576
  }
168439
- case 'PropertyDelete':
168440
- case 'PropertyStore':
168441
- case 'ComputedDelete':
168442
- case 'ComputedStore': {
168443
- validateNoRefAccess(
168444
- errors,
168445
- state,
168446
- instr.value.object,
168447
- (_b = state.refValues.get(instr.value.object.identifier.id)) !==
168448
- null && _b !== void 0
168449
- ? _b
168450
- : instr.loc
168577
+ if (isUseRefType(instr.lvalue.identifier)) {
168578
+ env.set(
168579
+ instr.lvalue.identifier.id,
168580
+ joinRefAccessTypes(
168581
+ (_e = env.get(instr.lvalue.identifier.id)) !== null &&
168582
+ _e !== void 0
168583
+ ? _e
168584
+ : {kind: 'None'},
168585
+ {kind: 'Ref'}
168586
+ )
168451
168587
  );
168452
- for (const operand of eachInstructionValueOperand(instr.value)) {
168453
- if (operand === instr.value.object) {
168454
- continue;
168455
- }
168456
- validateNoRefValueAccess(errors, state, operand);
168457
- }
168458
- break;
168459
168588
  }
168460
- case 'StartMemoize':
168461
- case 'FinishMemoize':
168462
- break;
168463
- default: {
168464
- for (const operand of eachInstructionValueOperand(instr.value)) {
168465
- validateNoRefValueAccess(errors, state, operand);
168466
- }
168467
- break;
168589
+ if (isRefValueType(instr.lvalue.identifier)) {
168590
+ env.set(
168591
+ instr.lvalue.identifier.id,
168592
+ joinRefAccessTypes(
168593
+ (_f = env.get(instr.lvalue.identifier.id)) !== null &&
168594
+ _f !== void 0
168595
+ ? _f
168596
+ : {kind: 'None'},
168597
+ {kind: 'RefValue', loc: instr.loc}
168598
+ )
168599
+ );
168468
168600
  }
168469
168601
  }
168470
- if (isUseRefType(instr.lvalue.identifier)) {
168471
- state.refs.add(instr.lvalue.identifier.id);
168472
- }
168473
- if (
168474
- isRefValueType(instr.lvalue.identifier) &&
168475
- !state.refValues.has(instr.lvalue.identifier.id)
168476
- ) {
168477
- state.refValues.set(instr.lvalue.identifier.id, instr.loc);
168602
+ for (const operand of eachTerminalOperand(block.terminal)) {
168603
+ if (block.terminal.kind !== 'return') {
168604
+ validateNoRefValueAccess(errors, env, operand);
168605
+ } else {
168606
+ validateNoDirectRefValueAccess(errors, operand, env);
168607
+ returnValues.push(env.get(operand.identifier.id));
168608
+ }
168478
168609
  }
168479
168610
  }
168480
- for (const operand of eachTerminalOperand(block.terminal)) {
168481
- if (block.terminal.kind !== 'return') {
168482
- validateNoRefValueAccess(errors, state, operand);
168483
- } else {
168484
- validateNoDirectRefValueAccess(errors, operand, state);
168485
- }
168611
+ if (errors.hasErrors()) {
168612
+ return Err(errors);
168486
168613
  }
168487
168614
  }
168488
- if (errors.hasErrors()) {
168489
- return Err(errors);
168490
- } else {
168491
- return Ok(undefined);
168615
+ CompilerError.invariant(!env.hasChanged(), {
168616
+ reason: 'Ref type environment did not converge',
168617
+ loc: null,
168618
+ });
168619
+ return Ok(
168620
+ joinRefAccessTypes(...returnValues.filter(env => env !== undefined))
168621
+ );
168622
+ }
168623
+ function destructure(type) {
168624
+ if (
168625
+ (type === null || type === void 0 ? void 0 : type.kind) === 'Structure' &&
168626
+ type.value !== null
168627
+ ) {
168628
+ return destructure(type.value);
168492
168629
  }
168630
+ return type;
168493
168631
  }
168494
- function validateNoRefValueAccess(errors, state, operand) {
168632
+ function validateNoRefValueAccess(errors, env, operand) {
168495
168633
  var _a;
168634
+ const type = destructure(env.get(operand.identifier.id));
168496
168635
  if (
168497
- state.refValues.has(operand.identifier.id) ||
168498
- state.refAccessingFunctions.has(operand.identifier.id)
168636
+ (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
168637
+ ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' &&
168638
+ ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))
168499
168639
  ) {
168500
168640
  errors.push({
168501
168641
  severity: exports.ErrorSeverity.InvalidReact,
168502
168642
  reason:
168503
168643
  'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
168504
- loc:
168505
- (_a = state.refValues.get(operand.identifier.id)) !== null &&
168506
- _a !== void 0
168507
- ? _a
168508
- : operand.loc,
168644
+ loc: (type.kind === 'RefValue' && type.loc) || operand.loc,
168509
168645
  description:
168510
168646
  operand.identifier.name !== null &&
168511
168647
  operand.identifier.name.kind === 'named'
@@ -168515,17 +168651,20 @@ function validateNoRefValueAccess(errors, state, operand) {
168515
168651
  });
168516
168652
  }
168517
168653
  }
168518
- function validateNoRefAccess(errors, state, operand, loc) {
168654
+ function validateNoRefAccess(errors, env, operand, loc) {
168655
+ var _a;
168656
+ const type = destructure(env.get(operand.identifier.id));
168519
168657
  if (
168520
- state.refs.has(operand.identifier.id) ||
168521
- state.refValues.has(operand.identifier.id) ||
168522
- state.refAccessingFunctions.has(operand.identifier.id)
168658
+ (type === null || type === void 0 ? void 0 : type.kind) === 'Ref' ||
168659
+ (type === null || type === void 0 ? void 0 : type.kind) === 'RefValue' ||
168660
+ ((type === null || type === void 0 ? void 0 : type.kind) === 'Structure' &&
168661
+ ((_a = type.fn) === null || _a === void 0 ? void 0 : _a.readRefEffect))
168523
168662
  ) {
168524
168663
  errors.push({
168525
168664
  severity: exports.ErrorSeverity.InvalidReact,
168526
168665
  reason:
168527
168666
  'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
168528
- loc: loc,
168667
+ loc: (type.kind === 'RefValue' && type.loc) || loc,
168529
168668
  description:
168530
168669
  operand.identifier.name !== null &&
168531
168670
  operand.identifier.name.kind === 'named'
@@ -168535,18 +168674,15 @@ function validateNoRefAccess(errors, state, operand, loc) {
168535
168674
  });
168536
168675
  }
168537
168676
  }
168538
- function validateNoDirectRefValueAccess(errors, operand, state) {
168677
+ function validateNoDirectRefValueAccess(errors, operand, env) {
168539
168678
  var _a;
168540
- if (state.refValues.has(operand.identifier.id)) {
168679
+ const type = destructure(env.get(operand.identifier.id));
168680
+ if ((type === null || type === void 0 ? void 0 : type.kind) === 'RefValue') {
168541
168681
  errors.push({
168542
168682
  severity: exports.ErrorSeverity.InvalidReact,
168543
168683
  reason:
168544
168684
  'Ref values (the `current` property) may not be accessed during render. (https://react.dev/reference/react/useRef)',
168545
- loc:
168546
- (_a = state.refValues.get(operand.identifier.id)) !== null &&
168547
- _a !== void 0
168548
- ? _a
168549
- : operand.loc,
168685
+ loc: (_a = type.loc) !== null && _a !== void 0 ? _a : operand.loc,
168550
168686
  description:
168551
168687
  operand.identifier.name !== null &&
168552
168688
  operand.identifier.name.kind === 'named'