ADR 0075 — The storage engine's findings: durable files, error conversion, an ordered map, checksums, a monotonic clock, assert/panic, replace, arrays as slices, *r, static tables, and tooling
- Status: Accepted by the owner, 2026-11-06 ("I want you to take over ~/dev/CeeSafe session and fix all the findings"). The findings come from the CosmoStore port (
CeeSafeApps/cosmostore/CEESAFE_GAPS.md, G1–G22). Each open finding was reproduced with ceesafec 0.18.2 on 2026-11-06 (§1). The owner did not answer §6 one by one. It is decided as proposed, as ADR 0074 §6 was, and is open to revision before the release. - Scope:
- type-system.md §6, §13.3, §16, §17.4, §23, §26.3, §26.10, §26.11, §39.4;
- spec/api/core.md and spec/api/std.md;
- diagnostics.md;
- the parser, checker, NIR lowering, C backend, interpreter and runtime;
- lib/core and lib/std;
ceesafec test --sweep allocand the package C build;- guide/builtins.md, guide/for-agents.md and templates/AGENTS.md;
- the corpus and tests/support.
1. Context
CosmoStore is an S3-compatible object store whose storage core (a journal, extents, checkpoints and crash recovery) is written in CeeSafe 0.18.1. To exist at all, it needed 130 lines of C (durable_shim.c). It also logged 22 findings. One is already fixed: HashKey for String and Vector<u8> (lib/std/collections.cee:179, :187). The rest reproduce on 0.18.2:
| # | Today (0.18.2) | The port's workaround |
|---|---|---|
| G1–G5 | File opens for reading, or creates truncating; no positional I/O, sync, length, truncate, rename or directory sync | durable_shim.c and a wrapper |
| G6 | AsyncFiles has only open, create, read and write | the journal is synchronous |
| G7 | r.isOk() is N0234; ? from Result<_, A> into Result<_, B> is N0261 | a generic adapter per error type (jio(f.size())?) |
| G8 | no ordered map | a full scan and sort for every LIST |
| G9 | no CRC32C, CRC64NVME, MD5, SHA-256 or HMAC in the libraries | its own CRC32C and MD5 |
| G10 | only Timer.now() in milliseconds | none (no latency histograms) |
| G11 | m.keyAt(0).name.view() is N0247 | a local per access |
| G12 | assert and panic are N0200 | checkedTruncate<u32>(x)! as an assertion |
| G13 | [0u8; 0] is N0259 | buf[0..0] |
| G14 | [u8; 8] has no readLE/writeLE (N0234) | let w = borrow mut h[..]; w.writeLE(…) |
| G15 | --sweep alloc counts a test's own ! as a failure (580 of 639 runs) | read the noise by hand |
| G16 | a package's C file is compiled from a temporary copy, so #include "x.h" beside it fails | include-dirs |
| G17 | a borrow error elsewhere in a function also reports N0265 "cannot infer T" | none |
| G18 | Vector has no insert/remove | sorted vectors by hand |
| G19 | moving a value out of a borrow mut place is N0251, and there is no replace | ObjectWriter.finish copies 128 KiB instead of moving it |
| G20 | a as u64 < b is N0100 (< read as generic arguments) | parentheses |
| G21 | [AtomicU64; 4] in a static is N0259 | a static mut table behind unsafe accessors |
| G22 | *r is N0102 | let id: u64 = r; |
2. Proposal
2.1 Durable files (G1–G5; §26.3, §26.10)
File gains three ways to open, positional I/O, two syncs, a length and a truncate. File.rename and Directory.sync are lib/std functions.
var journal = File.openOrCreate(path)?; // read and write; created if missing, never truncated
journal.writeAt(record.view(), offset)?; // every byte at `offset`, or an error
journal.syncData()?; // the data, and the metadata needed to read it back
let n = journal.readAt(mut buffer[..], offset)?; // bytes read; 0 at or past the end
journal.setLength(validEnd)?; // truncate a torn tail
File.rename(temporary, final)?; // atomic replace
Directory.sync(directory)?; // make the new names durableOpening.
Function Access Missing file Existing file File.openReadWrite(path)read and write NotFoundopened as is File.openOrCreate(path)read and write created opened as is File.createNew(path)read and write created AlreadyExists- A file is created with mode 0666 & ~umask.
- On Windows, every open shares read, write and delete.
Methods. Each takes
borrow mut thisand returnsResult<…, IoError>.EINTRis retried.f.readAt(mut buffer: SliceMut<u8>, offset: u64) -> usize: one positional read (pread;ReadFilewith anOVERLAPPEDoffset on Windows). It may return less than the buffer, and returns 0 at or past the end.f.writeAt(bytes: Slice<u8>, offset: u64) -> void: positional writes until every byte is written.f.syncData() -> void: the file's data, and the metadata needed to read it back, reach stable storage.- Linux:
fdatasync. - macOS and iOS:
fcntl(F_FULLFSYNC), becausefsyncthere does not flush the drive's cache. It falls back tofsynconly where the file system refusesF_FULLFSYNC(ENOTSUP,EINVAL). - Other POSIX systems:
fsync. - Windows:
FlushFileBuffers.
- Linux:
f.syncAll() -> void: the same, with all metadata (fsync, orF_FULLFSYNCon Apple systems).f.length() -> u64:fstat's size.f.setLength(n: u64) -> void:ftruncate(SetFileInformationByHandleon Windows), shrinking or zero-extending.- A failed sync leaves the file's durable contents unknown. After a failure, Linux may already have marked the dirty pages clean. A later successful sync does not mean the earlier writes reached the disk. A program that needs durability must treat the file as failed: rewrite it, or recover from what is known to be durable. The spec says this in so many words, and so does the guide.
readandwritekeep their sequential meaning on everyFile.
File.rename(from, to)(lib/std):rename(2), which atomically replacesto. On Windows it isMoveFileExW(MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH).Directory.sync(path)(lib/std): on POSIX,open(O_RDONLY | O_DIRECTORY)thenfsync, which makes the directory's entries (creations, renames, removals) durable. It isOkon Windows, where NTFS journals directory metadata and a directory handle cannot be flushed. The spec records this.Runtime. The C functions, each returning a value or a negated errno like the rest of
runtime/hosted/ceesafe_rt_io.c:ceesafe_file_open, with new modes 2, 3 and 4;ceesafe_fd_read_at,ceesafe_fd_write_at,ceesafe_fd_sync,ceesafe_fd_length,ceesafe_fd_set_length;ceesafe_host_rename,ceesafe_host_dir_sync.
Effects. All of these have
sleep, asFile.opendoes. In freestanding code they are N0293, asFileis.The interpreter runs them on the host file system, as it runs
File.open. Its sandbox refuses them, and it counts a sync as done.
2.2 Async files (G6; spec/api/std.md AsyncFiles)
AsyncFiles gains openReadWrite, openOrCreate, createNew, readAt, writeAt, syncData, syncAll, length, setLength, rename and syncDirectory, with §2.1's meaning. Each runs its blocking call on a worker (Async.blocking), as AsyncFiles.read does today. io_uring's IORING_OP_FSYNC and positional reads are an executor change for a later ADR. The API does not depend on how the work is done.
2.3 Results and conversion in ? (G7; §17.4, spec/api/core.md)
Methods of
Result<T, E>(lib/core):r.isOk()andr.isErr()takeborrow this;r.ok() -> T?andr.err() -> E?consumer;r.map(f)andr.mapErr(f)consumerand callfwith the payload.
Methods of
T?:o.okOr(e) -> Result<T, E>consumeso.Conversion in
?. A variant of a user enum whose single payload is the error typeAmay be marked@from:ceesafeenum StoreError { @from Io(IoError), @from Alloc(AllocError), Corrupt, } fn open(path: StringView) -> Result<Store, StoreError> { var f = File.openReadWrite(path)?; // an IoError becomes StoreError.Io(e) … }- In a function returning
Result<U, B>,e?withe: Result<T, A>is allowed whereAisB, or whereBis an enum with an@fromvariant whose payload type isA. TheErr(x)case then returnsErr(B.Variant(x)). - At most one
@fromvariant per payload type (N0262 otherwise; the diagnostic names both). A@fromvariant must have exactly one payload (N0262). - The conversion goes one step only, never
A → B → C. - It applies to
?only.return Err(x)still needsB.Variant(x), so a construction always says what it builds. - N0261 now says which
@fromvariant would fix the mismatch.
- In a function returning
Why an attribute, not an interface. A
From-style interface forIoError → StoreErrorwould have to live in the package that declares eitherIoErroror the interface. That works here, but an interface adds a call the reader cannot see, and generic code would have to resolve it per instance. A variant is visible where the error type is declared, costs nothing at run time, and is checked once.
2.4 An ordered map (G8; spec/api/std.md)
lib/std gains OrderedMap<K, V>, a B-tree:
- It is built over an arena of nodes (a
Vectorof nodes, linked by index), so it uses nounsafe. - Each node has at most 2B − 1 keys, for a fixed B of 16.
- Keys implement a new interface,
OrderKey<K>, withfn compare(borrow this, other: borrow K) -> i32(negative, zero or positive). lib/std implements it for the integers,bool,StringandVector<u8>(bytewise). create().put(key, value) -> Result<V?, AllocError>: the old value, if any.get(borrow key) -> borrow V?andgetMut(borrow key) -> borrow mut V?.contains(borrow key) -> bool.remove(borrow key) -> V?, which rebalances: borrow from a sibling, else merge.length() -> usizeandisEmpty() -> bool.clear().- Ordered access with cursors. A cursor is a plain value: a node, a slot and the map's version.
first(),last(),seek(borrow key)(the first entry ≥ key) andseekAfter(borrow key)return anOrderedCursor?.next(cursor) -> OrderedCursor?andprevious(cursor) -> OrderedCursor?step it.keyAt(cursor) -> borrow KandvalueAt(cursor) -> borrow Vread through it, andvalueAtMutwrites.- A cursor used after the map changed panics ("ordered map changed under a cursor"): a mutation bumps the version. A cursor cannot outlive the map's validity silently, and the borrow checker needs no new rule.
- A range scan is
seek(from)followed bynextuntilkeyAt(c).compare(to) >= 0.
- Iteration order is the keys' order, so output never depends on insertion order or hashing.
2.5 Checksums and hashes (G9; spec/api/std.md)
lib/std gains, in pure CeeSafe:
Crc32c: Castagnoli, reflected, slicing-by-8;Crc64Nvme: the CRC-64/NVME of the S3 checksum headers;Md5;Sha256;HmacSha256.
Each is incremental: create(), update(bytes), then finish(), which returns a u32/u64, or a [u8; 16]/[u8; 32] digest. Crc32c.of(bytes) and the like compute it in one call. The CRC tables are generated (tools/gen_checksums.py), as the other tables are. MD5 is for ETags and Content-MD5 only, and the API doc says it is broken as a signature. Hardware CRC (SSE4.2 crc32, ARMv8 crc32c) needs intrinsics, which CeeSafe does not have. It is left to a later ADR, and the API will not change. Test vectors come from Python (hashlib, hmac, and an independent CRC model in tools/oracles).
2.6 A monotonic clock in nanoseconds (G10; §26.11)
Clock.monotonicNanos() -> u64 (lib/std): nanoseconds on the monotonic clock, from an arbitrary start.
- POSIX:
clock_gettime(CLOCK_MONOTONIC). - Apple systems:
clock_gettime_nsec_np(CLOCK_UPTIME_RAW). - Windows:
QueryPerformanceCounter, scaled.
It never decreases within a process. The interpreter answers its virtual clock in nanoseconds. Timer.now() keeps its milliseconds.
2.7 A field of a returned reference is a place (G11; §13.2)
A call whose result is a reference is a reference expression. A field reached through it, m.keyAt(0).name, is "a place reached through a reference", which N0247's text already allows. So m.keyAt(0).name.view() borrows name through keyAt's result, and the loan is the call result's loan. The same holds for a method result (e.f()) and for chains (a.b().c.d()).
2.8 assert and panic (G12; §8)
panic(message: StringView) -> neverpanics with "panicked: " and the message. Like every panic, it reports the source position and aborts.assert(condition)panics with "assertion failed" whenconditionis false.assert(condition, message)uses the message instead.- These are built-in function names, so a user function named
assertorpanicshadows them, with no warning. - Assertions are always checked: there is no release mode that drops them, so a build does what its tests checked.
- The runtime gains
CEE_PANIC_ASSERTandceesafe_panic_message(position, text).
2.9 Empty arrays (G13; §16)
[T; 0] is a type and [e; 0] a value: the empty array.
- Its size is 0. No C storage is emitted for it: a zero-length array member is left out of its struct, and a local is a
uint8_tplaceholder that nothing reads. a[..]is an empty slice, and anya[i]panics.ein[e; 0]is still evaluated and then destroyed, because it is an expression with effects.[T; 0]in a@repr(C)struct or anextern "C"signature is N0259, because C has no zero-length arrays.Slice<T>.empty()andSliceMut<T>.empty()are also added: the empty slice, with no array behind it.
2.10 An array's methods are its slice's (G14; §16)
A method call on an array place whose name is not an array method calls the slice method on a[..]. It borrows mutably when the method needs a SliceMut, and needs a mutable place for that, as a[..] does. So h.writeLE(0, x) and h.readLE<u32>(4) work on [u8; 64], as do sortBy, swap and the rest.
2.11 Moving out of a mutable place: replace and swap (G19; §14)
replace(mut place, value) -> Tputsvalueinplaceand returns the old value.swap(mut a, mut b)exchanges two places of the same type.Both are built-in functions. The place is never left empty, so neither changes any move rule. They work for every type, including a field of a struct that has a
dropblock, which is how a consumingfinishgives up a buffer:ceesafefn finish(this: borrow mut ObjectWriter) -> Vector<u8> => replace(mut this.inline, Vector<u8>.create());swap's two places are two mutable loans at once, soswap(mut a.x, mut a.x)is N0241 as always. For two elements of one slice there iss.swap(i, j).Lowering:
T old = *p; *p = v;in C, withvmoved in. Drop elaboration sees a move into*pand a fresh value out.
2.12 Vector.insert, remove and swapRemove (G18; §23)
v.insert(at, x) -> Result<void, AllocError>shifts later elements up.at == lengthappends.v.remove(at) -> Tshifts later elements down.v.swapRemove(at) -> Tmoves the last element intoat, which is O(1) and does not keep the order.atpast the end panics (index out of bounds). The shifting is amemmovein C and a loop in the interpreter.
2.13 as T < (G20; grammar.md)
After as, a primitive type name (u8 … u64, i8 … i64, usize, isize, f32, f64, bool, char) takes no type arguments, so a < after it is the comparison operator: a as u64 < b is (a as u64) < b.
For a type that does take type arguments, as Box<T> is still parsed as written. If its < cannot start type arguments, N0100 now adds "write (e as T) < x for a comparison".
2.14 Prefix *: reading through a reference (G22; §13.3)
*r where r: borrow T or borrow mut T, with T a Copy type, is the value r refers to. It is a copy, of type T, so let id = *m.keyAt(0); declares a u64.
*ron a reference to a non-Copy type is N0251. The diagnostic says to borrow orreplace.*on a non-reference is N0205.- Assigning through
*r = vis accepted whereris aborrow mut T, the same asr = vtoday. - Raw pointers keep
p.read()andp.write(v).*pon a raw pointer is N0205, which points to them, because a raw read isunsafeand must look different. - The binary
*is unchanged: a prefix*is one with no left operand.
2.15 Static tables (G21; §39.4)
- Arrays of non-Copy elements, in statics only. A static's type may be
[T; N]with a non-CopyTthat has nodropblock (atomics, structs of atomics). Its initialiser must be an array literal or[e; N]whereeis a static initialiser.[e; N]there means N evaluations ofeat compile time, not a copy, so it needs no Copy. S[i]is a place, and methods borrow through it (SLOTS[i].fetchAdd(1)). It cannot be moved out of, as no static can.- Outside statics, arrays of non-Copy elements stay N0259. Locals, fields and parameters would need per-element drop flags, which is a separate decision.
Mutex<T>.constant(value)(lib/std,@constant) for aTwith a static initialiser, andVector<T>.empty(),@constant: an empty vector owns no memory, so it is a static initialiser. Together they allowstatic TABLE: Mutex<Vector<u64>> = Mutex<Vector<u64>>.constant(Vector<u64>.empty());.- A static's
Mutexis never destroyed. Its vector's memory is reclaimed at process exit, so the leak checker does not count a static's allocations.
- A static's
2.16 Tooling and diagnostics (G15, G16, G17)
G15.
ceesafec test --sweep allocputs each injected failure into one of three classes:- handled: the test passed;
- unwrapped by the test: the panic is
!or?'s unwrap at a position inside an@testfunction's own body; - failed: any other panic, a leak, a crash or a wrong result.
Only failed runs fail the sweep. The report shows the count of each, and lists the failed ones.
--sweep-strictkeeps today's behaviour.G16. A package's C files are compiled with their own source directory first on the quoted include path (
-iquote <dir>;/I<dir>on MSVC), so a header beside a.cfile is found. They are still compiled from the build copy. guide/packages.md says so.G17. A call whose arguments include an error expression no longer reports N0265 (cannot infer
T), and no inference diagnostic comes from an error type. The first error is the one shown.
3. Not included
- io_uring for files (§2.2) and hardware CRC (§2.5): each needs its own design, and neither changes the API.
- Arrays of non-Copy elements outside statics (§2.15).
- An interface-based
From(§2.3). take(mut place)for types with a default: CeeSafe has noDefaultinterface.replace(mut p, X.create())says the same thing.
4. Tests
Each section gets run-pass and check-fail corpus programs. Every new library function gets tests/support programs whose expected values come from Python oracles: hashes, CRCs and the ordered map against a sorted dict model. The file API gets a hosted test that writes, syncs, truncates, reopens and renames. The tests run with --check-leaks, and the interpreter must give the same results.
5. Consequences
- CosmoStore can delete
durable_shim.cand the error adapters, and its fault registry no longer needsunsafe. It can also use the library CRC32C and MD5. - Programs that already have their own functions named
assert,panic,replaceorswapkeep them, since a local name wins (§2.8). There are no other source changes.
6. Questions, decided as proposed
- Release: one release, 0.19.0, since the file API,
@fromand the statics are new features. @fromover aFrominterface (§2.3).- A cursor used after a mutation panics, rather than giving the borrow checker a new rule (§2.4).
Directory.syncisOkon Windows (§2.1).- Assertions are always checked (§2.8).
7. As built (2026-11-06): changes from the accepted text
- §2.8. The panic message has the existing format:
ceesafe panic: <message> at <file>:<line>:<column>, not "panicked: …".assertwithout a message says "assertion failed". The runtime gainsceesafe_panic_textandCEE_PANIC_EXPLICIT. A freestanding environment still defines onlyceesafe_panic, so the freestanding contract (profiles.md §4.2) is unchanged. - §2.9.
[T; 0]is not added. C has no zero-sized object, so the type would be laid out one way in C and another in CeeSafe (offsetOf, the interpreter). The empty slice is spelled[]where aSlice<T>orSliceMut<T>is expected, rather thanSlice<T>.empty(). That is what the finding asked for (buf[0..0]). - §2.3.
mapandmapErrare left out. A generic method in a generic struct cannot name the struct's type parameters yet (unknown type 'T'), and that is a checker change of its own.isOk,isErr,ok,err,okOrand@fromare in.@fromis recorded per?expression in a checker side table, soHirExpr.Trykeeps its shape. - §2.12. The shifting is a loop of
swaps in lib/core'sVectorEditing<T>, not amemmove. That keeps it out of the C backend and the interpreter. The index check is emitted at the call, asByteOrder's is, so a panic names the program's line. - §2.15.
Mutex<T>.constantandVector<T>.empty()are left out.Vectoris a built-in type, and making it a static initialiser is its own change. Static arrays of atomics are in, and they are what CosmoStore's registry needs. - §2.16, G15. A sweep panic counts as the tests' own when it is an unwrap in any file that declares an
@testfunction, not only inside an@testbody. Test helpers live in those files: CosmoStore's sweep went from 63 failures in 200 runs to 0, all 63 being helpers' and tests' unwraps.ceesafec testwritestest-spans.txtfor this.--sweep-strictkeeps the old count. - §2.16, G16. The headers beside a package's C file are copied with it into the build's
c/directory, instead of an-iquoteflag, so--emit c's output stays self-contained. Two different headers of one name are an error. - §2.4.
OrderKey's method iscompareKey, notcompare. A user'simpl Comparable<u8> for u8 { fn compare … }(check-pass/interfaces.cee) would otherwise clash with lib/std's impl onu8. - Library names (new, §5). A package's item may now have a lib/core or lib/std item's name. Before, that was N0201, and it would have made every new library name a source change. It would have broken this compiler (
src/support/sha256.cee), CeeSafeLibs'sha256package (Sha256,HmacSha256) and CosmoStore (Md5,Crc32c). The package's item shadows the library's in that package; the libraries still find their own (packageItemlooks in the package first, a library file only in the libraries). In C the library's item is thenceeT_lib_…,ceeF_lib_…and so on (appendShadowMark). - Library statics (new). A library's static is emitted in C only where compiled code uses it (
usedStatics), as a library function is. Otherwise every hosted program would carry the 24 KB of checksum tables. A program's own statics are still always emitted. - Corpus. A new directive,
// expect-library-panic: reason, covers a panic that a library raises at its own line (the stale OrderedMap cursor). spec/testing.md documents it.parse-fail/expression-errors.ceeline 6 now uses/ 2, because* 2is a dereference (a check error, not N0102). Four snapshots changed only because the library grew: the closure numbers in check-passasync-timeout.hir,effects-of.hirandstring-braces-warning.hir, and the order of two type declarations inemit-c/slice-bulk.c. Each was compared with numbers normalised (or sorted) before it was regenerated. - The checksum test leaves out the million-byte "a" message, which took the interpreter 3 minutes (the runner times out). It passed in both modes before it was removed, and the 4,096 and 8,193-byte cases still cross many blocks.
Found while building (fixed after 0.19.0, §8)
- N0272 false positive. A value of type parameter
Ttaken fromthisby a generic call, or a struct literal ofItem<T>built with a Copy field read throughthis, is reported as "a value borrowed from 'this'". Pushing it back intothisis then N0272. The B-tree works around it. Repro:take<T>(v: borrow mut Vector<T>) -> Tcalled aslet x = take(mut this.a); this.b.push(x)!;in a method ofstruct Two<T>. - N0212 across
?, kernel profile only. In lib/core,let length = v.length; v.push(x)?; var i = length;was "may not have been assigned" when checked with--profile freestanding --kernel cosmoos, and not otherwise.VectorEditing.insertnow computes the index after the push.
Tests run (2026-11-06, macOS arm64)
python3 tools/run_corpus.py --compiler out/ceesafec-new --corpus tests/reference/tests/corpus --jobs 8: every family passes (freestanding is "partial" as before). The new programs are run-passadr0075-language,durable-files,checksumsandordered-map; run-failpanic-message,assert-failed,vector-remove-past-endandordered-map-stale-cursor; and check-failadr0075-errors. Each also passes with--interp.- Fixed point: the new compiler built itself (gen2), gen2 built gen3, and their
--emit coutput is identical. checksumsandordered-mapexpectations come from Python (hashlib, hmac, tools/oracles/crc_model.py, and a sorted-dict model in tools/oracles/gen_ordered_map_cases.py).python3 tools/contract_tests.py --ceesafec out/ceesafec(gen2): every suite passes; Linux-only checks were skipped (fortify, io_uring). The suites are the fixed point, -Werror, asan, tsan, interp, the support, hashmap, fault and cancel sweeps, mutations, packages, spec, guide, debugger and mcp api. The corpus's one failure was check-fail/systems-capabilities.cee expecting N0201 for aPhysAddrof the program's own. That is §7.9's change: the expectation was edited (a reviewed change, noted on the line) and type-system.md §2, §26.8, §29.2 and §38.5 now say so.ceesafec checkis clean in all 44 packages of CeeSafeLibs and CeeSafeApps. Their 24 test suites pass, and so does CosmoStore's (54 tests).
8. Amendment (2026-11-06): the two bugs of §7, fixed after 0.19.0
The owner: "Fix the two bugs first, then migrate CosmoStore".
- N0272 on a referent's own contents.
- Callee. A result whose type is a type parameter (
fn take<T>(v: borrow mut Vector<T>) -> T) was tied tovby elision, so it carriedv's own loan.Tcannot name the reference's elided region, so each such reference parameter is now a deep source: the result carries only what the referent holds (src/check/references.cee; type-system.md §25.6). - Store. Rule 2 of §25.7 made a write through
borrow mut ptake only loans of parameters that flow intop, and a parameter never flows into itself. Nowp's deep placeholder may go back intop: what the referent held may return to it (checkParameterWrites,src/nir/borrow.cee). The loan ofpitself (its outer placeholder) and loans ofp's own storage still may not. - Tests. run-pass
generic-values-back-into-this.cee(both of §7's repros; 0.19.0 rejects it) and check-failvalues-into-this-still-checked.cee(a view ofthis.datastored intothis, and another parameter's view, still N0272).
- Callee. A result whose type is a type parameter (
- N0212 under the kernel profile. In a freestanding build, a lib/core function over
Vectorgets error types, and its N0293s are dropped with the libraries' other diagnostics (main.cee). Nothing was then left to stop the ownership analyses, which reported the consequences:let length = v.length; v.push(x)?; var i = length;was "may not have been assigned". Library functions with an error inside them are now recorded before those diagnostics are dropped (markUncheckedLibrary,Checker.uncheckedLibrary), and the NIR checks skip them. Nothing can call them: a caller would have the same type errors.VectorEditing.insertis back to that natural form, so the kernel corpus programs (check-pass and check-failkernel-library,kernel-percpu*, check-failasync-recursion) test it. File's durable methods takeborrow this. CosmoStore's journal and store read through shared references to their files.readAt,writeAt,syncData,syncAll,lengthandsetLengthnever move the position thatreadandwriteuse, as in Rust'sFileExt::read_at(&self), so they no longer needborrow mut this. This is a relaxation: code written for 0.19.0 still checks.AsyncFileskeeps itsborrow mut Fileparameters, since loosening a parameter would make its callers'mut farguments N0249.