@tsonic/frontend 0.0.59 → 0.0.61
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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/ir/binding/index.d.ts +17 -0
- package/dist/ir/binding/index.d.ts.map +1 -1
- package/dist/ir/binding/index.js +41 -7
- package/dist/ir/binding/index.js.map +1 -1
- package/dist/ir/converters/expressions/access.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access.js +94 -11
- package/dist/ir/converters/expressions/access.js.map +1 -1
- package/dist/ir/this-parameter-inference-rewrap.test.d.ts +14 -0
- package/dist/ir/this-parameter-inference-rewrap.test.d.ts.map +1 -0
- package/dist/ir/this-parameter-inference-rewrap.test.js +110 -0
- package/dist/ir/this-parameter-inference-rewrap.test.js.map +1 -0
- package/dist/ir/this-parameter-inference.test.d.ts +13 -0
- package/dist/ir/this-parameter-inference.test.d.ts.map +1 -0
- package/dist/ir/this-parameter-inference.test.js +165 -0
- package/dist/ir/this-parameter-inference.test.js.map +1 -0
- package/dist/ir/type-system/internal/handle-types.d.ts +2 -0
- package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.js +96 -2
- package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
- package/dist/ir/type-system/type-system.d.ts +4 -0
- package/dist/ir/type-system/type-system.d.ts.map +1 -1
- package/dist/ir/type-system/type-system.js +103 -28
- package/dist/ir/type-system/type-system.js.map +1 -1
- package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
- package/dist/ir/validation/soundness-gate.js +9 -1
- package/dist/ir/validation/soundness-gate.js.map +1 -1
- package/dist/program/bindings.d.ts +17 -0
- package/dist/program/bindings.d.ts.map +1 -1
- package/dist/program/bindings.js +137 -36
- package/dist/program/bindings.js.map +1 -1
- package/dist/types/diagnostic.d.ts +1 -1
- package/dist/types/diagnostic.d.ts.map +1 -1
- package/dist/types/diagnostic.js.map +1 -1
- package/dist/validation/static-safety.d.ts.map +1 -1
- package/dist/validation/static-safety.js +20 -0
- package/dist/validation/static-safety.js.map +1 -1
- package/package.json +3 -3
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import * as ts from "typescript";
|
|
15
15
|
import { substituteIrType as irSubstitute, } from "../types/ir-substitution.js";
|
|
16
16
|
import { inferNumericKindFromRaw } from "../types/numeric-helpers.js";
|
|
17
|
-
import { getBinaryResultKind, TSONIC_TO_NUMERIC_KIND } from "../types/numeric-kind.js";
|
|
17
|
+
import { getBinaryResultKind, TSONIC_TO_NUMERIC_KIND, } from "../types/numeric-kind.js";
|
|
18
18
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
19
|
// BUILTIN NOMINAL MAPPING
|
|
20
20
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -157,6 +157,11 @@ export const createTypeSystem = (config) => {
|
|
|
157
157
|
return undefined;
|
|
158
158
|
// Convert parameter types from TypeNodes to IrTypes
|
|
159
159
|
const parameterTypes = sigInfo.parameters.map((p) => (p.typeNode ? convertTypeNode(p.typeNode) : undefined));
|
|
160
|
+
// Convert a TypeScript `this:` parameter type (if present) to an IrType.
|
|
161
|
+
const thisParameterType = (() => {
|
|
162
|
+
const n = sigInfo.thisTypeNode;
|
|
163
|
+
return n ? convertTypeNode(n) : undefined;
|
|
164
|
+
})();
|
|
160
165
|
// Extract parameter modes
|
|
161
166
|
const parameterModes = sigInfo.parameters.map((p) => p.mode ?? "value");
|
|
162
167
|
// Extract parameter names
|
|
@@ -179,7 +184,10 @@ export const createTypeSystem = (config) => {
|
|
|
179
184
|
// identity captured in Binding and the (class) type parameters captured for the
|
|
180
185
|
// constructor signature.
|
|
181
186
|
if (isConstructor && sigInfo.declaringTypeTsName) {
|
|
182
|
-
const typeArguments = typeParameters.map((tp) => ({
|
|
187
|
+
const typeArguments = typeParameters.map((tp) => ({
|
|
188
|
+
kind: "typeParameterType",
|
|
189
|
+
name: tp.name,
|
|
190
|
+
}));
|
|
183
191
|
return {
|
|
184
192
|
kind: "referenceType",
|
|
185
193
|
name: sigInfo.declaringTypeTsName,
|
|
@@ -209,6 +217,7 @@ export const createTypeSystem = (config) => {
|
|
|
209
217
|
}
|
|
210
218
|
const rawSig = {
|
|
211
219
|
parameterTypes,
|
|
220
|
+
thisParameterType,
|
|
212
221
|
returnType,
|
|
213
222
|
parameterModes,
|
|
214
223
|
typeParameters,
|
|
@@ -602,14 +611,15 @@ export const createTypeSystem = (config) => {
|
|
|
602
611
|
* Deterministically infer an expression's type using only:
|
|
603
612
|
* - local lambda parameter environment
|
|
604
613
|
* - declaration types (typeOfDecl)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
614
|
+
* - numeric literal lexeme rules
|
|
615
|
+
*
|
|
616
|
+
* This is intentionally small: it's used only to type lambda bodies for
|
|
617
|
+
* initializer-driven generic inference (e.g., `Enumerable.select(..., x => x * 2)`).
|
|
618
|
+
*/
|
|
610
619
|
const inferExpressionType = (expr, env) => {
|
|
611
620
|
const unwrapped = unwrapParens(expr);
|
|
612
|
-
if (ts.isAsExpression(unwrapped) ||
|
|
621
|
+
if (ts.isAsExpression(unwrapped) ||
|
|
622
|
+
ts.isTypeAssertionExpression(unwrapped)) {
|
|
613
623
|
return convertTypeNode(unwrapped.type);
|
|
614
624
|
}
|
|
615
625
|
if (ts.isNonNullExpression(unwrapped)) {
|
|
@@ -790,13 +800,13 @@ export const createTypeSystem = (config) => {
|
|
|
790
800
|
});
|
|
791
801
|
const env = new Map();
|
|
792
802
|
for (const p of parameters) {
|
|
793
|
-
if (p.pattern.kind === "identifierPattern" &&
|
|
794
|
-
p.pattern.name &&
|
|
795
|
-
p.type) {
|
|
803
|
+
if (p.pattern.kind === "identifierPattern" && p.pattern.name && p.type) {
|
|
796
804
|
env.set(p.pattern.name, p.type);
|
|
797
805
|
}
|
|
798
806
|
}
|
|
799
|
-
const explicitReturnType = "type" in unwrapped && unwrapped.type
|
|
807
|
+
const explicitReturnType = "type" in unwrapped && unwrapped.type
|
|
808
|
+
? convertTypeNode(unwrapped.type)
|
|
809
|
+
: undefined;
|
|
800
810
|
const expectedReturnType = expectedFnType?.returnType;
|
|
801
811
|
const inferredReturnType = explicitReturnType ??
|
|
802
812
|
(expectedReturnType && !containsTypeParameter(expectedReturnType)
|
|
@@ -1222,7 +1232,9 @@ export const createTypeSystem = (config) => {
|
|
|
1222
1232
|
const effectiveReceiver = receiver.kind === "unionType"
|
|
1223
1233
|
? (() => {
|
|
1224
1234
|
const nonNullish = receiver.types.filter((t) => t && !isNullishPrimitive(t));
|
|
1225
|
-
return nonNullish.length === 1 && nonNullish[0]
|
|
1235
|
+
return nonNullish.length === 1 && nonNullish[0]
|
|
1236
|
+
? nonNullish[0]
|
|
1237
|
+
: receiver;
|
|
1226
1238
|
})()
|
|
1227
1239
|
: receiver;
|
|
1228
1240
|
// 1. Normalize receiver to nominal form
|
|
@@ -1230,7 +1242,8 @@ export const createTypeSystem = (config) => {
|
|
|
1230
1242
|
if (!normalized) {
|
|
1231
1243
|
// Handle structural types (objectType)
|
|
1232
1244
|
if (effectiveReceiver.kind === "objectType" ||
|
|
1233
|
-
(effectiveReceiver.kind === "referenceType" &&
|
|
1245
|
+
(effectiveReceiver.kind === "referenceType" &&
|
|
1246
|
+
effectiveReceiver.structuralMembers)) {
|
|
1234
1247
|
return lookupStructuralMember(effectiveReceiver, memberName, site);
|
|
1235
1248
|
}
|
|
1236
1249
|
emitDiagnostic("TSN5203", `Cannot resolve member '${memberName}' on type`, site);
|
|
@@ -1333,7 +1346,9 @@ export const createTypeSystem = (config) => {
|
|
|
1333
1346
|
if (!first)
|
|
1334
1347
|
return undefined;
|
|
1335
1348
|
// Strip assembly qualification (", Assembly, Version=..., ...") if present.
|
|
1336
|
-
const withoutAsm = first.includes(",")
|
|
1349
|
+
const withoutAsm = first.includes(",")
|
|
1350
|
+
? (first.split(",")[0] ?? first)
|
|
1351
|
+
: first;
|
|
1337
1352
|
return withoutAsm.trim();
|
|
1338
1353
|
};
|
|
1339
1354
|
const getIndexerInfo = (receiver, _site) => {
|
|
@@ -1401,7 +1416,22 @@ export const createTypeSystem = (config) => {
|
|
|
1401
1416
|
return true;
|
|
1402
1417
|
}
|
|
1403
1418
|
// Poison/any provides no deterministic information
|
|
1404
|
-
if (argumentType.kind === "unknownType" ||
|
|
1419
|
+
if (argumentType.kind === "unknownType" ||
|
|
1420
|
+
argumentType.kind === "anyType") {
|
|
1421
|
+
return true;
|
|
1422
|
+
}
|
|
1423
|
+
// Intersection argument types: unify through each constituent.
|
|
1424
|
+
//
|
|
1425
|
+
// This is required for airplane-grade extension method typing where the receiver
|
|
1426
|
+
// often has the form `TShape & <extension markers> & <method table>`.
|
|
1427
|
+
// Generic inference must still be able to infer through the real CLR shape in the intersection.
|
|
1428
|
+
if (argumentType.kind === "intersectionType") {
|
|
1429
|
+
for (const part of argumentType.types) {
|
|
1430
|
+
if (!part)
|
|
1431
|
+
continue;
|
|
1432
|
+
if (!tryUnify(parameterType, part))
|
|
1433
|
+
return false;
|
|
1434
|
+
}
|
|
1405
1435
|
return true;
|
|
1406
1436
|
}
|
|
1407
1437
|
// Expression<TDelegate> wrapper: infer through the underlying delegate shape.
|
|
@@ -1419,12 +1449,14 @@ export const createTypeSystem = (config) => {
|
|
|
1419
1449
|
// Without this, generic methods like:
|
|
1420
1450
|
// Select<TResult>(selector: Func<TSource, TResult>)
|
|
1421
1451
|
// cannot infer TResult from a lambda argument, causing TSN5201/TSN5202.
|
|
1422
|
-
if (parameterType.kind === "referenceType" &&
|
|
1452
|
+
if (parameterType.kind === "referenceType" &&
|
|
1453
|
+
argumentType.kind === "functionType") {
|
|
1423
1454
|
const delegateFn = delegateToFunctionType(parameterType);
|
|
1424
1455
|
if (delegateFn)
|
|
1425
1456
|
return tryUnify(delegateFn, argumentType);
|
|
1426
1457
|
}
|
|
1427
|
-
if (parameterType.kind === "functionType" &&
|
|
1458
|
+
if (parameterType.kind === "functionType" &&
|
|
1459
|
+
argumentType.kind === "referenceType") {
|
|
1428
1460
|
const delegateFn = delegateToFunctionType(argumentType);
|
|
1429
1461
|
if (delegateFn)
|
|
1430
1462
|
return tryUnify(parameterType, delegateFn);
|
|
@@ -1435,14 +1467,18 @@ export const createTypeSystem = (config) => {
|
|
|
1435
1467
|
(parameterType.typeArguments?.length ?? 0) === 1 &&
|
|
1436
1468
|
argumentType.kind === "arrayType") {
|
|
1437
1469
|
const elementParam = parameterType.typeArguments?.[0];
|
|
1438
|
-
return elementParam
|
|
1470
|
+
return elementParam
|
|
1471
|
+
? tryUnify(elementParam, argumentType.elementType)
|
|
1472
|
+
: true;
|
|
1439
1473
|
}
|
|
1440
1474
|
// Union parameter type: allow deterministic inference through common nullish unions.
|
|
1441
1475
|
// Example: constructor(value: T | null) with argument of type T.
|
|
1442
1476
|
if (parameterType.kind === "unionType") {
|
|
1443
1477
|
const nonNullish = parameterType.types.filter((t) => t && !isNullishPrimitive(t));
|
|
1444
1478
|
const nullish = parameterType.types.filter((t) => t && isNullishPrimitive(t));
|
|
1445
|
-
const candidates = isNullishPrimitive(argumentType)
|
|
1479
|
+
const candidates = isNullishPrimitive(argumentType)
|
|
1480
|
+
? nullish
|
|
1481
|
+
: nonNullish;
|
|
1446
1482
|
if (candidates.length === 1) {
|
|
1447
1483
|
const only = candidates[0];
|
|
1448
1484
|
return only ? tryUnify(only, argumentType) : true;
|
|
@@ -1455,7 +1491,9 @@ export const createTypeSystem = (config) => {
|
|
|
1455
1491
|
argumentType.name === "Array" &&
|
|
1456
1492
|
(argumentType.typeArguments?.length ?? 0) === 1) {
|
|
1457
1493
|
const elementArg = argumentType.typeArguments?.[0];
|
|
1458
|
-
return elementArg
|
|
1494
|
+
return elementArg
|
|
1495
|
+
? tryUnify(parameterType.elementType, elementArg)
|
|
1496
|
+
: true;
|
|
1459
1497
|
}
|
|
1460
1498
|
// Same-kind structural unification
|
|
1461
1499
|
if (parameterType.kind !== argumentType.kind) {
|
|
@@ -1550,7 +1588,6 @@ export const createTypeSystem = (config) => {
|
|
|
1550
1588
|
}
|
|
1551
1589
|
return tryUnify(parameterType.returnType, argFn.returnType);
|
|
1552
1590
|
}
|
|
1553
|
-
case "intersectionType":
|
|
1554
1591
|
case "objectType":
|
|
1555
1592
|
case "dictionaryType":
|
|
1556
1593
|
// Conservative: only infer through these when shapes already match exactly.
|
|
@@ -1587,7 +1624,8 @@ export const createTypeSystem = (config) => {
|
|
|
1587
1624
|
}
|
|
1588
1625
|
if (type.kind === "functionType") {
|
|
1589
1626
|
const paramsContain = type.parameters.some((p) => p.type ? containsMethodTypeParameter(p.type, unresolved) : false);
|
|
1590
|
-
return paramsContain ||
|
|
1627
|
+
return (paramsContain ||
|
|
1628
|
+
containsMethodTypeParameter(type.returnType, unresolved));
|
|
1591
1629
|
}
|
|
1592
1630
|
if (type.kind === "unionType" || type.kind === "intersectionType") {
|
|
1593
1631
|
return type.types.some((t) => t ? containsMethodTypeParameter(t, unresolved) : false);
|
|
@@ -1670,7 +1708,7 @@ export const createTypeSystem = (config) => {
|
|
|
1670
1708
|
return score;
|
|
1671
1709
|
};
|
|
1672
1710
|
const tryResolveCallFromUnifiedCatalog = (declaringTypeTsName, declaringMemberName, query) => {
|
|
1673
|
-
const { argumentCount, receiverType, explicitTypeArgs, argTypes
|
|
1711
|
+
const { argumentCount, receiverType, explicitTypeArgs, argTypes } = query;
|
|
1674
1712
|
if (!argTypes)
|
|
1675
1713
|
return undefined;
|
|
1676
1714
|
if (argTypes.length < argumentCount)
|
|
@@ -1810,6 +1848,7 @@ export const createTypeSystem = (config) => {
|
|
|
1810
1848
|
}
|
|
1811
1849
|
// 2. Start with raw types
|
|
1812
1850
|
let workingParams = [...rawSig.parameterTypes];
|
|
1851
|
+
let workingThisParam = rawSig.thisParameterType;
|
|
1813
1852
|
let workingReturn = rawSig.returnType;
|
|
1814
1853
|
let workingPredicate = rawSig.typePredicate;
|
|
1815
1854
|
// 3. Compute receiver substitution (class type params)
|
|
@@ -1819,6 +1858,9 @@ export const createTypeSystem = (config) => {
|
|
|
1819
1858
|
const receiverSubst = computeReceiverSubstitution(receiverType, rawSig.declaringTypeTsName, rawSig.declaringMemberName);
|
|
1820
1859
|
if (receiverSubst && receiverSubst.size > 0) {
|
|
1821
1860
|
workingParams = workingParams.map((p) => p ? irSubstitute(p, receiverSubst) : undefined);
|
|
1861
|
+
if (workingThisParam) {
|
|
1862
|
+
workingThisParam = irSubstitute(workingThisParam, receiverSubst);
|
|
1863
|
+
}
|
|
1822
1864
|
workingReturn = irSubstitute(workingReturn, receiverSubst);
|
|
1823
1865
|
if (workingPredicate) {
|
|
1824
1866
|
workingPredicate =
|
|
@@ -1849,9 +1891,38 @@ export const createTypeSystem = (config) => {
|
|
|
1849
1891
|
}
|
|
1850
1892
|
}
|
|
1851
1893
|
// Source 2: Deterministic argument-driven unification
|
|
1852
|
-
|
|
1894
|
+
// 2a) Receiver-driven unification via TS `this:` parameter
|
|
1895
|
+
//
|
|
1896
|
+
// Method-table extension typing represents the receiver as an explicit `this:` parameter
|
|
1897
|
+
// in the `.d.ts` signature. Generic methods like:
|
|
1898
|
+
// ToArrayAsync<T>(this: IQueryable<T>, ...): Task<T[]>
|
|
1899
|
+
// must infer T from the receiver even when there are ZERO call arguments.
|
|
1900
|
+
//
|
|
1901
|
+
// This is airplane-grade determinism: we anchor inference to the selected TS signature’s
|
|
1902
|
+
// `this:` type and the IR receiver type (not TS structural tricks).
|
|
1903
|
+
if (receiverType && workingThisParam) {
|
|
1904
|
+
const receiverParamForInference = callSubst.size > 0
|
|
1905
|
+
? irSubstitute(workingThisParam, callSubst)
|
|
1906
|
+
: workingThisParam;
|
|
1907
|
+
const inferredFromReceiver = inferMethodTypeArgsFromArguments(methodTypeParams, [receiverParamForInference], [receiverType]);
|
|
1908
|
+
if (inferredFromReceiver) {
|
|
1909
|
+
for (const [name, inferredType] of inferredFromReceiver) {
|
|
1910
|
+
const existing = callSubst.get(name);
|
|
1911
|
+
if (existing) {
|
|
1912
|
+
if (!typesEqual(existing, inferredType)) {
|
|
1913
|
+
emitDiagnostic("TSN5202", `Conflicting type argument inference for '${name}' (receiver)`, site);
|
|
1914
|
+
return poisonedCall(argumentCount, diagnostics.slice());
|
|
1915
|
+
}
|
|
1916
|
+
continue;
|
|
1917
|
+
}
|
|
1918
|
+
callSubst.set(name, inferredType);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
// 2b) Argument-driven unification (run even when argTypes is empty).
|
|
1923
|
+
if (argTypes) {
|
|
1853
1924
|
const paramsForInference = callSubst.size > 0
|
|
1854
|
-
? workingParams.map((p) =>
|
|
1925
|
+
? workingParams.map((p) => p ? irSubstitute(p, callSubst) : undefined)
|
|
1855
1926
|
: workingParams;
|
|
1856
1927
|
const inferred = inferMethodTypeArgsFromArguments(methodTypeParams, paramsForInference, argTypes);
|
|
1857
1928
|
if (!inferred) {
|
|
@@ -1897,7 +1968,8 @@ export const createTypeSystem = (config) => {
|
|
|
1897
1968
|
const unresolved = new Set(methodTypeParams
|
|
1898
1969
|
.map((tp) => tp.name)
|
|
1899
1970
|
.filter((name) => !callSubst.has(name)));
|
|
1900
|
-
if (unresolved.size > 0 &&
|
|
1971
|
+
if (unresolved.size > 0 &&
|
|
1972
|
+
containsMethodTypeParameter(workingReturn, unresolved)) {
|
|
1901
1973
|
const fallback = argTypes && rawSig.declaringTypeTsName && rawSig.declaringMemberName
|
|
1902
1974
|
? tryResolveCallFromUnifiedCatalog(rawSig.declaringTypeTsName, rawSig.declaringMemberName, query)
|
|
1903
1975
|
: undefined;
|
|
@@ -2237,7 +2309,10 @@ export const createTypeSystem = (config) => {
|
|
|
2237
2309
|
*/
|
|
2238
2310
|
const expandAwaitedUtility = (type) => {
|
|
2239
2311
|
if (type.kind === "unionType") {
|
|
2240
|
-
return {
|
|
2312
|
+
return {
|
|
2313
|
+
kind: "unionType",
|
|
2314
|
+
types: type.types.map((t) => expandAwaitedUtility(t)),
|
|
2315
|
+
};
|
|
2241
2316
|
}
|
|
2242
2317
|
// Check for Promise<T>
|
|
2243
2318
|
if (type.kind === "referenceType" &&
|