@shd101wyy/yo 0.1.30 → 0.1.32

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.
Files changed (36) hide show
  1. package/.github/skills/yo-syntax/syntax-cheatsheet.md +38 -0
  2. package/out/cjs/index.cjs +800 -633
  3. package/out/cjs/yo-cli.cjs +1007 -840
  4. package/out/cjs/yo-lsp.cjs +890 -723
  5. package/out/esm/index.mjs +804 -637
  6. package/out/types/src/codegen/index.d.ts +1 -1
  7. package/out/types/src/compiler-utils.d.ts +1 -1
  8. package/out/types/src/evaluator/builtins/contracts.d.ts +35 -0
  9. package/out/types/src/evaluator/memory-safety.d.ts +1 -1
  10. package/out/types/src/evaluator/types/function.d.ts +2 -0
  11. package/out/types/src/evaluator/utils/closure.d.ts +2 -1
  12. package/out/types/src/evaluator/utils.d.ts +3 -0
  13. package/out/types/src/evaluator/values/impl.d.ts +14 -0
  14. package/out/types/src/expr.d.ts +6 -0
  15. package/out/types/src/tests/contracts-comptime-violation.test.d.ts +1 -0
  16. package/out/types/src/tests/contracts-runtime-violation.test.d.ts +1 -0
  17. package/out/types/src/tests/thread-safety-codegen.test.d.ts +1 -0
  18. package/out/types/src/types/creators.d.ts +3 -1
  19. package/out/types/src/types/definitions.d.ts +2 -0
  20. package/out/types/tsconfig.tsbuildinfo +1 -1
  21. package/package.json +1 -1
  22. package/std/build.yo +5 -2
  23. package/std/imm/list.yo +1 -1
  24. package/std/imm/sorted_map.yo +1 -1
  25. package/std/libc/stdatomic.yo +285 -1
  26. package/std/prelude.yo +56 -3
  27. package/std/spec/numeric.yo +30 -0
  28. package/std/spec/refine.yo +43 -0
  29. package/std/string/rune.yo +4 -0
  30. package/std/sync/atomic.yo +557 -0
  31. package/std/sync/channel.yo +57 -42
  32. package/std/sync/cond.yo +7 -3
  33. package/std/sync/mutex.yo +75 -15
  34. package/std/sync/once.yo +25 -19
  35. package/std/sync/rwlock.yo +18 -15
  36. package/std/sync/waitgroup.yo +25 -16
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.1.30",
4
+ "version": "0.1.32",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
package/std/build.yo CHANGED
@@ -47,7 +47,9 @@ Sanitize :: enum(
47
47
  /// AddressSanitizer — detects memory errors and leaks.
48
48
  Address,
49
49
  /// LeakSanitizer — detects memory leaks only.
50
- Leak
50
+ Leak,
51
+ /// ThreadSanitizer — detects data races in multi-threaded code.
52
+ Thread
51
53
  );
52
54
  export(Sanitize);
53
55
  // ── Step kinds ───────────────────────────────────────────────────────
@@ -281,7 +283,8 @@ executable :: (fn(comptime(config) : Executable) -> comptime(Step))({
281
283
  config.sanitize,
282
284
  .None => "none",
283
285
  .Address => "address",
284
- .Leak => "leak"
286
+ .Leak => "leak",
287
+ .Thread => "thread"
285
288
  );
286
289
  __yo_build_executable(config.name, config.root, config.target, opt_str, alloc_str, san_str);
287
290
  Step(name : config.name, kind : StepKind.Executable)
package/std/imm/list.yo CHANGED
@@ -28,7 +28,7 @@ ListNode :: (fn(comptime(T) : Type, where(T <: Send)) -> comptime(Type))(
28
28
  )
29
29
  )
30
30
  );
31
- // Manual Acyclic impl — ListNode is self-referential, so auto-derivation skips it.
31
+ // SAFETY: Manual Acyclic impl — ListNode is self-referential, so auto-derivation skips it.
32
32
  // This is safe because ListNode is immutable: all operations create new nodes and never
33
33
  // mutate existing ones, making it impossible to form cycles at runtime.
