@velarscript/compiler 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +70 -0
  3. package/dist/analyzer.d.ts +1175 -0
  4. package/dist/analyzer.d.ts.map +1 -0
  5. package/dist/analyzer.js +12130 -0
  6. package/dist/analyzer.js.map +1 -0
  7. package/dist/application-package-host.d.ts +28 -0
  8. package/dist/application-package-host.d.ts.map +1 -0
  9. package/dist/application-package-host.js +2 -0
  10. package/dist/application-package-host.js.map +1 -0
  11. package/dist/ast.d.ts +853 -0
  12. package/dist/ast.d.ts.map +1 -0
  13. package/dist/ast.js +245 -0
  14. package/dist/ast.js.map +1 -0
  15. package/dist/class-runtime.d.ts +6 -0
  16. package/dist/class-runtime.d.ts.map +1 -0
  17. package/dist/class-runtime.js +45 -0
  18. package/dist/class-runtime.js.map +1 -0
  19. package/dist/collection-lowering-runtime.d.ts +7 -0
  20. package/dist/collection-lowering-runtime.d.ts.map +1 -0
  21. package/dist/collection-lowering-runtime.js +952 -0
  22. package/dist/collection-lowering-runtime.js.map +1 -0
  23. package/dist/collection-runtime.d.ts +16 -0
  24. package/dist/collection-runtime.d.ts.map +1 -0
  25. package/dist/collection-runtime.js +231 -0
  26. package/dist/collection-runtime.js.map +1 -0
  27. package/dist/core-vocabulary.d.ts +141 -0
  28. package/dist/core-vocabulary.d.ts.map +1 -0
  29. package/dist/core-vocabulary.js +88 -0
  30. package/dist/core-vocabulary.js.map +1 -0
  31. package/dist/diagnostic.d.ts +42 -0
  32. package/dist/diagnostic.d.ts.map +1 -0
  33. package/dist/diagnostic.js +66 -0
  34. package/dist/diagnostic.js.map +1 -0
  35. package/dist/embedded-javascript.d.ts +74 -0
  36. package/dist/embedded-javascript.d.ts.map +1 -0
  37. package/dist/embedded-javascript.js +341 -0
  38. package/dist/embedded-javascript.js.map +1 -0
  39. package/dist/embedded-module.d.ts +11 -0
  40. package/dist/embedded-module.d.ts.map +1 -0
  41. package/dist/embedded-module.js +67 -0
  42. package/dist/embedded-module.js.map +1 -0
  43. package/dist/embedded-source.d.ts +19 -0
  44. package/dist/embedded-source.d.ts.map +1 -0
  45. package/dist/embedded-source.js +61 -0
  46. package/dist/embedded-source.js.map +1 -0
  47. package/dist/emitter.d.ts +188 -0
  48. package/dist/emitter.d.ts.map +1 -0
  49. package/dist/emitter.js +3254 -0
  50. package/dist/emitter.js.map +1 -0
  51. package/dist/error-runtime.d.ts +17 -0
  52. package/dist/error-runtime.d.ts.map +1 -0
  53. package/dist/error-runtime.js +109 -0
  54. package/dist/error-runtime.js.map +1 -0
  55. package/dist/extension.d.ts +373 -0
  56. package/dist/extension.d.ts.map +1 -0
  57. package/dist/extension.js +25 -0
  58. package/dist/extension.js.map +1 -0
  59. package/dist/formatter.d.ts +13 -0
  60. package/dist/formatter.d.ts.map +1 -0
  61. package/dist/formatter.js +1440 -0
  62. package/dist/formatter.js.map +1 -0
  63. package/dist/framework-host.d.ts +87 -0
  64. package/dist/framework-host.d.ts.map +1 -0
  65. package/dist/framework-host.js +2 -0
  66. package/dist/framework-host.js.map +1 -0
  67. package/dist/index.d.ts +75 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +932 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/interpolated-string.d.ts +47 -0
  72. package/dist/interpolated-string.d.ts.map +1 -0
  73. package/dist/interpolated-string.js +344 -0
  74. package/dist/interpolated-string.js.map +1 -0
  75. package/dist/json-runtime.d.ts +2 -0
  76. package/dist/json-runtime.d.ts.map +1 -0
  77. package/dist/json-runtime.js +193 -0
  78. package/dist/json-runtime.js.map +1 -0
  79. package/dist/language-guidance.d.ts +31 -0
  80. package/dist/language-guidance.d.ts.map +1 -0
  81. package/dist/language-guidance.js +187 -0
  82. package/dist/language-guidance.js.map +1 -0
  83. package/dist/lexer.d.ts +85 -0
  84. package/dist/lexer.d.ts.map +1 -0
  85. package/dist/lexer.js +1004 -0
  86. package/dist/lexer.js.map +1 -0
  87. package/dist/limits.d.ts +2 -0
  88. package/dist/limits.d.ts.map +1 -0
  89. package/dist/limits.js +2 -0
  90. package/dist/limits.js.map +1 -0
  91. package/dist/mechanical-fix.d.ts +26 -0
  92. package/dist/mechanical-fix.d.ts.map +1 -0
  93. package/dist/mechanical-fix.js +61 -0
  94. package/dist/mechanical-fix.js.map +1 -0
  95. package/dist/narrowing-runtime.d.ts +5 -0
  96. package/dist/narrowing-runtime.d.ts.map +1 -0
  97. package/dist/narrowing-runtime.js +27 -0
  98. package/dist/narrowing-runtime.js.map +1 -0
  99. package/dist/number-runtime.d.ts +3 -0
  100. package/dist/number-runtime.d.ts.map +1 -0
  101. package/dist/number-runtime.js +37 -0
  102. package/dist/number-runtime.js.map +1 -0
  103. package/dist/parser.d.ts +245 -0
  104. package/dist/parser.d.ts.map +1 -0
  105. package/dist/parser.js +3582 -0
  106. package/dist/parser.js.map +1 -0
  107. package/dist/primitive-runtime.d.ts +4 -0
  108. package/dist/primitive-runtime.d.ts.map +1 -0
  109. package/dist/primitive-runtime.js +39 -0
  110. package/dist/primitive-runtime.js.map +1 -0
  111. package/dist/promise-runtime.d.ts +6 -0
  112. package/dist/promise-runtime.d.ts.map +1 -0
  113. package/dist/promise-runtime.js +86 -0
  114. package/dist/promise-runtime.js.map +1 -0
  115. package/dist/reactive-bridge-runtime.d.ts +7 -0
  116. package/dist/reactive-bridge-runtime.d.ts.map +1 -0
  117. package/dist/reactive-bridge-runtime.js +112 -0
  118. package/dist/reactive-bridge-runtime.js.map +1 -0
  119. package/dist/runtime-abi.d.ts +24 -0
  120. package/dist/runtime-abi.d.ts.map +1 -0
  121. package/dist/runtime-abi.js +24 -0
  122. package/dist/runtime-abi.js.map +1 -0
  123. package/dist/semantic.d.ts +142 -0
  124. package/dist/semantic.d.ts.map +1 -0
  125. package/dist/semantic.js +845 -0
  126. package/dist/semantic.js.map +1 -0
  127. package/dist/source-names.d.ts +32 -0
  128. package/dist/source-names.d.ts.map +1 -0
  129. package/dist/source-names.js +101 -0
  130. package/dist/source-names.js.map +1 -0
  131. package/dist/source.d.ts +19 -0
  132. package/dist/source.d.ts.map +1 -0
  133. package/dist/source.js +64 -0
  134. package/dist/source.js.map +1 -0
  135. package/dist/text-runtime.d.ts +2 -0
  136. package/dist/text-runtime.d.ts.map +1 -0
  137. package/dist/text-runtime.js +285 -0
  138. package/dist/text-runtime.js.map +1 -0
  139. package/dist/token.d.ts +19 -0
  140. package/dist/token.d.ts.map +1 -0
  141. package/dist/token.js +51 -0
  142. package/dist/token.js.map +1 -0
  143. package/dist/type-registry-runtime.d.ts +7 -0
  144. package/dist/type-registry-runtime.d.ts.map +1 -0
  145. package/dist/type-registry-runtime.js +51 -0
  146. package/dist/type-registry-runtime.js.map +1 -0
  147. package/dist/type-validation-runtime.d.ts +17 -0
  148. package/dist/type-validation-runtime.d.ts.map +1 -0
  149. package/dist/type-validation-runtime.js +150 -0
  150. package/dist/type-validation-runtime.js.map +1 -0
  151. package/dist/types.d.ts +356 -0
  152. package/dist/types.d.ts.map +1 -0
  153. package/dist/types.js +1170 -0
  154. package/dist/types.js.map +1 -0
  155. package/dist/utf8-runtime.d.ts +7 -0
  156. package/dist/utf8-runtime.d.ts.map +1 -0
  157. package/dist/utf8-runtime.js +43 -0
  158. package/dist/utf8-runtime.js.map +1 -0
  159. package/package.json +48 -0
