@rcrsr/rill 0.15.0 → 0.16.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.
Files changed (305) hide show
  1. package/dist/ast-nodes.d.ts +2 -13
  2. package/dist/ast-nodes.js +0 -1
  3. package/dist/ast-unions.d.ts +0 -1
  4. package/dist/ast-unions.js +0 -1
  5. package/dist/constants.d.ts +0 -1
  6. package/dist/constants.js +0 -1
  7. package/dist/error-classes.d.ts +0 -1
  8. package/dist/error-classes.js +0 -1
  9. package/dist/error-formatter.d.ts +0 -1
  10. package/dist/error-formatter.js +0 -1
  11. package/dist/error-registry.d.ts +0 -1
  12. package/dist/error-registry.js +32 -1
  13. package/dist/ext/crypto/index.d.ts +0 -1
  14. package/dist/ext/crypto/index.js +5 -6
  15. package/dist/ext/exec/index.d.ts +0 -1
  16. package/dist/ext/exec/index.js +3 -4
  17. package/dist/ext/exec/runner.d.ts +0 -1
  18. package/dist/ext/exec/runner.js +0 -1
  19. package/dist/ext/fetch/index.d.ts +0 -1
  20. package/dist/ext/fetch/index.js +8 -39
  21. package/dist/ext/fetch/request.d.ts +0 -1
  22. package/dist/ext/fetch/request.js +0 -1
  23. package/dist/ext/fs/index.d.ts +0 -1
  24. package/dist/ext/fs/index.js +26 -27
  25. package/dist/ext/fs/sandbox.d.ts +0 -1
  26. package/dist/ext/fs/sandbox.js +0 -1
  27. package/dist/ext/kv/index.d.ts +0 -1
  28. package/dist/ext/kv/index.js +19 -20
  29. package/dist/ext/kv/store.d.ts +0 -1
  30. package/dist/ext/kv/store.js +0 -1
  31. package/dist/generated/introspection-data.d.ts +0 -1
  32. package/dist/generated/introspection-data.js +0 -1
  33. package/dist/generated/version-data.d.ts +1 -2
  34. package/dist/generated/version-data.js +2 -3
  35. package/dist/highlight-map.d.ts +0 -1
  36. package/dist/highlight-map.js +0 -1
  37. package/dist/index.d.ts +1 -2
  38. package/dist/index.js +1 -2
  39. package/dist/lexer/errors.d.ts +0 -1
  40. package/dist/lexer/errors.js +0 -1
  41. package/dist/lexer/helpers.d.ts +0 -1
  42. package/dist/lexer/helpers.js +0 -1
  43. package/dist/lexer/index.d.ts +0 -1
  44. package/dist/lexer/index.js +0 -1
  45. package/dist/lexer/operators.d.ts +0 -1
  46. package/dist/lexer/operators.js +0 -1
  47. package/dist/lexer/readers.d.ts +0 -1
  48. package/dist/lexer/readers.js +0 -1
  49. package/dist/lexer/state.d.ts +0 -1
  50. package/dist/lexer/state.js +0 -1
  51. package/dist/lexer/tokenizer.d.ts +0 -1
  52. package/dist/lexer/tokenizer.js +0 -1
  53. package/dist/parser/helpers.d.ts +0 -1
  54. package/dist/parser/helpers.js +0 -1
  55. package/dist/parser/index.d.ts +0 -1
  56. package/dist/parser/index.js +0 -1
  57. package/dist/parser/parser-collect.d.ts +0 -1
  58. package/dist/parser/parser-collect.js +0 -1
  59. package/dist/parser/parser-control.d.ts +0 -1
  60. package/dist/parser/parser-control.js +0 -1
  61. package/dist/parser/parser-expr.d.ts +0 -1
  62. package/dist/parser/parser-expr.js +0 -1
  63. package/dist/parser/parser-extract.d.ts +0 -1
  64. package/dist/parser/parser-extract.js +0 -1
  65. package/dist/parser/parser-functions.d.ts +0 -1
  66. package/dist/parser/parser-functions.js +0 -1
  67. package/dist/parser/parser-literals.d.ts +0 -1
  68. package/dist/parser/parser-literals.js +4 -2
  69. package/dist/parser/parser-script.d.ts +0 -1
  70. package/dist/parser/parser-script.js +0 -1
  71. package/dist/parser/parser-shape.d.ts +2 -3
  72. package/dist/parser/parser-shape.js +8 -52
  73. package/dist/parser/parser-types.d.ts +28 -2
  74. package/dist/parser/parser-types.js +64 -13
  75. package/dist/parser/parser-use.d.ts +0 -1
  76. package/dist/parser/parser-use.js +0 -1
  77. package/dist/parser/parser-variables.d.ts +0 -1
  78. package/dist/parser/parser-variables.js +0 -1
  79. package/dist/parser/parser.d.ts +0 -1
  80. package/dist/parser/parser.js +0 -1
  81. package/dist/parser/state.d.ts +0 -1
  82. package/dist/parser/state.js +0 -1
  83. package/dist/runtime/core/callable.d.ts +40 -13
  84. package/dist/runtime/core/callable.js +137 -28
  85. package/dist/runtime/core/context.d.ts +0 -1
  86. package/dist/runtime/core/context.js +1 -2
  87. package/dist/runtime/core/equals.d.ts +0 -1
  88. package/dist/runtime/core/equals.js +35 -3
  89. package/dist/runtime/core/eval/base.d.ts +0 -1
  90. package/dist/runtime/core/eval/base.js +0 -1
  91. package/dist/runtime/core/eval/evaluator.d.ts +0 -1
  92. package/dist/runtime/core/eval/evaluator.js +0 -1
  93. package/dist/runtime/core/eval/index.d.ts +0 -1
  94. package/dist/runtime/core/eval/index.js +0 -1
  95. package/dist/runtime/core/eval/mixins/annotations.d.ts +0 -1
  96. package/dist/runtime/core/eval/mixins/annotations.js +0 -1
  97. package/dist/runtime/core/eval/mixins/closures.d.ts +0 -1
  98. package/dist/runtime/core/eval/mixins/closures.js +82 -60
  99. package/dist/runtime/core/eval/mixins/collections.d.ts +0 -1
  100. package/dist/runtime/core/eval/mixins/collections.js +9 -4
  101. package/dist/runtime/core/eval/mixins/control-flow.d.ts +0 -1
  102. package/dist/runtime/core/eval/mixins/control-flow.js +0 -1
  103. package/dist/runtime/core/eval/mixins/conversion.d.ts +0 -1
  104. package/dist/runtime/core/eval/mixins/conversion.js +153 -86
  105. package/dist/runtime/core/eval/mixins/core.d.ts +0 -1
  106. package/dist/runtime/core/eval/mixins/core.js +0 -1
  107. package/dist/runtime/core/eval/mixins/expressions.d.ts +0 -1
  108. package/dist/runtime/core/eval/mixins/expressions.js +0 -1
  109. package/dist/runtime/core/eval/mixins/extraction.d.ts +0 -1
  110. package/dist/runtime/core/eval/mixins/extraction.js +8 -9
  111. package/dist/runtime/core/eval/mixins/list-dispatch.d.ts +0 -1
  112. package/dist/runtime/core/eval/mixins/list-dispatch.js +0 -1
  113. package/dist/runtime/core/eval/mixins/literals.d.ts +0 -1
  114. package/dist/runtime/core/eval/mixins/literals.js +3 -7
  115. package/dist/runtime/core/eval/mixins/types.d.ts +2 -1
  116. package/dist/runtime/core/eval/mixins/types.js +222 -242
  117. package/dist/runtime/core/eval/mixins/use.d.ts +0 -1
  118. package/dist/runtime/core/eval/mixins/use.js +0 -1
  119. package/dist/runtime/core/eval/mixins/variables.d.ts +0 -1
  120. package/dist/runtime/core/eval/mixins/variables.js +6 -7
  121. package/dist/runtime/core/eval/types.d.ts +0 -1
  122. package/dist/runtime/core/eval/types.js +0 -1
  123. package/dist/runtime/core/execute.d.ts +0 -1
  124. package/dist/runtime/core/execute.js +0 -1
  125. package/dist/runtime/core/field-descriptor.d.ts +2 -3
  126. package/dist/runtime/core/field-descriptor.js +0 -1
  127. package/dist/runtime/core/introspection.d.ts +0 -1
  128. package/dist/runtime/core/introspection.js +0 -1
  129. package/dist/runtime/core/resolvers.d.ts +0 -1
  130. package/dist/runtime/core/resolvers.js +0 -1
  131. package/dist/runtime/core/signals.d.ts +0 -1
  132. package/dist/runtime/core/signals.js +0 -1
  133. package/dist/runtime/core/types.d.ts +0 -1
  134. package/dist/runtime/core/types.js +0 -1
  135. package/dist/runtime/core/values.d.ts +59 -26
  136. package/dist/runtime/core/values.js +289 -77
  137. package/dist/runtime/ext/builtins.d.ts +0 -1
  138. package/dist/runtime/ext/builtins.js +43 -17
  139. package/dist/runtime/ext/extensions.d.ts +0 -1
  140. package/dist/runtime/ext/extensions.js +0 -1
  141. package/dist/runtime/index.d.ts +2 -3
  142. package/dist/runtime/index.js +1 -2
  143. package/dist/signature-parser.d.ts +0 -1
  144. package/dist/signature-parser.js +8 -6
  145. package/dist/source-location.d.ts +0 -1
  146. package/dist/source-location.js +0 -1
  147. package/dist/token-types.d.ts +0 -1
  148. package/dist/token-types.js +0 -1
  149. package/dist/types.d.ts +0 -1
  150. package/dist/types.js +0 -1
  151. package/dist/value-types.d.ts +15 -12
  152. package/dist/value-types.js +0 -1
  153. package/package.json +2 -1
  154. package/dist/ast-nodes.d.ts.map +0 -1
  155. package/dist/ast-nodes.js.map +0 -1
  156. package/dist/ast-unions.d.ts.map +0 -1
  157. package/dist/ast-unions.js.map +0 -1
  158. package/dist/constants.d.ts.map +0 -1
  159. package/dist/constants.js.map +0 -1
  160. package/dist/error-classes.d.ts.map +0 -1
  161. package/dist/error-classes.js.map +0 -1
  162. package/dist/error-formatter.d.ts.map +0 -1
  163. package/dist/error-formatter.js.map +0 -1
  164. package/dist/error-registry.d.ts.map +0 -1
  165. package/dist/error-registry.js.map +0 -1
  166. package/dist/ext/crypto/index.d.ts.map +0 -1
  167. package/dist/ext/crypto/index.js.map +0 -1
  168. package/dist/ext/exec/index.d.ts.map +0 -1
  169. package/dist/ext/exec/index.js.map +0 -1
  170. package/dist/ext/exec/runner.d.ts.map +0 -1
  171. package/dist/ext/exec/runner.js.map +0 -1
  172. package/dist/ext/fetch/index.d.ts.map +0 -1
  173. package/dist/ext/fetch/index.js.map +0 -1
  174. package/dist/ext/fetch/request.d.ts.map +0 -1
  175. package/dist/ext/fetch/request.js.map +0 -1
  176. package/dist/ext/fs/index.d.ts.map +0 -1
  177. package/dist/ext/fs/index.js.map +0 -1
  178. package/dist/ext/fs/sandbox.d.ts.map +0 -1
  179. package/dist/ext/fs/sandbox.js.map +0 -1
  180. package/dist/ext/kv/index.d.ts.map +0 -1
  181. package/dist/ext/kv/index.js.map +0 -1
  182. package/dist/ext/kv/store.d.ts.map +0 -1
  183. package/dist/ext/kv/store.js.map +0 -1
  184. package/dist/generated/introspection-data.d.ts.map +0 -1
  185. package/dist/generated/introspection-data.js.map +0 -1
  186. package/dist/generated/version-data.d.ts.map +0 -1
  187. package/dist/generated/version-data.js.map +0 -1
  188. package/dist/highlight-map.d.ts.map +0 -1
  189. package/dist/highlight-map.js.map +0 -1
  190. package/dist/index.d.ts.map +0 -1
  191. package/dist/index.js.map +0 -1
  192. package/dist/lexer/errors.d.ts.map +0 -1
  193. package/dist/lexer/errors.js.map +0 -1
  194. package/dist/lexer/helpers.d.ts.map +0 -1
  195. package/dist/lexer/helpers.js.map +0 -1
  196. package/dist/lexer/index.d.ts.map +0 -1
  197. package/dist/lexer/index.js.map +0 -1
  198. package/dist/lexer/operators.d.ts.map +0 -1
  199. package/dist/lexer/operators.js.map +0 -1
  200. package/dist/lexer/readers.d.ts.map +0 -1
  201. package/dist/lexer/readers.js.map +0 -1
  202. package/dist/lexer/state.d.ts.map +0 -1
  203. package/dist/lexer/state.js.map +0 -1
  204. package/dist/lexer/tokenizer.d.ts.map +0 -1
  205. package/dist/lexer/tokenizer.js.map +0 -1
  206. package/dist/parser/helpers.d.ts.map +0 -1
  207. package/dist/parser/helpers.js.map +0 -1
  208. package/dist/parser/index.d.ts.map +0 -1
  209. package/dist/parser/index.js.map +0 -1
  210. package/dist/parser/parser-collect.d.ts.map +0 -1
  211. package/dist/parser/parser-collect.js.map +0 -1
  212. package/dist/parser/parser-control.d.ts.map +0 -1
  213. package/dist/parser/parser-control.js.map +0 -1
  214. package/dist/parser/parser-expr.d.ts.map +0 -1
  215. package/dist/parser/parser-expr.js.map +0 -1
  216. package/dist/parser/parser-extract.d.ts.map +0 -1
  217. package/dist/parser/parser-extract.js.map +0 -1
  218. package/dist/parser/parser-functions.d.ts.map +0 -1
  219. package/dist/parser/parser-functions.js.map +0 -1
  220. package/dist/parser/parser-literals.d.ts.map +0 -1
  221. package/dist/parser/parser-literals.js.map +0 -1
  222. package/dist/parser/parser-script.d.ts.map +0 -1
  223. package/dist/parser/parser-script.js.map +0 -1
  224. package/dist/parser/parser-shape.d.ts.map +0 -1
  225. package/dist/parser/parser-shape.js.map +0 -1
  226. package/dist/parser/parser-types.d.ts.map +0 -1
  227. package/dist/parser/parser-types.js.map +0 -1
  228. package/dist/parser/parser-use.d.ts.map +0 -1
  229. package/dist/parser/parser-use.js.map +0 -1
  230. package/dist/parser/parser-variables.d.ts.map +0 -1
  231. package/dist/parser/parser-variables.js.map +0 -1
  232. package/dist/parser/parser.d.ts.map +0 -1
  233. package/dist/parser/parser.js.map +0 -1
  234. package/dist/parser/state.d.ts.map +0 -1
  235. package/dist/parser/state.js.map +0 -1
  236. package/dist/runtime/core/callable.d.ts.map +0 -1
  237. package/dist/runtime/core/callable.js.map +0 -1
  238. package/dist/runtime/core/context.d.ts.map +0 -1
  239. package/dist/runtime/core/context.js.map +0 -1
  240. package/dist/runtime/core/equals.d.ts.map +0 -1
  241. package/dist/runtime/core/equals.js.map +0 -1
  242. package/dist/runtime/core/eval/base.d.ts.map +0 -1
  243. package/dist/runtime/core/eval/base.js.map +0 -1
  244. package/dist/runtime/core/eval/evaluator.d.ts.map +0 -1
  245. package/dist/runtime/core/eval/evaluator.js.map +0 -1
  246. package/dist/runtime/core/eval/index.d.ts.map +0 -1
  247. package/dist/runtime/core/eval/index.js.map +0 -1
  248. package/dist/runtime/core/eval/mixins/annotations.d.ts.map +0 -1
  249. package/dist/runtime/core/eval/mixins/annotations.js.map +0 -1
  250. package/dist/runtime/core/eval/mixins/closures.d.ts.map +0 -1
  251. package/dist/runtime/core/eval/mixins/closures.js.map +0 -1
  252. package/dist/runtime/core/eval/mixins/collections.d.ts.map +0 -1
  253. package/dist/runtime/core/eval/mixins/collections.js.map +0 -1
  254. package/dist/runtime/core/eval/mixins/control-flow.d.ts.map +0 -1
  255. package/dist/runtime/core/eval/mixins/control-flow.js.map +0 -1
  256. package/dist/runtime/core/eval/mixins/conversion.d.ts.map +0 -1
  257. package/dist/runtime/core/eval/mixins/conversion.js.map +0 -1
  258. package/dist/runtime/core/eval/mixins/core.d.ts.map +0 -1
  259. package/dist/runtime/core/eval/mixins/core.js.map +0 -1
  260. package/dist/runtime/core/eval/mixins/expressions.d.ts.map +0 -1
  261. package/dist/runtime/core/eval/mixins/expressions.js.map +0 -1
  262. package/dist/runtime/core/eval/mixins/extraction.d.ts.map +0 -1
  263. package/dist/runtime/core/eval/mixins/extraction.js.map +0 -1
  264. package/dist/runtime/core/eval/mixins/list-dispatch.d.ts.map +0 -1
  265. package/dist/runtime/core/eval/mixins/list-dispatch.js.map +0 -1
  266. package/dist/runtime/core/eval/mixins/literals.d.ts.map +0 -1
  267. package/dist/runtime/core/eval/mixins/literals.js.map +0 -1
  268. package/dist/runtime/core/eval/mixins/types.d.ts.map +0 -1
  269. package/dist/runtime/core/eval/mixins/types.js.map +0 -1
  270. package/dist/runtime/core/eval/mixins/use.d.ts.map +0 -1
  271. package/dist/runtime/core/eval/mixins/use.js.map +0 -1
  272. package/dist/runtime/core/eval/mixins/variables.d.ts.map +0 -1
  273. package/dist/runtime/core/eval/mixins/variables.js.map +0 -1
  274. package/dist/runtime/core/eval/types.d.ts.map +0 -1
  275. package/dist/runtime/core/eval/types.js.map +0 -1
  276. package/dist/runtime/core/execute.d.ts.map +0 -1
  277. package/dist/runtime/core/execute.js.map +0 -1
  278. package/dist/runtime/core/field-descriptor.d.ts.map +0 -1
  279. package/dist/runtime/core/field-descriptor.js.map +0 -1
  280. package/dist/runtime/core/introspection.d.ts.map +0 -1
  281. package/dist/runtime/core/introspection.js.map +0 -1
  282. package/dist/runtime/core/resolvers.d.ts.map +0 -1
  283. package/dist/runtime/core/resolvers.js.map +0 -1
  284. package/dist/runtime/core/signals.d.ts.map +0 -1
  285. package/dist/runtime/core/signals.js.map +0 -1
  286. package/dist/runtime/core/types.d.ts.map +0 -1
  287. package/dist/runtime/core/types.js.map +0 -1
  288. package/dist/runtime/core/values.d.ts.map +0 -1
  289. package/dist/runtime/core/values.js.map +0 -1
  290. package/dist/runtime/ext/builtins.d.ts.map +0 -1
  291. package/dist/runtime/ext/builtins.js.map +0 -1
  292. package/dist/runtime/ext/extensions.d.ts.map +0 -1
  293. package/dist/runtime/ext/extensions.js.map +0 -1
  294. package/dist/runtime/index.d.ts.map +0 -1
  295. package/dist/runtime/index.js.map +0 -1
  296. package/dist/signature-parser.d.ts.map +0 -1
  297. package/dist/signature-parser.js.map +0 -1
  298. package/dist/source-location.d.ts.map +0 -1
  299. package/dist/source-location.js.map +0 -1
  300. package/dist/token-types.d.ts.map +0 -1
  301. package/dist/token-types.js.map +0 -1
  302. package/dist/types.d.ts.map +0 -1
  303. package/dist/types.js.map +0 -1
  304. package/dist/value-types.d.ts.map +0 -1
  305. package/dist/value-types.js.map +0 -1
