@nudojs/core 1.14.1 → 1.15.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.
- package/dist/{chunk-4GZPH6YL.js → chunk-47UPDZHE.js} +75 -74
- package/dist/{chunk-JMOQEJTD.js → chunk-NUTYUT3I.js} +235 -33
- package/dist/exec.js +1 -1
- package/dist/index.js +42 -39
- package/dist/internal.d.ts +81 -1
- package/dist/internal.js +4 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
takeInterfaceDiagsSince,
|
|
75
75
|
takeRefineDiags,
|
|
76
76
|
takeRefineDiagsSince
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-47UPDZHE.js";
|
|
78
78
|
import {
|
|
79
79
|
$add,
|
|
80
80
|
$arguments,
|
|
@@ -190,6 +190,7 @@ import {
|
|
|
190
190
|
CONSTRAINT_BUILDER_NAMES,
|
|
191
191
|
CONSTRAINT_EXPR_RE,
|
|
192
192
|
DEFAULT_MAX_LOOP_ITERS,
|
|
193
|
+
DIAG,
|
|
193
194
|
FORK_TRUNCATION_LABEL,
|
|
194
195
|
HOST_EFFECT_LABEL_PREFIX,
|
|
195
196
|
LOOP_TRUNCATION_LABEL,
|
|
@@ -535,7 +536,7 @@ import {
|
|
|
535
536
|
withExecPhi,
|
|
536
537
|
withInvariantSpecs,
|
|
537
538
|
withVar
|
|
538
|
-
} from "./chunk-
|
|
539
|
+
} from "./chunk-NUTYUT3I.js";
|
|
539
540
|
|
|
540
541
|
// src/environment.ts
|
|
541
542
|
function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
|
|
@@ -657,7 +658,7 @@ function checkArg(arg, expect, phi = pTrue) {
|
|
|
657
658
|
if (arg.shape.k === "unknown" && !arg.term) {
|
|
658
659
|
return {
|
|
659
660
|
severity: "warning",
|
|
660
|
-
code:
|
|
661
|
+
code: DIAG.argOpaque,
|
|
661
662
|
message: `argument type is unknown; cannot verify constraint ${predToString(expect)}`,
|
|
662
663
|
suggestion: "add a call site or @nudo:case, or provide preconditions via --assume"
|
|
663
664
|
};
|
|
@@ -671,7 +672,7 @@ function checkArg(arg, expect, phi = pTrue) {
|
|
|
671
672
|
if (ok === false) {
|
|
672
673
|
return {
|
|
673
674
|
severity: "error",
|
|
674
|
-
code:
|
|
675
|
+
code: DIAG.constraintViolated,
|
|
675
676
|
message: `argument ${JSON.stringify(lvR.value)} does not satisfy ${predToString(expect)}`,
|
|
676
677
|
suggestion: `use a value satisfying the constraint, or relax the function precondition`
|
|
677
678
|
};
|
|
@@ -679,7 +680,7 @@ function checkArg(arg, expect, phi = pTrue) {
|
|
|
679
680
|
}
|
|
680
681
|
return {
|
|
681
682
|
severity: "warning",
|
|
682
|
-
code:
|
|
683
|
+
code: DIAG.constraintUnproven,
|
|
683
684
|
message: `cannot prove the argument satisfies ${predToString(expect)}`,
|
|
684
685
|
suggestion: `not enough information; use --assume or add a case`
|
|
685
686
|
};
|
|
@@ -708,7 +709,7 @@ function checkCall(source, fnName, args, phi = pTrue) {
|
|
|
708
709
|
if (!g) {
|
|
709
710
|
diags.push({
|
|
710
711
|
severity: "error",
|
|
711
|
-
code:
|
|
712
|
+
code: DIAG.fnNotFound,
|
|
712
713
|
message: `function ${fnName} not found`
|
|
713
714
|
});
|
|
714
715
|
return diags;
|
|
@@ -716,7 +717,7 @@ function checkCall(source, fnName, args, phi = pTrue) {
|
|
|
716
717
|
if (args.length !== g.params.length) {
|
|
717
718
|
diags.push({
|
|
718
719
|
severity: "error",
|
|
719
|
-
code:
|
|
720
|
+
code: DIAG.argCount,
|
|
720
721
|
message: `${fnName} expects ${g.params.length} argument(s), got ${args.length}`,
|
|
721
722
|
fn: fnName
|
|
722
723
|
});
|
|
@@ -731,7 +732,7 @@ function checkCall(source, fnName, args, phi = pTrue) {
|
|
|
731
732
|
if (g.symbolic.conf === "partial" || g.symbolic.conf === "opaque") {
|
|
732
733
|
diags.push({
|
|
733
734
|
severity: "info",
|
|
734
|
-
code:
|
|
735
|
+
code: DIAG.partialResult,
|
|
735
736
|
message: `${fnName}(...) result confidence ${g.symbolic.conf}`,
|
|
736
737
|
suggestion: "add a call site or constraint to improve precision",
|
|
737
738
|
fn: fnName
|
|
@@ -1499,7 +1500,7 @@ function interfaceDriftIssues(candidates, callRecords, evalResult) {
|
|
|
1499
1500
|
if (leqAbs(today2, expected2).ok && leqAbs(expected2, today2).ok) continue;
|
|
1500
1501
|
out.push({
|
|
1501
1502
|
severity: "warning",
|
|
1502
|
-
code:
|
|
1503
|
+
code: DIAG.interfaceDrift,
|
|
1503
1504
|
message: `${cand.fnName}[${param}]: persisted @generated segment \u2260 today's call-site domain`,
|
|
1504
1505
|
actual: formatAbs(today2),
|
|
1505
1506
|
expected: formatConstraint(constraint),
|
|
@@ -1524,7 +1525,7 @@ function interfaceDriftIssues(candidates, callRecords, evalResult) {
|
|
|
1524
1525
|
if (leqAbs(today, expected).ok && leqAbs(expected, today).ok) continue;
|
|
1525
1526
|
out.push({
|
|
1526
1527
|
severity: "warning",
|
|
1527
|
-
code:
|
|
1528
|
+
code: DIAG.interfaceDrift,
|
|
1528
1529
|
message: `${cand.fnName}[return]: persisted @generated segment \u2260 today's inferred return`,
|
|
1529
1530
|
actual: formatAbs(today),
|
|
1530
1531
|
expected: formatConstraint(retC),
|
|
@@ -1725,7 +1726,9 @@ function moduleMapId(m) {
|
|
|
1725
1726
|
function checkMemoKey(filePath, source, identityOpts, deps, sidecarFp) {
|
|
1726
1727
|
return [
|
|
1727
1728
|
hashSource(source),
|
|
1728
|
-
filePath
|
|
1729
|
+
// filePath 过 stablePathKey 归一(与依赖索引/逐出同口径):同一文件的
|
|
1730
|
+
// 裸路径与 file:// URL 两种形态不得各占一条 memo 条目(命中率损耗)。
|
|
1731
|
+
stablePathKey(filePath),
|
|
1729
1732
|
`${loadModuleId(identityOpts.loadModule)}:${identityOpts.fromFile ?? ""}`,
|
|
1730
1733
|
deps.fp,
|
|
1731
1734
|
sidecarFp ?? "-",
|
|
@@ -1943,7 +1946,7 @@ function structuralAssignIssues(records) {
|
|
|
1943
1946
|
if (!leq.ok) {
|
|
1944
1947
|
out.push({
|
|
1945
1948
|
severity: "error",
|
|
1946
|
-
code:
|
|
1949
|
+
code: DIAG.assignMismatch,
|
|
1947
1950
|
message: `${r.name}: assignment \u22AD existing shape`,
|
|
1948
1951
|
actual: formatAbs(r.next),
|
|
1949
1952
|
expected: formatAbs(r.prev),
|
|
@@ -2086,7 +2089,7 @@ function scanCaseInconsistency(source, knownFns, opts) {
|
|
|
2086
2089
|
const field = fieldPath.join(".");
|
|
2087
2090
|
out.push({
|
|
2088
2091
|
severity: "error",
|
|
2089
|
-
code:
|
|
2092
|
+
code: DIAG.caseInconsistency,
|
|
2090
2093
|
message: `${fnName} case "${caseName}": witness \u22AD contract`,
|
|
2091
2094
|
actual: formatAbs(arg),
|
|
2092
2095
|
expected: `missing field ${field}`,
|
|
@@ -2110,7 +2113,7 @@ function scanCaseInconsistency(source, knownFns, opts) {
|
|
|
2110
2113
|
const paramName = entry.param || paramNames[idx] || `arg${idx}`;
|
|
2111
2114
|
out.push({
|
|
2112
2115
|
severity: "error",
|
|
2113
|
-
code:
|
|
2116
|
+
code: DIAG.caseInconsistency,
|
|
2114
2117
|
message: `${fnName} case "${caseName}": witness \u22AD contract`,
|
|
2115
2118
|
actual: formatAbs(arg),
|
|
2116
2119
|
expected: formatConstraint(entry.constraint),
|
|
@@ -2126,7 +2129,7 @@ function scanCaseInconsistency(source, knownFns, opts) {
|
|
|
2126
2129
|
const paramName = entry.param || paramNames[idx] || `arg${idx}`;
|
|
2127
2130
|
out.push({
|
|
2128
2131
|
severity: "error",
|
|
2129
|
-
code:
|
|
2132
|
+
code: DIAG.caseInconsistency,
|
|
2130
2133
|
message: `${fnName} case "${caseName}": witness \u22AD contract`,
|
|
2131
2134
|
actual: formatAbs(arg),
|
|
2132
2135
|
expected: formatConstraint(entry.constraint),
|
|
@@ -2148,7 +2151,7 @@ function scanCaseInconsistency(source, knownFns, opts) {
|
|
|
2148
2151
|
const paramName = entry.param || paramNames[idx] || `arg${idx}`;
|
|
2149
2152
|
out.push({
|
|
2150
2153
|
severity: "error",
|
|
2151
|
-
code:
|
|
2154
|
+
code: DIAG.caseInconsistency,
|
|
2152
2155
|
message: `${fnName} case "${caseName}": witness \u22AD contract`,
|
|
2153
2156
|
actual: formatAbs(arg),
|
|
2154
2157
|
expected: predToString(p),
|
|
@@ -2375,7 +2378,7 @@ function sidecarDiagIssues(diags) {
|
|
|
2375
2378
|
const k = `${d.code}\0${d.message}`;
|
|
2376
2379
|
if (seen.has(k)) continue;
|
|
2377
2380
|
seen.add(k);
|
|
2378
|
-
const severity = d.code ===
|
|
2381
|
+
const severity = d.code === DIAG.contractSyntax || d.code === DIAG.directiveSyntax ? "warning" : "error";
|
|
2379
2382
|
out.push({ severity, code: d.code, message: d.message });
|
|
2380
2383
|
}
|
|
2381
2384
|
return out;
|
|
@@ -2397,7 +2400,7 @@ function assumePremisesPhiOf(name, source, file, issues) {
|
|
|
2397
2400
|
if (seg.kind === "bad") {
|
|
2398
2401
|
issues.push({
|
|
2399
2402
|
severity: "error",
|
|
2400
|
-
code:
|
|
2403
|
+
code: DIAG.assumeInvalid,
|
|
2401
2404
|
message: `${name}: malformed @nudo:assume '${seg.raw}' (expected <param> <= <param> or <param> >= <param>; constant bounds belong to sidecar contracts)`,
|
|
2402
2405
|
actual: seg.raw,
|
|
2403
2406
|
expected: "<param> <= <param>",
|
|
@@ -2410,7 +2413,7 @@ function assumePremisesPhiOf(name, source, file, issues) {
|
|
|
2410
2413
|
if (bad.length > 0) {
|
|
2411
2414
|
issues.push({
|
|
2412
2415
|
severity: "error",
|
|
2413
|
-
code:
|
|
2416
|
+
code: DIAG.assumeInvalid,
|
|
2414
2417
|
message: `${name}: @nudo:assume name(s) not bound as parameters or top-level locals (${bad.join(", ")})`,
|
|
2415
2418
|
actual: bad.join(", "),
|
|
2416
2419
|
expected: surface || "(no params/locals)",
|
|
@@ -2441,7 +2444,7 @@ function invariantSpecsOf(name, source, file, issues) {
|
|
|
2441
2444
|
if (seg.kind === "bad") {
|
|
2442
2445
|
issues.push({
|
|
2443
2446
|
severity: "warning",
|
|
2444
|
-
code:
|
|
2447
|
+
code: DIAG.invariantInvalid,
|
|
2445
2448
|
message: `${name}: malformed @nudo:invariant '${seg.raw}' (expected <name><path> <rel> <number>; path = [*] or .member steps)`,
|
|
2446
2449
|
actual: seg.raw,
|
|
2447
2450
|
expected: "<name><path> <rel> <number>",
|
|
@@ -2453,7 +2456,7 @@ function invariantSpecsOf(name, source, file, issues) {
|
|
|
2453
2456
|
if (!bindable.has(seg.name)) {
|
|
2454
2457
|
issues.push({
|
|
2455
2458
|
severity: "warning",
|
|
2456
|
-
code:
|
|
2459
|
+
code: DIAG.invariantInvalid,
|
|
2457
2460
|
message: `${name}: @nudo:invariant name not bound as a parameter or top-level local (${seg.name})`,
|
|
2458
2461
|
actual: seg.name,
|
|
2459
2462
|
expected: surface || "(no params/locals)",
|
|
@@ -2592,7 +2595,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2592
2595
|
const loc = findFnLoc(file, name);
|
|
2593
2596
|
issues.push({
|
|
2594
2597
|
severity: entryThrowsMode === "warning" ? "warning" : "error",
|
|
2595
|
-
code:
|
|
2598
|
+
code: DIAG.entryMayThrow,
|
|
2596
2599
|
message: `${name} (export): may throw ${gateDisplay}`,
|
|
2597
2600
|
actual: `${name}(\u2026) throws ${gateDisplay}`,
|
|
2598
2601
|
expected: "entry total, or @nudo:throws / try-catch",
|
|
@@ -2617,7 +2620,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2617
2620
|
}
|
|
2618
2621
|
issues.push({
|
|
2619
2622
|
severity: "warning",
|
|
2620
|
-
code:
|
|
2623
|
+
code: DIAG.noSignature,
|
|
2621
2624
|
message: `${name}: could not generalize a symbolic Abs`,
|
|
2622
2625
|
suggestion: "add @nudo:case or make the body algebraically evaluable",
|
|
2623
2626
|
fn: name
|
|
@@ -2637,7 +2640,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2637
2640
|
const loc = findFnLoc(file, name);
|
|
2638
2641
|
issues.push({
|
|
2639
2642
|
severity: entryThrowsMode === "warning" ? "warning" : "error",
|
|
2640
|
-
code:
|
|
2643
|
+
code: DIAG.entryMayThrow,
|
|
2641
2644
|
message: `${name} (export): may throw ${gateDisplay}`,
|
|
2642
2645
|
actual: `${formatEntrySigLine(name, g, gateDisplay)}`,
|
|
2643
2646
|
expected: "entry total, or @nudo:throws / try-catch",
|
|
@@ -2681,7 +2684,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2681
2684
|
const where = symbolicTrueUnknown ? `${name} => unknown` : `${name} param ${g.params[unknownParamIdx] ?? `#${unknownParamIdx}`}: unknown`;
|
|
2682
2685
|
issues.push({
|
|
2683
2686
|
severity: "warning",
|
|
2684
|
-
code:
|
|
2687
|
+
code: DIAG.unknownInference,
|
|
2685
2688
|
message: `${name}: signature has true unknown (inference failed)`,
|
|
2686
2689
|
actual: where,
|
|
2687
2690
|
expected: "computable Abs (any = unconstrained, unknown = engine debt)",
|
|
@@ -2702,7 +2705,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2702
2705
|
const surface = [...contractNames].filter((n) => !n.startsWith("_p") && n !== "_").join(", ");
|
|
2703
2706
|
issues.push({
|
|
2704
2707
|
severity: "error",
|
|
2705
|
-
code:
|
|
2708
|
+
code: DIAG.interfaceParamMismatch,
|
|
2706
2709
|
message: `${name}: contract parameter name(s) not in the formal parameter list (${unknownParams.join(", ")})`,
|
|
2707
2710
|
actual: unknownParams.join(", "),
|
|
2708
2711
|
expected: surface || g.params.join(", ") || "(no params)",
|
|
@@ -2715,7 +2718,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2715
2718
|
if (eff.conflict.params.length > 0) {
|
|
2716
2719
|
issues.push({
|
|
2717
2720
|
severity: "error",
|
|
2718
|
-
code:
|
|
2721
|
+
code: DIAG.interfaceConflict,
|
|
2719
2722
|
message: `${name}: handwritten contract conjunction unsatisfiable (${eff.conflict.params.join(", ")})`,
|
|
2720
2723
|
suggestion: "check whether the source @nudo:contract and the same-name sidecar binding have contradictory constant bounds",
|
|
2721
2724
|
fn: name
|
|
@@ -2724,7 +2727,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2724
2727
|
if (eff.conflict.returns) {
|
|
2725
2728
|
issues.push({
|
|
2726
2729
|
severity: "error",
|
|
2727
|
-
code:
|
|
2730
|
+
code: DIAG.interfaceConflict,
|
|
2728
2731
|
message: `${name}: handwritten contract conjunction unsatisfiable on the return slot`,
|
|
2729
2732
|
suggestion: "check whether the source @nudo:contract return and the sidecar fn() return constraint are contradictory (the return slot is not enforced when they are)",
|
|
2730
2733
|
fn: name
|
|
@@ -2760,7 +2763,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2760
2763
|
if (g.symbolic.conf === "opaque" && !truncated.has(name)) {
|
|
2761
2764
|
issues.push({
|
|
2762
2765
|
severity: "info",
|
|
2763
|
-
code:
|
|
2766
|
+
code: DIAG.opaqueResult,
|
|
2764
2767
|
message: `${name}(...): conf=opaque (path not covered, or native)`,
|
|
2765
2768
|
suggestion: opaqueEnvHint ? OPAQUE_ENV_HINT : OPAQUE_EVIDENCE_HINT,
|
|
2766
2769
|
fn: name
|
|
@@ -2771,7 +2774,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2771
2774
|
if (label === FORK_TRUNCATION_LABEL) {
|
|
2772
2775
|
issues.push({
|
|
2773
2776
|
severity: "info",
|
|
2774
|
-
code:
|
|
2777
|
+
code: DIAG.forkTruncated,
|
|
2775
2778
|
message: `Branch expansion was truncated (fork budget); affected results widened to unknown#opaque (budget)`,
|
|
2776
2779
|
suggestion: "optional: raise nudo.analysis.maxForks, or @nudo:budget forks=\u2026 on the function \u2014 non-blocking"
|
|
2777
2780
|
});
|
|
@@ -2780,7 +2783,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2780
2783
|
if (label === PROMISE_MICRO_OVERFLOW_LABEL) {
|
|
2781
2784
|
issues.push({
|
|
2782
2785
|
severity: "info",
|
|
2783
|
-
code:
|
|
2786
|
+
code: DIAG.promiseMicroTruncated,
|
|
2784
2787
|
message: `Promise microtask queue hit its hard cap; further then/catch callbacks were dropped (results stay fail-closed)`,
|
|
2785
2788
|
suggestion: "optional: reduce top-level Promise.then fan-out \u2014 non-blocking"
|
|
2786
2789
|
});
|
|
@@ -2789,7 +2792,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2789
2792
|
if (label === PROMISE_MICRO_ERROR_LABEL) {
|
|
2790
2793
|
issues.push({
|
|
2791
2794
|
severity: "info",
|
|
2792
|
-
code:
|
|
2795
|
+
code: DIAG.promiseMicroError,
|
|
2793
2796
|
message: `A promise microtask threw while draining; the error was recorded and did not rewrite the synchronous return value`,
|
|
2794
2797
|
suggestion: "optional: inspect the then/catch callback for a throw path \u2014 non-blocking"
|
|
2795
2798
|
});
|
|
@@ -2798,7 +2801,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2798
2801
|
if (label === MATH_FOLD_ERROR_LABEL) {
|
|
2799
2802
|
issues.push({
|
|
2800
2803
|
severity: "info",
|
|
2801
|
-
code:
|
|
2804
|
+
code: DIAG.mathFoldError,
|
|
2802
2805
|
message: `A Math native fold threw during analysis (host-tampered or divergent Math.*); the result was widened to number`,
|
|
2803
2806
|
suggestion: "optional: keep Math.* builtins unmodified in analyzed code, or mock them with @nudo:mock \u2014 non-blocking"
|
|
2804
2807
|
});
|
|
@@ -2808,7 +2811,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2808
2811
|
const hostName = label.slice(HOST_EFFECT_LABEL_PREFIX.length);
|
|
2809
2812
|
issues.push({
|
|
2810
2813
|
severity: "info",
|
|
2811
|
-
code:
|
|
2814
|
+
code: DIAG.hostEffectBlocked,
|
|
2812
2815
|
message: `Host function '${hostName}' is not executed during analysis (network/timer side effect); result widened to unknown#opaque`,
|
|
2813
2816
|
suggestion: "optional: mock it with @nudo:mock / @nudo:env, or pass the value in from a call site",
|
|
2814
2817
|
fn: hostName
|
|
@@ -2818,7 +2821,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2818
2821
|
if (label === LOOP_TRUNCATION_LABEL) {
|
|
2819
2822
|
issues.push({
|
|
2820
2823
|
severity: "info",
|
|
2821
|
-
code:
|
|
2824
|
+
code: DIAG.loopTruncated,
|
|
2822
2825
|
message: `A loop did not terminate within its iteration budget (abstract unroll cap reached and the exit condition stayed concrete-true); affected loop state was widened (bounded, not exact)`,
|
|
2823
2826
|
suggestion: "optional: restructure so the exit condition becomes abstract (data-dependent) within a few iterations, or pin the result with @nudo:case / @nudo:contract \u2014 non-blocking"
|
|
2824
2827
|
});
|
|
@@ -2829,7 +2832,7 @@ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures,
|
|
|
2829
2832
|
const calls = reasons.has("calls");
|
|
2830
2833
|
issues.push({
|
|
2831
2834
|
severity: "info",
|
|
2832
|
-
code:
|
|
2835
|
+
code: DIAG.recursionTruncated,
|
|
2833
2836
|
message: allCycle ? `Recursive evaluation of '${label}' hit a call cycle (same abstract arguments already on the stack); result widened to unknown#opaque (cycle \u2014 budget cannot lift this)` : `Recursive evaluation of '${label}' was truncated (${depth && calls ? "depth/size budget" : depth ? "call-depth budget" : calls ? "total-calls budget" : "depth/size budget"}); result widened to unknown#opaque (budget \u2014 not inference debt)`,
|
|
2834
2837
|
suggestion: allCycle ? "a call cycle is not a budget: make the recursion arguments vary per level, narrow the base case, or declare @nudo:contract \u2014 raising @nudo:budget will not change this" : depth && !calls ? "raise the function budget with @nudo:budget depth=\u2026 (or narrow the recursion base case / declare @nudo:contract return)" : calls && !depth ? "raise the function budget with @nudo:budget calls=\u2026 (or narrow the recursion base case / declare @nudo:contract return)" : "raise the function budget with @nudo:budget calls=\u2026 depth=\u2026 (or narrow the recursion base case / declare @nudo:contract return)",
|
|
2835
2838
|
reason: allCycle ? "cycle" : depth && calls ? "budget" : depth ? "depth" : calls ? "calls" : "budget",
|
|
@@ -2952,7 +2955,7 @@ function checkReturnConstraint(fnName, cName, constraint, ret, assumeDisplay, in
|
|
|
2952
2955
|
if (assumeDisplay && assumeDisplay.length > 0) {
|
|
2953
2956
|
relied.push({
|
|
2954
2957
|
severity: "info",
|
|
2955
|
-
code:
|
|
2958
|
+
code: DIAG.assumeRelied,
|
|
2956
2959
|
message: `${fnName}: return contract proved via @nudo:assume ${assumeDisplay.join("; ")}`,
|
|
2957
2960
|
actual: `proof relies on user lemma${assumeDisplay.length > 1 ? "s" : ""}`,
|
|
2958
2961
|
expected: "engine verifies the obligation, not the lemma itself",
|
|
@@ -2963,7 +2966,7 @@ function checkReturnConstraint(fnName, cName, constraint, ret, assumeDisplay, in
|
|
|
2963
2966
|
if (invariantDisplay && invariantDisplay.length > 0) {
|
|
2964
2967
|
relied.push({
|
|
2965
2968
|
severity: "info",
|
|
2966
|
-
code:
|
|
2969
|
+
code: DIAG.invariantRelied,
|
|
2967
2970
|
message: `${fnName}: return contract proved via @nudo:invariant ${invariantDisplay.join("; ")}`,
|
|
2968
2971
|
actual: `proof relies on user invariant${invariantDisplay.length > 1 ? "s" : ""}`,
|
|
2969
2972
|
expected: "engine verifies the obligation, not the loop invariant itself",
|
|
@@ -2976,7 +2979,7 @@ function checkReturnConstraint(fnName, cName, constraint, ret, assumeDisplay, in
|
|
|
2976
2979
|
const push = (severity, actual, expected, suggestion) => [
|
|
2977
2980
|
{
|
|
2978
2981
|
severity,
|
|
2979
|
-
code: severity === "error" ?
|
|
2982
|
+
code: severity === "error" ? DIAG.constraintViolated : DIAG.unprovenReturn,
|
|
2980
2983
|
message: `${fnName}: return value \u22AD @nudo:contract return ${cName}`,
|
|
2981
2984
|
actual,
|
|
2982
2985
|
expected,
|
package/dist/internal.d.ts
CHANGED
|
@@ -4,6 +4,86 @@ import { A as Abs, T as Term, c as AbsModuleExports, d as AstEnv } from './run-D
|
|
|
4
4
|
export { $ as $tryDigestSoft, e as $tryMarkSoft, f as $tryReleaseSoft, E as ERROR_FAMILY, g as EvalFallbackStats, M as MayThrowEffect, h as absLit, i as absNumLit, j as absStrLit, k as allAbsStr, l as clearPureCallMemo, m as clearPureMemo, n as enterEvalCallBudgetSession, o as errorTypeAbs, p as exitEvalCallBudgetSession, q as filterDeclaredThrows, r as filterGateThrows, s as filterIgnoredThrows, t as flushMayThrowEffects, u as formatThrowsAbs, v as getEvalCallBudgetState, w as getEvalFallbackStats, x as getMayThrowCollector, y as isThrowsIgnored, z as mayThrowEffectsToAbs, B as orphanMayThrowEffects, D as popMayThrowFrame, F as pushMayThrowFrame, G as recordMayThrow, H as resetEvalFallbackStats, I as runWithMayThrowSession, J as setMayThrowCollector, K as throwAbsToKinds, N as throwsKindCovered, O as withEvalBudgetOverride } from './run-DfloWX6i.js';
|
|
5
5
|
import { File, Node } from '@babel/types';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* 诊断码唯一注册表(P3-7):所有 `nudo:*` 诊断码字符串的单一真理源。
|
|
9
|
+
*
|
|
10
|
+
* - 零依赖叶子:core 内部相对 import,跨包(parser/service/lsp/nudojs)
|
|
11
|
+
* 走 `@nudojs/core/internal`——不引环、加载零成本。
|
|
12
|
+
* - 拼写漂移在类型层不可表达:键不存在 → tsc 报错,新增码只能落在本表。
|
|
13
|
+
* - 门禁联动:packages/website/tests/docs-coverage.test.ts 的 emittedCodes()
|
|
14
|
+
* 以「本注册表 ∪ src 残留字面量」双源强制诊断术语表(en+zh)锚点——
|
|
15
|
+
* 注册表里每个码都必须有 `{#nudo-<code>}` 锚点(冒号转连字符)。
|
|
16
|
+
* - 非诊断码的 `nudo:*` 字符串**不进**本表:指令名(`nudo:case` 等)、
|
|
17
|
+
* 控制流/Error 标记(`nudo:throw` / `nudo:return` / `nudo:loop` /
|
|
18
|
+
* `nudo:unsupported`)、Symbol 哨兵(`nudo:not-literal` / `nudo:json-omit` /
|
|
19
|
+
* `nudo:no-lit-key`)。
|
|
20
|
+
*/
|
|
21
|
+
/** 键名 = 码去掉 `nudo:` 前缀后按 `-` 分段转 camelCase。 */
|
|
22
|
+
declare const DIAG: {
|
|
23
|
+
readonly argCount: "nudo:arg-count";
|
|
24
|
+
readonly argOpaque: "nudo:arg-opaque";
|
|
25
|
+
readonly argStructure: "nudo:arg-structure";
|
|
26
|
+
readonly assignMismatch: "nudo:assign-mismatch";
|
|
27
|
+
readonly constraintUnproven: "nudo:constraint-unproven";
|
|
28
|
+
readonly constraintViolated: "nudo:constraint-violated";
|
|
29
|
+
readonly fnNotFound: "nudo:fn-not-found";
|
|
30
|
+
readonly partialResult: "nudo:partial-result";
|
|
31
|
+
readonly unprovenReturn: "nudo:unproven-return";
|
|
32
|
+
readonly assumeInvalid: "nudo:assume-invalid";
|
|
33
|
+
readonly assumeRelied: "nudo:assume-relied";
|
|
34
|
+
readonly contractSyntax: "nudo:contract-syntax";
|
|
35
|
+
readonly directiveSyntax: "nudo:directive-syntax";
|
|
36
|
+
readonly invariantInvalid: "nudo:invariant-invalid";
|
|
37
|
+
readonly invariantRelied: "nudo:invariant-relied";
|
|
38
|
+
readonly mockInvalid: "nudo:mock-invalid";
|
|
39
|
+
readonly caseExpected: "nudo:case-expected";
|
|
40
|
+
readonly caseInconsistency: "nudo:case-inconsistency";
|
|
41
|
+
readonly dualEntry: "nudo:dual-entry";
|
|
42
|
+
readonly entryMayThrow: "nudo:entry-may-throw";
|
|
43
|
+
readonly mayThrow: "nudo:may-throw";
|
|
44
|
+
readonly noSignature: "nudo:no-signature";
|
|
45
|
+
readonly builtinUnknown: "nudo:builtin-unknown";
|
|
46
|
+
readonly forkTruncated: "nudo:fork-truncated";
|
|
47
|
+
readonly hostEffectBlocked: "nudo:host-effect-blocked";
|
|
48
|
+
readonly loopTruncated: "nudo:loop-truncated";
|
|
49
|
+
readonly mathFoldError: "nudo:math-fold-error";
|
|
50
|
+
readonly opaqueResult: "nudo:opaque-result";
|
|
51
|
+
readonly promiseMicroError: "nudo:promise-micro-error";
|
|
52
|
+
readonly promiseMicroTruncated: "nudo:promise-micro-truncated";
|
|
53
|
+
readonly recursionTruncated: "nudo:recursion-truncated";
|
|
54
|
+
readonly unknownInference: "nudo:unknown-inference";
|
|
55
|
+
readonly unknownRecv: "nudo:unknown-recv";
|
|
56
|
+
readonly missingSlot: "nudo:missing-slot";
|
|
57
|
+
readonly noMethod: "nudo:no-method";
|
|
58
|
+
readonly interfaceConflict: "nudo:interface-conflict";
|
|
59
|
+
readonly interfaceCycle: "nudo:interface-cycle";
|
|
60
|
+
readonly interfaceDomainExceeds: "nudo:interface-domain-exceeds";
|
|
61
|
+
readonly interfaceDrift: "nudo:interface-drift";
|
|
62
|
+
readonly interfaceEmitDenied: "nudo:interface-emit-denied";
|
|
63
|
+
readonly interfaceEntryOnly: "nudo:interface-entry-only";
|
|
64
|
+
readonly interfaceLoad: "nudo:interface-load";
|
|
65
|
+
readonly interfaceMultiDeclarator: "nudo:interface-multi-declarator";
|
|
66
|
+
readonly interfaceNameClash: "nudo:interface-name-clash";
|
|
67
|
+
readonly interfaceNotProjectable: "nudo:interface-not-projectable";
|
|
68
|
+
readonly interfaceParamMismatch: "nudo:interface-param-mismatch";
|
|
69
|
+
readonly interfaceUnderivable: "nudo:interface-underivable";
|
|
70
|
+
readonly envHarvestConflict: "nudo:env-harvest-conflict";
|
|
71
|
+
readonly envUnresolved: "nudo:env-unresolved";
|
|
72
|
+
readonly exportsUnresolved: "nudo:exports-unresolved";
|
|
73
|
+
readonly missingExport: "nudo:missing-export";
|
|
74
|
+
readonly moduleCycle: "nudo:module-cycle";
|
|
75
|
+
readonly moduleDepth: "nudo:module-depth";
|
|
76
|
+
readonly moduleMissing: "nudo:module-missing";
|
|
77
|
+
readonly internal: "nudo:internal";
|
|
78
|
+
readonly pathEmptyDir: "nudo:path-empty-dir";
|
|
79
|
+
readonly pathIo: "nudo:path-io";
|
|
80
|
+
readonly pathMissingCallsite: "nudo:path-missing-callsite";
|
|
81
|
+
readonly pathNotFound: "nudo:path-not-found";
|
|
82
|
+
readonly pathNotTarget: "nudo:path-not-target";
|
|
83
|
+
};
|
|
84
|
+
/** 全部诊断码字面量联合(DIAG 值的类型面)。 */
|
|
85
|
+
type DiagCode = (typeof DIAG)[keyof typeof DIAG];
|
|
86
|
+
|
|
7
87
|
/**
|
|
8
88
|
* 源码文本工具:注释/字符串/正则字面量剥离。
|
|
9
89
|
* 原文正则特性探测(require/import/exports 等)必须先剥再测——
|
|
@@ -790,4 +870,4 @@ declare function runWithEvalMissingSlot<T>(enabled: boolean, body: () => T): T;
|
|
|
790
870
|
*/
|
|
791
871
|
declare function noteObjSlotMissing(recv: Abs | undefined, name: string, loc?: [number, number]): boolean;
|
|
792
872
|
|
|
793
|
-
export { type AbsBudgetStats, type AbsInlay, type ArgDerivation, type ClassDef, type CollectAbsInlaysOpts, type CollectorScopeParticipant, type DerivationNode, type DiagChannel, type EvalMemberDiag, FORK_TRUNCATION_LABEL, type FnFp, HOST_EFFECT_LABEL_PREFIX, type InjectedDomainEvidenceOpts, type InjectedDomainRecord, MAX_CALL_DEPTH, MAX_EVAL_TOTAL_FORKS, MAX_TOTAL_CALLS, type MethodDef, OBJECT_PROTO_NAMES, PROMISE_MICRO_ERROR_LABEL, PROMISE_MICRO_OVERFLOW_LABEL, type ScopedDiagChannel, type ScopedSlot, type StringLiteralSpan, type TemplateMeta, type TemplatePartDesc, type TemplatePartView, type TemplatePredicateDecision, abortDerivationSession, absTemplateViews, allFixedTextOfViews, anyMemberResult, awaitAbs, beginDerivationSession, bumpEvalForkBudget, callBudgetKey, canSkipLiteralCallScan, checkInjectedDomainEvidence, classChainNames, classFromMethods, clearLiveImportRefreshers, coerceAsyncReturn, collectAbsInlays, concatString, createDiagChannel, createScopedDiagChannel, createScopedSlot, createTemplateAbs, decideEndsWith, decideIncludes, decideStartsWith, defineClass, definitelyUncallableMember, denoteGuard, derivationChain, endDerivationSession, enterCall, escapeTemplateTypeFixed, exitCall, fixedLengthOfViews, fnFingerprints, formatObjectKey, formatTemplateNameViews, generalizeSourceKeyPart, getAbsCallBudgetStats, getAbsOrigin, getClass, getClassChain, getDerivation, getEvalForkBudgetLimit, getEvalForkCount, getFnNameAndBodies, hasDerivationSession, hashSource, instanceOf, instantiateClass, isEvalMissingSlotEnabled, isJsBindingIdent, isJsIdent, isNullishAbs, isTemplateLike, knownPrefixOfViews, knownSuffixOfViews, listTopFunctions, lookupMethod, lookupMethodWithOwner, lookupSuperMethod, maskCommentsAndStrings, mergeAdjacentFixedViews, noteAbsTruncation, noteAnyMemberMayThrow, noteDerivationAdd, noteDerivationJoin, noteEvalForkTruncation, noteHostEffectBlocked, noteMemberDispatchMiss, noteNullishMemberThrows, noteObjSlotMissing, notePrimMemberMissing, noteUnknownMemberMissing, popCallLoc, projectBrand, projectDerivationDsl, pushCallLoc, recordMemberDiag, registerCollectorScopeParticipant, resetAbsCallBudget, resetEvalForkBudget, resetFnFpCache, resetHashSourceCache, runWithCollectorScope, runWithEvalMissingSlot, safeMemberAccess, sanitizeCommentText, scanStringLiterals, setAbsTruncationCollector, setDerivation, setDerivationCollector, setEvalForkBudgetLimit, setEvalMissingSlotEnabled, setMemberDiagCollector, sourceHasCjsExports, sourceHasModuleDependency, sourceHasRequireCall, stableAnalyzeKeySource, stableCallId, stripCommentsAndStrings, stripStringsKeepComments, superNameOf, tagAbsOrigin, tagDerivationRoot, templateMatchesValue, templatePartsOf, termKey, toJsBindingIdent, truncatedAbs, viewTemplateParts, withFnBudgetOverride, wrapPromise };
|
|
873
|
+
export { type AbsBudgetStats, type AbsInlay, type ArgDerivation, type ClassDef, type CollectAbsInlaysOpts, type CollectorScopeParticipant, DIAG, type DerivationNode, type DiagChannel, type DiagCode, type EvalMemberDiag, FORK_TRUNCATION_LABEL, type FnFp, HOST_EFFECT_LABEL_PREFIX, type InjectedDomainEvidenceOpts, type InjectedDomainRecord, MAX_CALL_DEPTH, MAX_EVAL_TOTAL_FORKS, MAX_TOTAL_CALLS, type MethodDef, OBJECT_PROTO_NAMES, PROMISE_MICRO_ERROR_LABEL, PROMISE_MICRO_OVERFLOW_LABEL, type ScopedDiagChannel, type ScopedSlot, type StringLiteralSpan, type TemplateMeta, type TemplatePartDesc, type TemplatePartView, type TemplatePredicateDecision, abortDerivationSession, absTemplateViews, allFixedTextOfViews, anyMemberResult, awaitAbs, beginDerivationSession, bumpEvalForkBudget, callBudgetKey, canSkipLiteralCallScan, checkInjectedDomainEvidence, classChainNames, classFromMethods, clearLiveImportRefreshers, coerceAsyncReturn, collectAbsInlays, concatString, createDiagChannel, createScopedDiagChannel, createScopedSlot, createTemplateAbs, decideEndsWith, decideIncludes, decideStartsWith, defineClass, definitelyUncallableMember, denoteGuard, derivationChain, endDerivationSession, enterCall, escapeTemplateTypeFixed, exitCall, fixedLengthOfViews, fnFingerprints, formatObjectKey, formatTemplateNameViews, generalizeSourceKeyPart, getAbsCallBudgetStats, getAbsOrigin, getClass, getClassChain, getDerivation, getEvalForkBudgetLimit, getEvalForkCount, getFnNameAndBodies, hasDerivationSession, hashSource, instanceOf, instantiateClass, isEvalMissingSlotEnabled, isJsBindingIdent, isJsIdent, isNullishAbs, isTemplateLike, knownPrefixOfViews, knownSuffixOfViews, listTopFunctions, lookupMethod, lookupMethodWithOwner, lookupSuperMethod, maskCommentsAndStrings, mergeAdjacentFixedViews, noteAbsTruncation, noteAnyMemberMayThrow, noteDerivationAdd, noteDerivationJoin, noteEvalForkTruncation, noteHostEffectBlocked, noteMemberDispatchMiss, noteNullishMemberThrows, noteObjSlotMissing, notePrimMemberMissing, noteUnknownMemberMissing, popCallLoc, projectBrand, projectDerivationDsl, pushCallLoc, recordMemberDiag, registerCollectorScopeParticipant, resetAbsCallBudget, resetEvalForkBudget, resetFnFpCache, resetHashSourceCache, runWithCollectorScope, runWithEvalMissingSlot, safeMemberAccess, sanitizeCommentText, scanStringLiterals, setAbsTruncationCollector, setDerivation, setDerivationCollector, setEvalForkBudgetLimit, setEvalMissingSlotEnabled, setMemberDiagCollector, sourceHasCjsExports, sourceHasModuleDependency, sourceHasRequireCall, stableAnalyzeKeySource, stableCallId, stripCommentsAndStrings, stripStringsKeepComments, superNameOf, tagAbsOrigin, tagDerivationRoot, templateMatchesValue, templatePartsOf, termKey, toJsBindingIdent, truncatedAbs, viewTemplateParts, withFnBudgetOverride, wrapPromise };
|
package/dist/internal.js
CHANGED
|
@@ -22,11 +22,12 @@ import {
|
|
|
22
22
|
stableAnalyzeKeySource,
|
|
23
23
|
stablePathKey,
|
|
24
24
|
stablePathKeyGraph
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-47UPDZHE.js";
|
|
26
26
|
import {
|
|
27
27
|
$tryDigestSoft,
|
|
28
28
|
$tryMarkSoft,
|
|
29
29
|
$tryReleaseSoft,
|
|
30
|
+
DIAG,
|
|
30
31
|
ERROR_FAMILY,
|
|
31
32
|
FORK_TRUNCATION_LABEL,
|
|
32
33
|
HOST_EFFECT_LABEL_PREFIX,
|
|
@@ -171,7 +172,7 @@ import {
|
|
|
171
172
|
withEvalBudgetOverride,
|
|
172
173
|
withFnBudgetOverride,
|
|
173
174
|
wrapPromise
|
|
174
|
-
} from "./chunk-
|
|
175
|
+
} from "./chunk-NUTYUT3I.js";
|
|
175
176
|
|
|
176
177
|
// src/algebra/inlay.ts
|
|
177
178
|
function listFunctions(source) {
|
|
@@ -612,6 +613,7 @@ export {
|
|
|
612
613
|
$tryDigestSoft,
|
|
613
614
|
$tryMarkSoft,
|
|
614
615
|
$tryReleaseSoft,
|
|
616
|
+
DIAG,
|
|
615
617
|
ERROR_FAMILY,
|
|
616
618
|
FORK_TRUNCATION_LABEL,
|
|
617
619
|
HOST_EFFECT_LABEL_PREFIX,
|
package/package.json
CHANGED