@shd101wyy/yo 0.1.30 → 0.1.31
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/out/cjs/index.cjs +633 -474
- package/out/cjs/yo-cli.cjs +910 -751
- package/out/cjs/yo-lsp.cjs +849 -690
- package/out/esm/index.mjs +752 -593
- package/out/types/src/codegen/index.d.ts +1 -1
- package/out/types/src/compiler-utils.d.ts +1 -1
- package/out/types/src/evaluator/utils/closure.d.ts +2 -1
- package/out/types/src/evaluator/utils.d.ts +3 -0
- package/out/types/src/evaluator/values/impl.d.ts +14 -0
- package/out/types/src/tests/thread-safety-codegen.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/build.yo +5 -2
- package/std/imm/list.yo +1 -1
- package/std/imm/sorted_map.yo +1 -1
- package/std/libc/stdatomic.yo +250 -1
- package/std/prelude.yo +45 -2
- package/std/string/rune.yo +4 -0
- package/std/sync/atomic.yo +557 -0
- package/std/sync/channel.yo +57 -42
- package/std/sync/cond.yo +7 -3
- package/std/sync/mutex.yo +75 -15
- package/std/sync/once.yo +25 -19
- package/std/sync/rwlock.yo +18 -15
- package/std/sync/waitgroup.yo +25 -16
package/package.json
CHANGED
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());
|
package/std/imm/sorted_map.yo
CHANGED
|
@@ -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());
|
package/std/libc/stdatomic.yo
CHANGED
|
@@ -138,6 +138,209 @@ 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(obj : *(atomic_schar), expected : *(i8), desired : i8,
|
|
288
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
289
|
+
__yo_atomic_load_short :
|
|
290
|
+
fn(obj : *(atomic_short), order : memory_order) -> i16,
|
|
291
|
+
__yo_atomic_store_short :
|
|
292
|
+
fn(obj : *(atomic_short), desired : i16, order : memory_order) -> unit,
|
|
293
|
+
__yo_atomic_exchange_short :
|
|
294
|
+
fn(obj : *(atomic_short), desired : i16, order : memory_order) -> i16,
|
|
295
|
+
__yo_atomic_compare_exchange_short :
|
|
296
|
+
fn(obj : *(atomic_short), expected : *(i16), desired : i16,
|
|
297
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
298
|
+
__yo_atomic_load_uchar :
|
|
299
|
+
fn(obj : *(atomic_uchar), order : memory_order) -> u8,
|
|
300
|
+
__yo_atomic_store_uchar :
|
|
301
|
+
fn(obj : *(atomic_uchar), desired : u8, order : memory_order) -> unit,
|
|
302
|
+
__yo_atomic_exchange_uchar :
|
|
303
|
+
fn(obj : *(atomic_uchar), desired : u8, order : memory_order) -> u8,
|
|
304
|
+
__yo_atomic_compare_exchange_uchar :
|
|
305
|
+
fn(obj : *(atomic_uchar), expected : *(u8), desired : u8,
|
|
306
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
307
|
+
__yo_atomic_load_ushort :
|
|
308
|
+
fn(obj : *(atomic_ushort), order : memory_order) -> u16,
|
|
309
|
+
__yo_atomic_store_ushort :
|
|
310
|
+
fn(obj : *(atomic_ushort), desired : u16, order : memory_order) -> unit,
|
|
311
|
+
__yo_atomic_exchange_ushort :
|
|
312
|
+
fn(obj : *(atomic_ushort), desired : u16, order : memory_order) -> u16,
|
|
313
|
+
__yo_atomic_compare_exchange_ushort :
|
|
314
|
+
fn(obj : *(atomic_ushort), expected : *(u16), desired : u16,
|
|
315
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
316
|
+
__yo_atomic_load_uint :
|
|
317
|
+
fn(obj : *(atomic_uint), order : memory_order) -> u32,
|
|
318
|
+
__yo_atomic_store_uint :
|
|
319
|
+
fn(obj : *(atomic_uint), desired : u32, order : memory_order) -> unit,
|
|
320
|
+
__yo_atomic_exchange_uint :
|
|
321
|
+
fn(obj : *(atomic_uint), desired : u32, order : memory_order) -> u32,
|
|
322
|
+
__yo_atomic_compare_exchange_uint :
|
|
323
|
+
fn(obj : *(atomic_uint), expected : *(u32), desired : u32,
|
|
324
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
325
|
+
__yo_atomic_load_ullong :
|
|
326
|
+
fn(obj : *(atomic_ullong), order : memory_order) -> u64,
|
|
327
|
+
__yo_atomic_store_ullong :
|
|
328
|
+
fn(obj : *(atomic_ullong), desired : u64, order : memory_order) -> unit,
|
|
329
|
+
__yo_atomic_exchange_ullong :
|
|
330
|
+
fn(obj : *(atomic_ullong), desired : u64, order : memory_order) -> u64,
|
|
331
|
+
__yo_atomic_compare_exchange_ullong :
|
|
332
|
+
fn(obj : *(atomic_ullong), expected : *(u64), desired : u64,
|
|
333
|
+
success : memory_order, failure : memory_order) -> bool,
|
|
334
|
+
__yo_atomic_load_ptrdiff :
|
|
335
|
+
fn(obj : *(atomic_ptrdiff_t), order : memory_order) -> isize,
|
|
336
|
+
__yo_atomic_store_ptrdiff :
|
|
337
|
+
fn(obj : *(atomic_ptrdiff_t), desired : isize, order : memory_order) -> unit,
|
|
338
|
+
__yo_atomic_exchange_ptrdiff :
|
|
339
|
+
fn(obj : *(atomic_ptrdiff_t), desired : isize, order : memory_order) -> isize,
|
|
340
|
+
__yo_atomic_compare_exchange_ptrdiff :
|
|
341
|
+
fn(obj : *(atomic_ptrdiff_t), expected : *(isize), desired : isize,
|
|
342
|
+
success : memory_order, failure : memory_order) -> bool
|
|
343
|
+
);
|
|
141
344
|
export(
|
|
142
345
|
// Atomic types
|
|
143
346
|
atomic_bool,
|
|
@@ -238,5 +441,51 @@ export(
|
|
|
238
441
|
ATOMIC_LLONG_LOCK_FREE,
|
|
239
442
|
ATOMIC_POINTER_LOCK_FREE,
|
|
240
443
|
// Kill dependency
|
|
241
|
-
kill_dependency
|
|
444
|
+
kill_dependency,
|
|
445
|
+
// Phase C (THREAD_SAFETY): int-specific atomic wrappers
|
|
446
|
+
__yo_atomic_load_int,
|
|
447
|
+
__yo_atomic_store_int,
|
|
448
|
+
__yo_atomic_exchange_int,
|
|
449
|
+
__yo_atomic_compare_exchange_int,
|
|
450
|
+
// Phase C: size_t atomic wrappers
|
|
451
|
+
__yo_atomic_load_size_t,
|
|
452
|
+
__yo_atomic_store_size_t,
|
|
453
|
+
__yo_atomic_exchange_size_t,
|
|
454
|
+
__yo_atomic_compare_exchange_size_t,
|
|
455
|
+
// Phase C: llong atomic wrappers
|
|
456
|
+
__yo_atomic_load_llong,
|
|
457
|
+
__yo_atomic_store_llong,
|
|
458
|
+
__yo_atomic_exchange_llong,
|
|
459
|
+
__yo_atomic_compare_exchange_llong,
|
|
460
|
+
// Phase C: signed narrow atomics
|
|
461
|
+
__yo_atomic_load_schar,
|
|
462
|
+
__yo_atomic_store_schar,
|
|
463
|
+
__yo_atomic_exchange_schar,
|
|
464
|
+
__yo_atomic_compare_exchange_schar,
|
|
465
|
+
__yo_atomic_load_short,
|
|
466
|
+
__yo_atomic_store_short,
|
|
467
|
+
__yo_atomic_exchange_short,
|
|
468
|
+
__yo_atomic_compare_exchange_short,
|
|
469
|
+
// Phase C: unsigned atomics
|
|
470
|
+
__yo_atomic_load_uchar,
|
|
471
|
+
__yo_atomic_store_uchar,
|
|
472
|
+
__yo_atomic_exchange_uchar,
|
|
473
|
+
__yo_atomic_compare_exchange_uchar,
|
|
474
|
+
__yo_atomic_load_ushort,
|
|
475
|
+
__yo_atomic_store_ushort,
|
|
476
|
+
__yo_atomic_exchange_ushort,
|
|
477
|
+
__yo_atomic_compare_exchange_ushort,
|
|
478
|
+
__yo_atomic_load_uint,
|
|
479
|
+
__yo_atomic_store_uint,
|
|
480
|
+
__yo_atomic_exchange_uint,
|
|
481
|
+
__yo_atomic_compare_exchange_uint,
|
|
482
|
+
__yo_atomic_load_ullong,
|
|
483
|
+
__yo_atomic_store_ullong,
|
|
484
|
+
__yo_atomic_exchange_ullong,
|
|
485
|
+
__yo_atomic_compare_exchange_ullong,
|
|
486
|
+
// Phase C: isize
|
|
487
|
+
__yo_atomic_load_ptrdiff,
|
|
488
|
+
__yo_atomic_store_ptrdiff,
|
|
489
|
+
__yo_atomic_exchange_ptrdiff,
|
|
490
|
+
__yo_atomic_compare_exchange_ptrdiff
|
|
242
491
|
);
|
package/std/prelude.yo
CHANGED
|
@@ -732,6 +732,13 @@ ComptimeToString :: trait(
|
|
|
732
732
|
to_comptime_string : (fn(comptime(self) : Self) -> comptime(comptime_string)),
|
|
733
733
|
where(Self <: Comptime)
|
|
734
734
|
);
|
|
735
|
+
// SAFETY: All builtin primitive types (unit, void, comptime_int,
|
|
736
|
+
// comptime_float, comptime_string, bool, i8/i16/i32/i64, u8/u16/u32/u64,
|
|
737
|
+
// f32/f64, isize/usize, char/int/uint/short/ushort/long/ulong/longlong/
|
|
738
|
+
// ulonglong/longdouble) are plain value types with no heap allocations
|
|
739
|
+
// or thread-local state. They are trivially safe to send across threads
|
|
740
|
+
// and cannot form reference cycles. For these types, Send and Acyclic are
|
|
741
|
+
// structural properties of the underlying C types.
|
|
735
742
|
// === Builtin types ===
|
|
736
743
|
/// unit
|
|
737
744
|
impl(unit, Acyclic());
|
|
@@ -5475,6 +5482,11 @@ impl(
|
|
|
5475
5482
|
_longdouble :: longdouble;
|
|
5476
5483
|
export(longdouble : _longdouble);
|
|
5477
5484
|
/// Ptr
|
|
5485
|
+
// SAFETY: A raw pointer *(T) is Send only when the pointee T is Send —
|
|
5486
|
+
// the pointer itself is a plain value (an address), and Send implies
|
|
5487
|
+
// that any T reachable through it is safe to access from another thread.
|
|
5488
|
+
// *(T) is unconditionally Acyclic because raw pointers do not participate
|
|
5489
|
+
// in Yo's ARC reference-counting cycle analysis.
|
|
5478
5490
|
impl(forall(T : Type), where(T <: Send), *(T), Send());
|
|
5479
5491
|
impl(forall(T : Type), *(T), Acyclic());
|
|
5480
5492
|
impl(forall(T : Type), where(T <: Comptime), *(T), Comptime());
|
|
@@ -5536,6 +5548,10 @@ impl(
|
|
|
5536
5548
|
)
|
|
5537
5549
|
);
|
|
5538
5550
|
/// Array
|
|
5551
|
+
// SAFETY: Array(T, U) is a fixed-size array value type. It is Send when T
|
|
5552
|
+
// is Send because an array value is copied across threads (each thread
|
|
5553
|
+
// gets an independent copy). It is unconditionally Acyclic because arrays
|
|
5554
|
+
// are value-typed — they do not participate in ARC reference counting.
|
|
5539
5555
|
impl(forall(T : Type, U : usize), where(T <: Send), Array(T, U), Send());
|
|
5540
5556
|
impl(forall(T : Type, U : usize), Array(T, U), Acyclic());
|
|
5541
5557
|
impl(forall(T : Type, U : usize), where(T <: Comptime), Array(T, U), Comptime());
|
|
@@ -5619,6 +5635,12 @@ impl(
|
|
|
5619
5635
|
)
|
|
5620
5636
|
);
|
|
5621
5637
|
/// Slice
|
|
5638
|
+
// SAFETY: Slice(T) is a value-typed view (pointer + length) over a backing
|
|
5639
|
+
// array. Sending a slice across threads copies the header; both threads
|
|
5640
|
+
// can independently read the backing array. The backing array's lifetime
|
|
5641
|
+
// is managed by its owning collection (which must itself be Send to cross
|
|
5642
|
+
// threads). Slice is always Acyclic — it is a value type with no ARC.
|
|
5643
|
+
impl(forall(T : Type), where(T <: Send), Slice(T), Send());
|
|
5622
5644
|
impl(forall(T : Type), Slice(T), Acyclic());
|
|
5623
5645
|
impl(forall(T : Type), where(T <: Comptime), Slice(T), Comptime());
|
|
5624
5646
|
impl(forall(T : Type), where(T <: Runtime), Slice(T), Runtime());
|
|
@@ -7499,13 +7521,21 @@ export(
|
|
|
7499
7521
|
box
|
|
7500
7522
|
);
|
|
7501
7523
|
/// Iso — an isolated reference-counted value that can be sent across threads.
|
|
7524
|
+
// SAFETY: Iso(T) is unconditionally Send (no `T <: Send` bound) because
|
|
7525
|
+
// Iso's public API exposes no operation on the inner T except extract(),
|
|
7526
|
+
// which atomically verifies rc == 1 before returning. If you add any new
|
|
7527
|
+
// method to Iso(T) that touches the inner T (map, peek, read, &self
|
|
7528
|
+
// borrow, etc.), this Send claim becomes unsound and must be revoked.
|
|
7529
|
+
// See plans/THREAD_SAFETY.md "Iso(T) design notes — precedent and known
|
|
7530
|
+
// risks" for the full argument.
|
|
7502
7531
|
impl(forall(T : Type), Iso(T), Send());
|
|
7503
7532
|
impl(forall(T : Type), where(T <: Acyclic), Iso(T), Acyclic());
|
|
7504
7533
|
impl(
|
|
7505
7534
|
forall(T : Type),
|
|
7506
7535
|
Iso(T),
|
|
7507
|
-
///
|
|
7508
|
-
|
|
7536
|
+
/// Extract the inner value if this `Iso` holds the only reference.
|
|
7537
|
+
/// Panics if rc != 1 or if this Iso has already been extracted.
|
|
7538
|
+
extract : (fn(self : Self) -> T)(
|
|
7509
7539
|
__yo_iso_extract(self)
|
|
7510
7540
|
)
|
|
7511
7541
|
);
|
|
@@ -7581,6 +7611,9 @@ Arc :: (fn(comptime(V) : Type, where(V <: (Send, Acyclic))) -> comptime(Type))(
|
|
|
7581
7611
|
);
|
|
7582
7612
|
/// Allocate a value inside an Arc, returning an `Arc(V)`.
|
|
7583
7613
|
arc :: (fn(forall(V : Type), own(value) : V, where(V <: (Send, Acyclic))) -> Arc(V))(Arc(V)(value));
|
|
7614
|
+
// SAFETY: Arc(T) is an atomic reference-counted wrapper. It is Send when
|
|
7615
|
+
// the inner T is Send (all fields of the atomic-object must be Send per
|
|
7616
|
+
// auto-derive) and Acyclic (prevents permanent leaks from Arc cycles).
|
|
7584
7617
|
impl(forall(T : Type), where(T <: (Send, Acyclic)), Arc(T), Send());
|
|
7585
7618
|
export(Arc, arc);
|
|
7586
7619
|
/// === MaybeUninit ===
|
|
@@ -8325,6 +8358,8 @@ FutureState :: enum(
|
|
|
8325
8358
|
/// The future was aborted (e.g., via `unwind`).
|
|
8326
8359
|
Aborted = -(2)
|
|
8327
8360
|
);
|
|
8361
|
+
// SAFETY: FutureState is a plain enum of integer values (Pending, Done,
|
|
8362
|
+
// Aborted) with no heap allocations. It is trivially Send and Acyclic.
|
|
8328
8363
|
impl(FutureState, Acyclic());
|
|
8329
8364
|
impl(FutureState, Runtime());
|
|
8330
8365
|
impl(FutureState, Send());
|
|
@@ -8345,6 +8380,10 @@ JoinHandle :: (fn(comptime(T) : Type) -> comptime(Type))(
|
|
|
8345
8380
|
__future : *(T)
|
|
8346
8381
|
)
|
|
8347
8382
|
);
|
|
8383
|
+
// Phase L (THREAD_SAFETY): JoinHandle is NOT Send — the inner future state
|
|
8384
|
+
// machine lives on the spawner's event-loop thread. Cross-thread result
|
|
8385
|
+
// delivery uses Channel(T).
|
|
8386
|
+
impl(forall(T : Type), JoinHandle(T), !(Send()));
|
|
8348
8387
|
export(JoinHandle);
|
|
8349
8388
|
/// Io module — the async runtime effect.
|
|
8350
8389
|
///
|
|
@@ -8360,6 +8399,10 @@ Io :: struct(
|
|
|
8360
8399
|
/// Spawn a `Future` as an independent task, returning a `JoinHandle`.
|
|
8361
8400
|
spawn : (fn(forall(T : Type, E : Type.Struct), fut : Impl(Future(T, E)), e : E) -> JoinHandle(T))
|
|
8362
8401
|
);
|
|
8402
|
+
// Phase L (THREAD_SAFETY): Io is NOT Send — the async runtime it represents
|
|
8403
|
+
// is per-thread (per AGENTS.md). Sending Io across a thread boundary would
|
|
8404
|
+
// reference a scheduler on the wrong thread.
|
|
8405
|
+
impl(Io, !(Send()));
|
|
8363
8406
|
export(Io);
|
|
8364
8407
|
extern(
|
|
8365
8408
|
"Yo",
|
package/std/string/rune.yo
CHANGED
|
@@ -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);
|