semantifold 0.3.0 → 0.5.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 (303) hide show
  1. package/README.md +61 -15
  2. package/build/index.d.ts +52 -2
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +60 -8
  5. package/build/src/artifact-path.d.ts +23 -1
  6. package/build/src/artifact-path.d.ts.map +1 -1
  7. package/build/src/artifact-path.js +45 -3
  8. package/build/src/artifacts.d.ts.map +1 -1
  9. package/build/src/artifacts.js +66 -1
  10. package/build/src/backends/android.d.ts +49 -0
  11. package/build/src/backends/android.d.ts.map +1 -0
  12. package/build/src/backends/android.js +1274 -0
  13. package/build/src/backends/c-validation.d.ts.map +1 -1
  14. package/build/src/backends/c-validation.js +7 -3
  15. package/build/src/backends/cpp-validation.d.ts.map +1 -1
  16. package/build/src/backends/cpp-validation.js +7 -3
  17. package/build/src/backends/csharp.js +7 -1
  18. package/build/src/backends/dart-runtime.d.ts +2 -0
  19. package/build/src/backends/dart-runtime.d.ts.map +1 -0
  20. package/build/src/backends/dart-runtime.js +41 -0
  21. package/build/src/backends/dart.d.ts +20 -0
  22. package/build/src/backends/dart.d.ts.map +1 -0
  23. package/build/src/backends/dart.js +321 -0
  24. package/build/src/backends/effects.d.ts +60 -0
  25. package/build/src/backends/effects.d.ts.map +1 -0
  26. package/build/src/backends/effects.js +746 -0
  27. package/build/src/backends/go.js +18 -4
  28. package/build/src/backends/identifiers.d.ts +36 -4
  29. package/build/src/backends/identifiers.d.ts.map +1 -1
  30. package/build/src/backends/identifiers.js +160 -10
  31. package/build/src/backends/index.d.ts.map +1 -1
  32. package/build/src/backends/index.js +27 -4
  33. package/build/src/backends/ios.d.ts +68 -0
  34. package/build/src/backends/ios.d.ts.map +1 -0
  35. package/build/src/backends/ios.js +1503 -0
  36. package/build/src/backends/java.d.ts.map +1 -1
  37. package/build/src/backends/java.js +429 -36
  38. package/build/src/backends/javascript.d.ts +6 -0
  39. package/build/src/backends/javascript.d.ts.map +1 -1
  40. package/build/src/backends/javascript.js +380 -24
  41. package/build/src/backends/kotlin-runtime.d.ts +3 -0
  42. package/build/src/backends/kotlin-runtime.d.ts.map +1 -0
  43. package/build/src/backends/kotlin-runtime.js +29 -0
  44. package/build/src/backends/kotlin.d.ts +33 -0
  45. package/build/src/backends/kotlin.d.ts.map +1 -0
  46. package/build/src/backends/kotlin.js +138 -0
  47. package/build/src/backends/native-validation.d.ts +2 -2
  48. package/build/src/backends/native-validation.d.ts.map +1 -1
  49. package/build/src/backends/native-validation.js +2 -2
  50. package/build/src/backends/ordered-expressions.d.ts.map +1 -1
  51. package/build/src/backends/ordered-expressions.js +39 -7
  52. package/build/src/backends/php-stdlib-support.d.ts +19 -0
  53. package/build/src/backends/php-stdlib-support.d.ts.map +1 -0
  54. package/build/src/backends/php-stdlib-support.js +227 -0
  55. package/build/src/backends/php.d.ts.map +1 -1
  56. package/build/src/backends/php.js +448 -33
  57. package/build/src/backends/program.d.ts +83 -0
  58. package/build/src/backends/program.d.ts.map +1 -0
  59. package/build/src/backends/program.js +1309 -0
  60. package/build/src/backends/python.js +7 -1
  61. package/build/src/backends/ruby.d.ts.map +1 -1
  62. package/build/src/backends/ruby.js +310 -24
  63. package/build/src/backends/rust-runtime.d.ts +7 -0
  64. package/build/src/backends/rust-runtime.d.ts.map +1 -0
  65. package/build/src/backends/rust-runtime.js +32 -0
  66. package/build/src/backends/rust-validation.d.ts +9 -0
  67. package/build/src/backends/rust-validation.d.ts.map +1 -0
  68. package/build/src/backends/rust-validation.js +78 -0
  69. package/build/src/backends/rust.d.ts +24 -0
  70. package/build/src/backends/rust.d.ts.map +1 -0
  71. package/build/src/backends/rust.js +344 -0
  72. package/build/src/backends/scalars.d.ts +14 -6
  73. package/build/src/backends/scalars.d.ts.map +1 -1
  74. package/build/src/backends/scalars.js +167 -17
  75. package/build/src/backends/shared.d.ts +23 -4
  76. package/build/src/backends/shared.d.ts.map +1 -1
  77. package/build/src/backends/shared.js +2174 -62
  78. package/build/src/backends/stdlib-support.d.ts +14 -0
  79. package/build/src/backends/stdlib-support.d.ts.map +1 -0
  80. package/build/src/backends/stdlib-support.js +237 -0
  81. package/build/src/backends/swift-runtime.d.ts +3 -0
  82. package/build/src/backends/swift-runtime.d.ts.map +1 -0
  83. package/build/src/backends/swift-runtime.js +14 -0
  84. package/build/src/backends/swift.d.ts +8 -0
  85. package/build/src/backends/swift.d.ts.map +1 -0
  86. package/build/src/backends/swift.js +127 -0
  87. package/build/src/backends/typescript.d.ts.map +1 -1
  88. package/build/src/backends/typescript.js +344 -24
  89. package/build/src/backends/wasm.d.ts +43 -0
  90. package/build/src/backends/wasm.d.ts.map +1 -0
  91. package/build/src/backends/wasm.js +2164 -0
  92. package/build/src/backends/writer.d.ts +255 -4
  93. package/build/src/backends/writer.d.ts.map +1 -1
  94. package/build/src/backends/writer.js +491 -3
  95. package/build/src/diagnostic.d.ts +4 -3
  96. package/build/src/diagnostic.d.ts.map +1 -1
  97. package/build/src/diagnostic.js +5 -3
  98. package/build/src/frontends/c.d.ts.map +1 -1
  99. package/build/src/frontends/c.js +5 -3
  100. package/build/src/frontends/cpp.d.ts.map +1 -1
  101. package/build/src/frontends/cpp.js +5 -3
  102. package/build/src/frontends/csharp.d.ts.map +1 -1
  103. package/build/src/frontends/csharp.js +7 -3
  104. package/build/src/frontends/dart.d.ts +10 -0
  105. package/build/src/frontends/dart.d.ts.map +1 -0
  106. package/build/src/frontends/dart.js +913 -0
  107. package/build/src/frontends/index.d.ts +3 -1
  108. package/build/src/frontends/index.d.ts.map +1 -1
  109. package/build/src/frontends/index.js +15 -5
  110. package/build/src/frontends/java.d.ts +110 -1
  111. package/build/src/frontends/java.d.ts.map +1 -1
  112. package/build/src/frontends/java.js +1725 -70
  113. package/build/src/frontends/javascript-typescript.d.ts +69 -1
  114. package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
  115. package/build/src/frontends/javascript-typescript.js +1825 -93
  116. package/build/src/frontends/kotlin.d.ts +10 -0
  117. package/build/src/frontends/kotlin.d.ts.map +1 -0
  118. package/build/src/frontends/kotlin.js +685 -0
  119. package/build/src/frontends/php.d.ts +118 -1
  120. package/build/src/frontends/php.d.ts.map +1 -1
  121. package/build/src/frontends/php.js +1583 -76
  122. package/build/src/frontends/program.d.ts +74 -0
  123. package/build/src/frontends/program.d.ts.map +1 -0
  124. package/build/src/frontends/program.js +989 -0
  125. package/build/src/frontends/ruby.d.ts +68 -1
  126. package/build/src/frontends/ruby.d.ts.map +1 -1
  127. package/build/src/frontends/ruby.js +1446 -101
  128. package/build/src/frontends/rust-parser.d.ts +11 -0
  129. package/build/src/frontends/rust-parser.d.ts.map +1 -0
  130. package/build/src/frontends/rust-parser.js +15 -0
  131. package/build/src/frontends/rust.d.ts +14 -0
  132. package/build/src/frontends/rust.d.ts.map +1 -0
  133. package/build/src/frontends/rust.js +715 -0
  134. package/build/src/frontends/scalars.d.ts +10 -0
  135. package/build/src/frontends/scalars.d.ts.map +1 -1
  136. package/build/src/frontends/scalars.js +28 -2
  137. package/build/src/frontends/swift.d.ts +10 -0
  138. package/build/src/frontends/swift.d.ts.map +1 -0
  139. package/build/src/frontends/swift.js +860 -0
  140. package/build/src/frontends/types.d.ts +186 -0
  141. package/build/src/frontends/types.d.ts.map +1 -0
  142. package/build/src/frontends/types.js +634 -0
  143. package/build/src/language-registry.d.ts +46 -4
  144. package/build/src/language-registry.d.ts.map +1 -1
  145. package/build/src/language-registry.js +177 -13
  146. package/build/src/mapping.d.ts +2 -2
  147. package/build/src/mapping.d.ts.map +1 -1
  148. package/build/src/mapping.js +31 -10
  149. package/build/src/semantic/capabilities.d.ts +66 -0
  150. package/build/src/semantic/capabilities.d.ts.map +1 -0
  151. package/build/src/semantic/capabilities.js +649 -0
  152. package/build/src/semantic/effects.d.ts +26 -0
  153. package/build/src/semantic/effects.d.ts.map +1 -0
  154. package/build/src/semantic/effects.js +764 -0
  155. package/build/src/semantic/generics.d.ts +23 -0
  156. package/build/src/semantic/generics.d.ts.map +1 -0
  157. package/build/src/semantic/generics.js +61 -0
  158. package/build/src/semantic/lifetime.d.ts +37 -0
  159. package/build/src/semantic/lifetime.d.ts.map +1 -0
  160. package/build/src/semantic/lifetime.js +527 -0
  161. package/build/src/semantic/provenance.d.ts +9 -2
  162. package/build/src/semantic/provenance.d.ts.map +1 -1
  163. package/build/src/semantic/provenance.js +462 -20
  164. package/build/src/semantic/scalars.d.ts +11 -0
  165. package/build/src/semantic/scalars.d.ts.map +1 -1
  166. package/build/src/semantic/scalars.js +16 -1
  167. package/build/src/semantic/stdlib.d.ts +254 -0
  168. package/build/src/semantic/stdlib.d.ts.map +1 -0
  169. package/build/src/semantic/stdlib.js +880 -0
  170. package/build/src/semantic/types.d.ts +3108 -178
  171. package/build/src/semantic/types.d.ts.map +1 -1
  172. package/build/src/semantic/types.js +730 -15
  173. package/build/src/semantic/validate.d.ts +85 -5
  174. package/build/src/semantic/validate.d.ts.map +1 -1
  175. package/build/src/semantic/validate.js +2576 -98
  176. package/build/src/stdlib-facades.d.ts +304 -0
  177. package/build/src/stdlib-facades.d.ts.map +1 -0
  178. package/build/src/stdlib-facades.js +1167 -0
  179. package/build/src/stdlib-negotiation.d.ts +69 -0
  180. package/build/src/stdlib-negotiation.d.ts.map +1 -0
  181. package/build/src/stdlib-negotiation.js +403 -0
  182. package/build/src/stdlib-providers.d.ts +72 -0
  183. package/build/src/stdlib-providers.d.ts.map +1 -0
  184. package/build/src/stdlib-providers.js +339 -0
  185. package/build/src/toolchains.d.ts +55 -1
  186. package/build/src/toolchains.d.ts.map +1 -1
  187. package/build/src/toolchains.js +15 -4
  188. package/docs/android.md +79 -0
  189. package/docs/architecture.md +47 -13
  190. package/docs/dart.md +60 -0
  191. package/docs/goals.md +3 -3
  192. package/docs/ios.md +121 -0
  193. package/docs/kotlin.md +42 -0
  194. package/docs/language-support.md +238 -26
  195. package/docs/multi-file-modules.md +52 -0
  196. package/docs/parser-qualification.md +121 -8
  197. package/docs/plans/2026-09-05-standard-library-portability.md +10 -10
  198. package/docs/rust.md +88 -0
  199. package/docs/source-maps.md +17 -7
  200. package/docs/specification.md +5 -0
  201. package/docs/standard-library-portability.md +39 -8
  202. package/docs/swift.md +44 -0
  203. package/docs/testing.md +381 -4
  204. package/docs/webassembly.md +52 -0
  205. package/index.js +66 -8
  206. package/node_modules/semantifold-tree-sitter-legacy-internal/README.md +2 -2
  207. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/LICENSE +21 -0
  208. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/README.md +45 -0
  209. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/binding.gyp +30 -0
  210. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding.cc +20 -0
  211. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding_test.js +9 -0
  212. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.d.ts +28 -0
  213. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.js +11 -0
  214. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/grammar.js +1630 -0
  215. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/package.json +64 -0
  216. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-arm64/tree-sitter-rust.node +0 -0
  217. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-x64/tree-sitter-rust.node +0 -0
  218. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-arm64/tree-sitter-rust.node +0 -0
  219. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-x64/tree-sitter-rust.node +0 -0
  220. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-arm64/tree-sitter-rust.node +0 -0
  221. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-x64/tree-sitter-rust.node +0 -0
  222. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/highlights.scm +159 -0
  223. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/injections.scm +9 -0
  224. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/tags.scm +60 -0
  225. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/grammar.json +9405 -0
  226. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/node-types.json +5399 -0
  227. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/parser.c +192569 -0
  228. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/scanner.c +393 -0
  229. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/alloc.h +54 -0
  230. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/array.h +290 -0
  231. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/parser.h +266 -0
  232. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter-rust.wasm +0 -0
  233. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter.json +53 -0
  234. package/node_modules/semantifold-tree-sitter-legacy-internal/package.json +3 -2
  235. package/node_modules/semantifold-tree-sitter-legacy-internal/src/c.js +5 -4
  236. package/package.json +5 -2
  237. package/src/artifact-path.js +47 -2
  238. package/src/artifacts.js +67 -0
  239. package/src/backends/android.js +1370 -0
  240. package/src/backends/c-validation.js +6 -1
  241. package/src/backends/cpp-validation.js +6 -1
  242. package/src/backends/csharp.js +3 -0
  243. package/src/backends/dart-runtime.js +41 -0
  244. package/src/backends/dart.js +326 -0
  245. package/src/backends/effects.js +705 -0
  246. package/src/backends/go.js +14 -2
  247. package/src/backends/identifiers.js +166 -9
  248. package/src/backends/index.js +27 -2
  249. package/src/backends/ios.js +1612 -0
  250. package/src/backends/java.js +454 -36
  251. package/src/backends/javascript.js +389 -23
  252. package/src/backends/kotlin-runtime.js +29 -0
  253. package/src/backends/kotlin.js +144 -0
  254. package/src/backends/native-validation.js +1 -1
  255. package/src/backends/ordered-expressions.js +40 -6
  256. package/src/backends/php-stdlib-support.js +239 -0
  257. package/src/backends/php.js +469 -32
  258. package/src/backends/program.js +1408 -0
  259. package/src/backends/python.js +3 -0
  260. package/src/backends/ruby.js +326 -23
  261. package/src/backends/rust-runtime.js +34 -0
  262. package/src/backends/rust-validation.js +75 -0
  263. package/src/backends/rust.js +335 -0
  264. package/src/backends/scalars.js +141 -16
  265. package/src/backends/shared.js +2314 -115
  266. package/src/backends/stdlib-support.js +234 -0
  267. package/src/backends/swift-runtime.js +14 -0
  268. package/src/backends/swift.js +132 -0
  269. package/src/backends/typescript.js +349 -23
  270. package/src/backends/wasm.js +2208 -0
  271. package/src/backends/writer.js +545 -2
  272. package/src/diagnostic.js +4 -2
  273. package/src/frontends/c.js +4 -2
  274. package/src/frontends/cpp.js +4 -2
  275. package/src/frontends/csharp.js +4 -2
  276. package/src/frontends/dart.js +963 -0
  277. package/src/frontends/index.js +14 -4
  278. package/src/frontends/java.js +1977 -69
  279. package/src/frontends/javascript-typescript.js +2046 -102
  280. package/src/frontends/kotlin.js +713 -0
  281. package/src/frontends/php.js +1725 -79
  282. package/src/frontends/program.js +1062 -0
  283. package/src/frontends/ruby.js +1624 -98
  284. package/src/frontends/rust-parser.js +18 -0
  285. package/src/frontends/rust.js +714 -0
  286. package/src/frontends/scalars.js +31 -1
  287. package/src/frontends/swift.js +893 -0
  288. package/src/frontends/types.js +750 -0
  289. package/src/language-registry.js +182 -12
  290. package/src/mapping.js +33 -9
  291. package/src/semantic/capabilities.js +671 -0
  292. package/src/semantic/effects.js +737 -0
  293. package/src/semantic/generics.js +58 -0
  294. package/src/semantic/lifetime.js +517 -0
  295. package/src/semantic/provenance.js +412 -19
  296. package/src/semantic/scalars.js +17 -0
  297. package/src/semantic/stdlib.js +921 -0
  298. package/src/semantic/types.js +810 -14
  299. package/src/semantic/validate.js +2934 -209
  300. package/src/stdlib-facades.js +1211 -0
  301. package/src/stdlib-negotiation.js +446 -0
  302. package/src/stdlib-providers.js +377 -0
  303. package/src/toolchains.js +16 -3
