semantifold 0.12.0 → 0.14.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 (73) hide show
  1. package/README.md +2 -0
  2. package/build/src/backends/effects.js +5 -2
  3. package/build/src/backends/java.js +33 -14
  4. package/build/src/backends/javascript.js +83 -18
  5. package/build/src/backends/php.d.ts.map +1 -1
  6. package/build/src/backends/php.js +88 -16
  7. package/build/src/backends/ruby.js +37 -12
  8. package/build/src/backends/scalars.js +2 -2
  9. package/build/src/backends/shared.d.ts +2 -1
  10. package/build/src/backends/shared.d.ts.map +1 -1
  11. package/build/src/backends/shared.js +299 -42
  12. package/build/src/backends/typescript.js +83 -18
  13. package/build/src/backends/writer.d.ts +18 -4
  14. package/build/src/backends/writer.d.ts.map +1 -1
  15. package/build/src/backends/writer.js +40 -4
  16. package/build/src/frontends/java.d.ts +9 -1
  17. package/build/src/frontends/java.d.ts.map +1 -1
  18. package/build/src/frontends/java.js +90 -43
  19. package/build/src/frontends/javascript-typescript.d.ts +3 -1
  20. package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
  21. package/build/src/frontends/javascript-typescript.js +133 -52
  22. package/build/src/frontends/php.d.ts +13 -1
  23. package/build/src/frontends/php.d.ts.map +1 -1
  24. package/build/src/frontends/php.js +226 -59
  25. package/build/src/frontends/ruby.d.ts +4 -1
  26. package/build/src/frontends/ruby.d.ts.map +1 -1
  27. package/build/src/frontends/ruby.js +113 -37
  28. package/build/src/frontends/types.d.ts +9 -2
  29. package/build/src/frontends/types.d.ts.map +1 -1
  30. package/build/src/frontends/types.js +26 -9
  31. package/build/src/language-registry.d.ts.map +1 -1
  32. package/build/src/language-registry.js +14 -6
  33. package/build/src/mapping.d.ts.map +1 -1
  34. package/build/src/mapping.js +4 -2
  35. package/build/src/semantic/effects.d.ts.map +1 -1
  36. package/build/src/semantic/effects.js +20 -6
  37. package/build/src/semantic/lifetime.js +28 -4
  38. package/build/src/semantic/provenance.d.ts.map +1 -1
  39. package/build/src/semantic/provenance.js +61 -9
  40. package/build/src/semantic/types.d.ts +214 -23
  41. package/build/src/semantic/types.d.ts.map +1 -1
  42. package/build/src/semantic/types.js +58 -11
  43. package/build/src/semantic/validate.d.ts +31 -2
  44. package/build/src/semantic/validate.d.ts.map +1 -1
  45. package/build/src/semantic/validate.js +450 -60
  46. package/docs/adr/20261026-typed-error-handling-extension.md +55 -0
  47. package/docs/adr-bounded-subtyping.md +180 -0
  48. package/docs/adr-numeric-tower.md +156 -0
  49. package/docs/architecture.md +1 -1
  50. package/docs/language-support.md +8 -8
  51. package/docs/testing.md +5 -3
  52. package/package.json +1 -1
  53. package/src/backends/effects.js +3 -1
  54. package/src/backends/java.js +33 -14
  55. package/src/backends/javascript.js +83 -18
  56. package/src/backends/php.js +89 -16
  57. package/src/backends/ruby.js +36 -12
  58. package/src/backends/scalars.js +1 -1
  59. package/src/backends/shared.js +298 -47
  60. package/src/backends/typescript.js +83 -18
  61. package/src/backends/writer.js +41 -3
  62. package/src/frontends/java.js +95 -43
  63. package/src/frontends/javascript-typescript.js +145 -53
  64. package/src/frontends/php.js +243 -58
  65. package/src/frontends/ruby.js +117 -35
  66. package/src/frontends/types.js +26 -8
  67. package/src/language-registry.js +13 -5
  68. package/src/mapping.js +3 -1
  69. package/src/semantic/effects.js +18 -5
  70. package/src/semantic/lifetime.js +29 -3
  71. package/src/semantic/provenance.js +60 -14
  72. package/src/semantic/types.js +62 -10
  73. package/src/semantic/validate.js +481 -61
