@neocompose/cli 0.72.2 → 0.72.4

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/neo.mjs CHANGED
@@ -28917,12 +28917,18 @@ function identPathSegments(expression) {
28917
28917
  if (receiver === null) return null;
28918
28918
  return [...receiver, expression.name];
28919
28919
  }
28920
- function receiverNarrowings(path, rootEntry, scope) {
28920
+ function unaffectedNarrowings(path, rootEntry, scope) {
28921
28921
  const facts = [];
28922
- for (let dot = path.indexOf("."); dot !== -1; dot = path.indexOf(".", dot + 1)) {
28923
- const prefix = path.slice(0, dot);
28924
- const type = scope.lookupNarrowedType(prefix, rootEntry);
28925
- if (type !== null) facts.push([prefix, type]);
28922
+ const prefix = `${path}.`;
28923
+ const dot = path.lastIndexOf(".");
28924
+ if (dot === -1) return facts;
28925
+ const member = path.slice(dot);
28926
+ for (const [candidate, narrowed] of scope.effectiveNarrowedPaths()) {
28927
+ if (narrowed.rootEntry !== rootEntry) continue;
28928
+ if (candidate === path || candidate.startsWith(prefix)) continue;
28929
+ if (candidate.endsWith(member) || candidate.includes(`${member}.`))
28930
+ continue;
28931
+ facts.push([candidate, narrowed.type]);
28926
28932
  }
28927
28933
  return facts;
28928
28934
  }
@@ -29246,22 +29252,22 @@ function localsWithBindings(locals, expression, whenTrue) {
29246
29252
  ...facts.flatMap((fact) => fact.bindingName ? [fact.bindingName] : [])
29247
29253
  ]);
29248
29254
  }
