@angular/compiler 18.1.0-next.2 → 18.1.0-next.3

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 (35) hide show
  1. package/esm2022/src/expression_parser/ast.mjs +1 -1
  2. package/esm2022/src/expression_parser/parser.mjs +4 -2
  3. package/esm2022/src/render3/partial/class_metadata.mjs +2 -2
  4. package/esm2022/src/render3/partial/directive.mjs +1 -1
  5. package/esm2022/src/render3/partial/factory.mjs +1 -1
  6. package/esm2022/src/render3/partial/injectable.mjs +1 -1
  7. package/esm2022/src/render3/partial/injector.mjs +1 -1
  8. package/esm2022/src/render3/partial/ng_module.mjs +1 -1
  9. package/esm2022/src/render3/partial/pipe.mjs +1 -1
  10. package/esm2022/src/render3/r3_identifiers.mjs +4 -1
  11. package/esm2022/src/template/pipeline/ir/src/enums.mjs +45 -29
  12. package/esm2022/src/template/pipeline/ir/src/expression.mjs +60 -12
  13. package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +15 -1
  14. package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +16 -1
  15. package/esm2022/src/template/pipeline/ir/src/traits.mjs +3 -6
  16. package/esm2022/src/template/pipeline/src/emit.mjs +7 -1
  17. package/esm2022/src/template/pipeline/src/ingest.mjs +8 -3
  18. package/esm2022/src/template/pipeline/src/instruction.mjs +10 -1
  19. package/esm2022/src/template/pipeline/src/phases/chaining.mjs +2 -1
  20. package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +17 -7
  21. package/esm2022/src/template/pipeline/src/phases/generate_local_let_references.mjs +28 -0
  22. package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +22 -7
  23. package/esm2022/src/template/pipeline/src/phases/next_context_merging.mjs +2 -1
  24. package/esm2022/src/template/pipeline/src/phases/reify.mjs +10 -1
  25. package/esm2022/src/template/pipeline/src/phases/remove_illegal_let_references.mjs +36 -0
  26. package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +1 -1
  27. package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +2 -2
  28. package/esm2022/src/template/pipeline/src/phases/store_let_optimization.mjs +35 -0
  29. package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +4 -1
  30. package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +4 -1
  31. package/esm2022/src/version.mjs +1 -1
  32. package/fesm2022/compiler.mjs +304 -69
  33. package/fesm2022/compiler.mjs.map +1 -1
  34. package/index.d.ts +5 -1
  35. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v18.1.0-next.2
2
+ * @license Angular v18.1.0-next.3
3
3
  * (c) 2010-2024 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -2884,6 +2884,9 @@ class Identifiers {
2884
2884
  static { this.twoWayProperty = { name: 'ɵɵtwoWayProperty', moduleName: CORE }; }
2885
2885
  static { this.twoWayBindingSet = { name: 'ɵɵtwoWayBindingSet', moduleName: CORE }; }
2886
2886
  static { this.twoWayListener = { name: 'ɵɵtwoWayListener', moduleName: CORE }; }
2887
+ static { this.declareLet = { name: 'ɵɵdeclareLet', moduleName: CORE }; }
2888
+ static { this.storeLet = { name: 'ɵɵstoreLet', moduleName: CORE }; }
2889
+ static { this.readContextLet = { name: 'ɵɵreadContextLet', moduleName: CORE }; }
2887
2890
  static { this.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE }; }
2888
2891
  static { this.InheritDefinitionFeature = {
2889
2892
  name: 'ɵɵInheritDefinitionFeature',
@@ -8295,46 +8298,54 @@ var OpKind;
8295
8298
  * An operation declaring the event side of a two-way binding.
8296
8299
  */
8297
8300
  OpKind[OpKind["TwoWayListener"] = 37] = "TwoWayListener";
8301
+ /**
8302
+ * A creation-time operation that initializes the slot for a `@let` declaration.
8303
+ */
8304
+ OpKind[OpKind["DeclareLet"] = 38] = "DeclareLet";
8305
+ /**
8306
+ * An update-time operation that stores the current value of a `@let` declaration.
8307
+ */
8308
+ OpKind[OpKind["StoreLet"] = 39] = "StoreLet";
8298
8309
  /**
8299
8310
  * The start of an i18n block.
8300
8311
  */
8301
- OpKind[OpKind["I18nStart"] = 38] = "I18nStart";
8312
+ OpKind[OpKind["I18nStart"] = 40] = "I18nStart";
8302
8313
  /**
8303
8314
  * A self-closing i18n on a single element.
8304
8315
  */
8305
- OpKind[OpKind["I18n"] = 39] = "I18n";
8316
+ OpKind[OpKind["I18n"] = 41] = "I18n";
8306
8317
  /**
8307
8318
  * The end of an i18n block.
8308
8319
  */
8309
- OpKind[OpKind["I18nEnd"] = 40] = "I18nEnd";
8320
+ OpKind[OpKind["I18nEnd"] = 42] = "I18nEnd";
8310
8321
  /**
8311
8322
  * An expression in an i18n message.
8312
8323
  */
8313
- OpKind[OpKind["I18nExpression"] = 41] = "I18nExpression";
8324
+ OpKind[OpKind["I18nExpression"] = 43] = "I18nExpression";
8314
8325
  /**
8315
8326
  * An instruction that applies a set of i18n expressions.
8316
8327
  */
8317
- OpKind[OpKind["I18nApply"] = 42] = "I18nApply";
8328
+ OpKind[OpKind["I18nApply"] = 44] = "I18nApply";
8318
8329
  /**
8319
8330
  * An instruction to create an ICU expression.
8320
8331
  */
8321
- OpKind[OpKind["IcuStart"] = 43] = "IcuStart";
8332
+ OpKind[OpKind["IcuStart"] = 45] = "IcuStart";
8322
8333
  /**
8323
8334
  * An instruction to update an ICU expression.
8324
8335
  */
8325
- OpKind[OpKind["IcuEnd"] = 44] = "IcuEnd";
8336
+ OpKind[OpKind["IcuEnd"] = 46] = "IcuEnd";
8326
8337
  /**
8327
8338
  * An instruction representing a placeholder in an ICU expression.
8328
8339
  */
8329
- OpKind[OpKind["IcuPlaceholder"] = 45] = "IcuPlaceholder";
8340
+ OpKind[OpKind["IcuPlaceholder"] = 47] = "IcuPlaceholder";
8330
8341
  /**
8331
8342
  * An i18n context containing information needed to generate an i18n message.
8332
8343
  */
8333
- OpKind[OpKind["I18nContext"] = 46] = "I18nContext";
8344
+ OpKind[OpKind["I18nContext"] = 48] = "I18nContext";
8334
8345
  /**
8335
8346
  * A creation op that corresponds to i18n attributes on an element.
8336
8347
  */
8337
- OpKind[OpKind["I18nAttributes"] = 47] = "I18nAttributes";
8348
+ OpKind[OpKind["I18nAttributes"] = 49] = "I18nAttributes";
8338
8349
  })(OpKind || (OpKind = {}));