@@ -6,7 +6,7 @@ import {missingType, parseFailure, SemantifoldDiagnostic, unsupportedSyntax} fro
6
6
  import {blockReferencesProtectedEntry} from "../semantic/effects.js"
7
7
  import {locationFromOffsets, moduleLocation} from "../semantic/location.js"
8
8
  import {withAdaptedOperation} from "../semantic/operators.js"
9
- import {withParserRanges} from "../semantic/provenance.js"
9
+ import {setParserRanges, withParserRanges} from "../semantic/provenance.js"
10
10
  import {hasOnlyUnicodeScalars, scalarType} from "../semantic/scalars.js"
11
11
  import {isTask034ResourceProbe} from "../semantic/capabilities.js"
12
12
  import {hasExactEffectSupport} from "../backends/effects.js"
@@ -16,7 +16,7 @@ import {documentedValueType, instantiatedRecordFieldType, iterationBindingType,
16
16
  /** @typedef {NonNullable<import("@babel/parser").ParseResult<import("@babel/types").File>["tokens"]>[number]} BabelToken */
17
17
  /** @typedef {{byStart: Map<number, BabelToken>, tokens: BabelToken[]}} BabelTokenIndex */
18
18
  /** @typedef {{name: string, nameLocation: import("../semantic/types.js").SourceLocation, parameters: import("../semantic/types.js").Parameter[], returnType: import("../semantic/types.js").SemanticFunctionReturnType, typeParameters?: import("../semantic/types.js").TypeParameter[], location: import("../semantic/types.js").SourceLocation}} JavaScriptFunctionSignature */
19
- /** @typedef {{bindings: Map<string, import("../semantic/types.js").SemanticBindingType>, classes: Map<string, import("../semantic/types.js").ClassDeclaration>, currentClass?: import("../semantic/types.js").ClassDeclaration, errors: Map<string, import("../semantic/types.js").ErrorDeclaration>, errorNames: Map<string, import("../semantic/types.js").ErrorDeclaration>, functions: Map<string, JavaScriptFunctionSignature>, lexicalValueNames?: Set<string>, orderedMapDeclarations?: Set<object>, recordNames: Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>, records: Map<string, import("../semantic/types.js").RecordDeclaration>, returnType?: import("../semantic/types.js").SemanticFunctionReturnType, typeParameters?: Map<string, import("../semantic/types.js").TypeParameter>, valueRecordNames: Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration>}} JavaScriptConversionContext */
19
+ /** @typedef {{bindings: Map<string, import("../semantic/types.js").SemanticBindingType>, catchBindingNames?: Set<string>, catchBindingNodes?: Map<string, import("../semantic/types.js").CatchBinding>, classes: Map<string, import("../semantic/types.js").ClassDeclaration>, currentClass?: import("../semantic/types.js").ClassDeclaration, errors: Map<string, import("../semantic/types.js").ErrorDeclaration>, errorNames: Map<string, import("../semantic/types.js").ErrorDeclaration>, functions: Map<string, JavaScriptFunctionSignature>, lexicalValueNames?: Set<string>, orderedMapDeclarations?: Set<object>, recordNames: Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>, records: Map<string, import("../semantic/types.js").RecordDeclaration>, returnType?: import("../semantic/types.js").SemanticFunctionReturnType, typeParameters?: Map<string, import("../semantic/types.js").TypeParameter>, valueRecordNames: Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration>}} JavaScriptConversionContext */
20
20
 
21
21
  /** @type {WeakMap<object, BabelTokenIndex>} */
22
22
  const nodeTokens = new WeakMap()
@@ -875,7 +875,7 @@ function convertLocalStatement(node, language, filename, source, context) {
875
875
  * @param {string} name - Local name.
876
876
  * @param {string} filename - Source filename.
877
877
  * @param {string} source - Complete source.
878
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} recordNames - Nominal declarations by source name.
878
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} recordNames - Nominal declarations by source name.
879
879
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
880
880
  * @returns {import("../semantic/types.js").SemanticValueType} Semantic type.