34
34
  impl(forall(T : Type), where(T <: Send), ListNode(T), Acyclic());
@@ -40,7 +40,7 @@ RBNode :: (
40
40
  )
41
41
  )
42
42
  );
43
- // Manual Acyclic impl — RBNode is self-referential, so auto-derivation skips it.
43
+ // SAFETY: Manual Acyclic impl — RBNode is self-referential, so auto-derivation skips it.
44
44
  // This is safe because RBNode is immutable: all tree operations create new nodes
45
45
  // and never mutate existing ones, making it impossible to form cycles at runtime.
46
46
  impl(forall(K : Type, V : Type), where(K <: (Eq(K), Ord(K), Send), V <: Send), RBNode(K, V), Acyclic());
@@ -138,6 +138,244 @@ c_include(
138
138
  ATOMIC_LLONG_LOCK_FREE : i32,
139
139
  ATOMIC_POINTER_LOCK_FREE : i32
140
140
  );
141
+ // SAFETY: C11 atomic typedefs (atomic_bool, atomic_int, etc.) are opaque C
142
+ // types backed by _Atomic-qualified primitives. They contain no heap
143
+ // allocations or thread-local state — they are trivially safe to send
144
+ // across threads. They are Acyclic because they don't participate in Yo's
145
+ // ARC reference-counting cycle analysis.
146
+ impl(atomic_bool, Send());
147
+ impl(atomic_bool, Acyclic());
148
+ impl(atomic_char, Send());
149
+ impl(atomic_char, Acyclic());
150
+ impl(atomic_schar, Send());
151
+ impl(atomic_schar, Acyclic());
152
+ impl(atomic_uchar, Send());
153
+ impl(atomic_uchar, Acyclic());
154
+ impl(atomic_short, Send());
155
+ impl(atomic_short, Acyclic());
156
+ impl(atomic_ushort, Send());
157
+ impl(atomic_ushort, Acyclic());
158
+ impl(atomic_int, Send());
159
+ impl(atomic_int, Acyclic());
160
+ impl(atomic_uint, Send());
161
+ impl(atomic_uint, Acyclic());
162
+ impl(atomic_long, Send());
163
+ impl(atomic_long, Acyclic());
164
+ impl(atomic_ulong, Send());
165
+ impl(atomic_ulong, Acyclic());
166
+ impl(atomic_llong, Send());
167
+ impl(atomic_llong, Acyclic());
168
+ impl(atomic_ullong, Send());
169
+ impl(atomic_ullong, Acyclic());
170
+ impl(atomic_char16_t, Send());
171
+ impl(atomic_char16_t, Acyclic());
172
+ impl(atomic_char32_t, Send());
173
+ impl(atomic_char32_t, Acyclic());
174
+ impl(atomic_wchar_t, Send());
175
+ impl(atomic_wchar_t, Acyclic());
176
+ impl(atomic_int_least8_t, Send());
177
+ impl(atomic_int_least8_t, Acyclic());
178
+ impl(atomic_uint_least8_t, Send());
179
+ impl(atomic_uint_least8_t, Acyclic());
180
+ impl(atomic_int_least16_t, Send());
181
+ impl(atomic_int_least16_t, Acyclic());
182
+ impl(atomic_uint_least16_t, Send());
183
+ impl(atomic_uint_least16_t, Acyclic());
184
+ impl(atomic_int_least32_t, Send());
185
+ impl(atomic_int_least32_t, Acyclic());
186
+ impl(atomic_uint_least32_t, Send());
187
+ impl(atomic_uint_least32_t, Acyclic());
188
+ impl(atomic_int_least64_t, Send());
189
+ impl(atomic_int_least64_t, Acyclic());
190
+ impl(atomic_uint_least64_t, Send());
191
+ impl(atomic_uint_least64_t, Acyclic());
192
+ impl(atomic_int_fast8_t, Send());
193
+ impl(atomic_int_fast8_t, Acyclic());
194
+ impl(atomic_uint_fast8_t, Send());
195
+ impl(atomic_uint_fast8_t, Acyclic());
196
+ impl(atomic_int_fast16_t, Send());
197
+ impl(atomic_int_fast16_t, Acyclic());
198
+ impl(atomic_uint_fast16_t, Send());
199
+ impl(atomic_uint_fast16_t, Acyclic());
200
+ impl(atomic_int_fast32_t, Send());
201
+ impl(atomic_int_fast32_t, Acyclic());
202
+ impl(atomic_uint_fast32_t, Send());
203
+ impl(atomic_uint_fast32_t, Acyclic());
204
+ impl(atomic_int_fast64_t, Send());
205
+ impl(atomic_int_fast64_t, Acyclic());
206
+ impl(atomic_uint_fast64_t, Send());
207
+ impl(atomic_uint_fast64_t, Acyclic());
208
+ impl(atomic_intptr_t, Send());
209
+ impl(atomic_intptr_t, Acyclic());
210
+ impl(atomic_uintptr_t, Send());
211
+ impl(atomic_uintptr_t, Acyclic());
212
+ impl(atomic_size_t, Send());
213
+ impl(atomic_size_t, Acyclic());
214
+ impl(atomic_ptrdiff_t, Send());
215
+ impl(atomic_ptrdiff_t, Acyclic());
216
+ impl(atomic_intmax_t, Send());
217
+ impl(atomic_intmax_t, Acyclic());
218
+ impl(atomic_uintmax_t, Send());
219
+ impl(atomic_uintmax_t, Acyclic());
220
+ // Phase C (THREAD_SAFETY): int-specific atomic operations. The c_include
221
+ // block only declares load/store/exchange for atomic_bool. These Yo-runtime
222
+ // wrappers forward to the C11 _Generic macros in <stdatomic.h> so AtomicI32
223
+ // can use the full atomic API.
224
+ extern(
225
+ "Yo",
226
+ __yo_atomic_load_int :
227
+ fn(obj : *(atomic_int), order : memory_order) -> i32,
228
+ __yo_atomic_store_int :
229
+ fn(obj : *(atomic_int), desired : i32, order : memory_order) -> unit,
230
+ __yo_atomic_exchange_int :
231
+ fn(obj : *(atomic_int), desired : i32, order : memory_order) -> i32,
232
+ __yo_atomic_compare_exchange_int :
233
+ fn(
234
+ obj : *(atomic_int),
235
+ expected : *(i32),
236
+ desired : i32,
237
+ success : memory_order,
238
+ failure : memory_order
239
+ ) -> bool
240
+ );
241
+ // Phase C: size_t-specific atomic operations (for AtomicUsize)
242
+ extern(
243
+ "Yo",
244
+ __yo_atomic_load_size_t :
245
+ fn(obj : *(atomic_size_t), order : memory_order) -> usize,
246
+ __yo_atomic_store_size_t :
247
+ fn(obj : *(atomic_size_t), desired : usize, order : memory_order) -> unit,
248
+ __yo_atomic_exchange_size_t :
249
+ fn(obj : *(atomic_size_t), desired : usize, order : memory_order) -> usize,
250
+ __yo_atomic_compare_exchange_size_t :
251
+ fn(
252
+ obj : *(atomic_size_t),
253
+ expected : *(usize),
254
+ desired : usize,
255
+ success : memory_order,
256
+ failure : memory_order
257
+ ) -> bool
258
+ );
259
+ // Phase C: long-long-specific atomic operations (for AtomicI64)
260
+ extern(
261
+ "Yo",
262
+ __yo_atomic_load_llong :
263
+ fn(obj : *(atomic_llong), order : memory_order) -> i64,
264
+ __yo_atomic_store_llong :
265
+ fn(obj : *(atomic_llong), desired : i64, order : memory_order) -> unit,
266
+ __yo_atomic_exchange_llong :
267
+ fn(obj : *(atomic_llong), desired : i64, order : memory_order) -> i64,
268
+ __yo_atomic_compare_exchange_llong :
269
+ fn(
270
+ obj : *(atomic_llong),
271
+ expected : *(i64),
272
+ desired : i64,
273
+ success : memory_order,
274
+ failure : memory_order
275
+ ) -> bool
276
+ );
277
+ // Phase C: remaining atomic type wrappers
278
+ extern(
279
+ "Yo",
280
+ __yo_atomic_load_schar :
281
+ fn(obj : *(atomic_schar), order : memory_order) -> i8,
282
+ __yo_atomic_store_schar :
283
+ fn(obj : *(atomic_schar), desired : i8, order : memory_order) -> unit,
284
+ __yo_atomic_exchange_schar :
285
+ fn(obj : *(atomic_schar), desired : i8, order : memory_order) -> i8,
286
+ __yo_atomic_compare_exchange_schar :
287
+ fn(
288
+ obj : *(atomic_schar),
289
+ expected : *(i8),
290
+ desired : i8,
291
+ success : memory_order,
292
+ failure : memory_order
293
+ ) -> bool,
294
+ __yo_atomic_load_short :
295
+ fn(obj : *(atomic_short), order : memory_order) -> i16,
296
+ __yo_atomic_store_short :
297
+ fn(obj : *(atomic_short), desired : i16, order : memory_order) -> unit,
298
+ __yo_atomic_exchange_short :
299
+ fn(obj : *(atomic_short), desired : i16, order : memory_order) -> i16,
300
+ __yo_atomic_compare_exchange_short :
301
+ fn(
302
+ obj : *(atomic_short),
303
+ expected : *(i16),
304
+ desired : i16,
305
+ success : memory_order,
306
+ failure : memory_order
307
+ ) -> bool,
308
+ __yo_atomic_load_uchar :
309
+ fn(obj : *(atomic_uchar), order : memory_order) -> u8,
310
+ __yo_atomic_store_uchar :
311
+ fn(obj : *(atomic_uchar), desired : u8, order : memory_order) -> unit,
312
+ __yo_atomic_exchange_uchar :
313
+ fn(obj : *(atomic_uchar), desired : u8, order : memory_order) -> u8,
314
+ __yo_atomic_compare_exchange_uchar :
315
+ fn(
316
+ obj : *(atomic_uchar),
317
+ expected : *(u8),
318
+ desired : u8,
319
+ success : memory_order,
320
+ failure : memory_order
321
+ ) -> bool,
322
+ __yo_atomic_load_ushort :
323
+ fn(obj : *(atomic_ushort), order : memory_order) -> u16,
324
+ __yo_atomic_store_ushort :
325
+ fn(obj : *(atomic_ushort), desired : u16, order : memory_order) -> unit,
326
+ __yo_atomic_exchange_ushort :
327
+ fn(obj : *(atomic_ushort), desired : u16, order : memory_order) -> u16,
328
+ __yo_atomic_compare_exchange_ushort :
329
+ fn(
330
+ obj : *(atomic_ushort),
331
+ expected : *(u16),
332
+ desired : u16,
333
+ success : memory_order,
334
+ failure : memory_order
335
+ ) -> bool,
336
+ __yo_atomic_load_uint :
337
+ fn(obj : *(atomic_uint), order : memory_order) -> u32,
338
+ __yo_atomic_store_uint :
339
+ fn(obj : *(atomic_uint), desired : u32, order : memory_order) -> unit,
340
+ __yo_atomic_exchange_uint :
341
+ fn(obj : *(atomic_uint), desired : u32, order : memory_order) -> u32,
342
+ __yo_atomic_compare_exchange_uint :
343
+ fn(
344
+ obj : *(atomic_uint),
345
+ expected : *(u32),
346
+ desired : u32,
347
+ success : memory_order,
348
+ failure : memory_order
349
+ ) -> bool,
350
+ __yo_atomic_load_ullong :
351
+ fn(obj : *(atomic_ullong), order : memory_order) -> u64,
352
+ __yo_atomic_store_ullong :
353
+ fn(obj : *(atomic_ullong), desired : u64, order : memory_order) -> unit,
354
+ __yo_atomic_exchange_ullong :
355
+ fn(obj : *(atomic_ullong), desired : u64, order : memory_order) -> u64,
356
+ __yo_atomic_compare_exchange_ullong :
357
+ fn(
358
+ obj : *(atomic_ullong),
359
+ expected : *(u64),
360
+ desired : u64,
361
+ success : memory_order,
362
+ failure : memory_order
363
+ ) -> bool,
364
+ __yo_atomic_load_ptrdiff :
365
+ fn(obj : *(atomic_ptrdiff_t), order : memory_order) -> isize,
366
+ __yo_atomic_store_ptrdiff :
367
+ fn(obj : *(atomic_ptrdiff_t), desired : isize, order : memory_order) -> unit,
368
+ __yo_atomic_exchange_ptrdiff :
369
+ fn(obj : *(atomic_ptrdiff_t), desired : isize, order : memory_order) -> isize,
370
+ __yo_atomic_compare_exchange_ptrdiff :
371
+ fn(
372
+ obj : *(atomic_ptrdiff_t),
373
+ expected : *(isize),
374
+ desired : isize,
375
+ success : memory_order,
376
+ failure : memory_order
377
+ ) -> bool
378
+ );
141
379
  export(
142
380
  // Atomic types
143
381
  atomic_bool,
@@ -238,5 +476,51 @@ export(
238
476
  ATOMIC_LLONG_LOCK_FREE,
239
477
  ATOMIC_POINTER_LOCK_FREE,
240
478
  // Kill dependency
241
- kill_dependency
479
+ kill_dependency,
480
+ // Phase C (THREAD_SAFETY): int-specific atomic wrappers
481
+ __yo_atomic_load_int,
482
+ __yo_atomic_store_int,
483
+ __yo_atomic_exchange_int,
484
+ __yo_atomic_compare_exchange_int,
485
+ // Phase C: size_t atomic wrappers
486
+ __yo_atomic_load_size_t,
487
+ __yo_atomic_store_size_t,
488
+ __yo_atomic_exchange_size_t,
489
+ __yo_atomic_compare_exchange_size_t,
490
+ // Phase C: llong atomic wrappers
491
+ __yo_atomic_load_llong,
492
+ __yo_atomic_store_llong,
493
+ __yo_atomic_exchange_llong,
494
+ __yo_atomic_compare_exchange_llong,
495
+ // Phase C: signed narrow atomics
496
+ __yo_atomic_load_schar,
497
+ __yo_atomic_store_schar,
498
+ __yo_atomic_exchange_schar,
499
+ __yo_atomic_compare_exchange_schar,
500
+ __yo_atomic_load_short,
501
+ __yo_atomic_store_short,
502
+ __yo_atomic_exchange_short,
503
+ __yo_atomic_compare_exchange_short,
504
+ // Phase C: unsigned atomics
505
+ __yo_atomic_load_uchar,
506
+ __yo_atomic_store_uchar,
507
+ __yo_atomic_exchange_uchar,
508
+ __yo_atomic_compare_exchange_uchar,
509
+ __yo_atomic_load_ushort,
510
+ __yo_atomic_store_ushort,
511
+ __yo_atomic_exchange_ushort,
512
+ __yo_atomic_compare_exchange_ushort,
513
+ __yo_atomic_load_uint,
514
+ __yo_atomic_store_uint,
515
+ __yo_atomic_exchange_uint,
516
+ __yo_atomic_compare_exchange_uint,
517
+ __yo_atomic_load_ullong,
518
+ __yo_atomic_store_ullong,
519
+ __yo_atomic_exchange_ullong,
520
+ __yo_atomic_compare_exchange_ullong,
521
+ // Phase C: isize
522
+ __yo_atomic_load_ptrdiff,
523
+ __yo_atomic_store_ptrdiff,
524
+ __yo_atomic_exchange_ptrdiff,
525
+ __yo_atomic_compare_exchange_ptrdiff
242
526
  );
package/std/prelude.yo CHANGED
@@ -59,7 +59,17 @@ Pragma :: enum(
59
59
  /// Test-runner directive: skip when target is wasm32-emscripten.
60
60
  SkipWasm32Emscripten,
61
61
  /// Test-runner directive: skip when target is wasm32-wasi.
62
- SkipWasm32Wasi
62
+ SkipWasm32Wasi,
63
+ /// Formal verification: contracts in this file are proof obligations.
64
+ /// Phase 0 only registers the pragma; later phases will hook in
65
+ /// verification. See plans/FORMAL_VERIFICATION.md.
66
+ Verify,
67
+ /// Formal verification: try to prove, fall back to runtime assert
68
+ /// when proof times out. The production mode for verified code.
69
+ VerifyOrAssert,
70
+ /// Formal verification: erase contract clauses entirely (no proof,
71
+ /// no runtime assert). For release/benchmark builds.
72
+ NoContracts
63
73
  );
64
74
  export(Pragma);
65
75
 
@@ -732,6 +742,13 @@ ComptimeToString :: trait(
732
742
  to_comptime_string : (fn(comptime(self) : Self) -> comptime(comptime_string)),
733
743
  where(Self <: Comptime)
734
744
  );
745
+ // SAFETY: All builtin primitive types (unit, void, comptime_int,
746
+ // comptime_float, comptime_string, bool, i8/i16/i32/i64, u8/u16/u32/u64,
747
+ // f32/f64, isize/usize, char/int/uint/short/ushort/long/ulong/longlong/
748
+ // ulonglong/longdouble) are plain value types with no heap allocations
749
+ // or thread-local state. They are trivially safe to send across threads
750
+ // and cannot form reference cycles. For these types, Send and Acyclic are
751
+ // structural properties of the underlying C types.
735
752
  // === Builtin types ===
736
753
  /// unit
737
754
  impl(unit, Acyclic());
@@ -5475,6 +5492,11 @@ impl(
5475
5492
  _longdouble :: longdouble;
5476
5493
  export(longdouble : _longdouble);
5477
5494
  /// Ptr
5495
+ // SAFETY: A raw pointer *(T) is Send only when the pointee T is Send —
5496
+ // the pointer itself is a plain value (an address), and Send implies
5497
+ // that any T reachable through it is safe to access from another thread.
5498
+ // *(T) is unconditionally Acyclic because raw pointers do not participate
5499
+ // in Yo's ARC reference-counting cycle analysis.
5478
5500
  impl(forall(T : Type), where(T <: Send), *(T), Send());
5479
5501
  impl(forall(T : Type), *(T), Acyclic());
5480
5502
  impl(forall(T : Type), where(T <: Comptime), *(T), Comptime());
@@ -5536,6 +5558,10 @@ impl(
5536
5558
  )
5537
5559
  );
5538
5560
  /// Array
5561
+ // SAFETY: Array(T, U) is a fixed-size array value type. It is Send when T
5562
+ // is Send because an array value is copied across threads (each thread
5563
+ // gets an independent copy). It is unconditionally Acyclic because arrays
5564
+ // are value-typed — they do not participate in ARC reference counting.
5539
5565
  impl(forall(T : Type, U : usize), where(T <: Send), Array(T, U), Send());
5540
5566
  impl(forall(T : Type, U : usize), Array(T, U), Acyclic());
5541
5567
  impl(forall(T : Type, U : usize), where(T <: Comptime), Array(T, U), Comptime());
@@ -5619,6 +5645,12 @@ impl(
5619
5645
  )
5620
5646
  );