@@ -42,9 +42,9 @@
42
42
  * @internal
43
43
  */
44
44
  import { RillError, RuntimeError } from '../../../../types.js';
45
- import { isCallable, isScriptCallable, isApplicationCallable, isDict, validateCallableArgs, paramsToStructuralType, } from '../../callable.js';
45
+ import { isCallable, isScriptCallable, isApplicationCallable, isDict, marshalArgs, } from '../../callable.js';
46
46
  import { getVariable, pushCallFrame, popCallFrame, UNVALIDATED_METHOD_PARAMS, UNVALIDATED_METHOD_RECEIVERS, } from '../../context.js';
47
- import { inferType, isTypeValue, isTuple, isOrdered, createOrdered, inferStructuralType, structuralTypeMatches, formatStructuralType, anyTypeValue, } from '../../values.js';
47
+ import { inferType, isTypeValue, isTuple, isOrdered, paramToFieldDef, inferStructuralType, structuralTypeMatches, formatStructuralType, anyTypeValue, rillTypeToTypeValue, } from '../../values.js';
48
48
  /**
49
49
  * ClosuresMixin implementation.
50
50
  *
@@ -153,14 +153,22 @@ function createClosuresMixin(Base) {
153
153
  async invokeFnCallable(callable, args, callLocation, functionName = 'callable') {
154
154
  // Apply boundDict BEFORE validation (property-style callables need dict as first arg)
155
155
  const effectiveArgs = callable.boundDict && args.length === 0 ? [callable.boundDict] : args;
156
- // Validate arguments for typed ApplicationCallable (task 1.5)
156
+ // Marshal arguments for typed ApplicationCallable (IC-1).
157
157
  // Skip when params is undefined (untyped callable() factory).
158
- // Explicitly registered zero-param callables have params: [] and still validate.
158
+ // Untyped callables still receive RillValue[] cast as Record to preserve
159
+ // existing runtime behavior without changing the fn contract.
160
+ let fnArgs;
159
161
  if (isApplicationCallable(callable) && callable.params !== undefined) {
160
- validateCallableArgs(effectiveArgs, callable.params, functionName, callLocation);
162
+ fnArgs = marshalArgs(effectiveArgs, callable.params, {
163
+ functionName,
164
+ location: callLocation,
165
+ });
166
+ }
167
+ else {
168
+ fnArgs = effectiveArgs;
161
169
  }
162
170
  try {
163
- const result = callable.fn(effectiveArgs, this.ctx, callLocation);
171
+ const result = callable.fn(fnArgs, this.ctx, callLocation);
164
172
  return result instanceof Promise ? await result : result;
165
173
  }
166
174
  catch (error) {
@@ -219,28 +227,20 @@ function createClosuresMixin(Base) {
219
227
  */