8339
8350
  /**
8340
8351
  * Distinguishes different kinds of IR expressions.
@@ -8365,78 +8376,86 @@ var ExpressionKind;
8365
8376
  * Runtime operation to retrieve the value of a local reference.
8366
8377
  */
8367
8378
  ExpressionKind[ExpressionKind["Reference"] = 5] = "Reference";
8379
+ /**
8380
+ * A call storing the value of a `@let` declaration.
8381
+ */
8382
+ ExpressionKind[ExpressionKind["StoreLet"] = 6] = "StoreLet";
8383
+ /**
8384
+ * A reference to a `@let` declaration read from the context view.
8385
+ */
8386
+ ExpressionKind[ExpressionKind["ContextLetReference"] = 7] = "ContextLetReference";
8368
8387
  /**
8369
8388
  * Runtime operation to snapshot the current view context.
8370
8389
  */
8371
- ExpressionKind[ExpressionKind["GetCurrentView"] = 6] = "GetCurrentView";
8390
+ ExpressionKind[ExpressionKind["GetCurrentView"] = 8] = "GetCurrentView";
8372
8391
  /**
8373
8392
  * Runtime operation to restore a snapshotted view.
8374
8393
  */
8375
- ExpressionKind[ExpressionKind["RestoreView"] = 7] = "RestoreView";
8394
+ ExpressionKind[ExpressionKind["RestoreView"] = 9] = "RestoreView";
8376
8395
  /**
8377
8396
  * Runtime operation to reset the current view context after `RestoreView`.
8378
8397
  */
8379
- ExpressionKind[ExpressionKind["ResetView"] = 8] = "ResetView";
8398
+ ExpressionKind[ExpressionKind["ResetView"] = 10] = "ResetView";
8380
8399
  /**
8381
8400
  * Defines and calls a function with change-detected arguments.
8382
8401
  */
8383
- ExpressionKind[ExpressionKind["PureFunctionExpr"] = 9] = "PureFunctionExpr";
8402
+ ExpressionKind[ExpressionKind["PureFunctionExpr"] = 11] = "PureFunctionExpr";
8384
8403
  /**
8385
8404
  * Indicates a positional parameter to a pure function definition.
8386
8405
  */
8387
- ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 10] = "PureFunctionParameterExpr";
8406
+ ExpressionKind[ExpressionKind["PureFunctionParameterExpr"] = 12] = "PureFunctionParameterExpr";
8388
8407
  /**
8389
8408
  * Binding to a pipe transformation.
8390
8409
  */
8391
- ExpressionKind[ExpressionKind["PipeBinding"] = 11] = "PipeBinding";
8410
+ ExpressionKind[ExpressionKind["PipeBinding"] = 13] = "PipeBinding";
8392
8411
  /**
8393
8412
  * Binding to a pipe transformation with a variable number of arguments.
8394
8413
  */
8395
- ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 12] = "PipeBindingVariadic";
8414
+ ExpressionKind[ExpressionKind["PipeBindingVariadic"] = 14] = "PipeBindingVariadic";
8396
8415
  /*
8397
8416
  * A safe property read requiring expansion into a null check.
8398
8417
  */
8399
- ExpressionKind[ExpressionKind["SafePropertyRead"] = 13] = "SafePropertyRead";
8418
+ ExpressionKind[ExpressionKind["SafePropertyRead"] = 15] = "SafePropertyRead";
8400
8419
  /**
8401
8420
  * A safe keyed read requiring expansion into a null check.
8402
8421
  */
8403
- ExpressionKind[ExpressionKind["SafeKeyedRead"] = 14] = "SafeKeyedRead";
8422
+ ExpressionKind[ExpressionKind["SafeKeyedRead"] = 16] = "SafeKeyedRead";
8404
8423
  /**
8405
8424
  * A safe function call requiring expansion into a null check.
8406
8425
  */
8407
- ExpressionKind[ExpressionKind["SafeInvokeFunction"] = 15] = "SafeInvokeFunction";
8426
+ ExpressionKind[ExpressionKind["SafeInvokeFunction"] = 17] = "SafeInvokeFunction";
8408
8427
  /**
8409
8428
  * An intermediate expression that will be expanded from a safe read into an explicit ternary.
8410
8429
  */
8411
- ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 16] = "SafeTernaryExpr";
8430
+ ExpressionKind[ExpressionKind["SafeTernaryExpr"] = 18] = "SafeTernaryExpr";
8412
8431
  /**
8413
8432
  * An empty expression that will be stipped before generating the final output.
8414
8433
  */
