@neocompose/cli 0.81.4 → 0.82.0

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.
@@ -1492,6 +1492,7 @@ var MemberKind = /* @__PURE__ */ ((MemberKind7) => {
1492
1492
  MemberKind7[MemberKind7["NSAction"] = 26] = "NSAction";
1493
1493
  MemberKind7[MemberKind7["Variant"] = 27] = "Variant";
1494
1494
  MemberKind7[MemberKind7["Set"] = 28] = "Set";
1495
+ MemberKind7[MemberKind7["Reference"] = 29] = "Reference";
1495
1496
  return MemberKind7;
1496
1497
  })(MemberKind || {});
1497
1498
 
@@ -1508,7 +1509,7 @@ var TAXONOMY = {
1508
1509
  [6 /* List */]: [1 /* Direct */, BINDABLE, "collection", null, 12],
1509
1510
  [7 /* Class */]: [1 /* Direct */, BINDABLE, "class", null, 14],
1510
1511
  [8 /* Enum */]: [1 /* Direct */, BINDABLE, "core", null, 15],
1511
- [9 /* Lookup */]: [1 /* Direct */, STORED, "collection", null, 16],
1512
+ [9 /* Lookup */]: [1 /* Direct */, BINDABLE, "collection", null, 16],
1512
1513
  [10 /* NSProperty */]: [1 /* Direct */, 0, "code", null, 18],
1513
1514
  [11 /* Sprite */]: [1 /* Direct */, BINDABLE, "core", null, 24],
1514
1515
  [12 /* Audio */]: [1 /* Direct */, BINDABLE, "core", null, 25],
@@ -1557,7 +1558,8 @@ var TAXONOMY = {
1557
1558
  21
1558
1559
  ],
1559
1560
  [27 /* Variant */]: [1 /* Direct */, STORED, "world", null, 22],
1560
- [28 /* Set */]: [1 /* Direct */, BINDABLE, "collection", null, 13]
1561
+ [28 /* Set */]: [1 /* Direct */, BINDABLE, "collection", null, 13],
1562
+ [29 /* Reference */]: [0 /* None */, 0, null, null, null]
1561
1563
  };