220
228
  async invokeScriptCallable(callable, args, callLocation) {
221
229
  const callableCtx = this.createCallableContext(callable);
222
- // Validate excess arguments (EC-8)
223
- if (args.length > callable.params.length) {
224
- throw new RuntimeError('RILL-R001', `Function expects ${callable.params.length} arguments, got ${args.length}`, callLocation);
230
+ // Marshal positional args to named record (IC-1).
231
+ // Script callables always have params defined.
232
+ const record = marshalArgs(args, callable.params, {
233
+ functionName: '<anonymous>',
234
+ location: callLocation,
235
+ });
236
+ // Bind each named value into the callable context.
237
+ for (const [name, value] of Object.entries(record)) {
238
+ callableCtx.variables.set(name, value);
225
239
  }
226
- for (let i = 0; i < callable.params.length; i++) {
227
- const param = callable.params[i];
228
- let value;
229
- if (i < args.length) {
230
- value = args[i];
231
- }
232
- else if (param.defaultValue !== undefined) {
233
- value = param.defaultValue;
234
- }
235
- else {
236
- throw new RuntimeError('RILL-R001', `Missing argument for parameter '${param.name}' at position ${i}`, callLocation, { paramName: param.name, position: i });
237
- }
238
- this.validateParamType(param, value, callLocation);
239
- callableCtx.variables.set(param.name, value);
240
- // Block-closures have param named '$': sync with pipeValue for bare $ references
241
- if (param.name === '$') {
242
- callableCtx.pipeValue = value;
243
- }
240
+ // IR-4: Block closure pipe sync first param named '$' means block closure.
241
+ // Sync pipeValue so bare '$' references resolve correctly inside the body.
242
+ if (callable.params[0]?.name === '$') {
243
+ callableCtx.pipeValue = record['$'];
244
244
  }
245
245
  // EC-1: Reject empty block bodies before execution (AC-17)
246
246
  if (callable.body.type === 'Block' &&
@@ -557,23 +557,39 @@ function createClosuresMixin(Base) {
557
557
  const typeDict = this.ctx.typeMethodDicts.get(typeName);
558
558
  const typeMethod = typeDict?.[node.name];
559
559
  if (typeMethod !== undefined && isApplicationCallable(typeMethod)) {
560
- // AC-24 (EC-7): validate method args via typeMethod.params when set.
561
- // Methods in UNVALIDATED_METHOD_PARAMS handle their own arg validation
562
- // with specific error messages; skip generic validation for them.
563
- if (!UNVALIDATED_METHOD_PARAMS.has(node.name) &&
564
- typeMethod.params !== undefined &&
565
- typeMethod.params.length > 0) {
566
- validateCallableArgs(args, typeMethod.params, node.name, this.getNodeLocation(node));
567
- }
568
- // buildMethodEntry wraps fn(args) where args[0] = receiver and args[1..] = method args
569
- // Invoke fn directly to preserve the receiver-as-first-arg contract without
570
- // triggering invokeCallable's arity validation (params counts method args only)
560
+ // IC-1: marshalArgs handles type method dispatch.
561
+ // effectiveArgs prepends receiver as first element; after task 2.3 typeMethod.params
562
+ // will include the receiver param so the counts align.
563
+ // UNVALIDATED_METHOD_PARAMS methods handle their own validation internally;
564
+ // skip marshalArgs for them and pass the positional array via cast.
565
+ const callLocation = this.getNodeLocation(node);
566
+ const effectiveArgs = [receiver, ...args];
567
+ let methodArgs;
568
+ if (typeMethod.params === undefined) {
569
+ // Untyped method: pass positional array via cast.
570
+ methodArgs = effectiveArgs;
571
+ }
572
+ else if (UNVALIDATED_METHOD_PARAMS.has(node.name)) {
573
+ // UNVALIDATED_METHOD_PARAMS: method handles its own arity and type
574
+ // validation with custom error messages. Pass the actual user args
575
+ // via __positionalArgs so buildMethodEntry reconstructs positionalArgs
576
+ // with the correct length, letting method body arity checks fire.
577
+ methodArgs = {
578
+ receiver,
579
+ __positionalArgs: args,
580
+ };
581
+ }
582
+ else {
583
+ methodArgs = marshalArgs(effectiveArgs, typeMethod.params, {
584
+ functionName: node.name,
585
+ location: callLocation,
586
+ });
587
+ }
571
588
  try {
572
- const result = typeMethod.fn([receiver, ...args], this.ctx, this.getNodeLocation(node));
589
+ const result = typeMethod.fn(methodArgs, this.ctx, callLocation);
573
590
  return result instanceof Promise ? await result : result;
574
591
  }
575
592
  catch (error) {
576
- const callLocation = this.getNodeLocation(node);
577
593
  if (error instanceof RuntimeError &&
578
594
  !error.location &&
579
595
  callLocation) {
@@ -623,7 +639,18 @@ function createClosuresMixin(Base) {
623
639
  if (fallbackMethod !== undefined &&
624
640
  isApplicationCallable(fallbackMethod)) {
625
641
  try {
626
- const result = fallbackMethod.fn([receiver, ...args], this.ctx, this.getNodeLocation(node));
642
+ // UNVALIDATED_METHOD_RECEIVERS handle their own receiver validation.
643
+ // Build named record with receiver so buildMethodEntry extracts it correctly;
644
+ // the method body performs its own receiver type check with a custom error.
645
+ const fbMethodArgs = { receiver };
646
+ if (fallbackMethod.params) {
647
+ for (let i = 1; i < fallbackMethod.params.length; i++) {
648
+ const p = fallbackMethod.params[i];
649
+ if (p)
650
+ fbMethodArgs[p.name] = args[i - 1] ?? null;
651
+ }
652
+ }
653
+ const result = fallbackMethod.fn(fbMethodArgs, this.ctx, this.getNodeLocation(node));
627
654
  return result instanceof Promise ? await result : result;
628
655
  }
629
656
  catch (error) {
@@ -695,16 +722,16 @@ function createClosuresMixin(Base) {
695
722
  if (key === 'description') {
696
723
  return value.annotations['description'] ?? {};
697
724
  }
698
- // IR-3: ^input computes from callable.params via paramsToStructuralType() for all kinds
699
- // Params are converted from internal tuples to RillOrdered so the
700
- // value survives rill's homogeneous-list constraint.
725
+ // IR-3: ^input computes from callable.params for all kinds.
726
+ // Each param's RillType is converted to a RillTypeValue so it is recognized
727
+ // as a type token (not a plain dict) in rill's type system.
701
728
  if (key === 'input') {
702
729
  // Untyped host callables have params set to undefined at runtime (see callable() factory)
703
730
  if (value.params === undefined) {
704
- return createOrdered([]);
731
+ return rillTypeToTypeValue({ type: 'ordered', fields: [] });
705
732
  }
706
- const shape = paramsToStructuralType(value.params);
707
- return createOrdered(shape.params);
733
+ const fields = value.params.map((param) => paramToFieldDef(param.name, param.type ?? { type: 'any' }, param.defaultValue));
734
+ return rillTypeToTypeValue({ type: 'ordered', fields });
708
735
  }
709
736
  // IR-3: ^output reads callable.returnType directly for all kinds
710
737
  if (key === 'output') {
@@ -723,7 +750,14 @@ function createClosuresMixin(Base) {
723
750
  *
724
751
  * Evaluates positional args LTR, evaluates the spread expression, dispatches
725
752
  * by value type (Tuple, Ordered, or Dict), validates bindings, and returns
726
- * a Map of param name → value.
753
+ * a BoundArgs map of param name → value.
754
+ *
755
+ * Output is compatible with marshalArgs stages 2-3 (IR-1):
756
+ * - All params present in returned map (defaults applied, missing required throws)
757
+ * - Stage 1 (excess args) is NOT checked here; bindArgsToParams validates arity
758
+ * differently per spread source type (tuple length, dict key match, etc.)
759
+ * - Phase 2 callers convert BoundArgs.params to positional RillValue[] then
760
+ * feed into marshalArgs stages 2-3 for type-checking
727
761
  *
728
762
  * EC-3: bare ... with null pipe value → RuntimeError
729
763
  * EC-4: spread value is not tuple/dict/ordered → RuntimeError
@@ -835,17 +869,6 @@ function createClosuresMixin(Base) {
835
869
  finally {
836
870
  this.ctx.pipeValue = savedPipeValue;
837
871
  }
838
- // EC-8: check for missing required parameters
839
- for (const param of params) {
840
- if (!bound.has(param.name)) {
841
- if (param.defaultValue !== null && param.defaultValue !== undefined) {
842
- bound.set(param.name, param.defaultValue);
843
- }
844
- else {
845
- throw new RuntimeError('RILL-R001', `Missing required parameter '${param.name}'`, callLocation);
846
- }
847
- }
848
- }
849
872
  return { params: bound };
850
873
  }
851
874
  /**
@@ -887,4 +910,3 @@ function createClosuresMixin(Base) {
887
910
  // TypeScript can't generate declarations for functions returning classes with protected members
888
911
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
889
912
  export const ClosuresMixin = createClosuresMixin;
890
- //# sourceMappingURL=closures.js.map
@@ -21,4 +21,3 @@
21
21
  * @internal
22
22
  */
23
23
  export declare const CollectionsMixin: any;
24
- //# sourceMappingURL=collections.d.ts.map
@@ -24,7 +24,7 @@ import { RuntimeError } from '../../../../types.js';
24
24
  import { inferType, isRillIterator, isVector } from '../../values.js';
25
25
  import { createChildContext, getVariable } from '../../context.js';
26
26
  import { BreakSignal } from '../../signals.js';
27
- import { isCallable, isDict } from '../../callable.js';
27
+ import { isCallable, isDict, marshalArgs } from '../../callable.js';
28
28
  import { getEvaluator } from '../evaluator.js';
29
29
  /**
30
30
  * Default maximum iteration count for iterators.
@@ -223,9 +223,15 @@ function createCollectionsMixin(Base) {
223
223
  if (accumulator !== null) {
224
224
  args.push(accumulator);
225
225
  }
226
- // Handle both CallableFn and ApplicationCallable (task 1.5 will refactor validation)
227
226
  const fnToCall = typeof fn === 'function' ? fn : fn.fn;
228
- return fnToCall(args, this.ctx, body.span.start);
227
+ // Marshal args to named record if fn has params; cast otherwise (IC-1).
228
+ const callArgs = typeof fn !== 'function' && fn.params !== undefined
229
+ ? marshalArgs(args, fn.params, {
230
+ functionName: body.name,
231
+ location: body.span.start,
232
+ })
233
+ : args;
234
+ return fnToCall(callArgs, this.ctx, body.span.start);
229
235
  }
230
236
  default: {
231
237
  // TypeScript exhaustiveness check - should never reach here
@@ -509,4 +515,3 @@ function createCollectionsMixin(Base) {
509
515
  // TypeScript can't generate declarations for functions returning classes with protected members
510
516
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
511
517
  export const CollectionsMixin = createCollectionsMixin;
512
- //# sourceMappingURL=collections.js.map
@@ -24,4 +24,3 @@
24
24
  * @internal
25
25
  */
26
26
  export declare const ControlFlowMixin: any;
27
- //# sourceMappingURL=control-flow.d.ts.map
@@ -453,4 +453,3 @@ function createControlFlowMixin(Base) {
453
453
  // TypeScript can't generate declarations for functions returning classes with protected members
454
454
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
455
455
  export const ControlFlowMixin = createControlFlowMixin;
456
- //# sourceMappingURL=control-flow.js.map
@@ -27,4 +27,3 @@
27
27
  * @internal
28
28
  */
29
29
  export declare const ConversionMixin: any;
30
- //# sourceMappingURL=conversion.d.ts.map
@@ -27,7 +27,7 @@
27
27
  * @internal
28
28
  */
29
29
  import { RuntimeError } from '../../../../types.js';
30
- import { inferType, isTuple, isOrdered, isTypeValue, createOrdered, createTuple, formatValue, isFieldTypeWithDefault, } from '../../values.js';
30
+ import { inferType, isTuple, isOrdered, isTypeValue, createOrdered, createTuple, formatValue, deepCopyRillValue, hasCollectionFields, emptyForType, } from '../../values.js';
31
31
  import { isDict } from '../../callable.js';
32
32
  import { getVariable } from '../../context.js';
33
33
  /**
@@ -54,16 +54,31 @@ function createConversionMixin(Base) {
54
54
  const typeRef = node.typeRef;
55
55
  // Structural type constructor: :>ordered(name: type, ...) or :>list(T), :>dict(...), :>tuple(...)
56
56
  if (isTypeConstructorNode(typeRef)) {
57
- if (typeRef.constructorName === 'ordered') {
58
- return this.convertToOrderedWithSig(input, typeRef, node);
59
- }
60
- if (typeRef.constructorName === 'dict') {
61
- return this.convertToDictWithSig(input, typeRef, node);
62
- }
63
- if (typeRef.constructorName === 'tuple') {
57
+ // For dict/ordered/tuple, evaluate the type constructor to determine
58
+ // uniform (valueType) vs structural (fields/elements) dispatch.
59
+ if (typeRef.constructorName === 'ordered' ||
60
+ typeRef.constructorName === 'dict' ||
61
+ typeRef.constructorName === 'tuple') {
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ const typeValue = await this.evaluateTypeConstructor(typeRef);
64
+ const structure = typeValue.structure;
65
+ // Uniform types (valueType present): use general convert-then-assert path
66
+ if ('valueType' in structure && structure.valueType) {
67
+ const result = this.applyConversion(input, typeRef.constructorName, node);
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ this.assertType(result, structure, node.span.start);
70
+ return result;
71
+ }
72
+ // Structural types (fields/elements present): use structural-specific handlers
73
+ if (typeRef.constructorName === 'ordered') {
74
+ return this.convertToOrderedWithSig(input, typeRef, node);
75
+ }
76
+ if (typeRef.constructorName === 'dict') {
77
+ return this.convertToDictWithSig(input, typeRef, node);
78
+ }
64
79
  return this.convertToTupleWithSig(input, typeRef, node);
65
80
  }
66
- // Non-dict/ordered constructors: convert first, then assert structural type
81
+ // Non-dict/ordered/tuple constructors: convert first, then assert structural type
67
82
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
83
  const typeValue = await this.evaluateTypeConstructor(typeRef);
69
84
  const result = this.applyConversion(input, typeRef.constructorName, node);
@@ -209,28 +224,45 @@ function createConversionMixin(Base) {
209
224
  * - Extra keys not in signature: omitted from result
210
225
  */
211
226
  async convertToOrderedWithSig(input, sigNode, node) {
212
- if (!isDict(input)) {
227
+ let dictInput;
228
+ if (isOrdered(input)) {
229
+ dictInput = Object.fromEntries(input.entries);
230
+ }
231
+ else if (isDict(input)) {
232
+ dictInput = input;
233
+ }
234
+ else {
213
235
  throw new RuntimeError('RILL-R036', `cannot convert ${inferType(input)} to ordered`, this.getNodeLocation(node), { source: inferType(input), target: 'ordered' });
214
236
  }
237
+ const sourceType = isOrdered(input) ? 'ordered' : 'dict';
215
238
  // Evaluate the full type constructor to get resolved fields with defaults.
216
239
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
240
  const typeValue = await this.evaluateTypeConstructor(sigNode);
218
241
  const resolvedFields = typeValue.structure.type === 'ordered' && typeValue.structure.fields
219
242
  ? typeValue.structure.fields
220
243
  : [];
221
- const dictInput = input;
222
244
  const entries = [];
223
245
  for (const field of resolvedFields) {
224
- const fieldName = field[0];
225
- const hasDefault = field.length === 3;
246
+ const fieldName = field.name;
226
247
  if (fieldName in dictInput) {
227
- entries.push([fieldName, dictInput[fieldName]]);
248
+ let fieldValue = dictInput[fieldName];
249
+ fieldValue = this.hydrateNested(fieldValue, field.type, node);
250
+ entries.push([fieldName, fieldValue]);
251
+ }
252
+ else if (field.defaultValue !== undefined) {
253
+ entries.push([
254
+ fieldName,
255
+ this.hydrateNested(deepCopyRillValue(field.defaultValue), field.type, node),
256
+ ]);
228
257
  }
229
- else if (hasDefault) {
230
- entries.push([fieldName, deepCopyRillValue(field[2])]);
258
+ else if (hasCollectionFields(field.type)) {
259
+ entries.push([
260
+ fieldName,
261
+ this.hydrateNested(emptyForType(field.type), field.type, node),
262
+ ]);
231
263
  }
232
264
  else {
233
- throw new RuntimeError('RILL-R044', `cannot convert dict to ordered: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: 'dict', target: 'ordered' });
265
+ throw new RuntimeError('RILL-R044', `cannot convert ${sourceType} to ordered: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: sourceType, target: 'ordered' });
234
266
  }
235
267
  }
236
268
  return createOrdered(entries);
@@ -246,19 +278,26 @@ function createConversionMixin(Base) {
246
278
  * - Recurses into nested dict-typed fields for nested hydration
247
279
  */
248
280
  async convertToDictWithSig(input, sigNode, node) {
249
- if (!isDict(input)) {
281
+ let dictInput;
282
+ if (isOrdered(input)) {
283
+ dictInput = Object.fromEntries(input.entries);
284
+ }
285
+ else if (isDict(input)) {
286
+ dictInput = input;
287
+ }
288
+ else {
250
289
  throw new RuntimeError('RILL-R036', `cannot convert ${inferType(input)} to dict`, this.getNodeLocation(node), { source: inferType(input), target: 'dict' });
251
290
  }
291
+ const sourceType = isOrdered(input) ? 'ordered' : 'dict';
252
292
  // Evaluate the full type constructor to get resolved fields with defaults.
253
293
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
294
  const typeValue = await this.evaluateTypeConstructor(sigNode);
255
295
  const resolvedFields = typeValue.structure.type === 'dict' && typeValue.structure.fields
256
296
  ? typeValue.structure.fields
257
297
  : {};
258
- const dictInput = input;
259
298
  const result = {};
260
299
  for (const arg of sigNode.args) {
261
- if (arg.kind !== 'named') {
300
+ if (arg.name === undefined) {
262
301
  continue;
263
302
  }
264
303
  const fieldName = arg.name;
@@ -267,21 +306,22 @@ function createConversionMixin(Base) {
267
306
  // Field present in input: use it, recursing if the field type is a nested dict
268
307
  let fieldValue = dictInput[fieldName];
269
308
  if (resolvedField !== undefined) {
270
- const innerType = isFieldTypeWithDefault(resolvedField)
271
- ? resolvedField.type
272
- : resolvedField;
273
- fieldValue = this.hydrateNestedDict(fieldValue, innerType, node);
309
+ fieldValue = this.hydrateNested(fieldValue, resolvedField.type, node);
274
310
  }
275
311
  result[fieldName] = fieldValue;
276
312
  }
277
313
  else {
278
314
  // Field missing from input: use default if available, else error
279
315
  if (resolvedField !== undefined &&
280
- isFieldTypeWithDefault(resolvedField)) {
281
- result[fieldName] = deepCopyRillValue(resolvedField.defaultValue);
316
+ resolvedField.defaultValue !== undefined) {
317
+ result[fieldName] = this.hydrateNested(deepCopyRillValue(resolvedField.defaultValue), resolvedField.type, node);
318
+ }
319
+ else if (resolvedField !== undefined &&
320
+ hasCollectionFields(resolvedField.type)) {
321
+ result[fieldName] = this.hydrateNested(emptyForType(resolvedField.type), resolvedField.type, node);
282
322
  }
283
323
  else {
284
- throw new RuntimeError('RILL-R044', `cannot convert dict to dict: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: 'dict', target: 'dict' });
324
+ throw new RuntimeError('RILL-R044', `cannot convert ${sourceType} to dict: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: sourceType, target: 'dict' });
285
325
  }
286
326
  }
287
327
  }
@@ -314,14 +354,17 @@ function createConversionMixin(Base) {
314
354
  const result = [];
315
355
  for (let i = 0; i < resolvedElements.length; i++) {
316
356
  const element = resolvedElements[i];
317
- const hasDefault = element.length === 2;
318
357
  if (i < inputEntries.length) {
319
- // Element present in input: use it directly
320
- result.push(inputEntries[i]);
358
+ // Element present in input: recurse into nested types
359
+ result.push(this.hydrateNested(inputEntries[i], element.type, node));
360
+ }
361
+ else if (element.defaultValue !== undefined) {
362
+ // Missing trailing element with default: deep copy and hydrate
363
+ result.push(this.hydrateNested(deepCopyRillValue(element.defaultValue), element.type, node));
321
364
  }
322
- else if (hasDefault) {
323
- // Missing trailing element with default: deep copy default
324
- result.push(deepCopyRillValue(element[1]));
365
+ else if (hasCollectionFields(element.type)) {
366
+ // Missing element with collection type: seed empty and hydrate
367
+ result.push(this.hydrateNested(emptyForType(element.type), element.type, node));
325
368
  }
326
369
  else {
327
370
  // Missing element without default
@@ -331,40 +374,94 @@ function createConversionMixin(Base) {
331
374
  return createTuple(result);
332
375
  }
333
376
  /**
334
- * Recursively hydrate a dict value against a nested dict RillType.
335
- * Only applies when the field type is a dict with explicit fields.
336
- * Returns the value unchanged if it is not a dict or the type has no fields.
377
+ * Recursively hydrate a value against a nested dict, ordered, or tuple RillType.
378
+ * Only applies when the field type has explicit fields/elements.
379
+ * Returns the value unchanged if the type has no fields or the value type does not match.
337
380
  */
338
- hydrateNestedDict(value, fieldType, node) {
339
- if (fieldType.type !== 'dict' || !fieldType.fields) {
340
- return value;
341
- }
342
- if (!isDict(value)) {
343
- return value;
381
+ hydrateNested(value, fieldType, node) {
382
+ if (fieldType.type === 'dict' && fieldType.fields && isDict(value)) {
383
+ const dictValue = value;
384
+ const result = {};
385
+ for (const [fieldName, resolvedField] of Object.entries(fieldType.fields)) {
386
+ if (fieldName in dictValue) {
387
+ const fieldValue = this.hydrateNested(dictValue[fieldName], resolvedField.type, node);
388
+ result[fieldName] = fieldValue;
389
+ }
390
+ else {
391
+ if (resolvedField.defaultValue !== undefined) {
392
+ result[fieldName] = this.hydrateNested(deepCopyRillValue(resolvedField.defaultValue), resolvedField.type, node);
393
+ }
394
+ else if (hasCollectionFields(resolvedField.type)) {
395
+ result[fieldName] = this.hydrateNested(emptyForType(resolvedField.type), resolvedField.type, node);
396
+ }
397
+ else {
398
+ throw new RuntimeError('RILL-R044', `cannot convert dict to dict: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: 'dict', target: 'dict' });
399
+ }
400
+ }
401
+ }
402
+ return result;
344
403
  }
345
- const dictValue = value;
346
- const result = {};
347
- for (const [fieldName, resolvedField] of Object.entries(fieldType.fields)) {
348
- if (fieldName in dictValue) {
349
- let fieldValue = dictValue[fieldName];
350
- if (isFieldTypeWithDefault(resolvedField)) {
351
- fieldValue = this.hydrateNestedDict(fieldValue, resolvedField.type, node);
404
+ else if (fieldType.type === 'ordered' && fieldType.fields) {
405
+ // Only hydrate if the runtime value is an ordered or dict; return unchanged otherwise.
406
+ if (!isOrdered(value) && !isDict(value)) {
407
+ return value;
408
+ }
409
+ const source = isOrdered(value) ? 'ordered' : 'dict';
410
+ // Build a key->value lookup from either an ordered value or a dict value.
411
+ const lookup = new Map(isOrdered(value)
412
+ ? value.entries.map(([k, v]) => [k, v])
413
+ : Object.entries(value));
414
+ const resultEntries = [];
415
+ for (const field of fieldType.fields) {
416
+ const name = field.name;
417
+ if (lookup.has(name)) {
418
+ const fieldValue = this.hydrateNested(lookup.get(name), field.type, node);
419
+ resultEntries.push([name, fieldValue]);
420
+ }
421
+ else if (field.defaultValue !== undefined) {
422
+ resultEntries.push([
423
+ name,
424
+ this.hydrateNested(deepCopyRillValue(field.defaultValue), field.type, node),
425
+ ]);
426
+ }
427
+ else if (hasCollectionFields(field.type)) {
428
+ resultEntries.push([
429
+ name,
430
+ this.hydrateNested(emptyForType(field.type), field.type, node),
431
+ ]);
352
432
  }
353
433
  else {
354
- fieldValue = this.hydrateNestedDict(fieldValue, resolvedField, node);
434
+ throw new RuntimeError('RILL-R044', `cannot convert ${source} to ordered: missing required field '${name}'`, this.getNodeLocation(node), { source, target: 'ordered' });
355
435
  }
356
- result[fieldName] = fieldValue;
357
436
  }
358
- else {
359
- if (isFieldTypeWithDefault(resolvedField)) {
360
- result[fieldName] = deepCopyRillValue(resolvedField.defaultValue);
437
+ return createOrdered(resultEntries);
438
+ }
439
+ else if (fieldType.type === 'tuple' && fieldType.elements) {
440
+ // Only hydrate if the runtime value is a tuple; return unchanged otherwise.
441
+ if (!isTuple(value)) {
442
+ return value;
443
+ }
444
+ const inputEntries = value.entries;
445
+ const resultEntries = [];
446
+ for (let i = 0; i < fieldType.elements.length; i++) {
447
+ const element = fieldType.elements[i];
448
+ if (i < inputEntries.length) {
449
+ const elementValue = this.hydrateNested(inputEntries[i], element.type, node);
450
+ resultEntries.push(elementValue);
451
+ }
452
+ else if (element.defaultValue !== undefined) {
453
+ resultEntries.push(this.hydrateNested(deepCopyRillValue(element.defaultValue), element.type, node));
454
+ }
455
+ else if (hasCollectionFields(element.type)) {
456
+ resultEntries.push(this.hydrateNested(emptyForType(element.type), element.type, node));
361
457
  }
362
458
  else {
363
- throw new RuntimeError('RILL-R044', `cannot convert dict to dict: missing required field '${fieldName}'`, this.getNodeLocation(node), { source: 'dict', target: 'dict' });
459
+ throw new RuntimeError('RILL-R044', `cannot convert tuple to tuple: missing required element at position ${i}`, this.getNodeLocation(node), { source: 'tuple', target: 'tuple' });
364
460
  }
365
461
  }
462
+ return createTuple(resultEntries);
366
463
  }
367
- return result;
464
+ return value;
368
465
  }
369
466
  /** Throw EC-10 incompatible conversion error. */
370
467
  throwIncompatible(source, target, node) {
@@ -372,35 +469,6 @@ function createConversionMixin(Base) {
372
469
  }
373
470
  };
374
471
  }
375
- /**
376
- * Deep copy a RillValue, producing a new independent value.
377
- * Handles primitives, arrays, plain dicts, and null.
378
- * Special markers (closures, tuples, ordered, vectors, type values) are returned
379
- * as-is since they are immutable by contract.
380
- */
381
- function deepCopyRillValue(value) {
382
- if (value === null || typeof value !== 'object') {
383
- return value;
384
- }
385
- if (Array.isArray(value)) {
386
- return value.map(deepCopyRillValue);
387
- }
388
- // Plain dict: copy recursively. Special markers (RillTuple, RillOrdered, etc.)
389
- // carry __rill_* own properties and are treated as immutable; return as-is.
390
- if (!('__rill_tuple' in value) &&
391
- !('__rill_ordered' in value) &&
392
- !('__rill_vector' in value) &&
393
- !('__rill_type' in value) &&
394
- !('__type' in value) &&
395
- !('__rill_field_descriptor' in value)) {
396
- const copy = {};
397
- for (const [k, v] of Object.entries(value)) {
398
- copy[k] = deepCopyRillValue(v);
399
- }
400
- return copy;
401
- }
402
- return value;
403
- }
404
472
  /**
405
473
  * Type guard: check if a TypeRef | TypeConstructorNode is a TypeConstructorNode.
406
474
  */
@@ -410,4 +478,3 @@ function isTypeConstructorNode(ref) {
410
478
  // Export with type assertion to work around TS4094 limitation
411
479
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
412
480
  export const ConversionMixin = createConversionMixin;
413
- //# sourceMappingURL=conversion.js.map
@@ -21,4 +21,3 @@
21
21
  * @internal
22
22
  */
23
23
  export declare const CoreMixin: any;
24
- //# sourceMappingURL=core.d.ts.map
@@ -753,4 +753,3 @@ function createCoreMixin(Base) {
753
753
  // TypeScript can't generate declarations for functions returning classes with protected members
754
754
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
755
755
  export const CoreMixin = createCoreMixin;
756
- //# sourceMappingURL=core.js.map
@@ -18,4 +18,3 @@
18
18
  * @internal
19
19
  */
20
20
  export declare const ExpressionsMixin: any;
21
- //# sourceMappingURL=expressions.d.ts.map