5621
5647
  /// Slice
5648
+ // SAFETY: Slice(T) is a value-typed view (pointer + length) over a backing
5649
+ // array. Sending a slice across threads copies the header; both threads
5650
+ // can independently read the backing array. The backing array's lifetime
5651
+ // is managed by its owning collection (which must itself be Send to cross
5652
+ // threads). Slice is always Acyclic — it is a value type with no ARC.
5653
+ impl(forall(T : Type), where(T <: Send), Slice(T), Send());
5622
5654
  impl(forall(T : Type), Slice(T), Acyclic());
5623
5655
  impl(forall(T : Type), where(T <: Comptime), Slice(T), Comptime());
5624
5656
  impl(forall(T : Type), where(T <: Runtime), Slice(T), Runtime());
@@ -7499,13 +7531,21 @@ export(
7499
7531
  box
7500
7532
  );
7501
7533
  /// Iso — an isolated reference-counted value that can be sent across threads.
7534
+ // SAFETY: Iso(T) is unconditionally Send (no `T <: Send` bound) because
7535
+ // Iso's public API exposes no operation on the inner T except extract(),
7536
+ // which atomically verifies rc == 1 before returning. If you add any new
7537
+ // method to Iso(T) that touches the inner T (map, peek, read, &self
7538
+ // borrow, etc.), this Send claim becomes unsound and must be revoked.
7539
+ // See plans/THREAD_SAFETY.md "Iso(T) design notes — precedent and known
7540
+ // risks" for the full argument.
7502
7541
  impl(forall(T : Type), Iso(T), Send());
