@velarscript/compiler 0.12.1 → 0.13.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 (109) hide show
  1. package/dist/advisory-suppression.d.ts +62 -0
  2. package/dist/advisory-suppression.d.ts.map +1 -0
  3. package/dist/advisory-suppression.js +179 -0
  4. package/dist/advisory-suppression.js.map +1 -0
  5. package/dist/analyzer.d.ts +405 -17
  6. package/dist/analyzer.d.ts.map +1 -1
  7. package/dist/analyzer.js +1755 -211
  8. package/dist/analyzer.js.map +1 -1
  9. package/dist/ast.d.ts +6 -3
  10. package/dist/ast.d.ts.map +1 -1
  11. package/dist/ast.js.map +1 -1
  12. package/dist/binding-stability.d.ts +22 -0
  13. package/dist/binding-stability.d.ts.map +1 -0
  14. package/dist/binding-stability.js +63 -0
  15. package/dist/binding-stability.js.map +1 -0
  16. package/dist/collection-lowering-runtime.d.ts +1 -1
  17. package/dist/collection-lowering-runtime.d.ts.map +1 -1
  18. package/dist/collection-lowering-runtime.js +183 -56
  19. package/dist/collection-lowering-runtime.js.map +1 -1
  20. package/dist/diagnostic.d.ts +34 -0
  21. package/dist/diagnostic.d.ts.map +1 -1
  22. package/dist/diagnostic.js +11 -1
  23. package/dist/diagnostic.js.map +1 -1
  24. package/dist/embedded-javascript.d.ts +12 -1
  25. package/dist/embedded-javascript.d.ts.map +1 -1
  26. package/dist/embedded-javascript.js +111 -2
  27. package/dist/embedded-javascript.js.map +1 -1
  28. package/dist/embedded-module.d.ts.map +1 -1
  29. package/dist/embedded-module.js +22 -0
  30. package/dist/embedded-module.js.map +1 -1
  31. package/dist/emitter.d.ts +83 -1
  32. package/dist/emitter.d.ts.map +1 -1
  33. package/dist/emitter.js +518 -41
  34. package/dist/emitter.js.map +1 -1
  35. package/dist/error-runtime.d.ts +9 -0
  36. package/dist/error-runtime.d.ts.map +1 -1
  37. package/dist/error-runtime.js +21 -0
  38. package/dist/error-runtime.js.map +1 -1
  39. package/dist/extension.d.ts +5 -2
  40. package/dist/extension.d.ts.map +1 -1
  41. package/dist/extension.js +2 -1
  42. package/dist/extension.js.map +1 -1
  43. package/dist/formatter.d.ts.map +1 -1
  44. package/dist/formatter.js +222 -91
  45. package/dist/formatter.js.map +1 -1
  46. package/dist/index.d.ts +10 -2
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +43 -5
  49. package/dist/index.js.map +1 -1
  50. package/dist/interpolated-string.d.ts.map +1 -1
  51. package/dist/interpolated-string.js +29 -2
  52. package/dist/interpolated-string.js.map +1 -1
  53. package/dist/json-runtime.d.ts.map +1 -1
  54. package/dist/json-runtime.js +27 -3
  55. package/dist/json-runtime.js.map +1 -1
  56. package/dist/lexer.d.ts +217 -1
  57. package/dist/lexer.d.ts.map +1 -1
  58. package/dist/lexer.js +799 -37
  59. package/dist/lexer.js.map +1 -1
  60. package/dist/limits.d.ts +9 -0
  61. package/dist/limits.d.ts.map +1 -1
  62. package/dist/limits.js +9 -0
  63. package/dist/limits.js.map +1 -1
  64. package/dist/mechanical-fix.d.ts.map +1 -1
  65. package/dist/mechanical-fix.js +38 -0
  66. package/dist/mechanical-fix.js.map +1 -1
  67. package/dist/parser.d.ts +30 -1
  68. package/dist/parser.d.ts.map +1 -1
  69. package/dist/parser.js +137 -21
  70. package/dist/parser.js.map +1 -1
  71. package/dist/promise-runtime.d.ts +20 -1
  72. package/dist/promise-runtime.d.ts.map +1 -1
  73. package/dist/promise-runtime.js +38 -3
  74. package/dist/promise-runtime.js.map +1 -1
  75. package/dist/reactive-bridge-runtime.d.ts.map +1 -1
  76. package/dist/reactive-bridge-runtime.js +7 -1
  77. package/dist/reactive-bridge-runtime.js.map +1 -1
  78. package/dist/runtime-abi.d.ts +21 -1
  79. package/dist/runtime-abi.d.ts.map +1 -1
  80. package/dist/runtime-abi.js +23 -3
  81. package/dist/runtime-abi.js.map +1 -1
  82. package/dist/source-names.d.ts +26 -0
  83. package/dist/source-names.d.ts.map +1 -1
  84. package/dist/source-names.js +49 -5
  85. package/dist/source-names.js.map +1 -1
  86. package/dist/source.d.ts.map +1 -1
  87. package/dist/source.js +13 -0
  88. package/dist/source.js.map +1 -1
  89. package/dist/stable-order.d.ts +16 -0
  90. package/dist/stable-order.d.ts.map +1 -0
  91. package/dist/stable-order.js +18 -0
  92. package/dist/stable-order.js.map +1 -0
  93. package/dist/text-runtime.d.ts.map +1 -1
  94. package/dist/text-runtime.js +182 -41
  95. package/dist/text-runtime.js.map +1 -1
  96. package/dist/token.d.ts +11 -0
  97. package/dist/token.d.ts.map +1 -1
  98. package/dist/token.js.map +1 -1
  99. package/dist/type-registry-runtime.d.ts.map +1 -1
  100. package/dist/type-registry-runtime.js +8 -1
  101. package/dist/type-registry-runtime.js.map +1 -1
  102. package/dist/type-validation-runtime.d.ts.map +1 -1
  103. package/dist/type-validation-runtime.js +129 -1
  104. package/dist/type-validation-runtime.js.map +1 -1
  105. package/dist/types.d.ts +17 -1
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/types.js +161 -17
  108. package/dist/types.js.map +1 -1
  109. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import type { Expression, FunctionDeclaration, Program, Statement, TypeParameterDeclaration, TypeReference, TypeSyntax } from "./ast.ts";