881
881
  */
@@ -966,12 +966,23 @@ function convertStatement(node, language, filename, source, canonicalZeroRequire
966
966
  * @param {string} filename - Source filename.
967
967
  * @param {string} source - Complete source.
968
968
  * @param {JavaScriptConversionContext} context - Typed lexical context.
969
- * @returns {import("../semantic/types.js").RaiseStatement} Semantic raise.
969
+ * @returns {import("../semantic/types.js").RaiseStatement | import("../semantic/types.js").RethrowStatement} Semantic raise or rethrow.
970
970
  */
971
971
  function convertTypedThrow(node, language, filename, source, context) {
972
972
  const location = nodeLocation(node, filename, source)
973
973
  const argument = node.argument
974
974
 
975
+ if (argument?.type == "Identifier" && context.catchBindingNames?.has(argument.name) && context.bindings.get(argument.name)?.kind == "ErrorType") {
976
+ const bindingNode = context.catchBindingNodes?.get(argument.name)
977
+
978
+ if (!bindingNode) return unsupportedSyntax(language, "throw of a catch binding without an exact handler binding", location)
979
+ return withParserRanges({
980
+ binding: argument.name,
981
+ bindingNode,
982
+ kind: /** @type {const} */ ("RethrowStatement"),
983
+ location
984
+ }, {keyword: tokenLocation(node, "throw", node.start ?? 0, argument.start ?? node.end ?? source.length, filename, source)})
985
+ }
975
986
  if (!argument || argument.type != "NewExpression" || argument.callee.type != "Identifier" ||
976
987
  context.bindings.has(argument.callee.name) || !context.errorNames.has(argument.callee.name) || argument.arguments.length != 1 ||
977
988
  argument.arguments[0].type == "SpreadElement" || argument.arguments[0].type == "ArgumentPlaceholder" ||
@@ -1006,53 +1017,134 @@ function convertTypedThrow(node, language, filename, source, context) {
1006
1017
  function convertTypedTry(node, language, filename, source, canonicalZeroRequired, context) {
1007
1018
  const location = nodeLocation(node, filename, source)
1008
1019
 
1009
- if (node.finalizer || !node.handler || node.handler.param?.type != "Identifier" || node.handler.body.directives.length > 0) {
1010
- return unsupportedSyntax(language, "try without one explicit guarded catch", location)
1011
- }
1012
- const binding = node.handler.param
1013
- const guard = node.handler.body.body[0]
1014
-
1015
- if (!guard || guard.type != "IfStatement" || guard.alternate || guard.test.type != "UnaryExpression" ||
1016
- guard.test.operator != "!" || guard.test.argument.type != "BinaryExpression" || guard.test.argument.operator != "instanceof" ||
1017
- guard.test.argument.left.type != "Identifier" || guard.test.argument.left.name != binding.name ||
1018
- guard.test.argument.right.type != "Identifier" || guard.test.argument.right.name == binding.name ||
1019
- context.bindings.has(guard.test.argument.right.name) || !context.errorNames.has(guard.test.argument.right.name) ||
1020
- guard.consequent.type != "BlockStatement" || guard.consequent.body.length != 1 || guard.consequent.directives.length > 0 ||
1021
- guard.consequent.body[0].type != "ThrowStatement" || guard.consequent.body[0].argument?.type != "Identifier" ||
1022
- guard.consequent.body[0].argument.name != binding.name) {
1023
- return unsupportedSyntax(language, "catch without exact instanceof guard and unmatched rethrow", nodeLocation(guard ?? node.handler, filename, source))
1024
- }
1025
- const declaration = /** @type {import("../semantic/types.js").ErrorDeclaration} */ (context.errorNames.get(guard.test.argument.right.name))
1026
- const caughtTypeLocation = identifierLocation(guard.test.argument.right, filename, source)
1027
- const catchType = withParserRanges({
1028
- declarationId: /** @type {string} */ (declaration.id),
1029
- kind: /** @type {const} */ ("ErrorType")
1030
- }, {type: caughtTypeLocation})
1020
+ if (!node.handler) {
1021
+ if (!node.finalizer) return unsupportedSyntax(language, "try without an explicit guarded catch", location)
1022
+ const bodyContext = {...context, bindings: new Map(context.bindings)}
1023
+ const semantic = /** @type {import("../semantic/types.js").TryStatement} */ (withParserRanges({
1024
+ body: convertBlock(node.block, language, filename, source, canonicalZeroRequired, bodyContext),
1025
+ handlers: [],
1026
+ kind: /** @type {const} */ ("TryStatement"),
1027
+ location
1028
+ }, {
1029
+ try: tokenLocation(node, "try", node.start ?? 0, node.block.start ?? node.end ?? source.length, filename, source)
1030
+ }))
1031
+
1032
+ semantic.finallyBody = convertBlock(node.finalizer.body, language, filename, source, canonicalZeroRequired,
1033
+ {...context, bindings: new Map(context.bindings)}, nodeLocation(node.finalizer, filename, source))
1034
+ setParserRanges(semantic, {finally: nodeLocation(node.finalizer, filename, source),
1035
+ try: tokenLocation(node, "try", node.start ?? 0, node.block.start ?? node.end ?? source.length, filename, source)})
1036
+ return semantic
1037
+ }
1038
+ /** @type {import("../semantic/types.js").CatchHandler[]} */
1039
+ const handlers = []
1040
+ const seenHandlerNames = new Set(context.catchBindingNames ?? [])
1031
1041
  const bodyContext = {...context, bindings: new Map(context.bindings)}
1032
- const catchContext = {...context, bindings: new Map(context.bindings)}
1033
1042
 
1034
- catchContext.bindings.set(binding.name, catchType)
1035
- const catchStatements = node.handler.body.body.slice(1)
1043
+ // JavaScript has no sibling catch clauses, so the exact native profile for ordered
1044
+ // multi-catch is a guarded dispatch chain: each unmatched guard rethrows into the next
1045
+ // clause. The chain flattens back to one ordered handler list here.
1046
+ /** @type {import("@babel/types").CatchClause | undefined} */
1047
+ let clause = node.handler
1048
+
1049
+ while (clause) {
1050
+ const binding = clause.param
1051
+
1052
+ if (binding?.type != "Identifier" || clause.body.directives.length > 0) {
1053
+ return unsupportedSyntax(language, "catch without one explicit binding", nodeLocation(clause, filename, source))
1054
+ }
1055
+ if (seenHandlerNames.has(binding.name)) {
1056
+ return unsupportedSyntax(language, `catch binding '${binding.name}' shadows an outer handler binding`,
1057
+ identifierLocation(binding, filename, source))
1058
+ }
1059
+ seenHandlerNames.add(binding.name)
1060
+
1061
+ /** @type {import("@babel/types").Statement | undefined} */
1062
+ const guard = clause.body.body[0]
1063
+
1064
+ if (!guard || guard.type != "IfStatement" || guard.test.type != "UnaryExpression" ||
1065
+ guard.test.operator != "!" || guard.test.argument.type != "BinaryExpression" || guard.test.argument.operator != "instanceof" ||
1066
+ guard.test.argument.left.type != "Identifier" || guard.test.argument.left.name != binding.name ||
1067
+ guard.test.argument.right.type != "Identifier" || guard.test.argument.right.name == binding.name ||
1068
+ context.bindings.has(guard.test.argument.right.name) || !context.errorNames.has(guard.test.argument.right.name) ||
1069
+ guard.consequent.type != "BlockStatement" || guard.consequent.body.length != 1 || guard.consequent.directives.length > 0 ||
1070
+ (guard.alternate && (guard.alternate.type != "BlockStatement" || guard.alternate.directives.length > 0))) {
1071
+ return unsupportedSyntax(language, "catch without exact instanceof guard", nodeLocation(guard ?? clause, filename, source))
1072
+ }
1073
+
1074
+ /** @type {import("@babel/types").Statement | undefined} */
1075
+ const dispatch = guard.consequent.body[0]
1076
+ /** @type {import("@babel/types").CatchClause | undefined} */
1077
+ let nextClause = undefined
1078
+ /** @type {import("@babel/types").Statement[]} */
1079
+ let handlerBodyStatements = clause.body.body.slice(1)
1080
+ let handlerBodyLocation = nodeLocation(clause.body, filename, source)
1081
+
1082
+ if (dispatch.type == "TryStatement") {
1083
+ if (dispatch.finalizer || !dispatch.handler || dispatch.block.body.length != 1 || dispatch.block.body[0].type != "ThrowStatement" ||
1084
+ dispatch.block.body[0].argument?.type != "Identifier" || dispatch.block.body[0].argument.name != binding.name ||
1085
+ !guard.alternate || clause.body.body.length != 1) {
1086
+ return unsupportedSyntax(language, "catch guard dispatch without exact rethrow of its own binding",
1087
+ nodeLocation(dispatch, filename, source))
1088
+ }
1089
+ nextClause = dispatch.handler
1090
+ handlerBodyStatements = /** @type {import("@babel/types").BlockStatement} */ (guard.alternate).body
1091
+ handlerBodyLocation = nodeLocation(guard.alternate, filename, source)
1092
+ } else if (dispatch.type != "ThrowStatement" || dispatch.argument?.type != "Identifier" || dispatch.argument.name != binding.name) {
1093
+ return unsupportedSyntax(language, "catch guard without exact unmatched rethrow", nodeLocation(dispatch, filename, source))
1094
+ } else if (guard.alternate) {
1095
+ if (clause.body.body.length != 1) {
1096
+ return unsupportedSyntax(language, "catch guard dispatch without exact rethrow of its own binding",
1097
+ nodeLocation(guard.alternate, filename, source))
1098
+ }
1099
+ handlerBodyStatements = /** @type {import("@babel/types").BlockStatement} */ (guard.alternate).body
1100
+ handlerBodyLocation = nodeLocation(guard.alternate, filename, source)
1101
+ }
1036
1102
 
1037
- return withParserRanges({
1038
- body: convertBlock(node.block, language, filename, source, canonicalZeroRequired, bodyContext),
1039
- catchBinding: withParserRanges({
1103
+ const declaration = /** @type {import("../semantic/types.js").ErrorDeclaration} */ (context.errorNames.get(guard.test.argument.right.name))
1104
+ const caughtTypeLocation = identifierLocation(guard.test.argument.right, filename, source)
1105
+ const catchType = withParserRanges({
1106
+ declarationId: /** @type {string} */ (declaration.id),
1107
+ kind: /** @type {const} */ ("ErrorType")
1108
+ }, {type: caughtTypeLocation})
1109
+ const catchContext = {...context, bindings: new Map(context.bindings), catchBindingNames: new Set(seenHandlerNames),
1110
+ catchBindingNodes: new Map(context.catchBindingNodes)}
1111
+
1112
+ catchContext.bindings.set(binding.name, catchType)
1113
+ const catchBindingNode = withParserRanges({
1040
1114
  kind: /** @type {const} */ ("CatchBinding"),
1041
1115
  location: identifierLocation(binding, filename, source),
1042
1116
  mutable: /** @type {const} */ (false),
1043
1117
  name: binding.name,
1044
1118
  type: catchType
1045
- }, {name: identifierLocation(binding, filename, source)}),
1046
- catchBody: convertBlock(catchStatements, language, filename, source, canonicalZeroRequired, catchContext,
1047
- nodeLocation(node.handler.body, filename, source)),
1048
- catchType,
1119
+ }, {name: identifierLocation(binding, filename, source)})
1120
+
1121
+ catchContext.catchBindingNodes.set(binding.name, catchBindingNode)
1122
+ handlers.push(withParserRanges({
1123
+ catchBinding: catchBindingNode,
1124
+ catchBody: convertBlock(handlerBodyStatements, language, filename, source, canonicalZeroRequired, catchContext,
1125
+ handlerBodyLocation),
1126
+ catchType,
1127
+ kind: /** @type {const} */ ("CatchHandler"),
1128
+ location: nodeLocation(clause, filename, source)
1129
+ }, {catch: tokenLocation(clause, "catch", clause.start ?? 0, binding.start ?? clause.end ?? source.length, filename, source)}))
1130
+ clause = nextClause
1131
+ }
1132
+ const semantic = /** @type {import("../semantic/types.js").TryStatement} */ (withParserRanges({
1133
+ body: convertBlock(node.block, language, filename, source, canonicalZeroRequired, bodyContext),
1134
+ handlers,
1049
1135
  kind: /** @type {const} */ ("TryStatement"),
1050
1136
  location
1051
1137
  }, {
1052
- catch: tokenLocation(node.handler, "catch", node.handler.start ?? 0, binding.start ?? node.handler.end ?? source.length, filename, source),
1053
- guard: nodeLocation(guard, filename, source),
1054
1138
  try: tokenLocation(node, "try", node.start ?? 0, node.block.start ?? node.end ?? source.length, filename, source)
1055
- })
1139
+ }))
1140
+
1141
+ if (node.finalizer) {
1142
+ semantic.finallyBody = convertBlock(node.finalizer.body, language, filename, source, canonicalZeroRequired,
1143
+ {...context, bindings: new Map(context.bindings)}, nodeLocation(node.finalizer, filename, source))
1144
+ setParserRanges(semantic, {finally: nodeLocation(node.finalizer, filename, source),
1145
+ try: tokenLocation(node, "try", node.start ?? 0, node.block.start ?? node.end ?? source.length, filename, source)})
1146
+ }
1147
+ return semantic
1056
1148
  }
1057
1149
 
1058
1150
  /**
@@ -1301,7 +1393,7 @@ function classJsdocTypeParameters(node, ownerId, filename, source) {
1301
1393
  * @param {import("../semantic/types.js").SourceLocation} location - Source location.
1302
1394
  * @param {string} source - Complete parser input.
1303
1395
  * @param {import("../semantic/types.js").SourceLocation} [typeLocation] - Exact type token location.
1304
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [recordNames] - Nominal declarations by source name.
1396
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} [recordNames] - Nominal declarations by source name.
1305
1397
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
1306
1398
  * @returns {import("../semantic/types.js").SemanticValueType} Semantic type.
1307
1399
  */
@@ -1319,7 +1411,7 @@ function convertType(sourceType, language, subject, location, source, typeLocati
1319
1411
  * @param {import("../semantic/types.js").SourceLocation} location - Function location.
1320
1412
  * @param {string} source - Complete parser input.
1321
1413
  * @param {import("../semantic/types.js").SourceLocation} [typeLocation] - Exact annotation location.
1322
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [recordNames] - Nominal declarations by source name.
1414
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} [recordNames] - Nominal declarations by source name.
1323
1415
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
1324
1416
  * @returns {import("../semantic/types.js").SemanticFunctionReturnType} Semantic return type.
1325
1417
  */
@@ -1336,7 +1428,7 @@ function convertReturnType(sourceType, language, subject, location, source, type
1336
1428
  * @param {import("../semantic/types.js").SourceLocation} ownerLocation - Owning declaration location.
1337
1429
  * @param {string} filename - Source filename.
1338
1430
  * @param {string} source - Complete source.
1339
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [recordNames] - Nominal declarations by source name.
1431
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} [recordNames] - Nominal declarations by source name.
1340
1432
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
1341
1433
  * @returns {import("../semantic/types.js").SemanticValueType} Semantic type.
1342
1434
  */
@@ -1356,7 +1448,7 @@ function convertTypeScriptType(annotation, subject, ownerLocation, filename, sou
1356
1448
  * @param {import("../semantic/types.js").SourceLocation} ownerLocation - Owning declaration.
1357
1449
  * @param {string} filename - Source filename.
1358
1450
  * @param {string} source - Complete source.
1359
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [recordNames] - Nominal declarations by source name.
1451
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} [recordNames] - Nominal declarations by source name.
1360
1452
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
1361
1453
  * @returns {import("../semantic/types.js").SemanticValueType} Semantic value type.
1362
1454
  */
@@ -1375,7 +1467,7 @@ function convertTypeScriptValueTypeNode(typeNode, subject, ownerLocation, filena
1375
1467
  }
1376
1468
  if (typeNode.type == "TSTypeReference" && typeNode.typeName.type == "Identifier" &&
1377
1469
  recordNames.has(typeNode.typeName.name)) {
1378
- const declaration = /** @type {import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration} */ (recordNames.get(typeNode.typeName.name))
1470
+ const declaration = /** @type {import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration} */ (recordNames.get(typeNode.typeName.name))
1379
1471
 
1380
1472
  if (declaration.kind == "EffectResourceDeclaration") {
1381
1473
  if (typeNode.typeParameters) return unsupportedSyntax("typescript", "generic owned resource type", nodeLocation(typeNode, filename, source))
@@ -1457,7 +1549,7 @@ function convertTypeScriptValueTypeNode(typeNode, subject, ownerLocation, filena
1457
1549
  * @param {import("../semantic/types.js").SourceLocation} ownerLocation - Function location.
1458
1550
  * @param {string} filename - Source filename.
1459
1551
  * @param {string} source - Complete source.
1460
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [recordNames] - Nominal declarations by source name.
1552
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} [recordNames] - Nominal declarations by source name.
1461
1553
  * @param {Map<string, import("../semantic/types.js").TypeParameter>} [typeParameters] - Declaration-scoped parameters.
1462
1554
  * @returns {import("../semantic/types.js").SemanticFunctionReturnType} Semantic return type.
1463
1555
  */
@@ -1504,7 +1596,7 @@ function typeScriptTypeParameters(declaration, ownerId, filename, source) {
1504
1596
  * @param {"javascript" | "typescript"} language - Frontend language.
1505
1597
  * @param {string} filename - Source filename.
1506
1598
  * @param {string} source - Complete source.
1507
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} recordNames - Nominal declarations by source name.
1599
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} recordNames - Nominal declarations by source name.
1508
1600
  * @param {string} ownerId - Stable function identity.
1509
1601
  * @returns {JavaScriptFunctionSignature} Semantic function signature.
1510
1602
  */
@@ -1561,7 +1653,7 @@ function convertFunctionSignature(node, language, filename, source, recordNames,
1561
1653
  * @param {import("@babel/types").FunctionDeclaration} node - Babel function.
1562
1654
  * @param {JavaScriptFunctionSignature} signature - Converted signature.
1563
1655
  * @param {Map<string, JavaScriptFunctionSignature>} functions - Module signatures.
1564
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} recordNames - Nominal declarations by name.
1656
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} recordNames - Nominal declarations by name.
1565
1657
  * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration>} valueRecordNames - Nominal declarations available in value positions.
1566
1658
  * @param {Map<string, import("../semantic/types.js").RecordDeclaration>} records - Record declarations by identity.
1567
1659
  * @param {Map<string, import("../semantic/types.js").ClassDeclaration>} classes - Reference classes by identity.
@@ -1691,7 +1783,7 @@ function convertJavaScriptError(node, declaration, language, filename, source) {
1691
1783
  * Predeclares the bounded native private-field reference-class profile and all callable signatures.
1692
1784
  * @param {import("@babel/types").ClassDeclaration} node - Parser class.
1693
1785
  * @param {import("../semantic/types.js").ClassDeclaration} declaration - Predeclared class identity.
1694
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} nominalNames - Nominal types by name.
1786
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} nominalNames - Nominal types by name.
1695
1787
  * @param {"javascript" | "typescript"} language - Source language.
1696
1788
  * @param {string} filename - Source filename.
1697
1789
  * @param {string} source - Complete source.
@@ -1782,7 +1874,7 @@ function predeclareReferenceClass(node, declaration, nominalNames, language, fil
1782
1874
  * Converts one reference class body after every class signature is complete.
1783
1875
  * @param {import("@babel/types").ClassDeclaration} node - Parser class.
1784
1876
  * @param {import("../semantic/types.js").ClassDeclaration} declaration - Complete predeclared class signature.
1785
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} nominalNames - Nominal types by name.
1877
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} nominalNames - Nominal types by name.
1786
1878
  * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration>} valueNames - Nominal constructors by name.
