@scriptc/compiler 0.0.7 → 0.0.9

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 (94) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +13 -0
  2. package/dist/backend/cc.js +14 -0
  3. package/dist/backend/cc.js.map +1 -1
  4. package/dist/backend/emission/emit-exprs.js +155 -6
  5. package/dist/backend/emission/emit-exprs.js.map +1 -1
  6. package/dist/backend/emission/emit-island.js +9 -1
  7. package/dist/backend/emission/emit-island.js.map +1 -1
  8. package/dist/backend/emission/emit-stmts.js +3 -1
  9. package/dist/backend/emission/emit-stmts.js.map +1 -1
  10. package/dist/backend/emission/emit-types.d.ts +3 -0
  11. package/dist/backend/emission/emit-types.js +12 -0
  12. package/dist/backend/emission/emit-types.js.map +1 -1
  13. package/dist/backend/emission/emit-walkers.d.ts +7 -5
  14. package/dist/backend/emission/emit-walkers.js +45 -18
  15. package/dist/backend/emission/emit-walkers.js.map +1 -1
  16. package/dist/backend/emission/emitter.d.ts +1 -1
  17. package/dist/backend/emission/emitter.js +35 -10
  18. package/dist/backend/emission/emitter.js.map +1 -1
  19. package/dist/backend/emission/may-throw.js +4 -3
  20. package/dist/backend/emission/may-throw.js.map +1 -1
  21. package/dist/backend/llvm/emitter.js +300 -18
  22. package/dist/backend/llvm/emitter.js.map +1 -1
  23. package/dist/diagnostics/diagnostic.d.ts +98 -11
  24. package/dist/diagnostics/diagnostic.js +185 -25
  25. package/dist/diagnostics/diagnostic.js.map +1 -1
  26. package/dist/frontend/lib-contract.d.ts +24 -6
  27. package/dist/frontend/lib-contract.js +125 -44
  28. package/dist/frontend/lib-contract.js.map +1 -1
  29. package/dist/frontend/lowering/lower-assert.js +16 -0
  30. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  31. package/dist/frontend/lowering/lower-builtins.d.ts +11 -0
  32. package/dist/frontend/lowering/lower-builtins.js +127 -4
  33. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  34. package/dist/frontend/lowering/lower-calls.d.ts +77 -18
  35. package/dist/frontend/lowering/lower-calls.js +978 -44
  36. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  37. package/dist/frontend/lowering/lower-classes.d.ts +14 -1
  38. package/dist/frontend/lowering/lower-classes.js +112 -16
  39. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  40. package/dist/frontend/lowering/lower-containers.d.ts +4 -2
  41. package/dist/frontend/lowering/lower-containers.js +236 -44
  42. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  43. package/dist/frontend/lowering/lower-emitter.js +55 -1
  44. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  45. package/dist/frontend/lowering/lower-exprs.d.ts +26 -3
  46. package/dist/frontend/lowering/lower-exprs.js +507 -47
  47. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  48. package/dist/frontend/lowering/lower-island.d.ts +7 -0
  49. package/dist/frontend/lowering/lower-island.js +71 -10
  50. package/dist/frontend/lowering/lower-island.js.map +1 -1
  51. package/dist/frontend/lowering/lower-mixins.d.ts +1 -1
  52. package/dist/frontend/lowering/lower-mixins.js +1 -1
  53. package/dist/frontend/lowering/lower-modules.js +95 -4
  54. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  55. package/dist/frontend/lowering/lower-stmts.js +866 -56
  56. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  57. package/dist/frontend/lowering/lower-stream.js +28 -2
  58. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  59. package/dist/frontend/lowering/lowerer.d.ts +85 -17
  60. package/dist/frontend/lowering/lowerer.js +459 -37
  61. package/dist/frontend/lowering/lowerer.js.map +1 -1
  62. package/dist/frontend/lowering/surfaces.js +20 -3
  63. package/dist/frontend/lowering/surfaces.js.map +1 -1
  64. package/dist/frontend/npm-static-rewrite.d.ts +7 -2
  65. package/dist/frontend/npm-static-rewrite.js +566 -138
  66. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  67. package/dist/frontend/npm-static.js +11 -2
  68. package/dist/frontend/npm-static.js.map +1 -1
  69. package/dist/frontend/program.js +5 -5
  70. package/dist/frontend/program.js.map +1 -1
  71. package/dist/frontend/shared.d.ts +6 -1
  72. package/dist/frontend/shared.js +46 -1
  73. package/dist/frontend/shared.js.map +1 -1
  74. package/dist/frontend/types.d.ts +28 -1
  75. package/dist/frontend/types.js +304 -10
  76. package/dist/frontend/types.js.map +1 -1
  77. package/dist/index.d.ts +2 -1
  78. package/dist/index.js +181 -26
  79. package/dist/index.js.map +1 -1
  80. package/dist/ir/nodes.d.ts +159 -9
  81. package/dist/ir/nodes.js +76 -6
  82. package/dist/ir/nodes.js.map +1 -1
  83. package/dist/ir/validate.js +93 -14
  84. package/dist/ir/validate.js.map +1 -1
  85. package/dist/library/profile.d.ts +17 -3
  86. package/dist/library/profile.js +38 -9
  87. package/dist/library/profile.js.map +1 -1
  88. package/dist/library/sidecar.js +162 -43
  89. package/dist/library/sidecar.js.map +1 -1
  90. package/dist/library/trap-teaching.d.ts +11 -0
  91. package/dist/library/trap-teaching.js +49 -0
  92. package/dist/library/trap-teaching.js.map +1 -0
  93. package/package.json +2 -2
  94. package/surface-manifest.json +46 -4