2
2
  import { type PermanentNamespaceName } from "./core-vocabulary.ts";
3
- import { type Diagnostic, type DiagnosticFix } from "./diagnostic.ts";
3
+ import { type Advisory, type Diagnostic, type DiagnosticFix } from "./diagnostic.ts";
4
4
  import type { CompilerAnalysisExtension } from "./extension.ts";
5
5
  import { type Span } from "./source.ts";
6
6
  import { type EnumInfo, type BinaryStorageKind, type ExtensionValueType, type GenericTypeInfo, type TypeEnvironment, type TypeParameterBound, type ValueType } from "./types.ts";
@@ -12,6 +12,12 @@ interface Binding {
12
12
  readonly storageBinding?: Binding;
13
13
  readonly span: Span;
14
14
  narrowingFrame: number | null;
15
+ /**
16
+ * The scope depth this binding was created at. A flow snapshot only visits
17
+ * bindings whose facts have actually moved, and this is how the set of those
18
+ * is emptied again when the scope holding them exits.
19
+ */
20
+ readonly flowScope?: number;
15
21
  /**
16
22
  * D44 rule 71: true while the active narrowing was established by an
17
23
  * assignment (or a declaration initializer) rather than a check. Only
@@ -42,6 +48,8 @@ interface AnalyzableFunctionDeclaration {
42
48
  readonly body: FunctionDeclaration["body"];
43
49
  readonly span: Span;
44
50
  readonly asynchronous?: boolean;
51
+ readonly exported?: boolean;
52
+ readonly private?: boolean;
45
53
  }
46
54
  export interface ClassField {
47
55
  readonly mutable: boolean;
@@ -58,6 +66,14 @@ export interface ClassInfo {
58
66
  * than composes.
59
67
  */
60
68
  readonly iterate?: ValueType;
69
+ /**
70
+ * D90 R18: the element the class's asynchronous `@iterate:` form answers
71
+ * with. The block is the declared spelling of the pull contract `async for`
72
+ * consumes — pulled once per element, it may await, it answers `T?`, and
73
+ * null is exhaustion. A class declares one form or the other; the answer's
74
+ * shape (a collection against `T?`) is what tells them apart.
75
+ */
76
+ readonly iterateAsync?: ValueType;
61
77
  readonly parameters: readonly ValueType[];
62
78
  readonly parameterNames?: readonly string[];
63
79
  readonly requiredParameters: number;
@@ -206,6 +222,18 @@ export interface LoweringHints {
206
222
  * returns and every consumer keeps the lowering it already had.
207
223
  */
208
224
  readonly iterationContracts: ReadonlySet<string>;
225
+ /**
226
+ * D90 R18: start offsets of `async for` statements whose source's class
227
+ * declares the asynchronous `@iterate:` form. The emitter pulls these
228
+ * through the declared member instead of capturing a structural `next`.
229
+ */
230
+ readonly asyncIterationStatements: ReadonlySet<number>;
231
+ /**
232
+ * D90 R18: span identities of the `@iterate:` blocks that are the
233
+ * asynchronous pull form, keyed by their keyword span, so the emitter lands
234
+ * each one as an async method under its own key.
235
+ */
236
+ readonly asyncIterateBlocks: ReadonlySet<string>;
209
237
  /**
210
238
  * Span identities of JavaScript-boundary calls in synchronous
211
239
  * module-initialization position. A non-Error value thrown there would
@@ -275,6 +303,14 @@ export declare const disposeMemberKey = "__velar:dispose";
275
303
  * member can answer it by accident and no author call can reach it.
276
304
  */
277
305
  export declare const iterateMemberKey = "__velar:iterate";
306
+ /**
307
+ * The emitted member behind the asynchronous `@iterate:` form (D90 R18). It is
308
+ * a separate key because the two forms answer different questions — the
309
+ * synchronous member returns the finished collection once, this one is an
310
+ * async method `async for` pulls once per element — so no lowering can confuse
311
+ * one for the other.
312
+ */
313
+ export declare const iterateAsyncMemberKey = "__velar:iterateAsync";
278
314
  /** How a `using` binding releases its value at scope exit. */
279
315
  export interface DisposalContract {
280
316
  readonly member: string;
@@ -293,8 +329,22 @@ export declare function permanentNamespaceCoveringModule(source: string, exports
293
329
  export declare function isCorePrimitiveName(name: string): boolean;
294
330
  export declare class Analyzer implements TypeEnvironment {
295
331
  protected readonly diagnostics: Diagnostic[];
332
+ protected readonly advisories: Advisory[];
333
+ private readonly advisedIdentities;
296
334
  private readonly scopes;
297
335
  private readonly memberNarrowings;
336
+ /** Per scope depth, the names a narrowing has written there; see `narrowingsForVisibleBindings`. */
337
+ private readonly narrowedNames;
338
+ /** How many loop back-edge passes are running; see `reanalyzeLoopBackEdge`. */
339
+ private loopReanalysisDepth;
340
+ /** The "did you mean" roster, and the names each scope depth contributed to it. */
341
+ private readonly nearestNames;
342
+ private readonly scopedNames;
343
+ private nearestNamesSeeded;
344
+ /** Per scope depth, the bindings flow analysis has written; see `snapshotFlowFacts`. */
345
+ private readonly flowTouched;
346
+ /** What each of those held before its first write, or null for a shadow born mid-flow. */
347
+ private readonly flowOrigins;
298
348
  private readonly namedTypes;
299
349
  private readonly namedTypeReadonlyFields;
300
350
  private readonly namedTypeIdentities;
@@ -345,12 +395,10 @@ export declare class Analyzer implements TypeEnvironment {
345
395
  private readonly classDisposeChains;
346
396
  /** D68 rule 177: expression spans a consumer iterates through `@iterate:`. */
347
397
  private readonly iterationContracts;
348
- /**
349
- * D68 rule 177: the function depth of each `@iterate:` body being analyzed.
350
- * A nested arrow inside the block is an ordinary callable and keeps the
351
- * ordinary advice, so the contract's own message needs the exact depth.
352
- */
353
- private readonly iterateContractDepths;
398
+ /** D90 R18: `async for` statements pulling a declared asynchronous `@iterate:`. */
399
+ private readonly asyncIterationStatements;
400
+ /** D90 R18: `@iterate:` blocks that are the asynchronous pull form, by keyword span. */
401
+ private readonly asyncIterateBlocks;
354
402
  /** D51 rule 101: arrows that read a `using`-owned binding, by arrow span. */
355
403
  private readonly arrowOwnedCaptures;
356
404
  private readonly arrowCaptureFrames;
@@ -413,6 +461,22 @@ export declare class Analyzer implements TypeEnvironment {
413
461
  private readonly inferredFunctionResultSeeds;
414
462
  private readonly inferredFunctionResultTypes;
415
463
  private readonly finalizeFunctionResultInference;
464
+ /**
465
+ * D85 rule 209: one mistake is reported once. A reported VEL4039 hands its
466
+ * position `invalidType`, and an invalid body-inferred result is otherwise a
467
+ * convergence failure — so the four collections below carry the *reported*
468
+ * hole forward, and only that hole, to the place VEL4025 is decided.
469
+ * `reportedCollectionHoles` are the names bound to one, `reportedResultHoles`
470
+ * the local function results that are one, `functionResultKeys` maps a
471
+ * callable name to the result a call to it reaches, and
472
+ * `deferredConvergenceReports` holds the reports whose answer needs a callee
473
+ * that may be declared further down the module.
474
+ */
475
+ private readonly reportedCollectionHoles;
476
+ private readonly bindingHoleCauses;
477
+ private readonly reportedResultHoles;
478
+ private readonly functionResultKeys;
479
+ private readonly deferredConvergenceReports;
416
480
  private readonly logicalConditionNarrowings;
417
481
  private readonly privateFields;
418
482
  private readonly privateGetters;
@@ -438,8 +502,27 @@ export declare class Analyzer implements TypeEnvironment {
438
502
  /** Namespace import locals by name, known before signature validation runs (ENM-I9 teaching). */
439
503
  private readonly namespaceImportLocals;
440
504
  private readonly initializationImportReadSites;
505
+ /**
506
+ * D31 item 23's recorded residual: a top-level call of a module-local
507
+ * function runs that body during module evaluation, so a read of an imported
508
+ * binding inside it is an initialization-position read reached through one
509
+ * hop. The stack is the function frame a deferred read belongs to; the map
510
+ * is that frame by the name it was bound to, so a call resolves to it after
511
+ * the whole module is analyzed and hoisting order stops mattering.
512
+ */
513
+ private readonly deferredReadFrames;
514
+ private readonly localFunctionFrames;
515
+ private readonly arrowDeferredFrames;
516
+ private readonly initializationLocalCalls;
441
517
  /** Local class bindings mapped to the source offset where their `class` statement evaluates (CLS-D8). */
442
518
  private readonly hoistedClassDeclarations;
519
+ /**
520
+ * D90 R12: public class members whose omitted annotation inferred an output
521
+ * `any`. Whether the member is at an export position depends on whether a
522
+ * consumer can reach its class, which is not settled until the whole module
523
+ * is analyzed, so the report waits for reportExportPositionAny.
524
+ */
525
+ private readonly exportPositionCandidates;
443
526
  /** Module-scope names bound to runtime Type objects (local and imported); see LoweringHints.runtimeTypeObjectNames. */
444
527
  private readonly runtimeTypeObjectNames;
445
528
  private staticFieldInitialization;
@@ -474,11 +557,29 @@ export declare class Analyzer implements TypeEnvironment {
474
557
  * answer applies.
475
558
  */
476
559
  private guidanceForGlobal;
560
+ /**
561
+ * D90 (coherence): the one report an unresolved name earns, wherever it was
562
+ * written. A reserved global names the module that replaced it, a foreign
563
+ * builtin with no successor stops at the bare message rather than guessing,
564
+ * and everything else may carry the nearest visible name. Both unresolved-
565
+ * name sites reach this, because `exports = {run: run}` is the same mistake
566
+ * as `const value = exports` and used to earn a strictly worse answer for
567
+ * standing on the left of the `=`.
568
+ */
569
+ private reportUnresolvedName;
477
570
  private nearestVisibleBindingName;
571
+ /** Files a scope's name in the "did you mean" roster and takes it back out when the scope exits. */
572
+ private recordScopedName;
478
573
  private readonly modulePath;
479
574
  private readonly importBindings;
480
575
  private readonly dynamicImports;
481
576
  analyze(program: Program): readonly Diagnostic[];
577
+ /**
578
+ * D89: the advisories this analysis raised. `analyze` keeps returning the
579
+ * diagnostics alone, so the caller reads the two channels separately and the
580
+ * cursor arithmetic over `this.diagnostics` stays exact.
581
+ */
582
+ analyzedAdvisories(): readonly Advisory[];
482
583
  private registerExternTypeImports;
483
584
  private validateDataTypeDeclarations;
484
585
  private validateCoreDeclarationSignatures;
@@ -616,6 +717,21 @@ export declare class Analyzer implements TypeEnvironment {
616
717
  private registerClassNames;
617
718
  private registerClassShapes;
618
719
  protected analyzeStatement(statement: Statement): void;
720
+ /**
721
+ * D89 A2: the two-slot `for` over a List, Set, or string binds
722
+ * `value, index`, which matches JavaScript's `forEach((v, i) => …)` and
723
+ * inverts Python's `enumerate`. Python's own spelling is already a loud
724
+ * error, so nothing silent comes from it; the silence happens when a model
725
+ * writes `for i, v in nums`, a hybrid neither language has, and both names
726
+ * quietly hold the other one's value.
727
+ *
728
+ * Both rosters must hit. One name alone proves nothing — `for index, total
729
+ * in scores` may be counting exactly what it says — and a wrong guess here
730
+ * would tell a correct author to break working code. The value slot also
731
+ * accepts the singular of the collection's own name, because `for i, user
732
+ * in users` is the same reflex spelled from the data instead of a letter.
733
+ */
734
+ private adviseSwappedLoopSlots;
619
735
  private checkFloatingPromiseStatement;
620
736
  private checkDiscardedExpressionResult;
621
737
  private carriesPromise;
@@ -704,23 +820,44 @@ export declare class Analyzer implements TypeEnvironment {
704
820
  * result has and gets the same solution.
705
821
  */
706
822
  private seededIterationSource;
823
+ /**
824
+ * D90 R18: the seed routed to the field its form owns. An optional seed can
825
+ * only have come from the asynchronous pull form — the synchronous form
826
+ * never validates to `T?` — so the shape pre-pass reads the form off the
827
+ * seed the previous convergence pass learned.
828
+ */
829
+ private seededIterationInfo;
707
830
  /**
708
831
  * `@iterate:` answers the compiler's question "what does
709
- * iterating you mean?" with a collection the language already iterates. It
710
- * shares `@dispose:`'s compiler-name path, then supplies its own role: it is
711
- * a contract, not a method, it produces a value, and it may not `await`,
712
- * because every one of the eight consumers reads it synchronously.
832
+ * iterating you mean?". It shares `@dispose:`'s compiler-name path, then
833
+ * supplies its own role: it is a contract, not a method, and it produces a
834
+ * value. D90 R18 gives it two forms, told apart by the answer's shape the
835
+ * same way `@dispose:`'s async-ness is read off its own body: the
836
+ * synchronous form answers a collection the language already iterates and
837
+ * the eight plain consumers read it once; the asynchronous pull form
838
+ * answers `T?` — `async for` drives it once per element, it may await, and
839
+ * null is exhaustion.
713
840
  */
714
841
  private analyzeClassIterate;
715
842
  /**
716
- * The four collections are the whole answer space: the block says "iterating
717
- * me is iterating this", and the language already fixed what iterating a
718
- * List, Set, Map, or Record means. Anything else would be a second iteration
719
- * semantics, which is the thing charter section 19 keeps out.
843
+ * The answer space is the four collections plus `T?` (D90 R18): the
844
+ * synchronous form says "iterating me is iterating this", and the language
845
+ * already fixed what iterating a List, Set, Map, or Record means; the
846
+ * asynchronous pull form answers one element per pull, null for exhaustion.
847
+ * Anything else would be a second iteration semantics, which is the thing
848
+ * charter section 19 keeps out.
720
849
  */
721
850
  private validatedIterationSource;
722
851
  /** The `@iterate:` answer a class inherits, most derived ancestor first. */
723
852
  private inheritedIterationSource;
853
+ /** D90 R18: the asynchronous `@iterate:` element a class inherits, most derived ancestor first. */
854
+ private inheritedAsyncIterationSource;
855
+ /**
856
+ * D90 R18: what pulling this value under `async for` means. A class answers
857
+ * through the asynchronous `@iterate:` form — its own, or the one it
858
+ * inherits, mirroring the synchronous contract exactly.
859
+ */
860
+ private asyncIterationContract;
724
861
  /**
725
862
  * D68 rule 177: what iterating this value means. A class answers through
726
863
  * `@iterate:` — its own, or the one it inherits, because overriding replaces
@@ -782,6 +919,15 @@ export declare class Analyzer implements TypeEnvironment {
782
919
  */
783
920
  private inferredNullResultAnnotation;
784
921
  private reportInferredNullResult;
922
+ /**
923
+ * D89 (message correction): the one report a `self` parameter earns, and the
924
+ * deletion it names. The removed range reaches to the next parameter's start
925
+ * (or back to the previous one's end), so the separating comma and its
926
+ * whitespace come with it without reading the source text — the rewrite is a
927
+ * spelling change with no judgment in it, which is what D38 §48 requires of
928
+ * a registered fix.
929
+ */
930
+ private reportImplicitSelfParameter;
785
931
  protected analyzeFunctionDeclaration(statement: AnalyzableFunctionDeclaration, className: string | null, method?: boolean, declareSelf?: boolean, forceAsynchronous?: boolean, declarationKind?: string): void;
786
932
  /**
787
933
  * A target-owned declaration may use an ordinary default expression as a
@@ -814,14 +960,57 @@ export declare class Analyzer implements TypeEnvironment {
814
960
  private containsCoreDuration;
815
961
  private inferCoreDurationExpression;
816
962
  private inferBinary;
963
+ /**
964
+ * D89 A3: `%` follows JavaScript and keeps the dividend's sign, so `-7 % 3`
965
+ * is `-1` where Python answers `2`. Nothing here reports an error — both
966
+ * languages accept the spelling, they just disagree about the result.
967
+ *
968
+ * Only a literal negative dividend triggers. A variable's sign is not
969
+ * knowable, and advising every `%` whose left side might go negative would
970
+ * be the noise the tier exists to avoid. The shape matched is a unary minus
971
+ * wrapping a numeric literal, because that is what `-7` parses as; there is
972
+ * no negative-valued literal for a value test to find.
973
+ *
974
+ * The admission bar is "Vel accepts the spelling as a different meaning", so
975
+ * every shape whose two answers are the same is silent rather than advised:
976
+ * a remainder of zero (`-6 % 3`) agrees, `% 0` answers NaN here and raises
977
+ * in Python so there is no Python answer to name, and a non-finite dividend
978
+ * answers NaN on both sides. A message that states a disagreement and then
979
+ * prints the same number twice is a new defect, not a weaker advisory.
980
+ */
981
+ private adviseNegativeLiteralModulo;
817
982
  private requireIntersectingEquality;
818
983
  private rejectFreshCollectionEquality;
819
984
  private freshCollectionOperand;
820
985
  private requireMembershipIntersection;
986
+ private rejectFreshCollectionProbe;
821
987
  private rejectDisjointEnumTest;
822
988
  /** The enum/null arms of a type, or null when any arm falls outside that domain. */
823
989
  private pureEnumDomainArms;
824
990
  private rejectDisjointEnumValidatorProbe;
991
+ /**
992
+ * D59 rule 141 settled that `toBe` *is* `==` ("toBe 必须用语言自己的 `==`")
993
+ * and rule 141.1 settled that `toContain` *is* `values.has(item)`. The
994
+ * runtime half of both landed; the compile-time half did not travel with
995
+ * them, so `expect([1]).toBe([1])` compiled and failed at run time with
996
+ * both operands rendering byte-identically, while `[1] == [1]` is refused
997
+ * where it is written. This runs the operator's own two gates on the
998
+ * matcher: D42 item 64's intersection requirement, and COL-I3's rejection
999
+ * of a freshly built literal in an identity comparison.
1000
+ *
1001
+ * `toBe` and `toEqual` deliberately part company on the fresh-literal gate.
1002
+ * `toBe` asks the `==` question, where a new object can never be identical
1003
+ * to anything, so the literal proves the answer. `toEqual` asks the
1004
+ * `equals(a, b)` question, where a fresh literal is the normal and correct
1005
+ * spelling of the expected value — rejecting it there would refuse the very
1006
+ * repair the `toBe` message teaches. The intersection gate has no such
1007
+ * split: two types with no values in common never deeply equal either.
1008
+ *
1009
+ * `toHaveLength` and `toMatch` are left alone. Neither takes a comparand:
1010
+ * `toHaveLength` takes a count, and `toMatch` takes a regular-expression
1011
+ * pattern whose relation to the subject is matching, not equality.
1012
+ */
1013
+ private checkTestMatcherComparand;
825
1014
  private enumTargetOfValidatorObject;
826
1015
  /** The enum behind a type alias name, or null when the alias does not resolve to an enum. */
827
1016
  private aliasedEnumTarget;
@@ -960,6 +1149,21 @@ export declare class Analyzer implements TypeEnvironment {
960
1149
  private narrowingSubjectExpression;
961
1150
  /** The property name when an expression reads a getter rather than a stored field. */
962
1151
  private getterAccessProperty;
1152
+ /**
1153
+ * D90 R17: the author's own spelling of a boundary value, for the
1154
+ * diagnostics that teach `Type.parse`. Identifier and member paths render
1155
+ * exactly, a simple call renders as `name(...)`, and anything else answers
1156
+ * null so the caller falls back to the word `value`.
1157
+ */
1158
+ private boundaryReceiverText;
1159
+ /** A type name suggested from the receiver's last name segment, or 'X' when none reads naturally. */
1160
+ private boundaryTypeNameSuggestion;
1161
+ /**
1162
+ * D90 R17: an undeclared foreign value arrives as unknown, and the way into
1163
+ * the typed world is `Type.parse` at the edge. Every refusal on an unknown
1164
+ * teaches that ritual with the author's own expression spelled into it.
1165
+ */
1166
+ private boundaryValidationGuidance;
963
1167
  private conditionSubjectText;
964
1168
  protected requireAssignable(actual: ValueType, expected: ValueType, valueSpan: Span): void;
965
1169
  /**
@@ -1058,10 +1262,32 @@ export declare class Analyzer implements TypeEnvironment {
1058
1262
  * carried whole so the author never sees a half-migrated module.
1059
1263
  */
1060
1264
  private reportPermanentNamespaceImports;
1265
+ /**
1266
+ * D50 rule 97.3: a retirement that leaves one surviving spelling did not
1267
+ * happen. `export {stringify} from "velar/json"` is an import spelling with
1268
+ * an export in front of it — the barrel republishes the retired bare name
1269
+ * and every downstream `import {stringify} from "./barrel.vel"` is clean
1270
+ * forever after. No mechanical fix: which reads in which other modules
1271
+ * wanted the name is not a rewrite this module can make.
1272
+ */
1273
+ private reportPermanentNamespaceReExports;
1061
1274
  /** A member name to show in the rule 106 guidance, so the fix is concrete. */
1062
1275
  private firstNamespaceMember;
1063
1276
  protected typeError(message: string, errorSpan: Span, fix?: DiagnosticFix): void;
1064
1277
  protected recoveredTypeError(message: string, errorSpan: Span, fix?: DiagnosticFix): void;
1278
+ /**
1279
+ * D89: raises a roster advisory. It cannot reach `this.diagnostics`, so it
1280
+ * cannot fail a build and cannot shift the diagnostic cursors this analyzer
1281
+ * reads as array lengths.
1282
+ *
1283
+ * One report per code and span. `reanalyzeLoopBackEdge` runs a loop body a
1284
+ * second time whenever the back edge invalidates a fact, and its diagnostic
1285
+ * answer is `deduplicateDiagnostics`, which only ever touches
1286
+ * `this.diagnostics`. Deduplicating where the advisory is raised covers that
1287
+ * pass and every other re-analysis without a second pair of cursors, which
1288
+ * is the whole reason the two channels are separate arrays.
1289
+ */
1290
+ protected advise(code: string, message: string, adviceSpan: Span, fix?: DiagnosticFix): void;
1065
1291
  private analyzeMatchPattern;
1066
1292
  private matchLocationNarrowing;
1067
1293
  private retargetNarrowings;
@@ -1100,17 +1326,93 @@ export declare class Analyzer implements TypeEnvironment {
1100
1326
  * constructor's own arguments. Nothing infers it from a later mutation, so a
1101
1327
  * binding left with no source is reported at the construction rather than
1102
1328
  * kept as `unknown` for a following line to fill in.
1329
+ *
1330
+ * The value written at this position is not always the construction itself.
1331
+ * A ternary arm, a list element or its spread, a record-literal field, a
1332
+ * `??` fallback, a receiver and an argument all become part of the value the
1333
+ * name holds, so each is its own settling position and each reports at its
1334
+ * own `[]`. What stops the walk is the value, not the syntax: it descends
1335
+ * only while `carriesUnsettledCollection` still sees the hole in the type
1336
+ * arriving here, so `print(Set().size)` and `const n = Set().size` stay
1337
+ * legal per rule 208 — neither of those names holds a collection — while a
1338
+ * spread whose `unknown` the merge absorbs (`["x", ...[]]`) leaves nothing
1339
+ * to report. A sibling settles nothing for its neighbour: `[["a"], []]`
1340
+ * merges through `unionOf`, so the union still carries the hole and the
1341
+ * empty `[]` reports on its own.
1342
+ *
1343
+ * Returns whether it reported, so the caller can hand the name `invalidType`
1344
+ * instead of the hole. Rule 209 requires one mistake to be reported once,
1345
+ * and `List<unknown>` reaching a later line is what produces the second,
1346
+ * contradicting report the ruling exists to delete.
1347
+ */
1348
+ protected requireSettledCollectionElement(initializer: Expression, declared: ValueType, annotated: boolean): boolean;
1349
+ /**
1350
+ * D85 rule 209: where the value at this position came from, when it came
1351
+ * from a hole VEL4039 already reported. The answer is two-part because a
1352
+ * callee can be declared after its caller: `true` is a hole already on
1353
+ * record, and `causes` are the local results that make this position a hole
1354
+ * too if theirs turn out to be one.
1355
+ *
1356
+ * Only a name and a call to a local name are modelled — the two shapes an
1357
+ * author writes between an empty collection and the `return` that publishes
1358
+ * it. Anything else contributes nothing, so an unmodelled position keeps the
1359
+ * report it has today rather than losing one.
1360
+ */
1361
+ private collectResultHoleSources;
1362
+ /**
1363
+ * D85 rule 209: a name bound to a reported hole carries it, so `const a = []`
1364
+ * followed by `return a` is the same one mistake `return []` is. Only an
1365
+ * unannotated `const`/`let` of a single name carries anything: an annotation
1366
+ * settles the construction, and a destructuring pattern takes the hole apart
1367
+ * rather than passing it on.
1368
+ */
1369
+ private recordBindingHoleSource;
1370
+ /**
1371
+ * D85 rule 209: delete the convergence report of every function whose result
1372
+ * is invalid only because a hole VEL4039 already explained reached it through
1373
+ * a local call. The set grows until it stops growing, because a chain of
1374
+ * forwarding functions is still one mistake however long it is — and a cycle
1375
+ * with no empty collection anywhere in it never enters the set, so a genuine
1376
+ * convergence failure still reports on both of its halves.
1103
1377
  */
1104
- protected requireSettledCollectionElement(initializer: Expression, declared: ValueType, annotated: boolean): void;
1378
+ private resolveDeferredConvergenceReports;
1379
+ private reportUnsettledCollection;
1105
1380
  private isFreshUnresolvedCollection;
1106
1381
  protected declareBinding(name: string, mutable: boolean, type: ValueType, declarationSpan: Span, internal?: boolean, declaredType?: ValueType, importSource?: string): void;
1107
1382
  private recordImportedBindingSource;
1108
1383
  private recordImportedBindingOrigin;
1109
1384
  private recordInitializationImportRead;
1385
+ /**
1386
+ * D31 item 23: the call edge. Inside a deferred body it is an edge of the
1387
+ * reachability graph; at module top level it is a root, because that call
1388
+ * runs the callee while the module itself evaluates. The callee is held as
1389
+ * a binding, not as a frame — a `def` is hoisted, so `const x = pull()` can
1390
+ * be analyzed before `def pull()` is.
1391
+ */
1392
+ private recordDeferredCallEdge;
1393
+ /** Files an arrow's deferred frame under the module-local name it was bound to. */
1394
+ private claimArrowDeferredFrame;
1110
1395
  /** True while analysis is directly in a declaration body rather than a function frame. */
1111
1396
  protected inComponentSetupPosition(): boolean;
1112
1397
  protected inModuleInitializationPosition(): boolean;
1113
- /** Initialization-position reads of imported bindings, for the project module-cycle check. */
1398
+ /**
1399
+ * Initialization-position reads of imported bindings, for the project
1400
+ * module-cycle check.
1401
+ *
1402
+ * D31 item 23 recorded the indirect shape as a v1 residual: a top-level call
1403
+ * of a module-local function runs that body while the module evaluates, so
1404
+ * an imported binding read inside it is an initialization-position read too
1405
+ * — and following VEL3019's own remediation ("Move this read into a
1406
+ * function") and then calling that function at top level re-created the bare
1407
+ * `ReferenceError` the check exists to delete. The closure below is the
1408
+ * intra-module reachability pass that closes it: one module, one walk over
1409
+ * the call edges already collected, no cross-module analysis.
1410
+ *
1411
+ * An indirect read is reported at the *call*, not at the read. The call is
1412
+ * the line that runs during module evaluation and the line an author can
1413
+ * move; the read inside the body is already in a function, which is what the
1414
+ * remediation asks for.
1415
+ */
1114
1416
  moduleInitializationImportReads(): readonly InitializationImportRead[];
1115
1417
  private requireTextConvertible;
1116
1418
  private isTextConvertible;
@@ -1131,6 +1433,47 @@ export declare class Analyzer implements TypeEnvironment {
1131
1433
  private runtimeTypeObjectValue;
1132
1434
  private displayExternalClasses;
1133
1435
  protected prescanScopeDeclarations(statements: readonly Statement[]): void;
1436
+ /**
1437
+ * D90 R12: "exported" is a property of the declaration a consumer can reach,
1438
+ * not of the `def` keyword. A module-level declaration carries the flag
1439
+ * itself and is judged here and now. A class member carries none — a public
1440
+ * member of a class this module publishes is read by a consumer exactly as
1441
+ * an exported `const` is — but whether the class is published is a question
1442
+ * about the whole module, so the member waits for reportExportPositionAny. A
1443
+ * `private` member is never reachable, and R12's boundary does not move:
1444
+ * module-internal `any` stays legal.
1445
+ */
1446
+ private recordExportedAny;
1447
+ /**
1448
+ * D90 R12: the class members that turned out to be at an export position.
1449
+ * Reported once the module is analyzed, because the answer is reachability
1450
+ * and reachability is a property of the module, not of the declaration.
1451
+ */
1452
+ private reportExportPositionAny;
1453
+ /**
1454
+ * D90 R12: which class declarations a consuming module can reach. Exported
1455
+ * classes seed the set; from there it follows every position a consumer can
1456
+ * read a value *out of* — the type of anything else this module exports, the
1457
+ * base a reachable class names, and the public surface of a class already
1458
+ * reachable. `export class Box extends Base:` publishes `Base`'s members,
1459
+ * and `def make() -> Inner` publishes `Inner`'s, whether or not either name
1460
+ * is exported.
1461
+ *
1462
+ * Input positions are deliberately absent, for the same reason
1463
+ * `typeContainsAnyOutput` omits them: a consumer that has to *supply* an
1464
+ * instance obtained it from an output position first, and that position is
1465
+ * what makes the class reachable.
1466
+ */
1467
+ private exportReachableClasses;
1468
+ /**
1469
+ * D90 R12: the diagnostic has to teach the way out, not only refuse. A
1470
+ * consuming module never writes `unsafe`, so an exported `any` hands it a
1471
+ * value carrying no guarantee at all; the escape is to validate the value
1472
+ * into a declared type in the module that owns the boundary, which is what
1473
+ * `Type.parse` exists for. No new diagnostic code and no unsafe marker: this
1474
+ * is the rule at validateTypeReference finished, not a second rule.
1475
+ */
1476
+ private reportExportedAny;
1134
1477
  private collectPatternNames;
1135
1478
  private checkShadowedRead;
1136
1479
  private declarePattern;
@@ -1171,10 +1514,44 @@ export declare class Analyzer implements TypeEnvironment {
1171
1514
  private memberNarrowingRootType;
1172
1515
  private runtimeCheckedType;
1173
1516
  private matchPatternReflectionMayExecute;
1517
+ /**
1518
+ * A snapshot used to copy every binding of every live scope, which made a
1519
+ * branch cost O(names in the module) and whole-module analysis quadratic in
1520
+ * module size. A binding nothing ever narrows cannot differ between two
1521
+ * moments, so only the bindings flow analysis has actually written are
1522
+ * visited — `flowTouched`, kept per scope depth so an exiting scope drops
1523
+ * its own, and `flowOrigins`, which remembers what each one held before its
1524
+ * first write. `flowOrigins` answers for a binding a *later* write touched
1525
+ * than the snapshot being restored: the snapshot has no entry, and its
1526
+ * pre-write state is exactly the state that snapshot recorded. A narrowing
1527
+ * shadow born after the snapshot stores `null` instead, because a full-scope
1528
+ * snapshot had nothing to restore it to either.
1529
+ */
1530
+ private flowFactState;
1531
+ /** Called immediately before flow analysis writes a binding, so the recorded state is the pre-write one. */
1532
+ private recordFlowFactOrigin;
1533
+ /** A narrowing shadow created mid-flow: no older snapshot has a state for it. */
1534
+ private trackNarrowingShadow;
1535
+ private trackFlowBinding;
1536
+ /** Every binding whose flow facts may differ from another moment's, outermost scope first. */
1537
+ private touchedFlowBindings;
1538
+ /** The state `snapshot` recorded for `binding`, or null when it did not exist yet. */
1539
+ private flowStateIn;
1174
1540
  private snapshotFlowFacts;
1175
1541
  private restoreFlowFacts;
1176
1542
  private analyzeIsolatedFlow;
1177
1543
  private flowInvalidationsSince;
1544
+ /**
1545
+ * A loop's back-edge pass re-runs the whole body, and a nested loop inside
1546
+ * that pass runs its own, so the work doubled with every level of loop
1547
+ * nesting: fourteen levels of `while` in a 91-line file took 2.4 seconds and
1548
+ * seventeen took 35. The passes are budgeted by how many back-edge passes
1549
+ * are already running. Past the budget a loop analyzes its body once and its
1550
+ * exit keeps nothing — `widened` — which is what the loop would answer if
1551
+ * its back edge had falsified every fact, so the degradation only ever
1552
+ * removes a fact, never invents one. Real code does not nest loops four
1553
+ * deep, so nothing reachable by hand reaches the budget.
1554
+ */
1178
1555
  private reanalyzeLoopBackEdge;
1179
1556
  private flowInvalidationsAffectFacts;
1180
1557
  private deduplicateDiagnostics;
@@ -1182,7 +1559,18 @@ export declare class Analyzer implements TypeEnvironment {
1182
1559
  private clearCachedFlowTypesInSpan;
1183
1560
  private flowSnapshotAfterInvalidations;
1184
1561
  private visibleBindings;
1562
+ /** The binding a name resolved to when `visible` was captured. */
1563
+ private visibleBinding;
1564
+ /**
1565
+ * Only a name a narrowing has written can carry a fact, and `narrowedNames`
1566
+ * is the roster of those per scope — so this walks the narrowings rather
1567
+ * than every name in scope. The member half matches a dotted path against
1568
+ * the binding its root names instead of spreading the whole root set per
1569
+ * path, which is O(one lookup) rather than O(names in the module).
1570
+ */
1185
1571
  private narrowingsForVisibleBindings;
1572
+ /** Whether a member path's root — `<declaration offset>:<name>` — names a binding visible then. */
1573
+ private memberNarrowingRootIsVisible;
1186
1574
  private narrowingsInSnapshot;
1187
1575
  private commonNarrowings;
1188
1576
  /**