8415
- ExpressionKind[ExpressionKind["EmptyExpr"] = 17] = "EmptyExpr";
8434
+ ExpressionKind[ExpressionKind["EmptyExpr"] = 19] = "EmptyExpr";
8416
8435
  /*
8417
8436
  * An assignment to a temporary variable.
8418
8437
  */
8419
- ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 18] = "AssignTemporaryExpr";
8438
+ ExpressionKind[ExpressionKind["AssignTemporaryExpr"] = 20] = "AssignTemporaryExpr";
8420
8439
  /**
8421
8440
  * A reference to a temporary variable.
8422
8441
  */
8423
- ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 19] = "ReadTemporaryExpr";
8442
+ ExpressionKind[ExpressionKind["ReadTemporaryExpr"] = 21] = "ReadTemporaryExpr";
8424
8443
  /**
8425
8444
  * An expression that will cause a literal slot index to be emitted.
8426
8445
  */
8427
- ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 20] = "SlotLiteralExpr";
8446
+ ExpressionKind[ExpressionKind["SlotLiteralExpr"] = 22] = "SlotLiteralExpr";
8428
8447
  /**
8429
8448
  * A test expression for a conditional op.
8430
8449
  */
8431
- ExpressionKind[ExpressionKind["ConditionalCase"] = 21] = "ConditionalCase";
8450
+ ExpressionKind[ExpressionKind["ConditionalCase"] = 23] = "ConditionalCase";
8432
8451
  /**
8433
8452
  * An expression that will be automatically extracted to the component const array.
8434
8453
  */
8435
- ExpressionKind[ExpressionKind["ConstCollected"] = 22] = "ConstCollected";
8454
+ ExpressionKind[ExpressionKind["ConstCollected"] = 24] = "ConstCollected";
8436
8455
  /**
8437
8456
  * Operation that sets the value of a two-way binding.
8438
8457
  */
8439
- ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 23] = "TwoWayBindingSet";
8458
+ ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 25] = "TwoWayBindingSet";
8440
8459
  })(ExpressionKind || (ExpressionKind = {}));
8441
8460
  var VariableFlags;