1562
1564
  var ALL_MEMBER_KINDS = [
1563
1565
  0 /* Null */,
@@ -1588,7 +1590,8 @@ var ALL_MEMBER_KINDS = [
1588
1590
  25 /* NSDelegate */,
1589
1591
  26 /* NSAction */,
1590
1592
  27 /* Variant */,
1591
- 28 /* Set */
1593
+ 28 /* Set */,
1594
+ 29 /* Reference */
1592
1595
  ];
1593
1596
  var DIRECT_MEMBER_KINDS = ALL_MEMBER_KINDS.filter(
1594
1597
  (kind) => TAXONOMY[kind][0] === 1 /* Direct */
@@ -1662,7 +1665,9 @@ var AUTOMATIC_MEMBER_DISTRIBUTION = {
1662
1665
  /** Fixed class, variant, and optional bound-row ids. */
1663
1666
  [27 /* Variant */]: 1 /* Packed */,
1664
1667
  /** Entry count grows with content. */
1665
- [28 /* Set */]: { sparse: "entryCount" }
1668
+ [28 /* Set */]: { sparse: "entryCount" },
1669
+ /** Type-info only; a stored reference is a Lookup. */
1670
+ [29 /* Reference */]: "valueLess"
1666
1671
  };
1667
1672
  function memberKindSupportsDistribution(kind) {
1668
1673
  return memberKindSupportsStorage(kind);
@@ -2152,6 +2157,9 @@ var NEO_LOOKUP_VARIANT_TYPE_NAME = "NeoLookupVariant";
2152
2157
  var NEO_VARIANT_SCOPE_NAME = "Variants";
2153
2158
  var NEO_VARIANT_RESERVED_NAME = "Base";
2154
2159
  var NEO_VARIANT_FOLDER_PATH_SEPARATOR = "/";
2160
+ function isNeoVariantTypeName(name) {
2161
+ return name === NEO_VARIANT_TYPE_NAME || name === NEO_LOOKUP_VARIANT_TYPE_NAME;
2162
+ }
2155
2163
  var NEOSCRIPT_OPERATORS = [
2156
2164
  "===",
2157
2165
  "!==",
@@ -2349,6 +2357,15 @@ var NEOSCRIPT_DELEGATE_MAX_PARAMETERS = 16;
2349
2357
  function delegateArityMessage(provided) {
2350
2358
  return `Type 'NeoDelegate' expects a return type followed by up to ${NEOSCRIPT_DELEGATE_MAX_PARAMETERS} parameter types, but ${provided} type arguments were provided.`;
2351
2359
  }
2360
+ function referenceNamesCodeMessage(reference) {
2361
+ return `${reference} names code. A reference names a stored value, and a delegate or action member is already an indirection.`;
2362
+ }
2363
+ function referenceNeedsValueTypeMessage(reference) {
2364
+ return `${reference} needs a value type.`;
2365
+ }
2366
+ function referenceNamesObjectMessage(reference, required) {
2367
+ return `${reference} names an object, which is never null. Write Reference<${required}>? for a reference that may be unset.`;
2368
+ }
2352
2369
  function neoScriptRegistryReferenceType(entryTypeName) {
2353
2370
  for (const definition of Object.values(REGISTRY_ENTRY_TYPES)) {
2354
2371
  if (definition.entryType === entryTypeName) return definition.refType;
@@ -3101,7 +3118,19 @@ function isNSTypeInfo(value) {
3101
3118
  return isNSTypeInfoInternal(value, /* @__PURE__ */ new Set());
3102
3119
  }
3103
3120
  function isNSTypeInfoInternal(value, ancestors) {
3104
- return isNSTypeInfoUnknown(value) || isNSTypeInfoPrimitive(value) || isNSTypeInfoAsset(value) || isNSTypeInfoVector(value) || isNSTypeInfoColor(value) || isNSTypeInfoDialogueLookup(value) || isNSTypeInfoClassInternal(value, ancestors) || isNSTypeInfoInterface(value) || isNSTypeInfoGenericParam(value) || isNSTypeInfoDelegateInternal(value, ancestors) || isNSTypeInfoActionInternal(value, ancestors) || isNSTypeInfoCollectionInternal(value, ancestors) || isNSTypeInfoLookupInternal(value, ancestors) || isNSTypeInfoEnum(value);
3121
+ return isNSTypeInfoUnknown(value) || isNSTypeInfoPrimitive(value) || isNSTypeInfoAsset(value) || isNSTypeInfoVector(value) || isNSTypeInfoColor(value) || isNSTypeInfoDialogueLookup(value) || isNSTypeInfoClassInternal(value, ancestors) || isNSTypeInfoInterface(value) || isNSTypeInfoGenericParam(value) || isNSTypeInfoDelegateInternal(value, ancestors) || isNSTypeInfoActionInternal(value, ancestors) || isNSTypeInfoCollectionInternal(value, ancestors) || isNSTypeInfoLookupInternal(value, ancestors) || isNSTypeInfoEnum(value) || isNSTypeInfoReferenceInternal(value, ancestors);
3122
+ }
3123
+ function isNSTypeInfoReferenceInternal(value, ancestors) {
3124
+ if (!isNSTypeInfoBase(value)) return false;
3125
+ if (value.type !== 29 /* Reference */) return false;
3126
+ const reference = value;
3127
+ if (ancestors.has(reference)) return false;
3128
+ ancestors.add(reference);
3129
+ try {
3130
+ return isNSTypeInfoInternal(reference.targetTypeInfo, ancestors);
3131
+ } finally {
3132
+ ancestors.delete(reference);
3133
+ }
3105
3134
  }
3106
3135
  function isNSArgumentTypeInfo(value) {
3107
3136
  return isRequiredType(value, isNSArgumentTypeInfoUnsafe);
@@ -3336,6 +3365,17 @@ function isNSPointerForceUnwrap(value) {
3336
3365
  if (v?.type !== "forceUnwrap" /* forceUnwrap */) return false;
3337
3366
  return isNSPointer(v.pointer);
3338
3367
  }
3368
+ function isNSPointerRowOf(value) {
3369
+ const v = value;
3370
+ if (v?.type !== "rowOf" /* rowOf */) return false;
3371
+ if (v.typeInfo !== void 0 && !isNSTypeInfo(v.typeInfo)) return false;
3372
+ return isNSPointer(v.place);
3373
+ }
3374
+ function isNSPointerDeref(value) {
3375
+ const v = value;
3376
+ if (v?.type !== "deref" /* deref */) return false;
3377
+ return isNSPointer(v.pointer);
3378
+ }
3339
3379
  function isNSPointerIsCheck(value) {
3340
3380
  const v = value;
3341
3381
  if (v?.type !== "isCheck" /* isCheck */) return false;
@@ -3494,7 +3534,7 @@ function isNSPointerMemberTarget(value) {
3494
3534
  return isNSCallReceiver(pointer.receiver);
3495
3535
  }
3496
3536
  function isNSPointer(value) {
3497
- return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerConditional(value) || isNSPointerMemberTarget(value) || isNSPointerDelegateClosure(value) || isNSPointerObjectInitializer(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerTileConvert(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
3537
+ return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerRowOf(value) || isNSPointerDeref(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerConditional(value) || isNSPointerMemberTarget(value) || isNSPointerDelegateClosure(value) || isNSPointerObjectInitializer(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerTileConvert(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
3498
3538
  }
3499
3539
  function isNSPointers(value) {
3500
3540
  return Array.isArray(value) && value.every(isNSPointer);
@@ -4268,6 +4308,9 @@ function typeInfosInvariantlyEqual(left, right) {
4268
4308
  (argument2, index) => typeInfosInvariantlyEqual(argument2, right.argumentTypes[index])
4269
4309
  );
4270
4310
  }
4311
+ if (left.type === 29 /* Reference */ && right.type === 29 /* Reference */) {
4312
+ return typeInfosInvariantlyEqual(left.targetTypeInfo, right.targetTypeInfo);
4313
+ }
4271
4314
  if (left.type === 9 /* Lookup */ && right.type === 9 /* Lookup */) {
4272
4315
  if (left.collectionMemberId !== right.collectionMemberId) return false;
4273
4316
  if ((left.collectionValueId ?? void 0) !== (right.collectionValueId ?? void 0))
@@ -4277,6 +4320,45 @@ function typeInfosInvariantlyEqual(left, right) {
4277
4320
  return true;
4278
4321
  }
4279
4322
 
4323
+ // ../packages/models/src/members/reference-kind.ts
4324
+ function referenceKindCategory(target) {
4325
+ if (target.type === NS_TYPE_UNKNOWN) return "ineligible" /* Ineligible */;
4326
+ switch (target.type) {
4327
+ case 7 /* Class */:
4328
+ case 22 /* Interface */:
4329
+ case 6 /* List */:
4330
+ case 28 /* Set */:
4331
+ case 5 /* Dictionary */:
4332
+ case 9 /* Lookup */:
4333
+ return "handle" /* Handle */;
4334
+ case 1 /* Bool */:
4335
+ case 2 /* Int */:
4336
+ case 3 /* String */:
4337
+ case 4 /* Float */:
4338
+ case 20 /* Decimal */:
4339
+ case 8 /* Enum */:
4340
+ case 11 /* Sprite */:
4341
+ case 12 /* Audio */:
4342
+ case 14 /* Vector2 */:
4343
+ case 15 /* Vector2Int */:
4344
+ case 16 /* Vector3 */:
4345
+ case 17 /* Vector3Int */:
4346
+ case 19 /* Color */:
4347
+ case 18 /* DialogueLookup */:
4348
+ case 29 /* Reference */:
4349
+ return "slot" /* Slot */;
4350
+ case 21 /* Generic */:
4351
+ return "deferred" /* Deferred */;
4352
+ case 0 /* Null */:
4353
+ case 25 /* NSDelegate */:
4354
+ case 26 /* NSAction */:
4355
+ return "ineligible" /* Ineligible */;
4356
+ }
4357
+ }
4358
+ function isReferenceEligibleTypeInfo(target) {
4359
+ return referenceKindCategory(target) !== "ineligible" /* Ineligible */;
4360
+ }
4361
+
4280
4362
  // ../packages/models/src/members/structured-leaf-fields.ts
4281
4363
  var STRUCTURED_LEAF_FIELDS = {
4282
4364
  [11 /* Sprite */]: [
@@ -4770,7 +4852,7 @@ function isMemberTypeLookupBase(value) {
4770
4852
  }
4771
4853
  function isLookupTargetTypeInfo(value) {
4772
4854
  if (!isNSTypeInfo(value)) return false;
4773
- return value.type === 7 /* Class */ || value.type === 21 /* Generic */;
4855
+ return isReferenceEligibleTypeInfo(value);
4774
4856
  }
4775
4857
  function isMemberLookupBase(value) {
4776
4858
  return isMemberCollectionLookupBase(value) || isMemberTypeLookupBase(value);
@@ -8878,6 +8960,15 @@ var GENERIC_WORLD_SYSTEM_CLASS_KINDS = new Set(
8878
8960
  var WORLD_SYSTEM_ALL_KINDS = new Set(
8879
8961
  WORLD_SYSTEM_CLASS_DEFINITIONS.map((definition) => definition.worldKind)
8880
8962
  );
8963
+ function requireWorldSystemClassDefinition(worldKind) {
8964
+ const definition = WORLD_SYSTEM_CLASS_DEFINITION_BY_KIND.get(worldKind);
8965
+ if (definition === void 0) {
8966
+ throw new Error(
8967
+ `World system kind "${worldKind}" has no class definition in the generated table.`
8968
+ );
8969
+ }
8970
+ return definition;
8971
+ }
8881
8972
  var WORLD_SYSTEM_SCHEMA_FIELD_SITES_BY_MEMBER_ID = new Map(
8882
8973
  WORLD_SYSTEM_CLASS_DEFINITIONS.flatMap(
8883
8974
  (definition) => (definition.schemaFields ?? []).map(
@@ -9305,6 +9396,12 @@ function mapGenericTypeInfo(typeInfo, close) {
9305
9396
  entryTypeInfo: mapGenericTypeInfo(typeInfo.entryTypeInfo, close)
9306
9397
  };
9307
9398
  }
9399
+ if (typeInfo.type === 29 /* Reference */) {
9400
+ return {
9401
+ ...typeInfo,
9402
+ targetTypeInfo: mapGenericTypeInfo(typeInfo.targetTypeInfo, close)
9403
+ };
9404
+ }
9308
9405
  if (typeInfo.type === 7 /* Class */) {
9309
9406
  const typeArguments = typeInfo.typeArguments;
9310
9407
  if (typeArguments === void 0) return typeInfo;
@@ -9374,6 +9471,19 @@ function typeInfoFromArgumentSignature(signature) {
9374
9471
  entryTypeInfo: { ...enumTypeInfo, required: true }
9375
9472
  } : enumTypeInfo;
9376
9473
  }
9474
+ if (signature.type === 9 /* Lookup */) {
9475
+ const lookupSignature = signature;
9476
+ const reference = {
9477
+ type: 29 /* Reference */,
9478
+ required: lookupSignature.multiselect || lookupSignature.required,
9479
+ targetTypeInfo: lookupSignature.target
9480
+ };
9481
+ return lookupSignature.multiselect ? {
9482
+ type: 9 /* Lookup */,
9483
+ required: lookupSignature.required,
9484
+ entryTypeInfo: reference
9485
+ } : reference;
9486
+ }
9377
9487
  if (signature.type === 6 /* List */) {
9378
9488
  const listSignature = signature;
9379
9489
  return {
@@ -9516,6 +9626,19 @@ function typeArgumentSignatureOfMember(member, env, members, seen = /* @__PURE__
9516
9626
  )
9517
9627
  };
9518
9628
  }
9629
+ if (isMemberLookupBase(resolved)) {
9630
+ if (resolved.declaredTypeInfo === void 0) {
9631
+ throw new Error(
9632
+ `typeArgumentSignatureOfMember: Lookup "${resolved.name}" has no declared type; a type argument can't be a Lookup bound to a collection.`
9633
+ );
9634
+ }
9635
+ return {
9636
+ type: 9 /* Lookup */,
9637
+ required,
9638
+ multiselect: isMultiSelectionMember(resolved),
9639
+ target: substituteNestedTypeInfo(resolved.declaredTypeInfo, env, members)
9640
+ };
9641
+ }
9519
9642
  if (isMemberStringBase(resolved)) {
9520
9643
  return {
9521
9644
  type: 3 /* String */,
@@ -9608,6 +9731,12 @@ function signaturesEqual(a, b) {
9608
9731
  if (ad.keyEnumId !== bd.keyEnumId) return false;
9609
9732
  return signaturesEqual(ad.entry, bd.entry);
9610
9733
  }
9734
+ if (a.type === 9 /* Lookup */ && b.type === 9 /* Lookup */) {
9735
+ const al = a;
9736
+ const bl = b;
9737
+ if (al.multiselect !== bl.multiselect) return false;
9738
+ return typeInfosInvariantlyEqual(al.target, bl.target);
9739
+ }
9611
9740
  if (a.type === 25 /* NSDelegate */ && b.type === 25 /* NSDelegate */) {
9612
9741
  return typeInfosInvariantlyEqual(
9613
9742
  a,
@@ -13199,6 +13328,56 @@ function classImplementsInterface(classId, interfaceId, classes, interfaces) {
13199
13328
  );
13200
13329
  }
13201
13330
 
13331
+ // ../packages/models/src/neoscript/type-info-compatibility.ts
13332
+ function isTypeInfoAssignable(from, to, context) {
13333
+ if (to.type === NS_TYPE_UNKNOWN) return true;
13334
+ if (from.type === NS_TYPE_UNKNOWN) return false;
13335
+ if (from.required === false && to.required === true) return false;
13336
+ if (from.type === 0 /* Null */) return to.required === false;
13337
+ if (from.type === 29 /* Reference */) {
13338
+ if (to.type === 29 /* Reference */ && typeInfosInvariantlyEqual(from.targetTypeInfo, to.targetTypeInfo)) {
13339
+ return true;
13340
+ }
13341
+ return isTypeInfoAssignable(referenceReadTypeInfo(from), to, context);
13342
+ }
13343
+ if (to.type === 29 /* Reference */) return false;
13344
+ if (from.type === 2 /* Int */ && to.type === 4 /* Float */) {
13345
+ return true;
13346
+ }
13347
+ if (from.type === 7 /* Class */ && to.type === 7 /* Class */) {
13348
+ if (from.classId === to.classId) {
13349
+ return typeInfosInvariantlyEqual({ ...from, required: to.required }, to);
13350
+ }
13351
+ return resolveInheritanceChain(from.classId, context.classes).some(
13352
+ (schemaClass2) => schemaClass2.id === to.classId
13353
+ );
13354
+ }
13355
+ if (from.type === 7 /* Class */ && to.type === 22 /* Interface */) {
13356
+ return classImplementsInterface(
13357
+ from.classId,
13358
+ to.interfaceId,
13359
+ context.classes,
13360
+ context.interfaces
13361
+ );
13362
+ }
13363
+ if (from.type === 22 /* Interface */ && to.type === 22 /* Interface */) {
13364
+ return resolveInterfaceClosure(from.interfaceId, context.interfaces).some(
13365
+ (neoInterface) => neoInterface.id === to.interfaceId
13366
+ );
13367
+ }
13368
+ if (from.type === 22 /* Interface */ || to.type === 22 /* Interface */) {
13369
+ return false;
13370
+ }
13371
+ const normalizedFrom = { ...from, required: to.required };
13372
+ return typeInfosInvariantlyEqual(normalizedFrom, to);
13373
+ }
13374
+ function referenceReadTypeInfo(reference) {
13375
+ return {
13376
+ ...reference.targetTypeInfo,
13377
+ required: reference.required && reference.targetTypeInfo.required
13378
+ };
13379
+ }
13380
+
13202
13381
  // ../packages/models/src/neoscript/function-type-arguments.ts
13203
13382
  function functionGenericParamsOf(member) {
13204
13383
  const kind = getField(member, "kind");
@@ -13301,6 +13480,9 @@ function bindTypeInfoList(list, table) {
13301
13480
  }
13302
13481
  return bound ?? list;
13303
13482
  }
13483
+ function functionGenericParamName(typeInfo, params) {
13484
+ return params?.[typeInfo.index]?.name ?? `T${typeInfo.index}`;
13485
+ }
13304
13486
 
13305
13487
  // ../packages/manifest/src/value-comparison.ts
13306
13488
  function isObjectRecord(value) {
@@ -13412,6 +13594,11 @@ function compiledConstructionTypeMembers(members, bodies, projectId) {
13412
13594
  };
13413
13595
  } else if (type.type === 26 /* NSAction */) {
13414
13596
  return { argumentTypes: namedArguments(type.argumentTypes) };
13597
+ } else if (type.type === 29 /* Reference */) {
13598
+ return {
13599
+ kind: 9 /* Lookup */,
13600
+ declaredTypeInfo: type.targetTypeInfo
13601
+ };
13415
13602
  } else if (type.type === 22 /* Interface */ || type.type === 9 /* Lookup */ || type.type === 18 /* DialogueLookup */) {
13416
13603
  return null;
13417
13604
  } else {
@@ -13616,6 +13803,60 @@ function neoScriptMemberLookupType(type) {
13616
13803
  }
13617
13804
  return nullable2 && current.nullable !== true ? { ...current, nullable: true } : current;
13618
13805
  }
13806
+ function isNeoScriptHandleReferenceTarget(target, isValueType) {
13807
+ switch (target.kind) {
13808
+ case "list":
13809
+ case "set":
13810
+ case "dictionary":
13811
+ return true;
13812
+ case "named":
13813
+ return !isValueType(target);
13814
+ case "typeParameter": {
13815
+ const bound = neoScriptMemberLookupType(target);
13816
+ return bound.kind === "named" && !isValueType(bound);
13817
+ }
13818
+ default:
13819
+ return false;
13820
+ }
13821
+ }
13822
+ function neoScriptReferenceType(target, nullable2, isValueType) {
13823
+ if (isNeoScriptHandleReferenceTarget(target, isValueType)) {
13824
+ return nullable2 ? { ...target, nullable: true } : target;
13825
+ }
13826
+ return { kind: "reference", target, ...nullable2 ? { nullable: nullable2 } : {} };
13827
+ }
13828
+ function isNeoScriptValueNamedType(type, project) {
13829
+ const declared = project.typeById.get(type.typeId);
13830
+ if (declared === void 0) return false;
13831
+ return declared.kind === "enum" || isNeoVariantTypeName(declared.name);
13832
+ }
13833
+ var NON_VALUE_PRIMITIVES = /* @__PURE__ */ new Set([
13834
+ "null",
13835
+ "unknown",
13836
+ "void"
13837
+ ]);
13838
+ function neoScriptReferenceTargetError(target, project) {
13839
+ const reference = `Reference<${formatType(target, project)}>`;
13840
+ if (target.kind === "delegate" || target.kind === "action") {
13841
+ return referenceNamesCodeMessage(reference);
13842
+ }
13843
+ if (target.kind === "primitive") {
13844
+ return NON_VALUE_PRIMITIVES.has(target.name) ? referenceNeedsValueTypeMessage(reference) : null;
13845
+ }
13846
+ if (target.kind !== "named" || target.nullable !== true) return null;
13847
+ if (isNeoScriptValueNamedType(target, project)) return null;
13848
+ const required = formatType({ ...target, nullable: false }, project);
13849
+ return referenceNamesObjectMessage(reference, required);
13850
+ }
13851
+ function neoScriptReadType(type) {
13852
+ let current = type;
13853
+ let nullable2 = type.nullable === true;
13854
+ while (current.kind === "reference") {
13855
+ current = current.target;
13856
+ nullable2 ||= current.nullable === true;
13857
+ }
13858
+ return nullable2 && current.nullable !== true ? { ...current, nullable: true } : current;
13859
+ }
13619
13860
  function neoScriptParameterIsOmittable(parameter3) {
13620
13861
  return parameter3.defaultValue !== void 0;
13621
13862
  }
@@ -13944,6 +14185,19 @@ function isNeoScriptTypeAssignable(source, target, project) {
13944
14185
  return expected !== void 0 && isNeoScriptTypeAssignable(parameter3, expected, project) && isNeoScriptTypeAssignable(expected, parameter3, project);
13945
14186
  });
13946
14187
  }
14188
+ if (source.kind !== "reference" && target.kind === "reference" && isNeoScriptHandleReferenceTarget(
14189
+ target.target,
14190
+ (named) => isNeoScriptValueNamedType(named, project)
14191
+ )) {
14192
+ return isNeoScriptTypeAssignable(
14193
+ source,
14194
+ { ...target.target, nullable: target.nullable === true },
14195
+ project
14196
+ );
14197
+ }
14198
+ if (source.kind === "reference" && target.kind === "reference") {
14199
+ return isNeoScriptTypeAssignable(source.target, target.target, project) && isNeoScriptTypeAssignable(target.target, source.target, project);
14200
+ }
13947
14201
  if (source.kind === "action" && target.kind === "action") {
13948
14202
  return source.parameterTypes.length === target.parameterTypes.length && source.parameterTypes.every((parameter3, index) => {
13949
14203
  const expected = target.parameterTypes[index];
@@ -14017,6 +14271,8 @@ function formatType(type, project) {
14017
14271
  return `Dictionary<${formatType(type.keyType, project)}, ${formatType(type.valueType, project)}>${suffix}`;
14018
14272
  case "typeParameter":
14019
14273
  return `${type.name}${suffix}`;
14274
+ case "reference":
14275
+ return `Reference<${formatType(type.target, project)}>${suffix}`;
14020
14276
  case "delegate":
14021
14277
  return `NeoDelegate<${[
14022
14278
  formatType(type.returnType, project),
@@ -14379,14 +14635,16 @@ var UncompiledInitializerRuntimeError = class extends NSGetterRuntimeError {
14379
14635
 
14380
14636
  // ../packages/neoscript-runtime/src/neoscript/runtime-set.ts
14381
14637
  var RuntimeSet = class {
14382
- constructor(source, reference, enumEntries) {
14638
+ constructor(source, reference, enumEntries, slotReferences = null) {
14383
14639
  this.source = source;
14384
14640
  this.reference = reference;
14385
14641
  this.enumEntries = enumEntries;
14642
+ this.slotReferences = slotReferences;
14386
14643
  }
14387
14644
  source;
14388
14645
  reference;
14389
14646
  enumEntries;
14647
+ slotReferences;
14390
14648
  entries = /* @__PURE__ */ new Map();
14391
14649
  validations = /* @__PURE__ */ new Map();
14392
14650
  snapshot;
@@ -14432,6 +14690,21 @@ var RuntimeSet = class {
14432
14690
  }
14433
14691
  };
14434
14692
 
14693
+ // ../packages/neoscript-runtime/src/neoscript/slot-reference.ts
14694
+ var NSSlotReference = class {
14695
+ constructor(targetId, place, target, memberId) {
14696
+ this.targetId = targetId;
14697
+ this.place = place;
14698
+ this.target = target;
14699
+ this.memberId = memberId;
14700
+ Object.freeze(this);
14701
+ }
14702
+ targetId;
14703
+ place;
14704
+ target;
14705
+ memberId;
14706
+ };
14707
+
14435
14708
  // ../packages/neoscript-runtime/src/listener-write-index.ts
14436
14709
  var indexes = /* @__PURE__ */ new WeakMap();
14437
14710
  var empty = /* @__PURE__ */ new Map();
@@ -16771,6 +17044,339 @@ function readClassMember(args) {
16771
17044
  return { kind: "missing" };
16772
17045
  }
16773
17046
 
17047
+ // ../packages/models/src/members/reference-category.ts
17048
+ var variantClassIds;
17049
+ function isVariantClassId(classId) {
17050
+ variantClassIds ??= /* @__PURE__ */ new Set([
17051
+ requireWorldSystemClassDefinition(NeoWorldSystemClassKind.Variant).classId,
17052
+ requireWorldSystemClassDefinition(NeoWorldSystemClassKind.LookupVariant).classId
17053
+ ]);
17054
+ return variantClassIds.has(classId);
17055
+ }
17056
+ var NO_CONSTRAINTS = () => false;
17057
+ var CLASS_CONSTRAINED = /* @__PURE__ */ new WeakMap();
17058
+ function classConstrainedGenerics(classes) {
17059
+ const cached = CLASS_CONSTRAINED.get(classes);
17060
+ if (cached !== void 0) return cached;
17061
+ const constrained = /* @__PURE__ */ new Set();
17062
+ for (const schemaClass2 of classes) {
17063
+ for (const param of schemaClass2.genericParams ?? []) {
17064
+ if (param.constraint === void 0) continue;
17065
+ if (!isClassGenericConstraint(param.constraint)) continue;
17066
+ constrained.add(`${schemaClass2.id}:${param.id}`);
17067
+ }
17068
+ }
17069
+ const isClassConstrained = (generic) => constrained.has(`${generic.ownerClassId}:${generic.genericParamId}`);
17070
+ CLASS_CONSTRAINED.set(classes, isClassConstrained);
17071
+ return isClassConstrained;
17072
+ }
17073
+ function referenceCategory(target, isClassConstrained = NO_CONSTRAINTS) {
17074
+ if (target.type === 7 /* Class */ && isVariantClassId(target.classId)) {
17075
+ return "slot" /* Slot */;
17076
+ }
17077
+ if (target.type === 21 /* Generic */ && isClassGenericParamTypeInfo(target) && isClassConstrained(target)) {
17078
+ return "handle" /* Handle */;
17079
+ }
17080
+ return referenceKindCategory(target);
17081
+ }
17082
+ function referenceExpressionTypeInfo(target, required, isClassConstrained = NO_CONSTRAINTS) {
17083
+ if (referenceCategory(target, isClassConstrained) !== "handle" /* Handle */) {
17084
+ return { type: 29 /* Reference */, required, targetTypeInfo: target };
17085
+ }
17086
+ const handle = expressionTypeInfo(target, isClassConstrained);
17087
+ return { ...handle, required: required && handle.required };
17088
+ }
17089
+ function expressionTypeInfo(stored, isClassConstrained = NO_CONSTRAINTS) {
17090
+ if (stored.type === NS_TYPE_UNKNOWN) return stored;
17091
+ switch (stored.type) {
17092
+ case 29 /* Reference */:
17093
+ return referenceExpressionTypeInfo(
17094
+ stored.targetTypeInfo,
17095
+ stored.required,
17096
+ isClassConstrained
17097
+ );
17098
+ case 6 /* List */:
17099
+ case 28 /* Set */:
17100
+ case 5 /* Dictionary */:
17101
+ case 9 /* Lookup */:
17102
+ return {
17103
+ ...stored,
17104
+ entryTypeInfo: expressionTypeInfo(
17105
+ stored.entryTypeInfo,
17106
+ isClassConstrained
17107
+ )
17108
+ };
17109
+ default:
17110
+ return stored;
17111
+ }
17112
+ }
17113
+
17114
+ // ../packages/models/src/neoscript/type-info-format.ts
17115
+ function formatTypeInfo(typeInfo, names) {
17116
+ const suffix = typeInfo.required ? "" : "?";
17117
+ switch (typeInfo.type) {
17118
+ case NS_TYPE_UNKNOWN:
17119
+ return `unknown${suffix}`;
17120
+ case NS_TYPE_VOID:
17121
+ return "void";
17122
+ case 2 /* Int */:
17123
+ return `int${suffix}`;
17124
+ case 4 /* Float */:
17125
+ return `float${suffix}`;
17126
+ case 1 /* Bool */:
17127
+ return `bool${suffix}`;
17128
+ case 3 /* String */:
17129
+ return `string${suffix}`;
17130
+ case 11 /* Sprite */:
17131
+ return `SpriteInfo${suffix}`;
17132
+ case 12 /* Audio */:
17133
+ return `AudioClipInfo${suffix}`;
17134
+ case 14 /* Vector2 */:
17135
+ return `Vector2${suffix}`;
17136
+ case 15 /* Vector2Int */:
17137
+ return `Vector2Int${suffix}`;
17138
+ case 16 /* Vector3 */:
17139
+ return `Vector3${suffix}`;
17140
+ case 17 /* Vector3Int */:
17141
+ return `Vector3Int${suffix}`;
17142
+ case 19 /* Color */:
17143
+ return `Color${suffix}`;
17144
+ case 20 /* Decimal */:
17145
+ return `decimal${suffix}`;
17146
+ case 7 /* Class */:
17147
+ return `${names.schemaClassName(typeInfo.classId)}${suffix}`;
17148
+ case 22 /* Interface */:
17149
+ return `${names.interfaceName(typeInfo.interfaceId)}${suffix}`;
17150
+ case 8 /* Enum */:
17151
+ return `${names.enumName(typeInfo.enumId)}${suffix}`;
17152
+ case 6 /* List */:
17153
+ return `List<${formatTypeInfo(typeInfo.entryTypeInfo, names)}>${suffix}`;
17154
+ case 28 /* Set */:
17155
+ return `Set<${formatTypeInfo(typeInfo.entryTypeInfo, names)}>${suffix}`;
17156
+ case 5 /* Dictionary */:
17157
+ return `Dictionary<string, ${formatTypeInfo(typeInfo.entryTypeInfo, names)}>${suffix}`;
17158
+ case 9 /* Lookup */:
17159
+ return `Set<${formatTypeInfo(typeInfo.entryTypeInfo, names)}>${suffix}`;
17160
+ case 18 /* DialogueLookup */:
17161
+ return `NeoDialogueReference${suffix}`;
17162
+ case 29 /* Reference */:
17163
+ return `Reference<${formatTypeInfo(typeInfo.targetTypeInfo, names)}>${suffix}`;
17164
+ case 0 /* Null */:
17165
+ return "null";
17166
+ case 21 /* Generic */:
17167
+ if (!isClassGenericParamTypeInfo(typeInfo)) {
17168
+ return `${functionGenericParamName(typeInfo, names.functionGenericParams)}${suffix}`;
17169
+ }
17170
+ return `Generic<${typeInfo.genericParamId}>${suffix}`;
17171
+ case 25 /* NSDelegate */:
17172
+ return `NeoDelegate<${[
17173
+ formatTypeInfo(typeInfo.returnTypeInfo, names),
17174
+ ...typeInfo.argumentTypes.map(
17175
+ (argument2) => formatTypeInfo(argument2, names)
17176
+ )
17177
+ ].join(", ")}>${suffix}`;
17178
+ case 26 /* NSAction */:
17179
+ return `NeoAction<${typeInfo.argumentTypes.map((argument2) => formatTypeInfo(argument2, names)).join(", ")}>`;
17180
+ }
17181
+ }
17182
+
17183
+ // ../packages/models/src/variants/variant-member.ts
17184
+ function neoVariantSystemClass(classes, lookup = false) {
17185
+ const declared = classes.find(
17186
+ (item) => item.system?.worldKind === (lookup ? NeoWorldSystemClassKind.LookupVariant : NeoWorldSystemClassKind.Variant)
17187
+ );
17188
+ if (declared === void 0) {
17189
+ throw new Error(
17190
+ `Canonical ${lookup ? "NeoLookupVariant" : "NeoVariant"} system class is missing.`
17191
+ );
17192
+ }
17193
+ const targetParamId = declared.genericParams?.[0]?.id;
17194
+ if (targetParamId === void 0) {
17195
+ throw new Error(
17196
+ `Canonical ${lookup ? "NeoLookupVariant" : "NeoVariant"} system class "${declared.id}" is missing its target generic parameter.`
17197
+ );
17198
+ }
17199
+ const valueParamId = declared.genericParams?.[1]?.id;
17200
+ if (lookup && valueParamId === void 0) {
17201
+ throw new Error(
17202
+ `Canonical NeoLookupVariant system class "${declared.id}" is missing its value generic parameter.`
17203
+ );
17204
+ }
17205
+ return {
17206
+ classId: declared.id,
17207
+ targetParamId,
17208
+ ...valueParamId === void 0 ? {} : { valueParamId }
17209
+ };
17210
+ }
17211
+ function variantMemberDeclaredTypeInfo(member, systemClass) {
17212
+ return {
17213
+ type: 7 /* Class */,
17214
+ required: memberRequirementOf(member) === 1 /* Required */,
17215
+ classId: systemClass.classId,
17216
+ typeArguments: {
17217
+ [systemClass.targetParamId]: member.targetTypeInfo,
17218
+ ...member.valueTypeInfo == null || systemClass.valueParamId === void 0 ? {} : { [systemClass.valueParamId]: member.valueTypeInfo }
17219
+ }
17220
+ };
17221
+ }
17222
+
17223
+ // ../packages/models/src/members/slot-type-info.ts
17224
+ function slotTypeInfo(member, schema, env) {
17225
+ return slotTypeInfoInternal(member, schema, env, /* @__PURE__ */ new Set());
17226
+ }
17227
+ function slotTypeInfoInternal(member, schema, env, seen) {
17228
+ const resolved = env === void 0 ? resolveMember(member, schema.members) : substituteMember(member, env, schema.members);
17229
+ const id = getField(resolved, "id");
17230
+ if (typeof id === "string" && seen.has(id)) return null;
17231
+ const nextSeen = typeof id === "string" ? /* @__PURE__ */ new Set([...seen, id]) : seen;
17232
+ const byId = memberIndexFor(schema.members);
17233
+ const nested = (memberId) => {
17234
+ const found = byId.get(memberId);
17235
+ return found === void 0 ? null : slotTypeInfoInternal(found, schema, env, nextSeen);
17236
+ };
17237
+ const required = isRequiredMember(resolved);
17238
+ if (isMemberLookupBase(resolved)) {
17239
+ const target = resolved.declaredTypeInfo ?? collectionEntryType(resolved, nested);
17240
+ if (target === null) return null;
17241
+ if (isMultiSelectionMember(resolved)) {
17242
+ return {
17243
+ type: 9 /* Lookup */,
17244
+ required,
17245
+ entryTypeInfo: {
17246
+ type: 29 /* Reference */,
17247
+ required: true,
17248
+ targetTypeInfo: target
17249
+ }
17250
+ };
17251
+ }
17252
+ return { type: 29 /* Reference */, required, targetTypeInfo: target };
17253
+ }
17254
+ switch (resolved.kind) {
17255
+ case 1 /* Bool */:
17256
+ case 2 /* Int */:
17257
+ case 3 /* String */:
17258
+ case 4 /* Float */:
17259
+ case 20 /* Decimal */:
17260
+ case 11 /* Sprite */:
17261
+ case 12 /* Audio */:
17262
+ case 14 /* Vector2 */:
17263
+ case 15 /* Vector2Int */:
17264
+ case 16 /* Vector3 */:
17265
+ case 17 /* Vector3Int */:
17266
+ case 19 /* Color */:
17267
+ return { type: resolved.kind, required };
17268
+ case 18 /* DialogueLookup */:
17269
+ return isMultiSelectionMember(resolved) ? {
17270
+ type: 9 /* Lookup */,
17271
+ required,
17272
+ entryTypeInfo: { type: 18 /* DialogueLookup */, required: true }
17273
+ } : { type: 18 /* DialogueLookup */, required };
17274
+ case 8 /* Enum */: {
17275
+ const enumId = getField(resolved, "enumId");
17276
+ if (typeof enumId !== "string") return null;
17277
+ return isMultiSelectionMember(resolved) ? {
17278
+ type: 9 /* Lookup */,
17279
+ required,
17280
+ entryTypeInfo: { type: 8 /* Enum */, required: true, enumId }
17281
+ } : { type: 8 /* Enum */, required, enumId };
17282
+ }
17283
+ case 6 /* List */:
17284
+ case 28 /* Set */:
17285
+ case 5 /* Dictionary */: {
17286
+ const entryMemberId = getField(resolved, "entryMemberId");
17287
+ if (typeof entryMemberId !== "string") return null;
17288
+ const entryTypeInfo = nested(entryMemberId);
17289
+ if (entryTypeInfo === null) return null;
17290
+ if (resolved.kind === 28 /* Set */) {
17291
+ return { type: 9 /* Lookup */, required, entryTypeInfo };
17292
+ }
17293
+ return {
17294
+ type: resolved.kind,
17295
+ required,
17296
+ entryTypeInfo,
17297
+ ...isMemberDictionaryBase(resolved) && resolved.keyEnumId ? { keyEnumId: resolved.keyEnumId } : {}
17298
+ };
17299
+ }
17300
+ case 7 /* Class */: {
17301
+ if (!isMemberClassBase(resolved)) return null;
17302
+ const typeArguments = {};
17303
+ for (const [paramId, binding] of Object.entries(
17304
+ resolved.classArguments ?? {}
17305
+ )) {
17306
+ if (!isMemberGenericBinding(binding)) continue;
17307
+ const argument2 = nested(binding.memberId);
17308
+ if (argument2 !== null) typeArguments[paramId] = argument2;
17309
+ }
17310
+ return {
17311
+ type: 7 /* Class */,
17312
+ required,
17313
+ classId: resolved.classId,
17314
+ ...Object.keys(typeArguments).length === 0 ? {} : { typeArguments }
17315
+ };
17316
+ }
17317
+ case 27 /* Variant */:
17318
+ if (!isMemberVariantBase(resolved)) return null;
17319
+ return variantMemberDeclaredTypeInfo(
17320
+ resolved,
17321
+ neoVariantSystemClass(schema.classes, resolved.valueTypeInfo != null)
17322
+ );
17323
+ case 21 /* Generic */:
17324
+ if (!isMemberGenericBase(resolved)) return null;
17325
+ return {
17326
+ type: 21 /* Generic */,
17327
+ required: true,
17328
+ ownerClassId: genericOwnerClassId(resolved.genericParamId, schema),
17329
+ genericParamId: resolved.genericParamId
17330
+ };
17331
+ case 0 /* Null */:
17332
+ case 9 /* Lookup */:
17333
+ case 10 /* NSProperty */:
17334
+ case 13 /* Function */:
17335
+ case 23 /* NSFunction */:
17336
+ case 24 /* FunctionRef */:
17337
+ case 25 /* NSDelegate */:
17338
+ case 26 /* NSAction */:
17339
+ case 22 /* Interface */:
17340
+ case 29 /* Reference */:
17341
+ return null;
17342
+ }
17343
+ }
17344
+ function referenceTargetFits(stored, target, context) {
17345
+ switch (referenceCategory(target)) {
17346
+ case "handle" /* Handle */:
17347
+ if (stored.type === 29 /* Reference */) return false;
17348
+ return isTypeInfoAssignable(stored, target, context);
17349
+ case "slot" /* Slot */:
17350
+ return typeInfosInvariantlyEqual(stored, target);
17351
+ case "deferred" /* Deferred */:
17352
+ return true;
17353
+ case "ineligible" /* Ineligible */:
17354
+ return false;
17355
+ }
17356
+ }
17357
+ function referenceFitError(subject, targetId, stored, target, names) {
17358
+ const storedName = formatTypeInfo(stored, names);
17359
+ const article = /^[aeiou]/i.test(storedName) ? "an" : "a";
17360
+ return `${subject} target '${targetId}' is ${article} ${storedName}, but the reference declares ${formatTypeInfo(target, names)}.`;
17361
+ }
17362
+ function collectionEntryType(member, nested) {
17363
+ if (member.collectionMemberId === void 0) return null;
17364
+ const collection = nested(member.collectionMemberId);
17365
+ if (collection === null) return null;
17366
+ if (collection.type !== 6 /* List */ && collection.type !== 9 /* Lookup */ && collection.type !== 5 /* Dictionary */) {
17367
+ return null;
17368
+ }
17369
+ return collection.entryTypeInfo;
17370
+ }
17371
+ function genericOwnerClassId(genericParamId, schema) {
17372
+ for (const schemaClass2 of schema.classes) {
17373
+ if (schemaClass2.genericParams?.some(({ id }) => id === genericParamId)) {
17374
+ return schemaClass2.id;
17375
+ }
17376
+ }
17377
+ return "";
17378
+ }
17379
+
16774
17380
  // ../packages/neoscript-language/src/declared-constructors.ts
16775
17381
  function neoScriptArgumentNameSetKey(names) {
16776
17382
  return [...names].map((name) => name.toLowerCase()).sort().join(",");
@@ -17670,6 +18276,7 @@ function forgetLocalListIndexes(ctx, list) {
17670
18276
  function trackedRowForValueReference(value, ctx) {
17671
18277
  if (value instanceof RuntimeSet) value = value.source;
17672
18278
  if (typeof value !== "object" || value === null) return null;
18279
+ if (value instanceof NSSlotReference) return null;
17673
18280
  const indexes3 = evaluatorIndexes(ctx);
17674
18281
  const indexed = indexes3.rowByValueReference.get(value) ?? indexes3.baseRowByValueReference?.get(value) ?? ctx.vm.databaseVM?.rowForValueReference?.(value) ?? null;
17675
18282
  if (indexed !== null) return indexed;
@@ -17772,6 +18379,7 @@ function evaluatorResolutionCache(ctx) {
17772
18379
  schemaRevision
17773
18380
  ),
17774
18381
  callableSignatureByKey: /* @__PURE__ */ new Map(),
18382
+ collectionLookupTargets: /* @__PURE__ */ new WeakMap(),
17775
18383
  compiledFunctionByMemberId: /* @__PURE__ */ new Map(),
17776
18384
  compiledGetterByMemberId: /* @__PURE__ */ new Map(),
17777
18385
  compiledSetterByMemberId: /* @__PURE__ */ new Map(),
@@ -17931,14 +18539,18 @@ function createdSessionValuesSince(ctx, checkpoint) {
17931
18539
  }
17932
18540
  function exportInitializerCollections(created, writes, ctx) {
17933
18541
  const assignedValues = /* @__PURE__ */ new Set();
18542
+ const mutatedIds = /* @__PURE__ */ new Set();
17934
18543
  for (const write of writes) {
18544
+ const destination = write.resolvedDestination;
18545
+ if (destination !== void 0 && "containerValueId" in destination)
18546
+ mutatedIds.add(destination.containerValueId);
17935
18547
  if (write.kind === "assign" && write.valueId === void 0 && typeof write.value === "object" && write.value !== null) {
17936
18548
  assignedValues.add(write.value);
17937
18549
  }
17938
18550
  }
17939
18551
  const candidates = /* @__PURE__ */ new Set();
17940
18552
  for (const row of created) {
17941
- if (assignedValues.has(row.value) || Array.isArray(row.value) && row.value.length > 0 && ctx.__unorderedListProjections?.byContainerId.has(row.id)) {
18553
+ if (assignedValues.has(row.value) || row.classId === void 0 && mutatedIds.has(row.id) || Array.isArray(row.value) && row.value.length > 0 && ctx.__unorderedListProjections?.byContainerId.has(row.id)) {
17942
18554
  candidates.add(row.id);
17943
18555
  }
17944
18556
  }
@@ -17953,7 +18565,7 @@ function exportInitializerCollections(created, writes, ctx) {
17953
18565
  if (isMemberEntryCollectionBase(member) && listKindOf(member) === 1 /* Unordered */) {
17954
18566
  return { ...row, value: [] };
17955
18567
  }
17956
- if (!assignedValues.has(row.value)) return row;
18568
+ if (!assignedValues.has(row.value) && !mutatedIds.has(row.id)) return row;
17957
18569
  const values = [];
17958
18570
  const declarations = /* @__PURE__ */ new Map();
17959
18571
  const genericEnv = runtimeGenericEnvForValueRow(row, ctx, /* @__PURE__ */ new Set());
@@ -17969,7 +18581,7 @@ function exportInitializerCollections(created, writes, ctx) {
17969
18581
  createdValues: values,
17970
18582
  createdById: /* @__PURE__ */ new Map(),
17971
18583
  storageKeyDeclarations: declarations,
17972
- collectionEntriesAreReferences: false,
18584
+ collectionEntriesAreReferences: assignedValues.has(row.value) ? false : void 0,
17973
18585
  collectionOwnerId: row.id
17974
18586
  });
17975
18587
  const encoded = { ...row, value: materialized.value };
@@ -18321,7 +18933,8 @@ function withEvaluationRuntime(ctx, writes) {
18321
18933
  constructionTimestamp: Date.now(),
18322
18934
  ownedValueAttachments: /* @__PURE__ */ new Map(),
18323
18935
  constructionStack: [],
18324
- openConstructions: /* @__PURE__ */ new Map()
18936
+ openConstructions: /* @__PURE__ */ new Map(),
18937
+ detachedRowIds: /* @__PURE__ */ new Set()
18325
18938
  },
18326
18939
  __indexes: ctx.__executionState === void 0 || ctx.__valueOverlay === void 0 ? void 0 : ctx.__indexes
18327
18940
  };
@@ -18602,18 +19215,19 @@ function finalizeConstructorAllocations(ctx, returnValue, ownsInvocationState, r
18602
19215
  return;
18603
19216
  }
18604
19217
  if (!Array.isArray(row.value)) return;
18605
- for (const childId of row.value) {
18606
- if (typeof childId === "string") scanOwnedRow(childId, entryMember);
18607
- }
19218
+ for (const entry of row.value) scanOwnedEntry(entry, entryMember);
18608
19219
  return;
18609
19220
  }
18610
19221
  if (member !== null && isMemberDictionaryBase(member) && isOwnedRecord(row.value)) {
18611
19222
  const entryMember = evalMemberById(ctx.vm, member.entryMemberId);
18612
- for (const childId of Object.values(row.value)) {
18613
- if (typeof childId === "string") scanOwnedRow(childId, entryMember);
18614
- }
19223
+ for (const entry of Object.values(row.value))
19224
+ scanOwnedEntry(entry, entryMember);
18615
19225
  }
18616
19226
  };
19227
+ const scanOwnedEntry = (entry, entryMember) => {
19228
+ if (typeof entry === "string") scanOwnedRow(entry, entryMember);
19229
+ else scanReturnedValue(entry, void 0);
19230
+ };
18617
19231
  const scannedReturnReferences = /* @__PURE__ */ new Set();
18618
19232
  const scanReturnedValue = (value, typeInfo) => {
18619
19233
  if (typeof value === "object" && value !== null) {
@@ -18938,7 +19552,11 @@ function executeCompiledFunction(action, ctx, args, allowFallthroughReturn, runt
18938
19552
  for (let index = 0; index < filledArgs.length; index += 1) {
18939
19553
  const parameter3 = action.parameters[index + 2];
18940
19554
  const runtimeTypeInfo = runtimeArgumentTypes[index];
18941
- const value2 = asDeclaredRuntimeSet(filledArgs[index], runtimeTypeInfo, ctx);
19555
+ const value2 = asDeclaredRuntimeSet(
19556
+ restoreExportedReferences(filledArgs[index], runtimeTypeInfo, ctx),
19557
+ runtimeTypeInfo,
19558
+ ctx
19559
+ );
18942
19560
  if (!runtimeValueMatchesType(value2, runtimeTypeInfo, ctx)) {
18943
19561
  throw new NSGetterRuntimeError(
18944
19562
  `NSFunction argument ${index + 1} does not match its declared runtime type.`
@@ -19370,39 +19988,107 @@ function evalInstructions(instructions, scope, ctx, options) {
19370
19988
  );
19371
19989
  break;
19372
19990
  }
19373
- const destination = validateAssignmentTarget(
19374
- ins.target.pointer,
19991
+ let target = ins.target;
19992
+ let destination;
19993
+ if (target.pointer.type === "deref" /* deref */) {
19994
+ ({ target, destination } = writeThroughTarget(
19995
+ target,
19996
+ evalPointer(target.pointer.pointer, scope, ctx),
19997
+ ctx
19998
+ ));
19999
+ }
20000
+ destination = validateAssignmentTarget(
20001
+ target.pointer,
19375
20002
  scope,
19376
- ctx
20003
+ ctx,
20004
+ destination
19377
20005
  );
19378
- const member = assignmentTargetMember(
19379
- ins.target.pointer,
20006
+ let member = assignmentTargetMember(
20007
+ target.pointer,
19380
20008
  scope,
19381
20009
  ctx,
19382
20010
  destination
19383
20011
  );
19384
- const lookupAssignment = member !== null && isMemberLookupBase(member);
19385
- if (lookupAssignment) {
19386
- value = encodeLookupInitializerSelection(member, value, [], ctx);
20012
+ const through = genericSlotReference(member, destination, value, ctx);
20013
+ if (through !== null) {
20014
+ ({ target, destination } = writeThroughTarget(
20015
+ target,
20016
+ through,
20017
+ ctx
20018
+ ));
20019
+ destination = validateAssignmentTarget(
20020
+ target.pointer,
20021
+ scope,
20022
+ ctx,
20023
+ destination
20024
+ );
20025
+ member = assignmentTargetMember(
20026
+ target.pointer,
20027
+ scope,
20028
+ ctx,
20029
+ destination
20030
+ );
20031
+ }
20032
+ assertStoredClosureCaptures(
20033
+ member,
20034
+ target.pointer,
20035
+ destination,
20036
+ value,
20037
+ ctx
20038
+ );
20039
+ const lookupMember = member !== null && isMemberLookup(member) ? member : null;
20040
+ if (lookupMember !== null) {
20041
+ materializeReferencedSlots(value, ctx);
20042
+ const holder = destination === void 0 ? null : trackedRowForValueReference(destination.receiver, ctx);
20043
+ const lookupTarget = lookupTargetTypeInfo(
20044
+ lookupMember,
20045
+ holder,
20046
+ ctx
20047
+ );
20048
+ const selection = encodeLookupInitializerSelection(
20049
+ lookupMember,
20050
+ value,
20051
+ [],
20052
+ ctx,
20053
+ lookupTarget
20054
+ );
20055
+ assertStoredReferenceTargets(
20056
+ lookupMember,
20057
+ lookupTarget,
20058
+ slotStorage(target.pointer, lookupMember.id, holder, ctx),
20059
+ selection,
20060
+ ctx
20061
+ );
20062
+ value = selection;
19387
20063
  }
19388
- let targetTypeInfo = ins.target.typeInfo;
19389
- if (lookupAssignment && targetTypeInfo.type !== 9 /* Lookup */ && targetTypeInfo.type !== 18 /* DialogueLookup */) {
19390
- targetTypeInfo = member.collectionMemberId === void 0 ? {
20064
+ let targetTypeInfo = target.typeInfo;
20065
+ if (lookupMember !== null && targetTypeInfo.type !== 9 /* Lookup */ && targetTypeInfo.type !== 18 /* DialogueLookup */) {
20066
+ const entryTypeInfo = targetTypeInfo.type === 29 /* Reference */ ? targetTypeInfo.targetTypeInfo : targetTypeInfo;
20067
+ targetTypeInfo = lookupMember.collectionMemberId === void 0 ? {
19391
20068
  type: 9 /* Lookup */,
19392
20069
  required: targetTypeInfo.required,
19393
- entryTypeInfo: targetTypeInfo
20070
+ entryTypeInfo
19394
20071
  } : {
19395
20072
  type: 9 /* Lookup */,
19396
20073
  required: targetTypeInfo.required,
19397
- entryTypeInfo: targetTypeInfo,
19398
- collectionMemberId: member.collectionMemberId,
19399
- collectionValueId: member.collectionValueId
20074
+ entryTypeInfo,
20075
+ collectionMemberId: lookupMember.collectionMemberId,
20076
+ collectionValueId: lookupMember.collectionValueId
19400
20077
  };
19401
20078
  }
20079
+ if (isTypeInfoWithEntries(targetTypeInfo)) {
20080
+ value = keptCollectionSlotValue(
20081
+ target.pointer,
20082
+ targetTypeInfo,
20083
+ destination,
20084
+ value,
20085
+ ctx
20086
+ );
20087
+ }
19402
20088
  const assignedReferenceValueId = targetTypeInfo.type === 7 /* Class */ || targetTypeInfo.type === 6 /* List */ || targetTypeInfo.type === 28 /* Set */ || targetTypeInfo.type === 5 /* Dictionary */ ? findKnownRowIdByValueReference(value, ctx) : null;
19403
20089
  if (!bindOmittedConstantSlot(destination, member, value, ctx)) {
19404
20090
  applyOverlayAssignment(
19405
- ins.target.pointer,
20091
+ target.pointer,
19406
20092
  targetTypeInfo,
19407
20093
  value,
19408
20094
  scope,
@@ -19411,20 +20097,20 @@ function evalInstructions(instructions, scope, ctx, options) {
19411
20097
  );
19412
20098
  }
19413
20099
  const unorderedReplacement = assignedReferenceValueId === null && member !== null && isMemberEntryCollectionBase(member) && listKindOf(member) === 1 /* Unordered */ && Array.isArray(value) ? unorderedReplacementProjection(
19414
- ins.target.pointer,
20100
+ target.pointer,
19415
20101
  destination,
19416
20102
  scope,
19417
20103
  ctx
19418
20104
  ) : null;
19419
20105
  options.writes.push({
19420
20106
  kind: "assign",
19421
- target: targetTypeInfo === ins.target.typeInfo ? ins.target : { ...ins.target, typeInfo: targetTypeInfo },
20107
+ target: targetTypeInfo === target.typeInfo ? target : { ...target, typeInfo: targetTypeInfo },
19422
20108
  value: unorderedReplacement ?? value,
19423
20109
  ...targetTypeInfo.type === 7 /* Class */ || targetTypeInfo.type === 6 /* List */ || targetTypeInfo.type === 28 /* Set */ || targetTypeInfo.type === 5 /* Dictionary */ ? {
19424
20110
  valueId: value === null || value === void 0 ? void 0 : assignedReferenceValueId ?? void 0
19425
20111
  } : {},
19426
20112
  ...resolvedDestinationFieldsForAssign(
19427
- ins.target.pointer,
20113
+ target.pointer,
19428
20114
  scope,
19429
20115
  ctx,
19430
20116
  destination
@@ -19786,7 +20472,7 @@ function readNeoScriptChangeListenerValue(slot, ctx) {
19786
20472
  throw new NSGetterRuntimeError(
19787
20473
  `OnChanged cannot read '${slot.owner.id}/${slot.memberId}'.`
19788
20474
  );
19789
- return result.value;
20475
+ return readThroughReference(result.value, ctx);
19790
20476
  }
19791
20477
  function resolveNeoScriptChangeListenerHandler(slot, target, ctx) {
19792
20478
  const raw = evalMemberById(ctx.vm, target.memberId);
@@ -20065,7 +20751,7 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx, desti
20065
20751
  "Stored construction replay cannot assign persisted static values."
20066
20752
  );
20067
20753
  }
20068
- applyOverlayStaticAssignment(target.memberId, value, ctx);
20754
+ applyOverlayStaticAssignment(target.memberId, targetTypeInfo, value, ctx);
20069
20755
  return;
20070
20756
  }
20071
20757
  if (target.type !== "keyOf" /* keyOf */) {
@@ -20091,6 +20777,7 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx, desti
20091
20777
  `${parentId}[${index}]`,
20092
20778
  ctx
20093
20779
  );
20780
+ noteDetachedRow(receiver[index], referenceValueId, ctx);
20094
20781
  }
20095
20782
  receiver[index] = referenceValueId;
20096
20783
  recordWrittenEntry(receiver, index, true, ctx);
@@ -20125,6 +20812,7 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx, desti
20125
20812
  `${parentId}.${stringKey}`,
20126
20813
  ctx
20127
20814
  );
20815
+ noteDetachedRow(object[stringKey], referenceValueId, ctx);
20128
20816
  }
20129
20817
  object[stringKey] = referenceValueId;
20130
20818
  if (!field) recordWrittenEntry(object, stringKey, true, ctx);
@@ -20133,10 +20821,100 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx, desti
20133
20821
  }
20134
20822
  if (collectionReferences(object, ctx) === 0 /* RowIds */ && replaceEntryRowValue(object, object[stringKey], value, targetTypeInfo, ctx))
20135
20823
  return;
20824
+ if (field && targetTypeInfo.type === 7 /* Class */)
20825
+ noteDetachedRow(object[stringKey], value, ctx);
20136
20826
  object[stringKey] = value;
20137
20827
  if (!field) recordWrittenEntry(object, stringKey, false, ctx);
20138
20828
  invalidateEvaluatorIndexes(ctx, receiver);
20139
20829
  }
20830
+ function keptCollectionSlotValue(target, targetTypeInfo, destination, value, ctx) {
20831
+ const sourceId = findKnownRowIdByValueReference(value, ctx);
20832
+ if (sourceId === null) return value;
20833
+ const slot = collectionSlotRow(target, destination, ctx);
20834
+ if (slot === null) return value;
20835
+ if (slot.id === sourceId) return value;
20836
+ const source = evalValueById(
20837
+ ctx,
20838
+ sourceId,
20839
+ ctx.__runtimeSessionValues,
20840
+ ctx.__valueOverlay
20841
+ );
20842
+ if (source === null) return value;
20843
+ const entryTypeInfo = typeInfoContainsGeneric2(targetTypeInfo.entryTypeInfo) ? substituteRuntimeTypeInfo(
20844
+ targetTypeInfo.entryTypeInfo,
20845
+ runtimeGenericEnvForValueRow(slot, ctx, /* @__PURE__ */ new Set()),
20846
+ ctx
20847
+ ) : targetTypeInfo.entryTypeInfo;
20848
+ return copiedCollectionContents(source.value, entryTypeInfo, slot.id, ctx);
20849
+ }
20850
+ function collectionSlotRow(target, destination, ctx) {
20851
+ let slotId = null;
20852
+ if (target.type === "staticMember" /* staticMember */) {
20853
+ const member = evalMemberById(ctx.vm, target.memberId);
20854
+ slotId = member === null ? null : staticBindingTargetId(member, ctx);
20855
+ } else if (destination !== void 0) {
20856
+ const { receiver, key } = destination;
20857
+ if (typeof receiver !== "object" || receiver === null) return null;
20858
+ const entryKey = Array.isArray(receiver) ? Number(key) : String(key);
20859
+ if (!isReferenceEntry(collectionReferences(receiver, ctx), entryKey))
20860
+ return null;
20861
+ slotId = Reflect.get(receiver, entryKey);
20862
+ }
20863
+ if (typeof slotId !== "string") return null;
20864
+ return evalValueById(
20865
+ ctx,
20866
+ slotId,
20867
+ ctx.__runtimeSessionValues,
20868
+ ctx.__valueOverlay
20869
+ );
20870
+ }
20871
+ function copiedCollectionContents(source, entryTypeInfo, slotId, ctx) {
20872
+ const list = Array.isArray(source);
20873
+ const copy = list ? [] : {};
20874
+ const references = /* @__PURE__ */ new Set();
20875
+ forEachRawCollectionEntry(source, ctx, ({ raw, key, valueId }) => {
20876
+ let entry = raw;
20877
+ if (valueId !== null) {
20878
+ const row = evalValueById(
20879
+ ctx,
20880
+ valueId,
20881
+ ctx.__runtimeSessionValues,
20882
+ ctx.__valueOverlay
20883
+ );
20884
+ if (row !== null && isClassEntryRow(row)) {
20885
+ assertOwnedValueAttachable(
20886
+ valueId,
20887
+ { identity: `value:${slotId}:entry:${key}`, label: slotId },
20888
+ `${slotId}[${key}]`,
20889
+ ctx
20890
+ );
20891
+ references.add(key);
20892
+ } else if (row !== null) {
20893
+ const stored = readRowValue(row, ctx);
20894
+ entry = isTypeInfoWithEntries(entryTypeInfo) && stored !== null ? copiedCollectionContents(
20895
+ stored,
20896
+ entryTypeInfo.entryTypeInfo,
20897
+ slotId,
20898
+ ctx
20899
+ ) : deepClonePlainData(stored);
20900
+ }
20901
+ }
20902
+ if (Array.isArray(copy)) copy.push(entry);
20903
+ else copy[String(key)] = entry;
20904
+ return 0 /* Continue */;
20905
+ });
20906
+ const cache = unorderedListProjectionCache(ctx);
20907
+ if (Array.isArray(copy))
20908
+ cache.referenceEntryIndexesByArray.set(copy, references);
20909
+ else cache.referenceEntryKeysByRecord.set(copy, references);
20910
+ return copy;
20911
+ }
20912
+ function isClassEntryRow(row) {
20913
+ return typeof row.classId === "string" && !isVariantClassId(row.classId);
20914
+ }
20915
+ function isTypeInfoWithEntries(typeInfo) {
20916
+ return typeInfo.type === 6 /* List */ || typeInfo.type === 28 /* Set */ || typeInfo.type === 5 /* Dictionary */;
20917
+ }
20140
20918
  function replaceEntryRowValue(receiver, existing, value, targetTypeInfo, ctx) {
20141
20919
  if (typeof existing !== "string") return false;
20142
20920
  const row = evalValueById(
@@ -20176,7 +20954,7 @@ function replaceRowValue(row, value, receiver, ctx) {
20176
20954
  if (ctx.__valueOverlay instanceof LazyValueOverlay)
20177
20955
  indexes3.overlayRevision = ctx.__valueOverlay.revision;
20178
20956
  }
20179
- function applyOverlayStaticAssignment(memberId, value, ctx) {
20957
+ function applyOverlayStaticAssignment(memberId, targetTypeInfo, value, ctx) {
20180
20958
  const member = evalMemberById(ctx.vm, memberId);
20181
20959
  if (member === null || !isStaticMember(member)) {
20182
20960
  throw new NSGetterRuntimeError(
@@ -20185,19 +20963,23 @@ function applyOverlayStaticAssignment(memberId, value, ctx) {
20185
20963
  }
20186
20964
  const bindings = writableStaticBindingMap(member, ctx);
20187
20965
  ctx.__getterSubscriptions?.noteStaticBinding(member.id);
20966
+ const currentId = staticBindingTargetId(member, ctx);
20967
+ const resolved = resolveMember(member, ctx.vm.members);
20968
+ const classStatic = isMemberClassBase(resolved);
20188
20969
  if (value === null || value === void 0) {
20189
20970
  if (isRequiredMember(member)) {
20190
20971
  throw new NSGetterRuntimeError(
20191
20972
  `Required static member '${member.name}' cannot be cleared.`
20192
20973
  );
20193
20974
  }
20194
- bindings.set(member.id, null);
20195
- return;
20975
+ if (classStatic || currentId === null) {
20976
+ if (classStatic) noteDetachedRow(currentId, null, ctx);
20977
+ bindings.set(member.id, null);
20978
+ return;
20979
+ }
20196
20980
  }
20197
- const currentId = staticBindingTargetId(member, ctx);
20198
- const resolved = resolveMember(member, ctx.vm.members);
20199
- const referenceAssignment = isMemberClassBase(resolved) || isMemberWithEntries(resolved);
20200
- const trackedId = findKnownRowIdByValueReference(value, ctx);
20981
+ const referenceAssignment = classStatic || isMemberWithEntries(resolved);
20982
+ const trackedId = currentId === null || classStatic ? findKnownRowIdByValueReference(value, ctx) : null;
20201
20983
  if (referenceAssignment && trackedId !== null) {
20202
20984
  assertOwnedValueAttachable(
20203
20985
  trackedId,
@@ -20208,27 +20990,40 @@ function applyOverlayStaticAssignment(memberId, value, ctx) {
20208
20990
  `${member.name} static binding`,
20209
20991
  ctx
20210
20992
  );
20993
+ if (classStatic) noteDetachedRow(currentId, trackedId, ctx);
20211
20994
  bindings.set(member.id, trackedId);
20212
20995
  return;
20213
20996
  }
20214
- if (!referenceAssignment && currentId !== null) {
20215
- const row2 = evalValueById(
20997
+ if (!classStatic && currentId !== null) {
20998
+ const row = evalValueById(
20216
20999
  ctx,
20217
21000
  currentId,
20218
21001
  ctx.__runtimeSessionValues,
20219
21002
  ctx.__valueOverlay
20220
21003
  );
20221
- if (row2 === null) {
21004
+ if (row === null) {
20222
21005
  throw new NSGetterRuntimeError(
20223
21006
  `Static member '${member.name}' is bound to missing value '${currentId}'.`
20224
21007
  );
20225
21008
  }
20226
- observeValueWrite(ctx, row2);
20227
- row2.value = value;
20228
- row2.updatedAt = Date.now();
21009
+ observeValueWrite(ctx, row);
21010
+ keepAssignedCollectionValues(value, targetTypeInfo, ctx);
21011
+ row.value = value ?? null;
21012
+ row.updatedAt = Date.now();
21013
+ updateUnorderedListProjectionAfterAssignment(row, value, ctx);
20229
21014
  invalidateEvaluatorIndexes(ctx);
20230
21015
  return;
20231
21016
  }
21017
+ bindMaterializedStatic(
21018
+ member,
21019
+ resolved,
21020
+ value,
21021
+ classStatic ? void 0 : virtualValueId(member.id, "static"),
21022
+ ctx
21023
+ );
21024
+ }
21025
+ function bindMaterializedStatic(member, resolved, value, rowId, ctx) {
21026
+ const bindings = writableStaticBindingMap(member, ctx);
20232
21027
  const createdValues = [];
20233
21028
  const createdById = /* @__PURE__ */ new Map();
20234
21029
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
@@ -20242,7 +21037,8 @@ function applyOverlayStaticAssignment(memberId, value, ctx) {
20242
21037
  ctx,
20243
21038
  createdValues,
20244
21039
  createdById,
20245
- storageKeyDeclarations
21040
+ storageKeyDeclarations,
21041
+ rowId
20246
21042
  });
20247
21043
  stampCreatedValuesMapKey(createdValues, null);
20248
21044
  applyDeclaredStorageKeyOverrides({
@@ -20309,6 +21105,405 @@ function bindOmittedConstantSlot(destination, member, value, ctx) {
20309
21105
  function touchUnknown(_ins) {
20310
21106
  void _ins;
20311
21107
  }
21108
+ function writeThroughTarget(target, reference, ctx) {
21109
+ if (reference === null || reference === void 0) {
21110
+ throw new NSGetterRuntimeError(
21111
+ "Cannot write through a null reference. Check it for null first."
21112
+ );
21113
+ }
21114
+ if (!(reference instanceof NSSlotReference)) {
21115
+ throw new CorruptNeoScriptIRError(
21116
+ `A write through a reference reached a ${typeof reference}, not a reference.`
21117
+ );
21118
+ }
21119
+ let place = reference.place;
21120
+ if (place === null) {
21121
+ const row = referencedRow(reference, ctx);
21122
+ place = slotPlaceOfRow(row, ctx);
21123
+ if (place === null) return entryWriteTarget(target, row, reference, ctx);
21124
+ }
21125
+ const slotMember = evalMemberById(ctx.vm, place.memberId);
21126
+ if (slotMember === null) {
21127
+ throw new NSGetterRuntimeError(
21128
+ `${referenceSubject(reference.memberId, ctx)} names a slot of missing member '${place.memberId}'.`
21129
+ );
21130
+ }
21131
+ if (place.kind === 1 /* Static */) {
21132
+ if (isReadOnlyMember(slotMember))
21133
+ throw readonlyTargetError(slotMember, reference, ctx);
21134
+ const storage = effectiveStaticStorage(slotMember.id, ctx);
21135
+ if (storage === 1 /* Immutable */) throw assetTargetError();
21136
+ return {
21137
+ target: {
21138
+ pointer: { type: "staticMember" /* staticMember */, memberId: slotMember.id },
21139
+ typeInfo: target.typeInfo,
21140
+ writability: storage === 2 /* Save */ ? "save" /* Save */ : "session" /* Session */
21141
+ }
21142
+ };
21143
+ }
21144
+ if (reference.place !== null) assertPlaceAttached(reference, place, ctx);
21145
+ const { owner, key } = place;
21146
+ if (isReadOnlyMember(slotMember) && ctx.__executionState?.openConstructions.has(owner) !== true) {
21147
+ throw readonlyTargetError(slotMember, reference, ctx);
21148
+ }
21149
+ const ownerId = findKnownRowIdByValueReference(owner, ctx);
21150
+ if (ownerId === null) {
21151
+ throw new NSGetterRuntimeError(
21152
+ `${referenceSubject(reference.memberId, ctx)} names '${key}' of a value with no stored row.`
21153
+ );
21154
+ }
21155
+ if (constructorArgumentStorage(ownerId, ctx) === 1 /* Immutable */)
21156
+ throw assetTargetError();
21157
+ materializeSlotRow(place, reference.targetId, ctx);
21158
+ return {
21159
+ target: {
21160
+ pointer: {
21161
+ type: "keyOf" /* keyOf */,
21162
+ memberId: slotMember.id,
21163
+ keyOf: {
21164
+ pointer: { type: "reference" /* reference */, valueId: ownerId },
21165
+ key: {
21166
+ type: "value" /* value */,
21167
+ value: { typeInfo: STRING_TYPE_INFO, value: key }
21168
+ }
21169
+ }
21170
+ },
21171
+ typeInfo: target.typeInfo,
21172
+ writability: "runtime" /* Runtime */
21173
+ },
21174
+ destination: { receiver: owner, key }
21175
+ };
21176
+ }
21177
+ var STRING_TYPE_INFO = {
21178
+ type: 3 /* String */,
21179
+ required: true
21180
+ };
21181
+ var INT_TYPE_INFO = { type: 2 /* Int */, required: true };
21182
+ function assetTargetError() {
21183
+ return new NSGetterRuntimeError(
21184
+ "Cannot write runtime-owned target because its value is Asset-owned."
21185
+ );
21186
+ }
21187
+ function readonlyTargetError(slotMember, reference, ctx) {
21188
+ const writer = reference.memberId === null ? "a reference" : referenceSubject(reference.memberId, ctx);
21189
+ return new NSGetterRuntimeError(
21190
+ `\`${qualifiedMemberLabel(slotMember.id, ctx)}\` is readonly, so ${writer} can't write it.`
21191
+ );
21192
+ }
21193
+ function entryWriteTarget(target, row, reference, ctx) {
21194
+ const subject = referenceSubject(reference.memberId, ctx);
21195
+ const containerId = evaluatorParentLinks(evaluatorIndexes(ctx), row.id).find(
21196
+ (link) => link.key === ""
21197
+ )?.parentId;
21198
+ if (containerId === void 0) {
21199
+ throw new NSGetterRuntimeError(
21200
+ `${subject} target '${row.id}' is not held by a member slot.`
21201
+ );
21202
+ }
21203
+ const containerRow = evalValueById(
21204
+ ctx,
21205
+ containerId,
21206
+ ctx.__runtimeSessionValues,
21207
+ ctx.__valueOverlay
21208
+ );
21209
+ const containerPlace = containerRow === null ? null : slotPlaceOfRow(containerRow, ctx);
21210
+ if (containerPlace === null) {
21211
+ throw new NSGetterRuntimeError(
21212
+ `${subject} target '${row.id}' is an entry of '${containerId}', which no member slot holds.`
21213
+ );
21214
+ }
21215
+ if (evalMemberById(ctx.vm, containerPlace.memberId)?.kind === 28 /* Set */) {
21216
+ throw new NSGetterRuntimeError(
21217
+ `${subject} names an entry of a Set, which can't be written in place. Remove it and add the new value.`
21218
+ );
21219
+ }
21220
+ const collection = readSlot(containerPlace, ctx);
21221
+ let key;
21222
+ forEachRawCollectionEntry(collection, ctx, (entry) => {
21223
+ if (entry.valueId !== row.id) return 0 /* Continue */;
21224
+ key = entry.key;
21225
+ return 1 /* Break */;
21226
+ });
21227
+ if (key === void 0) {
21228
+ throw danglingReferenceError(reference.memberId, row.id, ctx);
21229
+ }
21230
+ return {
21231
+ target: {
21232
+ pointer: {
21233
+ type: "keyOf" /* keyOf */,
21234
+ memberId: memberForValueRow(row, ctx)?.id,
21235
+ keyOf: {
21236
+ pointer: { type: "reference" /* reference */, valueId: containerId },
21237
+ key: {
21238
+ type: "value" /* value */,
21239
+ value: {
21240
+ typeInfo: typeof key === "number" ? INT_TYPE_INFO : STRING_TYPE_INFO,
21241
+ value: key
21242
+ }
21243
+ }
21244
+ }
21245
+ },
21246
+ typeInfo: target.typeInfo,
21247
+ writability: "runtime" /* Runtime */
21248
+ },
21249
+ destination: { receiver: collection, key }
21250
+ };
21251
+ }
21252
+ function referencedRow(reference, ctx) {
21253
+ const row = evalValueById(
21254
+ ctx,
21255
+ reference.targetId,
21256
+ ctx.__runtimeSessionValues,
21257
+ ctx.__valueOverlay
21258
+ );
21259
+ if (row === null || inDetachedRow(row.id, ctx)) {
21260
+ throw danglingReferenceError(reference.memberId, reference.targetId, ctx);
21261
+ }
21262
+ assertReferenceFits(reference, row, ctx);
21263
+ return row;
21264
+ }
21265
+ function inDetachedRow(rowId, ctx) {
21266
+ const detached = ctx.__executionState?.detachedRowIds;
21267
+ if (detached === void 0 || detached.size === 0) return false;
21268
+ const pending = [rowId];
21269
+ const seen = /* @__PURE__ */ new Set();
21270
+ for (let cursor = 0; cursor < pending.length; cursor += 1) {
21271
+ const id = pending[cursor];
21272
+ if (id === void 0 || seen.has(id)) continue;
21273
+ seen.add(id);
21274
+ let rowOwned = false;
21275
+ for (const owner of currentOwnedValueAttachments(id, ctx)) {
21276
+ if (!owner.identity.startsWith("value:")) continue;
21277
+ rowOwned = true;
21278
+ pending.push(owner.label);
21279
+ }
21280
+ if (!rowOwned && detached.has(id) && activeStaticBindingRoot(id, ctx) === null) {
21281
+ return true;
21282
+ }
21283
+ }
21284
+ return false;
21285
+ }
21286
+ function assertPlaceAttached(reference, place, ctx) {
21287
+ if (place.kind !== 0 /* Member */) return;
21288
+ const detached = ctx.__executionState?.detachedRowIds;
21289
+ if (detached === void 0 || detached.size === 0) return;
21290
+ const ownerId = findKnownRowIdByValueReference(place.owner, ctx);
21291
+ if (ownerId !== null && inDetachedRow(ownerId, ctx)) {
21292
+ throw danglingReferenceError(reference.memberId, reference.targetId, ctx);
21293
+ }
21294
+ }
21295
+ function noteDetachedRow(previous, replacement, ctx) {
21296
+ if (typeof previous !== "string" || previous === replacement) return;
21297
+ ctx.__executionState?.detachedRowIds.add(previous);
21298
+ }
21299
+ function slotPlaceOfRow(row, ctx) {
21300
+ const member = memberForValueRow(row, ctx);
21301
+ if (member === null) return null;
21302
+ if (isStaticMember(member) && staticBindingTargetId(member, ctx) === row.id) {
21303
+ return { kind: 1 /* Static */, memberId: member.id };
21304
+ }
21305
+ for (const link of evaluatorParentLinks(evaluatorIndexes(ctx), row.id)) {
21306
+ if (link.key === "") continue;
21307
+ const parent = evalValueById(
21308
+ ctx,
21309
+ link.parentId,
21310
+ ctx.__runtimeSessionValues,
21311
+ ctx.__valueOverlay
21312
+ );
21313
+ const owner = parent?.value;
21314
+ if (typeof owner !== "object" || owner === null || Array.isArray(owner)) {
21315
+ continue;
21316
+ }
21317
+ return {
21318
+ kind: 0 /* Member */,
21319
+ owner,
21320
+ key: link.key,
21321
+ memberId: member.id
21322
+ };
21323
+ }
21324
+ return null;
21325
+ }
21326
+ function materializeSlotRow(place, targetId, ctx) {
21327
+ const current = getField(place.owner, place.key);
21328
+ if (typeof current === "string") return;
21329
+ if (evalValueById(
21330
+ ctx,
21331
+ targetId,
21332
+ ctx.__runtimeSessionValues,
21333
+ ctx.__valueOverlay
21334
+ ) !== null) {
21335
+ return;
21336
+ }
21337
+ const ownerId = findKnownRowIdByValueReference(place.owner, ctx);
21338
+ if (ownerId !== null && constructorArgumentStorage(ownerId, ctx) === 1 /* Immutable */) {
21339
+ throw new NSGetterRuntimeError(
21340
+ `Cannot bind missing member '${place.key}' on an immutable parent.`
21341
+ );
21342
+ }
21343
+ ctx.beforeValueAllocation?.();
21344
+ const read = readRecordKey(place.owner, place.key, place.memberId, ctx);
21345
+ const owner = trackedRowForValueReference(place.owner, ctx);
21346
+ const member = slotLookupMember(
21347
+ evalMemberById(ctx.vm, place.memberId),
21348
+ owner,
21349
+ ctx
21350
+ );
21351
+ const value = member === null ? read : encodeLookupInitializerSelection(
21352
+ member,
21353
+ read,
21354
+ [],
21355
+ ctx,
21356
+ lookupTargetTypeInfo(member, owner, ctx)
21357
+ );
21358
+ const row = {
21359
+ ...buildNewValue(ctx.vm.project.id, { value: value ?? null }),
21360
+ id: targetId
21361
+ };
21362
+ registerRuntimeSessionValue(ctx, row);
21363
+ Reflect.set(place.owner, place.key, targetId);
21364
+ invalidateEvaluatorIndexes(ctx, place.owner);
21365
+ }
21366
+ function slotLookupMember(member, owner, ctx) {
21367
+ if (member === null) return null;
21368
+ if (isMemberLookup(member)) return member;
21369
+ if (member.kind !== 21 /* Generic */ || owner === null) return null;
21370
+ const bound = substituteMember(
21371
+ member,
21372
+ runtimeGenericEnvForValueRow(owner, ctx),
21373
+ ctx.vm.members
21374
+ );
21375
+ return isMemberLookup(bound) ? bound : null;
21376
+ }
21377
+ function genericSlotReference(member, destination, value, ctx) {
21378
+ if (member === null || !isMemberLookup(member)) return null;
21379
+ if (destination === void 0) return null;
21380
+ if (member.declaredTypeInfo === void 0) return null;
21381
+ if (!typeInfoContainsGeneric2(member.declaredTypeInfo)) return null;
21382
+ if (value instanceof NSSlotReference) return null;
21383
+ const owner = trackedRowForValueReference(destination.receiver, ctx);
21384
+ const target = lookupTargetTypeInfo(member, owner, ctx);
21385
+ if (referenceCategory(target) !== "slot" /* Slot */) return null;
21386
+ if (typeof destination.receiver !== "object" || destination.receiver === null)
21387
+ return null;
21388
+ const current = readRecordKey(
21389
+ destination.receiver,
21390
+ String(destination.key),
21391
+ member.id,
21392
+ ctx
21393
+ );
21394
+ if (current instanceof NSSlotReference) return current;
21395
+ throw new NSGetterRuntimeError(
21396
+ `Cannot write through Reference \`${qualifiedMemberLabel(member.id, ctx)}\`, because it names no target.`
21397
+ );
21398
+ }
21399
+ function materializeReferencedSlots(value, ctx) {
21400
+ const entries = value instanceof RuntimeSet ? value.toArray() : Array.isArray(value) ? value : [value];
21401
+ for (const entry of entries) {
21402
+ if (!(entry instanceof NSSlotReference)) continue;
21403
+ const place = entry.place;
21404
+ if (place?.kind === 0 /* Member */) {
21405
+ materializeSlotRow(place, entry.targetId, ctx);
21406
+ }
21407
+ if (place?.kind === 1 /* Static */) {
21408
+ materializeStaticSlotRow(place.memberId, entry.targetId, ctx);
21409
+ }
21410
+ }
21411
+ }
21412
+ function materializeStaticSlotRow(memberId, targetId, ctx) {
21413
+ const member = evalMemberById(ctx.vm, memberId);
21414
+ if (member === null) return;
21415
+ if (staticBindingTargetId(member, ctx) !== null) return;
21416
+ bindMaterializedStatic(
21417
+ member,
21418
+ resolveMember(member, ctx.vm.members),
21419
+ null,
21420
+ targetId,
21421
+ ctx
21422
+ );
21423
+ }
21424
+ function assertStoredReferenceTargets(member, target, holderStorage, selection, ctx) {
21425
+ if (selection === null || selection.length === 0) return;
21426
+ const slot = referenceCategory(target) === "slot" /* Slot */;
21427
+ for (const targetId of selection) {
21428
+ if (slot) {
21429
+ const row = evalValueById(
21430
+ ctx,
21431
+ targetId,
21432
+ ctx.__runtimeSessionValues,
21433
+ ctx.__valueOverlay
21434
+ );
21435
+ if (row === null) throw danglingReferenceError(member.id, targetId, ctx);
21436
+ assertReferenceFits(
21437
+ new NSSlotReference(targetId, null, target, member.id),
21438
+ row,
21439
+ ctx
21440
+ );
21441
+ }
21442
+ assertReferenceLifetime(
21443
+ `Reference \`${qualifiedMemberLabel(member.id, ctx)}\``,
21444
+ holderStorage,
21445
+ targetId,
21446
+ ctx
21447
+ );
21448
+ }
21449
+ }
21450
+ function assertStoredClosureCaptures(member, pointer, destination, value, ctx) {
21451
+ const memberId = getField(member, "id");
21452
+ if (typeof memberId !== "string") return;
21453
+ if (!isNSDelegateClosureValue(value)) return;
21454
+ const holder = destination === void 0 ? null : trackedRowForValueReference(destination.receiver, ctx);
21455
+ const holderStorage = slotStorage(pointer, memberId, holder, ctx);
21456
+ if (holderStorage === null) return;
21457
+ const subject = `Closure \`${qualifiedMemberLabel(memberId, ctx)}\``;
21458
+ const visit = (captured) => {
21459
+ if (captured instanceof NSSlotReference) {
21460
+ assertReferenceLifetime(subject, holderStorage, captured.targetId, ctx);
21461
+ } else if (captured instanceof RuntimeSet) {
21462
+ captured.toArray().forEach(visit);
21463
+ } else if (Array.isArray(captured)) {
21464
+ captured.forEach(visit);
21465
+ } else if (isNSDelegateClosureValue(captured)) {
21466
+ captured.captures?.forEach(visit);
21467
+ } else if (isPlainRecord(captured)) {
21468
+ Object.values(captured).forEach(visit);
21469
+ }
21470
+ };
21471
+ value.captures?.forEach(visit);
21472
+ }
21473
+ function slotStorage(pointer, memberId, holder, ctx) {
21474
+ if (pointer.type === "staticMember" /* staticMember */) {
21475
+ return effectiveStorageForMemberId(pointer.memberId, ctx);
21476
+ }
21477
+ if (holder === null) return null;
21478
+ const owner = constructorArgumentStorage(holder.id, ctx);
21479
+ if (owner === null) return null;
21480
+ return childEffectiveStorage(
21481
+ effectiveStorageResolver(ctx).declaredStorage(memberId),
21482
+ owner
21483
+ );
21484
+ }
21485
+ var STORE_LIFETIME = {
21486
+ [1 /* Immutable */]: 4,
21487
+ [5 /* User */]: 3,
21488
+ [2 /* Save */]: 2,
21489
+ [3 /* Session */]: 1
21490
+ };
21491
+ var STORE_NAMES = {
21492
+ [1 /* Immutable */]: "Immutable",
21493
+ [5 /* User */]: "User",
21494
+ [2 /* Save */]: "Save",
21495
+ [3 /* Session */]: "Session"
21496
+ };
21497
+ function assertReferenceLifetime(subject, holderStorage, targetId, ctx) {
21498
+ if (holderStorage === null) return;
21499
+ if (ctx.vm.databaseVM?.hasStoredValueId?.(targetId) === true) return;
21500
+ const targetStorage = constructorArgumentStorage(targetId, ctx);
21501
+ if (targetStorage === null) return;
21502
+ if (STORE_LIFETIME[targetStorage] >= STORE_LIFETIME[holderStorage]) return;
21503
+ throw new NSGetterRuntimeError(
21504
+ `${subject} is ${STORE_NAMES[holderStorage]}-stored and can't name '${targetId}', which lives only in the ${STORE_NAMES[targetStorage]}.`
21505
+ );
21506
+ }
20312
21507
  function validateAssignmentTarget(target, scope, ctx, destination) {
20313
21508
  if (target.type === "staticMember" /* staticMember */) {
20314
21509
  const member = evalMemberById(ctx.vm, target.memberId);
@@ -20594,7 +21789,7 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
20594
21789
  if (ins.mutation === "Add" /* Add */ && isArrayCollection(targetValue) && unorderedContainerValueId !== null && !isLookupSet && findKnownRowIdByValueReference(args[0], ctx) === null) {
20595
21790
  overlayArgs[0] = createUnorderedScalarProjectionEntry(
20596
21791
  unorderedContainerValueId,
20597
- args[0],
21792
+ args[0] instanceof NSSlotReference ? [args[0].targetId] : args[0],
20598
21793
  ctx
20599
21794
  );
20600
21795
  }
@@ -20625,6 +21820,7 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
20625
21820
  );
20626
21821
  }
20627
21822
  }
21823
+ const removableRowIds = isLookupSet || ins.reference === true ? null : removableEntryRowIds(targetValue, ins.mutation, overlayArgs, ctx);
20628
21824
  const removedIndex = applyLocalCollectionMutation(
20629
21825
  targetValue,
20630
21826
  ins.mutation,
@@ -20640,6 +21836,13 @@ function evalCollectionMutationInstruction(ins, scope, ctx, options) {
20640
21836
  removedIndex,
20641
21837
  ctx
20642
21838
  );
21839
+ if (removableRowIds !== null) {
21840
+ const key = Array.isArray(targetValue) ? removedIndex : String(args[0]);
21841
+ for (const [entryKey, rowId] of removableRowIds) {
21842
+ if (ins.mutation === "Clear" /* Clear */ || entryKey === key)
21843
+ noteDetachedRow(rowId, null, ctx);
21844
+ }
21845
+ }
20643
21846
  if (writesEntry && !(targetValue instanceof RuntimeSet)) {
20644
21847
  const writtenAsRowId = attachedValueId !== null || unorderedContainerValueId !== null;
20645
21848
  if (Array.isArray(targetValue))
@@ -20784,6 +21987,7 @@ function flushRuntimeSets(ctx) {
20784
21987
  }
20785
21988
  function exportRuntimeSetValue(value, ctx, seen = /* @__PURE__ */ new Map()) {
20786
21989
  if (typeof value !== "object" || value === null) return value;
21990
+ if (value instanceof NSSlotReference) return value.targetId;
20787
21991
  if (seen.has(value)) return seen.get(value);
20788
21992
  if (value instanceof RuntimeSet) {
20789
21993
  seen.set(value, value.source);
@@ -20818,7 +22022,7 @@ function exportRuntimeSetValue(value, ctx, seen = /* @__PURE__ */ new Map()) {
20818
22022
  seen.set(value, result);
20819
22023
  return result;
20820
22024
  }
20821
- if (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null) {
22025
+ if (isPlainRecord(value)) {
20822
22026
  const copy = {};
20823
22027
  seen.set(value, copy);
20824
22028
  let changed = false;
@@ -20833,12 +22037,53 @@ function exportRuntimeSetValue(value, ctx, seen = /* @__PURE__ */ new Map()) {
20833
22037
  }
20834
22038
  return value;
20835
22039
  }
22040
+ function isPlainRecord(value) {
22041
+ if (typeof value !== "object" || value === null) return false;
22042
+ const prototype = Object.getPrototypeOf(value);
22043
+ return prototype === Object.prototype || prototype === null;
22044
+ }
20836
22045
  function isArrayCollection(value) {
20837
22046
  return Array.isArray(value) || value instanceof RuntimeSet;
20838
22047
  }
22048
+ function restoreExportedReferences(value, type, ctx) {
22049
+ if (type.type === 29 /* Reference */) {
22050
+ return typeof value === "string" && holdsSlotReference(type) ? new NSSlotReference(value, null, type.targetTypeInfo, null) : value;
22051
+ }
22052
+ if (type.type !== 6 /* List */ && type.type !== 5 /* Dictionary */ || !holdsSlotReference(type.entryTypeInfo) || trackedRowForValueReference(value, ctx) !== null)
22053
+ return value;
22054
+ if (Array.isArray(value)) {
22055
+ return value.map(
22056
+ (entry) => restoreExportedReferences(entry, type.entryTypeInfo, ctx)
22057
+ );
22058
+ }
22059
+ if (!isPlainRecord(value)) return value;
22060
+ const restored = {};
22061
+ for (const [key, entry] of Object.entries(value))
22062
+ setOwnField(
22063
+ restored,
22064
+ key,
22065
+ restoreExportedReferences(entry, type.entryTypeInfo, ctx)
22066
+ );
22067
+ return restored;
22068
+ }
22069
+ function holdsSlotReference(type) {
22070
+ if (type.type === 29 /* Reference */)
22071
+ return referenceCategory(type.targetTypeInfo) === "slot" /* Slot */;
22072
+ if (type.type === 6 /* List */ || type.type === 5 /* Dictionary */)
22073
+ return holdsSlotReference(type.entryTypeInfo);
22074
+ return false;
22075
+ }
20839
22076
  function asDeclaredRuntimeSet(value, type, ctx) {
20840
22077
  if (type.type !== 9 /* Lookup */ || !Array.isArray(value) || storedSetEntryMember(value, ctx) !== null)
20841
22078
  return value;
22079
+ if (type.entryTypeInfo.type === 29 /* Reference */) {
22080
+ return slotReferenceSet(
22081
+ value,
22082
+ type.entryTypeInfo.targetTypeInfo,
22083
+ null,
22084
+ ctx
22085
+ );
22086
+ }
20842
22087
  const entry = type.entryTypeInfo.type;
20843
22088
  return runtimeSet(
20844
22089
  value,
@@ -20848,6 +22093,7 @@ function asDeclaredRuntimeSet(value, type, ctx) {
20848
22093
  );
20849
22094
  }
20850
22095
  function runtimeSetKey(value, set, ctx) {
22096
+ if (set.slotReferences !== null) return slotReferenceKey(value);
20851
22097
  if (set.enumEntries && Array.isArray(value) && value.length === 1)
20852
22098
  value = value[0];
20853
22099
  return toSetEntryKey(value, null, set.reference, ctx);
@@ -20870,6 +22116,32 @@ function runtimeSet(array2, reference, enumEntries, ctx) {
20870
22116
  (ctx.__dirtyRuntimeSets ??= /* @__PURE__ */ new Set()).add(set);
20871
22117
  return set;
20872
22118
  }
22119
+ function slotReferenceSet(array2, target, memberId, ctx) {
22120
+ const sets = ctx.__runtimeSets ??= /* @__PURE__ */ new WeakMap();
22121
+ const existing = sets.get(array2);
22122
+ if (existing !== void 0) return existing;
22123
+ const set = new RuntimeSet(array2, true, false, { target, memberId });
22124
+ for (const entry of array2) set.add(slotReferenceKey(entry), entry, false);
22125
+ sets.set(array2, set);
22126
+ (ctx.__dirtyRuntimeSets ??= /* @__PURE__ */ new Set()).add(set);
22127
+ return set;
22128
+ }
22129
+ function slotReferenceKey(entry) {
22130
+ if (entry instanceof NSSlotReference) return entry.targetId;
22131
+ if (typeof entry === "string") return entry;
22132
+ throw new NSGetterRuntimeError(
22133
+ `A set of references holds a ${typeof entry} entry, not a value id.`
22134
+ );
22135
+ }
22136
+ function slotReferenceEntry(raw, references) {
22137
+ if (raw instanceof NSSlotReference) return raw;
22138
+ return new NSSlotReference(
22139
+ slotReferenceKey(raw),
22140
+ null,
22141
+ references.target,
22142
+ references.memberId
22143
+ );
22144
+ }
20873
22145
  function storedSetEntryMatch(raw, reference, entryMember, ctx) {
20874
22146
  const byIdentity = entryMember.kind === 7 /* Class */;
20875
22147
  const row = byIdentity || !reference || typeof raw !== "string" ? null : evalValueById(ctx, raw, ctx.__runtimeSessionValues, ctx.__valueOverlay);
@@ -20923,6 +22195,30 @@ function findStoredSetEntry(set, value, entryMember, ctx) {
20923
22195
  if (key === null) return null;
20924
22196
  return storedSetEntries(set, entryMember, ctx).get(key) ?? null;
20925
22197
  }
22198
+ function removableEntryRowIds(targetValue, mutation, args, ctx) {
22199
+ if (mutation !== "Remove" /* Remove */ && mutation !== "RemoveAt" /* RemoveAt */ && mutation !== "Clear" /* Clear */) {
22200
+ return null;
22201
+ }
22202
+ if (typeof targetValue !== "object" || targetValue === null) return null;
22203
+ const references = collectionReferences(targetValue, ctx);
22204
+ const rowIds = /* @__PURE__ */ new Map();
22205
+ const keep = (key, entry) => {
22206
+ if (typeof entry === "string" && isReferenceEntry(references, key))
22207
+ rowIds.set(key, entry);
22208
+ };
22209
+ if (mutation === "RemoveAt" /* RemoveAt */) {
22210
+ const index = Number(args[0]);
22211
+ keep(index, Reflect.get(targetValue, index));
22212
+ } else if (mutation === "Remove" /* Remove */ && !Array.isArray(targetValue)) {
22213
+ const key = String(args[0]);
22214
+ keep(key, Reflect.get(targetValue, key));
22215
+ } else if (Array.isArray(targetValue)) {
22216
+ for (const [index, entry] of targetValue.entries()) keep(index, entry);
22217
+ } else {
22218
+ for (const [key, entry] of Object.entries(targetValue)) keep(key, entry);
22219
+ }
22220
+ return rowIds;
22221
+ }
20926
22222
  function applyLocalCollectionMutation(targetValue, mutation, args, ctx, unique = false, resolveRemovalEntries = false, reference = false) {
20927
22223
  if (targetValue instanceof RuntimeSet) {
20928
22224
  (ctx.__dirtyRuntimeSets ??= /* @__PURE__ */ new Set()).add(targetValue);
@@ -21046,6 +22342,7 @@ function lookupSetSelectionValue(value, typeInfo, ctx) {
21046
22342
  return value[0];
21047
22343
  }
21048
22344
  if (typeof value === "string") return value;
22345
+ if (value instanceof NSSlotReference) return value.targetId;
21049
22346
  return findKnownRowIdByValueReference(value, ctx) ?? value;
21050
22347
  }
21051
22348
  function validateCollectionMutation(targetValue, mutation, args) {
@@ -21117,16 +22414,18 @@ function finiteNumberArg(value, name) {
21117
22414
  throw new NSGetterRuntimeError(`${name} must be a finite number`);
21118
22415
  }
21119
22416
  function effectiveStorageForMemberId(memberId, ctx) {
22417
+ const storages = [
22418
+ ...effectiveStorageResolver(ctx).effectiveStorages(memberId)
22419
+ ];
22420
+ return storages.length === 1 ? storages[0] : null;
22421
+ }
22422
+ function effectiveStorageResolver(ctx) {
21120
22423
  const cache = evaluatorResolutionCache(ctx);
21121
- cache.effectiveStorageResolver ??= new EffectiveStorageResolver({
22424
+ return cache.effectiveStorageResolver ??= new EffectiveStorageResolver({
21122
22425
  members: ctx.vm.members,
21123
22426
  classes: ctx.vm.classes,
21124
22427
  rootStorage: buildRootStorageMap(ctx.vm.project)
21125
22428
  });
21126
- const storages = [
21127
- ...cache.effectiveStorageResolver.effectiveStorages(memberId)
21128
- ];
21129
- return storages.length === 1 ? storages[0] : null;
21130
22429
  }
21131
22430
  function effectiveStaticStorage(memberId, ctx) {
21132
22431
  const storage = effectiveStorageForMemberId(memberId, ctx);
@@ -21196,7 +22495,162 @@ function evalStaticMember(memberId, ctx) {
21196
22495
  `Static member '${member.name}' is bound to missing value '${targetId}'.`
21197
22496
  );
21198
22497
  }
21199
- return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(readRowValue(row, ctx), ctx) : resolveLocalizedRowValueForMember(row, member, ctx);
22498
+ return readLookupSelection(
22499
+ member,
22500
+ resolveLocalizedRowValueForMember(row, member, ctx),
22501
+ row,
22502
+ ctx
22503
+ );
22504
+ }
22505
+ function evalRowOf(pointer, scope, ctx) {
22506
+ const { place } = pointer;
22507
+ switch (place.type) {
22508
+ case "keyOf" /* keyOf */: {
22509
+ const owner = evalPointer(place.keyOf.pointer, scope, ctx);
22510
+ const key = String(evalPointer(place.keyOf.key, scope, ctx));
22511
+ if (owner === null || owner === void 0) {
22512
+ if (place.optional === true) return null;
22513
+ throw new NSGetterRuntimeError(
22514
+ `Cannot reference '${key}' of ${owner === null ? "null" : "undefined"}.`
22515
+ );
22516
+ }
22517
+ if (typeof owner !== "object" || Array.isArray(owner)) {
22518
+ throw new NSGetterRuntimeError(
22519
+ `Cannot reference '${key}' of a ${Array.isArray(owner) ? "list" : typeof owner}, which has no member slots.`
22520
+ );
22521
+ }
22522
+ const memberId = resolveRuntimeSchemaMember(owner, key, ctx)?.id ?? place.memberId;
22523
+ if (memberId === void 0) {
22524
+ throw new NSGetterRuntimeError(
22525
+ `Cannot reference '${key}', which is not a declared member.`
22526
+ );
22527
+ }
22528
+ if (genericSlotCategory(owner, memberId, ctx) === "handle" /* Handle */) {
22529
+ return readRecordKey(owner, key, memberId, ctx);
22530
+ }
22531
+ return new NSSlotReference(
22532
+ slotTargetId(owner, key, memberId, ctx),
22533
+ { kind: 0 /* Member */, owner, key, memberId },
22534
+ null,
22535
+ null
22536
+ );
22537
+ }
22538
+ case "staticMember" /* staticMember */: {
22539
+ const member = evalMemberById(ctx.vm, place.memberId);
22540
+ if (member === null) {
22541
+ throw new NSGetterRuntimeError(
22542
+ `Static member '${place.memberId}' is missing, so it has no row to reference.`
22543
+ );
22544
+ }
22545
+ return new NSSlotReference(
22546
+ staticBindingTargetId(member, ctx) ?? virtualValueId(member.id, "static"),
22547
+ { kind: 1 /* Static */, memberId: member.id },
22548
+ null,
22549
+ null
22550
+ );
22551
+ }
22552
+ case "reference" /* reference */: {
22553
+ const row = resolveRuntimeReferenceRow(
22554
+ place.valueId,
22555
+ ctx,
22556
+ place.withProvenance === true
22557
+ );
22558
+ return new NSSlotReference(
22559
+ row?.id ?? place.valueId,
22560
+ null,
22561
+ pointer.typeInfo ?? null,
22562
+ null
22563
+ );
22564
+ }
22565
+ default:
22566
+ throw new CorruptNeoScriptIRError(
22567
+ `A row reference names a '${place.type}' pointer, not a member, static, or value id.`
22568
+ );
22569
+ }
22570
+ }
22571
+ function genericSlotCategory(owner, memberId, ctx) {
22572
+ const member = evalMemberById(ctx.vm, memberId);
22573
+ if (member === null || !isMemberGenericBase(member)) return null;
22574
+ const row = trackedRowForValueReference(owner, ctx);
22575
+ if (row === null) return null;
22576
+ const bound = runtimeTypeInfoForMember(
22577
+ member,
22578
+ runtimeGenericEnvForValueRow(row, ctx),
22579
+ ctx,
22580
+ /* @__PURE__ */ new Set()
22581
+ );
22582
+ return referenceCategory(bound);
22583
+ }
22584
+ function slotTargetId(owner, key, memberId, ctx) {
22585
+ const ownerId = findKnownRowIdByValueReference(owner, ctx);
22586
+ if (ownerId === null) {
22587
+ throw new NSGetterRuntimeError(
22588
+ `Cannot reference '${key}', because its owner has no stored row.`
22589
+ );
22590
+ }
22591
+ const at2 = getField(owner, key);
22592
+ if (typeof at2 === "string") return at2;
22593
+ const expanded = virtualExpandedRecordForReceiver(owner, ctx);
22594
+ const virtual = expanded === null ? void 0 : getField(expanded, key);
22595
+ if (typeof virtual === "string") return virtual;
22596
+ return virtualValueId(ownerId, memberId);
22597
+ }
22598
+ function readThroughReference(reference, ctx) {
22599
+ if (!(reference instanceof NSSlotReference)) return reference;
22600
+ if (reference.place !== null) {
22601
+ const row2 = evalValueById(
22602
+ ctx,
22603
+ reference.targetId,
22604
+ ctx.__runtimeSessionValues,
22605
+ ctx.__valueOverlay
22606
+ );
22607
+ if (row2 !== null) assertReferenceFits(reference, row2, ctx);
22608
+ assertPlaceAttached(reference, reference.place, ctx);
22609
+ return readSlot(reference.place, ctx);
22610
+ }
22611
+ const row = referencedRow(reference, ctx);
22612
+ const place = slotPlaceOfRow(row, ctx);
22613
+ return place === null ? resolveValueIfId(row.id, ctx) : readSlot(place, ctx);
22614
+ }
22615
+ function readSlot(place, ctx) {
22616
+ return place.kind === 0 /* Member */ ? readRecordKey(place.owner, place.key, place.memberId, ctx) : evalStaticMember(place.memberId, ctx);
22617
+ }
22618
+ function assertReferenceFits(reference, row, ctx) {
22619
+ const target = reference.target;
22620
+ if (target === null) return;
22621
+ const member = memberForValueRow(row, ctx);
22622
+ if (member === null) {
22623
+ throw danglingReferenceError(reference.memberId, row.id, ctx);
22624
+ }
22625
+ const declared = slotTypeInfo(member, ctx.vm);
22626
+ const stored = declared === null || typeInfoContainsGeneric2(declared) ? slotTypeInfo(member, ctx.vm, runtimeGenericEnvForValueRow(row, ctx)) : declared;
22627
+ if (stored === null) {
22628
+ throw new NSGetterRuntimeError(
22629
+ `${referenceSubject(reference.memberId, ctx)} target '${row.id}' is \`${qualifiedMemberLabel(member.id, ctx)}\`, which holds no value.`
22630
+ );
22631
+ }
22632
+ const context = {
22633
+ classes: ctx.vm.classes,
22634
+ interfaces: ctx.vm.interfaces ?? []
22635
+ };
22636
+ if (referenceTargetFits(stored, target, context)) return;
22637
+ throw new NSGetterRuntimeError(
22638
+ referenceFitError(
22639
+ referenceSubject(reference.memberId, ctx),
22640
+ row.id,
22641
+ stored,
22642
+ target,
22643
+ evaluatorTypeNames(ctx)
22644
+ )
22645
+ );
22646
+ }
22647
+ function evaluatorTypeNames(ctx) {
22648
+ const schema = evaluatorSchemaIndex(ctx);
22649
+ return {
22650
+ schemaClassName: (classId) => schema.class(classId)?.name ?? classId,
22651
+ enumName: (enumId) => schema.enum(enumId)?.name ?? enumId,
22652
+ interfaceName: (interfaceId) => ctx.vm.interfaces?.find(({ id }) => id === interfaceId)?.name ?? interfaceId
22653
+ };
21200
22654
  }
21201
22655
  function evalPointer(pointer, scope, ctx, resultUsage = "value") {
21202
22656
  try {
@@ -21291,6 +22745,13 @@ function evalPointerCore(pointer, scope, ctx, resultUsage = "value") {
21291
22745
  };
21292
22746
  case "staticMember" /* staticMember */:
21293
22747
  return evalStaticMember(pointer.memberId, ctx);
22748
+ case "rowOf" /* rowOf */:
22749
+ return evalRowOf(pointer, scope, ctx);
22750
+ case "deref" /* deref */:
22751
+ return readThroughReference(
22752
+ evalPointer(pointer.pointer, scope, ctx),
22753
+ ctx
22754
+ );
21294
22755
  case "keyOf" /* keyOf */:
21295
22756
  return evalKeyOf(pointer, scope, ctx);
21296
22757
  case "operation" /* operation */:
@@ -22307,6 +23768,9 @@ function substituteRuntimeTypeInfo(typeInfo, env, ctx) {
22307
23768
  )
22308
23769
  };
22309
23770
  }
23771
+ function lookupEntryTypeInfo(target, required) {
23772
+ return referenceCategory(target) === "slot" /* Slot */ ? { type: 29 /* Reference */, required, targetTypeInfo: target } : { ...target, required };
23773
+ }
22310
23774
  function runtimeTypeInfoForMember(rawMember, env, ctx, seen) {
22311
23775
  if (seen.has(rawMember.id)) {
22312
23776
  throw new NSGetterRuntimeError(
@@ -22393,11 +23857,14 @@ function runtimeTypeInfoForMember(rawMember, env, ctx, seen) {
22393
23857
  }
22394
23858
  if (isMemberLookup(member)) {
22395
23859
  if (member.collectionMemberId === void 0) {
22396
- const entryTypeInfo2 = {
22397
- ...substituteRuntimeTypeInfo(member.declaredTypeInfo, env, ctx),
22398
- required: isMultiSelectionMember(member) ? true : false
22399
- };
22400
- return isMultiSelectionMember(member) ? { type: 9 /* Lookup */, required, entryTypeInfo: entryTypeInfo2 } : entryTypeInfo2;
23860
+ const target = substituteRuntimeTypeInfo(
23861
+ member.declaredTypeInfo,
23862
+ env,
23863
+ ctx
23864
+ );
23865
+ const multi = isMultiSelectionMember(member);
23866
+ const entryTypeInfo2 = lookupEntryTypeInfo(target, multi || required);
23867
+ return multi ? { type: 9 /* Lookup */, required, entryTypeInfo: entryTypeInfo2 } : entryTypeInfo2;
22401
23868
  }
22402
23869
  const collection = evalMemberById(ctx.vm, member.collectionMemberId);
22403
23870
  if (collection === null) {
@@ -22416,10 +23883,10 @@ function runtimeTypeInfoForMember(rawMember, env, ctx, seen) {
22416
23883
  `Lookup binding '${member.id}' does not target a collection.`
22417
23884
  );
22418
23885
  }
22419
- const entryTypeInfo = {
22420
- ...collectionTypeInfo.entryTypeInfo,
22421
- required: isMultiSelectionMember(member) ? true : false
22422
- };
23886
+ const entryTypeInfo = lookupEntryTypeInfo(
23887
+ collectionTypeInfo.entryTypeInfo,
23888
+ isMultiSelectionMember(member) === true || required
23889
+ );
22423
23890
  return isMultiSelectionMember(member) ? {
22424
23891
  type: 9 /* Lookup */,
22425
23892
  required,
@@ -22779,6 +24246,8 @@ function runtimeTypeCheck(value, checkType, ctx, seenCollections = /* @__PURE__
22779
24246
  ctx.vm.interfaces ?? []
22780
24247
  );
22781
24248
  }
24249
+ case 29 /* Reference */:
24250
+ return value instanceof NSSlotReference || typeInfoContainsGeneric2(checkType.targetTypeInfo);
22782
24251
  case 21 /* Generic */:
22783
24252
  if (!isClassGenericParamTypeInfo(checkType)) {
22784
24253
  return runtimeTypeCheck(
@@ -22910,35 +24379,37 @@ function evalKeyOf(pointer, scope, ctx, onDestination) {
22910
24379
  return resolveCollectionEntry(receiver, receiver[idx], idx, ctx);
22911
24380
  }
22912
24381
  if (typeof receiver === "object" && receiver !== null) {
22913
- const k = String(key);
22914
- if (k === "Id") {
22915
- if (receiver === ctx.thisValue && typeof ctx.thisValueRowId === "string") {
22916
- return ctx.thisValueRowId;
22917
- }
22918
- const rowId = findKnownRowIdByValueReference(receiver, ctx);
22919
- if (rowId) return rowId;
22920
- throw new NSGetterRuntimeError("Class value has no backing row id.");
22921
- }
22922
- const assetMember = resolveAssetRuntimeMember(receiver, k, ctx);
22923
- if (assetMember.kind === "ok") return assetMember.value;
22924
- const dispatched = dispatchSchemaMember(receiver, k, ctx);
22925
- if (dispatched.kind === "ok") return dispatched.value;
22926
- if (Object.prototype.hasOwnProperty.call(receiver, k)) {
22927
- const at2 = receiver[k];
22928
- return typeof at2 === "string" && (pointer.memberId !== void 0 || isReferenceEntry(collectionReferences(receiver, ctx), k)) ? resolveValueIfId(at2, ctx) : at2;
22929
- }
22930
- const expanded = virtualExpandedRecordForReceiver(receiver, ctx);
22931
- if (expanded !== null && Object.prototype.hasOwnProperty.call(expanded, k)) {
22932
- return resolveValueIfId(expanded[k], ctx);
22933
- }
22934
- throw new NSGetterRuntimeError(
22935
- `Missing key '${k}' on object. Check that the key exists before reading it.`
22936
- );
24382
+ return readRecordKey(receiver, String(key), pointer.memberId, ctx);
22937
24383
  }
22938
24384
  throw new NSGetterRuntimeError(
22939
24385
  `Cannot index into ${typeof receiver} with key '${String(key)}'`
22940
24386
  );
22941
24387
  }
24388
+ function readRecordKey(receiver, k, memberId, ctx) {
24389
+ if (k === "Id") {
24390
+ if (receiver === ctx.thisValue && typeof ctx.thisValueRowId === "string") {
24391
+ return ctx.thisValueRowId;
24392
+ }
24393
+ const rowId = findKnownRowIdByValueReference(receiver, ctx);
24394
+ if (rowId) return rowId;
24395
+ throw new NSGetterRuntimeError("Class value has no backing row id.");
24396
+ }
24397
+ const assetMember = resolveAssetRuntimeMember(receiver, k, ctx);
24398
+ if (assetMember.kind === "ok") return assetMember.value;
24399
+ const dispatched = dispatchSchemaMember(receiver, k, ctx);
24400
+ if (dispatched.kind === "ok") return dispatched.value;
24401
+ if (Object.prototype.hasOwnProperty.call(receiver, k)) {
24402
+ const at2 = receiver[k];
24403
+ return typeof at2 === "string" && (memberId !== void 0 || isReferenceEntry(collectionReferences(receiver, ctx), k)) ? resolveValueIfId(at2, ctx) : at2;
24404
+ }
24405
+ const expanded = virtualExpandedRecordForReceiver(receiver, ctx);
24406
+ if (expanded !== null && Object.prototype.hasOwnProperty.call(expanded, k)) {
24407
+ return resolveValueIfId(expanded[k], ctx);
24408
+ }
24409
+ throw new NSGetterRuntimeError(
24410
+ `Missing key '${k}' on object. Check that the key exists before reading it.`
24411
+ );
24412
+ }
22942
24413
  function dispatchSchemaMember(receiver, schemaKey, ctx) {
22943
24414
  if (typeof receiver !== "object" || receiver === null) {
22944
24415
  return { kind: "no-info", matchedMember: false };
@@ -22981,7 +24452,7 @@ function dispatchSchemaMember(receiver, schemaKey, ctx) {
22981
24452
  case "value":
22982
24453
  return {
22983
24454
  kind: "ok",
22984
- value: resolveValueIfIdForMember(slot.value, member, ctx)
24455
+ value: resolveValueIfIdForMember(slot.value, member, ctx, receiverRow)
22985
24456
  };
22986
24457
  case "null":
22987
24458
  return { kind: "ok", value: null };
@@ -23111,8 +24582,8 @@ function readDeclarationDefault(member, ctx) {
23111
24582
  let value = member.defaultValue.value;
23112
24583
  if (isMemberString(member) && isLocalizedStringMember(member) !== false && typeof value === "string") {
23113
24584
  value = resolveLocalizedTextId(value, ctx);
23114
- } else if (shouldUnwrapSingleLookupValue(member)) {
23115
- value = unwrapSingleLookupValue(value, ctx);
24585
+ } else {
24586
+ value = readLookupSelection(member, value, null, ctx);
23116
24587
  }
23117
24588
  return { matched: true, value };
23118
24589
  }
@@ -23182,13 +24653,17 @@ function resolveValueIfId(at2, ctx) {
23182
24653
  if (member !== null && isMemberEntryCollectionBase(member) && listKindOf(member) === 1 /* Unordered */ && Array.isArray(row.value)) {
23183
24654
  return evaluatorUnorderedListEntryIds(row.id, ctx);
23184
24655
  }
23185
- const value = member === null ? resolveLocalizedRowValue(row, ctx) : resolveLocalizedRowValueForMember(row, member, ctx);
23186
- return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(value, ctx) : value;
24656
+ if (member === null) return resolveLocalizedRowValue(row, ctx);
24657
+ return readLookupSelection(
24658
+ member,
24659
+ resolveLocalizedRowValueForMember(row, member, ctx),
24660
+ row,
24661
+ ctx
24662
+ );
23187
24663
  }
23188
- function resolveValueIfIdForMember(at2, member, ctx) {
23189
- if (typeof at2 !== "string") {
23190
- return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(at2, ctx) : at2;
23191
- }
24664
+ function resolveValueIfIdForMember(at2, member, ctx, owner = null) {
24665
+ if (typeof at2 !== "string")
24666
+ return readLookupSelection(member, at2, owner, ctx);
23192
24667
  const row = evalValueById(
23193
24668
  ctx,
23194
24669
  at2,
@@ -23199,8 +24674,12 @@ function resolveValueIfIdForMember(at2, member, ctx) {
23199
24674
  if (isMemberEntryCollectionBase(member) && listKindOf(member) === 1 /* Unordered */ && Array.isArray(row.value)) {
23200
24675
  return evaluatorUnorderedListEntryIds(row.id, ctx);
23201
24676
  }
23202
- const value = resolveLocalizedRowValueForMember(row, member, ctx);
23203
- return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(value, ctx) : value;
24677
+ return readLookupSelection(
24678
+ member,
24679
+ resolveLocalizedRowValueForMember(row, member, ctx),
24680
+ row,
24681
+ ctx
24682
+ );
23204
24683
  }
23205
24684
  function createUnorderedListProjectionCache() {
23206
24685
  return {
@@ -23307,12 +24786,53 @@ function evaluatorUnorderedListEntryIds(containerValueId, ctx) {
23307
24786
  cache.containerIdByArray.set(projection, containerValueId);
23308
24787
  return projection;
23309
24788
  }
23310
- function shouldUnwrapSingleLookupValue(member) {
23311
- if (member === null) return false;
23312
- if (!isMemberLookup(member)) return false;
23313
- return isMultiSelectionMember(member) !== true;
24789
+ function readLookupSelection(member, value, row, ctx) {
24790
+ if (!isMemberLookup(member)) return value;
24791
+ const multi = isMultiSelectionMember(member) === true;
24792
+ const target = lookupTargetTypeInfo(member, row, ctx);
24793
+ if (referenceCategory(target) !== "slot" /* Slot */) {
24794
+ return multi ? value : unwrapSingleLookupValue(member, value, ctx);
24795
+ }
24796
+ if (value === null || value === void 0) return null;
24797
+ if (!Array.isArray(value)) {
24798
+ throw new NSGetterRuntimeError(
24799
+ `Lookup member '${member.name}' holds a ${typeof value}, not a list of target ids.`
24800
+ );
24801
+ }
24802
+ if (multi) return slotReferenceSet(value, target, member.id, ctx);
24803
+ const targetId = value[0];
24804
+ if (targetId === void 0) return null;
24805
+ if (typeof targetId !== "string") {
24806
+ throw new NSGetterRuntimeError(
24807
+ `Lookup member '${member.name}' holds a ${typeof targetId} target, not a value id.`
24808
+ );
24809
+ }
24810
+ return new NSSlotReference(targetId, null, target, member.id);
24811
+ }
24812
+ function lookupTargetTypeInfo(member, row, ctx) {
24813
+ const declared = member.declaredTypeInfo ?? collectionLookupTarget(member, ctx);
24814
+ if (row === null || !typeInfoContainsGeneric2(declared)) return declared;
24815
+ const env = runtimeGenericEnvForValueRow(row, ctx, /* @__PURE__ */ new Set());
24816
+ return substituteRuntimeTypeInfo(declared, env, ctx);
24817
+ }
24818
+ var UNKNOWN_LOOKUP_TARGET = {
24819
+ type: NS_TYPE_UNKNOWN,
24820
+ required: true
24821
+ };
24822
+ function isCollectionTypeInfo(typeInfo) {
24823
+ return typeInfo.type === 6 /* List */ || typeInfo.type === 28 /* Set */ || typeInfo.type === 9 /* Lookup */ || typeInfo.type === 5 /* Dictionary */;
23314
24824
  }
23315
- function unwrapSingleLookupValue(value, ctx) {
24825
+ function collectionLookupTarget(member, ctx) {
24826
+ const targets = evaluatorResolutionCache(ctx).collectionLookupTargets;
24827
+ const cached = targets.get(member);
24828
+ if (cached !== void 0) return cached;
24829
+ const stored = slotTypeInfo(member, ctx.vm);
24830
+ const reference = stored?.type === 9 /* Lookup */ ? stored.entryTypeInfo : stored;
24831
+ const target = reference?.type === 29 /* Reference */ ? reference.targetTypeInfo : UNKNOWN_LOOKUP_TARGET;
24832
+ targets.set(member, target);
24833
+ return target;
24834
+ }
24835
+ function unwrapSingleLookupValue(member, value, ctx) {
23316
24836
  if (Array.isArray(value) && value.length === 1 && typeof value[0] === "string") {
23317
24837
  const next = evalValueById(
23318
24838
  ctx,
@@ -23320,12 +24840,26 @@ function unwrapSingleLookupValue(value, ctx) {
23320
24840
  ctx.__runtimeSessionValues,
23321
24841
  ctx.__valueOverlay
23322
24842
  );
23323
- if (next) {
23324
- return readRowValue(next, ctx);
23325
- }
24843
+ if (next === null) throw danglingReferenceError(member.id, value[0], ctx);
24844
+ return readRowValue(next, ctx);
23326
24845
  }
23327
24846
  return value;
23328
24847
  }
24848
+ function danglingReferenceError(memberId, targetId, ctx) {
24849
+ return new NSGetterRuntimeError(
24850
+ `${referenceSubject(memberId, ctx)} names value '${targetId}', which no longer exists.`
24851
+ );
24852
+ }
24853
+ function referenceSubject(memberId, ctx) {
24854
+ if (memberId === null) return "A reference";
24855
+ return `Reference \`${qualifiedMemberLabel(memberId, ctx)}\``;
24856
+ }
24857
+ function qualifiedMemberLabel(memberId, ctx) {
24858
+ const member = evalMemberById(ctx.vm, memberId);
24859
+ const name = member?.name ?? memberId;
24860
+ const owner = evaluatorSchemaIndex(ctx).firstSchemaPlacement(memberId)?.ownerClass.name;
24861
+ return owner === void 0 ? name : `${owner}.${name}`;
24862
+ }
23329
24863
  function readRowValue(row, ctx) {
23330
24864
  const onInitializerRead = ctx.vm.databaseVM?.onInitializerRead;
23331
24865
  if (onInitializerRead !== void 0 && isInitValueContent(row)) {
@@ -23379,6 +24913,8 @@ function resolveMemberForValueRow(row, ctx, visited) {
23379
24913
  }
23380
24914
  const rootMatch = rootMemberForValueRow(row, ctx);
23381
24915
  if (rootMatch !== null) return rootMatch;
24916
+ const staticRoot = activeStaticBindingRoot(row.id, ctx);
24917
+ if (staticRoot !== null) return staticRoot.member;
23382
24918
  const syntheticMemberId = memberIdFromSyntheticDefaultValueId(row.id);
23383
24919
  if (syntheticMemberId !== null) {
23384
24920
  return evalMemberById(ctx.vm, syntheticMemberId);
@@ -24180,6 +25716,9 @@ function jsEqual(a, b) {
24180
25716
  if ((a === null || a === void 0) && (b === null || b === void 0)) {
24181
25717
  return true;
24182
25718
  }
25719
+ if (a instanceof NSSlotReference || b instanceof NSSlotReference) {
25720
+ return a instanceof NSSlotReference && b instanceof NSSlotReference && a.targetId === b.targetId;
25721
+ }
24183
25722
  if (a === b) return true;
24184
25723
  if (Array.isArray(a) && Array.isArray(b)) {
24185
25724
  if (a.length !== b.length) return false;
@@ -24206,9 +25745,15 @@ function jsEqual(a, b) {
24206
25745
  return false;
24207
25746
  }
24208
25747
  function referenceEqual(a, b, ctx) {
25748
+ if (a instanceof NSSlotReference || b instanceof NSSlotReference) {
25749
+ return jsEqual(readThroughReference(a, ctx), readThroughReference(b, ctx));
25750
+ }
24209
25751
  if (a === b) return true;
24210
25752
  if (a === null || a === void 0) return b === null || b === void 0;
24211
25753
  if (b === null || b === void 0) return false;
25754
+ if (typeof a === "object" && "variantId" in a && isVariantRefValue(a) && isVariantRefValue(b)) {
25755
+ return a.classId === b.classId && a.variantId === b.variantId && (a.rowValueId ?? null) === (b.rowValueId ?? null);
25756
+ }
24212
25757
  const aId = referenceIdOf(a, ctx);
24213
25758
  return aId !== null && aId === referenceIdOf(b, ctx);
24214
25759
  }
@@ -25568,6 +27113,18 @@ function applyConstructorFields(args) {
25568
27113
  overwriteConstructedLiteral(existing, value, ctx);
25569
27114
  continue;
25570
27115
  }
27116
+ const keptId = existing !== void 0 && isMemberWithEntries(member) ? existing.id : void 0;
27117
+ if (keptId !== void 0) {
27118
+ let kept = 0;
27119
+ for (const row of createdValues) {
27120
+ if (row.id === keptId || row.containerId === keptId) {
27121
+ createdById.delete(row.id);
27122
+ continue;
27123
+ }
27124
+ createdValues[kept++] = row;
27125
+ }
27126
+ createdValues.length = kept;
27127
+ }
25571
27128
  const materialized = materializeConstructorArgumentValue({
25572
27129
  member,
25573
27130
  value,
@@ -25575,7 +27132,8 @@ function applyConstructorFields(args) {
25575
27132
  ctx,
25576
27133
  createdValues,
25577
27134
  createdById,
25578
- storageKeyDeclarations
27135
+ storageKeyDeclarations,
27136
+ ...keptId === void 0 ? {} : { rowId: keptId }
25579
27137
  });
25580
27138
  rootRecord[schemaKey] = materialized.id;
25581
27139
  }
@@ -26611,9 +28169,11 @@ function encodeLookupInitializerResult(member, value, created, ctx) {
26611
28169
  }
26612
28170
  return { value: selection, classId: null };
26613
28171
  }
26614
- function encodeLookupInitializerSelection(member, value, created, ctx) {
28172
+ function encodeLookupInitializerSelection(member, value, created, ctx, target = lookupTargetTypeInfo(member, null, ctx)) {
26615
28173
  if (value === null) return null;
26616
28174
  if (value === void 0) return null;
28175
+ if (isMultiSelectionMember(member) !== true && isCollectionTypeInfo(target))
28176
+ return [lookupInitializerSelectionId(member, value, created, ctx)];
26617
28177
  if (value instanceof RuntimeSet) value = value.toArray();
26618
28178
  if (Array.isArray(value)) {
26619
28179
  if (isMultiSelectionMember(member) !== true && value.length > 1) {
@@ -26634,6 +28194,7 @@ function encodeLookupInitializerSelection(member, value, created, ctx) {
26634
28194
  }
26635
28195
  function lookupInitializerSelectionId(member, entry, created, ctx) {
26636
28196
  if (typeof entry === "string") return entry;
28197
+ if (entry instanceof NSSlotReference) return entry.targetId;
26637
28198
  if (typeof entry !== "object" || entry === null) {
26638
28199
  throw new NSGetterRuntimeError(
26639
28200
  `Lookup member '${member.name}' initializer produced a ${typeof entry} entry, which cannot name a collection row.`
@@ -28389,19 +29950,27 @@ function materializeConstructorArgumentValue(args) {
28389
29950
  for (const entry of rows) sourceEntries.push(entry.value);
28390
29951
  }
28391
29952
  const ids = [];
28392
- const referenceIndexes = args.ctx.__unorderedListProjections?.referenceEntryIndexesByArray.get(
28393
- sourceEntries
28394
- );
29953
+ const references = recordedReferenceEntries(sourceEntries, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(sourceEntries, args.ctx));
28395
29954
  for (const [index, rawEntry] of sourceEntries.entries()) {
29955
+ if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, index) && typeof rawEntry === "string" && evalValueById(
29956
+ args.ctx,
29957
+ rawEntry,
29958
+ args.ctx.__runtimeSessionValues,
29959
+ args.ctx.__valueOverlay
29960
+ ) !== null) {
29961
+ ids.push(rawEntry);
29962
+ continue;
29963
+ }
28396
29964
  const entryValue = constructorCollectionEntryValue(
28397
29965
  rawEntry,
28398
29966
  args.ctx,
28399
- isMemberClassBase(resolvedEntry) || isMemberWithEntries(resolvedEntry) || (referenceIndexes?.has(index) ?? args.collectionEntriesAreReferences ?? trackedValueId !== null)
29967
+ isMemberClassBase(resolvedEntry) || isMemberWithEntries(resolvedEntry) || isReferenceEntry(references, index)
28400
29968
  );
28401
29969
  const child = materializeConstructorArgumentValue({
28402
29970
  ...args,
28403
29971
  collectionEntriesAreReferences: void 0,
28404
29972
  collectionOwnerId: void 0,
29973
+ rowId: void 0,
28405
29974
  member: resolvedEntry,
28406
29975
  genericEnv: entryEnv,
28407
29976
  value: entryValue,
@@ -28440,16 +30009,27 @@ function materializeConstructorArgumentValue(args) {
28440
30009
  );
28441
30010
  const row = registerConstructorArgumentRow(args, {});
28442
30011
  const record4 = /* @__PURE__ */ Object.create(null);
30012
+ const references = recordedReferenceEntries(args.value, args.ctx) ?? (args.collectionEntriesAreReferences === false ? 1 /* Values */ : collectionReferences(args.value, args.ctx));
28443
30013
  for (const [key, rawEntry] of Object.entries(args.value)) {
30014
+ if (args.collectionOwnerId !== void 0 && args.collectionEntriesAreReferences !== false && isReferenceEntry(references, key) && typeof rawEntry === "string" && evalValueById(
30015
+ args.ctx,
30016
+ rawEntry,
30017
+ args.ctx.__runtimeSessionValues,
30018
+ args.ctx.__valueOverlay
30019
+ ) !== null) {
30020
+ record4[key] = rawEntry;
30021
+ continue;
30022
+ }
28444
30023
  const entry = constructorCollectionEntryValue(
28445
30024
  rawEntry,
28446
30025
  args.ctx,
28447
- isMemberClassBase(resolvedEntry) || isMemberWithEntries(resolvedEntry) || (args.collectionEntriesAreReferences ?? trackedValueId !== null)
30026
+ isMemberClassBase(resolvedEntry) || isMemberWithEntries(resolvedEntry) || isReferenceEntry(references, key)
28448
30027
  );
28449
30028
  record4[key] = materializeConstructorArgumentValue({
28450
30029
  ...args,
28451
30030
  collectionEntriesAreReferences: void 0,
28452
30031
  collectionOwnerId: void 0,
30032
+ rowId: void 0,
28453
30033
  member: resolvedEntry,
28454
30034
  genericEnv: entryEnv,
28455
30035
  value: entry,
@@ -28468,6 +30048,7 @@ function materializeConstructorArgumentValue(args) {
28468
30048
  function registerConstructorArgumentRow(args, value) {
28469
30049
  args.ctx.beforeValueAllocation?.();
28470
30050
  const row = buildNewValue(args.ctx.vm.project.id, { value });
30051
+ if (args.rowId !== void 0) row.id = args.rowId;
28471
30052
  const genericBindings = rowGenericBindings(args);
28472
30053
  if (genericBindings !== void 0) row.genericBindings = genericBindings;
28473
30054
  args.createdValues.push(row);
@@ -29033,13 +30614,18 @@ function snapshotCollectionMembership(collection, ctx) {
29033
30614
  }
29034
30615
  function forEachRawCollectionEntry(c, ctx, callback) {
29035
30616
  if (c instanceof RuntimeSet) {
30617
+ const slots = c.slotReferences;
29036
30618
  for (const [key, entry] of c.membership().entries()) {
29037
- if (callback({
30619
+ const control = slots === null ? callback({
29038
30620
  raw: entry.raw,
29039
30621
  key,
29040
30622
  valueId: entry.reference && typeof entry.raw === "string" ? entry.raw : null
29041
- }) === 1 /* Break */)
29042
- break;
30623
+ }) : callback({
30624
+ raw: slotReferenceEntry(entry.raw, slots),
30625
+ key,
30626
+ valueId: null
30627
+ });
30628
+ if (control === 1 /* Break */) break;
29043
30629
  }
29044
30630
  return true;
29045
30631
  }
@@ -29402,15 +30988,21 @@ function projectListenerEndpoint(args) {
29402
30988
  }
29403
30989
 
29404
30990
  // ../packages/models/src/members/lookup-declared-type.ts
29405
- function lookupDeclaredTypeInfo(member, collectionTypeInfo) {
29406
- const entryTypeInfo = lookupEntryTypeInfo(member, collectionTypeInfo);
29407
- if (entryTypeInfo === null) return null;
30991
+ function lookupDeclaredTypeInfo(member, collectionTypeInfo, isClassConstrained) {
30992
+ const targetTypeInfo = lookupEntryTypeInfo2(member, collectionTypeInfo);
30993
+ if (targetTypeInfo === null) return null;
29408
30994
  if (isMultiSelectionMember(member) !== true) {
29409
- return {
29410
- ...entryTypeInfo,
29411
- required: isRequiredMember(member)
29412
- };
30995
+ return referenceExpressionTypeInfo(
30996
+ targetTypeInfo,
30997
+ isRequiredMember(member),
30998
+ isClassConstrained
30999
+ );
29413
31000
  }
31001
+ const entryTypeInfo = referenceExpressionTypeInfo(
31002
+ targetTypeInfo,
31003
+ true,
31004
+ isClassConstrained
31005
+ );
29414
31006
  if (member.collectionMemberId === void 0) {
29415
31007
  return {
29416
31008
  type: 9 /* Lookup */,
@@ -29426,7 +31018,7 @@ function lookupDeclaredTypeInfo(member, collectionTypeInfo) {
29426
31018
  collectionValueId: member.collectionValueId ?? null
29427
31019
  };
29428
31020
  }
29429
- function lookupEntryTypeInfo(member, collectionTypeInfo) {
31021
+ function lookupEntryTypeInfo2(member, collectionTypeInfo) {
29430
31022
  if (member.collectionMemberId === void 0) return member.declaredTypeInfo;
29431
31023
  const collection = collectionTypeInfo(member.collectionMemberId);
29432
31024
  if (collection === null) return null;
@@ -29443,10 +31035,11 @@ function resolveMemberDeclaredTypeInfo(member, members, ownerClass = null, env)
29443
31035
  members,
29444
31036
  /* @__PURE__ */ new Set(),
29445
31037
  ownerClass,
29446
- env
31038
+ env,
31039
+ ownerClass === null ? void 0 : classConstrainedGenerics([ownerClass])
29447
31040
  );
29448
31041
  }
29449
- function resolveMemberDeclaredTypeInfoInternal(member, members, seen, ownerClass, env) {
31042
+ function resolveMemberDeclaredTypeInfoInternal(member, members, seen, ownerClass, env, isClassConstrained) {
29450
31043
  const resolved = env === void 0 ? resolveMember(member, members) : substituteMember(member, env, members);
29451
31044
  const memberId = getField(resolved, "id");
29452
31045
  if (typeof memberId === "string" && seen.has(memberId)) return null;
@@ -29473,7 +31066,8 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen, ownerClass
29473
31066
  members,
29474
31067
  nextSeen,
29475
31068
  ownerClass,
29476
- env
31069
+ env,
31070
+ isClassConstrained
29477
31071
  );
29478
31072
  return argumentType === null ? [] : [[genericParamId, argumentType]];
29479
31073
  }
@@ -29536,7 +31130,8 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen, ownerClass
29536
31130
  members,
29537
31131
  nextSeen,
29538
31132
  ownerClass,
29539
- env
31133
+ env,
31134
+ isClassConstrained
29540
31135
  );
29541
31136
  if (entryTypeInfo === null) return null;
29542
31137
  return {
@@ -29547,19 +31142,24 @@ function resolveMemberDeclaredTypeInfoInternal(member, members, seen, ownerClass
29547
31142
  };
29548
31143
  }
29549
31144
  if (isMemberLookupBase(resolved)) {
29550
- return lookupDeclaredTypeInfo(resolved, (collectionMemberId) => {
29551
- const collection = members.find(
29552
- (candidate) => candidate.id === collectionMemberId
29553
- );
29554
- if (collection === void 0) return null;
29555
- return resolveMemberDeclaredTypeInfoInternal(
29556
- collection,
29557
- members,
29558
- nextSeen,
29559
- ownerClass,
29560
- env
29561
- );
29562
- });
31145
+ return lookupDeclaredTypeInfo(
31146
+ resolved,
31147
+ (collectionMemberId) => {
31148
+ const collection = members.find(
31149
+ (candidate) => candidate.id === collectionMemberId
31150
+ );
31151
+ if (collection === void 0) return null;
31152
+ return resolveMemberDeclaredTypeInfoInternal(
31153
+ collection,
31154
+ members,
31155
+ nextSeen,
31156
+ ownerClass,
31157
+ env,
31158
+ isClassConstrained
31159
+ );
31160
+ },
31161
+ isClassConstrained
31162
+ );
29563
31163
  }
29564
31164
  if (resolved.kind === 9 /* Lookup */) return null;
29565
31165
  if (!memberKindSupportsStorage(resolved.kind)) return null;
@@ -32419,18 +34019,55 @@ function evaluateInitializerMaterialization(args) {
32419
34019
  });
32420
34020
  return { evaluated, createdValues, storageKeyDeclarations };
32421
34021
  }
34022
+ function materializeInPlaceFields(document2, root, createdValues) {
34023
+ const owners = [root, ...createdValues];
34024
+ for (const owner of owners) {
34025
+ const record4 = owner.value;
34026
+ if (typeof owner.classId !== "string") continue;
34027
+ if (typeof record4 !== "object" || record4 === null) continue;
34028
+ if (Array.isArray(record4)) continue;
34029
+ let memberIds;
34030
+ for (const [schemaKey, value] of Object.entries(record4)) {
34031
+ if (typeof value === "string" || value === null) continue;
34032
+ memberIds ??= new Map(
34033
+ resolvedClassSchema(
34034
+ owner.classId,
34035
+ document2.classes,
34036
+ document2.members
34037
+ ).surface.map((entry) => [entry.schemaKey, entry.memberId])
34038
+ );
34039
+ const memberId = memberIds.get(schemaKey);
34040
+ if (memberId === void 0) {
34041
+ throw new Error(
34042
+ `Class "${owner.classId}" holds "${schemaKey}" in place, which its schema doesn't declare.`
34043
+ );
34044
+ }
34045
+ const row = {
34046
+ id: virtualValueId(owner.id, memberId),
34047
+ projectId: owner.projectId,
34048
+ createdAt: owner.createdAt,
34049
+ updatedAt: owner.updatedAt,
34050
+ value
34051
+ };
34052
+ createdValues.push(row);
34053
+ record4[schemaKey] = row.id;
34054
+ }
34055
+ }
34056
+ }
32422
34057
  function finalizeMaterializedRoot(args) {
32423
- for (const created of args.allCreated) {
34058
+ materializeInPlaceFields(args.document, args.root, args.createdValues);
34059
+ const allCreated = [args.root, ...args.createdValues];
34060
+ for (const created of allCreated) {
32424
34061
  if (created === args.root) continue;
32425
34062
  if (created.classId === void 0) delete created.classId;
32426
34063
  }
32427
- stampCreatedValuesMapKey(args.allCreated, args.mapKey);
34064
+ stampCreatedValuesMapKey(allCreated, args.mapKey);
32428
34065
  if (args.supersededRootId !== void 0) {
32429
34066
  args.storageKeyDeclarations.delete(args.supersededRootId);
32430
34067
  }
32431
34068
  args.storageKeyDeclarations.delete(args.root.id);
32432
34069
  applyDeclaredStorageKeyOverrides({
32433
- createdValues: args.allCreated,
34070
+ createdValues: allCreated,
32434
34071
  declarationByValueId: args.storageKeyDeclarations,
32435
34072
  existingParentContextById: /* @__PURE__ */ new Map([
32436
34073
  [
@@ -32474,21 +34111,21 @@ function materializeInitializerValue(args) {
32474
34111
  ...evaluated.genericBindings === void 0 ? {} : { genericBindings: { ...evaluated.genericBindings } },
32475
34112
  ...deepClonePlainData(pickInstanceProvenance(evaluated))
32476
34113
  };
32477
- const allCreated = [root, ...createdValues];
32478
34114
  if (evaluated.provisionalRootId !== void 0) {
32479
34115
  args.document.listenerDefaultCapture?.retarget(
32480
34116
  evaluated.provisionalRootId,
32481
34117
  root.id
32482
34118
  );
32483
34119
  retargetInitializerRootValueIds(
32484
- allCreated,
34120
+ [root, ...createdValues],
32485
34121
  evaluated.provisionalRootId,
32486
34122
  root.id
32487
34123
  );
32488
34124
  }
32489
34125
  finalizeMaterializedRoot({
34126
+ document: args.document,
32490
34127
  root,
32491
- allCreated,
34128
+ createdValues,
32492
34129
  mapKey: args.row.mapKey,
32493
34130
  storageKeyDeclarations
32494
34131
  });
@@ -32603,12 +34240,12 @@ function materializeMemberDefaultValue(args) {
32603
34240
  ...built.classId === void 0 ? {} : { classId: built.classId },
32604
34241
  ...built.genericBindings == null ? {} : { genericBindings: { ...built.genericBindings } }
32605
34242
  };
32606
- const allCreated = [root, ...interior];
32607
34243
  args.document.listenerDefaultCapture?.retarget(built.id, root.id);
32608
- retargetInitializerRootValueIds(allCreated, built.id, root.id);
34244
+ retargetInitializerRootValueIds([root, ...interior], built.id, root.id);
32609
34245
  finalizeMaterializedRoot({
34246
+ document: args.document,
32610
34247
  root,
32611
- allCreated,
34248
+ createdValues: interior,
32612
34249
  mapKey: args.envelope.mapKey,
32613
34250
  storageKeyDeclarations,
32614
34251
  supersededRootId: built.id
@@ -32628,7 +34265,7 @@ function isMaterializedSpine(location) {
32628
34265
  const virtual = location.virtualRow;
32629
34266
  if (!isLiteralValueContent(stored) || !isLiteralValueContent(virtual))
32630
34267
  return false;
32631
- return stored.id === virtual.id && (stored.instanceVariantId ?? null) === (virtual.instanceVariantId ?? null) && (stored.instanceVariantRowValueId ?? null) === (virtual.instanceVariantRowValueId ?? null) && (stored.instanceAppliedVariantId ?? null) === (virtual.instanceAppliedVariantId ?? null) && (stored.instanceAppliedVariantRowValueId ?? null) === (virtual.instanceAppliedVariantRowValueId ?? null);
34268
+ return stored.id === virtual.id && (stored.instanceConstructorId ?? null) === (virtual.instanceConstructorId ?? null) && (stored.instanceVariantId ?? null) === (virtual.instanceVariantId ?? null) && (stored.instanceVariantRowValueId ?? null) === (virtual.instanceVariantRowValueId ?? null) && (stored.instanceAppliedVariantId ?? null) === (virtual.instanceAppliedVariantId ?? null) && (stored.instanceAppliedVariantRowValueId ?? null) === (virtual.instanceAppliedVariantRowValueId ?? null);
32632
34269
  }
32633
34270
  function buildVirtualInstanceMaterializedIndex(args) {
32634
34271
  const rowsById = new Map(
@@ -33321,14 +34958,21 @@ function resolveVirtualInstanceGraph(args) {
33321
34958
  };
33322
34959
  const rootLocation = resolvePath(ROOT_PATH, args.instanceRoot.id, null);
33323
34960
  const canonicalReceiver = (id) => locationsById.get(id)?.virtualRow.id ?? id;
34961
+ const replayedId = (id) => {
34962
+ const target = expansion.nodesByExpandedId.get(id);
34963
+ return target === void 0 ? id : locationsByPath.get(target.pathKey)?.id ?? target.virtualId;
34964
+ };
33324
34965
  for (const location of locationsByPath.values()) {
33325
34966
  if (location.materializedRow !== null) continue;
33326
- if (location.member.kind !== 25 /* NSDelegate */) continue;
33327
34967
  const effective = rowsById.get(location.id);
33328
- effective.value = remapMemberDelegateReceiver(effective.value, (id) => {
33329
- const target = expansion.nodesByExpandedId.get(id);
33330
- return target === void 0 ? id : locationsByPath.get(target.pathKey)?.id ?? target.virtualId;
33331
- });
34968
+ if (location.member.kind === 25 /* NSDelegate */) {
34969
+ effective.value = remapMemberDelegateReceiver(
34970
+ effective.value,
34971
+ replayedId
34972
+ );
34973
+ } else if (location.member.kind === 9 /* Lookup */) {
34974
+ effective.value = remapLookupSelection(effective.value, replayedId);
34975
+ }
33332
34976
  }
33333
34977
  let listenerDefaultsByOwner;
33334
34978
  const settled = /* @__PURE__ */ new Map();
@@ -34543,6 +36187,9 @@ function rewriteExpandedRow(node, expansion) {
34543
36187
  if (node.member.kind === 25 /* NSDelegate */) {
34544
36188
  row.value = remapMemberDelegateReceiver(row.value, rewrite);
34545
36189
  }
36190
+ if (node.member.kind === 9 /* Lookup */) {
36191
+ row.value = remapLookupSelection(row.value, rewrite);
36192
+ }
34546
36193
  if (typeof row.containerId === "string") {
34547
36194
  row.containerId = rewrite(row.containerId);
34548
36195
  }
@@ -34563,6 +36210,10 @@ function createFromRow(prior, id, value, update) {
34563
36210
  };
34564
36211
  return create;
34565
36212
  }
36213
+ function remapLookupSelection(value, remap) {
36214
+ if (!Array.isArray(value)) return value;
36215
+ return value.map((id) => typeof id === "string" ? remap(id) : id);
36216
+ }
34566
36217
  function remapMemberDelegateReceiver(value, remap) {
34567
36218
  if (!isMemberDelegateTarget(value) || value.valueId === null) return value;
34568
36219
  const valueId = remap(value.valueId);
@@ -37097,23 +38748,28 @@ function sourcePositionMapper(source) {
37097
38748
  var SYSTEM_RECORD_ID_PREFIX2 = "system_";
37098
38749
 
37099
38750
  // ../packages/neoscript-language/src/type-substitution.ts
37100
- function substituteTypeParameters(member, receiver, declaring) {
38751
+ function substituteTypeParameters(member, receiver, declaring, project) {
37101
38752
  const bindings = classTypeBindings({ type: receiver, declaring });
37102
38753
  return substituteBindings(
37103
38754
  member,
37104
- (type) => type.ownerMemberId === void 0 ? bindings.get(type.id) : void 0
38755
+ (type) => type.ownerMemberId === void 0 ? bindings.get(type.id) : void 0,
38756
+ project
37105
38757
  );
37106
38758
  }
37107
- function substituteCallTypeArguments(member, functionArguments, typeParameters, receiver) {
38759
+ function substituteCallTypeArguments(member, functionArguments, typeParameters, receiver, project) {
37108
38760
  const classBindings = receiver && classTypeBindings(receiver);
37109
38761
  const declared = typeParameters?.[0]?.type;
37110
38762
  const owner = declared?.kind === "typeParameter" ? declared.ownerMemberId : void 0;
37111
- return substituteBindings(member, (type) => {
37112
- if (type.ownerMemberId === void 0) return classBindings?.get(type.id);
37113
- if (type.ownerMemberId !== owner) return void 0;
37114
- if (type.index === void 0) return void 0;
37115
- return functionArguments[type.index];
37116
- });
38763
+ return substituteBindings(
38764
+ member,
38765
+ (type) => {
38766
+ if (type.ownerMemberId === void 0) return classBindings?.get(type.id);
38767
+ if (type.ownerMemberId !== owner) return void 0;
38768
+ if (type.index === void 0) return void 0;
38769
+ return functionArguments[type.index];
38770
+ },
38771
+ project
38772
+ );
37117
38773
  }
37118
38774
  function classTypeBindings(receiver) {
37119
38775
  const parameters = receiver.declaring.typeParameters ?? [];
@@ -37125,7 +38781,7 @@ function classTypeBindings(receiver) {
37125
38781
  });
37126
38782
  return bindings;
37127
38783
  }
37128
- function substituteBindings(member, bindingOf) {
38784
+ function substituteBindings(member, bindingOf, project) {
37129
38785
  const visit = (type) => {
37130
38786
  if (type.kind === "typeParameter") {
37131
38787
  const binding = bindingOf(type);
@@ -37155,8 +38811,19 @@ function substituteBindings(member, bindingOf) {
37155
38811
  if (type.kind === "action") {
37156
38812
  return { ...type, parameterTypes: type.parameterTypes.map(visit) };
37157
38813
  }
38814
+ if (type.kind === "reference" && containsTypeParameter(type.target)) {
38815
+ if (type.target.kind === "reference") {
38816
+ return { ...type, target: visitReferenceTarget(type.target) };
38817
+ }
38818
+ return neoScriptReferenceType(
38819
+ visit(type.target),
38820
+ type.nullable === true,
38821
+ (named) => isNeoScriptValueNamedType(named, project)
38822
+ );
38823
+ }
37158
38824
  return type;
37159
38825
  };
38826
+ const visitReferenceTarget = (type) => type.kind === "reference" ? { ...type, target: visitReferenceTarget(type.target) } : visit(type);
37160
38827
  return visit(member);
37161
38828
  }
37162
38829
  function containsTypeParameter(type) {
@@ -37174,6 +38841,8 @@ function containsTypeParameter(type) {
37174
38841
  return containsTypeParameter(type.returnType) || type.parameterTypes.some(containsTypeParameter);
37175
38842
  case "action":
37176
38843
  return type.parameterTypes.some(containsTypeParameter);
38844
+ case "reference":
38845
+ return containsTypeParameter(type.target);
37177
38846
  default:
37178
38847
  return false;
37179
38848
  }
@@ -37269,7 +38938,8 @@ function createListenerAnnotationProvider(project, context = {}) {
37269
38938
  const observedType = substituteTypeParameters(
37270
38939
  symbol.type,
37271
38940
  owner,
37272
- declaration
38941
+ declaration,
38942
+ project
37273
38943
  );
37274
38944
  if (observedType.kind === "delegate" || observedType.kind === "action")
37275
38945
  continue;
@@ -37423,6 +39093,8 @@ var UserSafeTypeCheck = class {
37423
39093
  case "list":
37424
39094
  case "set":
37425
39095
  return this.unsafeName(type.elementType);
39096
+ case "reference":
39097
+ return this.unsafeName(type.target);
37426
39098
  case "dictionary":
37427
39099
  return this.unsafeName(type.keyType) ?? this.unsafeName(type.valueType);
37428
39100
  case "delegate":
@@ -37917,6 +39589,16 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37917
39589
  );
37918
39590
  this.requireAssignable(resolved.type, expected, expression.pos, "value");
37919
39591
  }
39592
+ /** P112 §2.2. Checks a stored default's `Reference(place)` the push can't settle. */
39593
+ resolvePersistedReference(expression, expected) {
39594
+ const resolved = this.resolveExpression(
39595
+ expression,
39596
+ this.initialScope(),
39597
+ expected
39598
+ );
39599
+ if (expected === void 0) return;
39600
+ this.requireAssignable(resolved.type, expected, expression.pos, "value");
39601
+ }
37920
39602
  persistedListenerCompletions(receiver, expected) {
37921
39603
  const scope = this.initialScope();
37922
39604
  let receiverType = this.context.thisClass;
@@ -38173,7 +39855,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38173
39855
  );
38174
39856
  }
38175
39857
  const declared = statement.type ? this.resolveType(statement.type) : void 0;
38176
- const initial = this.resolveExpression(statement.init, scope, declared);
39858
+ const initial = inferred ? this.resolveReferenceExpression(statement.init, scope) : this.resolveExpression(statement.init, scope, declared);
38177
39859
  if (inferred && isNull(initial.type)) {
38178
39860
  throw new CompileError(
38179
39861
  `Cannot infer the type of '${statement.name}' from null; use an explicit nullable type.`,
@@ -39260,7 +40942,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39260
40942
  );
39261
40943
  }
39262
40944
  if (statement.target.kind === "member" && statement.target.name === NEOSCRIPT_ON_CHANGED_MEMBER) {
39263
- const observed = this.resolveExpression(statement.target.receiver, scope);
40945
+ const observed = this.resolveReferenceExpression(
40946
+ statement.target.receiver,
40947
+ scope
40948
+ );
39264
40949
  const observedType = neoScriptMemberLookupType(observed.type);
39265
40950
  const declared = observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some(
39266
40951
  (member) => member.name === NEOSCRIPT_ON_CHANGED_MEMBER
@@ -39292,14 +40977,19 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39292
40977
  statement.pos
39293
40978
  );
39294
40979
  }
39295
- const resolvedTarget = this.resolveExpression(statement.target, scope);
40980
+ const placeTarget = this.resolveReferenceExpression(
40981
+ statement.target,
40982
+ scope
40983
+ );
39296
40984
  const storageType = this.assignmentStorageType(
39297
40985
  statement.target,
39298
- resolvedTarget,
40986
+ placeTarget,
39299
40987
  local,
39300
40988
  scope
39301
40989
  );
39302
- const target = statement.op === "=" ? { ...resolvedTarget, type: storageType } : resolvedTarget;
40990
+ const reference = placeTarget.type.kind === "reference" ? this.referenceAssignment(statement, placeTarget, storageType, scope) : null;
40991
+ const resolvedTarget = reference?.target ?? placeTarget;
40992
+ const target = reference === null && statement.op === "=" ? { ...resolvedTarget, type: storageType } : resolvedTarget;
39303
40993
  const initSlot = target.initWritability !== void 0 ? {
39304
40994
  pointer: target.pointer,
39305
40995
  initWritability: target.initWritability
@@ -39376,7 +41066,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39376
41066
  );
39377
41067
  }
39378
41068
  let value;
39379
- if (statement.op === "=") {
41069
+ if (reference?.value !== void 0) {
41070
+ value = reference.value;
41071
+ } else if (statement.op === "=") {
39380
41072
  if (!statement.value) {
39381
41073
  throw new CompileError(
39382
41074
  "Assignment operator '=' requires a right-hand value.",
@@ -39394,6 +41086,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39394
41086
  );
39395
41087
  }
39396
41088
  this.requireAssignable(value.type, target.type, statement.pos, "assign");
41089
+ if (statement.op === "=" && this.holdsHandleReference(target)) {
41090
+ this.requireStoredHandle(statement.target, value, scope);
41091
+ }
39397
41092
  if (local && statement.op === "=") {
39398
41093
  scope.setOwnership(
39399
41094
  local,
@@ -39416,9 +41111,16 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39416
41111
  for (const [path, type] of retainedFacts) {
39417
41112
  scope.narrow(path, rootEntry, type);
39418
41113
  }
39419
- if (statement.op === "=" && !isNullable(value.type)) {
41114
+ if (reference !== null && reference.through > 0) {
41115
+ scope.narrow(
41116
+ assignedPath,
41117
+ rootEntry,
41118
+ nonNullLayers(storageType, reference.through)
41119
+ );
41120
+ }
41121
+ if (statement.op === "=" && !isNullable(value.type) && target.pointer.type !== "deref" /* Deref */) {
39420
41122
  scope.narrow(assignedPath, rootEntry, {
39421
- ...target.type,
41123
+ ...reference === null ? target.type : storageType,
39422
41124
  nullable: false
39423
41125
  });
39424
41126
  }
@@ -39435,6 +41137,205 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39435
41137
  pointer: value.pointer
39436
41138
  };
39437
41139
  }
41140
+ /**
41141
+ * P112 §3.2. Where `target = value` writes. The first reference layer the
41142
+ * value fits rebinds; every layer it doesn't fit is written through. A
41143
+ * generic layer that doesn't fit statically keeps the Lookup assignment,
41144
+ * and its evaluator decides at the write (§3.5). A compound operator always
41145
+ * writes through.
41146
+ */
41147
+ referenceAssignment(statement, place, storageType, scope) {
41148
+ const source = statement.op === "=" ? statement.value ?? void 0 : void 0;
41149
+ const nullLiteral = source?.kind === "litNull";
41150
+ const assigned = source === void 0 ? void 0 : this.resolveReferenceExpression(
41151
+ source,
41152
+ scope,
41153
+ nullLiteral ? void 0 : neoScriptReadType(storageType)
41154
+ );
41155
+ const valueAt = (type) => {
41156
+ if (source === void 0 || assigned === void 0) return void 0;
41157
+ return nullLiteral ? this.resolveReferenceExpression(source, scope, type) : this.readReferences(assigned, type);
41158
+ };
41159
+ let layer = assigned === void 0 ? place : { ...place, type: storageType };
41160
+ let narrowed = place.type;
41161
+ let through = 0;
41162
+ while (layer.type.kind === "reference") {
41163
+ if (assigned !== void 0) {
41164
+ const bound = narrowed.kind === "reference" ? narrowed : layer.type;
41165
+ if (isNeoScriptTypeAssignable(
41166
+ this.readReferences(assigned, bound).type,
41167
+ bound,
41168
+ this.project
41169
+ )) {
41170
+ return { target: layer, value: valueAt(layer.type), through };
41171
+ }
41172
+ if (layer.type.target.kind === "typeParameter") {
41173
+ const target2 = layer.type.target;
41174
+ return {
41175
+ target: { ...layer, type: target2 },
41176
+ value: valueAt(target2),
41177
+ through
41178
+ };
41179
+ }
41180
+ }
41181
+ if (isNullable(narrowed)) {
41182
+ throw new CompileError(
41183
+ `${this.referenceSubject(statement.target, scope)} may be null. Narrow it with a null check before writing through it.`,
41184
+ statement.pos
41185
+ );
41186
+ }
41187
+ const target = layer.type.target;
41188
+ layer = {
41189
+ pointer: { type: "deref" /* Deref */, pointer: layer.pointer },
41190
+ type: target,
41191
+ writability: "runtime" /* Runtime */
41192
+ };
41193
+ narrowed = narrowed.kind === "reference" ? narrowed.target : target;
41194
+ through += 1;
41195
+ }
41196
+ return { target: layer, value: valueAt(layer.type), through };
41197
+ }
41198
+ /** `Reference<target>` as an expression type (P112 §3.1). */
41199
+ referenceType(target, nullable2) {
41200
+ return neoScriptReferenceType(
41201
+ target,
41202
+ nullable2,
41203
+ (named) => isNeoScriptValueNamedType(named, this.project)
41204
+ );
41205
+ }
41206
+ /**
41207
+ * P112 §2.2. `Reference(place)`: the row a stored member slot is, typed by
41208
+ * the slot's stored type. A value that already is a reference, which every
41209
+ * handle is, stays as it is.
41210
+ */
41211
+ resolveRowOf(place, scope) {
41212
+ if (place.kind === "member") return this.resolveMemberRowOf(place, scope);
41213
+ if (NEW_VALUE_EXPRESSION_KINDS.has(place.kind)) {
41214
+ throw new CompileError(
41215
+ "A new value has no row yet. Store it in a member, then reference the member.",
41216
+ place.pos
41217
+ );
41218
+ }
41219
+ const value = this.resolveReferenceExpression(place, scope);
41220
+ if (value.type.kind === "reference") return value;
41221
+ const constructs = value.pointer.type === "function" /* Function */ && CONSTRUCTION_FUNCTION_KINDS.has(value.pointer.function.type);
41222
+ if (constructs) {
41223
+ throw new CompileError(
41224
+ "A new value has no row yet. Store it in a member, then reference the member.",
41225
+ place.pos
41226
+ );
41227
+ }
41228
+ const computed = value.pointer.type === "function" /* Function */;
41229
+ if (!computed && this.referenceType(value.type, false) === value.type) {
41230
+ return value;
41231
+ }
41232
+ const text = referencePlaceText(place);
41233
+ switch (place.kind) {
41234
+ case "ident":
41235
+ throw new CompileError(
41236
+ `\`${place.name}\` is a local, which has no stored row. Reference a member instead.`,
41237
+ place.pos
41238
+ );
41239
+ case "index": {
41240
+ const collection = this.resolveExpression(place.receiver, scope).type;
41241
+ const element = collection.kind === "dictionary" ? "dictionary entry" : "list element";
41242
+ throw new CompileError(
41243
+ text === null ? `A reference can't name a ${element}. Reference a member instead.` : `\`${text}\` is a ${element}, which a reference can't name. Reference a member instead.`,
41244
+ place.pos
41245
+ );
41246
+ }
41247
+ case "call":
41248
+ throw new CompileError(
41249
+ text === null ? "A call's result is computed, so it has no row to reference." : `\`${text}\` is computed, so it has no row to reference.`,
41250
+ place.pos
41251
+ );
41252
+ default:
41253
+ throw new CompileError(
41254
+ "A new value has no row yet. Store it in a member, then reference the member.",
41255
+ place.pos
41256
+ );
41257
+ }
41258
+ }
41259
+ resolveMemberRowOf(place, scope) {
41260
+ const optional2 = place.optional === true;
41261
+ if ((this.context.kind === "initializer" || this.context.kind === "initializerExpression") && this.delegateCaptureContexts.length === 0 && referencePlaceRoot(place) === "this") {
41262
+ const text = referencePlaceText(place) ?? "this";
41263
+ throw new CompileError(
41264
+ `A default runs before its instance exists, so \`${text}\` has no row to reference yet. Set the reference in a constructor instead.`,
41265
+ place.pos
41266
+ );
41267
+ }
41268
+ const slot = this.resolveMemberNatural(
41269
+ place.receiver,
41270
+ place.name,
41271
+ scope,
41272
+ place.pos,
41273
+ optional2
41274
+ );
41275
+ const member = slot.symbol;
41276
+ if (member === void 0) {
41277
+ const owner = this.resolveExpression(place.receiver, scope).type;
41278
+ const text = referencePlaceText(place);
41279
+ const subject = text === null ? `\`${place.name}\`` : `\`${text}\``;
41280
+ throw new CompileError(
41281
+ `${subject} is part of a ${this.describe({ ...owner, nullable: false })} value, which a reference can't name. Reference the whole member instead.`,
41282
+ place.pos
41283
+ );
41284
+ }
41285
+ if (member.computed === true) {
41286
+ throw new CompileError(
41287
+ `\`${this.referenceLabel(place, scope)}\` is computed, so it has no row to reference.`,
41288
+ place.pos
41289
+ );
41290
+ }
41291
+ const read = slot.optionalChainType ?? slot.type;
41292
+ const stored = member.lookup !== void 0 && member.lookup.multiselect !== true && read.kind !== "reference" ? {
41293
+ kind: "reference",
41294
+ target: { ...read, nullable: false },
41295
+ ...isNullable(read) ? { nullable: true } : {}
41296
+ } : read;
41297
+ const type = this.referenceType(stored, optional2);
41298
+ if (type.kind !== "reference") return slot;
41299
+ return {
41300
+ pointer: { type: "rowOf" /* RowOf */, place: slot.pointer },
41301
+ type
41302
+ };
41303
+ }
41304
+ /** Whether assigning `target` rebinds a reference to a handle. */
41305
+ holdsHandleReference(target) {
41306
+ if (target.type.kind === "reference") {
41307
+ return this.referenceType(target.type.target, false).kind !== "reference";
41308
+ }
41309
+ const lookup = target.symbol?.lookup;
41310
+ return lookup !== void 0 && lookup.multiselect !== true;
41311
+ }
41312
+ /** P112 §3.2. A reference never owns, so it rebinds only to a stored row. */
41313
+ requireStoredHandle(place, value, scope) {
41314
+ if (!makesNewValue(value)) return;
41315
+ const noun = handleNoun(value.type);
41316
+ throw new CompileError(
41317
+ `${this.referenceSubject(place, scope)} can't hold a new ${this.describe({ ...value.type, nullable: false })}, because a reference never owns. Assign a stored ${noun}, or change the referenced ${noun}'s ${noun === "object" ? "members" : "entries"}.`,
41318
+ place.pos
41319
+ );
41320
+ }
41321
+ /** A reference-typed place as a message's subject: "Reference `Widget.TrackedStat`". */
41322
+ referenceSubject(place, scope) {
41323
+ if (place.kind !== "member") {
41324
+ const text = referencePlaceText(place);
41325
+ return text === null ? "This reference" : `Reference \`${text}\``;
41326
+ }
41327
+ return `Reference \`${this.referenceLabel(place, scope)}\``;
41328
+ }
41329
+ /** How a member place reads in a message: `Widget.TrackedStat`. */
41330
+ referenceLabel(place, scope) {
41331
+ if (place.receiver.kind === "ident" && !this.hasValueReceiver(place.receiver.name, scope)) {
41332
+ return `${place.receiver.name}.${place.name}`;
41333
+ }
41334
+ const receiver = this.resolveExpression(place.receiver, scope);
41335
+ const owner = neoScriptMemberLookupType(receiver.type);
41336
+ const named = owner.kind === "named" ? { kind: "named", typeId: owner.typeId } : owner;
41337
+ return `${this.describe({ ...named, nullable: false })}.${place.name}`;
41338
+ }
39438
41339
  /**
39439
41340
  * The declared type of an assignment target, with any flow narrowing on the
39440
41341
  * path stripped back off. Locals carry their declaration on the scope entry;
@@ -39486,7 +41387,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39486
41387
  if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Clear" || expression.callee.receiver.kind !== "member" || expression.callee.receiver.name !== NEOSCRIPT_ON_CHANGED_MEMBER)
39487
41388
  return null;
39488
41389
  const onChanged = expression.callee.receiver;
39489
- const observed = this.resolveExpression(onChanged.receiver, scope);
41390
+ const observed = this.resolveReferenceExpression(onChanged.receiver, scope);
39490
41391
  const observedType = neoScriptMemberLookupType(observed.type);
39491
41392
  if (observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some((member) => member.name === NEOSCRIPT_ON_CHANGED_MEMBER))
39492
41393
  return null;
@@ -39582,15 +41483,16 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39582
41483
  null,
39583
41484
  scope
39584
41485
  );
41486
+ const listenedType = observed.type.kind === "reference" ? readReference(observed, observed.type).type : storageType;
39585
41487
  return this.changeListenerInstruction(
39586
41488
  edit,
39587
41489
  {
39588
41490
  owner: observed.pointer.keyOf.pointer,
39589
41491
  memberId: member.canonicalMemberId ?? observed.pointer.memberId,
39590
- typeInfo: toWireType(storageType, this.project),
41492
+ typeInfo: toWireType(listenedType, this.project),
39591
41493
  writability
39592
41494
  },
39593
- storageType,
41495
+ listenedType,
39594
41496
  scope,
39595
41497
  pos
39596
41498
  );
@@ -39933,7 +41835,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39933
41835
  type,
39934
41836
  listenerArguments,
39935
41837
  symbol.typeParameters,
39936
- receiver
41838
+ receiver,
41839
+ this.project
39937
41840
  );
39938
41841
  const signature = actionListenerSignature(symbol);
39939
41842
  if (signature === null) {
@@ -39955,7 +41858,17 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39955
41858
  }
39956
41859
  }
39957
41860
  resolveExpression(expression, scope, expected) {
39958
- const result = this.resolveReceiverExpression(expression, scope, expected);
41861
+ return this.readReferences(
41862
+ this.resolveReferenceExpression(expression, scope, expected),
41863
+ expected
41864
+ );
41865
+ }
41866
+ /**
41867
+ * P112 §3.1. {@link resolveExpression} that keeps a slot reference a
41868
+ * reference, for the positions that name a slot rather than read it.
41869
+ */
41870
+ resolveReferenceExpression(expression, scope, expected) {
41871
+ const result = this.resolveRawExpression(expression, scope, expected);
39959
41872
  if (result.dialogues !== void 0) {
39960
41873
  throw new CompileError(
39961
41874
  dialogueValueError(result.dialogues),
@@ -39966,6 +41879,38 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
39966
41879
  }
39967
41880
  /** {@link resolveExpression} that also admits a `root.Dialogues` receiver. */
39968
41881
  resolveReceiverExpression(expression, scope, expected) {
41882
+ return this.readReferences(
41883
+ this.resolveRawExpression(expression, scope, expected),
41884
+ expected
41885
+ );
41886
+ }
41887
+ /**
41888
+ * P112 §3.1. Reads a slot reference through as many layers as it takes to
41889
+ * reach `expected`: all of them unless a reference is expected.
41890
+ */
41891
+ readReferences(result, expected) {
41892
+ if (result.type.kind !== "reference") return result;
41893
+ const wantsReference = expected?.kind === "reference";
41894
+ let current = result;
41895
+ while (current.type.kind === "reference") {
41896
+ if (wantsReference && isNeoScriptTypeAssignable(current.type, expected, this.project))
41897
+ return current;
41898
+ current = readReference(current, current.type);
41899
+ }
41900
+ return wantsReference ? result : current;
41901
+ }
41902
+ /**
41903
+ * P112 §3.4. A reference read down to its first layer that may be null,
41904
+ * which is the layer a null check or `!` is about.
41905
+ */
41906
+ readToNullable(result) {
41907
+ let current = result;
41908
+ while (current.type.kind === "reference" && !isNullable(current.type)) {
41909
+ current = readReference(current, current.type);
41910
+ }
41911
+ return current;
41912
+ }
41913
+ resolveRawExpression(expression, scope, expected) {
39969
41914
  let result = this.resolveExpressionCore(expression, scope, expected);
39970
41915
  if (result.pointer.type === "function" /* Function */ || result.pointer.type === "callFunction" /* CallFunction */ || result.pointer.type === "callDelegate" /* CallDelegate */ || result.pointer.type === "callAction" /* CallAction */ || result.pointer.type === "callGetter" /* CallGetter */) {
39971
41916
  result = {
@@ -40076,6 +42021,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40076
42021
  expression.optional === true
40077
42022
  );
40078
42023
  case "call": {
42024
+ if (expression.callee.kind === "ident" && expression.callee.name === "Reference" && expression.typeArguments === void 0 && expression.argumentNames === void 0 && expression.args.length === 1 && scope.lookup("Reference") === null) {
42025
+ return this.resolveRowOf(expression.args[0], scope);
42026
+ }
40079
42027
  const receiverValue = this.callReceiver(expression.callee, scope);
40080
42028
  if (expression.callee.kind === "ident" && expression.callee.name === "Reference") {
40081
42029
  if (expression.args.length === 1 && expression.argumentNames?.[0] == null) {
@@ -40158,13 +42106,17 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40158
42106
  );
40159
42107
  }
40160
42108
  const referencedType = this.resolveType(referenceTypeArgument);
40161
- if (expected !== void 0 && !isNeoScriptTypeAssignable(referencedType, expected, this.project)) {
42109
+ if (expected !== void 0 && !isNeoScriptTypeAssignable(
42110
+ neoScriptReadType(referencedType),
42111
+ neoScriptReadType(expected),
42112
+ this.project
42113
+ )) {
40162
42114
  throw new CompileError(
40163
42115
  `Reference target ${this.describe(referencedType)} is not assignable to ${this.describe(expected)}.`,
40164
42116
  expression.pos
40165
42117
  );
40166
42118
  }
40167
- if (isPrimitive(referencedType, "ImageRef") || isPrimitive(referencedType, "AudioClipRef")) {
42119
+ if (expected?.kind !== "reference" && (isPrimitive(referencedType, "ImageRef") || isPrimitive(referencedType, "AudioClipRef"))) {
40168
42120
  if (hasProvenanceArgument) {
40169
42121
  throw new CompileError(
40170
42122
  `Reference<${referenceTypeArgument.kind === "named" ? referenceTypeArgument.name : "file"}> does not support withProvenance because a project file reference is a file id, not a value-row reference.`,
@@ -40177,14 +42129,20 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40177
42129
  this.project
40178
42130
  );
40179
42131
  }
40180
- return {
42132
+ const row = {
42133
+ type: "reference" /* Reference */,
42134
+ valueId: expression.args[0].value,
42135
+ ...expression.args[1]?.kind === "litBool" && expression.args[1].value ? { withProvenance: true } : {}
42136
+ };
42137
+ const reference = this.referenceType(referencedType, false);
42138
+ return reference.kind === "reference" ? {
40181
42139
  pointer: {
40182
- type: "reference" /* Reference */,
40183
- valueId: expression.args[0].value,
40184
- ...expression.args[1]?.kind === "litBool" && expression.args[1].value ? { withProvenance: true } : {}
42140
+ type: "rowOf" /* RowOf */,
42141
+ place: row,
42142
+ typeInfo: toWireType(referencedType, this.project)
40185
42143
  },
40186
- type: referencedType
40187
- };
42144
+ type: reference
42145
+ } : { pointer: row, type: reference };
40188
42146
  }
40189
42147
  if (expression.callee.kind === "member" && expression.callee.name === "TryConvert") {
40190
42148
  const conversion = this.resolveTileConversion(
@@ -40352,7 +42310,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40352
42310
  );
40353
42311
  }
40354
42312
  case "force": {
40355
- const operand = this.resolveExpression(expression.operand, scope);
42313
+ const operand = this.readToNullable(
42314
+ this.resolveReferenceExpression(expression.operand, scope)
42315
+ );
40356
42316
  return {
40357
42317
  pointer: {
40358
42318
  type: "forceUnwrap" /* ForceUnwrap */,
@@ -40679,14 +42639,16 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40679
42639
  symbol.returnType ?? symbol.type,
40680
42640
  methodGroupArguments,
40681
42641
  symbol.typeParameters,
40682
- bound
42642
+ bound,
42643
+ this.project
40683
42644
  );
40684
42645
  const parameterTypes = (symbol.parameters ?? []).map(
40685
42646
  (parameter3) => substituteCallTypeArguments(
40686
42647
  parameter3.type,
40687
42648
  methodGroupArguments,
40688
42649
  symbol.typeParameters,
40689
- bound
42650
+ bound,
42651
+ this.project
40690
42652
  )
40691
42653
  );
40692
42654
  const expectedVoid = isVoid(expected.returnType);
@@ -40755,14 +42717,16 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40755
42717
  symbol.returnType ?? symbol.type,
40756
42718
  mockArguments,
40757
42719
  symbol.typeParameters,
40758
- receiver
42720
+ receiver,
42721
+ this.project
40759
42722
  );
40760
42723
  const parameterTypes = (symbol.parameters ?? []).map(
40761
42724
  (parameter3) => substituteCallTypeArguments(
40762
42725
  parameter3.type,
40763
42726
  mockArguments,
40764
42727
  symbol.typeParameters,
40765
- receiver
42728
+ receiver,
42729
+ this.project
40766
42730
  )
40767
42731
  );
40768
42732
  return { kind: "delegate", returnType, parameterTypes };
@@ -41157,10 +43121,17 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41157
43121
  applyFactsToScope(targetScope, facts, mode = "all") {
41158
43122
  for (const fact of facts) {
41159
43123
  if (mode === "bindings-only" && !fact.bindingName) continue;
41160
- const natural = this.resolveExpression(fact.expression, targetScope);
43124
+ const place = this.resolveReferenceExpression(
43125
+ fact.expression,
43126
+ targetScope
43127
+ );
43128
+ const natural = this.readReferences(place, void 0);
41161
43129
  const rootEntry = fact.path === null ? null : targetScope.lookup(pathRoot(fact.path));
41162
43130
  if (fact.nullValue) {
41163
43131
  if (fact.path === null || rootEntry === null) continue;
43132
+ if (place.type.kind === "reference" && !isNullable(place.type)) {
43133
+ continue;
43134
+ }
41164
43135
  if (fact.loose === true && natural.type.kind === "primitive" && (natural.type.name === "string" || natural.type.name === "int" || natural.type.name === "float" || natural.type.name === "bool")) {
41165
43136
  continue;
41166
43137
  }
@@ -41177,7 +43148,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41177
43148
  const naturalDefinition = natural.type.kind === "named" ? this.project.typeById.get(natural.type.typeId) : void 0;
41178
43149
  const retainConcreteClass = !fact.bindingName && naturalDefinition?.kind === "class" && targetDefinition?.kind === "interface";
41179
43150
  const narrowed = retainConcreteClass ? { ...natural.type, nullable: false } : { ...target, nullable: false };
41180
- if (mode === "all" && fact.path !== null && rootEntry !== null) {
43151
+ if (mode === "all" && fact.path !== null && rootEntry !== null && place.type.kind !== "reference") {
41181
43152
  targetScope.narrow(fact.path, rootEntry, narrowed);
41182
43153
  }
41183
43154
  if (fact.bindingName) {
@@ -41199,11 +43170,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41199
43170
  continue;
41200
43171
  }
41201
43172
  if (fact.path === null || rootEntry === null) continue;
41202
- if (!isNullable(natural.type)) continue;
41203
- targetScope.narrow(fact.path, rootEntry, {
41204
- ...natural.type,
41205
- nullable: false
41206
- });
43173
+ const nonNull = withoutFirstNull(place.type);
43174
+ if (nonNull === null) continue;
43175
+ targetScope.narrow(fact.path, rootEntry, nonNull);
41207
43176
  }
41208
43177
  }
41209
43178
  /**
@@ -41566,7 +43535,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41566
43535
  type: receiver2.expression.type.kind === "named" ? substituteTypeParameters(
41567
43536
  symbol.type,
41568
43537
  receiver2.expression.type,
41569
- owner
43538
+ owner,
43539
+ this.project
41570
43540
  ) : symbol.type,
41571
43541
  writability: "readOnly" /* ReadOnly */,
41572
43542
  symbol
@@ -41817,7 +43787,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41817
43787
  const memberType2 = substituteTypeParameters(
41818
43788
  member.type,
41819
43789
  memberReceiverType,
41820
- type
43790
+ type,
43791
+ this.project
41821
43792
  );
41822
43793
  if (member.computed === true) {
41823
43794
  return {
@@ -41884,7 +43855,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41884
43855
  return substituteTypeParameters(
41885
43856
  key?.type ?? index.keyType,
41886
43857
  entry,
41887
- declaring
43858
+ declaring,
43859
+ this.project
41888
43860
  );
41889
43861
  }
41890
43862
  /** The indexes declared on a schema-backed List or Set, keyed by its member. */
@@ -43130,7 +45102,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
43130
45102
  closedConstructorParameters(
43131
45103
  signature.parameters,
43132
45104
  this.constructorTargetType(schemaClass2, expression, expected),
43133
- schemaClass2
45105
+ schemaClass2,
45106
+ this.project
43134
45107
  ),
43135
45108
  expression.args.length
43136
45109
  ).map((name) => name.toLowerCase())
@@ -43181,7 +45154,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
43181
45154
  const parameters = closedConstructorParameters(
43182
45155
  signature.parameters,
43183
45156
  targetType,
43184
- schemaClass2
45157
+ schemaClass2,
45158
+ this.project
43185
45159
  );
43186
45160
  const argumentsList2 = expression.args;
43187
45161
  if (expression.argumentNames !== void 0) {
@@ -43342,7 +45316,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
43342
45316
  type: substituteTypeParameters(
43343
45317
  parameter3.type,
43344
45318
  targetType,
43345
- schemaClass2
45319
+ schemaClass2,
45320
+ this.project
43346
45321
  )
43347
45322
  }))
43348
45323
  })
@@ -43568,7 +45543,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
43568
45543
  const memberType2 = substituteTypeParameters(
43569
45544
  member.type,
43570
45545
  targetType,
43571
- schemaClass2
45546
+ schemaClass2,
45547
+ this.project
43572
45548
  );
43573
45549
  if (memberType2.kind === "action") {
43574
45550
  return {
@@ -44004,7 +45980,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
44004
45980
  );
44005
45981
  }
44006
45982
  const args = argumentsList2.map((argument2, index) => {
44007
- let expected = requiredAt(parameters, index).type;
45983
+ const parameter3 = requiredAt(parameters, index);
45984
+ let expected = parameter3.type;
44008
45985
  if ((symbol.id === NEO_TEST_IDS.mockReturns || symbol.id === NEO_TEST_IDS.mockReturnsOnce) && receiver?.kind === "instance") {
44009
45986
  const delegate = this.delegateTypeFromMockHandle(
44010
45987
  receiver.expression.type
@@ -44018,6 +45995,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
44018
45995
  }
44019
45996
  const resolved = isUnknown(expected) ? this.resolveExpression(argument2, scope) : this.resolveExpression(argument2, scope, expected);
44020
45997
  if (!isUnknown(expected)) {
45998
+ this.requireReferenceArgument(
45999
+ resolved.type,
46000
+ expected,
46001
+ parameter3.name,
46002
+ argument2.pos
46003
+ );
44021
46004
  this.requireAssignable(
44022
46005
  resolved.type,
44023
46006
  expected,
@@ -44045,14 +46028,15 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
44045
46028
  const functionArguments = this.resolveFunctionTypeArguments(
44046
46029
  symbol,
44047
46030
  typeArguments,
44048
- (type) => substituteCallTypeArguments(type, [], void 0, bound),
46031
+ (type) => substituteCallTypeArguments(type, [], void 0, bound, this.project),
44049
46032
  pos
44050
46033
  );
44051
46034
  const bind = (type) => substituteCallTypeArguments(
44052
46035
  type,
44053
46036
  functionArguments,
44054
46037
  symbol.typeParameters,
44055
- bound
46038
+ bound,
46039
+ this.project
44056
46040
  );
44057
46041
  return {
44058
46042
  parameters: (symbol.parameters ?? []).map((parameter3) => ({
@@ -45572,6 +47556,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45572
47556
  scope,
45573
47557
  preResolvedRight.type
45574
47558
  );
47559
+ } else if (expression.right.kind === "litNull" && (expression.op === "==" || expression.op === "!=")) {
47560
+ left = this.readToNullable(
47561
+ this.resolveReferenceExpression(expression.left, scope)
47562
+ );
45575
47563
  } else {
45576
47564
  left = this.resolveExpression(expression.left, scope);
45577
47565
  }
@@ -45583,7 +47571,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45583
47571
  expression.op === "&&" ? this.conditionFacts(expression.left, scope, true) : this.conditionFacts(expression.left, scope, false)
45584
47572
  );
45585
47573
  }
45586
- const right = preResolvedRight ?? this.resolveExpression(expression.right, rightScope, left.type);
47574
+ const right = preResolvedRight ?? (expression.left.kind === "litNull" && (expression.op === "==" || expression.op === "!=") ? this.readToNullable(
47575
+ this.resolveReferenceExpression(expression.right, rightScope)
47576
+ ) : this.resolveExpression(expression.right, rightScope, left.type));
45587
47577
  if (expression.op === "==" || expression.op === "!=" || expression.op === "<" || expression.op === ">" || expression.op === "<=" || expression.op === ">=") {
45588
47578
  return this.booleanComparison(expression.op, left, right, expression.pos);
45589
47579
  }
@@ -45677,6 +47667,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45677
47667
  );
45678
47668
  }
45679
47669
  const kind = comparisonOperator(operator);
47670
+ const deferred = equality && (isGenericRead(left) || isGenericRead(right));
45680
47671
  return {
45681
47672
  pointer: {
45682
47673
  type: "operation" /* Operation */,
@@ -45685,10 +47676,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45685
47676
  expression: {
45686
47677
  condition: {
45687
47678
  type: kind,
45688
- operand1: left.pointer,
45689
- operand2: right.pointer,
47679
+ operand1: deferred ? unreadGeneric(left) : left.pointer,
47680
+ operand2: deferred ? unreadGeneric(right) : right.pointer,
45690
47681
  ...isPrimitive(left.type, "decimal") || isPrimitive(right.type, "decimal") ? { decimal: true } : {},
45691
- ...equality && (hasReferenceEquality(left.type, this.project) || hasReferenceEquality(right.type, this.project)) ? { reference: true } : {}
47682
+ ...deferred || equality && (hasReferenceEquality(left.type, this.project) || hasReferenceEquality(right.type, this.project)) ? { reference: true } : {}
45692
47683
  }
45693
47684
  }
45694
47685
  }
@@ -45913,6 +47904,19 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45913
47904
  pos
45914
47905
  );
45915
47906
  }
47907
+ /** P112 §3.1. A value never converts to a reference, since it has no row. */
47908
+ requireReferenceArgument(source, target, parameter3, pos) {
47909
+ if (target.kind !== "reference") return;
47910
+ if (source.kind === "reference") return;
47911
+ const read = neoScriptReadType(target);
47912
+ if (!isNeoScriptTypeAssignable(source, read, this.project)) return;
47913
+ const value = this.describe(source);
47914
+ const article = /^[aeiou]/i.test(value) ? "an" : "a";
47915
+ throw new CompileError(
47916
+ `Argument \`${parameter3}\` needs a ${this.describe(target)}, not ${article} ${value}. Wrap a member path in Reference() to pass a stored ${this.describe(read)}.`,
47917
+ pos
47918
+ );
47919
+ }
45916
47920
  requireCollectionOperationAssignable(source, target, receiver, collection, pos, usage) {
45917
47921
  if (isLookupSelectionCollection(receiver, collection) && isNeoScriptTypeAssignable(source, collection.valueType, this.project)) {
45918
47922
  return;
@@ -45997,6 +48001,141 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
45997
48001
  return result;
45998
48002
  }
45999
48003
  };
48004
+ function isGenericRead(expression) {
48005
+ return expression.pointer.type === "deref" /* Deref */ && expression.type.kind === "typeParameter";
48006
+ }
48007
+ function unreadGeneric(expression) {
48008
+ return isGenericRead(expression) && expression.pointer.type === "deref" /* Deref */ ? expression.pointer.pointer : expression.pointer;
48009
+ }
48010
+ function readReference(reference, type) {
48011
+ return {
48012
+ pointer: { type: "deref" /* Deref */, pointer: reference.pointer },
48013
+ type: type.nullable === true ? { ...type.target, nullable: true } : type.target,
48014
+ // §3.6. The target row decides each write through the reference.
48015
+ writability: "runtime" /* Runtime */
48016
+ };
48017
+ }
48018
+ function nonNullLayers(type, count) {
48019
+ if (count === 0 || type.kind !== "reference") return type;
48020
+ return {
48021
+ ...type,
48022
+ nullable: false,
48023
+ target: nonNullLayers(type.target, count - 1)
48024
+ };
48025
+ }
48026
+ function withoutFirstNull(type) {
48027
+ if (isNullable(type)) return { ...type, nullable: false };
48028
+ if (type.kind !== "reference") return null;
48029
+ const target = withoutFirstNull(type.target);
48030
+ return target === null ? null : { ...type, target };
48031
+ }
48032
+ function makesNewValue(value) {
48033
+ switch (value.pointer.type) {
48034
+ case "listLiteral" /* ListLiteral */:
48035
+ case "dictLiteral" /* DictLiteral */:
48036
+ case "objectInitializer" /* ObjectInitializer */:
48037
+ return true;
48038
+ case "function" /* Function */:
48039
+ return CONSTRUCTION_FUNCTION_KINDS.has(value.pointer.function.type) || COLLECTION_FUNCTION_KINDS.has(value.pointer.function.type);
48040
+ default:
48041
+ return false;
48042
+ }
48043
+ }
48044
+ function handleNoun(type) {
48045
+ switch (type.kind) {
48046
+ case "list":
48047
+ return "list";
48048
+ case "set":
48049
+ return "set";
48050
+ case "dictionary":
48051
+ return "dictionary";
48052
+ default:
48053
+ return "object";
48054
+ }
48055
+ }
48056
+ var NEW_VALUE_EXPRESSION_KINDS = /* @__PURE__ */ new Set([
48057
+ "litNull",
48058
+ "litBool",
48059
+ "litInt",
48060
+ "litFloat",
48061
+ "litString",
48062
+ "litInterp",
48063
+ "litTripleString",
48064
+ "contextualEnum",
48065
+ "litList",
48066
+ "litDict",
48067
+ "new",
48068
+ "lambda"
48069
+ ]);
48070
+ var CONSTRUCTION_FUNCTION_KINDS = /* @__PURE__ */ new Set(
48071
+ [
48072
+ "classConstructor" /* ClassConstructor */,
48073
+ "declaredConstructor" /* DeclaredConstructor */,
48074
+ "classClone" /* ClassClone */,
48075
+ "variantInitialize" /* VariantInitialize */
48076
+ ]
48077
+ );
48078
+ var COLLECTION_FUNCTION_KINDS = /* @__PURE__ */ new Set([
48079
+ "collectionQuery" /* CollectionQuery */,
48080
+ "select" /* Select */,
48081
+ "where" /* Where */,
48082
+ "listRepeat" /* ListRepeat */
48083
+ ]);
48084
+ function referencePlaceRoot(expression) {
48085
+ switch (expression.kind) {
48086
+ case "ident":
48087
+ return expression.name;
48088
+ case "member":
48089
+ case "index":
48090
+ return referencePlaceRoot(expression.receiver);
48091
+ case "force":
48092
+ return referencePlaceRoot(expression.operand);
48093
+ default:
48094
+ return null;
48095
+ }
48096
+ }
48097
+ function referencePlaceText(expression) {
48098
+ switch (expression.kind) {
48099
+ case "ident":
48100
+ return expression.name;
48101
+ case "litInt":
48102
+ return expression.raw;
48103
+ case "litString":
48104
+ return JSON.stringify(expression.value);
48105
+ case "litBool":
48106
+ return String(expression.value);
48107
+ case "member": {
48108
+ const receiver = referencePlaceText(expression.receiver);
48109
+ if (receiver === null) return null;
48110
+ return `${receiver}${expression.optional ? "?." : "."}${expression.name}`;
48111
+ }
48112
+ case "index": {
48113
+ const receiver = referencePlaceText(expression.receiver);
48114
+ const key = referencePlaceText(expression.index);
48115
+ if (receiver === null || key === null) return null;
48116
+ return `${receiver}[${key}]`;
48117
+ }
48118
+ case "force": {
48119
+ const operand = referencePlaceText(expression.operand);
48120
+ return operand === null ? null : `${operand}!`;
48121
+ }
48122
+ case "call": {
48123
+ if (expression.typeArguments !== void 0) return null;
48124
+ const callee = referencePlaceText(expression.callee);
48125
+ if (callee === null) return null;
48126
+ const args = [];
48127
+ for (const [index, argument2] of expression.args.entries()) {
48128
+ const text = referencePlaceText(argument2);
48129
+ if (text === null) return null;
48130
+ const name = expression.argumentNames?.[index];
48131
+ args.push(typeof name === "string" ? `${name}: ${text}` : text);
48132
+ }
48133
+ return `${callee}(${args.join(", ")})`;
48134
+ }
48135
+ default:
48136
+ return null;
48137
+ }
48138
+ }
46000
48139
  function canonicalPath(expression) {
46001
48140
  if (expression.kind === "ident") return expression.name;
46002
48141
  if (expression.kind !== "member") return null;
@@ -46235,12 +48374,13 @@ function variable(id, type, pointer, project) {
46235
48374
  function isGeneratedPositionalCall(target, expression) {
46236
48375
  return neoScriptRequiredConstructor(target) === null && target.constructorSignature !== void 0 && expression.argumentNames === void 0 && callHasPositionalArguments(expression);
46237
48376
  }
46238
- function closedConstructorParameters(parameters, targetType, schemaClass2) {
48377
+ function closedConstructorParameters(parameters, targetType, schemaClass2, project) {
46239
48378
  return parameters.map((parameter3) => {
46240
48379
  const valueType = substituteTypeParameters(
46241
48380
  parameter3.valueType,
46242
48381
  targetType,
46243
- schemaClass2
48382
+ schemaClass2,
48383
+ project
46244
48384
  );
46245
48385
  return {
46246
48386
  ...parameter3,
@@ -46248,7 +48388,8 @@ function closedConstructorParameters(parameters, targetType, schemaClass2) {
46248
48388
  parameterType: substituteTypeParameters(
46249
48389
  parameter3.parameterType,
46250
48390
  targetType,
46251
- schemaClass2
48391
+ schemaClass2,
48392
+ project
46252
48393
  ),
46253
48394
  required: parameter3.required && valueType.nullable !== true
46254
48395
  };
@@ -46916,6 +49057,12 @@ function toWireType(type, project) {
46916
49057
  ownerClassId: type.ownerClassId ?? findGenericParameterOwner(type.id, project) ?? "",
46917
49058
  genericParamId: type.id
46918
49059
  };
49060
+ case "reference":
49061
+ return {
49062
+ type: 29 /* Reference */,
49063
+ required,
49064
+ targetTypeInfo: toWireType(type.target, project)
49065
+ };
46919
49066
  case "delegate":
46920
49067
  return {
46921
49068
  type: 25 /* Delegate */,
@@ -47012,6 +49159,13 @@ function fromWireType(type) {
47012
49159
  parameterTypes: type.argumentTypes.map(fromWireType)
47013
49160
  };
47014
49161
  }
49162
+ if (type.type === 29 /* Reference */) {
49163
+ return {
49164
+ kind: "reference",
49165
+ target: fromWireType(type.targetTypeInfo),
49166
+ nullable: nullable2
49167
+ };
49168
+ }
47015
49169
  return { kind: "primitive", name: valueKindPrimitive(type.type), nullable: nullable2 };
47016
49170
  }
47017
49171
  function findGenericParameterOwner(parameterId, project) {
@@ -47254,7 +49408,7 @@ function collectionOperationValueType(expression, collection) {
47254
49408
  return collection.valueType;
47255
49409
  }
47256
49410
  function isLookupSelectionCollection(expression, collection) {
47257
- return collection.kind === "set" && expression.wireType?.type === 9 /* Lookup */;
49411
+ return collection.kind === "set" && collection.valueType.kind !== "reference" && expression.wireType?.type === 9 /* Lookup */;
47258
49412
  }
47259
49413
  function assignableFieldList(owner) {
47260
49414
  if (!isNeoScriptStructuredLeafTypeName(owner)) return "a stored field";
@@ -47621,6 +49775,24 @@ function resolveNeoScriptType(type, context, project) {
47621
49775
  resolved = registryReference;
47622
49776
  break;
47623
49777
  }
49778
+ if (type.name === "Reference") {
49779
+ const [targetType] = (type.typeArguments ?? []).map(
49780
+ (argument2) => resolveStoredReferenceTarget(argument2, context, project)
49781
+ );
49782
+ if (written !== 1 || targetType === void 0)
49783
+ throw new CompileError(
49784
+ typeArgumentArityMessage(type.name, 1, written),
49785
+ type.pos
49786
+ );
49787
+ const ineligible = neoScriptReferenceTargetError(targetType, project);
49788
+ if (ineligible !== null) throw new CompileError(ineligible, type.pos);
49789
+ resolved = neoScriptReferenceType(
49790
+ targetType,
49791
+ false,
49792
+ (named2) => isNeoScriptValueNamedType(named2, project)
49793
+ );
49794
+ break;
49795
+ }
47624
49796
  if (type.name === "NeoDelegate") {
47625
49797
  if (written > NEOSCRIPT_DELEGATE_MAX_PARAMETERS + 1)
47626
49798
  throw new CompileError(delegateArityMessage(written), type.pos);
@@ -47660,12 +49832,15 @@ function resolveNeoScriptType(type, context, project) {
47660
49832
  elementType: resolveNeoScriptType(type.element, context, project)
47661
49833
  };
47662
49834
  break;
47663
- case "set":
49835
+ case "set": {
49836
+ const element = resolveNeoScriptType(type.element, context, project);
47664
49837
  resolved = {
47665
49838
  kind: "set",
47666
- elementType: resolveNeoScriptType(type.element, context, project)
49839
+ // P105 §2.2. Multiselect dialogue elements are bare dialogue ids.
49840
+ elementType: isPrimitive(element, "NeoDialogueReference") ? { kind: "primitive", name: "string" } : element
47667
49841
  };
47668
49842
  break;
49843
+ }
47669
49844
  case "dict": {
47670
49845
  const key = resolveNeoScriptType(type.key, context, project);
47671
49846
  if (!isPrimitive(key, "string") && !isNamedEnum(key, project)) {
@@ -47684,6 +49859,14 @@ function resolveNeoScriptType(type, context, project) {
47684
49859
  }
47685
49860
  return { ...resolved, nullable: !type.required };
47686
49861
  }
49862
+ function resolveStoredReferenceTarget(type, context, project) {
49863
+ const inner = type.kind === "named" && type.name === "Reference" && type.typeArguments?.length === 1 ? type.typeArguments[0] : void 0;
49864
+ if (inner === void 0) return resolveNeoScriptType(type, context, project);
49865
+ const target = resolveStoredReferenceTarget(inner, context, project);
49866
+ const ineligible = neoScriptReferenceTargetError(target, project);
49867
+ if (ineligible !== null) throw new CompileError(ineligible, type.pos);
49868
+ return { kind: "reference", target, nullable: !type.required };
49869
+ }
47687
49870
  function methodGroupTypeArguments(symbol, mockTarget, pos) {
47688
49871
  return (symbol.typeParameters ?? []).map((parameter3) => {
47689
49872
  const declared = parameter3.type;
@@ -47723,7 +49906,12 @@ function assertTypeArgumentConstraints(declaring, type, pos, project) {
47723
49906
  const argument2 = type.typeArguments?.[index];
47724
49907
  const constraint = parameter3.type.kind === "typeParameter" ? parameter3.type.constraint : void 0;
47725
49908
  if (argument2 === void 0 || constraint === void 0) return;
47726
- const expected = substituteTypeParameters(constraint, type, declaring);
49909
+ const expected = substituteTypeParameters(
49910
+ constraint,
49911
+ type,
49912
+ declaring,
49913
+ project
49914
+ );
47727
49915
  if (isNeoScriptTypeAssignable(argument2, expected, project)) return;
47728
49916
  throw new CompileError(
47729
49917
  `Type argument '${formatType(argument2, project)}' does not satisfy '${parameter3.name} extends ${formatType(expected, project)}' on '${declaring.name}'.`,
@@ -49001,9 +51189,16 @@ function memberType(member, environment, visiting, field) {
49001
51189
  const collection = collectionMemberId === null ? void 0 : environment.members.get(collectionMemberId);
49002
51190
  const collectionType = collection ? memberType(collection, environment, next, `${field}.collection`) : unknownType();
49003
51191
  const declared = optionalRecord(member.declaredType);
49004
- const declaredType = declared ? manifestType(declared, environment, `${field}.declaredType`) : null;
51192
+ const declaredType = declared ? manifestStoredType(declared, environment, `${field}.declaredType`) : null;
49005
51193
  const entryType = declaredType && !isUnknownType2(declaredType) ? declaredType : collectionElementType(collectionType) ?? unknownType();
49006
- return member.multiselect === true ? { kind: "set", elementType: entryType, nullable: nullable2 } : { ...entryType, nullable: nullable2 };
51194
+ if (isUnknownType2(entryType)) {
51195
+ return member.multiselect === true ? { kind: "set", elementType: entryType, nullable: nullable2 } : { ...entryType, nullable: nullable2 };
51196
+ }
51197
+ return member.multiselect === true ? {
51198
+ kind: "set",
51199
+ elementType: manifestReferenceType(entryType, false, environment),
51200
+ nullable: nullable2
51201
+ } : manifestReferenceType(entryType, nullable2, environment);
49007
51202
  }
49008
51203
  if (kind === "dialogueLookup") {
49009
51204
  return member.multiselect === true ? { kind: "set", elementType: primitive("string", false), nullable: nullable2 } : { ...primitive("NeoDialogueReference", false), nullable: nullable2 };
@@ -49071,10 +51266,39 @@ function manifestReturnType(value, environment, field) {
49071
51266
  const type = record2(value, field);
49072
51267
  return type.kind === "void" ? primitive("void", false) : manifestType(type, environment, field);
49073
51268
  }
51269
+ function isManifestValueType(typeId, environment) {
51270
+ if (environment.enums.has(typeId)) return true;
51271
+ const name = environment.classes.get(typeId)?.name;
51272
+ return typeof name === "string" && isNeoVariantTypeName(name);
51273
+ }
51274
+ function manifestReferenceType(target, nullable2, environment) {
51275
+ return neoScriptReferenceType(
51276
+ target,
51277
+ nullable2,
51278
+ (named) => isManifestValueType(named.typeId, environment)
51279
+ );
51280
+ }
51281
+ function manifestStoredType(value, environment, field) {
51282
+ const type = record2(value, field);
51283
+ if (type.kind !== "reference") return manifestType(type, environment, field);
51284
+ const nullable2 = boolean(type.nullable, `${field}.nullable`);
51285
+ return {
51286
+ kind: "reference",
51287
+ target: manifestStoredType(type.target, environment, `${field}.target`),
51288
+ ...nullable2 ? { nullable: nullable2 } : {}
51289
+ };
51290
+ }
49074
51291
  function manifestType(value, environment, field) {
49075
51292
  const type = record2(value, field);
49076
51293
  const kind = string(type.kind, `${field}.kind`);
49077
51294
  const nullable2 = boolean(type.nullable, `${field}.nullable`);
51295
+ if (kind === "reference") {
51296
+ return manifestReferenceType(
51297
+ manifestStoredType(type.target, environment, `${field}.target`),
51298
+ nullable2,
51299
+ environment
51300
+ );
51301
+ }
49078
51302
  const primitiveName = manifestPrimitive(kind);
49079
51303
  if (primitiveName) return primitive(primitiveName, nullable2);
49080
51304
  if (kind === "unknown") return { ...unknownType(), nullable: nullable2 };
@@ -49777,35 +52001,6 @@ function getInterfaceMemberKeyOrder(neoInterface) {
49777
52001
  return result;
49778
52002
  }
49779
52003
 
49780
- // ../packages/models/src/variants/variant-member.ts
49781
- function neoVariantSystemClass(classes, lookup = false) {
49782
- const declared = classes.find(
49783
- (item) => item.system?.worldKind === (lookup ? NeoWorldSystemClassKind.LookupVariant : NeoWorldSystemClassKind.Variant)
49784
- );
49785
- if (declared === void 0) {
49786
- throw new Error(
49787
- `Canonical ${lookup ? "NeoLookupVariant" : "NeoVariant"} system class is missing.`
49788
- );
49789
- }
49790
- const targetParamId = declared.genericParams?.[0]?.id;
49791
- if (targetParamId === void 0) {
49792
- throw new Error(
49793
- `Canonical ${lookup ? "NeoLookupVariant" : "NeoVariant"} system class "${declared.id}" is missing its target generic parameter.`
49794
- );
49795
- }
49796
- const valueParamId = declared.genericParams?.[1]?.id;
49797
- if (lookup && valueParamId === void 0) {
49798
- throw new Error(
49799
- `Canonical NeoLookupVariant system class "${declared.id}" is missing its value generic parameter.`
49800
- );
49801
- }
49802
- return {
49803
- classId: declared.id,
49804
- targetParamId,
49805
- ...valueParamId === void 0 ? {} : { valueParamId }
49806
- };
49807
- }
49808
-
49809
52004
  // ../src/database/neoscript/project-file-registry.ts
49810
52005
  var PROJECT_FILE_REGISTRIES = [
49811
52006
  {
@@ -51046,11 +53241,16 @@ function memberRuntimeType(record4, context, seen = /* @__PURE__ */ new Set(), g
51046
53241
  genericEnvironment
51047
53242
  ));
51048
53243
  if (!entry) return UNKNOWN_TYPE;
51049
- return isMultiSelectionMember(member) ? {
51050
- kind: "set",
51051
- elementType: requiredType(entry),
51052
- nullable: !required
51053
- } : { ...entry, nullable: !required };
53244
+ if (isMultiSelectionMember(member)) {
53245
+ const element = analyzerReferenceType(entry, false, context);
53246
+ return {
53247
+ kind: "set",
53248
+ elementType: element.kind === "reference" ? element : requiredType(entry),
53249
+ nullable: !required
53250
+ };
53251
+ }
53252
+ const reference = analyzerReferenceType(entry, !required, context);
53253
+ return reference.kind === "reference" ? reference : { ...entry, nullable: !required };
51054
53254
  }
51055
53255
  case 10 /* NSProperty */:
51056
53256
  if (isMemberNSPropertyBase(member) || isMemberNSPropertyContractBase(member)) {
@@ -51142,6 +53342,7 @@ function memberRuntimeType(record4, context, seen = /* @__PURE__ */ new Set(), g
51142
53342
  };
51143
53343
  }
51144
53344
  case 22 /* Interface */:
53345
+ case 29 /* Reference */:
51145
53346
  return UNKNOWN_TYPE;
51146
53347
  }
51147
53348
  }
@@ -51249,6 +53450,16 @@ function toLanguageType(type, context, genericEnvironment) {
51249
53450
  }
51250
53451
  case 22 /* Interface */:
51251
53452
  return namedType(type.interfaceId, required);
53453
+ case 29 /* Reference */:
53454
+ return {
53455
+ kind: "reference",
53456
+ target: toLanguageType(
53457
+ type.targetTypeInfo,
53458
+ context,
53459
+ genericEnvironment
53460
+ ),
53461
+ nullable: !required
53462
+ };
51252
53463
  case 8 /* Enum */:
51253
53464
  return namedType(type.enumId, required);
51254
53465
  case 6 /* List */:
@@ -51290,11 +53501,8 @@ function toLanguageType(type, context, genericEnvironment) {
51290
53501
  case 9 /* Lookup */:
51291
53502
  return {
51292
53503
  kind: "set",
51293
- elementType: toLanguageType(
51294
- type.entryTypeInfo,
51295
- context,
51296
- genericEnvironment
51297
- ),
53504
+ // P105 §2.2. Multiselect dialogue elements are bare dialogue ids.
53505
+ elementType: type.entryTypeInfo.type === 18 /* DialogueLookup */ ? primitive2("string", true) : toLanguageType(type.entryTypeInfo, context, genericEnvironment),
51298
53506
  nullable: !required
51299
53507
  };
51300
53508
  case 25 /* NSDelegate */:
@@ -51462,13 +53670,19 @@ function functionReturnType(type, context, genericEnvironment) {
51462
53670
  function primitive2(name, required) {
51463
53671
  return { kind: "primitive", name, nullable: !required };
51464
53672
  }
53673
+ function analyzerReferenceType(target, nullable2, context) {
53674
+ return neoScriptReferenceType(target, nullable2, (named) => {
53675
+ if (analyzerSchemaIndex(context).enum(named.typeId)) return true;
53676
+ return isVariantClassId(named.typeId);
53677
+ });
53678
+ }
51465
53679
  function namedType(typeId, required) {
51466
53680
  return { kind: "named", typeId, nullable: !required };
51467
53681
  }
51468
53682
  function requiredType(type) {
51469
53683
  return { ...type, nullable: false };
51470
53684
  }
51471
- function collectionEntryType(type) {
53685
+ function collectionEntryType2(type) {
51472
53686
  if (type.kind === "list" || type.kind === "set") return type.elementType;
51473
53687
  if (type.kind === "dictionary") return type.valueType;
51474
53688
  return null;
@@ -51476,7 +53690,7 @@ function collectionEntryType(type) {
51476
53690
  function lookupCollectionEntryType(collectionMemberId, context, seen, genericEnvironment) {
51477
53691
  const collection = analyzerMemberById(context, collectionMemberId);
51478
53692
  if (!collection) return null;
51479
- return collectionEntryType(
53693
+ return collectionEntryType2(
51480
53694
  memberRuntimeType(collection, context, new Set(seen), genericEnvironment)
51481
53695
  );
51482
53696
  }
@@ -52423,9 +54637,9 @@ function decodeConvexOpaqueJson(value, context) {
52423
54637
  // ../convex/projectRecordSnapshotStorage.ts
52424
54638
  function decodeProjectRecordSnapshotData(snapshot, context = `Project record snapshot for ${snapshot.recordKind} "${snapshot.recordId}" dataJson`) {
52425
54639
  const decoded = decodeConvexOpaqueJson(snapshot.dataJson, context);
52426
- if (!isPlainRecord(decoded)) return decoded;
54640
+ if (!isPlainRecord2(decoded)) return decoded;
52427
54641
  const hydratedData = { ...decoded };
52428
- if (snapshot.recordKind === "enum" && !Object.hasOwn(hydratedData, "optionKeyOrder") && isPlainRecord(hydratedData.options)) {
54642
+ if (snapshot.recordKind === "enum" && !Object.hasOwn(hydratedData, "optionKeyOrder") && isPlainRecord2(hydratedData.options)) {
52429
54643
  hydratedData.optionKeyOrder = Object.keys(hydratedData.options);
52430
54644
  }
52431
54645
  hydratedData.id = snapshot.recordId;
@@ -52437,7 +54651,7 @@ function decodeProjectRecordSnapshotData(snapshot, context = `Project record sna
52437
54651
  }
52438
54652
  return hydratedData;
52439
54653
  }
52440
- function isPlainRecord(value) {
54654
+ function isPlainRecord2(value) {
52441
54655
  return typeof value === "object" && value !== null && !Array.isArray(value);
52442
54656
  }
52443
54657
 
@@ -54611,7 +56825,7 @@ var BOOL_TYPE_INFO = {
54611
56825
  type: 1 /* Bool */,
54612
56826
  required: true
54613
56827
  };
54614
- var STRING_TYPE_INFO = {
56828
+ var STRING_TYPE_INFO2 = {
54615
56829
  type: 3 /* String */,
54616
56830
  required: true
54617
56831
  };
@@ -56435,6 +58649,17 @@ var schemaGenericParameterSchema = strictObject({
56435
58649
  source: schemaSourceSpanSchema,
56436
58650
  selectionSpan: schemaSourceSpanSchema
56437
58651
  });
58652
+ function isSchemaReferenceTarget(type) {
58653
+ switch (type.kind) {
58654
+ case "null":
58655
+ case "unknown":
58656
+ case "delegate":
58657
+ case "action":
58658
+ return false;
58659
+ default:
58660
+ return true;
58661
+ }
58662
+ }
56438
58663
  var primitiveTypeKinds = [
56439
58664
  "null",
56440
58665
  "bool",
@@ -56519,6 +58744,9 @@ function schemaTypeOptionsAtDepth(depth) {
56519
58744
  "A lookup collection value requires a collection member."
56520
58745
  )
56521
58746
  ),
58747
+ nullableTypeSchema("reference", {
58748
+ target: schemaTypeAtDepth(depth + 1)
58749
+ }),
56522
58750
  nullableTypeSchema("delegate", {
56523
58751
  returnType: schemaFunctionReturnTypeAtDepth(depth + 1),
56524
58752
  argumentTypes: pipe(
@@ -56811,8 +59039,8 @@ var schemaMemberSchema = variant("kind", [
56811
59039
  "A lookup collection value requires a collection member."
56812
59040
  ),
56813
59041
  check(
56814
- (member) => member.collectionMemberId !== null || member.declaredType?.kind === "class" || member.declaredType?.kind === "generic",
56815
- "A lookup without a collection needs a class or generic declared type."
59042
+ (member) => member.collectionMemberId !== null || member.declaredType !== null && isSchemaReferenceTarget(member.declaredType),
59043
+ "A lookup without a collection needs a value type."
56816
59044
  )
56817
59045
  ),
56818
59046
  memberSchema("dialogueLookup", {
@@ -56935,7 +59163,8 @@ var MEMBER_KIND = {
56935
59163
  NSDelegate: 25,
56936
59164
  NSAction: 26,
56937
59165
  Variant: 27,
56938
- Set: 28
59166
+ Set: 28,
59167
+ Reference: 29
56939
59168
  };
56940
59169
  var MEMBER_MODIFIERS = ["virtual", "sealed", "abstract", "static"];
56941
59170
  var MEMBER_ACCESS = ["public", "protected", "private"];
@@ -57889,6 +60118,17 @@ function documentTypeToManifest(value, record4, path) {
57889
60118
  )
57890
60119
  };
57891
60120
  }
60121
+ if (kind === MEMBER_KIND.Reference) {
60122
+ return {
60123
+ kind: "reference",
60124
+ nullable: nullable2,
60125
+ target: documentTypeToManifest(
60126
+ typeInfo.targetTypeInfo,
60127
+ record4,
60128
+ `${path}.targetTypeInfo`
60129
+ )
60130
+ };
60131
+ }
57892
60132
  if (kind === MEMBER_KIND.Lookup) {
57893
60133
  const collectionValueId = optionalStringOrNull(typeInfo.collectionValueId);
57894
60134
  const collectionMemberId = optionalStringOrNull(
@@ -58054,6 +60294,13 @@ function manifestTypeToDocument(type) {
58054
60294
  argumentTypes: type.argumentTypes.map(manifestTypeToDocument)
58055
60295
  };
58056
60296
  }
60297
+ if (type.kind === "reference") {
60298
+ return {
60299
+ type: MEMBER_KIND.Reference,
60300
+ required,
60301
+ targetTypeInfo: manifestTypeToDocument(type.target)
60302
+ };
60303
+ }
58057
60304
  if (type.kind === "action") {
58058
60305
  return {
58059
60306
  type: MEMBER_KIND.NSAction,
@@ -59638,7 +61885,7 @@ var INITIALIZER_KEY_PLACEHOLDER = new RegExp(
59638
61885
 
59639
61886
  // ../packages/manifest/schema-contract/registry.mjs
59640
61887
  var PROJECT_SCHEMA_CONTRACT = Object.freeze({
59641
- cliVersion: "0.81.4",
61888
+ cliVersion: "0.82.0",
59642
61889
  projectFileUploadBatchSize: 32,
59643
61890
  documentRecords: {
59644
61891
  member: {
@@ -61479,7 +63726,7 @@ var SCRIPT_COLLECTION_READERS = {
61479
63726
  };
61480
63727
 
61481
63728
  // ../src/models/exports/unity-codegen-revision.ts
61482
- var UNITY_CODEGEN_REVISION = "d4026a3848848c8507d45dd54b6d31c1a0588b17b64c35e3fe9b25c89eb2fc05";
63729
+ var UNITY_CODEGEN_REVISION = "4eae63e39962f0ceb684c43fe8932b031b420c82ad6319670c46608bd9cd1470";
61483
63730
 
61484
63731
  // src/export-cache.ts
61485
63732
  var CACHE_BUILD = JSON.stringify([