@@ -525,7 +525,7 @@ let mapTypeDepth = 0;
525
525
  * The recursive-shape machinery keys shape identity by checker type, which
526
526
  * is sound only for context-FREE mappings: a recursive frame that observes
527
527
  * a bump between entry and exit stays fenced (recursive generic-open types
528
- * report SC2001 instead of interning a per-context-wrong shape). */
528
+ * stay fenced instead of interning a per-context-wrong shape). */
529
529
  let contextResolutions = 0;
530
530
  export function mapType(type, ctx) {
531
531
  if (mapTypeDepth >= MAP_TYPE_MAX_DEPTH)
@@ -584,6 +584,15 @@ function mapTypeInner(type, ctx) {
584
584
  contextResolutions++;
585
585
  return viaAwaited;
586
586
  }
587
+ // `T[K]` over a bound parameter: like Awaited, a form the checker
588
+ // keeps symbolic inside the body. Two resolvers, tried in order: the
589
+ // structural read against the record binding, then the bound-checker
590
+ // route for a K naming one concrete key (mapBoundIndexedAccess).
591
+ const viaIndexed = mapGenericIndexedAccess(type, ctx) ?? mapBoundIndexedAccess(type, ctx);
592
+ if (viaIndexed !== null) {
593
+ contextResolutions++;
594
+ return viaIndexed;
595
+ }
587
596
  }
588
597
  const widened = checker.getBaseTypeOfLiteralType(type);
589
598
  const flags = widened.flags;
@@ -1030,8 +1039,8 @@ function mapTypeInner(type, ctx) {
1030
1039
  // provenance, not the name (a user's own `interface Map` maps as a record
1031
1040
  // like any other). Keys are fenced to f64/string (SameValueZero hashing),
1032
1041
  // values to the supported kinds (see isSupportedMapValue); anything
1033
- // outside stays unmapped — callers report SC2001 with the full type
1034
- // text, and the `new Map` lowering names the offending half specifically.
1042
+ // outside stays unmapped — callers report the component fence (SC2009)
1043
+ // naming the offending half, as does the `new Map` lowering per site.
1035
1044
  const psym = widened.getSymbol();
1036
1045
  const isStdlibInterface = (name) => psym?.name === name &&
1037
1046
  checker.declarationsOf(psym).some((d) => ts.isInterfaceDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()));