8442
8461
  (function (VariableFlags) {
@@ -8657,11 +8676,8 @@ const TRAIT_CONSUMES_VARS = {
8657
8676
  function hasConsumesSlotTrait(op) {
8658
8677
  return op[ConsumesSlot] === true;
8659
8678
  }
8660
- /**
8661
- * Test whether an operation implements `DependsOnSlotContextOpTrait`.
8662
- */
8663
- function hasDependsOnSlotContextTrait(op) {
8664
- return op[DependsOnSlotContext] === true;
8679
+ function hasDependsOnSlotContextTrait(value) {
8680
+ return value[DependsOnSlotContext] === true;
8665
8681
  }
8666
8682
  function hasConsumesVarsTrait(value) {
8667
8683
  return value[ConsumesVarsTrait] === true;
@@ -8959,8 +8975,23 @@ function createI18nApplyOp(owner, handle, sourceSpan) {
8959
8975
  ...NEW_OP,
8960
8976
  };
8961
8977
  }
8978
+ /**
8979
+ * Creates a `StoreLetOp`.
8980
+ */
8981
+ function createStoreLetOp(target, declaredName, value, sourceSpan) {
8982
+ return {
8983
+ kind: OpKind.StoreLet,
8984
+ target,
8985
+ declaredName,
8986
+ value,
8987
+ sourceSpan,
8988
+ ...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
8989
+ ...TRAIT_CONSUMES_VARS,
8990
+ ...NEW_OP,
8991
+ };
8992
+ }
8962
8993
 
8963
- var _a, _b, _c, _d, _e, _f;
8994
+ var _a, _b, _c, _d, _e, _f, _g, _h;
8964
8995
  /**
8965
8996
  * Check whether a given `o.Expression` is a logical IR expression type.
8966
8997
  */
@@ -9022,6 +9053,50 @@ class ReferenceExpr extends ExpressionBase {
9022
9053
  return new ReferenceExpr(this.target, this.targetSlot, this.offset);
9023
9054
  }
9024
9055
  }
9056
+ class StoreLetExpr extends ExpressionBase {
9057
+ static { _a = ConsumesVarsTrait, _b = DependsOnSlotContext; }
9058
+ constructor(target, value, sourceSpan) {
9059
+ super();
9060
+ this.target = target;
9061
+ this.value = value;
9062
+ this.sourceSpan = sourceSpan;
9063
+ this.kind = ExpressionKind.StoreLet;
9064
+ this[_a] = true;
9065
+ this[_b] = true;
9066
+ }
9067
+ visitExpression() { }
9068
+ isEquivalent(e) {
9069
+ return (e instanceof StoreLetExpr && e.target === this.target && e.value.isEquivalent(this.value));
9070
+ }
9071
+ isConstant() {
9072
+ return false;
9073
+ }
9074
+ transformInternalExpressions(transform, flags) {
9075
+ this.value = transformExpressionsInExpression(this.value, transform, flags);
9076
+ }
9077
+ clone() {
9078
+ return new StoreLetExpr(this.target, this.value, this.sourceSpan);
9079
+ }
9080
+ }
9081
+ class ContextLetReferenceExpr extends ExpressionBase {
9082
+ constructor(target, targetSlot) {
9083
+ super();
9084
+ this.target = target;
9085
+ this.targetSlot = targetSlot;
9086
+ this.kind = ExpressionKind.ContextLetReference;
9087
+ }
9088
+ visitExpression() { }
9089
+ isEquivalent(e) {
9090
+ return e instanceof ContextLetReferenceExpr && e.target === this.target;
9091
+ }
9092
+ isConstant() {
9093
+ return false;
9094
+ }
9095
+ transformInternalExpressions() { }
9096
+ clone() {
9097
+ return new ContextLetReferenceExpr(this.target, this.targetSlot);
9098
+ }
9099
+ }
9025
9100
  /**
9026
9101
  * A reference to the current view context (usually the `ctx` variable in a template function).
9027
9102
  */
@@ -9222,12 +9297,12 @@ class ReadVariableExpr extends ExpressionBase {
9222
9297
  }
9223
9298
  }
9224
9299
  class PureFunctionExpr extends ExpressionBase {
9225
- static { _a = ConsumesVarsTrait, _b = UsesVarOffset; }
9300
+ static { _c = ConsumesVarsTrait, _d = UsesVarOffset; }
9226
9301
  constructor(expression, args) {
9227
9302
  super();
9228
9303
  this.kind = ExpressionKind.PureFunctionExpr;
9229
- this[_a] = true;
9230
- this[_b] = true;
9304
+ this[_c] = true;
9305
+ this[_d] = true;
9231
9306
  this.varOffset = null;
9232
9307
  /**
9233
9308
  * Once extracted to the `ConstantPool`, a reference to the function which defines the computation
@@ -9293,7 +9368,7 @@ class PureFunctionParameterExpr extends ExpressionBase {
9293
9368
  }
9294
9369
  }
9295
9370
  class PipeBindingExpr extends ExpressionBase {
9296
- static { _c = ConsumesVarsTrait, _d = UsesVarOffset; }
9371
+ static { _e = ConsumesVarsTrait, _f = UsesVarOffset; }
9297
9372
  constructor(target, targetSlot, name, args) {
9298
9373
  super();
9299
9374
  this.target = target;
@@ -9301,8 +9376,8 @@ class PipeBindingExpr extends ExpressionBase {
9301
9376
  this.name = name;
9302
9377
  this.args = args;
9303
9378
  this.kind = ExpressionKind.PipeBinding;
9304
- this[_c] = true;
9305
- this[_d] = true;
9379
+ this[_e] = true;
9380
+ this[_f] = true;
9306
9381
  this.varOffset = null;
9307
9382
  }
9308
9383
  visitExpression(visitor, context) {
@@ -9328,7 +9403,7 @@ class PipeBindingExpr extends ExpressionBase {
9328
9403
  }
9329
9404
  }
9330
9405
  class PipeBindingVariadicExpr extends ExpressionBase {
9331
- static { _e = ConsumesVarsTrait, _f = UsesVarOffset; }
9406
+ static { _g = ConsumesVarsTrait, _h = UsesVarOffset; }
9332
9407
  constructor(target, targetSlot, name, args, numArgs) {
9333
9408
  super();
9334
9409
  this.target = target;
@@ -9337,8 +9412,8 @@ class PipeBindingVariadicExpr extends ExpressionBase {
9337
9412
  this.args = args;
9338
9413
  this.numArgs = numArgs;
9339
9414
  this.kind = ExpressionKind.PipeBindingVariadic;
9340
- this[_e] = true;
9341
- this[_f] = true;
9415
+ this[_g] = true;
9416
+ this[_h] = true;
9342
9417
  this.varOffset = null;
9343
9418
  }
9344
9419
  visitExpression(visitor, context) {
@@ -9732,6 +9807,9 @@ function transformExpressionsInOp(op, transform, flags) {
9732
9807
  case OpKind.DeferWhen:
9733
9808
  op.expr = transformExpressionsInExpression(op.expr, transform, flags);
9734
9809
  break;
9810
+ case OpKind.StoreLet:
9811
+ op.value = transformExpressionsInExpression(op.value, transform, flags);
9812
+ break;
9735
9813
  case OpKind.Advance:
9736
9814
  case OpKind.Container:
9737
9815
  case OpKind.ContainerEnd:
@@ -9757,6 +9835,7 @@ function transformExpressionsInOp(op, transform, flags) {
9757
9835
  case OpKind.Text:
9758
9836
  case OpKind.I18nAttributes:
9759
9837
  case OpKind.IcuPlaceholder:
9838
+ case OpKind.DeclareLet:
9760
9839
  // These operations contain no expressions.
9761
9840
  break;
9762
9841
  default:
@@ -10424,6 +10503,20 @@ function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
10424
10503
  ...NEW_OP,
10425
10504
  };
10426
10505
  }
10506
+ /**
10507
+ * Creates a `DeclareLetOp`.
10508
+ */
10509
+ function createDeclareLetOp(xref, declaredName, sourceSpan) {
10510
+ return {
10511
+ kind: OpKind.DeclareLet,
10512
+ xref,
10513
+ declaredName,
10514
+ sourceSpan,
10515
+ handle: new SlotHandle(),
10516
+ ...TRAIT_CONSUMES_SLOT,
10517
+ ...NEW_OP,
10518
+ };
10519
+ }
10427
10520
  /**
10428
10521
  * Create an `ExtractedMessageOp`.
10429
10522
  */
@@ -11117,6 +11210,7 @@ const CHAINABLE = new Set([
11117
11210
  Identifiers.templateCreate,
11118
11211
  Identifiers.twoWayProperty,
11119
11212
  Identifiers.twoWayListener,
11213
+ Identifiers.declareLet,
11120
11214
  ]);
11121
11215
  /**
11122
11216
  * Post-process a reified view compilation and convert sequential calls to chainable instructions
@@ -12287,16 +12381,26 @@ function generateAdvance(job) {
12287
12381
  // To do that, we track what the runtime's slot counter will be through the update operations.
12288
12382
  let slotContext = 0;
12289
12383
  for (const op of unit.update) {
12290
- if (!hasDependsOnSlotContextTrait(op)) {
12291
- // `op` doesn't depend on the slot counter, so it can be skipped.
12384
+ let consumer = null;
12385
+ if (hasDependsOnSlotContextTrait(op)) {
12386
+ consumer = op;
12387
+ }
12388
+ else {
12389
+ visitExpressionsInOp(op, (expr) => {
12390
+ if (consumer === null && hasDependsOnSlotContextTrait(expr)) {
12391
+ consumer = expr;
12392
+ }
12393
+ });
12394
+ }
12395
+ if (consumer === null) {
12292
12396
  continue;
12293
12397
  }
12294
- else if (!slotMap.has(op.target)) {
12398
+ if (!slotMap.has(consumer.target)) {
12295
12399
  // We expect ops that _do_ depend on the slot counter to point at declarations that exist in
12296
12400
  // the `slotMap`.
12297
- throw new Error(`AssertionError: reference to unknown slot for target ${op.target}`);
12401
+ throw new Error(`AssertionError: reference to unknown slot for target ${consumer.target}`);
12298
12402
  }
12299
- const slot = slotMap.get(op.target);
12403
+ const slot = slotMap.get(consumer.target);
12300
12404
  // Does the slot counter need to be adjusted?
12301
12405
  if (slotContext !== slot) {
12302
12406
  // If so, generate an `ir.AdvanceOp` to advance the counter.
@@ -12304,7 +12408,7 @@ function generateAdvance(job) {
12304
12408
  if (delta < 0) {
12305
12409
  throw new Error(`AssertionError: slot counter should never need to move backwards`);
12306
12410
  }
12307
- OpList.insertBefore(createAdvanceOp(delta, op.sourceSpan), op);
12411
+ OpList.insertBefore(createAdvanceOp(delta, consumer.sourceSpan), op);
12308
12412
  slotContext = slot;
12309
12413
  }
12310
12414
  }
@@ -12395,13 +12499,11 @@ function recursivelyProcessView(view, parentScope) {
12395
12499
  case OpKind.Listener:
12396
12500
  case OpKind.TwoWayListener:
12397
12501
  // Prepend variables to listener handler functions.
12398
- op.handlerOps.prepend(generateVariablesInScopeForView(view, scope));
12502
+ op.handlerOps.prepend(generateVariablesInScopeForView(view, scope, true));
12399
12503
  break;
12400
12504
  }
12401
12505
  }
12402
- // Prepend the declarations for all available variables in scope to the `update` block.
12403
- const preambleOps = generateVariablesInScopeForView(view, scope);
12404
- view.update.prepend(preambleOps);
12506
+ view.update.prepend(generateVariablesInScopeForView(view, scope, false));
12405
12507
  }
12406
12508
  /**
12407
12509
  * Process a view and generate a `Scope` representing the variables available for reference within
@@ -12418,6 +12520,7 @@ function getScopeForView(view, parent) {
12418
12520
  contextVariables: new Map(),
12419
12521
  aliases: view.aliases,
12420
12522
  references: [],
12523
+ letDeclarations: [],
12421
12524
  parent,
12422
12525
  };
12423
12526
  for (const identifier of view.contextVariables.keys()) {
@@ -12449,6 +12552,17 @@ function getScopeForView(view, parent) {
12449
12552
  });
12450
12553
  }
12451
12554
  break;
12555
+ case OpKind.DeclareLet:
12556
+ scope.letDeclarations.push({
12557
+ targetId: op.xref,
12558
+ targetSlot: op.handle,
12559
+ variable: {
12560
+ kind: SemanticVariableKind.Identifier,
12561
+ name: null,
12562
+ identifier: op.declaredName,
12563
+ },
12564
+ });
12565
+ break;
12452
12566
  }
12453
12567
  }
12454
12568
  return scope;
@@ -12459,7 +12573,7 @@ function getScopeForView(view, parent) {
12459
12573
  * This is a recursive process, as views inherit variables available from their parent view, which
12460
12574
  * itself may have inherited variables, etc.
12461
12575
  */
12462
- function generateVariablesInScopeForView(view, scope) {
12576
+ function generateVariablesInScopeForView(view, scope, isListener) {
12463
12577
  const newOps = [];
12464
12578
  if (scope.view !== view.xref) {
12465
12579
  // Before generating variables for a parent view, we need to switch to the context of the parent
@@ -12483,9 +12597,14 @@ function generateVariablesInScopeForView(view, scope) {
12483
12597
  for (const ref of scope.references) {
12484
12598
  newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
12485
12599
  }
12600
+ if (scope.view !== view.xref || isListener) {
12601
+ for (const decl of scope.letDeclarations) {
12602
+ newOps.push(createVariableOp(view.job.allocateXrefId(), decl.variable, new ContextLetReferenceExpr(decl.targetId, decl.targetSlot), VariableFlags.None));
12603
+ }
12604
+ }
12486
12605
  if (scope.parent !== null) {
12487
12606
  // Recursively add variables from the parent scope.
12488
- newOps.push(...generateVariablesInScopeForView(view, scope.parent));
12607
+ newOps.push(...generateVariablesInScopeForView(view, scope.parent, false));
12489
12608
  }
12490
12609
  return newOps;
12491
12610
  }
@@ -13849,7 +13968,8 @@ class _ParseAST {
13849
13968
  const keyStart = this.inputIndex;
13850
13969
  const quoted = this.next.isString();
13851
13970
  const key = this.expectIdentifierOrKeywordOrString();
13852
- keys.push({ key, quoted });
13971
+ const literalMapKey = { key, quoted };
13972
+ keys.push(literalMapKey);
13853
13973
  // Properties with quoted keys can't use the shorthand syntax.
13854
13974
  if (quoted) {
13855
13975
  this.expectCharacter($COLON);
@@ -13859,6 +13979,7 @@ class _ParseAST {
13859
13979
  values.push(this.parsePipe());
13860
13980
  }
13861
13981
  else {
13982
+ literalMapKey.isShorthandInitialized = true;
13862
13983
  const span = this.span(keyStart);
13863
13984
  const sourceSpan = this.sourceSpan(keyStart);
13864
13985
  values.push(new PropertyRead(span, sourceSpan, sourceSpan, new ImplicitReceiver(span, sourceSpan), key));
@@ -20623,6 +20744,7 @@ function mergeNextContextsInOps(ops) {
20623
20744
  break;
20624
20745
  case ExpressionKind.GetCurrentView:
20625
20746
  case ExpressionKind.Reference:
20747
+ case ExpressionKind.ContextLetReference:
20626
20748
  // Can't merge past a dependency on the context.
20627
20749
  tryToMerge = false;
20628
20750
  break;
@@ -21348,6 +21470,15 @@ function repeater(collection, sourceSpan) {
21348
21470
  function deferWhen(prefetch, expr, sourceSpan) {
21349
21471
  return call(prefetch ? Identifiers.deferPrefetchWhen : Identifiers.deferWhen, [expr], sourceSpan);
21350
21472
  }
21473
+ function declareLet(slot, sourceSpan) {
21474
+ return call(Identifiers.declareLet, [literal(slot)], sourceSpan);
21475
+ }
21476
+ function storeLet(value, sourceSpan) {
21477
+ return importExpr(Identifiers.storeLet).callFn([value], sourceSpan);
21478
+ }
21479
+ function readContextLet(slot) {
21480
+ return importExpr(Identifiers.readContextLet).callFn([literal(slot)]);
21481
+ }
21351
21482
  function i18n(slot, constIndex, subTemplateIndex, sourceSpan) {
21352
21483
  const args = [literal(slot), literal(constIndex)];
21353
21484
  if (subTemplateIndex) {
@@ -21784,6 +21915,9 @@ function reifyCreateOperations(unit, ops) {
21784
21915
  case OpKind.Pipe:
21785
21916
  OpList.replace(op, pipe(op.handle.slot, op.name));
21786
21917
  break;
21918
+ case OpKind.DeclareLet:
21919
+ OpList.replace(op, declareLet(op.handle.slot, op.sourceSpan));
21920
+ break;
21787
21921
  case OpKind.Listener:
21788
21922
  const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
21789
21923
  const eventTargetResolver = op.eventTarget
@@ -22003,6 +22137,8 @@ function reifyUpdateOperations(_unit, ops) {
22003
22137
  case OpKind.DeferWhen:
22004
22138
  OpList.replace(op, deferWhen(op.prefetch, op.expr, op.sourceSpan));
22005
22139
  break;
22140
+ case OpKind.StoreLet:
22141
+ throw new Error(`AssertionError: unexpected storeLet ${op.declaredName}`);
22006
22142
  case OpKind.Statement:
22007
22143
  // Pass statement operations directly through.
22008
22144
  break;
@@ -22061,6 +22197,10 @@ function reifyIrExpression(expr) {
22061
22197
  return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
22062
22198
  case ExpressionKind.SlotLiteralExpr:
22063
22199
  return literal(expr.slot.slot);
22200
+ case ExpressionKind.ContextLetReference:
22201
+ return readContextLet(expr.targetSlot.slot);
22202
+ case ExpressionKind.StoreLet:
22203
+ return storeLet(expr.value, expr.sourceSpan);
22064
22204
  default:
22065
22205
  throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
22066
22206
  }
@@ -22819,7 +22959,7 @@ function saveAndRestoreView(job) {
22819
22959
  if (!needsRestoreView) {
22820
22960
  for (const handlerOp of op.handlerOps) {
22821
22961
  visitExpressionsInOp(handlerOp, (expr) => {
22822
- if (expr instanceof ReferenceExpr) {
22962
+ if (expr instanceof ReferenceExpr || expr instanceof ContextLetReferenceExpr) {
22823
22963
  // Listeners that reference() a local ref need the save/restore view operation.
22824
22964
  needsRestoreView = true;
22825
22965
  }
@@ -23274,6 +23414,7 @@ function varsUsedByOp(op) {
23274
23414
  case OpKind.I18nExpression:
23275
23415
  case OpKind.Conditional:
23276
23416
  case OpKind.DeferWhen:
23417
+ case OpKind.StoreLet:
23277
23418
  return 1;
23278
23419
  case OpKind.RepeaterCreate:
23279
23420
  // Repeaters may require an extra variable binding slot, if they have an empty view, for the
@@ -23293,6 +23434,8 @@ function varsUsedByIrExpression(expr) {
23293
23434
  return 1 + expr.args.length;
23294
23435
  case ExpressionKind.PipeBindingVariadic:
23295
23436
  return 1 + expr.numArgs;
23437
+ case ExpressionKind.StoreLet:
23438
+ return 1;
23296
23439
  default:
23297
23440
  throw new Error(`AssertionError: unhandled ConsumesVarsTrait expression ${expr.constructor.name}`);
23298
23441
  }
@@ -23549,7 +23692,10 @@ function fencesForIrExpression(expr) {
23549
23692
  return Fence.ViewContextRead | Fence.ViewContextWrite;
23550
23693
  case ExpressionKind.RestoreView:
23551
23694
  return Fence.ViewContextRead | Fence.ViewContextWrite | Fence.SideEffectful;
23695
+ case ExpressionKind.StoreLet:
23696
+ return Fence.SideEffectful;
23552
23697
  case ExpressionKind.Reference:
23698
+ case ExpressionKind.ContextLetReference:
23553
23699
  return Fence.ViewContextRead;
23554
23700
  default:
23555
23701
  return Fence.None;
@@ -23751,6 +23897,87 @@ function wrapI18nIcus(job) {
23751
23897
  }
23752
23898
  }
23753
23899
 
23900
+ /*!
23901
+ * @license
23902
+ * Copyright Google LLC All Rights Reserved.
23903
+ *
23904
+ * Use of this source code is governed by an MIT-style license that can be
23905
+ * found in the LICENSE file at https://angular.io/license
23906
+ */
23907
+ /**
23908
+ * Removes any `storeLet` calls that aren't referenced outside of the current view.
23909
+ */
23910
+ function optimizeStoreLet(job) {
23911
+ const letUsedExternally = new Set();
23912
+ // Since `@let` declarations can be referenced in child views, both in
23913
+ // the creation block (via listeners) and in the update block, we have
23914
+ // to look through all the ops to find the references.
23915
+ for (const unit of job.units) {
23916
+ for (const op of unit.ops()) {
23917
+ visitExpressionsInOp(op, (expr) => {
23918
+ if (expr instanceof ContextLetReferenceExpr) {
23919
+ letUsedExternally.add(expr.target);
23920
+ }
23921
+ });
23922
+ }
23923
+ }
23924
+ // TODO(crisbeto): potentially remove the unused calls completely, pending discussion.
23925
+ for (const unit of job.units) {
23926
+ for (const op of unit.update) {
23927
+ transformExpressionsInOp(op, (expression) => expression instanceof StoreLetExpr && !letUsedExternally.has(expression.target)
23928
+ ? expression.value
23929
+ : expression, VisitorContextFlag.None);
23930
+ }
23931
+ }
23932
+ }
23933
+
23934
+ /**
23935
+ * It's not allowed to access a `@let` declaration before it has been defined. This is enforced
23936
+ * already via template type checking, however it can trip some of the assertions in the pipeline.
23937
+ * E.g. the naming phase can fail because we resolved the variable here, but the variable doesn't
23938
+ * exist anymore because the optimization phase removed it since it's invalid. To avoid surfacing
23939
+ * confusing errors to users in the case where template type checking isn't running (e.g. in JIT
23940
+ * mode) this phase detects illegal forward references and replaces them with `undefined`.
23941
+ * Eventually users will see the proper error from the template type checker.
23942
+ */
23943
+ function removeIllegalLetReferences(job) {
23944
+ for (const unit of job.units) {
23945
+ for (const op of unit.update) {
23946
+ if (op.kind !== OpKind.Variable ||
23947
+ op.variable.kind !== SemanticVariableKind.Identifier ||
23948
+ !(op.initializer instanceof StoreLetExpr)) {
23949
+ continue;
23950
+ }
23951
+ const name = op.variable.identifier;
23952
+ let current = op;
23953
+ while (current && current.kind !== OpKind.ListEnd) {
23954
+ transformExpressionsInOp(current, (expr) => expr instanceof LexicalReadExpr && expr.name === name ? literal(undefined) : expr, VisitorContextFlag.None);
23955
+ current = current.prev;
23956
+ }
23957
+ }
23958
+ }
23959
+ }
23960
+
23961
+ /**
23962
+ * Replaces the `storeLet` ops with variables that can be
23963
+ * used to reference the value within the same view.
23964
+ */
23965
+ function generateLocalLetReferences(job) {
23966
+ for (const unit of job.units) {
23967
+ for (const op of unit.update) {
23968
+ if (op.kind !== OpKind.StoreLet) {
23969
+ continue;
23970
+ }
23971
+ const variable = {
23972
+ kind: SemanticVariableKind.Identifier,
23973
+ name: null,
23974
+ identifier: op.declaredName,
23975
+ };
23976
+ OpList.replace(op, createVariableOp(job.allocateXrefId(), variable, new StoreLetExpr(op.target, op.value, op.sourceSpan), VariableFlags.None));
23977
+ }
23978
+ }
23979
+ }
23980
+
23754
23981
  /**
23755
23982
  *
23756
23983
  * @license
@@ -23785,11 +24012,13 @@ const phases = [
23785
24012
  { kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
23786
24013
  { kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
23787
24014
  { kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
24015
+ { kind: CompilationJobKind.Tmpl, fn: generateLocalLetReferences },
23788
24016
  { kind: CompilationJobKind.Tmpl, fn: generateVariables },
23789
24017
  { kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
23790
24018
  { kind: CompilationJobKind.Both, fn: deleteAnyCasts },
23791
24019
  { kind: CompilationJobKind.Both, fn: resolveDollarEvent },
23792
24020
  { kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
24021
+ { kind: CompilationJobKind.Tmpl, fn: removeIllegalLetReferences },
23793
24022
  { kind: CompilationJobKind.Both, fn: resolveNames },
23794
24023
  { kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
23795
24024
  { kind: CompilationJobKind.Tmpl, fn: transformTwoWayBindingSet },
@@ -23801,6 +24030,7 @@ const phases = [
23801
24030
  { kind: CompilationJobKind.Both, fn: expandSafeReads },
23802
24031
  { kind: CompilationJobKind.Both, fn: generateTemporaryVariables },
23803
24032
  { kind: CompilationJobKind.Both, fn: optimizeVariables },
24033
+ { kind: CompilationJobKind.Both, fn: optimizeStoreLet },
23804
24034
  { kind: CompilationJobKind.Tmpl, fn: allocateSlots },
23805
24035
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
23806
24036
  { kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
@@ -24038,7 +24268,7 @@ function ingestNodes(unit, template) {
24038
24268
  ingestForBlock(unit, node);
24039
24269
  }
24040
24270
  else if (node instanceof LetDeclaration$1) {
24041
- // TODO(crisbeto): needs further integration
24271
+ ingestLetDeclaration(unit, node);
24042
24272
  }
24043
24273
  else {
24044
24274
  throw new Error(`Unsupported template node: ${node.constructor.name}`);
@@ -24454,6 +24684,11 @@ function getComputedForLoopVariableExpression(variable, indexName, countName) {
24454
24684
  throw new Error(`AssertionError: unknown @for loop variable ${variable.value}`);
24455
24685
  }
24456
24686
  }
24687
+ function ingestLetDeclaration(unit, node) {
24688
+ const target = unit.job.allocateXrefId();
24689
+ unit.create.push(createDeclareLetOp(target, node.name, node.sourceSpan));
24690
+ unit.update.push(createStoreLetOp(target, node.name, convertAst(node.value, unit.job, node.valueSpan), node.sourceSpan));
24691
+ }
24457
24692
  /**
24458
24693
  * Convert a template AST expression into an output AST expression.
24459
24694
  */
@@ -24479,7 +24714,7 @@ function convertAst(ast, job, baseSourceSpan) {
24479
24714
  // The whole point of the explicit `this` was to access the class property, but TDB and the
24480
24715
  // current TCB treat the read as implicit, and give you the context property instead!
24481
24716
  //
24482
- // For now, we emulate this old behvaior by aggressively converting explicit reads to to
24717
+ // For now, we emulate this old behavior by aggressively converting explicit reads to to
24483
24718
  // implicit reads, except for the special cases that TDB and the current TCB protect. However,
24484
24719
  // it would be an improvement to fix this.
24485
24720
  //
@@ -29261,7 +29496,7 @@ function publishFacade(global) {
29261
29496
  * @description
29262
29497
  * Entry point for all public APIs of the compiler package.
29263
29498
  */
29264
- const VERSION = new Version('18.1.0-next.2');
29499
+ const VERSION = new Version('18.1.0-next.3');
29265
29500
 
29266
29501
  class CompilerConfig {
29267
29502
  constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters, } = {}) {
@@ -30899,7 +31134,7 @@ const MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION = '18.0.0';
30899
31134
  function compileDeclareClassMetadata(metadata) {
30900
31135
  const definitionMap = new DefinitionMap();
30901
31136
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
30902
- definitionMap.set('version', literal('18.1.0-next.2'));
31137
+ definitionMap.set('version', literal('18.1.0-next.3'));
30903
31138
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30904
31139
  definitionMap.set('type', metadata.type);
30905
31140
  definitionMap.set('decorators', metadata.decorators);
@@ -30917,7 +31152,7 @@ function compileComponentDeclareClassMetadata(metadata, dependencies) {
30917
31152
  callbackReturnDefinitionMap.set('ctorParameters', metadata.ctorParameters ?? literal(null));
30918
31153
  callbackReturnDefinitionMap.set('propDecorators', metadata.propDecorators ?? literal(null));
30919
31154
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_DEFER_SUPPORT_VERSION));
30920
- definitionMap.set('version', literal('18.1.0-next.2'));
31155
+ definitionMap.set('version', literal('18.1.0-next.3'));
30921
31156
  definitionMap.set('ngImport', importExpr(Identifiers.core));
30922
31157
  definitionMap.set('type', metadata.type);
30923
31158
  definitionMap.set('resolveDeferredDeps', compileComponentMetadataAsyncResolver(dependencies));
@@ -31012,7 +31247,7 @@ function createDirectiveDefinitionMap(meta) {
31012
31247
  const definitionMap = new DefinitionMap();
31013
31248
  const minVersion = getMinimumVersionForPartialOutput(meta);
31014
31249
  definitionMap.set('minVersion', literal(minVersion));
31015
- definitionMap.set('version', literal('18.1.0-next.2'));
31250
+ definitionMap.set('version', literal('18.1.0-next.3'));
31016
31251
  // e.g. `type: MyDirective`
31017
31252
  definitionMap.set('type', meta.type.value);
31018
31253
  if (meta.isStandalone) {
@@ -31434,7 +31669,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
31434
31669
  function compileDeclareFactoryFunction(meta) {
31435
31670
  const definitionMap = new DefinitionMap();
31436
31671
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
31437
- definitionMap.set('version', literal('18.1.0-next.2'));
31672
+ definitionMap.set('version', literal('18.1.0-next.3'));
31438
31673
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31439
31674
  definitionMap.set('type', meta.type.value);
31440
31675
  definitionMap.set('deps', compileDependencies(meta.deps));
@@ -31469,7 +31704,7 @@ function compileDeclareInjectableFromMetadata(meta) {
31469
31704
  function createInjectableDefinitionMap(meta) {
31470
31705
  const definitionMap = new DefinitionMap();
31471
31706
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
31472
- definitionMap.set('version', literal('18.1.0-next.2'));
31707
+ definitionMap.set('version', literal('18.1.0-next.3'));
31473
31708
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31474
31709
  definitionMap.set('type', meta.type.value);
31475
31710
  // Only generate providedIn property if it has a non-null value
@@ -31520,7 +31755,7 @@ function compileDeclareInjectorFromMetadata(meta) {
31520
31755
  function createInjectorDefinitionMap(meta) {
31521
31756
  const definitionMap = new DefinitionMap();
31522
31757
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
31523
- definitionMap.set('version', literal('18.1.0-next.2'));
31758
+ definitionMap.set('version', literal('18.1.0-next.3'));
31524
31759
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31525
31760
  definitionMap.set('type', meta.type.value);
31526
31761
  definitionMap.set('providers', meta.providers);
@@ -31553,7 +31788,7 @@ function createNgModuleDefinitionMap(meta) {
31553
31788
  throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
31554
31789
  }
31555
31790
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
31556
- definitionMap.set('version', literal('18.1.0-next.2'));
31791
+ definitionMap.set('version', literal('18.1.0-next.3'));
31557
31792
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31558
31793
  definitionMap.set('type', meta.type.value);
31559
31794
  // We only generate the keys in the metadata if the arrays contain values.
@@ -31604,7 +31839,7 @@ function compileDeclarePipeFromMetadata(meta) {
31604
31839
  function createPipeDefinitionMap(meta) {
31605
31840
  const definitionMap = new DefinitionMap();
31606
31841
  definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
31607
- definitionMap.set('version', literal('18.1.0-next.2'));
31842
+ definitionMap.set('version', literal('18.1.0-next.3'));
31608
31843
  definitionMap.set('ngImport', importExpr(Identifiers.core));
31609
31844
  // e.g. `type: MyPipe`
31610
31845
  definitionMap.set('type', meta.type.value);