7503
7542
  impl(forall(T : Type), where(T <: Acyclic), Iso(T), Acyclic());
7504
7543
  impl(
7505
7544
  forall(T : Type),
7506
7545
  Iso(T),
7507
- /// Attempt to extract the inner value if this `Iso` holds the only reference.
7508
- extract : (fn(self : Self) -> Option(T))(
7546
+ /// Extract the inner value if this `Iso` holds the only reference.
7547
+ /// Panics if rc != 1 or if this Iso has already been extracted.
7548
+ extract : (fn(self : Self) -> T)(
7509
7549
  __yo_iso_extract(self)
7510
7550
  )
7511
7551
  );
@@ -7581,6 +7621,9 @@ Arc :: (fn(comptime(V) : Type, where(V <: (Send, Acyclic))) -> comptime(Type))(
7581
7621
  );
7582
7622
  /// Allocate a value inside an Arc, returning an `Arc(V)`.
7583
7623
  arc :: (fn(forall(V : Type), own(value) : V, where(V <: (Send, Acyclic))) -> Arc(V))(Arc(V)(value));
7624
+ // SAFETY: Arc(T) is an atomic reference-counted wrapper. It is Send when
7625
+ // the inner T is Send (all fields of the atomic-object must be Send per
7626
+ // auto-derive) and Acyclic (prevents permanent leaks from Arc cycles).
7584
7627
  impl(forall(T : Type), where(T <: (Send, Acyclic)), Arc(T), Send());
7585
7628
  export(Arc, arc);
7586
7629
  /// === MaybeUninit ===
@@ -8325,6 +8368,8 @@ FutureState :: enum(
8325
8368
  /// The future was aborted (e.g., via `unwind`).
8326
8369
  Aborted = -(2)
8327
8370
  );
8371
+ // SAFETY: FutureState is a plain enum of integer values (Pending, Done,
8372
+ // Aborted) with no heap allocations. It is trivially Send and Acyclic.
8328
8373
  impl(FutureState, Acyclic());
8329
8374
  impl(FutureState, Runtime());
8330
8375
  impl(FutureState, Send());
@@ -8345,6 +8390,10 @@ JoinHandle :: (fn(comptime(T) : Type) -> comptime(Type))(
8345
8390
  __future : *(T)
8346
8391
  )
8347
8392
  );
