@manifesto-ai/compiler 1.8.0 → 1.8.2
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/{chunk-MKLDAZ2Z.js → chunk-4JJQCFJH.js} +779 -68
- package/dist/chunk-4JJQCFJH.js.map +1 -0
- package/dist/{chunk-D62NIFP4.js → chunk-AYZTDA3J.js} +2 -2
- package/dist/{chunk-BH25NHMN.js → chunk-K4IKHGOP.js} +3 -3
- package/dist/esbuild.js +3 -3
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -1
- package/dist/node-loader.js +2 -2
- package/dist/rollup.js +3 -3
- package/dist/rspack.js +3 -3
- package/dist/vite.js +3 -3
- package/dist/webpack.js +3 -3
- package/package.json +4 -4
- package/dist/chunk-MKLDAZ2Z.js.map +0 -1
- /package/dist/{chunk-D62NIFP4.js.map → chunk-AYZTDA3J.js.map} +0 -0
- /package/dist/{chunk-BH25NHMN.js.map → chunk-K4IKHGOP.js.map} +0 -0
|
@@ -2002,16 +2002,16 @@ function inferExprType(expr, env, symbols) {
|
|
|
2002
2002
|
location: expr.location
|
|
2003
2003
|
};
|
|
2004
2004
|
case "arrayLiteral": {
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
if (!
|
|
2005
|
+
const elementType = joinTypeCandidates(
|
|
2006
|
+
expr.elements.map((element) => inferExprType(element, env, symbols)),
|
|
2007
|
+
expr.location
|
|
2008
|
+
);
|
|
2009
|
+
if (!elementType) {
|
|
2010
2010
|
return null;
|
|
2011
2011
|
}
|
|
2012
2012
|
return {
|
|
2013
2013
|
kind: "arrayType",
|
|
2014
|
-
elementType
|
|
2014
|
+
elementType,
|
|
2015
2015
|
location: expr.location
|
|
2016
2016
|
};
|
|
2017
2017
|
}
|
|
@@ -2030,8 +2030,9 @@ function inferExprType(expr, env, symbols) {
|
|
|
2030
2030
|
case "functionCall":
|
|
2031
2031
|
return inferFunctionCallType(expr, env, symbols);
|
|
2032
2032
|
case "systemIdent":
|
|
2033
|
-
case "iterationVar":
|
|
2034
2033
|
return null;
|
|
2034
|
+
case "iterationVar":
|
|
2035
|
+
return env.get("$item") ?? null;
|
|
2035
2036
|
}
|
|
2036
2037
|
}
|
|
2037
2038
|
function classifyComparableExpr(expr, env, symbols) {
|
|
@@ -2265,6 +2266,29 @@ function inferFunctionCallType(expr, env, symbols) {
|
|
|
2265
2266
|
}
|
|
2266
2267
|
return joinTypeCandidates([elementType, simpleType("null", expr.location)], expr.location);
|
|
2267
2268
|
}
|
|
2269
|
+
if (expr.name === "filter" && expr.args.length >= 1) {
|
|
2270
|
+
return inferExprType(expr.args[0], env, symbols);
|
|
2271
|
+
}
|
|
2272
|
+
if (expr.name === "map" && expr.args.length >= 2) {
|
|
2273
|
+
const arrayType = inferExprType(expr.args[0], env, symbols);
|
|
2274
|
+
const elementType = getArrayElementType(arrayType, symbols);
|
|
2275
|
+
if (!elementType) {
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
const mapperType = inferExprType(
|
|
2279
|
+
expr.args[1],
|
|
2280
|
+
extendCollectionEnv(env, elementType),
|
|
2281
|
+
symbols
|
|
2282
|
+
);
|
|
2283
|
+
if (!mapperType) {
|
|
2284
|
+
return null;
|
|
2285
|
+
}
|
|
2286
|
+
return {
|
|
2287
|
+
kind: "arrayType",
|
|
2288
|
+
elementType: mapperType,
|
|
2289
|
+
location: expr.location
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2268
2292
|
if ((expr.name === "first" || expr.name === "last") && expr.args.length >= 1) {
|
|
2269
2293
|
return getArrayElementType(inferExprType(expr.args[0], env, symbols), symbols);
|
|
2270
2294
|
}
|
|
@@ -2299,6 +2323,20 @@ function inferFunctionCallType(expr, env, symbols) {
|
|
|
2299
2323
|
if (expr.name === "slice" && expr.args.length >= 1) {
|
|
2300
2324
|
return inferExprType(expr.args[0], env, symbols);
|
|
2301
2325
|
}
|
|
2326
|
+
if (expr.name === "split") {
|
|
2327
|
+
return {
|
|
2328
|
+
kind: "arrayType",
|
|
2329
|
+
elementType: simpleType("string", expr.location),
|
|
2330
|
+
location: expr.location
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
if (expr.name === "keys") {
|
|
2334
|
+
return {
|
|
2335
|
+
kind: "arrayType",
|
|
2336
|
+
elementType: simpleType("string", expr.location),
|
|
2337
|
+
location: expr.location
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2302
2340
|
return null;
|
|
2303
2341
|
}
|
|
2304
2342
|
function joinComparableClasses(classes) {
|
|
@@ -2360,6 +2398,11 @@ function getStaticPropertyName(expr) {
|
|
|
2360
2398
|
}
|
|
2361
2399
|
return null;
|
|
2362
2400
|
}
|
|
2401
|
+
function extendCollectionEnv(env, itemType) {
|
|
2402
|
+
const next = new Map(env);
|
|
2403
|
+
next.set("$item", itemType);
|
|
2404
|
+
return next;
|
|
2405
|
+
}
|
|
2363
2406
|
|
|
2364
2407
|
// src/analyzer/entity-primitives.ts
|
|
2365
2408
|
var ENTITY_LOOKUP_FNS = /* @__PURE__ */ new Set(["findById", "existsById"]);
|
|
@@ -2680,6 +2723,288 @@ function createContext() {
|
|
|
2680
2723
|
};
|
|
2681
2724
|
}
|
|
2682
2725
|
var STOP_WAITING_REASON_PATTERN = /\b(await(?:ing)?|wait(?:ing)?|pending)\b/i;
|
|
2726
|
+
function simpleTypeNode(name, location) {
|
|
2727
|
+
return {
|
|
2728
|
+
kind: "simpleType",
|
|
2729
|
+
name,
|
|
2730
|
+
location
|
|
2731
|
+
};
|
|
2732
|
+
}
|
|
2733
|
+
function isAssignableType(sourceType, targetType, symbols) {
|
|
2734
|
+
const resolvedSource = resolveType(sourceType, symbols);
|
|
2735
|
+
const resolvedTarget = resolveType(targetType, symbols);
|
|
2736
|
+
if (!resolvedSource || !resolvedTarget) {
|
|
2737
|
+
return null;
|
|
2738
|
+
}
|
|
2739
|
+
if (resolvedTarget.kind === "unionType") {
|
|
2740
|
+
const sourceMembers = resolvedSource.kind === "unionType" ? resolvedSource.types : [resolvedSource];
|
|
2741
|
+
let sawUnknown = false;
|
|
2742
|
+
for (const member of sourceMembers) {
|
|
2743
|
+
const outcomes = resolvedTarget.types.map(
|
|
2744
|
+
(candidate) => isAssignableType(member, candidate, symbols)
|
|
2745
|
+
);
|
|
2746
|
+
if (outcomes.includes(true)) {
|
|
2747
|
+
continue;
|
|
2748
|
+
}
|
|
2749
|
+
if (outcomes.every((outcome) => outcome === false)) {
|
|
2750
|
+
return false;
|
|
2751
|
+
}
|
|
2752
|
+
sawUnknown = true;
|
|
2753
|
+
}
|
|
2754
|
+
return sawUnknown ? null : true;
|
|
2755
|
+
}
|
|
2756
|
+
if (resolvedSource.kind === "unionType") {
|
|
2757
|
+
let sawUnknown = false;
|
|
2758
|
+
for (const member of resolvedSource.types) {
|
|
2759
|
+
const outcome = isAssignableType(member, resolvedTarget, symbols);
|
|
2760
|
+
if (outcome === false) {
|
|
2761
|
+
return false;
|
|
2762
|
+
}
|
|
2763
|
+
if (outcome === null) {
|
|
2764
|
+
sawUnknown = true;
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
return sawUnknown ? null : true;
|
|
2768
|
+
}
|
|
2769
|
+
if (resolvedTarget.kind === "simpleType") {
|
|
2770
|
+
if (resolvedSource.kind === "simpleType") {
|
|
2771
|
+
return resolvedSource.name === resolvedTarget.name;
|
|
2772
|
+
}
|
|
2773
|
+
if (resolvedSource.kind === "literalType") {
|
|
2774
|
+
if (resolvedTarget.name === "null") {
|
|
2775
|
+
return resolvedSource.value === null;
|
|
2776
|
+
}
|
|
2777
|
+
return typeof resolvedSource.value === resolvedTarget.name;
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
if (resolvedTarget.kind === "literalType") {
|
|
2781
|
+
if (resolvedSource.kind !== "literalType") {
|
|
2782
|
+
return false;
|
|
2783
|
+
}
|
|
2784
|
+
return resolvedSource.value === resolvedTarget.value;
|
|
2785
|
+
}
|
|
2786
|
+
if (resolvedTarget.kind === "arrayType") {
|
|
2787
|
+
if (resolvedSource.kind !== "arrayType") {
|
|
2788
|
+
return false;
|
|
2789
|
+
}
|
|
2790
|
+
return isAssignableType(resolvedSource.elementType, resolvedTarget.elementType, symbols);
|
|
2791
|
+
}
|
|
2792
|
+
if (resolvedTarget.kind === "objectType") {
|
|
2793
|
+
if (resolvedSource.kind !== "objectType") {
|
|
2794
|
+
return false;
|
|
2795
|
+
}
|
|
2796
|
+
for (const targetField of resolvedTarget.fields) {
|
|
2797
|
+
const sourceField = resolvedSource.fields.find((candidate) => candidate.name === targetField.name);
|
|
2798
|
+
if (!sourceField) {
|
|
2799
|
+
if (targetField.optional) {
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
return false;
|
|
2803
|
+
}
|
|
2804
|
+
const fieldAssignable = isAssignableType(sourceField.typeExpr, targetField.typeExpr, symbols);
|
|
2805
|
+
if (fieldAssignable !== true) {
|
|
2806
|
+
return fieldAssignable;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
return true;
|
|
2810
|
+
}
|
|
2811
|
+
if (resolvedTarget.kind === "recordType") {
|
|
2812
|
+
if (resolvedSource.kind !== "recordType") {
|
|
2813
|
+
return null;
|
|
2814
|
+
}
|
|
2815
|
+
return isAssignableType(resolvedSource.valueType, resolvedTarget.valueType, symbols);
|
|
2816
|
+
}
|
|
2817
|
+
return null;
|
|
2818
|
+
}
|
|
2819
|
+
function describeTypeExpr(typeExpr, symbols) {
|
|
2820
|
+
const resolved = resolveType(typeExpr, symbols);
|
|
2821
|
+
if (!resolved) {
|
|
2822
|
+
return "unknown";
|
|
2823
|
+
}
|
|
2824
|
+
switch (resolved.kind) {
|
|
2825
|
+
case "simpleType":
|
|
2826
|
+
return resolved.name;
|
|
2827
|
+
case "literalType":
|
|
2828
|
+
return JSON.stringify(resolved.value);
|
|
2829
|
+
case "arrayType":
|
|
2830
|
+
return `Array<${describeTypeExpr(resolved.elementType, symbols)}>`;
|
|
2831
|
+
case "recordType":
|
|
2832
|
+
return `Record<${describeTypeExpr(resolved.keyType, symbols)}, ${describeTypeExpr(resolved.valueType, symbols)}>`;
|
|
2833
|
+
case "objectType":
|
|
2834
|
+
return `{ ${resolved.fields.map((field) => `${field.name}${field.optional ? "?" : ""}: ${describeTypeExpr(field.typeExpr, symbols)}`).join("; ")} }`;
|
|
2835
|
+
case "unionType":
|
|
2836
|
+
return resolved.types.map((member) => describeTypeExpr(member, symbols)).join(" | ");
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
function collectPrimitiveKinds(typeExpr, symbols) {
|
|
2840
|
+
const resolved = resolveType(typeExpr, symbols);
|
|
2841
|
+
if (!resolved) {
|
|
2842
|
+
return null;
|
|
2843
|
+
}
|
|
2844
|
+
switch (resolved.kind) {
|
|
2845
|
+
case "simpleType":
|
|
2846
|
+
if (resolved.name === "string" || resolved.name === "number" || resolved.name === "boolean" || resolved.name === "null") {
|
|
2847
|
+
return /* @__PURE__ */ new Set([resolved.name]);
|
|
2848
|
+
}
|
|
2849
|
+
return resolved.name === "object" ? "nonprimitive" : null;
|
|
2850
|
+
case "literalType":
|
|
2851
|
+
return /* @__PURE__ */ new Set([
|
|
2852
|
+
resolved.value === null ? "null" : typeof resolved.value
|
|
2853
|
+
]);
|
|
2854
|
+
case "arrayType":
|
|
2855
|
+
case "recordType":
|
|
2856
|
+
case "objectType":
|
|
2857
|
+
return "nonprimitive";
|
|
2858
|
+
case "unionType": {
|
|
2859
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
2860
|
+
for (const member of resolved.types) {
|
|
2861
|
+
const memberKinds = collectPrimitiveKinds(member, symbols);
|
|
2862
|
+
if (memberKinds === null) {
|
|
2863
|
+
return null;
|
|
2864
|
+
}
|
|
2865
|
+
if (memberKinds === "nonprimitive") {
|
|
2866
|
+
return "nonprimitive";
|
|
2867
|
+
}
|
|
2868
|
+
for (const kind of memberKinds) {
|
|
2869
|
+
kinds.add(kind);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
return kinds;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
function areComparableTypesCompatible(leftType, rightType, symbols) {
|
|
2877
|
+
const leftKinds = collectPrimitiveKinds(leftType, symbols);
|
|
2878
|
+
const rightKinds = collectPrimitiveKinds(rightType, symbols);
|
|
2879
|
+
if (leftKinds === null || rightKinds === null) {
|
|
2880
|
+
return null;
|
|
2881
|
+
}
|
|
2882
|
+
if (leftKinds === "nonprimitive" || rightKinds === "nonprimitive") {
|
|
2883
|
+
return false;
|
|
2884
|
+
}
|
|
2885
|
+
if (!(leftKinds instanceof Set) || !(rightKinds instanceof Set)) {
|
|
2886
|
+
return null;
|
|
2887
|
+
}
|
|
2888
|
+
const leftNonNull = [...leftKinds].filter((kind) => kind !== "null");
|
|
2889
|
+
const rightNonNull = [...rightKinds].filter((kind) => kind !== "null");
|
|
2890
|
+
if (leftNonNull.length === 0 || rightNonNull.length === 0) {
|
|
2891
|
+
return true;
|
|
2892
|
+
}
|
|
2893
|
+
return leftNonNull.some((kind) => rightNonNull.includes(kind));
|
|
2894
|
+
}
|
|
2895
|
+
function stripNullType(typeExpr, symbols) {
|
|
2896
|
+
const resolved = resolveType(typeExpr, symbols);
|
|
2897
|
+
if (!resolved || isNullType(resolved)) {
|
|
2898
|
+
return null;
|
|
2899
|
+
}
|
|
2900
|
+
if (resolved.kind !== "unionType") {
|
|
2901
|
+
return resolved;
|
|
2902
|
+
}
|
|
2903
|
+
const members = resolved.types.filter((member) => !isNullType(member));
|
|
2904
|
+
if (members.length === 0) {
|
|
2905
|
+
return null;
|
|
2906
|
+
}
|
|
2907
|
+
if (members.length === 1) {
|
|
2908
|
+
return members[0];
|
|
2909
|
+
}
|
|
2910
|
+
return {
|
|
2911
|
+
kind: "unionType",
|
|
2912
|
+
types: members,
|
|
2913
|
+
location: resolved.location
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
function areTypesCompatible(leftType, rightType, symbols) {
|
|
2917
|
+
if (!leftType || !rightType) {
|
|
2918
|
+
return null;
|
|
2919
|
+
}
|
|
2920
|
+
const leftToRight = isAssignableType(leftType, rightType, symbols);
|
|
2921
|
+
if (leftToRight === true) {
|
|
2922
|
+
return true;
|
|
2923
|
+
}
|
|
2924
|
+
const rightToLeft = isAssignableType(rightType, leftType, symbols);
|
|
2925
|
+
if (rightToLeft === true) {
|
|
2926
|
+
return true;
|
|
2927
|
+
}
|
|
2928
|
+
const comparable = areComparableTypesCompatible(leftType, rightType, symbols);
|
|
2929
|
+
if (comparable !== null) {
|
|
2930
|
+
return comparable;
|
|
2931
|
+
}
|
|
2932
|
+
if (leftToRight === false && rightToLeft === false) {
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
return null;
|
|
2936
|
+
}
|
|
2937
|
+
function classifyArrayOperand(typeExpr, symbols) {
|
|
2938
|
+
const resolved = resolveType(typeExpr, symbols);
|
|
2939
|
+
if (!resolved) {
|
|
2940
|
+
return null;
|
|
2941
|
+
}
|
|
2942
|
+
if (resolved.kind === "unionType") {
|
|
2943
|
+
const outcomes = resolved.types.map((member) => classifyArrayOperand(member, symbols));
|
|
2944
|
+
if (outcomes.every((outcome) => outcome === true)) {
|
|
2945
|
+
return true;
|
|
2946
|
+
}
|
|
2947
|
+
return outcomes.some((outcome) => outcome === false) ? false : null;
|
|
2948
|
+
}
|
|
2949
|
+
return resolved.kind === "arrayType";
|
|
2950
|
+
}
|
|
2951
|
+
function classifyLenOperand(typeExpr, symbols) {
|
|
2952
|
+
const resolved = resolveType(typeExpr, symbols);
|
|
2953
|
+
if (!resolved) {
|
|
2954
|
+
return null;
|
|
2955
|
+
}
|
|
2956
|
+
if (resolved.kind === "unionType") {
|
|
2957
|
+
const outcomes = resolved.types.map((member) => classifyLenOperand(member, symbols));
|
|
2958
|
+
if (outcomes.every((outcome) => outcome === true)) {
|
|
2959
|
+
return true;
|
|
2960
|
+
}
|
|
2961
|
+
return outcomes.some((outcome) => outcome === false) ? false : null;
|
|
2962
|
+
}
|
|
2963
|
+
if (resolved.kind === "arrayType" || resolved.kind === "recordType" || resolved.kind === "objectType") {
|
|
2964
|
+
return true;
|
|
2965
|
+
}
|
|
2966
|
+
if (resolved.kind === "literalType") {
|
|
2967
|
+
return typeof resolved.value === "string";
|
|
2968
|
+
}
|
|
2969
|
+
if (resolved.kind === "simpleType") {
|
|
2970
|
+
return resolved.name === "string" || resolved.name === "object";
|
|
2971
|
+
}
|
|
2972
|
+
return false;
|
|
2973
|
+
}
|
|
2974
|
+
function extendCollectionTypeEnv(baseEnv, itemType) {
|
|
2975
|
+
const next = new Map(baseEnv);
|
|
2976
|
+
next.set("$item", itemType);
|
|
2977
|
+
return next;
|
|
2978
|
+
}
|
|
2979
|
+
function resolvePathType(path, symbols) {
|
|
2980
|
+
const [first, ...rest] = path.segments;
|
|
2981
|
+
if (!first || first.kind !== "propertySegment") {
|
|
2982
|
+
return null;
|
|
2983
|
+
}
|
|
2984
|
+
let current = symbols.stateTypes.get(first.name) ?? null;
|
|
2985
|
+
for (const segment of rest) {
|
|
2986
|
+
if (!current) {
|
|
2987
|
+
return null;
|
|
2988
|
+
}
|
|
2989
|
+
current = segment.kind === "propertySegment" ? getPropertyType(current, segment.name, symbols) : getIndexType(current, symbols);
|
|
2990
|
+
}
|
|
2991
|
+
return current;
|
|
2992
|
+
}
|
|
2993
|
+
function renderPath(path) {
|
|
2994
|
+
let result = "";
|
|
2995
|
+
for (const [index, segment] of path.segments.entries()) {
|
|
2996
|
+
if (segment.kind === "propertySegment") {
|
|
2997
|
+
result += index === 0 ? segment.name : `.${segment.name}`;
|
|
2998
|
+
continue;
|
|
2999
|
+
}
|
|
3000
|
+
if (segment.index.kind === "literal") {
|
|
3001
|
+
result += `[${JSON.stringify(segment.index.value)}]`;
|
|
3002
|
+
} else {
|
|
3003
|
+
result += "[*]";
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
return result;
|
|
3007
|
+
}
|
|
2683
3008
|
var SemanticValidator = class {
|
|
2684
3009
|
ctx = createContext();
|
|
2685
3010
|
symbols = null;
|
|
@@ -3063,7 +3388,23 @@ var SemanticValidator = class {
|
|
|
3063
3388
|
);
|
|
3064
3389
|
}
|
|
3065
3390
|
if (stmt.value) {
|
|
3066
|
-
this.
|
|
3391
|
+
const before = this.ctx.diagnostics.length;
|
|
3392
|
+
const valueType = this.validateExpr(stmt.value, "action");
|
|
3393
|
+
if (!this.symbols || before !== this.ctx.diagnostics.length) {
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
const targetType = resolvePathType(stmt.path, this.symbols);
|
|
3397
|
+
if (!targetType || !valueType) {
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
const assignable = isAssignableType(valueType, targetType, this.symbols);
|
|
3401
|
+
if (assignable === false) {
|
|
3402
|
+
this.error(
|
|
3403
|
+
`Patch value for '${renderPath(stmt.path)}' must be assignable to ${describeTypeExpr(targetType, this.symbols)}, got ${describeTypeExpr(valueType, this.symbols)}`,
|
|
3404
|
+
stmt.value.location,
|
|
3405
|
+
"E_TYPE_MISMATCH"
|
|
3406
|
+
);
|
|
3407
|
+
}
|
|
3067
3408
|
}
|
|
3068
3409
|
}
|
|
3069
3410
|
validateEffect(stmt) {
|
|
@@ -3109,57 +3450,144 @@ var SemanticValidator = class {
|
|
|
3109
3450
|
}
|
|
3110
3451
|
}
|
|
3111
3452
|
validateCondition(expr, guardType) {
|
|
3112
|
-
this.
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3453
|
+
const before = this.ctx.diagnostics.length;
|
|
3454
|
+
const conditionType = this.validateExpr(expr, "action");
|
|
3455
|
+
if (before === this.ctx.diagnostics.length) {
|
|
3456
|
+
this.requireAssignable(
|
|
3457
|
+
conditionType,
|
|
3458
|
+
simpleTypeNode("boolean", expr.location),
|
|
3116
3459
|
expr.location,
|
|
3117
|
-
|
|
3460
|
+
`Condition in ${guardType} must evaluate to boolean`
|
|
3118
3461
|
);
|
|
3119
3462
|
}
|
|
3120
3463
|
}
|
|
3121
|
-
validateExpr(expr, context) {
|
|
3464
|
+
validateExpr(expr, context, env = this.ctx.currentActionParamTypes) {
|
|
3122
3465
|
switch (expr.kind) {
|
|
3123
3466
|
case "functionCall":
|
|
3124
|
-
this.validateFunctionCall(expr, context);
|
|
3125
|
-
|
|
3126
|
-
case "binary":
|
|
3127
|
-
this.
|
|
3128
|
-
this.validateExpr(expr.
|
|
3129
|
-
|
|
3130
|
-
|
|
3467
|
+
this.validateFunctionCall(expr, context, env);
|
|
3468
|
+
return this.inferType(expr, env);
|
|
3469
|
+
case "binary": {
|
|
3470
|
+
const before = this.ctx.diagnostics.length;
|
|
3471
|
+
const leftType = this.validateExpr(expr.left, context, env);
|
|
3472
|
+
const rightType = this.validateExpr(expr.right, context, env);
|
|
3473
|
+
const hadInnerErrors = before !== this.ctx.diagnostics.length;
|
|
3474
|
+
if (!hadInnerErrors) {
|
|
3475
|
+
switch (expr.operator) {
|
|
3476
|
+
case "==":
|
|
3477
|
+
case "!=":
|
|
3478
|
+
this.validatePrimitiveEquality(expr.left, expr.right, leftType, rightType, expr.location);
|
|
3479
|
+
break;
|
|
3480
|
+
case "<":
|
|
3481
|
+
case "<=":
|
|
3482
|
+
case ">":
|
|
3483
|
+
case ">=":
|
|
3484
|
+
this.requireAssignable(
|
|
3485
|
+
leftType,
|
|
3486
|
+
simpleTypeNode("number", expr.left.location),
|
|
3487
|
+
expr.left.location,
|
|
3488
|
+
`Operator '${expr.operator}' requires a numeric left operand`
|
|
3489
|
+
);
|
|
3490
|
+
this.requireAssignable(
|
|
3491
|
+
rightType,
|
|
3492
|
+
simpleTypeNode("number", expr.right.location),
|
|
3493
|
+
expr.right.location,
|
|
3494
|
+
`Operator '${expr.operator}' requires a numeric right operand`
|
|
3495
|
+
);
|
|
3496
|
+
break;
|
|
3497
|
+
case "&&":
|
|
3498
|
+
case "||":
|
|
3499
|
+
this.requireAssignable(
|
|
3500
|
+
leftType,
|
|
3501
|
+
simpleTypeNode("boolean", expr.left.location),
|
|
3502
|
+
expr.left.location,
|
|
3503
|
+
`Operator '${expr.operator}' requires a boolean left operand`
|
|
3504
|
+
);
|
|
3505
|
+
this.requireAssignable(
|
|
3506
|
+
rightType,
|
|
3507
|
+
simpleTypeNode("boolean", expr.right.location),
|
|
3508
|
+
expr.right.location,
|
|
3509
|
+
`Operator '${expr.operator}' requires a boolean right operand`
|
|
3510
|
+
);
|
|
3511
|
+
break;
|
|
3512
|
+
case "+":
|
|
3513
|
+
case "-":
|
|
3514
|
+
case "*":
|
|
3515
|
+
case "/":
|
|
3516
|
+
case "%":
|
|
3517
|
+
this.requireAssignable(
|
|
3518
|
+
leftType,
|
|
3519
|
+
simpleTypeNode("number", expr.left.location),
|
|
3520
|
+
expr.left.location,
|
|
3521
|
+
`Operator '${expr.operator}' requires a numeric left operand`
|
|
3522
|
+
);
|
|
3523
|
+
this.requireAssignable(
|
|
3524
|
+
rightType,
|
|
3525
|
+
simpleTypeNode("number", expr.right.location),
|
|
3526
|
+
expr.right.location,
|
|
3527
|
+
`Operator '${expr.operator}' requires a numeric right operand`
|
|
3528
|
+
);
|
|
3529
|
+
break;
|
|
3530
|
+
case "??":
|
|
3531
|
+
this.validateCoalesceTypes([leftType, rightType], expr.location);
|
|
3532
|
+
break;
|
|
3533
|
+
}
|
|
3131
3534
|
}
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
this.
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3535
|
+
return this.inferType(expr, env);
|
|
3536
|
+
}
|
|
3537
|
+
case "unary": {
|
|
3538
|
+
const before = this.ctx.diagnostics.length;
|
|
3539
|
+
const operandType = this.validateExpr(expr.operand, context, env);
|
|
3540
|
+
if (before === this.ctx.diagnostics.length) {
|
|
3541
|
+
this.requireAssignable(
|
|
3542
|
+
operandType,
|
|
3543
|
+
simpleTypeNode(expr.operator === "!" ? "boolean" : "number", expr.operand.location),
|
|
3544
|
+
expr.operand.location,
|
|
3545
|
+
expr.operator === "!" ? "Unary '!' requires a boolean operand" : "Unary '-' requires a numeric operand"
|
|
3546
|
+
);
|
|
3547
|
+
}
|
|
3548
|
+
return this.inferType(expr, env);
|
|
3549
|
+
}
|
|
3550
|
+
case "ternary": {
|
|
3551
|
+
const before = this.ctx.diagnostics.length;
|
|
3552
|
+
const conditionType = this.validateExpr(expr.condition, context, env);
|
|
3553
|
+
this.validateExpr(expr.consequent, context, env);
|
|
3554
|
+
this.validateExpr(expr.alternate, context, env);
|
|
3555
|
+
if (before === this.ctx.diagnostics.length) {
|
|
3556
|
+
this.requireAssignable(
|
|
3557
|
+
conditionType,
|
|
3558
|
+
simpleTypeNode("boolean", expr.condition.location),
|
|
3559
|
+
expr.condition.location,
|
|
3560
|
+
"Ternary condition must evaluate to boolean"
|
|
3561
|
+
);
|
|
3562
|
+
}
|
|
3563
|
+
return this.inferType(expr, env);
|
|
3564
|
+
}
|
|
3141
3565
|
case "propertyAccess":
|
|
3142
|
-
this.validateExpr(expr.object, context);
|
|
3143
|
-
|
|
3566
|
+
this.validateExpr(expr.object, context, env);
|
|
3567
|
+
return this.inferType(expr, env);
|
|
3144
3568
|
case "indexAccess":
|
|
3145
|
-
this.validateExpr(expr.object, context);
|
|
3146
|
-
this.validateExpr(expr.index, context);
|
|
3147
|
-
|
|
3569
|
+
this.validateExpr(expr.object, context, env);
|
|
3570
|
+
this.validateExpr(expr.index, context, env);
|
|
3571
|
+
return this.inferType(expr, env);
|
|
3148
3572
|
case "objectLiteral":
|
|
3149
3573
|
for (const prop of expr.properties) {
|
|
3150
|
-
this.validateExpr(prop.value, context);
|
|
3574
|
+
this.validateExpr(prop.value, context, env);
|
|
3151
3575
|
}
|
|
3152
|
-
|
|
3576
|
+
return this.inferType(expr, env);
|
|
3153
3577
|
case "arrayLiteral":
|
|
3154
3578
|
for (const elem of expr.elements) {
|
|
3155
|
-
this.validateExpr(elem, context);
|
|
3579
|
+
this.validateExpr(elem, context, env);
|
|
3156
3580
|
}
|
|
3157
|
-
|
|
3581
|
+
return this.inferType(expr, env);
|
|
3158
3582
|
case "systemIdent":
|
|
3159
|
-
|
|
3583
|
+
return this.inferType(expr, env);
|
|
3584
|
+
case "literal":
|
|
3585
|
+
case "identifier":
|
|
3586
|
+
case "iterationVar":
|
|
3587
|
+
return this.inferType(expr, env);
|
|
3160
3588
|
}
|
|
3161
3589
|
}
|
|
3162
|
-
validateFunctionCall(expr, context) {
|
|
3590
|
+
validateFunctionCall(expr, context, env) {
|
|
3163
3591
|
const { name, args, location } = expr;
|
|
3164
3592
|
if (["reduce", "fold", "foldl", "foldr", "scan"].includes(name)) {
|
|
3165
3593
|
this.error(
|
|
@@ -3189,9 +3617,6 @@ var SemanticValidator = class {
|
|
|
3189
3617
|
// FDR-MEL-042: eq/neq on primitives only
|
|
3190
3618
|
case "eq":
|
|
3191
3619
|
case "neq":
|
|
3192
|
-
if (args.length === 2) {
|
|
3193
|
-
this.validatePrimitiveEquality(args[0], args[1], location);
|
|
3194
|
-
}
|
|
3195
3620
|
break;
|
|
3196
3621
|
// FDR-MEL-026: len() on Array only
|
|
3197
3622
|
case "len":
|
|
@@ -3362,32 +3787,318 @@ var SemanticValidator = class {
|
|
|
3362
3787
|
);
|
|
3363
3788
|
break;
|
|
3364
3789
|
}
|
|
3365
|
-
|
|
3366
|
-
|
|
3790
|
+
const argTypes = [];
|
|
3791
|
+
if (["filter", "map", "find", "every", "some"].includes(name) && args.length > 0) {
|
|
3792
|
+
const sourceType = this.validateExpr(args[0], context, env);
|
|
3793
|
+
argTypes.push(sourceType);
|
|
3794
|
+
let callbackEnv = env;
|
|
3795
|
+
if (this.symbols) {
|
|
3796
|
+
const itemType = getArrayElementType(sourceType, this.symbols);
|
|
3797
|
+
if (itemType) {
|
|
3798
|
+
callbackEnv = extendCollectionTypeEnv(env, itemType);
|
|
3799
|
+
}
|
|
3800
|
+
}
|
|
3801
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
3802
|
+
argTypes.push(this.validateExpr(args[index], context, index === 1 ? callbackEnv : env));
|
|
3803
|
+
}
|
|
3804
|
+
} else {
|
|
3805
|
+
for (const arg of args) {
|
|
3806
|
+
argTypes.push(this.validateExpr(arg, context, env));
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
if (!this.symbols) {
|
|
3810
|
+
return;
|
|
3811
|
+
}
|
|
3812
|
+
switch (name) {
|
|
3813
|
+
case "eq":
|
|
3814
|
+
case "neq":
|
|
3815
|
+
if (args.length === 2) {
|
|
3816
|
+
this.validatePrimitiveEquality(args[0], args[1], argTypes[0], argTypes[1], location);
|
|
3817
|
+
}
|
|
3818
|
+
break;
|
|
3819
|
+
case "add":
|
|
3820
|
+
case "sub":
|
|
3821
|
+
case "mul":
|
|
3822
|
+
case "div":
|
|
3823
|
+
case "mod":
|
|
3824
|
+
case "pow":
|
|
3825
|
+
if (args.length === 2) {
|
|
3826
|
+
this.requireAssignable(
|
|
3827
|
+
argTypes[0],
|
|
3828
|
+
simpleTypeNode("number", args[0].location),
|
|
3829
|
+
args[0].location,
|
|
3830
|
+
`Function '${name}' expects a numeric first argument`
|
|
3831
|
+
);
|
|
3832
|
+
this.requireAssignable(
|
|
3833
|
+
argTypes[1],
|
|
3834
|
+
simpleTypeNode("number", args[1].location),
|
|
3835
|
+
args[1].location,
|
|
3836
|
+
`Function '${name}' expects a numeric second argument`
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3839
|
+
break;
|
|
3840
|
+
case "gt":
|
|
3841
|
+
case "gte":
|
|
3842
|
+
case "lt":
|
|
3843
|
+
case "lte":
|
|
3844
|
+
if (args.length === 2) {
|
|
3845
|
+
this.requireAssignable(
|
|
3846
|
+
argTypes[0],
|
|
3847
|
+
simpleTypeNode("number", args[0].location),
|
|
3848
|
+
args[0].location,
|
|
3849
|
+
`Function '${name}' expects a numeric first argument`
|
|
3850
|
+
);
|
|
3851
|
+
this.requireAssignable(
|
|
3852
|
+
argTypes[1],
|
|
3853
|
+
simpleTypeNode("number", args[1].location),
|
|
3854
|
+
args[1].location,
|
|
3855
|
+
`Function '${name}' expects a numeric second argument`
|
|
3856
|
+
);
|
|
3857
|
+
}
|
|
3858
|
+
break;
|
|
3859
|
+
case "and":
|
|
3860
|
+
case "or":
|
|
3861
|
+
for (const [index, arg] of args.entries()) {
|
|
3862
|
+
this.requireAssignable(
|
|
3863
|
+
argTypes[index],
|
|
3864
|
+
simpleTypeNode("boolean", arg.location),
|
|
3865
|
+
arg.location,
|
|
3866
|
+
`Function '${name}' expects boolean arguments`
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3869
|
+
break;
|
|
3870
|
+
case "not":
|
|
3871
|
+
if (args.length === 1) {
|
|
3872
|
+
this.requireAssignable(
|
|
3873
|
+
argTypes[0],
|
|
3874
|
+
simpleTypeNode("boolean", args[0].location),
|
|
3875
|
+
args[0].location,
|
|
3876
|
+
"Function 'not' expects a boolean argument"
|
|
3877
|
+
);
|
|
3878
|
+
}
|
|
3879
|
+
break;
|
|
3880
|
+
case "neg":
|
|
3881
|
+
case "abs":
|
|
3882
|
+
case "floor":
|
|
3883
|
+
case "ceil":
|
|
3884
|
+
case "round":
|
|
3885
|
+
case "sqrt":
|
|
3886
|
+
if (args.length === 1) {
|
|
3887
|
+
this.requireAssignable(
|
|
3888
|
+
argTypes[0],
|
|
3889
|
+
simpleTypeNode("number", args[0].location),
|
|
3890
|
+
args[0].location,
|
|
3891
|
+
`Function '${name}' expects a numeric argument`
|
|
3892
|
+
);
|
|
3893
|
+
}
|
|
3894
|
+
break;
|
|
3895
|
+
case "trim":
|
|
3896
|
+
case "lower":
|
|
3897
|
+
case "upper":
|
|
3898
|
+
case "strlen":
|
|
3899
|
+
if (args.length === 1) {
|
|
3900
|
+
this.requireAssignable(
|
|
3901
|
+
argTypes[0],
|
|
3902
|
+
simpleTypeNode("string", args[0].location),
|
|
3903
|
+
args[0].location,
|
|
3904
|
+
`Function '${name}' expects a string argument`
|
|
3905
|
+
);
|
|
3906
|
+
}
|
|
3907
|
+
break;
|
|
3908
|
+
case "startsWith":
|
|
3909
|
+
case "endsWith":
|
|
3910
|
+
case "strIncludes":
|
|
3911
|
+
case "indexOf":
|
|
3912
|
+
case "split":
|
|
3913
|
+
if (args.length === 2) {
|
|
3914
|
+
this.requireAssignable(
|
|
3915
|
+
argTypes[0],
|
|
3916
|
+
simpleTypeNode("string", args[0].location),
|
|
3917
|
+
args[0].location,
|
|
3918
|
+
`Function '${name}' expects a string first argument`
|
|
3919
|
+
);
|
|
3920
|
+
this.requireAssignable(
|
|
3921
|
+
argTypes[1],
|
|
3922
|
+
simpleTypeNode("string", args[1].location),
|
|
3923
|
+
args[1].location,
|
|
3924
|
+
`Function '${name}' expects a string second argument`
|
|
3925
|
+
);
|
|
3926
|
+
}
|
|
3927
|
+
break;
|
|
3928
|
+
case "replace":
|
|
3929
|
+
if (args.length >= 2) {
|
|
3930
|
+
this.requireAssignable(
|
|
3931
|
+
argTypes[0],
|
|
3932
|
+
simpleTypeNode("string", args[0].location),
|
|
3933
|
+
args[0].location,
|
|
3934
|
+
"Function 'replace' expects a string first argument"
|
|
3935
|
+
);
|
|
3936
|
+
this.requireAssignable(
|
|
3937
|
+
argTypes[1],
|
|
3938
|
+
simpleTypeNode("string", args[1].location),
|
|
3939
|
+
args[1].location,
|
|
3940
|
+
"Function 'replace' expects a string second argument"
|
|
3941
|
+
);
|
|
3942
|
+
}
|
|
3943
|
+
if (args.length === 3) {
|
|
3944
|
+
this.requireAssignable(
|
|
3945
|
+
argTypes[2],
|
|
3946
|
+
simpleTypeNode("string", args[2].location),
|
|
3947
|
+
args[2].location,
|
|
3948
|
+
"Function 'replace' expects a string replacement argument"
|
|
3949
|
+
);
|
|
3950
|
+
}
|
|
3951
|
+
break;
|
|
3952
|
+
case "substring":
|
|
3953
|
+
case "substr":
|
|
3954
|
+
if (args.length >= 2) {
|
|
3955
|
+
this.requireAssignable(
|
|
3956
|
+
argTypes[0],
|
|
3957
|
+
simpleTypeNode("string", args[0].location),
|
|
3958
|
+
args[0].location,
|
|
3959
|
+
`Function '${name}' expects a string first argument`
|
|
3960
|
+
);
|
|
3961
|
+
this.requireAssignable(
|
|
3962
|
+
argTypes[1],
|
|
3963
|
+
simpleTypeNode("number", args[1].location),
|
|
3964
|
+
args[1].location,
|
|
3965
|
+
`Function '${name}' expects a numeric second argument`
|
|
3966
|
+
);
|
|
3967
|
+
}
|
|
3968
|
+
if (args.length === 3) {
|
|
3969
|
+
this.requireAssignable(
|
|
3970
|
+
argTypes[2],
|
|
3971
|
+
simpleTypeNode("number", args[2].location),
|
|
3972
|
+
args[2].location,
|
|
3973
|
+
`Function '${name}' expects a numeric third argument`
|
|
3974
|
+
);
|
|
3975
|
+
}
|
|
3976
|
+
break;
|
|
3977
|
+
case "len":
|
|
3978
|
+
if (args.length === 1) {
|
|
3979
|
+
this.requireLenCompatible(argTypes[0], args[0].location);
|
|
3980
|
+
}
|
|
3981
|
+
break;
|
|
3982
|
+
case "filter":
|
|
3983
|
+
case "find":
|
|
3984
|
+
case "every":
|
|
3985
|
+
case "some":
|
|
3986
|
+
if (args.length === 2) {
|
|
3987
|
+
this.requireArrayCompatible(argTypes[0], args[0].location, name);
|
|
3988
|
+
this.requireAssignable(
|
|
3989
|
+
argTypes[1],
|
|
3990
|
+
simpleTypeNode("boolean", args[1].location),
|
|
3991
|
+
args[1].location,
|
|
3992
|
+
`Function '${name}' requires a boolean-valued callback`
|
|
3993
|
+
);
|
|
3994
|
+
}
|
|
3995
|
+
break;
|
|
3996
|
+
case "map":
|
|
3997
|
+
if (args.length === 2) {
|
|
3998
|
+
this.requireArrayCompatible(argTypes[0], args[0].location, name);
|
|
3999
|
+
}
|
|
4000
|
+
break;
|
|
4001
|
+
case "coalesce":
|
|
4002
|
+
this.validateCoalesceTypes(argTypes, location);
|
|
4003
|
+
break;
|
|
4004
|
+
case "if":
|
|
4005
|
+
case "cond":
|
|
4006
|
+
if (args.length === 3) {
|
|
4007
|
+
this.requireAssignable(
|
|
4008
|
+
argTypes[0],
|
|
4009
|
+
simpleTypeNode("boolean", args[0].location),
|
|
4010
|
+
args[0].location,
|
|
4011
|
+
`Function '${name}' expects a boolean condition`
|
|
4012
|
+
);
|
|
4013
|
+
}
|
|
4014
|
+
break;
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
validatePrimitiveEquality(leftExpr, rightExpr, leftType, rightType, location) {
|
|
4018
|
+
if (!this.symbols) {
|
|
4019
|
+
return;
|
|
4020
|
+
}
|
|
4021
|
+
if (leftExpr.kind === "objectLiteral" || leftExpr.kind === "arrayLiteral" || rightExpr.kind === "objectLiteral" || rightExpr.kind === "arrayLiteral") {
|
|
4022
|
+
this.error(
|
|
4023
|
+
"eq/neq operands must be compatible primitive types, not object or array literals",
|
|
4024
|
+
location,
|
|
4025
|
+
"E_TYPE_MISMATCH"
|
|
4026
|
+
);
|
|
4027
|
+
return;
|
|
4028
|
+
}
|
|
4029
|
+
const compatible = areComparableTypesCompatible(leftType, rightType, this.symbols);
|
|
4030
|
+
if (compatible === false) {
|
|
4031
|
+
this.error(
|
|
4032
|
+
`eq/neq operands must be compatible primitive types, got ${describeTypeExpr(leftType, this.symbols)} and ${describeTypeExpr(rightType, this.symbols)}`,
|
|
4033
|
+
location,
|
|
4034
|
+
"E_TYPE_MISMATCH"
|
|
4035
|
+
);
|
|
3367
4036
|
}
|
|
3368
4037
|
}
|
|
3369
|
-
|
|
4038
|
+
inferType(expr, env) {
|
|
3370
4039
|
if (!this.symbols) {
|
|
4040
|
+
return null;
|
|
4041
|
+
}
|
|
4042
|
+
return inferExprType(expr, env, this.symbols);
|
|
4043
|
+
}
|
|
4044
|
+
requireAssignable(actualType, expectedType, location, message) {
|
|
4045
|
+
if (!this.symbols || !actualType) {
|
|
3371
4046
|
return;
|
|
3372
4047
|
}
|
|
3373
|
-
const
|
|
3374
|
-
|
|
3375
|
-
this.ctx.currentActionParamTypes,
|
|
3376
|
-
this.symbols
|
|
3377
|
-
);
|
|
3378
|
-
const rightClass = classifyComparableExpr(
|
|
3379
|
-
right,
|
|
3380
|
-
this.ctx.currentActionParamTypes,
|
|
3381
|
-
this.symbols
|
|
3382
|
-
);
|
|
3383
|
-
if (leftClass === "nonprimitive" || rightClass === "nonprimitive") {
|
|
4048
|
+
const assignable = isAssignableType(actualType, expectedType, this.symbols);
|
|
4049
|
+
if (assignable === false) {
|
|
3384
4050
|
this.error(
|
|
3385
|
-
|
|
4051
|
+
`${message}, got ${describeTypeExpr(actualType, this.symbols)}`,
|
|
3386
4052
|
location,
|
|
3387
4053
|
"E_TYPE_MISMATCH"
|
|
3388
4054
|
);
|
|
3389
4055
|
}
|
|
3390
4056
|
}
|
|
4057
|
+
requireArrayCompatible(actualType, location, fnName) {
|
|
4058
|
+
if (!this.symbols || !actualType) {
|
|
4059
|
+
return;
|
|
4060
|
+
}
|
|
4061
|
+
const outcome = classifyArrayOperand(actualType, this.symbols);
|
|
4062
|
+
if (outcome === false) {
|
|
4063
|
+
this.error(
|
|
4064
|
+
`Function '${fnName}' expects an array first argument, got ${describeTypeExpr(actualType, this.symbols)}`,
|
|
4065
|
+
location,
|
|
4066
|
+
"E_TYPE_MISMATCH"
|
|
4067
|
+
);
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
requireLenCompatible(actualType, location) {
|
|
4071
|
+
if (!this.symbols || !actualType) {
|
|
4072
|
+
return;
|
|
4073
|
+
}
|
|
4074
|
+
const outcome = classifyLenOperand(actualType, this.symbols);
|
|
4075
|
+
if (outcome === false) {
|
|
4076
|
+
this.error(
|
|
4077
|
+
`Function 'len' expects a string, array, object, or record argument, got ${describeTypeExpr(actualType, this.symbols)}`,
|
|
4078
|
+
location,
|
|
4079
|
+
"E_TYPE_MISMATCH"
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
validateCoalesceTypes(types, location) {
|
|
4084
|
+
if (!this.symbols) {
|
|
4085
|
+
return;
|
|
4086
|
+
}
|
|
4087
|
+
const concreteTypes = types.map((typeExpr) => stripNullType(typeExpr, this.symbols)).filter((typeExpr) => typeExpr !== null);
|
|
4088
|
+
for (let i = 0; i < concreteTypes.length; i += 1) {
|
|
4089
|
+
for (let j = i + 1; j < concreteTypes.length; j += 1) {
|
|
4090
|
+
const compatible = areTypesCompatible(concreteTypes[i], concreteTypes[j], this.symbols);
|
|
4091
|
+
if (compatible === false) {
|
|
4092
|
+
this.error(
|
|
4093
|
+
`coalesce arguments must have compatible non-null types, got ${describeTypeExpr(concreteTypes[i], this.symbols)} and ${describeTypeExpr(concreteTypes[j], this.symbols)}`,
|
|
4094
|
+
location,
|
|
4095
|
+
"E_TYPE_MISMATCH"
|
|
4096
|
+
);
|
|
4097
|
+
return;
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
3391
4102
|
error(message, location, code) {
|
|
3392
4103
|
this.ctx.diagnostics.push({
|
|
3393
4104
|
severity: "error",
|
|
@@ -4635,7 +5346,7 @@ function typeExprToFieldSpec(typeExpr, ctx, seenTypeRefs = []) {
|
|
|
4635
5346
|
pushSchemaTypeError(
|
|
4636
5347
|
ctx,
|
|
4637
5348
|
"E045",
|
|
4638
|
-
`Nullable type '${
|
|
5349
|
+
`Nullable type '${describeTypeExpr2(typeExpr)}' cannot be lowered to FieldSpec`,
|
|
4639
5350
|
typeExpr.location
|
|
4640
5351
|
);
|
|
4641
5352
|
return null;
|
|
@@ -4643,7 +5354,7 @@ function typeExprToFieldSpec(typeExpr, ctx, seenTypeRefs = []) {
|
|
|
4643
5354
|
pushSchemaTypeError(
|
|
4644
5355
|
ctx,
|
|
4645
5356
|
"E043",
|
|
4646
|
-
`Union type '${
|
|
5357
|
+
`Union type '${describeTypeExpr2(typeExpr)}' cannot be soundly lowered to FieldSpec`,
|
|
4647
5358
|
typeExpr.location
|
|
4648
5359
|
);
|
|
4649
5360
|
return null;
|
|
@@ -4663,7 +5374,7 @@ function typeExprToFieldSpec(typeExpr, ctx, seenTypeRefs = []) {
|
|
|
4663
5374
|
pushSchemaTypeError(
|
|
4664
5375
|
ctx,
|
|
4665
5376
|
"E046",
|
|
4666
|
-
`Record type '${
|
|
5377
|
+
`Record type '${describeTypeExpr2(typeExpr)}' cannot be lowered to FieldSpec`,
|
|
4667
5378
|
typeExpr.location
|
|
4668
5379
|
);
|
|
4669
5380
|
return null;
|
|
@@ -4700,20 +5411,20 @@ function pushSchemaTypeError(ctx, code, message, location) {
|
|
|
4700
5411
|
location
|
|
4701
5412
|
});
|
|
4702
5413
|
}
|
|
4703
|
-
function
|
|
5414
|
+
function describeTypeExpr2(typeExpr) {
|
|
4704
5415
|
switch (typeExpr.kind) {
|
|
4705
5416
|
case "simpleType":
|
|
4706
5417
|
return typeExpr.name;
|
|
4707
5418
|
case "unionType":
|
|
4708
|
-
return typeExpr.types.map((member) =>
|
|
5419
|
+
return typeExpr.types.map((member) => describeTypeExpr2(member)).join(" | ");
|
|
4709
5420
|
case "arrayType":
|
|
4710
|
-
return `Array<${
|
|
5421
|
+
return `Array<${describeTypeExpr2(typeExpr.elementType)}>`;
|
|
4711
5422
|
case "recordType":
|
|
4712
|
-
return `Record<${
|
|
5423
|
+
return `Record<${describeTypeExpr2(typeExpr.keyType)}, ${describeTypeExpr2(typeExpr.valueType)}>`;
|
|
4713
5424
|
case "literalType":
|
|
4714
5425
|
return JSON.stringify(typeExpr.value);
|
|
4715
5426
|
case "objectType":
|
|
4716
|
-
return `{ ${typeExpr.fields.map((field) => `${field.name}${field.optional ? "?" : ""}: ${
|
|
5427
|
+
return `{ ${typeExpr.fields.map((field) => `${field.name}${field.optional ? "?" : ""}: ${describeTypeExpr2(field.typeExpr)}`).join("; ")} }`;
|
|
4717
5428
|
}
|
|
4718
5429
|
}
|
|
4719
5430
|
function validateLiteralAgainstSpec(value, spec, fieldName, location, ctx) {
|
|
@@ -6917,4 +7628,4 @@ export {
|
|
|
6917
7628
|
compileMelDomain,
|
|
6918
7629
|
compileMelPatch
|
|
6919
7630
|
};
|
|
6920
|
-
//# sourceMappingURL=chunk-
|
|
7631
|
+
//# sourceMappingURL=chunk-4JJQCFJH.js.map
|