package/dist/types.js ADDED
@@ -0,0 +1,1170 @@
1
+ /** Canonical identities for Core's cross-runtime binary storage types. */
2
+ export const VELAR_BYTES_TYPE_IDENTITY = "velar/binary#type:Bytes";
3
+ export const VELAR_UINT8_BUFFER_TYPE_IDENTITY = "velar/binary#type:UInt8Buffer";
4
+ export const VELAR_UINT16_BUFFER_TYPE_IDENTITY = "velar/binary#type:UInt16Buffer";
5
+ export const VELAR_UINT32_BUFFER_TYPE_IDENTITY = "velar/binary#type:UInt32Buffer";
6
+ export const VELAR_FLOAT32_BUFFER_TYPE_IDENTITY = "velar/binary#type:Float32Buffer";
7
+ /**
8
+ * Binary storage stays nominal even though its JavaScript representation is a
9
+ * typed array. This keeps Buffer's accidental surface out of source while
10
+ * giving the analyzer and emitter one exact fast-path discriminator.
11
+ */
12
+ export function binaryStorageKind(type) {
13
+ if (type.kind !== "named")
14
+ return null;
15
+ if (type.identity === VELAR_BYTES_TYPE_IDENTITY)
16
+ return "bytes";
17
+ if (type.identity === VELAR_UINT8_BUFFER_TYPE_IDENTITY)
18
+ return "uint8";
19
+ if (type.identity === VELAR_UINT16_BUFFER_TYPE_IDENTITY)
20
+ return "uint16";
21
+ if (type.identity === VELAR_UINT32_BUFFER_TYPE_IDENTITY)
22
+ return "uint32";
23
+ if (type.identity === VELAR_FLOAT32_BUFFER_TYPE_IDENTITY)
24
+ return "float32";
25
+ return null;
26
+ }
27
+ export const unknownType = { kind: "unknown" };
28
+ export const invalidType = Object.freeze({ kind: "unknown" });
29
+ export const anyType = { kind: "any" };
30
+ /** The declared parameter domain of the built-in `str`; see `isTextConvertibleType`. */
31
+ export const textConvertibleType = Object.freeze({ kind: "any", textConvertible: true });
32
+ export const nullType = { kind: "null" };
33
+ export const stringType = { kind: "string" };
34
+ export const numberType = { kind: "number" };
35
+ export const boolType = { kind: "bool" };
36
+ /**
37
+ * D41 item 61: the complete, closed bound vocabulary. A bound is a name the
38
+ * compiler owns; users cannot define one, and there is no syntax for combining
39
+ * two — D51 rule 110: not because the three form a containment chain (they do
40
+ * not: a Web text-shaped value satisfies Text and is refused by Data), but
41
+ * because no real function demands two at once. The grant table below is the
42
+ * whole definition; nothing computes a relation between two bounds.
43
+ */
44
+ export const typeParameterBoundNames = Object.freeze(["Comparable", "Text", "Data"]);
45
+ /**
46
+ * The 4x3 capability-grant table (D41 item 61). Every check reads this
47
+ * constant; nothing computes a relation between two bounds, so the rule
48
+ * "bounds have no subtyping" holds literally. The overlaps below are grants,
49
+ * not type containment (D51 rule 110).
50
+ */
51
+ const boundCapabilityGrants = Object.freeze({
52
+ Data: Object.freeze({ text: false, order: false, data: true }),
53
+ Text: Object.freeze({ text: true, order: false, data: true }),
54
+ Comparable: Object.freeze({ text: true, order: true, data: true }),
55
+ });
56
+ export function isTypeParameterBound(name) {
57
+ return typeParameterBoundNames.includes(name);
58
+ }
59
+ /** Reads the grant table. An unbounded parameter (`null`) grants nothing. */
60
+ export function boundGrants(bound, capability) {
61
+ return bound ? boundCapabilityGrants[bound][capability] : false;
62
+ }
63
+ /**
64
+ * A callable carrying `actual` bounds may stand where `expected` bounds are
65
+ * declared only when it demands no capability the target does not promise —
66
+ * decided by the same grant table, one capability at a time.
67
+ */
68
+ export function boundAccepts(actual, expected) {
69
+ if (actual === expected)
70
+ return true;
71
+ return ["text", "order", "data"].every((capability) => !boundGrants(actual, capability) || boundGrants(expected, capability));
72
+ }
73
+ /**
74
+ * The text-conversion whitelist (charter section 14): values whose text form is
75
+ * total and hook-free. This is the single authority behind both the direct
76
+ * `str(value)` / f-string check and the assignability of the `textConvertible`
77
+ * parameter domain, so `str` used as a value cannot admit anything a direct
78
+ * call rejects.
79
+ */
80
+ export function isTextConvertibleType(type, environment) {
81
+ const expanded = environment.expandTypeAliases?.(type) ?? type;
82
+ if (isInvalidType(expanded))
83
+ return true;
84
+ switch (expanded.kind) {
85
+ case "string":
86
+ case "number":
87
+ case "bool":
88
+ case "null":
89
+ case "enum":
90
+ case "enumMember":
91
+ return true;
92
+ case "optional":
93
+ return isTextConvertibleType(expanded.inner, environment);
94
+ case "union":
95
+ return expanded.members.every((member) => isTextConvertibleType(member, environment));
96
+ // D41 item 61: a `Text`-bounded parameter promises every value it can hold
97
+ // is already in this whitelist, so the body may interpolate it.
98
+ case "parameter":
99
+ return boundGrants(environment.boundOf?.(expanded) ?? null, "text");
100
+ default:
101
+ return environment.extensionTextForm?.(expanded) === true;
102
+ }
103
+ }
104
+ export function resolveTypeReference(reference, extension) {
105
+ return typeFromSyntax(reference.syntax, extension);
106
+ }
107
+ export function typeFromSyntax(syntax, extension) {
108
+ const nested = (value) => typeFromSyntax(value, extension);
109
+ const owned = extension?.(syntax, nested);
110
+ if (owned)
111
+ return owned;
112
+ switch (syntax.kind) {
113
+ case "NamedTypeSyntax":
114
+ switch (syntax.name) {
115
+ case "string": return stringType;
116
+ case "number": return numberType;
117
+ case "bool": return boolType;
118
+ case "null": return nullType;
119
+ case "unknown": return unknownType;
120
+ case "any": return anyType;
121
+ case "Promise": return { kind: "promise", value: nullType };
122
+ case "Function": return { kind: "function", parameters: [], requiredParameters: 0, result: nullType };
123
+ default: return { kind: "named", name: syntax.name };
124
+ }
125
+ case "EnumMemberTypeSyntax":
126
+ return { kind: "enumMember", name: syntax.enumName, identity: syntax.enumName, member: syntax.member };
127
+ case "GenericTypeSyntax": {
128
+ const arguments_ = syntax.arguments.map(nested);
129
+ if (syntax.name === "List")
130
+ return { kind: "list", element: arguments_[0] ?? unknownType };
131
+ if (syntax.name === "Set")
132
+ return { kind: "set", element: arguments_[0] ?? unknownType };
133
+ if (syntax.name === "Map")
134
+ return { kind: "map", key: arguments_[0] ?? unknownType, value: arguments_[1] ?? unknownType };
135
+ if (syntax.name === "Record")
136
+ return { kind: "record", value: arguments_[0] ?? unknownType };
137
+ if (syntax.name === "Promise")
138
+ return { kind: "promise", value: arguments_[0] ?? unknownType };
139
+ if (syntax.name === "Type")
140
+ return { kind: "runtimeType", value: arguments_[0] ?? unknownType };
141
+ if (syntax.name === "Function") {
142
+ const result = arguments_.at(-1) ?? nullType;
143
+ const parameters = arguments_.slice(0, -1);
144
+ return { kind: "function", parameters, requiredParameters: parameters.length, result };
145
+ }
146
+ // D55 rule 121: a name core does not own is either an extension family
147
+ // (claimed above) or a user generic record. The arguments ride along
148
+ // unresolved so the one stage that knows the declarations — the analyzer,
149
+ // or a module interface being built — can canonicalize the application;
150
+ // until then the display name stays exactly the source text it always was.
151
+ return { kind: "named", name: formatTypeSyntax(syntax), application: { declaration: syntax.name, name: syntax.name, arguments: arguments_ } };
152
+ }
153
+ case "ReadonlyTypeSyntax":
154
+ return readonlyViewOf(nested(syntax.inner));
155
+ case "OptionalTypeSyntax":
156
+ return optionalOf(nested(syntax.inner));
157
+ case "UnionTypeSyntax":
158
+ return unionOf(syntax.members.map(nested));
159
+ case "FunctionTypeSyntax": {
160
+ const fixed = syntax.parameters.filter((parameter) => !parameter.rest);
161
+ const rest = syntax.parameters.find((parameter) => parameter.rest);
162
+ return {
163
+ kind: "function",
164
+ parameters: fixed.map((parameter) => nested(parameter.type)),
165
+ ...(fixed.some((parameter) => parameter.name) ? { parameterNames: fixed.map((parameter) => parameter.name ?? "") } : {}),
166
+ requiredParameters: fixed.filter((parameter) => !parameter.optional).length,
167
+ ...(rest ? { rest: nested(rest.type) } : {}),
168
+ result: nested(syntax.result),
169
+ };
170
+ }
171
+ }
172
+ }
173
+ /**
174
+ * The canonical identity of one instantiation. D55 rule 121 puts the arguments
175
+ * in the identity string rather than adding a field `typeIdentity` would have
176
+ * to learn, so `Box<string>` and `Box<number>` are two identities and
177
+ * `typeIdentity`'s `named` branch is unchanged. Arguments are keyed by their
178
+ * own identities, which is what makes `Box<Id>` and `Box<string>` one type when
179
+ * `Id` is an alias of `string`.
180
+ */
181
+ export function genericApplicationIdentity(declaration, arguments_) {
182
+ return `${declaration}<${arguments_.map((argument) => semanticTypeIdentity(argument)).join(",")}>`;
183
+ }
184
+ /** The display text of one instantiation — `Box<string>`. */
185
+ export function genericApplicationName(name, arguments_) {
186
+ return `${name}<${arguments_.map(describeType).join(", ")}>`;
187
+ }
188
+ /** The one constructor for a resolved application, so identity and text never diverge. */
189
+ export function genericApplicationType(declaration, name, arguments_, readonlyView = false) {
190
+ return {
191
+ kind: "named",
192
+ name: genericApplicationName(name, arguments_),
193
+ identity: genericApplicationIdentity(declaration, arguments_),
194
+ application: { declaration, name, arguments: arguments_ },
195
+ ...(readonlyView ? { readonlyView: true } : {}),
196
+ };
197
+ }
198
+ /**
199
+ * Rebuilds a type with `map` applied to each type it directly contains. The
200
+ * nested positions are exactly the ones `substituteTypeParameters` walks, kept
201
+ * in one place so a traversal added by a caller cannot miss one of them.
202
+ */
203
+ export function mapNestedTypes(type, map) {
204
+ switch (type.kind) {
205
+ case "optional":
206
+ return optionalOf(map(type.inner));
207
+ case "list":
208
+ case "set":
209
+ return { ...type, element: map(type.element) };
210
+ case "map":
211
+ return { ...type, key: map(type.key), value: map(type.value) };
212
+ case "record":
213
+ return { ...type, value: map(type.value) };
214
+ case "promise":
215
+ return { kind: "promise", value: map(type.value) };
216
+ case "runtimeType":
217
+ return { kind: "runtimeType", value: map(type.value) };
218
+ case "typeObject":
219
+ return type.value ? { ...type, value: map(type.value) } : type;
220
+ case "object":
221
+ return { ...type, fields: new Map([...type.fields].map(([name, value]) => [name, map(value)])) };
222
+ case "named":
223
+ return type.application
224
+ ? { ...type, application: { ...type.application, arguments: type.application.arguments.map(map) } }
225
+ : type;
226
+ case "extension":
227
+ return {
228
+ ...type,
229
+ properties: new Map([...type.properties].map(([name, value]) => [name, map(value)])),
230
+ arguments: type.arguments.map(map),
231
+ };
232
+ case "function":
233
+ case "action":
234
+ case "intrinsic":
235
+ return {
236
+ ...type,
237
+ parameters: type.parameters.map(map),
238
+ ...(type.rest ? { rest: map(type.rest) } : {}),
239
+ result: map(type.result),
240
+ };
241
+ case "union":
242
+ return unionOf(type.members.map(map));
243
+ default:
244
+ return type;
245
+ }
246
+ }
247
+ export function formatTypeReference(reference) {
248
+ return formatTypeSyntax(reference.syntax);
249
+ }
250
+ export function formatTypeSyntax(syntax) {
251
+ switch (syntax.kind) {
252
+ case "NamedTypeSyntax": return syntax.name;
253
+ case "EnumMemberTypeSyntax": return `${syntax.enumName}.${syntax.member}`;
254
+ case "GenericTypeSyntax": return `${syntax.name}<${syntax.arguments.map(formatTypeSyntax).join(", ")}>`;
255
+ case "ReadonlyTypeSyntax": return `readonly ${syntax.inner.kind === "UnionTypeSyntax" || syntax.inner.kind === "FunctionTypeSyntax" ? `(${formatTypeSyntax(syntax.inner)})` : formatTypeSyntax(syntax.inner)}`;
256
+ case "OptionalTypeSyntax": return `${syntax.inner.kind === "UnionTypeSyntax" || syntax.inner.kind === "FunctionTypeSyntax" ? `(${formatTypeSyntax(syntax.inner)})` : formatTypeSyntax(syntax.inner)}?`;
257
+ case "UnionTypeSyntax": return syntax.members.map(formatTypeSyntax).join(" | ");
258
+ case "FunctionTypeSyntax": return `(${syntax.parameters.map((parameter) => `${parameter.rest ? "..." : ""}${parameter.name ? `${parameter.name}${parameter.optional ? "?" : ""}: ` : ""}${formatTypeSyntax(parameter.type)}`).join(", ")}) -> ${formatTypeSyntax(syntax.result)}`;
259
+ }
260
+ }
261
+ export function isReadonlyView(type) {
262
+ return (type.kind === "list" || type.kind === "set" || type.kind === "map" || type.kind === "record"
263
+ || type.kind === "object" || type.kind === "named")
264
+ && type.readonlyView === true;
265
+ }
266
+ export function readonlyViewOf(type) {
267
+ if (type.kind === "optional")
268
+ return optionalOf(readonlyViewOf(type.inner));
269
+ if (type.kind === "union")
270
+ return unionOf(type.members.map(readonlyViewOf));
271
+ if (type.kind === "list" || type.kind === "set" || type.kind === "map" || type.kind === "record"
272
+ || type.kind === "object" || type.kind === "named") {
273
+ return type.readonlyView ? type : { ...type, readonlyView: true };
274
+ }
275
+ return type;
276
+ }
277
+ export function mutableViewOf(type) {
278
+ if (type.kind === "optional")
279
+ return optionalOf(mutableViewOf(type.inner));
280
+ if (type.kind === "union")
281
+ return unionOf(type.members.map(mutableViewOf));
282
+ if (type.kind === "list")
283
+ return { kind: "list", element: type.element };
284
+ if (type.kind === "set")
285
+ return { kind: "set", element: type.element };
286
+ if (type.kind === "map")
287
+ return { kind: "map", key: type.key, value: type.value };
288
+ if (type.kind === "record")
289
+ return { kind: "record", value: type.value };
290
+ if (type.kind === "object")
291
+ return { kind: "object", fields: type.fields, ...(type.readonlyFields ? { readonlyFields: type.readonlyFields } : {}), ...(type.optionalFields ? { optionalFields: type.optionalFields } : {}) };
292
+ if (type.kind === "named")
293
+ return { kind: "named", name: type.name, ...(type.identity ? { identity: type.identity } : {}), ...(type.application ? { application: type.application } : {}) };
294
+ return type;
295
+ }
296
+ export function optionalOf(type) {
297
+ if (isInvalidType(type)) {
298
+ return invalidType;
299
+ }
300
+ if (type.kind === "optional") {
301
+ return type;
302
+ }
303
+ if (type.kind === "null") {
304
+ return nullType;
305
+ }
306
+ return { kind: "optional", inner: type };
307
+ }
308
+ export function nonOptional(type) {
309
+ return type.kind === "optional" ? type.inner : type;
310
+ }
311
+ export function unionOf(types) {
312
+ const members = [];
313
+ let nullable = false;
314
+ const add = (type) => {
315
+ if (isInvalidType(type))
316
+ return false;
317
+ if (type.kind === "union")
318
+ return type.members.every(add);
319
+ if (type.kind === "optional") {
320
+ nullable = true;
321
+ return add(type.inner);
322
+ }
323
+ if (type.kind === "null") {
324
+ nullable = true;
325
+ return true;
326
+ }
327
+ if (!members.some((member) => sameType(member, type)))
328
+ members.push(type);
329
+ return true;
330
+ };
331
+ if (!types.every(add))
332
+ return invalidType;
333
+ const value = members.length === 0 ? unknownType : members.length === 1 ? members[0] : { kind: "union", members };
334
+ return nullable ? members.length === 0 ? nullType : optionalOf(value) : value;
335
+ }
336
+ export function mergeTypes(left, right) {
337
+ if (isInvalidType(left) || isInvalidType(right)) {
338
+ return invalidType;
339
+ }
340
+ if (left.kind === "unknown" && !left.restricted) {
341
+ return right;
342
+ }
343
+ if (right.kind === "unknown" && !right.restricted) {
344
+ return left;
345
+ }
346
+ if (sameType(left, right)) {
347
+ return left;
348
+ }
349
+ if ((isReadonlyView(left) || isReadonlyView(right))
350
+ && sameType(mutableViewOf(left), mutableViewOf(right))) {
351
+ return readonlyViewOf(isReadonlyView(left) ? left : right);
352
+ }
353
+ if (left.kind === "optional" && sameType(left.inner, right)) {
354
+ return left;
355
+ }
356
+ if (right.kind === "optional" && sameType(right.inner, left)) {
357
+ return right;
358
+ }
359
+ if (left.kind === "null") {
360
+ return optionalOf(right);
361
+ }
362
+ if (right.kind === "null") {
363
+ return optionalOf(left);
364
+ }
365
+ return unionOf([left, right]);
366
+ }
367
+ export function resolvedAsyncType(type) {
368
+ if (type.kind === "promise")
369
+ return resolvedAsyncType(type.value);
370
+ if (type.kind === "optional")
371
+ return optionalOf(resolvedAsyncType(type.inner));
372
+ if (type.kind === "union")
373
+ return unionOf(type.members.map(resolvedAsyncType));
374
+ return type;
375
+ }
376
+ export function sameType(left, right) {
377
+ return semanticTypeIdentity(left) === semanticTypeIdentity(right);
378
+ }
379
+ // Parameter labels are editor/call-site metadata, not part of the runtime
380
+ // callable domain. Override implementations may keep local names while every
381
+ // declaration still exposes its own checked named-argument surface.
382
+ export function sameTypeIgnoringCallableParameterNames(left, right) {
383
+ return typeIdentity(left, false) === typeIdentity(right, false);
384
+ }
385
+ function runtimeTypeValue(type) {
386
+ if (type.kind === "runtimeType")
387
+ return type.value;
388
+ if (type.kind === "typeObject")
389
+ return type.value ?? { kind: "named", name: type.name };
390
+ if (type.kind === "enumObject")
391
+ return { kind: "enum", name: type.name, identity: type.identity };
392
+ return null;
393
+ }
394
+ export function isAssignable(actual, expected, environment, seen = new Set()) {
395
+ if (isInvalidType(actual) || isInvalidType(expected)) {
396
+ return true;
397
+ }
398
+ // The text-conversion domain is narrower than `any` and must be decided
399
+ // before the `any` shortcut, so `str` passed as a value keeps the whitelist
400
+ // at every indirect call site (`const c = str`, `values.map(str)`).
401
+ if (expected.kind === "any" && expected.textConvertible) {
402
+ return isTextConvertibleType(actual, environment);
403
+ }
404
+ if (actual.kind === "any" || expected.kind === "any") {
405
+ return true;
406
+ }
407
+ if (expected.kind === "unknown") {
408
+ return !expected.restricted;
409
+ }
410
+ if (actual.kind === "unknown") {
411
+ return false;
412
+ }
413
+ if (sameType(actual, expected)) {
414
+ return true;
415
+ }
416
+ const pair = `${semanticTypeIdentity(actual)}\u0000${semanticTypeIdentity(expected)}`;
417
+ if (seen.has(pair))
418
+ return true;
419
+ seen.add(pair);
420
+ if (actual.kind === "union") {
421
+ return actual.members.every((member) => isAssignable(member, expected, environment, new Set(seen)));
422
+ }
423
+ if (actual.kind === "optional") {
424
+ return isAssignable(nullType, expected, environment, new Set(seen))
425
+ && isAssignable(actual.inner, expected, environment, new Set(seen));
426
+ }
427
+ if (expected.kind === "optional") {
428
+ return actual.kind === "null" || isAssignable(actual, expected.inner, environment, seen);
429
+ }
430
+ if (expected.kind === "union") {
431
+ return expected.members.some((member) => isAssignable(actual, member, environment, new Set(seen)));
432
+ }
433
+ if (isReadonlyView(actual) && !isReadonlyView(expected)) {
434
+ return false;
435
+ }
436
+ if (actual.kind === "parameter" && expected.kind === "parameter") {
437
+ return actual.index === expected.index;
438
+ }
439
+ if (actual.kind === "enum" && expected.kind === "string") {
440
+ return true;
441
+ }
442
+ if (actual.kind === "enumMember") {
443
+ if (expected.kind === "enumMember") {
444
+ return actual.identity === expected.identity && actual.member === expected.member;
445
+ }
446
+ if (expected.kind === "enum")
447
+ return actual.identity === expected.identity;
448
+ if (expected.kind === "string")
449
+ return true;
450
+ }
451
+ if (expected.kind === "runtimeType") {
452
+ const value = runtimeTypeValue(actual);
453
+ return value !== null && isAssignable(value, expected.value, environment, seen);
454
+ }
455
+ if (actual.kind === "list" && expected.kind === "list") {
456
+ if (expected.readonlyView) {
457
+ return isAssignable(readonlyViewOf(actual.element), readonlyViewOf(expected.element), environment, new Set(seen));
458
+ }
459
+ return invariant(actual.element, expected.element, environment, seen);
460
+ }
461
+ if (actual.kind === "set" && expected.kind === "set") {
462
+ if (expected.readonlyView) {
463
+ return isAssignable(readonlyViewOf(actual.element), readonlyViewOf(expected.element), environment, new Set(seen));
464
+ }
465
+ return invariant(actual.element, expected.element, environment, seen);
466
+ }
467
+ if (actual.kind === "map" && expected.kind === "map") {
468
+ if (expected.readonlyView) {
469
+ return isAssignable(readonlyViewOf(actual.key), readonlyViewOf(expected.key), environment, new Set(seen))
470
+ && isAssignable(readonlyViewOf(actual.value), readonlyViewOf(expected.value), environment, new Set(seen));
471
+ }
472
+ return invariant(actual.key, expected.key, environment, seen)
473
+ && invariant(actual.value, expected.value, environment, seen);
474
+ }
475
+ if (actual.kind === "record" && expected.kind === "record") {
476
+ if (expected.readonlyView) {
477
+ return isAssignable(readonlyViewOf(actual.value), readonlyViewOf(expected.value), environment, new Set(seen));
478
+ }
479
+ return invariant(actual.value, expected.value, environment, seen);
480
+ }
481
+ if (actual.kind === "object" && expected.kind === "record") {
482
+ if (expected.readonlyView) {
483
+ return [...actual.fields.values()].every((field) => isAssignable(readonlyViewOf(field), readonlyViewOf(expected.value), environment, new Set(seen)));
484
+ }
485
+ if (actual.readonlyFields && actual.readonlyFields.size > 0)
486
+ return false;
487
+ return [...actual.fields.values()].every((field) => invariant(field, expected.value, environment, seen));
488
+ }
489
+ if (actual.kind === "promise" && expected.kind === "promise") {
490
+ return isAssignable(actual.value, expected.value, environment, seen);
491
+ }
492
+ if (actual.kind === "object" && expected.kind === "named") {
493
+ if (environment.isPrimitiveType(expected.name))
494
+ return false;
495
+ const fields = environment.fieldsOf(expected.identity ?? expected.name);
496
+ const expectedReadonly = expected.readonlyView ? new Set(fields?.keys()) : environment.readonlyFieldsOf?.(expected.identity ?? expected.name) ?? undefined;
497
+ return fields ? objectFieldsAssignable(actual.fields, fields, environment, seen, actual.readonlyView ? new Set(actual.fields.keys()) : actual.readonlyFields, expectedReadonly, actual.optionalFields) : false;
498
+ }
499
+ if (actual.kind === "named" && expected.kind === "object") {
500
+ if (environment.isPrimitiveType(actual.name))
501
+ return false;
502
+ const fields = environment.fieldsOf(actual.identity ?? actual.name);
503
+ const actualReadonly = actual.readonlyView ? new Set(fields?.keys()) : environment.readonlyFieldsOf?.(actual.identity ?? actual.name) ?? undefined;
504
+ const expectedReadonly = expected.readonlyView ? new Set(expected.fields.keys()) : expected.readonlyFields;
505
+ return fields ? objectFieldsAssignable(fields, expected.fields, environment, seen, actualReadonly, expectedReadonly, undefined, expected.optionalFields) : false;
506
+ }
507
+ if (actual.kind === "named" && expected.kind === "named") {
508
+ const actualPrimitive = environment.isPrimitiveType(actual.name);
509
+ const expectedPrimitive = environment.isPrimitiveType(expected.name);
510
+ if (actualPrimitive || expectedPrimitive) {
511
+ return actualPrimitive && expectedPrimitive && environment.isPrimitiveSubtype(actual.name, expected.name);
512
+ }
513
+ const actualFields = environment.fieldsOf(actual.identity ?? actual.name);
514
+ const expectedFields = environment.fieldsOf(expected.identity ?? expected.name);
515
+ return actualFields !== null && expectedFields !== null
516
+ ? objectFieldsAssignable(actualFields, expectedFields, environment, seen, actual.readonlyView ? new Set(actualFields.keys()) : environment.readonlyFieldsOf?.(actual.identity ?? actual.name) ?? undefined, expected.readonlyView ? new Set(expectedFields.keys()) : environment.readonlyFieldsOf?.(expected.identity ?? expected.name) ?? undefined)
517
+ : false;
518
+ }
519
+ if (actual.kind === "class" && expected.kind === "class") {
520
+ return environment.isSubclassOf(actual.identity ?? actual.name, expected.identity ?? expected.name);
521
+ }
522
+ if (actual.kind === "object" && expected.kind === "object") {
523
+ return objectFieldsAssignable(actual.fields, expected.fields, environment, seen, actual.readonlyView ? new Set(actual.fields.keys()) : actual.readonlyFields, expected.readonlyView ? new Set(expected.fields.keys()) : expected.readonlyFields, actual.optionalFields, expected.optionalFields);
524
+ }
525
+ if ((actual.kind === "function" || actual.kind === "action" || actual.kind === "intrinsic") && (expected.kind === "function" || expected.kind === "action" || expected.kind === "intrinsic")) {
526
+ const actualTypeParameters = actual.typeParameterNames?.length ?? 0;
527
+ const expectedTypeParameters = expected.typeParameterNames?.length ?? 0;
528
+ if (actualTypeParameters !== expectedTypeParameters) {
529
+ if (expectedTypeParameters !== 0)
530
+ return false;
531
+ // D41 item 61 check site 2: the first-class path erases the parameters
532
+ // silently, so an unsatisfied bound has to make the value unassignable
533
+ // here; the analyzer wrapper turns the same fact into a directed message.
534
+ const violations = [];
535
+ const concrete = instantiateGenericCallable(actual, expected, environment, violations);
536
+ return violations.length === 0 && isAssignable(concrete, expected, environment, seen);
537
+ }
538
+ if (actualTypeParameters > 0 && !typeParameterBoundsAccept(actual, expected))
539
+ return false;
540
+ return callableInputsAssignable(actual, expected, environment, seen)
541
+ && isAssignable(actual.result, expected.result, environment, seen);
542
+ }
543
+ if (actual.kind === "extension" && expected.kind === "extension") {
544
+ return environment.isExtensionTypeAssignable?.(actual, expected, (nestedActual, nestedExpected) => isAssignable(nestedActual, nestedExpected, environment, new Set(seen))) ?? false;
545
+ }
546
+ return false;
547
+ }
548
+ export function semanticTypeIdentity(type) {
549
+ return typeIdentity(type);
550
+ }
551
+ export const analysisTypeIdentity = semanticTypeIdentity;
552
+ function typeIdentity(type, includeCallableParameterNames = true) {
553
+ const nested = (value) => typeIdentity(value, includeCallableParameterNames);
554
+ switch (type.kind) {
555
+ case "unknown":
556
+ return identityNode("unknown", [isInvalidType(type) ? "diagnosed" : type.restricted ? "restricted" : ""]);
557
+ case "any":
558
+ // The text-conversion domain is a distinct contract from `any`; sharing
559
+ // an identity would let `sameType` short-circuit the whitelist.
560
+ return identityNode("any", [type.textConvertible ? "text" : ""]);
561
+ case "null":
562
+ case "string":
563
+ case "number":
564
+ case "bool":
565
+ return identityNode(type.kind);
566
+ case "class":
567
+ return identityNode("class", [type.identity ?? type.name]);
568
+ case "classConstructor":
569
+ return identityNode("class-constructor", [type.identity ?? type.name]);
570
+ case "named":
571
+ return identityNode("named", [type.readonlyView ? "readonly" : "", type.identity ?? type.name]);
572
+ case "parameter":
573
+ // De Bruijn-style: the identity encodes only the index so that (T) -> T
574
+ // and (U) -> U from any two declarations are the same type.
575
+ return identityNode("parameter", [String(type.index)]);
576
+ case "enum":
577
+ case "enumMember":
578
+ case "enumObject":
579
+ return identityNode(type.kind, [type.identity, ...(type.kind === "enumMember" ? [type.member] : [])]);
580
+ case "typeObject":
581
+ return identityNode("type-object", [type.name]);
582
+ case "runtimeType":
583
+ return identityNode("runtime-type", [nested(type.value)]);
584
+ case "optional":
585
+ return identityNode("optional", [nested(type.inner)]);
586
+ case "list":
587
+ return identityNode("list", [type.readonlyView ? "readonly" : "", nested(type.element)]);
588
+ case "set":
589
+ return identityNode("set", [type.readonlyView ? "readonly" : "", nested(type.element)]);
590
+ case "map":
591
+ return identityNode("map", [type.readonlyView ? "readonly" : "", nested(type.key), nested(type.value)]);
592
+ case "record":
593
+ return identityNode("record", [type.readonlyView ? "readonly" : "", nested(type.value)]);
594
+ case "promise":
595
+ return identityNode("promise", [nested(type.value)]);
596
+ case "object":
597
+ return identityNode("object", [type.readonlyView ? "readonly" : "", ...[...type.fields]
598
+ .map(([name, value]) => [name, nested(value)])
599
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
600
+ .map(([name, value]) => identityNode("field", [
601
+ type.readonlyFields?.has(name) ? "readonly" : "",
602
+ type.optionalFields?.has(name) ? "optional" : "",
603
+ name,
604
+ value,
605
+ ]))]);
606
+ case "function":
607
+ case "action":
608
+ case "intrinsic":
609
+ return identityNode(type.kind, [
610
+ type.kind === "intrinsic" ? type.name : "",
611
+ type.typeParameterNames?.length ? String(type.typeParameterNames.length) : "",
612
+ // D41 item 61 risk 1: the bound cannot live in the `parameter` kind's
613
+ // identity without breaking its De Bruijn contract, so the callable
614
+ // carries it — otherwise `<T: Text>(T) -> T` and `<U>(U) -> U` would
615
+ // share one identity and assignment between them would go unchecked.
616
+ type.typeParameterBounds?.some((bound) => bound !== null)
617
+ ? identityNode("bounds", type.typeParameterBounds.map((bound) => bound ?? ""))
618
+ : "",
619
+ identityNode("parameter-names", includeCallableParameterNames ? type.parameterNames ?? [] : []),
620
+ String(type.requiredParameters),
621
+ identityNode("parameters", type.parameters.map(nested)),
622
+ type.rest ? nested(type.rest) : "",
623
+ nested(type.result),
624
+ ]);
625
+ case "extension":
626
+ return identityNode("extension", [type.extensionId, type.family, type.role, type.nominal ?? "", ...[...type.properties]
627
+ .map(([name, value]) => [name, nested(value)])
628
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
629
+ .map(([name, value]) => identityNode("property", [name, value])),
630
+ identityNode("required-properties", [...type.requiredProperties].sort()),
631
+ identityNode("arguments", type.arguments.map(nested)),
632
+ identityNode("metadata", Object.entries(type.metadata ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([name, value]) => identityNode("entry", [name, value]))),]);
633
+ case "union":
634
+ return identityNode("union", type.members.map(nested).sort());
635
+ }
636
+ }
637
+ function identityNode(kind, parts = []) {
638
+ return `${kind.length}:${kind}${parts.map((part) => `${part.length}:${part}`).join("")}`;
639
+ }
640
+ export function isInvalidType(type) {
641
+ return type === invalidType;
642
+ }
643
+ export function describeType(type) {
644
+ switch (type.kind) {
645
+ case "any":
646
+ return type.textConvertible ? "string | number | bool | enum | null" : "any";
647
+ case "unknown":
648
+ case "null":
649
+ case "string":
650
+ case "number":
651
+ case "bool":
652
+ return type.kind;
653
+ case "optional":
654
+ return `${["function", "action", "intrinsic", "union"].includes(type.inner.kind) ? `(${describeType(type.inner)})` : describeType(type.inner)}?`;
655
+ case "list":
656
+ return `${type.readonlyView ? "readonly " : ""}List<${describeType(type.element)}>`;
657
+ case "set":
658
+ return `${type.readonlyView ? "readonly " : ""}Set<${describeType(type.element)}>`;
659
+ case "map":
660
+ return `${type.readonlyView ? "readonly " : ""}Map<${describeType(type.key)}, ${describeType(type.value)}>`;
661
+ case "record":
662
+ return `${type.readonlyView ? "readonly " : ""}Record<${describeType(type.value)}>`;
663
+ case "promise":
664
+ return `Promise<${describeType(type.value)}>`;
665
+ case "runtimeType":
666
+ return `Type<${describeType(type.value)}>`;
667
+ case "object":
668
+ return `${type.readonlyView ? "readonly " : ""}{ ${[...type.fields].map(([name, value]) => `${type.readonlyFields?.has(name) ? "readonly " : ""}${name}${type.optionalFields?.has(name) ? "?" : ""}: ${describeType(value)}`).join(", ")} }`;
669
+ case "named":
670
+ return `${type.readonlyView ? "readonly " : ""}${type.name}`;
671
+ case "parameter":
672
+ case "class":
673
+ case "enum":
674
+ return type.name;
675
+ case "enumMember":
676
+ return `${type.name}.${type.member}`;
677
+ case "typeObject":
678
+ case "classConstructor":
679
+ return type.name;
680
+ case "enumObject":
681
+ return `enum ${type.name}`;
682
+ case "extension": {
683
+ if (type.display.kind === "named")
684
+ return type.display.name;
685
+ if (type.display.kind === "constructor")
686
+ return `${type.display.prefix} ${type.display.name}`;
687
+ const display = type.display;
688
+ const properties = [...type.properties]
689
+ .filter(([name, value]) => {
690
+ if (type.requiredProperties.has(name))
691
+ return true;
692
+ const hidden = display.hiddenOptionalProperties?.get(name);
693
+ return hidden === undefined || describeType(value) !== hidden;
694
+ })
695
+ .map(([name, value]) => `${name}${type.requiredProperties.has(name) ? "" : "?"}: ${describeType(value)}`);
696
+ if (properties.length === 0 && type.arguments.length === 0)
697
+ return display.name;
698
+ return `${display.name}<(${properties.join(", ")}) -> ${display.result}${type.arguments.map((argument) => `, ${describeType(argument)}`).join("")}>`;
699
+ }
700
+ case "function":
701
+ case "action":
702
+ case "intrinsic":
703
+ return `${type.kind === "action" ? "action " : ""}${type.typeParameterNames?.length ? `<${type.typeParameterNames.join(", ")}>` : ""}(${[
704
+ ...type.parameters.map((parameter, index) => {
705
+ const described = describeType(parameter);
706
+ const labeled = type.parameterNames?.[index] ? `${type.parameterNames[index]}: ${described}` : described;
707
+ return index >= type.requiredParameters
708
+ ? `${labeled} = default`
709
+ : labeled;
710
+ }),
711
+ ...(type.rest ? [`...${describeType(type.rest)}`] : []),
712
+ ].join(", ")}) -> ${describeType(type.result)}`;
713
+ case "union":
714
+ return type.members.map(describeType).join(" | ");
715
+ }
716
+ }
717
+ function invariant(actual, expected, environment, seen) {
718
+ return isAssignable(actual, expected, environment, new Set(seen))
719
+ && isAssignable(expected, actual, environment, new Set(seen));
720
+ }
721
+ export function typeContainsParameter(type, matches = () => true) {
722
+ switch (type.kind) {
723
+ case "parameter":
724
+ return matches(type);
725
+ case "optional":
726
+ return typeContainsParameter(type.inner, matches);
727
+ case "list":
728
+ case "set":
729
+ return typeContainsParameter(type.element, matches);
730
+ case "map":
731
+ return typeContainsParameter(type.key, matches) || typeContainsParameter(type.value, matches);
732
+ case "record":
733
+ return typeContainsParameter(type.value, matches);
734
+ case "promise":
735
+ case "runtimeType":
736
+ return typeContainsParameter(type.value, matches);
737
+ case "object":
738
+ return [...type.fields.values()].some((field) => typeContainsParameter(field, matches));
739
+ // D55 rule 121: `Box<T>` mentions T as surely as `List<T>` does, so every
740
+ // rule phrased over "does this type still mention a parameter" — erasure
741
+ // refusals, generic-callable unification — sees it without being told.
742
+ case "named":
743
+ return (type.application?.arguments ?? []).some((argument) => typeContainsParameter(argument, matches));
744
+ case "extension":
745
+ return [...type.properties.values(), ...type.arguments].some((value) => typeContainsParameter(value, matches));
746
+ case "function":
747
+ case "action":
748
+ case "intrinsic":
749
+ // A generic callable owns its parameter indexes; they are not free here.
750
+ if (type.typeParameterNames?.length)
751
+ return false;
752
+ return type.parameters.some((parameter) => typeContainsParameter(parameter, matches))
753
+ || (type.rest ? typeContainsParameter(type.rest, matches) : false)
754
+ || typeContainsParameter(type.result, matches);
755
+ case "union":
756
+ return type.members.some((member) => typeContainsParameter(member, matches));
757
+ default:
758
+ return false;
759
+ }
760
+ }
761
+ // Mirrors the recursive positions that emitTypeCheck actually inspects. A
762
+ // Type<T> value carries a compiler-known checker, but the checker object itself
763
+ // has no runtime identity for T, so accepting it in one of these positions
764
+ // would otherwise emit a predicate that can never be sound.
765
+ export function typeContainsRuntimeTypeCheck(type) {
766
+ switch (type.kind) {
767
+ case "runtimeType":
768
+ return true;
769
+ case "optional":
770
+ return typeContainsRuntimeTypeCheck(type.inner);
771
+ case "list":
772
+ case "set":
773
+ return typeContainsRuntimeTypeCheck(type.element);
774
+ case "map":
775
+ return typeContainsRuntimeTypeCheck(type.key) || typeContainsRuntimeTypeCheck(type.value);
776
+ case "record":
777
+ return typeContainsRuntimeTypeCheck(type.value);
778
+ case "object":
779
+ return [...type.fields.values()].some(typeContainsRuntimeTypeCheck);
780
+ // D55 rule 124: `Box<Type<User>>` puts the carrier in a runtime-validated
781
+ // field just as `type Holder: t: Type<User>` does, and is refused by the
782
+ // same VEL4022 at the position that wrote it — no new mechanism.
783
+ case "named":
784
+ return (type.application?.arguments ?? []).some(typeContainsRuntimeTypeCheck);
785
+ case "union":
786
+ return type.members.some(typeContainsRuntimeTypeCheck);
787
+ default:
788
+ // Promise and callable checks intentionally validate only their runtime
789
+ // carrier, just as they already do for every other erased inner type.
790
+ return false;
791
+ }
792
+ }
793
+ export function substituteTypeParameters(type, bindings) {
794
+ switch (type.kind) {
795
+ case "parameter":
796
+ return bindings[type.index] ?? unknownType;
797
+ case "optional":
798
+ return optionalOf(substituteTypeParameters(type.inner, bindings));
799
+ case "list":
800
+ case "set": {
801
+ const element = substituteTypeParameters(type.element, bindings);
802
+ return element === type.element ? type : { ...type, element };
803
+ }
804
+ case "map": {
805
+ const key = substituteTypeParameters(type.key, bindings);
806
+ const value = substituteTypeParameters(type.value, bindings);
807
+ return key === type.key && value === type.value ? type : { ...type, key, value };
808
+ }
809
+ case "record": {
810
+ const value = substituteTypeParameters(type.value, bindings);
811
+ return value === type.value ? type : { ...type, value };
812
+ }
813
+ case "promise": {
814
+ const value = substituteTypeParameters(type.value, bindings);
815
+ return value === type.value ? type : { kind: "promise", value };
816
+ }
817
+ case "runtimeType": {
818
+ const value = substituteTypeParameters(type.value, bindings);
819
+ return value === type.value ? type : { kind: "runtimeType", value };
820
+ }
821
+ case "object":
822
+ return { ...type, fields: new Map([...type.fields].map(([name, value]) => [name, substituteTypeParameters(value, bindings)])) };
823
+ // D55 rule 121: substituting inside an application rebuilds it through the
824
+ // one constructor, so the identity a generic `def` produces for `Box<T>`
825
+ // with `T := string` is the identity the analyzer registered for a written
826
+ // `Box<string>`. Two spellings of one instantiation cannot drift apart.
827
+ case "named": {
828
+ if (!type.application)
829
+ return type;
830
+ const arguments_ = type.application.arguments.map((argument) => substituteTypeParameters(argument, bindings));
831
+ if (arguments_.every((argument, index) => argument === type.application.arguments[index]))
832
+ return type;
833
+ return genericApplicationType(type.application.declaration, type.application.name, arguments_, type.readonlyView === true);
834
+ }
835
+ case "extension":
836
+ return {
837
+ ...type,
838
+ properties: new Map([...type.properties].map(([name, value]) => [name, substituteTypeParameters(value, bindings)])),
839
+ arguments: type.arguments.map((argument) => substituteTypeParameters(argument, bindings)),
840
+ };
841
+ case "function":
842
+ case "action":
843
+ case "intrinsic":
844
+ if (type.typeParameterNames?.length)
845
+ return type;
846
+ return {
847
+ ...type,
848
+ parameters: type.parameters.map((parameter) => substituteTypeParameters(parameter, bindings)),
849
+ ...(type.rest ? { rest: substituteTypeParameters(type.rest, bindings) } : {}),
850
+ result: substituteTypeParameters(type.result, bindings),
851
+ };
852
+ case "union":
853
+ return unionOf(type.members.map((member) => substituteTypeParameters(member, bindings)));
854
+ default:
855
+ return type;
856
+ }
857
+ }
858
+ export function bindNamedTypeParameters(type, parameters) {
859
+ switch (type.kind) {
860
+ case "named": {
861
+ const bound = !type.identity ? parameters.get(type.name) : undefined;
862
+ if (bound)
863
+ return bound;
864
+ // D55 rule 121: `Box<T>` inside a signature binds T exactly as a bare `T`
865
+ // does; without this the argument stayed a free name and the interface
866
+ // published a different type than the body was checked against.
867
+ return type.application
868
+ ? { ...type, application: { ...type.application, arguments: type.application.arguments.map((argument) => bindNamedTypeParameters(argument, parameters)) } }
869
+ : type;
870
+ }
871
+ case "optional":
872
+ return optionalOf(bindNamedTypeParameters(type.inner, parameters));
873
+ case "list":
874
+ case "set": {
875
+ const element = bindNamedTypeParameters(type.element, parameters);
876
+ return element === type.element ? type : { ...type, element };
877
+ }
878
+ case "map":
879
+ return { ...type, key: bindNamedTypeParameters(type.key, parameters), value: bindNamedTypeParameters(type.value, parameters) };
880
+ case "record":
881
+ return { ...type, value: bindNamedTypeParameters(type.value, parameters) };
882
+ case "promise":
883
+ return { kind: "promise", value: bindNamedTypeParameters(type.value, parameters) };
884
+ case "runtimeType":
885
+ return { kind: "runtimeType", value: bindNamedTypeParameters(type.value, parameters) };
886
+ case "object":
887
+ return { ...type, fields: new Map([...type.fields].map(([name, value]) => [name, bindNamedTypeParameters(value, parameters)])) };
888
+ case "extension":
889
+ return {
890
+ ...type,
891
+ properties: new Map([...type.properties].map(([name, value]) => [name, bindNamedTypeParameters(value, parameters)])),
892
+ arguments: type.arguments.map((argument) => bindNamedTypeParameters(argument, parameters)),
893
+ };
894
+ case "function":
895
+ case "action":
896
+ case "intrinsic":
897
+ if (type.typeParameterNames?.length)
898
+ return type;
899
+ return {
900
+ ...type,
901
+ parameters: type.parameters.map((parameter) => bindNamedTypeParameters(parameter, parameters)),
902
+ ...(type.rest ? { rest: bindNamedTypeParameters(type.rest, parameters) } : {}),
903
+ result: bindNamedTypeParameters(type.result, parameters),
904
+ };
905
+ case "union":
906
+ return { kind: "union", members: type.members.map((member) => bindNamedTypeParameters(member, parameters)) };
907
+ default:
908
+ return type;
909
+ }
910
+ }
911
+ /**
912
+ * D51 item NEW-D3: `unknown` never *binds* a parameter — merging it would erase
913
+ * every concrete actual at the other positions — but the site must still be
914
+ * remembered. A bounded parameter that only `unknown` ever reached is solved to
915
+ * `unknown`, which satisfies no bound; dropping the site silently let `unknown`
916
+ * through every bound and on into the implicit-conversion the bound forbids.
917
+ * Callers that check bounds pass this sink; the rest may ignore it.
918
+ */
919
+ export function unifyTypeParameters(pattern, actual, bindings, fieldsOf = () => null, unknownParameters) {
920
+ unifyInto(pattern, actual, bindings, fieldsOf, unknownParameters);
921
+ }
922
+ function unifyInto(pattern, actual, bindings, fieldsOf, unknownParameters) {
923
+ const unifyTypeParameters = (nextPattern, nextActual) => unifyInto(nextPattern, nextActual, bindings, fieldsOf, unknownParameters);
924
+ if (isInvalidType(actual))
925
+ return;
926
+ if (pattern.kind === "parameter") {
927
+ if (actual.kind === "unknown") {
928
+ unknownParameters?.add(pattern.index);
929
+ return;
930
+ }
931
+ const existing = bindings[pattern.index];
932
+ bindings[pattern.index] = existing ? mergeTypes(existing, actual) : actual;
933
+ return;
934
+ }
935
+ if (pattern.kind === "optional") {
936
+ if (actual.kind === "null")
937
+ return;
938
+ if (actual.kind === "optional")
939
+ return unifyTypeParameters(pattern.inner, actual.inner);
940
+ if (actual.kind === "union") {
941
+ const remaining = actual.members.filter((member) => member.kind !== "null");
942
+ if (remaining.length === 0)
943
+ return;
944
+ return unifyTypeParameters(pattern.inner, unionOf(remaining));
945
+ }
946
+ return unifyTypeParameters(pattern.inner, actual);
947
+ }
948
+ if (pattern.kind === "union") {
949
+ const concrete = pattern.members.filter((member) => !typeContainsParameter(member));
950
+ const actualMembers = actual.kind === "union" ? actual.members : [actual];
951
+ const remaining = actualMembers.filter((member) => !concrete.some((covered) => sameType(covered, member)));
952
+ if (remaining.length === 0)
953
+ return;
954
+ for (const member of pattern.members) {
955
+ if (typeContainsParameter(member))
956
+ unifyTypeParameters(member, unionOf(remaining));
957
+ }
958
+ return;
959
+ }
960
+ if ((pattern.kind === "list" && actual.kind === "list") || (pattern.kind === "set" && actual.kind === "set")) {
961
+ return unifyTypeParameters(pattern.element, actual.element);
962
+ }
963
+ if (pattern.kind === "map" && actual.kind === "map") {
964
+ unifyTypeParameters(pattern.key, actual.key);
965
+ unifyTypeParameters(pattern.value, actual.value);
966
+ return;
967
+ }
968
+ if (pattern.kind === "record" && actual.kind === "record") {
969
+ return unifyTypeParameters(pattern.value, actual.value);
970
+ }
971
+ if (pattern.kind === "promise" && actual.kind === "promise") {
972
+ return unifyTypeParameters(pattern.value, actual.value);
973
+ }
974
+ if (pattern.kind === "runtimeType") {
975
+ const value = runtimeTypeValue(actual);
976
+ if (value)
977
+ return unifyTypeParameters(pattern.value, value);
978
+ }
979
+ // D55 rule 121: `def unwrap<T>(box: Box<T>) -> T` solves T from the applied
980
+ // argument. Two applications unify only when they apply the same declaration,
981
+ // which is the nominal rule records already follow.
982
+ if (pattern.kind === "named" && pattern.application) {
983
+ if (actual.kind === "named" && actual.application
984
+ && pattern.application.declaration === actual.application.declaration) {
985
+ for (let index = 0; index < pattern.application.arguments.length; index += 1) {
986
+ const provided = actual.application.arguments[index];
987
+ if (provided)
988
+ unifyTypeParameters(pattern.application.arguments[index], provided);
989
+ }
990
+ return;
991
+ }
992
+ // A record literal is the argument a call most often actually passes, and
993
+ // it carries no application to pair with. The instantiation's own field
994
+ // table still names where each parameter stands, so the literal's fields
995
+ // solve them the same way an `object` pattern's do.
996
+ const fields = actual.kind === "object" ? actual.fields : null;
997
+ const declared = pattern.identity ? fieldsOf(pattern.identity) : null;
998
+ if (!fields || !declared)
999
+ return;
1000
+ for (const [name, field] of declared) {
1001
+ const provided = fields.get(name);
1002
+ if (provided)
1003
+ unifyTypeParameters(field, provided);
1004
+ }
1005
+ return;
1006
+ }
1007
+ if (pattern.kind === "object") {
1008
+ const fields = actual.kind === "object" ? actual.fields
1009
+ : actual.kind === "named" ? fieldsOf(actual.identity ?? actual.name)
1010
+ : null;
1011
+ if (!fields)
1012
+ return;
1013
+ for (const [name, field] of pattern.fields) {
1014
+ const provided = fields.get(name);
1015
+ if (provided)
1016
+ unifyTypeParameters(field, provided);
1017
+ }
1018
+ return;
1019
+ }
1020
+ if (pattern.kind === "extension" && actual.kind === "extension"
1021
+ && pattern.extensionId === actual.extensionId && pattern.family === actual.family) {
1022
+ for (const [name, property] of pattern.properties) {
1023
+ const provided = actual.properties.get(name);
1024
+ if (provided)
1025
+ unifyTypeParameters(property, provided);
1026
+ }
1027
+ for (let index = 0; index < pattern.arguments.length; index += 1) {
1028
+ const provided = actual.arguments[index];
1029
+ if (provided)
1030
+ unifyTypeParameters(pattern.arguments[index], provided);
1031
+ }
1032
+ return;
1033
+ }
1034
+ if ((pattern.kind === "function" || pattern.kind === "action" || pattern.kind === "intrinsic")
1035
+ && (actual.kind === "function" || actual.kind === "action" || actual.kind === "intrinsic")) {
1036
+ // A generic callable value is sealed: its parameter indexes belong to it.
1037
+ if (actual.typeParameterNames?.length)
1038
+ return;
1039
+ for (let index = 0; index < pattern.parameters.length; index += 1) {
1040
+ const provided = actual.parameters[index] ?? actual.rest;
1041
+ if (provided)
1042
+ unifyTypeParameters(pattern.parameters[index], provided);
1043
+ }
1044
+ if (pattern.rest && actual.rest)
1045
+ unifyTypeParameters(pattern.rest, actual.rest);
1046
+ unifyTypeParameters(pattern.result, actual.result);
1047
+ }
1048
+ }
1049
+ /** Every declared bound of `actual` must be promised by `expected`'s. */
1050
+ function typeParameterBoundsAccept(actual, expected) {
1051
+ const count = actual.typeParameterNames?.length ?? 0;
1052
+ for (let index = 0; index < count; index += 1) {
1053
+ if (!boundAccepts(actual.typeParameterBounds?.[index] ?? null, expected.typeParameterBounds?.[index] ?? null))
1054
+ return false;
1055
+ }
1056
+ return true;
1057
+ }
1058
+ /**
1059
+ * Reports every solved binding its declared bound rejects. `satisfiesBound` is
1060
+ * the environment's decision procedure, so the three predicates that answer a
1061
+ * bound live in exactly one place (the analyzer).
1062
+ */
1063
+ export function collectGenericBoundViolations(callable, bindings, satisfiesBound, unknownParameters) {
1064
+ return collectTypeArgumentBoundViolations(callable.typeParameterNames, callable.typeParameterBounds, bindings, satisfiesBound, unknownParameters);
1065
+ }
1066
+ /**
1067
+ * D55 rule 124: the same judgment for a declaration that is not a callable —
1068
+ * `type Box<T: Data>` applied to an argument. The callable form above is now a
1069
+ * thin caller, so a bound is decided in exactly one place no matter which
1070
+ * declaration form carries it.
1071
+ */
1072
+ export function collectTypeArgumentBoundViolations(names, bounds, bindings, satisfiesBound, unknownParameters) {
1073
+ if (!bounds?.some((bound) => bound !== null))
1074
+ return [];
1075
+ const violations = [];
1076
+ for (let index = 0; index < bounds.length; index += 1) {
1077
+ const bound = bounds[index];
1078
+ if (!bound)
1079
+ continue;
1080
+ // A parameter no argument mentioned substitutes `unknown`, which satisfies
1081
+ // nothing; checking it would report every call that leaves a parameter
1082
+ // open. A parameter an `unknown` argument *did* reach is a different fact:
1083
+ // it is solved, and solved to the one type no bound admits (NEW-D3).
1084
+ const solved = bindings[index] ?? (unknownParameters?.has(index) ? unknownType : null);
1085
+ if (solved == null)
1086
+ continue;
1087
+ if (!satisfiesBound(solved, bound)) {
1088
+ violations.push({ index, name: names?.[index] ?? `#${index + 1}`, bound, solved });
1089
+ }
1090
+ }
1091
+ return violations;
1092
+ }
1093
+ export function instantiateGenericCallable(actual, expected, environment, violations) {
1094
+ const bindings = Array.from({ length: actual.typeParameterNames?.length ?? 0 }, () => null);
1095
+ const unknownParameters = new Set();
1096
+ const fieldsOf = (identity) => environment.fieldsOf(identity);
1097
+ for (let index = 0; index < actual.parameters.length; index += 1) {
1098
+ const provided = expected.parameters[index] ?? expected.rest;
1099
+ if (provided)
1100
+ unifyTypeParameters(actual.parameters[index], provided, bindings, fieldsOf, unknownParameters);
1101
+ }
1102
+ if (actual.rest) {
1103
+ for (let index = actual.parameters.length; index < expected.parameters.length; index += 1) {
1104
+ unifyTypeParameters(actual.rest, expected.parameters[index], bindings, fieldsOf, unknownParameters);
1105
+ }
1106
+ if (expected.rest)
1107
+ unifyTypeParameters(actual.rest, expected.rest, bindings, fieldsOf, unknownParameters);
1108
+ }
1109
+ // The result position is deliberately outside the `unknown` sink: an expected
1110
+ // result of `unknown` says "the consumer accepts anything", not "the callee
1111
+ // is handed an unvalidated value". Only the input positions can force a
1112
+ // bounded parameter to be `unknown` inside the body.
1113
+ unifyTypeParameters(actual.result, expected.result, bindings, fieldsOf);
1114
+ if (violations && environment.satisfiesBound) {
1115
+ const decide = environment.satisfiesBound.bind(environment);
1116
+ violations.push(...collectGenericBoundViolations(actual, bindings, decide, unknownParameters));
1117
+ }
1118
+ const { typeParameterNames: _erased, typeParameterBounds: _erasedBounds, ...base } = actual;
1119
+ return {
1120
+ ...base,
1121
+ parameters: actual.parameters.map((parameter) => substituteTypeParameters(parameter, bindings)),
1122
+ ...(actual.rest ? { rest: substituteTypeParameters(actual.rest, bindings) } : {}),
1123
+ result: substituteTypeParameters(actual.result, bindings),
1124
+ };
1125
+ }
1126
+ function callableInputsAssignable(actual, expected, environment, seen) {
1127
+ if (actual.requiredParameters > expected.requiredParameters)
1128
+ return false;
1129
+ if (!actual.rest && (expected.rest || actual.parameters.length < expected.parameters.length))
1130
+ return false;
1131
+ for (let index = 0; index < expected.parameters.length; index += 1) {
1132
+ const accepted = actual.parameters[index] ?? actual.rest;
1133
+ if (!accepted || !isAssignable(expected.parameters[index], accepted, environment, new Set(seen)))
1134
+ return false;
1135
+ }
1136
+ if (expected.rest) {
1137
+ if (!actual.rest)
1138
+ return false;
1139
+ for (let index = expected.parameters.length; index < actual.parameters.length; index += 1) {
1140
+ if (!isAssignable(expected.rest, actual.parameters[index], environment, new Set(seen)))
1141
+ return false;
1142
+ }
1143
+ if (!isAssignable(expected.rest, actual.rest, environment, new Set(seen)))
1144
+ return false;
1145
+ }
1146
+ return true;
1147
+ }
1148
+ function objectFieldsAssignable(actual, expected, environment, seen, actualReadonly = undefined, expectedReadonly = undefined, actualOptional = undefined, expectedOptional = undefined) {
1149
+ for (const [name, expectedType] of expected) {
1150
+ const actualType = actual.get(name);
1151
+ if (!actualType) {
1152
+ if (expectedType.kind === "optional" || expectedOptional?.has(name))
1153
+ continue;
1154
+ return false;
1155
+ }
1156
+ if (actualOptional?.has(name) && expectedType.kind !== "optional" && !expectedOptional?.has(name))
1157
+ return false;
1158
+ if (expectedReadonly?.has(name)) {
1159
+ if (!isAssignable(actualType, expectedType, environment, new Set(seen)))
1160
+ return false;
1161
+ }
1162
+ else if (actualReadonly?.has(name) || !invariant(actualType, expectedType, environment, seen))
1163
+ return false;
1164
+ }
1165
+ return true;
1166
+ }
1167
+ function writableFieldsAssignable(actual, expected, environment, seen) {
1168
+ return objectFieldsAssignable(actual, expected, environment, seen);
1169
+ }
1170
+ //# sourceMappingURL=types.js.map