1787
1879
  * @param {Map<string, import("../semantic/types.js").RecordDeclaration>} records - Records by identity.
1788
1880
  * @param {Map<string, import("../semantic/types.js").ClassDeclaration>} classes - Classes by identity.
@@ -1824,7 +1916,7 @@ function convertReferenceClassBodies(node, declaration, nominalNames, valueNames
1824
1916
  * Reads one constructor or method signature without admitting overloads or modifiers.
1825
1917
  * @param {import("@babel/types").ClassMethod} node - Parser method.
1826
1918
  * @param {import("../semantic/types.js").ClassDeclaration} declaration - Declaring class.
1827
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} nominalNames - Nominal types.
1919
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} nominalNames - Nominal types.
1828
1920
  * @param {"javascript" | "typescript"} language - Source language.
1829
1921
  * @param {string} filename - Source filename.
1830
1922
  * @param {string} source - Complete source.
@@ -1880,7 +1972,7 @@ function convertClassCallableSignature(node, declaration, nominalNames, language
1880
1972
  * Converts one exact TypeScript readonly constructor-parameter record profile.
1881
1973
  * @param {import("@babel/types").ClassDeclaration} node - Class declaration.
1882
1974
  * @param {import("../semantic/types.js").RecordDeclaration} declaration - Predeclared nominal identity.
1883
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} recordNames - All nominal declarations by name.
1975
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} recordNames - All nominal declarations by name.
1884
1976
  * @param {string} filename - Source filename.
1885
1977
  * @param {string} source - Complete source.
1886
1978
  * @returns {import("../semantic/types.js").RecordDeclaration} Semantic record declaration.
@@ -1935,7 +2027,7 @@ function convertTypeScriptRecord(node, declaration, recordNames, filename, sourc
1935
2027
  * Converts one exact JSDoc constructor/readonly-assignment/freeze record profile.
1936
2028
  * @param {import("@babel/types").ClassDeclaration} node - Class declaration.
1937
2029
  * @param {import("../semantic/types.js").RecordDeclaration} declaration - Predeclared nominal identity.
1938
- * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} recordNames - Nominal declarations by name.
2030
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} recordNames - Nominal declarations by name.
1939
2031
  * @param {string} filename - Source filename.
1940
2032
  * @param {string} source - Complete source.
1941
2033
  * @returns {import("../semantic/types.js").RecordDeclaration} Semantic record declaration.
@@ -2267,7 +2359,7 @@ export function parseJavaScriptTypeScript({capabilities = [], filename, language
2267
2359
  fields: [], id: `class:${index}`, kind: /** @type {const} */ ("ClassDeclaration"),
2268
2360
  location: nodeLocation(node, filename, source), methods: [], name: node.id?.name ?? ""
2269
2361
  }))
2270
- const recordNames = /** @type {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} */ (
2362
+ const recordNames = /** @type {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration | import("../semantic/types.js").InterfaceDeclaration>} */ (
2271
2363
  new Map(program?.records ?? []))
2272
2364
  for (const resource of capabilities.flatMap(({resources}) => resources)) recordNames.set(resource.name, resource)
2273
2365
  const valueRecordNames = /** @type {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration>} */ (