You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(check): faithful typing for fallible calls and literals
Close two static-checker fidelity gaps that forced a batch of
type-mismatch diagnostics to stay non-blocking, and gate the
first batch - operator mismatches - as errors.
Fallible calls. A call returning `T|error` panics at the call
site when it errors, so the error never flows into normal code.
The checker now types such calls as their success type `T`,
matching runtime behaviour. This drops false operator errors
like `parse_int(s) + 1` and lets genuine ones gate: `"hi" + 1`
now reports RAD30002 as an error, not a hint. A new non-blocking
RAD30011 hint nudges handling an unhandled fallible call with
`catch` or `??`.
Literal shape. synth widens `[1, "2"]` to `(int|str)[]` and
`{"k": 1}` to `{str: int}`, which never match a tuple, struct,
or str-enum target under invariant assignability - so valid
literals false-flagged. A new structural check walks a literal
against the expected type recursively: valid literals now pass,
and real mismatches localise to the offending element rather
than the whole literal. These stay hints for now; promoting
them to errors is the next step.
Kan: promote-type-check.
Copy file name to clipboardExpand all lines: core/testing/docs_snippet_tolerances.go
+48-47Lines changed: 48 additions & 47 deletions
Original file line number
Diff line number
Diff line change
@@ -31,6 +31,18 @@ type Tolerance struct {
31
31
Reasonstring
32
32
}
33
33
34
+
// globallyToleratedCodes are advisory diagnostics accepted in ANY doc
35
+
// snippet, without a per-snippet entry. RAD30011 (unhandled fallible
36
+
// call) is a pervasive teaching-style hint: docs and examples call
37
+
// parse_int / read_file / etc. terse by design, to keep the focus on
38
+
// the feature being shown rather than on error scaffolding. Pinning it
39
+
// per-snippet would add dozens of no-signal entries. It's a Hint and
40
+
// never gates execution, so tolerating it globally hides no real error
41
+
// - the snippets still run.
42
+
vargloballyToleratedCodes=map[string]bool{
43
+
"RAD30011": true,
44
+
}
45
+
34
46
// docSnippetTolerances maps snippet IDs to their accepted diagnostic profile.
35
47
// Add entries via copy-paste from the test failure output - each failure
36
48
// prints a ready-to-paste stub.
@@ -209,25 +221,26 @@ var docSnippetTolerances = map[string]Tolerance{
209
221
},
210
222
211
223
// hm.md
212
-
"docs-web/docs/examples/hm.md#4eb5a0f8": {
213
-
ExpectedCodes: []string{"RAD30001"},
214
-
Reason: "checker false positive: `state.load(...)` UFCS-resolves to `load(state, ...)` where state is `error|map`; the first param is `map`, so the checker hints. The script is correct in practice because errdefer + state handling cover the error case at runtime.",
215
-
},
224
+
// #4eb5a0f8 (the final-form script + its preview duplicate) no longer
225
+
// needs an entry: load_state() now strips its error arm at the call
226
+
// (Gap 2), so `state` is `map` and the old `error|map` UFCS false
227
+
// positive is gone. The unhandled-fallible hint it now carries is
228
+
// globally tolerated.
216
229
"docs-web/docs/examples/hm.md#19e0e50a": {
217
230
ExpectedCodes: []string{"RAD40003"},
218
231
Reason: "intermediate tutorial step: command callbacks `do_show`/`do_edit`/`do_list` are added in the following tutorial steps. The RAD40003 warning surfaces because the tracking only sees top-level fns.",
219
232
},
220
233
"docs-web/docs/examples/hm.md#03e13698": {
221
-
ExpectedCodes: []string{"RAD30001", "RAD40003"},
222
-
Reason: "intermediate tutorial step: `do_edit`/`do_list` not yet defined (added in later steps), plus the same `error|map` hint as #4eb5a0f8.",
234
+
ExpectedCodes: []string{"RAD40003"},
235
+
Reason: "intermediate tutorial step: `do_edit`/`do_list` not yet defined (added in later steps). The old `error|map` RAD30001 hint is gone now that load_state() strips its error arm (Gap 2).",
223
236
},
224
237
"docs-web/docs/examples/hm.md#0b53f387": {
225
-
ExpectedCodes: []string{"RAD30001", "RAD40003"},
226
-
Reason: "intermediate tutorial step: `do_list` not yet defined; same `error|map` hint pattern.",
238
+
ExpectedCodes: []string{"RAD40003"},
239
+
Reason: "intermediate tutorial step: `do_list` not yet defined. Old `error|map` RAD30001 hint gone after Gap 2 error-strip.",
227
240
},
228
241
"docs-web/docs/examples/hm.md#abb66476": {
229
-
ExpectedCodes: []string{"RAD30001", "RAD40003"},
230
-
Reason: "intermediate tutorial step: `do_list` not yet defined; same `error|map` hint pattern.",
242
+
ExpectedCodes: []string{"RAD40003"},
243
+
Reason: "intermediate tutorial step: `do_list` not yet defined. Old `error|map` RAD30001 hint gone after Gap 2 error-strip.",
Reason: "checker hint: 'float|error * float' in the user's error-flow example. The doc is teaching error propagation; the hint surfaces because the checker doesn't see that the error short-circuit happens before the arithmetic.",
375
-
},
385
+
// #82491324 no longer needs an entry: `parse_float(...)` now strips
386
+
// its error arm at the call (Gap 2), so `price` is `float` and the
387
+
// old `float|error * float` RAD30002 hint is gone - the very false
388
+
// positive that hint represented. It now carries the globally-
Reason: "checker hint: `port = parse_int(port_str) ?? 8080` should narrow to `int`, but `??` doesn't fully narrow `int|error ?? int` today, so the subsequent `validate_port(port)` call sees a residual `int|error|int`.",
383
-
},
394
+
// #b558bc7f no longer needs an entry: `parse_int(port_str) ?? 8080`
395
+
// now yields `int` because the call strips its error arm before `??`
396
+
// (Gap 2), so the residual-`int|error|int` RAD30001 hint into
397
+
// validate_port is gone. This is exactly the narrowing the old
Reason: "checker hint: load_state() returns error|map and the doc shows direct use; the doc teaches the state-management pattern, error handling is covered separately.",
509
-
},
510
-
"docs-web/docs/guide/stashes.md#43a279d8": {
511
-
ExpectedCodes: []string{"RAD30001"},
512
-
Reason: "same load_state() error|map pattern as #18fa9b0a.",
513
-
},
521
+
// Most load_state() snippets no longer need entries: load_state()
522
+
// strips its error arm at the call (Gap 2), so `state` is `map` and
523
+
// the old error|map RAD30001 hints are gone; they now carry only the
524
+
// globally-tolerated unhandled-fallible hint.
514
525
"docs-web/docs/guide/stashes.md#ed4e81de": {
515
-
ExpectedCodes: []string{"RAD30001", "RAD30002"},
516
-
Reason: "same load_state() pattern + arithmetic on error|int. The error case is handled by the surrounding flow at runtime but the static checker can't yet see that.",
526
+
ExpectedCodes: []string{"RAD30002"},
527
+
Reason: "checker hint: `count = state[\"count\"] ?? 0` is `dynamic|int` (untyped map index), so `count++` flags `dynamic|int + int`. The script is correct at runtime. Was RAD30001 pre-Gap-2 (load_state's error|map); the error arm now strips, surfacing the underlying dynamic-map-index hint instead.",
Reason: "checker hint: vararg `*data_points: int|float` doesn't refine into `sum()`'s `float[]` or `join()`'s `str|list|map` parameters. RAD30002 cascades on the division because total/len both produce union types.",
@@ -554,10 +559,6 @@ var docSnippetTolerances = map[string]Tolerance{
554
559
ExpectedCodes: []string{"RAD30002"},
555
560
Reason: "literal-fidelity hint on words.join(' ') return type vs declared str.",
0 commit comments