@@ -2041,9 +2050,12 @@ function mapTypeInner(type, ctx) {
2041
2050
  return arms[0];
2042
2051
  }
2043
2052
  if (arms.some((a) => a.kind === "void" || a.kind === "union" ||
2044
- // Map/Set and regex arms stay out (like func against data
2045
- // arms: no narrowing test — no discriminant fields on them).
2046
- a.kind === "map" || a.kind === "set" || a.kind === "regex" || a.kind === "dyn" ||
2053
+ // Map/Set arms stay out (like func against data arms: no
2054
+ // narrowing test — no discriminant fields on them). REGEX
2055
+ // arms map: `x instanceof RegExp` is their narrowing test
2056
+ // (the skip-utility `string | RegExp` shape), and the arm
2057
+ // rides the ref machinery like array regex elements.
2058
+ a.kind === "map" || a.kind === "set" || a.kind === "dyn" ||
2047
2059
  // Generator arms follow the map/set rule: no narrowing test.
2048
2060
  a.kind === "generator" ||
2049
2061
  // Func arms map beside ANY sibling: `typeof x === "function"`
@@ -2145,6 +2157,36 @@ function mapNarrowedTypeParam(type, ctx) {
2145
2157
  // Filtering preserves the canonical (typeKey-sorted) arm order.
2146
2158
  return { kind: "union", unionId: unions.intern(arms) };
2147
2159
  }
2160
+ /** `T[K]` inside a generic body, resolved through the instantiation's BOUND
2161
+ * checker types (the checker keeps indexed accesses over type parameters
2162
+ * symbolic). Object and index sides each resolve through resolveTypeParamTs
2163
+ * when they are type parameters; when the index lands on ONE literal key
2164
+ * (`K extends keyof T` bound to `"a"` — inference preserves the literal
2165
+ * there), the named property's type maps like a concrete member read. A
2166
+ * non-literal index (K bound to `string` or a key union) answers null: the
2167
+ * access has no one property type, and the per-site keyed-read machinery
2168
+ * (or its fences) owns the story. */
2169
+ function mapBoundIndexedAccess(type, ctx) {
2170
+ const { checker, resolveTypeParamTs } = ctx;
2171
+ if (!resolveTypeParamTs || !type.isIndexedAccessType())
2172
+ return null;
2173
+ const resolveSide = (t) => t.flags & ts.TypeFlags.TypeParameter ? resolveTypeParamTs(t) : t;
2174
+ const objT = resolveSide(type.getObjectType());
2175
+ const idxT = resolveSide(type.getIndexType());
2176
+ if (!objT || !idxT)
2177
+ return null;
2178
+ const key = idxT.isStringLiteralType()
2179
+ ? idxT.value
2180
+ : idxT.isNumberLiteralType()
2181
+ ? String(idxT.value)
2182
+ : null;
2183
+ if (key === null)
2184
+ return null;
2185
+ const prop = checker.getPropertyOfType(objT, key);
2186
+ if (!prop)
2187
+ return null;
2188
+ return mapType(checker.getTypeOfSymbol(prop), ctx);
2189
+ }
2148
2190
  /** `Partial<T>` / `Readonly<T>` where T is a STILL-GENERIC type parameter —
2149
2191
  * the one mapped-type spelling a monomorphized body can contain that the
2150
2192
  * checker cannot resolve for us (`keyof T` is unknown inside the body, so
@@ -2227,6 +2269,52 @@ function mapGenericAwaitedAlias(type, ctx) {
2227
2269
  r = r.inner;
2228
2270
  return r;
2229
2271
  }
2272
+ /** `T[K]` where T is a STILL-GENERIC type parameter, resolved against the
2273
+ * lowerer's binding — the checker keeps the access symbolic inside a
2274
+ * generic body (the mockable-clock module shape: a JSDoc-generic factory
2275
+ * whose declared return carries `implementation: T[K]` members). The
2276
+ * binding decides which field types the access can name: a string-LITERAL
2277
+ * index picks its one declared field (the index signature's value type for
2278
+ * an undeclared name); an all-keys index — `keyof T` over the same
2279
+ * parameter, or an index parameter whose own binding widened to plain
2280
+ * string — covers every declared field. The mapping answers only when
2281
+ * every covered field agrees on ONE IR type (the call boundary resolved
2282
+ * the same access against the concrete T, so the shapes intern equal);
2283
+ * disagreeing fields would need a union whose arms this relation cannot
2284
+ * vouch for — those stay unmapped, keeping their fences. */
2285
+ function mapGenericIndexedAccess(type, ctx) {
2286
+ const { resolveTypeParam, shapes } = ctx;
2287
+ if (!resolveTypeParam || !type.isIndexedAccessType())
2288
+ return null;
2289
+ const obj = type.getObjectType();
2290
+ if (!(obj.flags & ts.TypeFlags.TypeParameter))
2291
+ return null;
2292
+ const bound = resolveTypeParam(obj);
2293
+ if (!bound || bound.kind !== "record")
2294
+ return null;
2295
+ const shape = shapes.get(bound.shapeId);
2296
+ if (!shape || shape.tuple)
2297
+ return null;
2298
+ const idx = type.getIndexType();
2299
+ let covered = null;
2300
+ if (idx.isStringLiteralType()) {
2301
+ const f = shape.fields.find((x) => x.name === idx.value);
2302
+ covered = f ? [f.type] : shape.indexValue ? [shape.indexValue] : null;
2303
+ }
2304
+ else {
2305
+ const allKeys = (idx.flags & ts.TypeFlags.TypeParameter && resolveTypeParam(idx)?.kind === "string") ||
2306
+ (idx.isIndexType() && idx.getTarget() === obj);
2307
+ if (allKeys) {
2308
+ covered = shape.fields.map((f) => f.type);
2309
+ if (shape.indexValue)
2310
+ covered.push(shape.indexValue);
2311
+ }
2312
+ }
2313
+ if (!covered || covered.length === 0)
2314
+ return null;
2315
+ const first = covered[0];
2316
+ return covered.every((t) => typeEquals(t, first)) ? first : null;
2317
+ }
2230
2318
  function mapGenericUtilityAlias(widened, ctx) {
2231
2319
  const { resolveTypeParam, shapes, unions } = ctx;
2232
2320
  if (!resolveTypeParam)
@@ -2369,8 +2457,7 @@ export function withUndefinedArm(t, unions) {
2369
2457
  arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
2370
2458
  return { kind: "union", unionId: unions.intern(arms) };
2371
2459
  }
2372
- if (t.kind === "void" || t.kind === "map" ||
2373
- t.kind === "regex" || t.kind === "dyn" ||
2460
+ if (t.kind === "void" || t.kind === "map" || t.kind === "dyn" ||
2374
2461
  // A bare unit field type cannot occur (units live only inside unions),
2375
2462
  // but guard against constructing a single-arm union from one.
2376
2463
  isUnitType(t)) {
@@ -2568,8 +2655,10 @@ function mapRecordTypeInner(widened, ctx) {
2568
2655
  // BOTH signatures at once (string + number) collapse into the one store
2569
2656
  // when their value types intern identically (tsc requires only
2570
2657
  // assignability; unequal slots would need a per-key answer the store
2571
- // cannot give). Value types outside the map-value world stay unmapped
2572
- // (isSupportedIndexValue).
2658
+ // cannot give). The value domain is the overflow store's
2659
+ // (isSupportedIndexValue): the map-value kinds plus 'unknown', functions
2660
+ // (the command-registry pattern), Maps/Sets, and nested index-signature
2661
+ // records; everything else stays unmapped.
2573
2662
  let indexValue;
2574
2663
  const indexInfos = checker.getIndexInfosOfType(widened);
2575
2664
  if (indexInfos.length > 0) {
@@ -2824,4 +2913,209 @@ function mapRecordTypeInner(widened, ctx) {
2824
2913
  return { fields, ...(indexValue ? { indexValue } : {}), declaredOrder };
2825
2914
  }
2826
2915
  }
2916
+ /* ── Component-fence classification (SC2009) ───────────────────────────────
2917
+ * badType's post-hoc classifiers: given a type mapType REJECTED, decide
2918
+ * whether the failure lives in a COMPONENT of an otherwise supported shape
2919
+ * — and if so, name it. Pure description: these run only on the failure
2920
+ * path (the build already carries a diagnostic for the site), mirror
2921
+ * mapType's own rules, and never change what maps. Probing through mapType
2922
+ * here is safe for the same reason badType's dynamic probe is: anything
2923
+ * interned on the way belongs to a build that is not emitted. */
2924
+ /** The recognized stdlib containers and the slot name each type-argument
2925
+ * position plays in their messages. */
2926
+ const STDLIB_CONTAINERS = {
2927
+ Map: { role: (i) => (i === 0 ? "key" : "value") },
2928
+ ReadonlyMap: { role: (i) => (i === 0 ? "key" : "value") },
2929
+ Set: { role: () => "element" },
2930
+ ReadonlySet: { role: () => "element" },
2931
+ Promise: { role: () => "value" },
2932
+ Generator: { role: (i) => ["yield", "return", "next"][i] ?? "channel" },
2933
+ AsyncGenerator: { role: (i) => ["yield", "return", "next"][i] ?? "channel" },
2934
+ };
2935
+ /** Arm kinds with no home in a compiled union (mapTypeInner's union rule):
2936
+ * no runtime narrowing test exists against sibling data arms. */
2937
+ function armHasUnionHome(arm, siblingCount) {
2938
+ switch (arm.kind) {
2939
+ case "void":
2940
+ case "union":
2941
+ case "map":
2942
+ case "set":
2943
+ case "regex":
2944
+ case "generator":
2945
+ case "dyn":
2946
+ return false;
2947
+ // Promise arms map only beside unit siblings (the promise-or-absent
2948
+ // shape); a data sibling has no narrowing test against them.
2949
+ case "promise":
2950
+ return siblingCount === 0;
2951
+ default:
2952
+ return true;
2953
+ }
2954
+ }
2955
+ /** When an unmapped type is a SUPPORTED container/composite whose failure
2956
+ * lives in a component, answer a message tail naming the component (the
2957
+ * SC2009 story); null when the shape itself is the blocker (the caller
2958
+ * falls through to the other fences). Stdlib container heads (Map, Set,
2959
+ * Promise, generators) ALWAYS answer — their shapes have lowerings, so a
2960
+ * later "no lowering" claim about them would be false. */
2961
+ export function describeComponentBlocker(widened, ctx) {
2962
+ const { checker } = ctx;
2963
+ const text = (t) => checker.typeToString(t);
2964
+ // Stdlib container references (provenance, not the name — a user's own
2965
+ // `interface Map` is a record shape and keeps the record stories).
2966
+ const psym = widened.getSymbol();
2967
+ const container = psym !== undefined &&
2968
+ Object.prototype.hasOwnProperty.call(STDLIB_CONTAINERS, psym.name) &&
2969
+ checker.declarationsOf(psym).some((d) => ts.isInterfaceDeclaration(d) && ctx.isStdlibFile(d.getSourceFile()))
2970
+ ? psym.name
2971
+ : undefined;
2972
+ if (container !== undefined) {
2973
+ const spec = STDLIB_CONTAINERS[container];
2974
+ const args = checker.getTypeArguments(widened);
2975
+ for (let i = 0; i < args.length; i++) {
2976
+ const arg = args[i];
2977
+ const role = spec.role(i);
2978
+ const mapped = mapType(arg, ctx);
2979
+ if (!mapped) {
2980
+ return `the ${container} shape is supported, but its ${role} type '${text(arg)}' does not compile`;
2981
+ }
2982
+ if ((container === "Map" || container === "ReadonlyMap") && i === 0 && !isSupportedMapKey(mapped)) {
2983
+ return `the ${container} shape is supported, but keys are limited to numbers and strings — '${text(arg)}' is outside that domain`;
2984
+ }
2985
+ if ((container === "Map" || container === "ReadonlyMap") && i === 1 && !isSupportedMapValue(mapped)) {
2986
+ return `the ${container} shape is supported, but '${text(arg)}' values have no Map slot yet (functions, promises, and nested Maps stay out)`;
2987
+ }
2988
+ if ((container === "Set" || container === "ReadonlySet") && !isSupportedSetElem(mapped)) {
2989
+ return `the ${container} shape is supported, but elements are limited to numbers and strings — '${text(arg)}' is outside that domain`;
2990
+ }
2991
+ }
2992
+ // Every argument passed the per-slot checks and the type still failed:
2993
+ // a composition rule the slots alone don't show (a generator's channel
2994
+ // interplay, a promise wrapper rule). Still the container's story.
2995
+ return `the ${container} shape is supported, but this instantiation's type arguments are outside the supported set`;
2996
+ }
2997
+ // Arrays: the element is the failure by construction (a mappable element
2998
+ // makes the array map).
2999
+ if (checker.isArrayType(widened)) {
3000
+ const elemTs = checker.getTypeArguments(widened)[0];
3001
+ if (elemTs === undefined)
3002
+ return null;
3003
+ const elem = mapType(elemTs, ctx);
3004
+ if (!elem) {
3005
+ return `the array shape is supported, but its element type '${text(elemTs)}' does not compile`;
3006
+ }
3007
+ return `the array shape is supported, but '${text(elemTs)}' elements have no array representation yet`;
3008
+ }
3009
+ // Tuples: name the first element whose type does not map. Optional/rest
3010
+ // tuples in static builds are dynamic-representable and never get here
3011
+ // (badType's dynamic probe speaks first).
3012
+ if (checker.isTupleType(widened)) {
3013
+ for (const arg of checker.getTypeArguments(widened)) {
3014
+ const et = mapType(arg, ctx);
3015
+ if (et?.kind === "void" && isUnitOnlyTsType(arg))
3016
+ continue;
3017
+ if (!et || et.kind === "void") {
3018
+ return `the tuple shape is supported, but its element type '${text(arg)}' does not compile`;
3019
+ }
3020
+ }
3021
+ return null;
3022
+ }
3023
+ // Unions: name the first arm that does not compile, or the first mapped
3024
+ // arm kind with no union home. Unions have no symbol, so a null answer
3025
+ // falls through to the residual fence, never to a false lib claim.
3026
+ if (widened.isUnionType()) {
3027
+ const parts = widened.getTypes();
3028
+ const UNIT = ts.TypeFlags.Undefined | ts.TypeFlags.Void | ts.TypeFlags.Null;
3029
+ const dataArms = parts.filter((p) => (p.flags & UNIT) === 0);
3030
+ for (const part of dataArms) {
3031
+ const mapped = mapType(part, ctx);
3032
+ if (!mapped) {
3033
+ return `the union shape is supported, but its arm '${text(part)}' does not compile`;
3034
+ }
3035
+ if (!armHasUnionHome(mapped, dataArms.length - 1)) {
3036
+ return `the union shape is supported, but '${text(part)}' arms have no home in a compiled union yet (no runtime narrowing test exists against sibling arms)`;
3037
+ }
3038
+ }
3039
+ return null;
3040
+ }
3041
+ // Single-signature, non-generic function types: rest parameters, a
3042
+ // parameter type, or the return type carries the failure. (Generic and
3043
+ // overloaded signatures have their own fences — SC2005/SC2007 — and
3044
+ // badType runs those first.)
3045
+ const callSigs = checker.getCallSignatures(widened);
3046
+ if (callSigs.length === 1) {
3047
+ const sig = callSigs[0];
3048
+ if (sig.getTypeParameters().length > 0)
3049
+ return null;
3050
+ const sigDecl = checker.signatureDeclaration(sig);
3051
+ if (sigDecl !== undefined &&
3052
+ ts.isFunctionLike(sigDecl) &&
3053
+ (sigDecl.parameters.length !== sig.getParameters().length ||
3054
+ bodyReadsArgumentsLocal(sigDecl))) {
3055
+ return `the function shape is supported, but its signature is variadic ('arguments'-reading), and a compiled signature is fixed-arity`;
3056
+ }
3057
+ for (const p of sig.getParameters()) {
3058
+ const decl = checker.valueDeclarationOf(p);
3059
+ if (decl !== undefined && ts.isParameter(decl) && decl.dotDotDotToken !== undefined) {
3060
+ return `the function shape is supported, but its rest parameter '${p.name}' has no compiled calling convention yet (a compiled signature is fixed-arity)`;
3061
+ }
3062
+ const pTs = checker.getTypeOfSymbol(p);
3063
+ if (!mapType(pTs, ctx)) {
3064
+ return `the function shape is supported, but its parameter '${p.name}' has type '${text(pTs)}', which does not compile`;
3065
+ }
3066
+ }
3067
+ const retTs = checker.getReturnTypeOfSignature(sig);
3068
+ if ((retTs.flags & ts.TypeFlags.Never) === 0 && !mapType(retTs, ctx)) {
3069
+ return `the function shape is supported, but its return type '${text(retTs)}' does not compile`;
3070
+ }
3071
+ return null;
3072
+ }
3073
+ return null;
3074
+ }
3075
+ /** The record-member arm of the component fence: a USER record shape
3076
+ * blocked by ONE member's type. Runs AFTER badType's stdlib/npm/index-
3077
+ * signature routing, so what reaches it is a plain data shape; a null
3078
+ * answer (no member pinpointed — provenance fences, accessor rules, shape
3079
+ * knots) keeps the residual SC2001 story. */
3080
+ export function describeRecordMemberBlocker(widened, ctx) {
3081
+ const { checker } = ctx;
3082
+ if ((widened.flags & ts.TypeFlags.Object) === 0)
3083
+ return null;
3084
+ if (checker.getCallSignatures(widened).length > 0)
3085
+ return null;
3086
+ if (checker.getConstructSignatures(widened).length > 0)
3087
+ return null;
3088
+ if (checker.isTupleType(widened) || checker.isArrayLikeType(widened))
3089
+ return null;
3090
+ if (checker.getIndexInfosOfType(widened).length > 0)
3091
+ return null;
3092
+ const widenedSym = widened.getSymbol();
3093
+ if (widenedSym !== undefined && (widenedSym.flags & ts.SymbolFlags.Enum) !== 0)
3094
+ return null;
3095
+ const computed = isMappedShape(widened);
3096
+ for (const p of checker.getPropertiesOfType(widened)) {
3097
+ // Accessor members and symbol-keyed members have their own multi-shaped
3098
+ // rules (mapRecordTypeInner) — no single-member claim is honest there.
3099
+ if ((p.flags & (ts.SymbolFlags.GetAccessor | ts.SymbolFlags.SetAccessor)) !== 0)
3100
+ continue;
3101
+ if (p.name.startsWith("__@"))
3102
+ continue;
3103
+ // Computed shapes over LIBRARY members (`Readonly<Date>`): the record
3104
+ // fence there is per-member PROVENANCE (mapRecordTypeInner's rule), not
3105
+ // any one member's type — that story stays with the residual fence.
3106
+ if (computed && checker.declarationsOf(p).some((d) => d.getSourceFile().isDeclarationFile)) {
3107
+ return null;
3108
+ }
3109
+ const fieldTs = checker.getTypeOfSymbol(p);
3110
+ if (isGenericCallableMemberType(fieldTs, checker))
3111
+ continue;
3112
+ let pt = mapType(fieldTs, ctx);
3113
+ if (pt?.kind === "void" && isUnitOnlyTsType(fieldTs))
3114
+ pt = unitOnlyUnion(ctx.unions);
3115
+ if (!pt || pt.kind === "void") {
3116
+ return `the record shape is supported, but its member '${p.name}' has type '${checker.typeToString(fieldTs)}', which does not compile`;
3117
+ }
3118
+ }
3119
+ return null;
3120
+ }
2827
3121
  //# sourceMappingURL=types.js.map