8393
+ // Phase L (THREAD_SAFETY): JoinHandle is NOT Send — the inner future state
8394
+ // machine lives on the spawner's event-loop thread. Cross-thread result
8395
+ // delivery uses Channel(T).
8396
+ impl(forall(T : Type), JoinHandle(T), !(Send()));
8348
8397
  export(JoinHandle);
8349
8398
  /// Io module — the async runtime effect.
8350
8399
  ///
@@ -8360,6 +8409,10 @@ Io :: struct(
8360
8409
  /// Spawn a `Future` as an independent task, returning a `JoinHandle`.
8361
8410
  spawn : (fn(forall(T : Type, E : Type.Struct), fut : Impl(Future(T, E)), e : E) -> JoinHandle(T))
8362
8411
  );
8412
+ // Phase L (THREAD_SAFETY): Io is NOT Send — the async runtime it represents
8413
+ // is per-thread (per AGENTS.md). Sending Io across a thread boundary would
8414
+ // reference a scheduler on the wrong thread.
8415
+ impl(Io, !(Send()));
8363
8416
  export(Io);
8364
8417
  extern(
8365
8418
  "Yo",
@@ -0,0 +1,30 @@
1
+ // Phase 0 of plans/FORMAL_VERIFICATION.md task #7.
2
+ //
3
+ // Numeric refinement aliases. All Phase 0 implementations are
4
+ // type aliases; the verifier (Phase 2+) will attach concrete
5
+ // predicates and enforce them.
6
+ { Refine } :: import("./refine.yo");
7
+
8
+ /// Even integer.
9
+ Even :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
10
+ export(Even);
11
+
12
+ /// Odd integer.
13
+ Odd :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
14
+ export(Odd);
15
+
16
+ /// Strictly positive value (> 0).
17
+ Positive :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
18
+ export(Positive);
19
+
20
+ /// Strictly negative value (< 0).
21
+ Negative :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
22
+ export(Negative);
23
+
24
+ /// Non-negative value (>= 0).
25
+ NonNegative :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
26
+ export(NonNegative);
27
+
28
+ /// Non-positive value (<= 0).
29
+ NonPositive :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
30
+ export(NonPositive);
@@ -0,0 +1,43 @@
1
+ // Phase 0 of plans/FORMAL_VERIFICATION.md task #7.
2
+ //
3
+ // `Refine`, `NonZero`, `Bounded` are comptime type constructors.
4
+ // In Phase 0 they all return their underlying type unchanged —
5
+ // effectively `Refine(T) = T`. The refinement predicate is
6
+ // documented as a future parameter; the verifier (Phase 2) will
7
+ // extend the surface to `Refine(T, predicate)` and enforce the
8
+ // predicate at construction sites.
9
+ //
10
+ // Even without enforcement, these aliases serve as
11
+ // human-and-LLM-readable signatures that signal intent. A function
12
+ // taking `denom : NonZero(i32)` documents the precondition; callers
13
+ // that want runtime enforcement can pair the alias with a
14
+ // `requires(denom != i32(0))` clause until the verifier lands.
15
+ /// A value of type `T` paired with a (compile-time) refinement
16
+ /// predicate. Phase 0 ignores the predicate; later phases will
17
+ /// require it as a second parameter and enforce it via
18
+ /// the SMT backend.
19
+ Refine :: (fn(comptime(T) : Type) -> comptime(Type))(T);
20
+ export(Refine);
21
+
22
+ /// `NonZero(T)` — values of `T` that are not zero. Phase 0 is a
23
+ /// type alias for `T`; future phases will enforce via verification.
24
+ NonZero :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
25
+ export(NonZero);
26
+
27
+ /// `Bounded(T, lo, hi)` — values of `T` in the closed range
28
+ /// `[lo, hi]`. Phase 0 is a type alias for `T`. T must be `Comptime`
29
+ /// so the bounds can be compile-time-known.
30
+ Bounded :: (
31
+ fn(
32
+ comptime(T) : Type,
33
+ comptime(_lo) : T,
34
+ comptime(_hi) : T,
35
+ where(T <: Comptime)
36
+ ) -> comptime(Type)
37
+ )(Refine(T));
38
+ export(Bounded);
39
+
40
+ /// `NonEmpty(T)` — collection types with at least one element.
41
+ /// Phase 0 is a type alias for `T`.
42
+ NonEmpty :: (fn(comptime(T) : Type) -> comptime(Type))(Refine(T));
43
+ export(NonEmpty);
@@ -1,4 +1,5 @@
1
1
  //! Unicode code point type (`rune`) for representing individual characters.
2
+ pragma(Pragma.AllowUnsafe);
2
3
  /// Unicode code point (U+0000 to U+10FFFF, excluding surrogates).
3
4
  /// Similar to Go's `rune` or Rust's `char`.
4
5
  rune :: newtype(
@@ -93,5 +94,8 @@ impl(
93
94
  (>=) : ((a, b) -> (a.char >= b.char))
94
95
  )
95
96
  );
97
+ // SAFETY: rune is a newtype over u32. u32 is a plain value type with no
98
+ // internal heap allocations or thread-local state — it is trivially safe
99
+ // to send across threads.
96
100
  impl(rune, Send());
97
101
  export(rune);