@@ -0,0 +1,737 @@
1
+ // @ts-check
2
+
3
+ import {authorizedOperation, isTask034OperationName} from "./capabilities.js"
4
+ import {parseProtectedEntryName} from "./stdlib.js"
5
+
6
+ /** @typedef {{failureIds: Set<string>, host: boolean}} EffectSummary */
7
+ /** @typedef {(expression: import("./types.js").Expression) => void} ExpressionVisitor */
8
+
9
+ /**
10
+ * Resolves compiler-authorized calls before ordinary semantic type validation.
11
+ * Source functions always win; authority is never inferred from spelling alone.
12
+ * @param {import("./types.js").SemanticModule} module - Parser-authored module.
13
+ * @param {string} language - Source language identity for protected entry targets.
14
+ * @param {Map<string, import("./types.js").FunctionDeclaration>} functions - Visible ordinary functions.
15
+ * @param {(code: string, detail: string, location: import("./types.js").SourceLocation) => never} fail - Located failure.
16
+ * @param {boolean} normalize - Whether parser-authored operation intent may be normalized.
17
+ * @param {Map<string, import("./types.js").ClassDeclaration>} [visibleClasses] - Resolved reference classes.
18
+ * @returns {void}
19
+ */
20
+ export function validateEffectGraph(module, language, functions, fail, normalize, visibleClasses = new Map()) {
21
+ const capabilities = module.capabilities ?? []
22
+ const capabilityIds = new Set()
23
+ const operationIds = new Set()
24
+ const resourceIds = new Set()
25
+ const failureIds = new Set()
26
+ const operationNames = new Set()
27
+
28
+ if (!Array.isArray(capabilities)) fail("INVALID_CAPABILITY_AUTHORITY", "Capabilities must be an ordered array.", module.location)
29
+ for (const [capabilityIndex, capability] of capabilities.entries()) {
30
+ const legacyId = `capability:${capabilityIndex}`
31
+
32
+ if (!capability || capability.kind != "EffectCapabilityDeclaration" ||
33
+ capability.id != legacyId && !/^module:\d+\/capability:\d+$/u.test(capability.id) || capabilityIds.has(capability.id) ||
34
+ typeof capability.authorityId != "string" || typeof capability.name != "string" || !Array.isArray(capability.resources) ||
35
+ !Array.isArray(capability.failures) || !Array.isArray(capability.operations)) {
36
+ fail("INVALID_CAPABILITY_AUTHORITY", "Malformed capability declaration graph.", module.location)
37
+ }
38
+ capabilityIds.add(capability.id)
39
+ for (const [index, resource] of capability.resources.entries()) {
40
+ if (resource.kind != "EffectResourceDeclaration" || resource.id != `${capability.id}/resource:${index}` ||
41
+ resourceIds.has(resource.id)) fail("INVALID_CAPABILITY_AUTHORITY", "Malformed capability resource identity.", module.location)
42
+ resourceIds.add(resource.id)
43
+ }
44
+ for (const [index, failure] of capability.failures.entries()) {
45
+ if (failure.kind != "EffectFailureDeclaration" || failure.id != `${capability.id}/failure:${index}` ||
46
+ failureIds.has(failure.id)) fail("INVALID_CAPABILITY_AUTHORITY", "Malformed capability failure identity.", module.location)
47
+ failureIds.add(failure.id)
48
+ }
49
+ }
50
+ for (const capability of capabilities) {
51
+ for (const [index, operation] of capability.operations.entries()) {
52
+ if (operation.kind != "EffectOperationDeclaration" || operation.id != `${capability.id}/operation:${index}` ||
53
+ operationIds.has(operation.id) || operationNames.has(operation.name) || !Array.isArray(operation.parameters) ||
54
+ !Array.isArray(operation.failureIds) || operation.effects?.length != 1 || operation.effects[0] != "host" ||
55
+ operation.failureIds.some((id) => !failureIds.has(id))) {
56
+ fail("INVALID_CAPABILITY_AUTHORITY", "Malformed or ambiguous capability operation graph.", module.location)
57
+ }
58
+ operationIds.add(operation.id)
59
+ operationNames.add(operation.name)
60
+ }
61
+ }
62
+
63
+ for (const declaration of [
64
+ ...module.functions,
65
+ ...(module.records ?? []),
66
+ ...(module.classes ?? []),
67
+ ...(module.errors ?? [])
68
+ ]) {
69
+ if (parseProtectedEntryName(declaration.name) !== null) {
70
+ fail("STDLIB_PROTECTED_BINDING_ACCESS",
71
+ `Source declaration '${declaration.name}' captures a reserved protected provider binding.`, declaration.location)
72
+ }
73
+ }
74
+
75
+ forEachExpression(module, (expression) => {
76
+ if (expression.kind == "EffectCallExpression") {
77
+ const capability = capabilities.find(({id}) => id == expression.resolution?.capabilityId)
78
+ const operation = capability?.operations.find(({id}) => id == expression.operation)
79
+
80
+ if (operation && expression.resolution.operationId == operation.id &&
81
+ (!Array.isArray(expression.resolution.failureIds) ||
82
+ expression.resolution.failureIds.join(",") != operation.failureIds.join(","))) {
83
+ fail("UNDECLARED_FAILURE", "UNDECLARED_FAILURE: Effect call failure boundary does not match its compiler authority.",
84
+ expression.location)
85
+ }
86
+ if (!operation || expression.resolution.operationId != operation.id ||
87
+ JSON.stringify(expression.resolution) != JSON.stringify(signature(/** @type {import("./types.js").EffectCapabilityDeclaration} */ (capability), operation))) {
88
+ fail("UNDECLARED_EFFECT", "Effect call resolution does not match its compiler authority.", expression.location)
89
+ }
90
+ return
91
+ }
92
+ if (expression.kind == "IdentifierExpression" && parseProtectedEntryName(expression.name) !== null) {
93
+ fail("STDLIB_PROTECTED_BINDING_ACCESS",
94
+ `Reference to protected provider entry '${expression.name}' is not portable code.`, expression.location)
95
+ }
96
+ if (expression.kind != "CallExpression") return
97
+ if (functions.has(expression.callee)) return
98
+ let operationName = expression.callee
99
+ const protectedEntry = parseProtectedEntryName(expression.callee)
100
+
101
+ if (protectedEntry !== null) {
102
+ if (capabilities.length == 0) {
103
+ fail("STDLIB_PROTECTED_BINDING_ACCESS",
104
+ `Protected provider entry '${expression.callee}' requires an explicit capability authority.`, expression.location)
105
+ }
106
+ if (protectedEntry.target != language) {
107
+ fail("STDLIB_PROTECTED_BINDING_ACCESS",
108
+ `Protected provider entry target '${protectedEntry.target}' does not match source language '${language}'.`,
109
+ expression.location)
110
+ }
111
+ operationName = protectedEntry.operation
112
+ }
113
+ const match = authorizedOperation(capabilities, operationName)
114
+
115
+ if (!match) {
116
+ if (protectedEntry !== null) {
117
+ fail("STDLIB_PROTECTED_BINDING_ACCESS",
118
+ `Protected provider entry for undeclared operation '${operationName}' has no authorized capability operation.`,
119
+ expression.location)
120
+ }
121
+ if (isTask034OperationName(operationName)) {
122
+ fail("MISSING_CAPABILITY_AUTHORITY", `Operation '${operationName}' requires explicit compiler authority.`, expression.location)
123
+ }
124
+ return
125
+ }
126
+ if (!normalize) {
127
+ fail("UNDECLARED_EFFECT", `Caller-authored ordinary call '${expression.callee}' cannot forge a capability operation.`, expression.location)
128
+ }
129
+ const {capability, operation} = match
130
+ const flow = operation.resourceFlow
131
+
132
+ if ((flow.kind == "borrow" || flow.kind == "close") && expression.arguments[flow.parameterIndex]) {
133
+ const argument = expression.arguments[flow.parameterIndex]
134
+ if (argument.kind != "IdentifierExpression" && argument.kind != "PrivateFieldRead" && argument.kind != "ReceiverExpression") {
135
+ fail("INVALID_RESOURCE_BORROW", "An owned borrow must name one immediate resource place.", argument.location)
136
+ }
137
+ expression.arguments[flow.parameterIndex] = {
138
+ expression: argument,
139
+ kind: "OwnedBorrowExpression",
140
+ location: argument.location,
141
+ mode: flow.kind == "close" ? "exclusive" : "shared",
142
+ sourceProvenance: argument.sourceProvenance,
143
+ type: /** @type {import("./types.js").OwnedResourceType | import("./types.js").OwnedReferenceType} */ (
144
+ operation.parameters[flow.parameterIndex].type
145
+ )
146
+ }
147
+ }
148
+ const replacement = /** @type {import("./types.js").EffectCallExpression} */ (/** @type {unknown} */ (expression))
149
+ delete /** @type {{callee?: string}} */ (replacement).callee
150
+ replacement.kind = "EffectCallExpression"
151
+ replacement.operation = operation.id
152
+ replacement.resolution = signature(capability, operation)
153
+ })
154
+
155
+ const complete = completeEffectSummaries(module, failureIds, visibleClasses)
156
+ const summaries = complete.functions
157
+ const methodSummaries = complete.methods
158
+ const constructorSummaries = complete.constructors
159
+
160
+ for (const declaration of module.classes ?? []) {
161
+ applyDeclarationSummary(declaration.constructor,
162
+ constructorSummaries.get(/** @type {string} */ (declaration.constructor.id)), normalize, fail)
163
+ for (const method of declaration.methods) {
164
+ applyDeclarationSummary(method, methodSummaries.get(/** @type {string} */ (method.id)), normalize, fail)
165
+ }
166
+ }
167
+ let site = 0
168
+
169
+ forEachExpression(module, (expression) => {
170
+ if (expression.kind == "EffectCallExpression") {
171
+ if (normalize) expression.effectSiteId = `effect:${site}`
172
+ else validateSite(expression, site, fail)
173
+ site += 1
174
+ return
175
+ }
176
+ if (expression.kind == "CallExpression") {
177
+ const summary = summaries.get(expression.callee)
178
+ if (!summary?.host) {
179
+ if (normalize) {
180
+ delete expression.effectSiteId
181
+ delete expression.effects
182
+ delete expression.failureIds
183
+ }
184
+ if (!normalize && Array.isArray(expression.failureIds) && expression.failureIds.length > 0) {
185
+ fail("UNDECLARED_FAILURE", "UNDECLARED_FAILURE: Pure call carries a forged typed failure boundary.", expression.location)
186
+ }
187
+ if (!normalize && (expression.effectSiteId !== undefined || expression.effects !== undefined || expression.failureIds !== undefined)) {
188
+ fail("UNDECLARED_EFFECT", "Pure call carries forged effect metadata.", expression.location)
189
+ }
190
+ return
191
+ }
192
+ if (normalize) {
193
+ expression.effectSiteId = `effect:${site}`
194
+ expression.effects = ["host"]
195
+ expression.failureIds = [...summary.failureIds]
196
+ } else {
197
+ validateSite(expression, site, fail)
198
+ if (!Array.isArray(expression.failureIds) || expression.failureIds.join(",") != [...summary.failureIds].join(",")) {
199
+ fail("UNDECLARED_FAILURE", "UNDECLARED_FAILURE: Call failure boundary does not match its resolved function.", expression.location)
200
+ }
201
+ if (expression.effects?.length != 1 || expression.effects[0] != "host") {
202
+ fail("UNDECLARED_EFFECT", "Call effect summary does not match its resolved function.", expression.location)
203
+ }
204
+ }
205
+ site += 1
206
+ return
207
+ }
208
+ if (expression.kind == "MethodCallExpression" || expression.kind == "ReferenceConstruction") {
209
+ const summary = expression.kind == "MethodCallExpression"
210
+ ? methodSummaries.get(expression.method)
211
+ : constructorSummaries.get(expression.resolution?.declarationId ?? `${expression.reference.declarationId}:constructor`)
212
+ const label = expression.kind == "MethodCallExpression" ? "method call" : "construction"
213
+ if (!summary?.host) {
214
+ if (normalize) {
215
+ delete expression.effectSiteId
216
+ delete expression.effects
217
+ delete expression.failureIds
218
+ }
219
+ if (!normalize && Array.isArray(expression.failureIds) && expression.failureIds.length > 0) {
220
+ fail("UNDECLARED_FAILURE", `UNDECLARED_FAILURE: Pure ${label} carries a forged typed failure boundary.`, expression.location)
221
+ }
222
+ if (!normalize && (expression.effectSiteId !== undefined || expression.effects !== undefined || expression.failureIds !== undefined)) {
223
+ fail("UNDECLARED_EFFECT", `Pure ${label} carries forged effect metadata.`, expression.location)
224
+ }
225
+ return
226
+ }
227
+ if (normalize) {
228
+ expression.effectSiteId = `effect:${site}`
229
+ expression.effects = ["host"]
230
+ expression.failureIds = [...summary.failureIds]
231
+ } else {
232
+ validateSite(expression, site, fail)
233
+ if (!Array.isArray(expression.failureIds) || expression.failureIds.join(",") != [...summary.failureIds].join(",")) {
234
+ fail("UNDECLARED_FAILURE", `UNDECLARED_FAILURE: ${label} failure boundary does not match its resolved declaration.`, expression.location)
235
+ }
236
+ if (expression.effects?.length != 1 || expression.effects[0] != "host") {
237
+ fail("UNDECLARED_EFFECT", `${label} effect summary does not match its resolved declaration.`, expression.location)
238
+ }
239
+ }
240
+ site += 1
241
+ }
242
+ }, true)
243
+ }
244
+
245
+ /**
246
+ * Computes the joint finite fixed point across functions and resolved receiver methods.
247
+ * @param {import("./types.js").SemanticModule} module - Resolved module.
248
+ * @param {Set<string>} capabilityFailureIds - Declared capability failures.
249
+ * @param {Map<string, import("./types.js").ClassDeclaration>} visibleClasses - Resolved reference classes.
250
+ * @returns {{constructors: Map<string, EffectSummary>, functions: Map<string, EffectSummary>, methods: Map<string, EffectSummary>}} Complete summaries.
251
+ */
252
+ function completeEffectSummaries(module, capabilityFailureIds, visibleClasses) {
253
+ const importedMethods = declaredClassSummaries(visibleClasses, "methods")
254
+ let functions = effectSummaries(module.functions, new Map(), capabilityFailureIds)
255
+ let methods = directMethodSummaries(module, functions, importedMethods, capabilityFailureIds, importedMethods)
256
+
257
+ while (true) {
258
+ const nextFunctions = effectSummaries(module.functions, methods, capabilityFailureIds)
259
+ const nextMethods = directMethodSummaries(module, nextFunctions, methods, capabilityFailureIds, importedMethods)
260
+
261
+ if (sameSummaries(functions, nextFunctions) && sameSummaries(methods, nextMethods)) {
262
+ return {constructors: directConstructorSummaries(module, nextFunctions, nextMethods, capabilityFailureIds,
263
+ declaredClassSummaries(visibleClasses, "constructors")), functions: nextFunctions, methods: nextMethods}
264
+ }
265
+ functions = nextFunctions
266
+ methods = nextMethods
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Compares stable host/failure summary maps.
272
+ * @param {Map<string, EffectSummary>} left - Previous summaries.
273
+ * @param {Map<string, EffectSummary>} right - Next summaries.
274
+ * @returns {boolean} Whether the summaries are identical.
275
+ */
276
+ function sameSummaries(left, right) {
277
+ if (left.size != right.size) return false
278
+ for (const [name, summary] of left) {
279
+ const candidate = right.get(name)
280
+
281
+ if (!candidate || summary.host != candidate.host || summary.failureIds.size != candidate.failureIds.size ||
282
+ [...summary.failureIds].some((id) => !candidate.failureIds.has(id))) return false
283
+ }
284
+ return true
285
+ }
286
+
287
+ /**
288
+ * Builds the complete immutable resolution recorded at an effect call site.
289
+ * @param {import("./types.js").EffectCapabilityDeclaration} capability - Declaring capability.
290
+ * @param {import("./types.js").EffectOperationDeclaration} operation - Resolved operation.
291
+ * @returns {import("./types.js").ResolvedEffectOperationSignature} Complete resolution.
292
+ */
293
+ function signature(capability, operation) {
294
+ return {
295
+ capabilityId: capability.id,
296
+ effects: /** @type {const} */ (["host"]),
297
+ failureIds: [...operation.failureIds],
298
+ kind: /** @type {const} */ ("ResolvedEffectOperationSignature"),
299
+ operationId: operation.id,
300
+ parameterTypes: operation.parameters.map(({type}) => /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(type))),
301
+ resourceFlow: structuredClone(operation.resourceFlow),
302
+ returnType: typeIdentity(operation.returnType)
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Removes locations and provenance from one resolved type.
308
+ * @param {import("./types.js").SemanticFunctionReturnType} type - Semantic type.
309
+ * @returns {import("./types.js").FunctionReturnTypeIdentity} Stable type identity.
310
+ */
311
+ function typeIdentity(type) {
312
+ if (type.kind == "TypeReference") return type.name
313
+ if (type.kind == "OwnedResourceType") return {kind: type.kind, resourceId: type.resourceId}
314
+ if (type.kind == "OwnedReferenceType") return {declarationId: type.declarationId, kind: type.kind}
315
+ if (type.kind == "OptionalType") return {kind: type.kind,
316
+ valueType: /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(type.valueType))}
317
+ if (type.kind == "ListType") return {
318
+ elementType: /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(type.elementType)), kind: type.kind}
319
+ if (type.kind == "MapType" || type.kind == "OrderedMapType") {
320
+ const keyType = /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(type.keyType))
321
+ const valueType = /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(type.valueType))
322
+
323
+ return type.kind == "OrderedMapType" ? {keyType, kind: type.kind, order: "insertion", valueType} :
324
+ {keyType, kind: type.kind, valueType}
325
+ }
326
+ if (type.kind == "RecordType") return {arguments: type.arguments?.map((argument) =>
327
+ /** @type {import("./types.js").SemanticTypeIdentity} */ (typeIdentity(argument))), declarationId: type.declarationId, kind: type.kind}
328
+ if (type.kind == "ReferenceType") return {declarationId: type.declarationId, kind: type.kind}
329
+ return {kind: type.kind, parameterId: type.parameterId}
330
+ }
331
+
332
+ /**
333
+ * Computes the fixed-point host-effect summary for ordinary functions.
334
+ * @param {import("./types.js").FunctionDeclaration[]} functions - Module functions.
335
+ * @param {Map<string, EffectSummary>} [methodSummaries] - Receiver-call summaries from the current fixed-point round.
336
+ * @param {Set<string>} [capabilityFailureIds] - Capability failures eligible for call-site propagation.
337
+ * @returns {Map<string, EffectSummary>} Summaries by source function name.
338
+ */
339
+ function effectSummaries(functions, methodSummaries = new Map(), capabilityFailureIds = new Set()) {
340
+ const summaries = new Map(functions.map(({name}) => /** @type {[string, EffectSummary]} */ (
341
+ [name, {failureIds: new Set(), host: false}]
342
+ )))
343
+ let changed = true
344
+
345
+ while (changed) {
346
+ changed = false
347
+ for (const declaration of functions) {
348
+ const summary = summaries.get(declaration.name)
349
+ if (!summary) continue
350
+ forEachBlockExpression(declaration.body, (expression) => {
351
+ if (expression.kind == "EffectCallExpression") {
352
+ if (!summary.host) { summary.host = true; changed = true }
353
+ } else if (expression.kind == "CallExpression") {
354
+ const called = summaries.get(expression.callee)
355
+ if (called?.host && !summary.host) { summary.host = true; changed = true }
356
+ } else if (expression.kind == "MethodCallExpression") {
357
+ const called = methodSummaries.get(expression.method)
358
+ if (called?.host && !summary.host) { summary.host = true; changed = true }
359
+ }
360
+ }, false)
361
+ const escaping = escapingBlockFailures(declaration.body, summaries, methodSummaries, capabilityFailureIds)
362
+
363
+ for (const id of escaping) if (!summary.failureIds.has(id)) { summary.failureIds.add(id); changed = true }
364
+ }
365
+ }
366
+ return summaries
367
+ }
368
+
369
+ /**
370
+ * Computes the capability failures escaping one structured block.
371
+ * @param {import("./types.js").Block} block - Function body.
372
+ * @param {Map<string, EffectSummary>} functionSummaries - Current function fixed point.
373
+ * @param {Map<string, EffectSummary>} methodSummaries - Resolved method summaries.
374
+ * @param {Set<string>} capabilityFailureIds - Declared capability failures.
375
+ * @returns {Set<string>} Escaping failure identities.
376
+ */
377
+ function escapingBlockFailures(block, functionSummaries, methodSummaries, capabilityFailureIds) {
378
+ const result = new Set()
379
+
380
+ for (const statement of block.statements) {
381
+ if (statement.kind == "TryStatement") {
382
+ const body = escapingBlockFailures(statement.body, functionSummaries, methodSummaries, capabilityFailureIds)
383
+
384
+ if (body.delete(statement.catchType.declarationId)) {
385
+ addFailures(result, escapingBlockFailures(statement.catchBody, functionSummaries, methodSummaries, capabilityFailureIds))
386
+ }
387
+ addFailures(result, body)
388
+ continue
389
+ }
390
+ for (const expression of statementExpressions(statement)) {
391
+ addExpressionFailures(result, expression, functionSummaries, methodSummaries)
392
+ }
393
+ if (statement.kind == "RaiseStatement" && capabilityFailureIds.has(statement.error.error.declarationId)) {
394
+ result.add(statement.error.error.declarationId)
395
+ }
396
+ for (const child of statementBlocks(statement)) {
397
+ addFailures(result, escapingBlockFailures(child, functionSummaries, methodSummaries, capabilityFailureIds))
398
+ }
399
+ }
400
+ return result
401
+ }
402
+
403
+ /**
404
+ * Adds failures evaluated by one expression subtree.
405
+ * @param {Set<string>} target - Destination identities.
406
+ * @param {import("./types.js").Expression} expression - Expression root.
407
+ * @param {Map<string, EffectSummary>} functionSummaries - Function summaries.
408
+ * @param {Map<string, EffectSummary>} methodSummaries - Method summaries.
409
+ * @returns {void}
410
+ */
411
+ function addExpressionFailures(target, expression, functionSummaries, methodSummaries) {
412
+ if (expression.kind == "EffectCallExpression") addFailures(target, expression.resolution.failureIds)
413
+ else if (expression.kind == "CallExpression") addFailures(target, functionSummaries.get(expression.callee)?.failureIds ?? [])
414
+ else if (expression.kind == "MethodCallExpression") addFailures(target, methodSummaries.get(expression.method)?.failureIds ?? [])
415
+ for (const child of expressionChildren(expression)) addExpressionFailures(target, child, functionSummaries, methodSummaries)
416
+ }
417
+
418
+ /**
419
+ * Returns directly evaluated expressions for one statement.
420
+ * @param {import("./types.js").Statement} statement - Statement.
421
+ * @returns {import("./types.js").Expression[]} Expression roots.
422
+ */
423
+ function statementExpressions(statement) {
424
+ if (statement.kind == "LocalDeclaration") return [statement.initializer]
425
+ if (statement.kind == "AssignmentStatement" || statement.kind == "PrivateFieldWriteStatement" ||
426
+ statement.kind == "ExpressionStatement" || statement.kind == "PrintStatement") return [statement.expression]
427
+ if (statement.kind == "ReturnStatement") return statement.expression ? [statement.expression] : []
428
+ if (statement.kind == "RaiseStatement") return [statement.error.message]
429
+ if (statement.kind == "IfStatement" || statement.kind == "WhileStatement") return [statement.condition]
430
+ if (statement.kind == "ForEachStatement") return [statement.list]
431
+ if (statement.kind == "ForEachMapStatement") return [statement.map]
432
+ return []
433
+ }
434
+
435
+ /**
436
+ * Returns nested blocks whose failures propagate through one statement.
437
+ * @param {import("./types.js").Statement} statement - Statement.
438
+ * @returns {import("./types.js").Block[]} Child blocks.
439
+ */
440
+ function statementBlocks(statement) {
441
+ if (statement.kind == "IfStatement") return [statement.consequent, ...(statement.alternate ? [statement.alternate] : [])]
442
+ if (statement.kind == "WhileStatement" || statement.kind == "ForEachStatement" || statement.kind == "ForEachMapStatement") {
443
+ return [statement.body]
444
+ }
445
+ return []
446
+ }
447
+
448
+ /**
449
+ * Adds an iterable of failure identities to a set.
450
+ * @param {Set<string>} target - Destination.
451
+ * @param {Iterable<string>} source - Source identities.
452
+ * @returns {void}
453
+ */
454
+ function addFailures(target, source) {
455
+ for (const id of source) target.add(id)
456
+ }
457
+
458
+ /**
459
+ * Computes bounded direct summaries for class methods.
460
+ * @param {import("./types.js").SemanticModule} module - Resolved module.
461
+ * @param {Map<string, EffectSummary>} functionSummaries - Ordinary function summaries.
462
+ * @param {Map<string, EffectSummary>} priorMethodSummaries - Receiver summaries from the previous fixed-point round.
463
+ * @param {Set<string>} capabilityFailureIds - Declared capability failures.
464
+ * @param {Map<string, EffectSummary>} baseSummaries - Imported receiver summaries.
465
+ * @returns {Map<string, EffectSummary>} Summaries by resolved method identity.
466
+ */
467
+ function directMethodSummaries(module, functionSummaries, priorMethodSummaries, capabilityFailureIds, baseSummaries = new Map()) {
468
+ /** @type {Map<string, EffectSummary>} */
469
+ const summaries = new Map(baseSummaries)
470
+
471
+ for (const declaration of module.classes ?? []) {
472
+ for (const method of declaration.methods) {
473
+ /** @type {EffectSummary} */
474
+ const summary = {failureIds: escapingBlockFailures(method.body, functionSummaries, priorMethodSummaries, capabilityFailureIds), host: false}
475
+
476
+ forEachBlockExpression(method.body, (expression) => {
477
+ if (expression.kind == "EffectCallExpression") {
478
+ summary.host = true
479
+ const flow = expression.resolution.resourceFlow
480
+ const argument = flow.kind == "borrow" || flow.kind == "close" ? expression.arguments[flow.parameterIndex] : undefined
481
+ const borrowedParameterName = argument?.kind == "OwnedBorrowExpression" && argument.expression.kind == "IdentifierExpression"
482
+ ? argument.expression.name : undefined
483
+ const knownOpenBorrow = declaration.ownership?.kind == "ownedResource" && argument?.kind == "OwnedBorrowExpression" && (
484
+ argument.expression.kind == "PrivateFieldRead" && argument.expression.field == declaration.ownership.fieldId ||
485
+ borrowedParameterName !== undefined && method.parameters.some((parameter) =>
486
+ parameter.name == borrowedParameterName &&
487
+ (parameter.type.kind == "OwnedResourceType" || parameter.type.kind == "OwnedReferenceType"))
488
+ )
489
+ const terminalFailureId = knownOpenBorrow
490
+ ? flow.kind == "borrow" || flow.kind == "close" ? flow.terminalFailureId : undefined
491
+ : undefined
492
+
493
+ if (terminalFailureId) summary.failureIds.delete(terminalFailureId)
494
+ } else if (expression.kind == "CallExpression") {
495
+ const called = functionSummaries.get(expression.callee)
496
+ if (called?.host) summary.host = true
497
+ } else if (expression.kind == "MethodCallExpression") {
498
+ const called = priorMethodSummaries.get(expression.method)
499
+ if (called?.host) summary.host = true
500
+ }
501
+ }, false)
502
+ summaries.set(/** @type {string} */ (method.id), summary)
503
+ }
504
+ }
505
+ return summaries
506
+ }
507
+
508
+ /**
509
+ * Reads checked summaries already proved on imported class declarations.
510
+ * @param {Map<string, import("./types.js").ClassDeclaration>} classes - Visible classes.
511
+ * @param {"constructors" | "methods"} kind - Declaration cohort.
512
+ * @returns {Map<string, EffectSummary>} Imported summaries by declaration identity.
513
+ */
514
+ function declaredClassSummaries(classes, kind) {
515
+ /** @type {Map<string, EffectSummary>} */
516
+ const summaries = new Map()
517
+
518
+ for (const declaration of classes.values()) {
519
+ const members = kind == "constructors" ? [declaration.constructor] : declaration.methods
520
+
521
+ for (const member of members) {
522
+ if (member.effects?.length == 1 && member.effects[0] == "host" && Array.isArray(member.failureIds)) {
523
+ summaries.set(/** @type {string} */ (member.id), {failureIds: new Set(member.failureIds), host: true})
524
+ }
525
+ }
526
+ }
527
+ return summaries
528
+ }
529
+
530
+ /**
531
+ * Computes direct constructor effects after function and method fixed points stabilize.
532
+ * @param {import("./types.js").SemanticModule} module - Resolved module.
533
+ * @param {Map<string, EffectSummary>} functionSummaries - Stable function summaries.
534
+ * @param {Map<string, EffectSummary>} methodSummaries - Stable method summaries.
535
+ * @param {Set<string>} capabilityFailureIds - Declared capability failures.
536
+ * @param {Map<string, EffectSummary>} baseSummaries - Imported constructor summaries.
537
+ * @returns {Map<string, EffectSummary>} Constructor summaries by identity.
538
+ */
539
+ function directConstructorSummaries(module, functionSummaries, methodSummaries, capabilityFailureIds, baseSummaries) {
540
+ const summaries = new Map(baseSummaries)
541
+
542
+ for (const declaration of module.classes ?? []) {
543
+ const constructor = declaration.constructor
544
+ /** @type {EffectSummary} */
545
+ const summary = {
546
+ failureIds: escapingBlockFailures(constructor.body, functionSummaries, methodSummaries, capabilityFailureIds),
547
+ host: false
548
+ }
549
+
550
+ forEachBlockExpression(constructor.body, (expression) => {
551
+ if (expression.kind == "EffectCallExpression") summary.host = true
552
+ else if (expression.kind == "CallExpression" && functionSummaries.get(expression.callee)?.host) summary.host = true
553
+ else if (expression.kind == "MethodCallExpression" && methodSummaries.get(expression.method)?.host) summary.host = true
554
+ }, false)
555
+ summaries.set(/** @type {string} */ (constructor.id), summary)
556
+ }
557
+ return summaries
558
+ }
559
+
560
+ /**
561
+ * Records or verifies one checked class-member summary.
562
+ * @param {import("./types.js").ConstructorDeclaration | import("./types.js").MethodDeclaration} declaration - Class member.
563
+ * @param {EffectSummary | undefined} summary - Computed summary.
564
+ * @param {boolean} normalize - Whether metadata may be written.
565
+ * @param {(code: string, detail: string, location: import("./types.js").SourceLocation) => never} fail - Located failure.
566
+ * @returns {void}
567
+ */
568
+ function applyDeclarationSummary(declaration, summary, normalize, fail) {
569
+ if (!summary?.host) {
570
+ if (normalize) {
571
+ delete declaration.effects
572
+ delete declaration.failureIds
573
+ } else if (declaration.effects !== undefined || declaration.failureIds !== undefined) {
574
+ fail("UNDECLARED_EFFECT", "Pure class member carries forged effect metadata.", declaration.location)
575
+ }
576
+ return
577
+ }
578
+ const failureIds = [...summary.failureIds]
579
+
580
+ if (normalize) {
581
+ declaration.effects = ["host"]
582
+ declaration.failureIds = failureIds
583
+ } else if (declaration.effects?.length != 1 || declaration.effects[0] != "host" ||
584
+ !Array.isArray(declaration.failureIds) || declaration.failureIds.join(",") != failureIds.join(",")) {
585
+ fail("UNDECLARED_EFFECT", "Class member effect summary does not match its body.", declaration.location)
586
+ }
587
+ }
588
+
589
+ /**
590
+ * Validates one deterministic effect-site identity.
591
+ * @param {import("./types.js").CallExpression | import("./types.js").EffectCallExpression | import("./types.js").MethodCallExpression | import("./types.js").ReferenceConstruction} expression - Effectful call.
592
+ * @param {number} site - Expected traversal index.
593
+ * @param {(code: string, detail: string, location: import("./types.js").SourceLocation) => never} fail - Located failure.
594
+ * @returns {void}
595
+ */
596
+ function validateSite(expression, site, fail) {
597
+ if (expression.effectSiteId != `effect:${site}`) {
598
+ fail("INVALID_EFFECT_ORDER", `Effect site '${String(expression.effectSiteId)}' is not expected site 'effect:${site}'.`, expression.location)
599
+ }
600
+ }
601
+
602
+ /**
603
+ * Visits every expression in deterministic declaration and evaluation order.
604
+ * @param {import("./types.js").SemanticModule} module - Module to traverse.
605
+ * @param {ExpressionVisitor} visitor - Expression visitor.
606
+ * @param {boolean} [postorder] - Visit children before parents.
607
+ * @returns {void}
608
+ */
609
+ function forEachExpression(module, visitor, postorder = false) {
610
+ for (const declaration of module.classes ?? []) {
611
+ forEachBlockExpression(declaration.constructor.body, visitor, postorder)
612
+ for (const method of declaration.methods) forEachBlockExpression(method.body, visitor, postorder)
613
+ }
614
+ for (const declaration of module.functions) forEachBlockExpression(declaration.body, visitor, postorder)
615
+ forEachBlockExpression(module.entryPoint.body, visitor, postorder)
616
+ }
617
+
618
+ /**
619
+ * Visits expressions in one structured block.
620
+ * @param {import("./types.js").Block} block - Block to traverse.
621
+ * @param {ExpressionVisitor} visitor - Expression visitor.
622
+ * @param {boolean} postorder - Visit children before parents.
623
+ * @returns {void}
624
+ */
625
+ function forEachBlockExpression(block, visitor, postorder) {
626
+ for (const statement of block.statements) {
627
+ if (statement.kind == "LocalDeclaration") visit(statement.initializer)
628
+ else if (statement.kind == "AssignmentStatement" || statement.kind == "PrivateFieldWriteStatement") visit(statement.expression)
629
+ else if (statement.kind == "ReturnStatement" && statement.expression) visit(statement.expression)
630
+ else if (statement.kind == "ExpressionStatement" || statement.kind == "PrintStatement") visit(statement.expression)
631
+ else if (statement.kind == "IfStatement") {
632
+ visit(statement.condition); forEachBlockExpression(statement.consequent, visitor, postorder)
633
+ if (statement.alternate) forEachBlockExpression(statement.alternate, visitor, postorder)
634
+ } else if (statement.kind == "ForEachStatement") {
635
+ visit(statement.list); forEachBlockExpression(statement.body, visitor, postorder)
636
+ } else if (statement.kind == "ForEachMapStatement") {
637
+ visit(statement.map); forEachBlockExpression(statement.body, visitor, postorder)
638
+ } else if (statement.kind == "WhileStatement") {
639
+ visit(statement.condition); forEachBlockExpression(statement.body, visitor, postorder)
640
+ } else if (statement.kind == "RaiseStatement") visit(statement.error.message)
641
+ else if (statement.kind == "TryStatement") {
642
+ forEachBlockExpression(statement.body, visitor, postorder); forEachBlockExpression(statement.catchBody, visitor, postorder)
643
+ }
644
+ }
645
+
646
+ /**
647
+ * Visits one expression subtree.
648
+ * @param {import("./types.js").Expression} expression - Expression root.
649
+ * @returns {void}
650
+ */
651
+ function visit(expression) {
652
+ if (!postorder) visitor(expression)
653
+ for (const child of expressionChildren(expression)) visit(child)
654
+ if (postorder) visitor(expression)
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Reports whether one semantic block references a reserved protected provider entry.
660
+ * @param {import("./types.js").Block} block - Semantic block.
661
+ * @returns {boolean} Whether a protected entry name is referenced.
662
+ */
663
+ export function blockReferencesProtectedEntry(block) {
664
+ return block.statements.some(statementReferencesProtectedEntry)
665
+ }
666
+
667
+ /**
668
+ * Reports whether one semantic statement references a reserved protected provider entry.
669
+ * @param {import("./types.js").Statement} statement - Semantic statement.
670
+ * @returns {boolean} Whether a protected entry name is referenced.
671
+ */
672
+ function statementReferencesProtectedEntry(statement) {
673
+ switch (statement.kind) {
674
+ case "LocalDeclaration":
675
+ return expressionReferencesProtectedEntry(statement.initializer)
676
+ case "AssignmentStatement":
677
+ case "PrivateFieldWriteStatement":
678
+ return expressionReferencesProtectedEntry(statement.expression)
679
+ case "ReturnStatement":
680
+ return statement.expression ? expressionReferencesProtectedEntry(statement.expression) : false
681
+ case "ExpressionStatement":
682
+ case "PrintStatement":
683
+ return expressionReferencesProtectedEntry(statement.expression)
684
+ case "IfStatement":
685
+ return expressionReferencesProtectedEntry(statement.condition) ||
686
+ blockReferencesProtectedEntry(statement.consequent) ||
687
+ (statement.alternate ? blockReferencesProtectedEntry(statement.alternate) : false)
688
+ case "ForEachStatement":
689
+ return expressionReferencesProtectedEntry(statement.list) || blockReferencesProtectedEntry(statement.body)
690
+ case "ForEachMapStatement":
691
+ return expressionReferencesProtectedEntry(statement.map) || blockReferencesProtectedEntry(statement.body)
692
+ case "WhileStatement":
693
+ return expressionReferencesProtectedEntry(statement.condition) || blockReferencesProtectedEntry(statement.body)
694
+ case "RaiseStatement":
695
+ return expressionReferencesProtectedEntry(statement.error.message)
696
+ case "TryStatement":
697
+ return blockReferencesProtectedEntry(statement.body) || blockReferencesProtectedEntry(statement.catchBody)
698
+ default:
699
+ return false
700
+ }
701
+ }
702
+
703
+ /**
704
+ * Reports whether one semantic expression references a reserved protected provider entry.
705
+ * @param {import("./types.js").Expression} expression - Semantic expression.
706
+ * @returns {boolean} Whether a protected entry name is referenced.
707
+ */
708
+ function expressionReferencesProtectedEntry(expression) {
709
+ if (expression.kind == "IdentifierExpression" && parseProtectedEntryName(expression.name) !== null) return true
710
+ if (expression.kind == "CallExpression" && parseProtectedEntryName(expression.callee) !== null) return true
711
+ return expressionChildren(expression).some(expressionReferencesProtectedEntry)
712
+ }
713
+
714
+ /**
715
+ * Returns semantic child expressions in evaluation order.
716
+ * @param {import("./types.js").Expression} expression - Parent expression.
717
+ * @returns {import("./types.js").Expression[]} Children.
718
+ */
719
+ function expressionChildren(expression) {
720
+ if (expression.kind == "CallExpression" || expression.kind == "EffectCallExpression" || expression.kind == "ReferenceConstruction" ||
721
+ expression.kind == "RecordConstruction") return expression.arguments
722
+ if (expression.kind == "MethodCallExpression") return [expression.receiver, ...expression.arguments]
723
+ if (expression.kind == "OwnedBorrowExpression" || expression.kind == "OwnedMoveExpression") return [expression.expression]
724
+ if (expression.kind == "BinaryExpression") return [expression.left, expression.right]
725
+ if (expression.kind == "UnaryExpression") return [expression.operand]
726
+ if (expression.kind == "OptionalSome") return [expression.value]
727
+ if (expression.kind == "OptionalIsPresent" || expression.kind == "OptionalUnwrap") return [expression.operand]
728
+ if (expression.kind == "ListLiteral") return expression.elements
729
+ if (expression.kind == "MapLiteral" || expression.kind == "OrderedMapLiteral") return expression.entries.map(({value}) => value)
730
+ if (expression.kind == "ListIndexExpression") return [expression.collection, expression.index]
731
+ if (expression.kind == "MapLookupExpression") return [expression.collection, expression.key]
732
+ if (expression.kind == "CollectionSizeExpression") return [expression.collection]
733
+ if (expression.kind == "MemberRead") return [expression.receiver]
734
+ if (expression.kind == "PrivateFieldRead") return [expression.receiver]
735
+ if (expression.kind == "ErrorMessageRead") return [expression.receiver]
736
+ return []
737
+ }