29249
- function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(), inheritedLocals = /* @__PURE__ */ new Set(), flowCache = /* @__PURE__ */ new WeakMap()) {
29255
+ function collectAssignedPaths(statements, roots = /* @__PURE__ */ new Set(), inheritedLocals = /* @__PURE__ */ new Set(), flowCache = /* @__PURE__ */ new WeakMap()) {
29250
29256
  const locals = new Set(inheritedLocals);
29251
29257
  for (const statement of statements) {
29252
29258
  if (statement.kind === "assign") {
29253
29259
  const assignedPath = canonicalPath(statement.target);
29254
29260
  if (assignedPath && !locals.has(pathRoot(assignedPath))) {
29255
- roots.add(pathRoot(assignedPath));
29261
+ roots.add(assignedPath);
29256
29262
  }
29257
- collectAssignedPathRootsInExpression(
29263
+ collectAssignedPathsInExpression(
29258
29264
  statement.target,
29259
29265
  roots,
29260
29266
  locals,
29261
29267
  flowCache
29262
29268
  );
29263
29269
  if (statement.value)
29264
- collectAssignedPathRootsInExpression(
29270
+ collectAssignedPathsInExpression(
29265
29271
  statement.value,
29266
29272
  roots,
29267
29273
  locals,
@@ -29270,7 +29276,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29270
29276
  continue;
29271
29277
  }
29272
29278
  if (statement.kind === "varDecl") {
29273
- collectAssignedPathRootsInExpression(
29279
+ collectAssignedPathsInExpression(
29274
29280
  statement.init,
29275
29281
  roots,
29276
29282
  locals,
@@ -29284,7 +29290,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29284
29290
  const falseFacts = [];
29285
29291
  const fallthroughFacts = [];
29286
29292
  for (const branch of statement.branches) {
29287
- collectAssignedPathRootsInExpression(
29293
+ collectAssignedPathsInExpression(
29288
29294
  branch.cond,
29289
29295
  roots,
29290
29296
  falseLocals,
@@ -29294,7 +29300,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29294
29300
  ...falseFacts,
29295
29301
  ...factsWhenTrue(branch.cond, canonicalPath)
29296
29302
  ];
29297
- collectAssignedPathRoots(
29303
+ collectAssignedPaths(
29298
29304
  branch.body,
29299
29305
  roots,
29300
29306
  localsWithBindings(falseLocals, branch.cond, true),
@@ -29306,12 +29312,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29306
29312
  falseLocals = localsWithBindings(falseLocals, branch.cond, false);
29307
29313
  }
29308
29314
  if (statement.elseBody) {
29309
- collectAssignedPathRoots(
29310
- statement.elseBody,
29311
- roots,
29312
- falseLocals,
29313
- flowCache
29314
- );
29315
+ collectAssignedPaths(statement.elseBody, roots, falseLocals, flowCache);
29315
29316
  if (statementFlow(statement.elseBody, flowCache).has("fallthrough"))
29316
29317
  fallthroughFacts.push(falseFacts);
29317
29318
  } else {
@@ -29323,18 +29324,18 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29323
29324
  continue;
29324
29325
  }
29325
29326
  if (statement.kind === "try") {
29326
- collectAssignedPathRoots(statement.body, roots, locals, flowCache);
29327
+ collectAssignedPaths(statement.body, roots, locals, flowCache);
29327
29328
  for (const clause of statement.catches) {
29328
29329
  const catchLocals = /* @__PURE__ */ new Set([...locals, clause.name]);
29329
29330
  if (clause.filter) {
29330
- collectAssignedPathRootsInExpression(
29331
+ collectAssignedPathsInExpression(
29331
29332
  clause.filter,
29332
29333
  roots,
29333
29334
  catchLocals,
29334
29335
  flowCache
29335
29336
  );
29336
29337
  }
29337
- collectAssignedPathRoots(
29338
+ collectAssignedPaths(
29338
29339
  clause.body,
29339
29340
  roots,
29340
29341
  clause.filter ? localsWithBindings(catchLocals, clause.filter, true) : catchLocals,
@@ -29344,13 +29345,13 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29344
29345
  continue;
29345
29346
  }
29346
29347
  if (statement.kind === "while" || statement.kind === "doWhile") {
29347
- collectAssignedPathRootsInExpression(
29348
+ collectAssignedPathsInExpression(
29348
29349
  statement.condition,
29349
29350
  roots,
29350
29351
  locals,
29351
29352
  flowCache
29352
29353
  );
29353
- collectAssignedPathRoots(
29354
+ collectAssignedPaths(
29354
29355
  statement.body,
29355
29356
  roots,
29356
29357
  statement.kind === "while" ? localsWithBindings(locals, statement.condition, true) : locals,
@@ -29359,14 +29360,14 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29359
29360
  continue;
29360
29361
  }
29361
29362
  if (statement.kind === "for") {
29362
- collectAssignedPathRootsInExpression(
29363
+ collectAssignedPathsInExpression(
29363
29364
  statement.initializer.init,
29364
29365
  roots,
29365
29366
  locals,
29366
29367
  flowCache
29367
29368
  );
29368
29369
  const loopLocals = /* @__PURE__ */ new Set([...locals, statement.initializer.name]);
29369
- collectAssignedPathRootsInExpression(
29370
+ collectAssignedPathsInExpression(
29370
29371
  statement.condition,
29371
29372
  roots,
29372
29373
  loopLocals,
@@ -29377,22 +29378,17 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29377
29378
  statement.condition,
29378
29379
  true
29379
29380
  );
29380
- collectAssignedPathRoots(
29381
+ collectAssignedPaths(
29381
29382
  [statement.iterator],
29382
29383
  roots,
29383
29384
  iterationLocals,
29384
29385
  flowCache
29385
29386
  );
29386
- collectAssignedPathRoots(
29387
- statement.body,
29388
- roots,
29389
- iterationLocals,
29390
- flowCache
29391
- );
29387
+ collectAssignedPaths(statement.body, roots, iterationLocals, flowCache);
29392
29388
  continue;
29393
29389
  }
29394
29390
  if (statement.kind === "forEach") {
29395
- collectAssignedPathRootsInExpression(
29391
+ collectAssignedPathsInExpression(
29396
29392
  statement.collection,
29397
29393
  roots,
29398
29394
  locals,
@@ -29400,11 +29396,11 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29400
29396
  );
29401
29397
  const loopLocals = /* @__PURE__ */ new Set([...locals, statement.name]);
29402
29398
  if (statement.key) loopLocals.add(statement.key.name);
29403
- collectAssignedPathRoots(statement.body, roots, loopLocals, flowCache);
29399
+ collectAssignedPaths(statement.body, roots, loopLocals, flowCache);
29404
29400
  continue;
29405
29401
  }
29406
29402
  if (statement.kind === "switch") {
29407
- collectAssignedPathRootsInExpression(
29403
+ collectAssignedPathsInExpression(
29408
29404
  statement.selector,
29409
29405
  roots,
29410
29406
  locals,
@@ -29413,7 +29409,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29413
29409
  for (const section of statement.sections) {
29414
29410
  for (const label of section.labels) {
29415
29411
  if (label.kind === "case") {
29416
- collectAssignedPathRootsInExpression(
29412
+ collectAssignedPathsInExpression(
29417
29413
  label.expression,
29418
29414
  roots,
29419
29415
  locals,
@@ -29421,13 +29417,13 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29421
29417
  );
29422
29418
  }
29423
29419
  }
29424
- collectAssignedPathRoots(section.body, roots, locals, flowCache);
29420
+ collectAssignedPaths(section.body, roots, locals, flowCache);
29425
29421
  }
29426
29422
  continue;
29427
29423
  }
29428
29424
  if (statement.kind === "return" || statement.kind === "throw") {
29429
29425
  if (statement.expr)
29430
- collectAssignedPathRootsInExpression(
29426
+ collectAssignedPathsInExpression(
29431
29427
  statement.expr,
29432
29428
  roots,
29433
29429
  locals,
@@ -29436,7 +29432,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29436
29432
  continue;
29437
29433
  }
29438
29434
  if (statement.kind === "exprStmt") {
29439
- collectAssignedPathRootsInExpression(
29435
+ collectAssignedPathsInExpression(
29440
29436
  statement.expr,
29441
29437
  roots,
29442
29438
  locals,
@@ -29446,43 +29442,28 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
29446
29442
  }
29447
29443
  return roots;
29448
29444
  }
29449
- function collectAssignedPathRootsInExpression(expression, roots, locals, flowCache) {
29445
+ function collectAssignedPathsInExpression(expression, roots, locals, flowCache) {
29450
29446
  switch (expression.kind) {
29451
29447
  case "litInterp":
29452
29448
  for (const part of expression.parts) {
29453
29449
  if (part.kind === "expr") {
29454
- collectAssignedPathRootsInExpression(
29455
- part.expr,
29456
- roots,
29457
- locals,
29458
- flowCache
29459
- );
29450
+ collectAssignedPathsInExpression(part.expr, roots, locals, flowCache);
29460
29451
  }
29461
29452
  }
29462
29453
  return;
29463
29454
  case "litList":
29464
29455
  for (const element of expression.elements) {
29465
- collectAssignedPathRootsInExpression(element, roots, locals, flowCache);
29456
+ collectAssignedPathsInExpression(element, roots, locals, flowCache);
29466
29457
  }
29467
29458
  return;
29468
29459
  case "litDict":
29469
29460
  for (const entry of expression.entries) {
29470
- collectAssignedPathRootsInExpression(
29471
- entry.key,
29472
- roots,
29473
- locals,
29474
- flowCache
29475
- );
29476
- collectAssignedPathRootsInExpression(
29477
- entry.value,
29478
- roots,
29479
- locals,
29480
- flowCache
29481
- );
29461
+ collectAssignedPathsInExpression(entry.key, roots, locals, flowCache);
29462
+ collectAssignedPathsInExpression(entry.value, roots, locals, flowCache);
29482
29463
  }
29483
29464
  return;
29484
29465
  case "member":
29485
- collectAssignedPathRootsInExpression(
29466
+ collectAssignedPathsInExpression(
29486
29467
  expression.receiver,
29487
29468
  roots,
29488
29469
  locals,
@@ -29490,13 +29471,13 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29490
29471
  );
29491
29472
  return;
29492
29473
  case "index":
29493
- collectAssignedPathRootsInExpression(
29474
+ collectAssignedPathsInExpression(
29494
29475
  expression.receiver,
29495
29476
  roots,
29496
29477
  locals,
29497
29478
  flowCache
29498
29479
  );
29499
- collectAssignedPathRootsInExpression(
29480
+ collectAssignedPathsInExpression(
29500
29481
  expression.index,
29501
29482
  roots,
29502
29483
  locals,
@@ -29504,32 +29485,22 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29504
29485
  );
29505
29486
  return;
29506
29487
  case "call":
29507
- collectAssignedPathRootsInExpression(
29488
+ collectAssignedPathsInExpression(
29508
29489
  expression.callee,
29509
29490
  roots,
29510
29491
  locals,
29511
29492
  flowCache
29512
29493
  );
29513
29494
  for (const argument2 of expression.args) {
29514
- collectAssignedPathRootsInExpression(
29515
- argument2,
29516
- roots,
29517
- locals,
29518
- flowCache
29519
- );
29495
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
29520
29496
  }
29521
29497
  return;
29522
29498
  case "new":
29523
29499
  for (const argument2 of expression.args) {
29524
- collectAssignedPathRootsInExpression(
29525
- argument2,
29526
- roots,
29527
- locals,
29528
- flowCache
29529
- );
29500
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
29530
29501
  }
29531
29502
  for (const initializer of expression.initializer ?? []) {
29532
- collectAssignedPathRootsInExpression(
29503
+ collectAssignedPathsInExpression(
29533
29504
  initializer.value,
29534
29505
  roots,
29535
29506
  locals,
@@ -29540,15 +29511,10 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29540
29511
  case "annotated":
29541
29512
  for (const annotation2 of expression.annotations) {
29542
29513
  for (const argument2 of annotation2.args) {
29543
- collectAssignedPathRootsInExpression(
29544
- argument2,
29545
- roots,
29546
- locals,
29547
- flowCache
29548
- );
29514
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
29549
29515
  }
29550
29516
  }
29551
- collectAssignedPathRootsInExpression(
29517
+ collectAssignedPathsInExpression(
29552
29518
  expression.expression,
29553
29519
  roots,
29554
29520
  locals,
@@ -29557,13 +29523,13 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29557
29523
  return;
29558
29524
  case "binary":
29559
29525
  case "coalesce":
29560
- collectAssignedPathRootsInExpression(
29526
+ collectAssignedPathsInExpression(
29561
29527
  expression.left,
29562
29528
  roots,
29563
29529
  locals,
29564
29530
  flowCache
29565
29531
  );
29566
- collectAssignedPathRootsInExpression(
29532
+ collectAssignedPathsInExpression(
29567
29533
  expression.right,
29568
29534
  roots,
29569
29535
  locals,
@@ -29571,19 +29537,19 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29571
29537
  );
29572
29538
  return;
29573
29539
  case "conditional":
29574
- collectAssignedPathRootsInExpression(
29540
+ collectAssignedPathsInExpression(
29575
29541
  expression.condition,
29576
29542
  roots,
29577
29543
  locals,
29578
29544
  flowCache
29579
29545
  );
29580
- collectAssignedPathRootsInExpression(
29546
+ collectAssignedPathsInExpression(
29581
29547
  expression.whenTrue,
29582
29548
  roots,
29583
29549
  locals,
29584
29550
  flowCache
29585
29551
  );
29586
- collectAssignedPathRootsInExpression(
29552
+ collectAssignedPathsInExpression(
29587
29553
  expression.whenFalse,
29588
29554
  roots,
29589
29555
  locals,
@@ -29592,7 +29558,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29592
29558
  return;
29593
29559
  case "unary":
29594
29560
  case "force":
29595
- collectAssignedPathRootsInExpression(
29561
+ collectAssignedPathsInExpression(
29596
29562
  expression.operand,
29597
29563
  roots,
29598
29564
  locals,
@@ -29600,7 +29566,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29600
29566
  );
29601
29567
  return;
29602
29568
  case "is":
29603
- collectAssignedPathRootsInExpression(
29569
+ collectAssignedPathsInExpression(
29604
29570
  expression.operand,
29605
29571
  roots,
29606
29572
  locals,
@@ -29608,7 +29574,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
29608
29574
  );
29609
29575
  return;
29610
29576
  case "lambda":
29611
- collectAssignedPathRoots(
29577
+ collectAssignedPaths(
29612
29578
  expression.body,
29613
29579
  roots,
29614
29580
  /* @__PURE__ */ new Set([
@@ -30602,14 +30568,17 @@ var init_strict_resolver = __esm({
30602
30568
  return this.invalidatedRoots;
30603
30569
  }
30604
30570
  effectiveNarrowedPaths() {
30605
- const effective = this.parent ? new Map(this.parent.effectiveNarrowedPaths()) : /* @__PURE__ */ new Map();
30606
- for (const invalidated of this.invalidatedRoots) {
30607
- for (const [path, narrowed] of effective) {
30608
- if (narrowed.rootEntry === invalidated) effective.delete(path);
30571
+ const effective = new Map(this.narrowedPaths);
30572
+ const invalidated = new Set(this.invalidatedRoots);
30573
+ for (const root of this.hiddenNarrowingRoots) invalidated.add(root);
30574
+ for (let current = this.parent; current; current = current.parent) {
30575
+ for (const [path, narrowed] of current.narrowedPaths) {
30576
+ if (!effective.has(path) && !invalidated.has(narrowed.rootEntry)) {
30577
+ effective.set(path, narrowed);
30578
+ }
30609
30579
  }
30610
- }
30611
- for (const [path, narrowed] of this.narrowedPaths) {
30612
- effective.set(path, narrowed);
30580
+ for (const root of current.invalidatedRoots) invalidated.add(root);
30581
+ for (const root of current.hiddenNarrowingRoots) invalidated.add(root);
30613
30582
  }
30614
30583
  return effective;
30615
30584
  }
@@ -30635,6 +30604,9 @@ var init_strict_resolver = __esm({
30635
30604
  hideInheritedNarrowing(rootEntry) {
30636
30605
  this.hiddenNarrowingRoots.add(rootEntry);
30637
30606
  this.updatePatternType(rootEntry, rootEntry.type);
30607
+ for (const [path, narrowed] of this.narrowedPaths) {
30608
+ if (narrowed.rootEntry === rootEntry) this.narrowedPaths.delete(path);
30609
+ }
30638
30610
  }
30639
30611
  invalidate(rootEntry) {
30640
30612
  this.invalidatedRoots.add(rootEntry);
@@ -31192,24 +31164,26 @@ var init_strict_resolver = __esm({
31192
31164
  const branchExitNarrowings = [];
31193
31165
  const branchExitOwnershipScopes = [];
31194
31166
  const branches = statement.branches.map((branch) => {
31167
+ const conditionScope = new Scope(scope);
31168
+ this.applyFactsToScope(conditionScope, cumulativeFalseFacts);
31195
31169
  const condition = this.toBool(
31196
- this.resolveExpression(branch.cond, scope),
31170
+ this.resolveExpression(branch.cond, conditionScope),
31197
31171
  branch.cond.pos
31198
31172
  );
31199
31173
  const child2 = new Scope(scope);
31200
31174
  const branchFacts = [
31201
31175
  ...cumulativeFalseFacts,
31202
- ...this.conditionFacts(branch.cond, scope, true)
31176
+ ...this.conditionFacts(branch.cond, conditionScope, true)
31203
31177
  ];
31204
31178
  this.applyFactsToScope(child2, branchFacts);
31205
31179
  const instructions = this.resolveStatements(branch.body, child2);
31206
31180
  if (!instructionsTerminate(instructions)) {
31207
31181
  branchExitFacts.push(branchFacts);
31208
- branchExitNarrowings.push(new Map(child2.narrowedPaths));
31182
+ branchExitNarrowings.push(child2.effectiveNarrowedPaths());
31209
31183
  branchExitOwnershipScopes.push(child2);
31210
31184
  }
31211
31185
  cumulativeFalseFacts.push(
31212
- ...this.conditionFacts(branch.cond, scope, false)
31186
+ ...this.conditionFacts(branch.cond, conditionScope, false)
31213
31187
  );
31214
31188
  return {
31215
31189
  expression: pointerToBooleanExpression(condition.pointer),
@@ -31223,14 +31197,14 @@ var init_strict_resolver = __esm({
31223
31197
  otherwise = this.resolveStatements(statement.elseBody, elseScope);
31224
31198
  if (!instructionsTerminate(otherwise)) {
31225
31199
  branchExitFacts.push([...cumulativeFalseFacts]);
31226
- branchExitNarrowings.push(new Map(elseScope.narrowedPaths));
31200
+ branchExitNarrowings.push(elseScope.effectiveNarrowedPaths());
31227
31201
  branchExitOwnershipScopes.push(elseScope);
31228
31202
  }
31229
31203
  } else {
31230
31204
  const noBranchScope = new Scope(scope);
31231
31205
  this.applyFactsToScope(noBranchScope, cumulativeFalseFacts);
31232
31206
  branchExitFacts.push([...cumulativeFalseFacts]);
31233
- branchExitNarrowings.push(new Map(noBranchScope.narrowedPaths));
31207
+ branchExitNarrowings.push(noBranchScope.effectiveNarrowedPaths());
31234
31208
  branchExitOwnershipScopes.push(noBranchScope);
31235
31209
  }
31236
31210
  mergeBranchInvalidations(scope, branchExitOwnershipScopes);
@@ -31464,12 +31438,15 @@ var init_strict_resolver = __esm({
31464
31438
  statement.body,
31465
31439
  conditionLocals
31466
31440
  );
31467
- this.invalidateLoopEntryNarrowingsAssignedBy(
31468
- loopEntryScope,
31469
- loopScope,
31470
- [statement.iterator],
31471
- conditionLocals
31472
- );
31441
+ const bodyFlow = statementFlow(statement.body, /* @__PURE__ */ new WeakMap());
31442
+ if (bodyFlow.has("fallthrough") || bodyFlow.has("continue")) {
31443
+ this.invalidateLoopEntryNarrowingsAssignedBy(
31444
+ loopEntryScope,
31445
+ loopScope,
31446
+ [statement.iterator],
31447
+ conditionLocals
31448
+ );
31449
+ }
31473
31450
  const condition = this.toBool(
31474
31451
  this.resolveExpression(statement.condition, loopEntryScope),
31475
31452
  statement.condition.pos
@@ -32336,13 +32313,13 @@ var init_strict_resolver = __esm({
32336
32313
  if (assignedPath) {
32337
32314
  const rootEntry = scope.lookup(pathRoot(assignedPath));
32338
32315
  if (rootEntry) {
32339
- const receiverFacts = receiverNarrowings(
32316
+ const retainedFacts = unaffectedNarrowings(
32340
32317
  assignedPath,
32341
32318
  rootEntry,
32342
32319
  scope
32343
32320
  );
32344
32321
  scope.invalidate(rootEntry);
32345
- for (const [path, type] of receiverFacts) {
32322
+ for (const [path, type] of retainedFacts) {
32346
32323
  scope.narrow(path, rootEntry, type);
32347
32324
  }
32348
32325
  if (statement.op === "=" && !isNullable(value.type)) {
@@ -32559,13 +32536,13 @@ var init_strict_resolver = __esm({
32559
32536
  if (assignedPath) {
32560
32537
  const rootEntry = scope.lookup(pathRoot(assignedPath));
32561
32538
  if (rootEntry) {
32562
- const receiverFacts = receiverNarrowings(
32539
+ const retainedFacts = unaffectedNarrowings(
32563
32540
  assignedPath,
32564
32541
  rootEntry,
32565
32542
  scope
32566
32543
  );
32567
32544
  scope.invalidate(rootEntry);
32568
- for (const [path, type] of receiverFacts) {
32545
+ for (const [path, type] of retainedFacts) {
32569
32546
  scope.narrow(path, rootEntry, type);
32570
32547
  }
32571
32548
  }
@@ -33180,18 +33157,19 @@ var init_strict_resolver = __esm({
33180
33157
  case "coalesce": {
33181
33158
  const left = this.resolveExpression(expression.left, scope);
33182
33159
  const leftOptional = { ...left.type, nullable: true };
33160
+ const nullLeft = isNull(left.type);
33183
33161
  const right = this.resolveExpression(
33184
33162
  expression.right,
33185
33163
  scope,
33186
- leftOptional
33164
+ nullLeft ? expected : leftOptional
33187
33165
  );
33188
- if (!isNeoScriptTypeAssignable(right.type, leftOptional, this.project)) {
33166
+ if (!nullLeft && !isNeoScriptTypeAssignable(right.type, leftOptional, this.project)) {
33189
33167
  throw new CompileError(
33190
33168
  `\`??\` right operand ${this.describe(right.type)} is not assignable to ${this.describe(leftOptional)}`,
33191
33169
  expression.pos
33192
33170
  );
33193
33171
  }
33194
- const resultType = {
33172
+ const resultType = nullLeft ? right.type : {
33195
33173
  ...left.type,
33196
33174
  nullable: isNullable(left.type) && isNullable(right.type)
33197
33175
  };
@@ -33892,20 +33870,25 @@ var init_strict_resolver = __esm({
33892
33870
  return whenTrue ? factsWhenTrue(expression, pathOf) : factsWhenFalse(expression, pathOf);
33893
33871
  }
33894
33872
  /**
33895
- * A loop body is resolved once but can execute repeatedly. Any narrowing rooted
33896
- * in an outer binding that the body or iterator may write is therefore stale
33897
- * at a later iteration entry. Invalidate those roots before resolving the
33898
- * shared iteration so only the loop's own condition can narrow them again.
33873
+ * A loop body is resolved once but can execute repeatedly. Hide facts about
33874
+ * paths it may replace before resolving the shared iteration; unrelated facts
33875
+ * still hold, and the loop condition can narrow the written paths again.
33899
33876
  */
33900
33877
  invalidateLoopEntryNarrowingsAssignedBy(loopEntryScope, outerScope, statements, locals = /* @__PURE__ */ new Set()) {
33901
- for (const rootName of collectAssignedPathRoots(
33878
+ for (const assignedPath of collectAssignedPaths(
33902
33879
  statements,
33903
33880
  /* @__PURE__ */ new Set(),
33904
33881
  locals
33905
33882
  )) {
33906
- const path = this.narrowingPath(rootName, outerScope);
33883
+ const path = this.narrowingPath(assignedPath, outerScope);
33907
33884
  const outerEntry = path === null ? null : outerScope.lookup(pathRoot(path));
33908
- if (outerEntry) loopEntryScope.hideInheritedNarrowing(outerEntry);
33885
+ if (outerEntry && path !== null) {
33886
+ const retained = unaffectedNarrowings(path, outerEntry, loopEntryScope);
33887
+ loopEntryScope.hideInheritedNarrowing(outerEntry);
33888
+ for (const [retainedPath, type] of retained) {
33889
+ loopEntryScope.narrow(retainedPath, outerEntry, type);
33890
+ }
33891
+ }
33909
33892
  }
33910
33893
  }
33911
33894
  applyFactsToScope(targetScope, facts, mode = "all") {
@@ -44074,7 +44057,7 @@ function validateExpression(expression, expected, scope, environment, uri, range
44074
44057
  if (expression.kind === "coalesce") {
44075
44058
  validateExpression(
44076
44059
  expression.left,
44077
- expected,
44060
+ expected ? { ...expected, nullable: true } : void 0,
44078
44061
  scope,
44079
44062
  environment,
44080
44063
  uri,
@@ -44085,7 +44068,7 @@ function validateExpression(expression, expected, scope, environment, uri, range
44085
44068
  const left = inferExpressionType(expression.left, scope, environment);
44086
44069
  validateExpression(
44087
44070
  expression.right,
44088
- left ?? expected,
44071
+ left && left.name !== "null" ? { ...left, nullable: true } : expected,
44089
44072
  scope,
44090
44073
  environment,
44091
44074
  uri,
@@ -44714,6 +44697,16 @@ function inferExpressionType(expression, scope, environment) {
44714
44697
  const operand = inferExpressionType(expression.operand, scope, environment);
44715
44698
  return operand ? { ...operand, nullable: false } : void 0;
44716
44699
  }
44700
+ if (expression.kind === "coalesce") {
44701
+ const left = inferExpressionType(expression.left, scope, environment);
44702
+ const right = inferExpressionType(expression.right, scope, environment);
44703
+ if (left?.name === "null") return right;
44704
+ if (!left || !right) return void 0;
44705
+ return {
44706
+ ...left,
44707
+ nullable: left.nullable === true && right.nullable === true
44708
+ };
44709
+ }
44717
44710
  if (expression.kind === "index") {
44718
44711
  const receiver = inferExpressionType(
44719
44712
  expression.receiver,
@@ -50982,7 +50975,7 @@ var init_registry = __esm({
50982
50975
  "../packages/manifest/schema-contract/registry.mjs"() {
50983
50976
  "use strict";
50984
50977
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
50985
- cliVersion: "0.72.2",
50978
+ cliVersion: "0.72.4",
50986
50979
  projectFileUploadBatchSize: 32,
50987
50980
  documentRecords: {
50988
50981
  member: {
@@ -125017,6 +125010,7 @@ function buildValueLowerContext(state, manifest, options = {}) {
125017
125010
  localizationConversionValueIds: registry.localizationConversionValueIds,
125018
125011
  loweredMemberIdByValueId: /* @__PURE__ */ new Map(),
125019
125012
  storedClassSchemaMemberIds: /* @__PURE__ */ new Map(),
125013
+ renamedSchemaKeys: /* @__PURE__ */ new Map(),
125020
125014
  ordinaryMoveFields: /* @__PURE__ */ new Map(),
125021
125015
  pendingBindingMembersByClassId: registry.pendingBindingMembersByClassId,
125022
125016
  declaredConstructors: declaredConstructorIndex,
@@ -126285,7 +126279,11 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
126285
126279
  environment,
126286
126280
  binding.label
126287
126281
  );
126288
- const baseBody = backed.body;
126282
+ const baseBody = retainedStoredClassBody(
126283
+ context,
126284
+ currentClassId,
126285
+ backed.body
126286
+ );
126289
126287
  const body = {};
126290
126288
  lowerConstructorProjections(
126291
126289
  context,
@@ -126685,12 +126683,43 @@ function pendingSeedGraphRows(args) {
126685
126683
  function retainedStoredClassBody(context, storedClassId, baseBody) {
126686
126684
  const storedMemberIds = storedClassSchemaMemberIds(context, storedClassId);
126687
126685
  const body = {};
126686
+ const renames = renamedSchemaKeys(context, storedClassId);
126688
126687
  for (const [key, childId] of Object.entries(baseBody)) {
126689
126688
  if (storedMemberRemoved(context, storedMemberIds, key)) continue;
126690
- body[key] = childId;
126689
+ body[renames.get(key) ?? key] = childId;
126691
126690
  }
126692
126691
  return body;
126693
126692
  }
126693
+ function renamedSchemaKeys(context, classId) {
126694
+ const cached = context.renamedSchemaKeys.get(classId);
126695
+ if (cached !== void 0) return cached;
126696
+ const currentMembers = /* @__PURE__ */ new Map();
126697
+ for (const schemaClass2 of classInheritanceChain(context.classes, classId)) {
126698
+ for (const [key, memberId] of Object.entries(schemaClass2.schema)) {
126699
+ if (!currentMembers.has(key)) currentMembers.set(key, memberId);
126700
+ }
126701
+ }
126702
+ const renamed = schemaKeyRenamesByMemberId(
126703
+ storedClassSchemaMemberIds(context, classId),
126704
+ currentMembers
126705
+ );
126706
+ context.renamedSchemaKeys.set(classId, renamed);
126707
+ return renamed;
126708
+ }
126709
+ function schemaKeyRenamesByMemberId(before, after) {
126710
+ const currentKeys = /* @__PURE__ */ new Map();
126711
+ for (const [key, memberId] of after) {
126712
+ if (memberId !== null && !currentKeys.has(memberId))
126713
+ currentKeys.set(memberId, key);
126714
+ }
126715
+ const renamed = /* @__PURE__ */ new Map();
126716
+ for (const [key, memberId] of before) {
126717
+ const currentKey = memberId === null ? void 0 : currentKeys.get(memberId);
126718
+ if (currentKey !== void 0 && currentKey !== key)
126719
+ renamed.set(key, currentKey);
126720
+ }
126721
+ return renamed;
126722
+ }
126694
126723
  function storedMemberRemoved(context, storedMemberIds, key) {
126695
126724
  const storedMemberId = storedMemberIds.get(key);
126696
126725
  return storedMemberId !== void 0 && !context.members.has(storedMemberId);
@@ -127932,7 +127961,7 @@ function lowerValueBody(context, member, expression, base, source, environment,
127932
127961
  );
127933
127962
  }
127934
127963
  }
127935
- function authoredResetSchemaKeys(context, base, baseBody, expression, partial) {
127964
+ function authoredResetSchemaKeys(context, base, baseBody, expression, partial, classId) {
127936
127965
  if (partial) return /* @__PURE__ */ new Set();
127937
127966
  if (expression.kind !== "new") return /* @__PURE__ */ new Set();
127938
127967
  if (typeof base.id !== "string") return /* @__PURE__ */ new Set();
@@ -127940,15 +127969,17 @@ function authoredResetSchemaKeys(context, base, baseBody, expression, partial) {
127940
127969
  (expression.initializer ?? []).map((assignment) => assignment.name)
127941
127970
  );
127942
127971
  const expressions = context.materializedConstructorExpressions;
127972
+ const renames = renamedSchemaKeys(context, classId);
127943
127973
  if (Object.keys(baseBody).every(
127944
- (key) => authored.has(key) || expressions.declaresSchemaKey?.(key) === false
127974
+ (key) => authored.has(renames.get(key) ?? key) || expressions.declaresSchemaKey?.(key) === false
127945
127975
  )) {
127946
127976
  return /* @__PURE__ */ new Set();
127947
127977
  }
127948
127978
  const canonicalOverrideKeys = expressions.overrideSchemaKeys?.(base.id);
127949
127979
  if (canonicalOverrideKeys === void 0) return /* @__PURE__ */ new Set();
127950
127980
  const resets = /* @__PURE__ */ new Set();
127951
- for (const schemaKey of canonicalOverrideKeys) {
127981
+ for (const storedKey of canonicalOverrideKeys) {
127982
+ const schemaKey = renames.get(storedKey) ?? storedKey;
127952
127983
  if (!authored.has(schemaKey)) resets.add(schemaKey);
127953
127984
  }
127954
127985
  return resets;
@@ -128005,7 +128036,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
128005
128036
  schemaClass2,
128006
128037
  expression,
128007
128038
  base,
128008
- baseBody,
128039
+ body,
128009
128040
  body,
128010
128041
  source,
128011
128042
  environment,
@@ -128075,7 +128106,8 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
128075
128106
  base,
128076
128107
  baseBody,
128077
128108
  expression,
128078
- partial
128109
+ partial,
128110
+ currentClassId
128079
128111
  );
128080
128112
  for (const schemaKey of resetSchemaKeys) delete body[schemaKey];
128081
128113
  {
@@ -128083,10 +128115,12 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
128083
128115
  (expression.initializer ?? []).map((assignment) => assignment.name)
128084
128116
  );
128085
128117
  const storedMemberIds = storedClassSchemaMemberIds(context, currentClassId);
128086
- for (const [schemaKey, childId] of Object.entries(baseBody)) {
128118
+ const renames = renamedSchemaKeys(context, currentClassId);
128119
+ for (const [storedKey, childId] of Object.entries(baseBody)) {
128120
+ const schemaKey = renames.get(storedKey) ?? storedKey;
128087
128121
  if (typeof childId !== "string") continue;
128088
128122
  if (resetSchemaKeys.has(schemaKey)) continue;
128089
- if (storedMemberRemoved(context, storedMemberIds, schemaKey)) continue;
128123
+ if (storedMemberRemoved(context, storedMemberIds, storedKey)) continue;
128090
128124
  if (materializedConstruction === "lower" && authoredKeys.has(schemaKey)) {
128091
128125
  continue;
128092
128126
  }
@@ -128095,7 +128129,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
128095
128129
  childId,
128096
128130
  source.source,
128097
128131
  /* @__PURE__ */ new Set(),
128098
- memberById(context, storedMemberIds.get(schemaKey)),
128132
+ memberById(context, storedMemberIds.get(storedKey)),
128099
128133
  environment
128100
128134
  );
128101
128135
  }
@@ -128195,14 +128229,18 @@ function retainStoredValueSubgraph(context, valueId, source, visited, member, en
128195
128229
  visited.add(valueId);
128196
128230
  const state = context.state[`value:${valueId}`];
128197
128231
  if (state === void 0 || !isObjectRecord2(state.data)) return;
128198
- addReconstructed(
128199
- context,
128200
- "value",
128201
- valueId,
128202
- valueFileFields(state.data),
128203
- source,
128204
- { retained: true }
128205
- );
128232
+ const storedClassId = stringOrNull2(state.data.classId);
128233
+ const fields = valueFileFields(state.data);
128234
+ if (storedClassId !== null && isObjectRecord2(state.data.value) && renamedSchemaKeys(context, storedClassId).size > 0) {
128235
+ fields.value = retainedStoredClassBody(
128236
+ context,
128237
+ storedClassId,
128238
+ state.data.value
128239
+ );
128240
+ }
128241
+ addReconstructed(context, "value", valueId, fields, source, {
128242
+ retained: true
128243
+ });
128206
128244
  const rawOwningMember = member ?? storedRowPlacementMember(context, valueId);
128207
128245
  const owningMember = rawOwningMember === null ? null : resolveGenericSchemaMember(context, rawOwningMember, environment);
128208
128246
  if (owningMember?.kind === "string" && owningMember.localizable) {
@@ -128250,7 +128288,6 @@ function retainStoredValueSubgraph(context, valueId, source, visited, member, en
128250
128288
  for (const entry of Object.values(value)) collect(entry, childMember);
128251
128289
  };
128252
128290
  const body = state.data.value;
128253
- const storedClassId = stringOrNull2(state.data.classId);
128254
128291
  let childEnvironment = environment;
128255
128292
  if (storedClassId !== null) {
128256
128293
  if (owningMember?.kind === "class") {
@@ -128395,13 +128432,14 @@ function classProjectsEveryStoredConstructorRow(context, classId, argumentCount,
128395
128432
  if (projections2.length === 0 || projections2.length !== argumentCount) {
128396
128433
  return false;
128397
128434
  }
128435
+ const body = renamedSchemaKeys(context, classId).size === 0 ? storedBody : retainedStoredClassBody(context, classId, storedBody);
128398
128436
  return projections2.every((projection) => {
128399
128437
  const schemaKey = inheritedProjectionSchemaKey(
128400
128438
  context.classes,
128401
128439
  classId,
128402
128440
  projection.memberId
128403
128441
  );
128404
- return schemaKey !== null && typeof storedBody[schemaKey] === "string";
128442
+ return schemaKey !== null && typeof body[schemaKey] === "string";
128405
128443
  });
128406
128444
  }
128407
128445
  function requiredConstructorProjectionMap(classes, constructors, members, classId, visited) {
@@ -138693,7 +138731,7 @@ function materializedInitializerReconciliationFailuresV4(args) {
138693
138731
  continue;
138694
138732
  }
138695
138733
  assertPulledConstructorsCompiled(replayDocument, replayContext);
138696
- currentRows ??= new Map(currentDocument.values.map((row) => [row.id, row]));
138734
+ currentRows ??= storedRowsWithRenamedKeys(currentDocument, replayDocument);
138697
138735
  currentReader ??= new EffectiveValueReader(replayDocument, currentRows);
138698
138736
  const replay = replayRows.get(reconciliation.valueId);
138699
138737
  const replayArgs = replay !== void 0 && isLiteralValueContent(replay) ? replay.constructorArgs : void 0;
@@ -138725,6 +138763,41 @@ function materializedInitializerReconciliationFailuresV4(args) {
138725
138763
  }
138726
138764
  return failures;
138727
138765
  }
138766
+ function storedRowsWithRenamedKeys(before, after) {
138767
+ const renamesByClass = /* @__PURE__ */ new Map();
138768
+ const rows = /* @__PURE__ */ new Map();
138769
+ for (const row of before.values) {
138770
+ let renamed = row;
138771
+ if (typeof row.classId === "string" && isObjectRecord2(row.value)) {
138772
+ const classId = row.classId;
138773
+ let renames = renamesByClass.get(classId);
138774
+ if (renames === void 0) {
138775
+ const entries = (document) => mergeInstanceSurfaceSchema(
138776
+ classId,
138777
+ document.classes,
138778
+ document.members
138779
+ ).map((entry) => [entry.schemaKey, entry.memberId]);
138780
+ renames = schemaKeyRenamesByMemberId(entries(before), entries(after));
138781
+ renamesByClass.set(row.classId, renames);
138782
+ }
138783
+ if (renames.size > 0) {
138784
+ const value = {};
138785
+ let collision = false;
138786
+ for (const [key, child2] of Object.entries(row.value)) {
138787
+ const target = renames.get(key) ?? key;
138788
+ if (target !== key && Object.hasOwn(row.value, target) && !renames.has(target)) {
138789
+ collision = true;
138790
+ break;
138791
+ }
138792
+ value[target] = child2;
138793
+ }
138794
+ if (!collision) renamed = { ...row, value };
138795
+ }
138796
+ }
138797
+ rows.set(row.id, renamed);
138798
+ }
138799
+ return rows;
138800
+ }
138728
138801
  function withoutSharedArguments(stored, replayed) {
138729
138802
  const storedRest = { ...stored };
138730
138803
  const replayedRest = { ...replayed };
@@ -139108,6 +139181,7 @@ var init_local_initializer_materialization = __esm({
139108
139181
  init_variant_value_graph();
139109
139182
  init_members();
139110
139183
  init_member_value_id();
139184
+ init_inheritance();
139111
139185
  init_effective_value_reader();
139112
139186
  init_virtual_instance_values();
139113
139187
  init_value_graph();
@@ -140319,33 +140393,35 @@ function computeWorkspaceStatus(workspace, options) {
140319
140393
  )
140320
140394
  );
140321
140395
  }
140322
- try {
140323
- parseErrors.push(
140324
- ...materializedInitializerReconciliationFailuresV4({
140325
- workspace,
140326
- changes,
140327
- authoredValueSeeds,
140328
- reconciliations: valueLowerRegistry.initializerReconciliations,
140329
- canonicalConstructions: valueLowerRegistry.materializedConstructorExpressions,
140330
- localizedTextDependencies,
140331
- manifest,
140332
- analysis: projectAnalysisV4,
140333
- forceRecompile: options.forceRecompile,
140334
- useBuildCaches: options.useBuildCaches,
140335
- sourceTextByUri: new Map(
140336
- sourceEntries.map((entry) => [entry.relPath, entry.source])
140396
+ if (!parseErrors.some(isBlockingSchemaSourceError)) {
140397
+ try {
140398
+ parseErrors.push(
140399
+ ...materializedInitializerReconciliationFailuresV4({
140400
+ workspace,
140401
+ changes,
140402
+ authoredValueSeeds,
140403
+ reconciliations: valueLowerRegistry.initializerReconciliations,
140404
+ canonicalConstructions: valueLowerRegistry.materializedConstructorExpressions,
140405
+ localizedTextDependencies,
140406
+ manifest,
140407
+ analysis: projectAnalysisV4,
140408
+ forceRecompile: options.forceRecompile,
140409
+ useBuildCaches: options.useBuildCaches,
140410
+ sourceTextByUri: new Map(
140411
+ sourceEntries.map((entry) => [entry.relPath, entry.source])
140412
+ )
140413
+ })
140414
+ );
140415
+ } catch (error) {
140416
+ parseErrors.push(
140417
+ error instanceof SchemaSourceError ? error : new SchemaSourceError(
140418
+ error instanceof Error ? error.message : String(error),
140419
+ "<initializer-materialization>",
140420
+ 1,
140421
+ 1
140337
140422
  )
140338
- })
140339
- );
140340
- } catch (error) {
140341
- parseErrors.push(
140342
- error instanceof SchemaSourceError ? error : new SchemaSourceError(
140343
- error instanceof Error ? error.message : String(error),
140344
- "<initializer-materialization>",
140345
- 1,
140346
- 1
140347
- )
140348
- );
140423
+ );
140424
+ }
140349
140425
  }
140350
140426
  reportPhase("initializer-reconciliation", "Checking project files\u2026");
140351
140427
  for (const fileId of options.trustedPendingProjectFiles?.keys() ?? []) {
@@ -140410,7 +140486,7 @@ function computeWorkspaceStatus(workspace, options) {
140410
140486
  )) {
140411
140487
  parseErrors.push(new SchemaSourceError(message, "<project-files>", 1, 1));
140412
140488
  }
140413
- if (animationValidationInputsChanged(changes, authoredValueSeeds)) {
140489
+ if (!parseErrors.some(isBlockingSchemaSourceError) && animationValidationInputsChanged(changes, authoredValueSeeds)) {
140414
140490
  try {
140415
140491
  const animationRecords = prospectiveAnimationRecords(
140416
140492
  workspace.state.records,
@@ -190443,7 +190519,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
190443
190519
  async function main() {
190444
190520
  const args = parseArgs(process.argv.slice(2));
190445
190521
  if (args.command === "--version") {
190446
- console.log("0.72.2");
190522
+ console.log("0.72.4");
190447
190523
  return;
190448
190524
  }
190449
190525
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {