rooklang 0.0.0-stage → 0.3.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 (314) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -2
  3. package/README.ru.md +178 -0
  4. package/dist/ast/declarations.d.ts +185 -0
  5. package/dist/ast/declarations.js +1 -0
  6. package/dist/ast/expressions.d.ts +201 -0
  7. package/dist/ast/expressions.js +1 -0
  8. package/dist/ast/markup.d.ts +141 -0
  9. package/dist/ast/markup.js +1 -0
  10. package/dist/ast/statements.d.ts +173 -0
  11. package/dist/ast/statements.js +1 -0
  12. package/dist/ast.d.ts +18 -0
  13. package/dist/ast.js +18 -0
  14. package/dist/attrs.d.ts +8 -0
  15. package/dist/attrs.js +23 -0
  16. package/dist/browser.d.ts +30 -0
  17. package/dist/browser.js +36 -0
  18. package/dist/build.d.ts +48 -0
  19. package/dist/build.js +112 -0
  20. package/dist/checker/assignments.d.ts +14 -0
  21. package/dist/checker/assignments.js +197 -0
  22. package/dist/checker/base.d.ts +124 -0
  23. package/dist/checker/base.js +180 -0
  24. package/dist/checker/bigint.d.ts +15 -0
  25. package/dist/checker/bigint.js +85 -0
  26. package/dist/checker/builtins.d.ts +9 -0
  27. package/dist/checker/builtins.js +307 -0
  28. package/dist/checker/bytes.d.ts +11 -0
  29. package/dist/checker/bytes.js +72 -0
  30. package/dist/checker/calls.d.ts +23 -0
  31. package/dist/checker/calls.js +210 -0
  32. package/dist/checker/channel.d.ts +14 -0
  33. package/dist/checker/channel.js +44 -0
  34. package/dist/checker/channels.d.ts +9 -0
  35. package/dist/checker/channels.js +95 -0
  36. package/dist/checker/checker.d.ts +4 -0
  37. package/dist/checker/checker.js +22 -0
  38. package/dist/checker/classes.d.ts +24 -0
  39. package/dist/checker/classes.js +223 -0
  40. package/dist/checker/completion-names.d.ts +11 -0
  41. package/dist/checker/completion-names.js +100 -0
  42. package/dist/checker/completion.d.ts +25 -0
  43. package/dist/checker/completion.js +222 -0
  44. package/dist/checker/component-values.d.ts +11 -0
  45. package/dist/checker/component-values.js +88 -0
  46. package/dist/checker/components.d.ts +37 -0
  47. package/dist/checker/components.js +287 -0
  48. package/dist/checker/context.d.ts +196 -0
  49. package/dist/checker/context.js +35 -0
  50. package/dist/checker/control-flow.d.ts +24 -0
  51. package/dist/checker/control-flow.js +237 -0
  52. package/dist/checker/declarations.d.ts +26 -0
  53. package/dist/checker/declarations.js +259 -0
  54. package/dist/checker/decorator-exports.d.ts +5 -0
  55. package/dist/checker/decorator-exports.js +40 -0
  56. package/dist/checker/decorator-members.d.ts +28 -0
  57. package/dist/checker/decorator-members.js +140 -0
  58. package/dist/checker/decorator-wrappers.d.ts +20 -0
  59. package/dist/checker/decorator-wrappers.js +132 -0
  60. package/dist/checker/decorators.d.ts +28 -0
  61. package/dist/checker/decorators.js +265 -0
  62. package/dist/checker/dom-svg.d.ts +7 -0
  63. package/dist/checker/dom-svg.js +19 -0
  64. package/dist/checker/dom.d.ts +22 -0
  65. package/dist/checker/dom.js +361 -0
  66. package/dist/checker/expressions.d.ts +32 -0
  67. package/dist/checker/expressions.js +244 -0
  68. package/dist/checker/flow.d.ts +18 -0
  69. package/dist/checker/flow.js +134 -0
  70. package/dist/checker/forwarding.d.ts +15 -0
  71. package/dist/checker/forwarding.js +78 -0
  72. package/dist/checker/functions.d.ts +24 -0
  73. package/dist/checker/functions.js +154 -0
  74. package/dist/checker/go-for.d.ts +12 -0
  75. package/dist/checker/go-for.js +93 -0
  76. package/dist/checker/goroutines.d.ts +19 -0
  77. package/dist/checker/goroutines.js +110 -0
  78. package/dist/checker/helpers.d.ts +35 -0
  79. package/dist/checker/helpers.js +162 -0
  80. package/dist/checker/imports.d.ts +7 -0
  81. package/dist/checker/imports.js +83 -0
  82. package/dist/checker/initializers.d.ts +22 -0
  83. package/dist/checker/initializers.js +104 -0
  84. package/dist/checker/iterables.d.ts +5 -0
  85. package/dist/checker/iterables.js +17 -0
  86. package/dist/checker/iterators.d.ts +13 -0
  87. package/dist/checker/iterators.js +95 -0
  88. package/dist/checker/loops.d.ts +10 -0
  89. package/dist/checker/loops.js +82 -0
  90. package/dist/checker/markup.d.ts +28 -0
  91. package/dist/checker/markup.js +220 -0
  92. package/dist/checker/members.d.ts +29 -0
  93. package/dist/checker/members.js +233 -0
  94. package/dist/checker/operators.d.ts +13 -0
  95. package/dist/checker/operators.js +177 -0
  96. package/dist/checker/promise.d.ts +17 -0
  97. package/dist/checker/promise.js +49 -0
  98. package/dist/checker/refs.d.ts +26 -0
  99. package/dist/checker/refs.js +136 -0
  100. package/dist/checker/resolution.d.ts +23 -0
  101. package/dist/checker/resolution.js +173 -0
  102. package/dist/checker/statements.d.ts +28 -0
  103. package/dist/checker/statements.js +212 -0
  104. package/dist/checker/styles.d.ts +14 -0
  105. package/dist/checker/styles.js +49 -0
  106. package/dist/checker/transfer.d.ts +5 -0
  107. package/dist/checker/transfer.js +83 -0
  108. package/dist/checker/types/bytes.d.ts +4 -0
  109. package/dist/checker/types/bytes.js +51 -0
  110. package/dist/checker/types/classes.d.ts +22 -0
  111. package/dist/checker/types/classes.js +93 -0
  112. package/dist/checker/types/constructors.d.ts +27 -0
  113. package/dist/checker/types/constructors.js +129 -0
  114. package/dist/checker/types/generics.d.ts +20 -0
  115. package/dist/checker/types/generics.js +75 -0
  116. package/dist/checker/types/lazy.d.ts +30 -0
  117. package/dist/checker/types/lazy.js +92 -0
  118. package/dist/checker/types/model.d.ts +149 -0
  119. package/dist/checker/types/model.js +15 -0
  120. package/dist/checker/types/params.d.ts +7 -0
  121. package/dist/checker/types/params.js +220 -0
  122. package/dist/checker/types/printing.d.ts +6 -0
  123. package/dist/checker/types/printing.js +109 -0
  124. package/dist/checker/types/relations.d.ts +16 -0
  125. package/dist/checker/types/relations.js +294 -0
  126. package/dist/checker/types.d.ts +9 -0
  127. package/dist/checker/types.js +10 -0
  128. package/dist/cli.d.ts +2 -0
  129. package/dist/cli.js +193 -0
  130. package/dist/codegen/analysis.d.ts +18 -0
  131. package/dist/codegen/analysis.js +144 -0
  132. package/dist/codegen/attributes.d.ts +40 -0
  133. package/dist/codegen/attributes.js +227 -0
  134. package/dist/codegen/calls.d.ts +22 -0
  135. package/dist/codegen/calls.js +106 -0
  136. package/dist/codegen/chan-helpers.d.ts +2 -0
  137. package/dist/codegen/chan-helpers.js +253 -0
  138. package/dist/codegen/component-helpers.d.ts +33 -0
  139. package/dist/codegen/component-helpers.js +18 -0
  140. package/dist/codegen/component-props.d.ts +42 -0
  141. package/dist/codegen/component-props.js +173 -0
  142. package/dist/codegen/component-values.d.ts +27 -0
  143. package/dist/codegen/component-values.js +146 -0
  144. package/dist/codegen/components.d.ts +53 -0
  145. package/dist/codegen/components.js +268 -0
  146. package/dist/codegen/control-flow.d.ts +25 -0
  147. package/dist/codegen/control-flow.js +152 -0
  148. package/dist/codegen/control-statements.d.ts +28 -0
  149. package/dist/codegen/control-statements.js +226 -0
  150. package/dist/codegen/creation.d.ts +31 -0
  151. package/dist/codegen/creation.js +113 -0
  152. package/dist/codegen/early-returns.d.ts +59 -0
  153. package/dist/codegen/early-returns.js +244 -0
  154. package/dist/codegen/element-helpers.d.ts +12 -0
  155. package/dist/codegen/element-helpers.js +54 -0
  156. package/dist/codegen/elements.d.ts +71 -0
  157. package/dist/codegen/elements.js +293 -0
  158. package/dist/codegen/emitter.d.ts +135 -0
  159. package/dist/codegen/emitter.js +296 -0
  160. package/dist/codegen/expressions.d.ts +49 -0
  161. package/dist/codegen/expressions.js +262 -0
  162. package/dist/codegen/functions.d.ts +28 -0
  163. package/dist/codegen/functions.js +170 -0
  164. package/dist/codegen/go-helpers.d.ts +9 -0
  165. package/dist/codegen/go-helpers.js +307 -0
  166. package/dist/codegen/helpers.d.ts +10 -0
  167. package/dist/codegen/helpers.js +356 -0
  168. package/dist/codegen/imported.d.ts +38 -0
  169. package/dist/codegen/imported.js +71 -0
  170. package/dist/codegen/js.d.ts +20 -0
  171. package/dist/codegen/js.js +113 -0
  172. package/dist/codegen/mutations.d.ts +10 -0
  173. package/dist/codegen/mutations.js +102 -0
  174. package/dist/codegen/parallel.d.ts +7 -0
  175. package/dist/codegen/parallel.js +63 -0
  176. package/dist/codegen/reactive.d.ts +95 -0
  177. package/dist/codegen/reactive.js +280 -0
  178. package/dist/codegen/refs.d.ts +62 -0
  179. package/dist/codegen/refs.js +160 -0
  180. package/dist/codegen/select-helpers.d.ts +2 -0
  181. package/dist/codegen/select-helpers.js +135 -0
  182. package/dist/codegen/simple-statements.d.ts +42 -0
  183. package/dist/codegen/simple-statements.js +253 -0
  184. package/dist/codegen/statements.d.ts +22 -0
  185. package/dist/codegen/statements.js +142 -0
  186. package/dist/codegen/styles.d.ts +54 -0
  187. package/dist/codegen/styles.js +157 -0
  188. package/dist/codegen/syntax.d.ts +18 -0
  189. package/dist/codegen/syntax.js +70 -0
  190. package/dist/codegen/thread-helpers.d.ts +2 -0
  191. package/dist/codegen/thread-helpers.js +198 -0
  192. package/dist/codegen/updates.d.ts +51 -0
  193. package/dist/codegen/updates.js +201 -0
  194. package/dist/codegen/web-components.d.ts +20 -0
  195. package/dist/codegen/web-components.js +149 -0
  196. package/dist/compile-file.d.ts +11 -0
  197. package/dist/compile-file.js +24 -0
  198. package/dist/compile.d.ts +53 -0
  199. package/dist/compile.js +187 -0
  200. package/dist/completion.d.ts +10 -0
  201. package/dist/completion.js +134 -0
  202. package/dist/config.d.ts +2 -0
  203. package/dist/config.js +44 -0
  204. package/dist/css/hash.d.ts +1 -0
  205. package/dist/css/hash.js +10 -0
  206. package/dist/css/parse.d.ts +42 -0
  207. package/dist/css/parse.js +138 -0
  208. package/dist/css/print.d.ts +9 -0
  209. package/dist/css/print.js +35 -0
  210. package/dist/css/selectors.d.ts +29 -0
  211. package/dist/css/selectors.js +168 -0
  212. package/dist/declarations.d.ts +3 -0
  213. package/dist/declarations.js +207 -0
  214. package/dist/decorator-copy.d.ts +18 -0
  215. package/dist/decorator-copy.js +158 -0
  216. package/dist/decorators.d.ts +61 -0
  217. package/dist/decorators.js +241 -0
  218. package/dist/diagnostics.d.ts +17 -0
  219. package/dist/diagnostics.js +22 -0
  220. package/dist/go-for.d.ts +26 -0
  221. package/dist/go-for.js +155 -0
  222. package/dist/goroutines.d.ts +37 -0
  223. package/dist/goroutines.js +253 -0
  224. package/dist/html-tag.d.ts +21 -0
  225. package/dist/html-tag.js +103 -0
  226. package/dist/index.d.ts +33 -0
  227. package/dist/index.js +55 -0
  228. package/dist/inline-packages.d.ts +32 -0
  229. package/dist/inline-packages.js +129 -0
  230. package/dist/iterators.d.ts +10 -0
  231. package/dist/iterators.js +33 -0
  232. package/dist/lexer/base.d.ts +24 -0
  233. package/dist/lexer/base.js +87 -0
  234. package/dist/lexer/lexer.d.ts +8 -0
  235. package/dist/lexer/lexer.js +134 -0
  236. package/dist/lexer/literals.d.ts +18 -0
  237. package/dist/lexer/literals.js +203 -0
  238. package/dist/lexer/markup.d.ts +10 -0
  239. package/dist/lexer/markup.js +93 -0
  240. package/dist/lexer/style.d.ts +17 -0
  241. package/dist/lexer/style.js +97 -0
  242. package/dist/lexer/tables.d.ts +53 -0
  243. package/dist/lexer/tables.js +101 -0
  244. package/dist/lexer/token.d.ts +42 -0
  245. package/dist/lexer/token.js +108 -0
  246. package/dist/loader.d.ts +1 -0
  247. package/dist/loader.js +50 -0
  248. package/dist/methods.d.ts +5 -0
  249. package/dist/methods.js +81 -0
  250. package/dist/modules.d.ts +3 -0
  251. package/dist/modules.js +49 -0
  252. package/dist/names.d.ts +23 -0
  253. package/dist/names.js +267 -0
  254. package/dist/parser/base.d.ts +96 -0
  255. package/dist/parser/base.js +202 -0
  256. package/dist/parser/classes.d.ts +8 -0
  257. package/dist/parser/classes.js +164 -0
  258. package/dist/parser/control-flow.d.ts +29 -0
  259. package/dist/parser/control-flow.js +232 -0
  260. package/dist/parser/declarations.d.ts +27 -0
  261. package/dist/parser/declarations.js +238 -0
  262. package/dist/parser/decorators.d.ts +30 -0
  263. package/dist/parser/decorators.js +176 -0
  264. package/dist/parser/expressions.d.ts +15 -0
  265. package/dist/parser/expressions.js +255 -0
  266. package/dist/parser/literals.d.ts +27 -0
  267. package/dist/parser/literals.js +206 -0
  268. package/dist/parser/markup.d.ts +22 -0
  269. package/dist/parser/markup.js +193 -0
  270. package/dist/parser/parser.d.ts +14 -0
  271. package/dist/parser/parser.js +22 -0
  272. package/dist/parser/simple-statements.d.ts +22 -0
  273. package/dist/parser/simple-statements.js +156 -0
  274. package/dist/parser/statements.d.ts +37 -0
  275. package/dist/parser/statements.js +267 -0
  276. package/dist/parser/syntax.d.ts +51 -0
  277. package/dist/parser/syntax.js +173 -0
  278. package/dist/parser/types.d.ts +23 -0
  279. package/dist/parser/types.js +218 -0
  280. package/dist/recursion.d.ts +25 -0
  281. package/dist/recursion.js +170 -0
  282. package/dist/refs.d.ts +49 -0
  283. package/dist/refs.js +210 -0
  284. package/dist/run.d.ts +1 -0
  285. package/dist/run.js +21 -0
  286. package/dist/source.d.ts +15 -0
  287. package/dist/source.js +34 -0
  288. package/dist/style-modules.d.ts +17 -0
  289. package/dist/style-modules.js +49 -0
  290. package/dist/styles.d.ts +36 -0
  291. package/dist/styles.js +160 -0
  292. package/dist/svg.d.ts +8 -0
  293. package/dist/svg.js +77 -0
  294. package/dist/ts-types.d.ts +11 -0
  295. package/dist/ts-types.js +133 -0
  296. package/dist/typed-arrays.d.ts +8 -0
  297. package/dist/typed-arrays.js +43 -0
  298. package/dist/typescript/convert-base.d.ts +42 -0
  299. package/dist/typescript/convert-base.js +135 -0
  300. package/dist/typescript/convert-objects.d.ts +28 -0
  301. package/dist/typescript/convert-objects.js +245 -0
  302. package/dist/typescript/convert.d.ts +14 -0
  303. package/dist/typescript/convert.js +67 -0
  304. package/dist/typescript/importer.d.ts +37 -0
  305. package/dist/typescript/importer.js +152 -0
  306. package/dist/typescript/library.d.ts +23 -0
  307. package/dist/typescript/library.js +81 -0
  308. package/dist/vite.d.ts +11 -0
  309. package/dist/vite.js +86 -0
  310. package/dist/walk-types.d.ts +4 -0
  311. package/dist/walk-types.js +56 -0
  312. package/dist/walk.d.ts +5 -0
  313. package/dist/walk.js +315 -0
  314. package/package.json +104 -4
@@ -0,0 +1,210 @@
1
+ import { isUntyped, signaturesOf, callSignature } from "./helpers.js";
2
+ import { MemberChecker } from "./members.js";
3
+ import { ANY, classInstance, constructorOf, containsTypeParam, func, hasUntypedBase, inferTypeParams, isAssignable, isSubclass, substitute, typeToString, UNKNOWN, VOID, } from "./types.js";
4
+ // Calls and `new`: overloads, arguments, and the inference of type arguments.
5
+ export class CallChecker extends MemberChecker {
6
+ checkCall(node, callee, expected = null) {
7
+ if (isUntyped(callee)) {
8
+ this.checkArgumentsLoosely(node.arguments);
9
+ return callee;
10
+ }
11
+ if (callee.kind === 'classValue') {
12
+ this.error(`use "new ${callee.info.name}(...)" to create a ${callee.info.name}`, node);
13
+ this.checkArgumentsLoosely(node.arguments);
14
+ return callee.info.instance;
15
+ }
16
+ const signature = callSignature(callee);
17
+ if (!signature) {
18
+ this.error(`${typeToString(callee)} cannot be called`, node.callee);
19
+ this.checkArgumentsLoosely(node.arguments);
20
+ return UNKNOWN;
21
+ }
22
+ const { results } = this.checkOverloads(signaturesOf(signature), node.arguments, node, expected);
23
+ if (results.length === 0)
24
+ return VOID;
25
+ if (results.length === 1)
26
+ return results[0];
27
+ return { kind: 'tuple', types: results };
28
+ }
29
+ checkSuperCall(node) {
30
+ const info = this.cls?.info;
31
+ if (!info || !this.fn?.isConstructor) {
32
+ this.error('"super(...)" can only be called in a constructor', node);
33
+ this.checkArgumentsLoosely(node.arguments);
34
+ return VOID;
35
+ }
36
+ if (!info.superClass) {
37
+ if (!hasUntypedBase(info))
38
+ this.error(`class "${info.name}" has no base class`, node);
39
+ this.checkArgumentsLoosely(node.arguments);
40
+ return VOID;
41
+ }
42
+ this.checkArguments(constructorOf(info.superClass).type, node.arguments, node);
43
+ return VOID;
44
+ }
45
+ checkNew(node, expected = null) {
46
+ const callee = this.checkValue(node.callee);
47
+ if (isUntyped(callee)) {
48
+ this.checkArgumentsLoosely(node.arguments);
49
+ return callee;
50
+ }
51
+ if (callee.kind === 'object' && callee.construct) {
52
+ const signatures = signaturesOf(callee.construct);
53
+ return this.checkOverloads(signatures, node.arguments, node, expected).results[0] ?? UNKNOWN;
54
+ }
55
+ if (callee.kind !== 'classValue') {
56
+ this.error(`${typeToString(callee)} is not a class`, node.callee);
57
+ this.checkArgumentsLoosely(node.arguments);
58
+ return UNKNOWN;
59
+ }
60
+ const { info } = callee;
61
+ this.ensureClassResolved(info);
62
+ const { type, owner } = constructorOf(info);
63
+ if (owner && owner.ctorVisibility !== 'public') {
64
+ const current = this.cls?.info;
65
+ const allowed = owner.ctorVisibility === 'private'
66
+ ? current === owner
67
+ : current !== undefined && isSubclass(current, owner);
68
+ if (!allowed) {
69
+ this.error(`the constructor of ${owner.name} is ${owner.ctorVisibility}`, node);
70
+ }
71
+ }
72
+ if (info.typeParams.length === 0) {
73
+ this.checkOverloads(signaturesOf(type), node.arguments, node, null);
74
+ return info.instance;
75
+ }
76
+ // `new Stack<number>()` is not valid syntax: the arguments come from the constructor
77
+ // arguments, or from the expected type, as in `let s Stack<number> = new Stack()`.
78
+ const instance = { kind: 'class', info, args: info.typeParams };
79
+ const signatures = signaturesOf(type).map((signature) => func(signature.params, [instance], {
80
+ required: signature.required,
81
+ ...(signature.rest ? { rest: signature.rest } : {}),
82
+ typeParams: [...new Set([...info.typeParams, ...signature.typeParams])],
83
+ }));
84
+ const { inferred } = this.checkOverloads(signatures, node.arguments, node, expected);
85
+ return classInstance(info, info.typeParams.map((param) => inferred.get(param) ?? UNKNOWN));
86
+ }
87
+ /**
88
+ * Checks a call of an overloaded function (from a `.d.ts`): the first signature that fits the
89
+ * arguments is used. Signatures that take this many arguments are tried first.
90
+ */
91
+ checkOverloads(signatures, args, node, expected) {
92
+ if (signatures.length === 1) {
93
+ const inferred = new Map();
94
+ const results = this.checkArguments(signatures[0], args, node, inferred, expected);
95
+ return { results, inferred };
96
+ }
97
+ const takes = (signature) => args.some((arg) => arg.kind === 'SpreadElement') ||
98
+ (args.length >= signature.required &&
99
+ (args.length <= signature.params.length || signature.rest !== null));
100
+ const ordered = [...signatures.filter(takes), ...signatures.filter((each) => !takes(each))];
101
+ const errors = this.diagnostics.length;
102
+ for (const signature of ordered) {
103
+ const inferred = new Map();
104
+ const results = this.checkArguments(signature, args, node, inferred, expected);
105
+ if (this.diagnostics.length === errors)
106
+ return { results, inferred };
107
+ this.diagnostics.length = errors;
108
+ }
109
+ // The same signature may be declared twice, as `fetch` by lib.dom and @types/node.
110
+ const listed = [...new Set(signatures.map(typeToString))];
111
+ this.error(`no overload fits these arguments: ${listed.join('; ')}`, node);
112
+ this.checkArgumentsLoosely(args);
113
+ const results = signatures[0].results.map((result) => substitute(result, new Map(), UNKNOWN));
114
+ return { results, inferred: new Map() };
115
+ }
116
+ checkArgumentsLoosely(args) {
117
+ for (const arg of args)
118
+ this.checkValue(arg.kind === 'SpreadElement' ? arg.argument : arg, ANY);
119
+ }
120
+ /**
121
+ * Checks call arguments against a signature and returns the result types. Type parameters are
122
+ * inferred into `inferred` from the arguments and then from the expected result.
123
+ */
124
+ checkArguments(signature, args, node, inferred = new Map(), expected = null) {
125
+ const hasSpread = args.some((arg) => arg.kind === 'SpreadElement');
126
+ if (!hasSpread) {
127
+ if (args.length < signature.required) {
128
+ this.error(`not enough arguments: expected ${signature.required}, got ${args.length}`, node);
129
+ }
130
+ else if (args.length > signature.params.length && signature.rest === null) {
131
+ this.error(`too many arguments: expected ${signature.params.length}, got ${args.length}`, args[signature.params.length]);
132
+ }
133
+ }
134
+ // Arrow functions without parameter types are checked last: their parameter types may depend
135
+ // on type parameters inferred from the other arguments (e.g. `reduce(f, initial)`).
136
+ const needsContext = (arg) => arg.kind === 'ArrowFunction' && arg.params.some((param) => param.type === null);
137
+ const inferring = this.inferring;
138
+ this.inferring = new Set(signature.typeParams);
139
+ const errors = this.diagnostics.length;
140
+ // What the other arguments leave open comes from the expected result, before those arrow
141
+ // functions: `const done Promise<number> = new Promise(resolve => ...)`.
142
+ const fromExpected = () => {
143
+ if (expected && signature.results.length === 1) {
144
+ inferTypeParams(signature.results[0], expected, inferred);
145
+ }
146
+ };
147
+ try {
148
+ this.checkArgumentList(signature, args, inferred, needsContext, fromExpected);
149
+ }
150
+ finally {
151
+ this.inferring = inferring;
152
+ }
153
+ fromExpected();
154
+ for (const param of signature.typeParams) {
155
+ if (!inferred.has(param) && param.default)
156
+ inferred.set(param, param.default);
157
+ }
158
+ // `let xs = empty()`: nothing says what T is. Not reported after errors in the arguments.
159
+ const unknown = signature.typeParams.filter((param) => !inferred.has(param) &&
160
+ signature.results.some((result) => containsTypeParam(result, new Set([param]))));
161
+ if (unknown.length > 0 && this.diagnostics.length === errors) {
162
+ this.error(`cannot infer ${unknown.map((param) => param.name).join(', ')}: declare the type of the result`, node);
163
+ }
164
+ for (const param of signature.typeParams) {
165
+ const type = inferred.get(param);
166
+ if (type && param.constraint && !isAssignable(type, param.constraint)) {
167
+ this.error(`${typeToString(type)} does not satisfy the constraint ${typeToString(param.constraint)} of ${param.name}`, node);
168
+ }
169
+ }
170
+ return signature.results.map((result) => substitute(result, inferred, UNKNOWN));
171
+ }
172
+ checkArgumentList(signature, args, inferred, needsContext, beforeContext) {
173
+ for (const contextPass of [false, true]) {
174
+ if (contextPass)
175
+ beforeContext?.();
176
+ args.forEach((arg, i) => {
177
+ if (needsContext(arg) !== contextPass)
178
+ return;
179
+ if (arg.kind === 'SpreadElement') {
180
+ const type = this.checkValue(arg.argument);
181
+ if (isUntyped(type))
182
+ return;
183
+ if (type.kind !== 'array') {
184
+ this.error(`cannot spread ${typeToString(type)}: it is not an array`, arg.argument);
185
+ }
186
+ else if (signature.rest === null) {
187
+ this.error('a spread argument needs a "...rest" parameter', arg);
188
+ }
189
+ else {
190
+ this.expectAssignable(type.element, signature.rest, arg.argument);
191
+ }
192
+ return;
193
+ }
194
+ const param = signature.params[i] ?? signature.rest;
195
+ if (!param) {
196
+ this.checkValue(arg);
197
+ return;
198
+ }
199
+ // An expected type with parameters that are not inferred yet would reject the argument:
200
+ // `[1, 2]` for `[]T` is checked on its own, and T is inferred from it.
201
+ const expected = substitute(param, inferred);
202
+ const type = this.checkValue(arg, arg.kind === 'ArrowFunction' || !containsTypeParam(expected, this.inferring)
203
+ ? expected
204
+ : null);
205
+ inferTypeParams(param, type, inferred);
206
+ this.expectAssignable(type, substitute(param, inferred), arg, ` in argument ${i + 1}`);
207
+ });
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,14 @@
1
+ import { type ObjectType, type Type } from './types.ts';
2
+ export type ChanDirection = 'both' | 'send' | 'receive';
3
+ export declare const CHAN: ObjectType;
4
+ export declare function chanOf(element: Type, direction?: ChanDirection): ObjectType;
5
+ export declare function isChan(type: Type): type is ObjectType;
6
+ /** Which way a channel type goes, or null for a type that is not a channel. */
7
+ export declare function chanDirection(type: ObjectType): ChanDirection | null;
8
+ /** The type of the values of a channel type. */
9
+ export declare function elementOf(chan: ObjectType): Type;
10
+ /**
11
+ * What `<-ch` gives: the value, or after `close` the zero value of its type, as in Go. A type
12
+ * without a zero value (an interface, a class) gives null then.
13
+ */
14
+ export declare function received(element: Type): Type;
@@ -0,0 +1,44 @@
1
+ import { hasZeroValue, instantiate, nullable } from "./types.js";
2
+ function template(name) {
3
+ return {
4
+ kind: 'object',
5
+ name,
6
+ members: new Map(),
7
+ call: null,
8
+ typeParams: [{ kind: 'param', name: 'T' }],
9
+ };
10
+ }
11
+ export const CHAN = template('chan');
12
+ const TEMPLATES = {
13
+ both: CHAN,
14
+ send: template('chan<-'),
15
+ receive: template('<-chan'),
16
+ };
17
+ export function chanOf(element, direction = 'both') {
18
+ return instantiate(TEMPLATES[direction], [element]);
19
+ }
20
+ export function isChan(type) {
21
+ return type.kind === 'object' && chanDirection(type) !== null;
22
+ }
23
+ /** Which way a channel type goes, or null for a type that is not a channel. */
24
+ export function chanDirection(type) {
25
+ const template = type.instanceOf?.template;
26
+ if (template === TEMPLATES.both)
27
+ return 'both';
28
+ if (template === TEMPLATES.send)
29
+ return 'send';
30
+ if (template === TEMPLATES.receive)
31
+ return 'receive';
32
+ return null;
33
+ }
34
+ /** The type of the values of a channel type. */
35
+ export function elementOf(chan) {
36
+ return chan.instanceOf.args[0];
37
+ }
38
+ /**
39
+ * What `<-ch` gives: the value, or after `close` the zero value of its type, as in Go. A type
40
+ * without a zero value (an interface, a class) gives null then.
41
+ */
42
+ export function received(element) {
43
+ return hasZeroValue(element) ? element : nullable(element);
44
+ }
@@ -0,0 +1,9 @@
1
+ import type * as ast from '../ast.ts';
2
+ import { GoroutineChecker } from './goroutines.ts';
3
+ import { type Type } from './types.ts';
4
+ export declare abstract class ChannelChecker extends GoroutineChecker {
5
+ protected checkChan(node: ast.ChanExpression): Type;
6
+ protected checkSend(node: ast.SendStatement): void;
7
+ protected checkCall(node: ast.CallExpression, callee: Type, expected?: Type | null): Type;
8
+ protected checkSelect(node: ast.SelectStatement): void;
9
+ }
@@ -0,0 +1,95 @@
1
+ import { assignedNames } from "../names.js";
2
+ import { chanDirection, chanOf, elementOf, isChan } from "./channel.js";
3
+ import { GoroutineChecker } from "./goroutines.js";
4
+ import { isUntyped } from "./helpers.js";
5
+ import { isPromise } from "./promise.js";
6
+ import { BUFFERS } from "./transfer.js";
7
+ import { BOOL, isNullable, nonNull, NUMBER, typeToString } from "./types.js";
8
+ // Channels: `chan<number>(10)` makes one, `ch <- v` sends a value, `<-ch` receives one (in
9
+ // operators.ts), `for v in ch` receives them until it is closed (in control-flow.ts), and
10
+ // `select` waits for the first of several. `transfer(x)` moves a buffer to another thread.
11
+ /** What `transfer(x)` moves: a buffer, or a view whose buffer moves. */
12
+ const MOVABLE = new Set(BUFFERS);
13
+ function typeName(type) {
14
+ if (type.kind === 'class')
15
+ return type.info.name;
16
+ if (type.kind === 'object')
17
+ return type.instanceOf?.template.name ?? type.name;
18
+ return null;
19
+ }
20
+ export class ChannelChecker extends GoroutineChecker {
21
+ checkChan(node) {
22
+ const element = this.resolveType(node.element);
23
+ if (node.size)
24
+ this.expectAssignable(this.checkValue(node.size, NUMBER), NUMBER, node.size);
25
+ return chanOf(element);
26
+ }
27
+ checkSend(node) {
28
+ const nullChannel = this.inSelectCase;
29
+ this.inSelectCase = false;
30
+ const type = this.checkValue(node.channel);
31
+ const channel = nullChannel && isNullable(type) ? nonNull(type) : type;
32
+ if (!isChan(channel)) {
33
+ if (!isUntyped(channel)) {
34
+ this.error(`"<-" sends to a channel, not to ${typeToString(channel)}`, node.channel);
35
+ }
36
+ this.checkValue(node.value);
37
+ return;
38
+ }
39
+ const element = elementOf(channel);
40
+ if (chanDirection(channel) === 'receive') {
41
+ this.error(`"<-" cannot send to ${typeToString(channel)}: it only receives; send to a "chan T" or a "chan<- T"`, node.channel);
42
+ }
43
+ this.expectAssignable(this.checkValue(node.value, element), element, node.value);
44
+ }
45
+ // `close(ch)` takes any channel, but a channel is closed by its sender, so not a `<-chan T`;
46
+ // `cancel(task)` takes the Promise of `go`; `transfer(x)` takes what postMessage can move: a
47
+ // buffer, or a view of one.
48
+ checkCall(node, callee, expected = null) {
49
+ const result = super.checkCall(node, callee, expected);
50
+ const [argument] = node.arguments;
51
+ const type = argument && argument.kind !== 'SpreadElement' && this.checkedTypes.get(argument);
52
+ const builtin = node.callee.kind === 'Identifier' &&
53
+ this.lookupValue(node.callee.name) === this.globals.values.get(node.callee.name)
54
+ ? node.callee.name
55
+ : null;
56
+ if (!type || !argument)
57
+ return result;
58
+ if (builtin === 'close' && isChan(type) && chanDirection(type) === 'receive') {
59
+ this.error(`cannot close ${typeToString(type)}: it only receives, and a channel is closed by its sender`, argument);
60
+ }
61
+ if (builtin === 'cancel' && !isUntyped(type) && !isPromise(type)) {
62
+ this.error(`cancel() stops a goroutine: give it the Promise of "go", not ${typeToString(type)}, e.g. "const task = go work(x)" and "cancel(task)"`, argument);
63
+ }
64
+ if (builtin === 'transfer' && !isUntyped(type) && !MOVABLE.has(typeName(type) ?? '')) {
65
+ this.error(`transfer() moves an ArrayBuffer or a typed array to another thread, not ${typeToString(type)}; other values are copied`, argument);
66
+ }
67
+ return result;
68
+ }
69
+ checkSelect(node) {
70
+ this.dropNarrowing(assignedNames(node));
71
+ const entry = this.flow;
72
+ for (const { names, operation, body } of node.cases) {
73
+ this.flow = new Map(entry);
74
+ this.withScope(() => {
75
+ // A null channel turns its case off, as a nil channel does in Go.
76
+ this.inSelectCase = operation !== null;
77
+ if (operation?.kind === 'SendStatement') {
78
+ this.checkSend(operation);
79
+ }
80
+ else if (operation) {
81
+ // `case v, ok = <-ch:` declares the variables of the case.
82
+ const value = this.checkExpression(operation, null);
83
+ const [name, ok] = names;
84
+ if (name)
85
+ this.declareValue(name, 'const', value);
86
+ if (ok)
87
+ this.declareValue(ok, 'const', BOOL);
88
+ }
89
+ this.inSelectCase = false;
90
+ this.checkBlock(body);
91
+ });
92
+ }
93
+ this.flow = entry;
94
+ }
95
+ }
@@ -0,0 +1,4 @@
1
+ import type * as ast from '../ast.ts';
2
+ import type { CheckOptions, CheckResult } from './context.ts';
3
+ export type { CheckOptions, CheckResult, Completion, CompletionContext, CompletionResult, ImportResult, Library, ModuleExports, } from './context.ts';
4
+ export declare function check(program: ast.Program, options?: CheckOptions): CheckResult;
@@ -0,0 +1,22 @@
1
+ import { CompletionChecker } from "./completion.js";
2
+ // The type checker of a module; its layers are listed in base.ts.
3
+ class Checker extends CompletionChecker {
4
+ run() {
5
+ this.checkStatementList(this.program.body, true);
6
+ this.checkEndlessRecursion();
7
+ this.checkIterators();
8
+ this.checkHtmlTags();
9
+ this.diagnostics.sort((a, b) => a.start - b.start);
10
+ this.warnings.sort((a, b) => a.start - b.start);
11
+ return {
12
+ diagnostics: this.diagnostics,
13
+ warnings: this.warnings,
14
+ ...this.collectDeclarations(),
15
+ types: this.checkedTypes,
16
+ ...(this.completion ? { completion: this.completion } : {}),
17
+ };
18
+ }
19
+ }
20
+ export function check(program, options = {}) {
21
+ return new Checker(program, options).run();
22
+ }
@@ -0,0 +1,24 @@
1
+ import type * as ast from '../ast.ts';
2
+ import { type ModulePackages } from '../inline-packages.ts';
3
+ import type { ModuleExports } from './context.ts';
4
+ import { DeclarationChecker } from './declarations.ts';
5
+ import { type ClassInfo, type Member } from './types.ts';
6
+ export declare abstract class ClassChecker extends DeclarationChecker {
7
+ protected ensureClassResolved(info: ClassInfo): void;
8
+ /** Resolves the base class and the types of all members (but does not check method bodies). */
9
+ protected resolveClass(node: ast.ClassDeclaration, info: ClassInfo): void;
10
+ protected resolveClassMembers(node: ast.ClassDeclaration, info: ClassInfo): void;
11
+ protected declareMember(info: ClassInfo, isStatic: boolean, name: ast.Identifier, member: Member): void;
12
+ /** Method bodies and the checks that need every member of the class. */
13
+ protected checkClassBodies(node: ast.ClassDeclaration, info: ClassInfo): void;
14
+ protected checkClassMembers(node: ast.ClassDeclaration, info: ClassInfo): void;
15
+ protected checkOverride(info: ClassInfo, method: ast.MethodDeclaration): void;
16
+ private packages;
17
+ /** What other modules need to inline the exported components and decorators of this one. */
18
+ protected modulePackages(): ModulePackages;
19
+ /** The top-level declarations, and those of them that are exported. */
20
+ protected collectDeclarations(): {
21
+ exports: ModuleExports;
22
+ declarations: ModuleExports;
23
+ };
24
+ }
@@ -0,0 +1,223 @@
1
+ import { inlinePackages } from "../inline-packages.js";
2
+ import { DeclarationChecker } from "./declarations.js";
3
+ import { isSuperCall, assignsField } from "./helpers.js";
4
+ import { explainMismatch, findClassMember, hasZeroValue, isAssignable, isSubclass, typeToString, UNKNOWN, } from "./types.js";
5
+ // Classes: their base class and members, method bodies, overrides and `implements`; and the declarations a module exports.
6
+ export class ClassChecker extends DeclarationChecker {
7
+ ensureClassResolved(info) {
8
+ const resolve = this.unresolvedClasses.get(info);
9
+ if (!resolve || this.resolvingClasses.has(info))
10
+ return;
11
+ this.resolvingClasses.add(info);
12
+ try {
13
+ resolve();
14
+ }
15
+ finally {
16
+ this.resolvingClasses.delete(info);
17
+ this.unresolvedClasses.delete(info);
18
+ }
19
+ }
20
+ /** Resolves the base class and the types of all members (but does not check method bodies). */
21
+ resolveClass(node, info) {
22
+ this.withTypeParams(info.typeParams, node.typeParams, () => this.resolveClassMembers(node, info));
23
+ }
24
+ resolveClassMembers(node, info) {
25
+ if (node.superClass) {
26
+ const base = this.checkValue(node.superClass);
27
+ const baseParams = base.kind === 'classValue' ? base.info.typeParams : [];
28
+ if (base.kind === 'classValue' && baseParams.some((param) => !param.default)) {
29
+ // The base is a value, as in JS, so it has no type arguments: `extends Stack<number>` cannot be written.
30
+ this.error(`cannot extend the generic class "${base.info.name}": generic base classes are not supported`, node.superClass);
31
+ info.untypedBase = true;
32
+ }
33
+ else if (base.kind === 'classValue') {
34
+ this.ensureClassResolved(base.info);
35
+ if (this.resolvingClasses.has(base.info) || isSubclass(base.info, info)) {
36
+ this.error(`class "${info.name}" cannot extend itself`, node.superClass);
37
+ }
38
+ else {
39
+ info.superClass = base.info;
40
+ // A generic class from a `.d.ts` whose parameters all have defaults.
41
+ if (baseParams.length > 0)
42
+ info.superArgs = baseParams.map((param) => param.default);
43
+ }
44
+ }
45
+ else if (base.kind === 'any') {
46
+ info.untypedBase = true;
47
+ }
48
+ else if (base.kind !== 'unknown') {
49
+ this.error(`cannot extend ${typeToString(base)}: it is not a class`, node.superClass);
50
+ }
51
+ }
52
+ for (const member of node.members) {
53
+ switch (member.kind) {
54
+ case 'FieldDeclaration': {
55
+ const declared = member.type ? this.resolveType(member.type) : null;
56
+ let type = declared ?? UNKNOWN;
57
+ const { value } = member;
58
+ if (value) {
59
+ const valueType = this.withClass({ info, isStatic: member.isStatic }, () => this.checkValue(value, declared));
60
+ if (declared)
61
+ this.expectAssignable(valueType, declared, value);
62
+ else
63
+ type = this.inferredType(valueType, value);
64
+ }
65
+ this.declareMember(info, member.isStatic, member.name, {
66
+ type,
67
+ method: false,
68
+ visibility: member.visibility,
69
+ owner: info,
70
+ });
71
+ break;
72
+ }
73
+ case 'MethodDeclaration':
74
+ this.declareMember(info, member.isStatic, member.name, {
75
+ type: this.signature(member.params, member.results, member.async),
76
+ method: true,
77
+ visibility: member.visibility,
78
+ owner: info,
79
+ });
80
+ break;
81
+ case 'ConstructorDeclaration':
82
+ if (info.ctor)
83
+ this.error('a class can have only one constructor', member);
84
+ info.ctor = this.signature(member.params, []);
85
+ info.ctorVisibility = member.visibility;
86
+ break;
87
+ }
88
+ }
89
+ }
90
+ declareMember(info, isStatic, name, member) {
91
+ const members = isStatic ? info.statics : info.members;
92
+ if (members.has(name.name))
93
+ this.error(`duplicate member "${name.name}"`, name);
94
+ members.set(name.name, member);
95
+ }
96
+ /** Method bodies and the checks that need every member of the class. */
97
+ checkClassBodies(node, info) {
98
+ this.withTypeParams(info.typeParams, null, () => this.checkClassMembers(node, info));
99
+ }
100
+ checkClassMembers(node, info) {
101
+ let constructorNode = null;
102
+ for (const member of node.members) {
103
+ if (member.kind === 'MethodDeclaration') {
104
+ const type = (member.isStatic ? info.statics : info.members).get(member.name.name)?.type;
105
+ if (type?.kind !== 'function')
106
+ continue;
107
+ this.withClass({ info, isStatic: member.isStatic }, () => this.checkFunction(member.params, type, type.results, member.body, {
108
+ async: member.async,
109
+ }));
110
+ this.checkOverride(info, member);
111
+ }
112
+ else if (member.kind === 'ConstructorDeclaration' && info.ctor) {
113
+ constructorNode = member;
114
+ const type = info.ctor;
115
+ this.withClass({ info, isStatic: false }, () => this.checkFunction(member.params, type, [], member.body, { isConstructor: true }));
116
+ const derived = info.superClass !== null || info.untypedBase;
117
+ if (derived && !member.body.body.some(isSuperCall)) {
118
+ this.error('the constructor of a derived class must call super(...)', member);
119
+ }
120
+ }
121
+ }
122
+ // Fields without a zero value must get one at once or in the constructor.
123
+ for (const member of node.members) {
124
+ if (member.kind !== 'FieldDeclaration' || member.isStatic || member.value)
125
+ continue;
126
+ const type = info.members.get(member.name.name)?.type;
127
+ if (!type || hasZeroValue(type))
128
+ continue;
129
+ if (constructorNode && assignsField(constructorNode.body, member.name.name))
130
+ continue;
131
+ this.error(`field "${member.name.name}" needs a value: ${typeToString(type)} has no zero value, ` +
132
+ 'so initialize it here or assign it in the constructor', member.name);
133
+ }
134
+ for (const reference of node.implements) {
135
+ const target = this.resolveTypeName(reference.name, reference.typeArgs);
136
+ if (target.kind === 'unknown')
137
+ continue;
138
+ if (target.kind !== 'object' && target.kind !== 'class') {
139
+ this.error(`cannot implement ${typeToString(target)}: it is not an interface`, reference);
140
+ }
141
+ else if (!isAssignable(info.instance, target)) {
142
+ const reason = explainMismatch(info.instance, target);
143
+ this.error(`class "${info.name}" does not implement ${typeToString(target)}${reason ? `: ${reason}` : ''}`, reference);
144
+ }
145
+ }
146
+ }
147
+ checkOverride(info, method) {
148
+ if (!info.superClass)
149
+ return;
150
+ const base = findClassMember(info.superClass, method.name.name, method.isStatic);
151
+ const own = (method.isStatic ? info.statics : info.members).get(method.name.name);
152
+ if (!base || !own || isAssignable(own.type, base.type))
153
+ return;
154
+ this.error(`"${method.name.name}" overrides ${base.owner?.name ?? info.superClass.name}.${method.name.name} ` +
155
+ `with an incompatible type: ${typeToString(own.type)} instead of ${typeToString(base.type)}`, method.name);
156
+ }
157
+ packages = null;
158
+ /** What other modules need to inline the exported components and decorators of this one. */
159
+ modulePackages() {
160
+ return (this.packages ??= inlinePackages(this.program));
161
+ }
162
+ /** The top-level declarations, and those of them that are exported. */
163
+ collectDeclarations() {
164
+ const exports = {
165
+ values: new Map(),
166
+ types: new Map(),
167
+ decorators: new Map(),
168
+ components: new Map(),
169
+ };
170
+ const declarations = { values: new Map(), types: new Map() };
171
+ const valueOf = (name) => this.moduleScope.values.get(name)?.type ?? UNKNOWN;
172
+ const typeOf = (name) => {
173
+ const entry = this.moduleScope.types.get(name);
174
+ if (!entry)
175
+ return UNKNOWN;
176
+ return entry.kind === 'alias' ? this.resolveAlias(entry) : entry;
177
+ };
178
+ const add = (exported, kind, name, type) => {
179
+ declarations[kind].set(name, type);
180
+ if (exported)
181
+ exports[kind].set(name, type);
182
+ };
183
+ for (const statement of this.program.body) {
184
+ switch (statement.kind) {
185
+ case 'FuncDeclaration':
186
+ add(statement.exported, 'values', statement.name.name, valueOf(statement.name.name));
187
+ break;
188
+ case 'VariableDeclaration':
189
+ for (const name of statement.names) {
190
+ add(statement.exported, 'values', name.name, valueOf(name.name));
191
+ }
192
+ break;
193
+ case 'ClassDeclaration':
194
+ add(statement.exported, 'values', statement.name.name, valueOf(statement.name.name));
195
+ add(statement.exported, 'types', statement.name.name, typeOf(statement.name.name));
196
+ break;
197
+ case 'InterfaceDeclaration':
198
+ case 'TypeAliasDeclaration':
199
+ add(statement.exported, 'types', statement.name.name, typeOf(statement.name.name));
200
+ break;
201
+ case 'ComponentDeclaration': {
202
+ const info = this.moduleScope.values.get(statement.name.name)?.component;
203
+ if (statement.exported && info?.node === statement) {
204
+ info.inline = this.modulePackages().components.get(info.node.name.name) ?? null;
205
+ info.expressionTypes = this.checkedTypes;
206
+ exports.components.set(statement.name.name, info);
207
+ }
208
+ break;
209
+ }
210
+ case 'DecoratorDeclaration': {
211
+ const info = this.decorators.get(statement.name.name);
212
+ if (statement.exported && info?.node === statement) {
213
+ exports.decorators.set(statement.name.name, info);
214
+ }
215
+ break;
216
+ }
217
+ default:
218
+ break;
219
+ }
220
+ }
221
+ return { exports, declarations };
222
+ }
223
+ }
@@ -0,0 +1,11 @@
1
+ export declare const STRING_MEMBERS: string[];
2
+ export declare const NUMBER_MEMBERS: string[];
3
+ export declare const BOOL_MEMBERS: string[];
4
+ export declare const BIGINT_MEMBERS: string[];
5
+ export declare const ARRAY_MEMBERS: string[];
6
+ /** HTML tags, for completion without TypeScript's `HTMLElementTagNameMap`. */
7
+ export declare const HTML_TAGS: string[];
8
+ /** Event attributes as programs write them: `on` and the event in camel case. */
9
+ export declare const EVENT_ATTRIBUTES: string[];
10
+ /** DOM properties that attributes spell differently. */
11
+ export declare const ATTRIBUTE_NAMES: ReadonlyMap<string, string>;