Scope and ownership
СсылкаThis page owns the concurrent forms, arm results, completion, failure, and timeout behavior.
Functions and generics owns calls. Blocks and control flow owns general control transfer. Bindings and scope owns captures and mutation. Failure and propagation owns language-level propagation. Thread and scheduler implementation details are outside this page.
The typed compilation path currently rejects timed groups as a whole. This applies to every timed group, including groups with no defer or using. Its contract and unsupported semantic-role path were inspected in source. No typed execution observation is attached here. The installed engine is assessed separately by the examples and the host handle reclamation limitation below.
Concurrent forms
СсылкаConcurrent = Join | Timed ;Join = "concurrent" "{" ArmSequence? "}" ;Timed = "concurrent" "(" "timeout" ":" Expression ")""{" ArmSequence? "}" "else" Block ;Arm = Identifier ":" Expression ;DurationLiteral = DecimalInteger DurationUnit ;DurationUnit = "ms" | "s" | "m" ;
This grammar imports separators, expression grouping, blocks, and decimal integer spelling from their language chapters. Arm names the arm sequence.
Named arm expressions
Each concurrent arm has the form name: expression, where name is an identifier.
Причина
Arm labels become record fields. The same name: value shape connects each computation to the field that will hold its result.
Concurrent groups may contain zero arms
A concurrent group may contain zero arms. An untimed empty group completes immediately with the zero-field structural record. Its type is written {} in type positions, and it is distinct from unit (). The ordinary empty expression block {} retains its unit result.
A timed empty group evaluates its Duration expression exactly once before the group, then follows the same deadline/completion arbitration as every timed group. A zero deadline selects the else block. The fallback must satisfy the same zero-field record result type. An untimed concurrent {} can supply that value.
Причина
Each concurrent arm contributes one named result field. With no arms, the result is the zero-field structural record, and an untimed group is already complete. The matching empty structural type can be written explicitly so adding a type annotation does not change which result is expressible. Timed empty groups retain the existing deadline priority, including a zero deadline.
Timeout and fallback appear together
The concurrent(timeout: . form requires an else block. An else block requires the timeout form. Either missing partner is rejected with TPZ2005.
Причина
A timed group can finish without a complete result record. A fallback supplies the value or control transfer for that path.
A timeout accepts a Duration expression
The timeout operand is an ordinary expression whose resolved type is Duration. Parentheses, bindings, calls, and conditionals obey the same expression and type rules. An int or float does not implicitly convert to Duration. An incompatible operand produces TPZ5001 during checking. Evaluate the operand exactly once, before starting its deadline or any arm. If that evaluation fails, propagate its original failure and location without starting an arm or evaluating the fallback. After it succeeds, start the deadline and apply the existing completion/deadline arbitration. A zero deadline wins even against immediately ready arms.
Причина
A duration keeps its value and type when it is parenthesized, bound to a name, returned from a function, or selected by an expression. Checking that value against Duration gives timeout one ordinary expression rule. Evaluating it once before the group starts prevents duplicated effects and keeps computing a budget outside the budget it establishes.
Arms and result fields
СсылкаDistinct arm names
Arm names in one concurrent expression must be distinct. A repeated arm name is rejected with TPZ5008.
Причина
Each arm supplies one result field. Repeated names would make that field ambiguous or silently discard an arm value.
The result record type
When the arm result types are known, a concurrent expression has a structural record type. Each arm name becomes a field name. Each field type is the widened type inferred for its arm expression.
Причина
Named fields preserve which computation produced each value regardless of completion order. Ordinary record access can then read the results.
Arm names, enclosing scope, and visible effects
Arms resolve enclosing names using the ordinary lexical rules. Names introduced inside an arm block stay in that block. Arm labels name result fields and do not introduce bindings. Start order, completion order, and interleaving of visible effects are unspecified. Read completed fields after the expression returns when output order matters.
Progress and effects when work is abandoned follow timed group progress.
Причина
Lexical scope gives enclosing names their usual meaning inside an arm. Scheduling remains independent of source order so arm placement does not promise effect order.
Each arm has its own control boundary
Each concurrent arm is an independent control boundary. A return or postfix ? cannot target a function outside the arm. A break or continue cannot target an outer loop. Missing arm-local function or unlabelled loop targets are rejected during checking with TPZ5001. A loop label without a target inside the arm is rejected during checking with TPZ5720. Functions called by the arm and loops introduced inside it consume their own control transfers.
An arm ends the search for enclosing return and loop targets. TPZ5001 already diagnoses a return or failure propagation without a function context, and unlabelled loop control without a loop context. TPZ5720 already diagnoses a label without an enclosing loop target. These existing diagnostics apply after the arm boundary removes outer targets from that search.
Причина
Each arm runs independently. Keeping control transfers inside its boundary avoids making sibling cancellation depend on a return or loop outside the arm.
Completion and failure
СсылкаCollect completed values
When every arm finishes successfully before any applicable timeout, the concurrent expression produces a record containing the named arm values.
Причина
A completed record must contain every declared field. Waiting for all arms prevents callers from receiving missing results.
Result values remain field values
An arm that completes with an ordinary Result value stores that value in its result field, preserving Ok(. or Err(.. The concurrent expression does not apply postfix propagation to that value.
Причина
Result variants are ordinary values until a program handles or propagates them. Preserving each variant keeps concurrency from adding implicit propagation.
An arm execution failure leaves the expression
If an arm reports an execution failure before the timeout is reached, that failure leaves the concurrent expression without evaluating its fallback. The same failure transfer applies to the form without a timeout.
Причина
The fallback handles an expired deadline. Using it for an arm fault would hide that failure and give the fallback two different meanings.
Evaluate the fallback after timeout
When the deadline is reached before all arms complete, or coincides with completion, unfinished arms are abandoned and collected result values are discarded. The concurrent expression then evaluates its else block.
Progress and effects when work is abandoned follow timed group progress.
The remaining defer blocks and using cleanup of an abandoned arm follow abandoned arm cleanup.
Причина
The fallback replaces the group result as a whole. Discarding collected values prevents the returned fields from depending on scheduling.
Deadline priority and competing faults
Timeout takes priority when reaching the deadline coincides with arm completion, including a zero-millisecond timeout. The else block determines the result in that case. When arm faults occur simultaneously, arm declaration order gives no fault priority.
Progress and effects when work is abandoned follow timed group progress.
The remaining defer blocks and using cleanup of an abandoned arm follow abandoned arm cleanup.
Причина
Giving the deadline priority makes a boundary case reproducible, including a zero timeout. Fault priority does not change when independent arms are reordered.
Timed group progress
A timed concurrent reaches its fallback after the deadline even when an arm cannot finish, including an infinite loop or deep recursion. A host call already in progress finishes without interruption and can delay group completion. An abandoned arm produces no effects after the group finishes. Effects that occurred before completion remain. A group without a timeout makes no fairness guarantee.
See timeout fallback, deadline races, and abandoned arm cleanup.
The remaining defer blocks and using cleanup of an abandoned arm follow abandoned arm cleanup.
Причина
A timeout must let a group finish even when an arm does not. Host calls finish as one operation. Untimed fairness would impose scheduling work on every program.
Deadline abandonment skips language cleanup
A concurrent arm abandoned by a deadline does not execute its remaining defer blocks or using cleanup. Normal block completion and structured exits through return, break, continue, or an Err from ? run language cleanup. Abandonment follows the same cleanup rule as an ordinary runtime fault. Cleanup performed by an arm that completed before the deadline remains observable. Host resource handles follow runtime reclamation.
Причина
Running cleanup after a deadline would execute more user code. Slow or nonterminating cleanup would break timed group progress. Running it would also require a separate cancellation path. Abandonment follows the runtime fault cleanup rule, giving both exits one cleanup behavior.
Runtime reclamation of abandoned arm handles
When the group finishes, the runtime reclaims host resource handles opened by an abandoned arm, such as File handles. This reclamation is performed by the runtime and does not execute the arm's remaining language cleanup.
Причина
Runtime reclamation releases host resources without running user cleanup after the deadline. This preserves timed group progress.
Duration and fallback values
СсылкаDuration units
Причина
A shared literal definition keeps timeout expressions consistent with ordinary expressions.
Duration literal bounds
Причина
Keeping literal bounds in one place prevents timeout syntax from acquiring a separate value range.
The fallback result type
When the arm result types are known, a value-producing fallback is checked against their record type. A fallback that terminates control flow is checked without that expected result type.
Причина
Successful completion and the fallback feed the same expression. Matching their record types lets callers use the result without testing which path completed.
Examples and expected checks
СсылкаRead both completed arm values
Ссылкаimport std.iolet joined = concurrent {first: 2second: 3}io.writeLine("{joined.first}")io.writeLine("{joined.second}")
2
3
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
23
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
23
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Keep an Err value in the result record
Ссылкаimport std.iofunction completeError() -> Result<int, string> {Err("missing")}let joined = concurrent {value: completeError()count: 7}match (joined.value) {case Ok(_) => io.writeLine("unexpected")case Err(message) => io.writeLine(message)}io.writeLine("{joined.count}")
missing
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
missing7
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
missing7
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Distinct arm names and result fields
Ссылкаlet joined = concurrent {first: 1second: 2}let first: int = joined.firstlet second: int = joined.second
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
A fallback with the corresponding result fields
Ссылкаlet joined = concurrent(timeout: 25ms) {count: 2 + 3label: "ready"} else {{ count: 0, label: "timeout" }}let count: int = joined.countlet label: string = joined.label
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
The three duration units
Ссылкаlet milliseconds = concurrent(timeout: 1ms) { value: 1 } else { { value: 0 } }let seconds = concurrent(timeout: 1s) { value: 1 } else { { value: 0 } }let minutes = concurrent(timeout: 1m) { value: 1 } else { { value: 0 } }
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
Нет стандартного вывода.
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
Repeated name in one concurrent expression
Ссылкаlet joined = concurrent {value: 1value: 2}
Нет стандартного вывода.error[TPZ5008]: duplicate concurrent arm `value`
--> example.tpz:3:5
|
3 | value: 2
| ^^^^^
example.tpz: 1 type diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
duplicate-concurrent-arm at
example.tpz:3:5
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ5008]: duplicate concurrent arm `value`--> example.tpz:3:5|3 | value: 2| ^^^^^example.tpz: 1 type diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ5008; cause duplicate-concurrent-arm; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
Timeout with no fallback block
Ссылкаlet joined = concurrent(timeout: 25ms) {count: 2 + 3label: "ready"}
Нет стандартного вывода.error[TPZ2005]: the `concurrent(timeout: ...)` form requires an `else` block
--> example.tpz:1:14
|
1 | let joined = concurrent(timeout: 25ms) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
example.tpz: 1 diagnostic
Ожидаемый результат
Ожидаемый результат
Этап отклонения parse. Ненулевой код завершения.
concurrent-timeout-without-else at
example.tpz:1:14
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 1.
Нет стандартного вывода.
error[TPZ2005]: the `concurrent(timeout: ...)` form requires an `else` block--> example.tpz:1:14|1 | let joined = concurrent(timeout: 25ms) {| ^^^^^^^^^^^^^^^^^^^^^^^^^^^example.tpz: 1 diagnostic
- Пройдено · expected nonzero; observed 1
- Пройдено · checking TPZ2005; cause concurrent-timeout-without-else; primary location asserted; additional diagnostics allow
- Пройдено · stdout matches the authored expectation
An untimed group may have no arms
Ссылкаlet joined = concurrent {}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
Arm blocks keep their own names and read the enclosing binding
Ссылкаimport std.iolet base: int = 10let joined = concurrent {first: {let branchLocal = base + 1branchLocal}second: {let branchLocal = base + 2branchLocal}}io.writeLine("{joined.first},{joined.second}")
11,12
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
11,12
An arm label does not bind a value
Ссылкаlet joined = concurrent {first: 1second: first}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-label-not-bound at
example.tpz:3:13
An arm block does not expose its local to a sibling
Ссылкаlet joined = concurrent {first: {let branchLocal = 1branchLocal}second: branchLocal}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-sibling-local-not-bound at
example.tpz:6:13
A noncompleting arm selects the timeout fallback
Ссылкаimport std.iofunction waitForever() -> int {while (true) {}0}let joined = concurrent(timeout: 0ms) {value: waitForever()} else {{ value: 7 }}io.writeLine("{joined.value}")
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
7
The arm cannot complete, so this example does not choose a rule for completion coinciding with a deadline. It expects the complete fallback record.
Called functions and inner loops consume their own control transfer
Ссылкаimport std.iofunction advance(value: Result<int, string>) -> Result<int, string> {let number: int = value?return Ok(number + 1)}let joined = concurrent {result: advance(Err("missing"))count: {let mut count = 0while (count < 3) {count += 1if (count < 3) { continue }break}count}}match (joined.result) {case Ok(_) => io.writeLine("unexpected")case Err(message) => io.writeLine(message)}io.writeLine("{joined.count}")
missing
3
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
missing3
Zero duration takes the fallback for one ready arm
Ссылкаimport std.iolet joined = concurrent(timeout: 0ms) {value: 1} else {{ value: 7 }}io.writeLine("{joined.value}")
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
7
Zero duration takes the complete fallback for multiple ready arms
Ссылкаimport std.iolet joined = concurrent(timeout: 0ms) {left: 1right: 2} else {{ left: 7, right: 8 }}io.writeLine("{joined.left}:{joined.right}")
7:8
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
7:8
A zero-duration fallback can raise its own runtime fault
Ссылкаfunction divide(divisor: int) -> int {42 / divisor}let joined = concurrent(timeout: 0ms) {value: 1} else {{ value: divide(0) }}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения run. Код завершения 1.
diagnostic-tpz4002 at
example.tpz:2:5
An arm cannot return from its enclosing function
Ссылкаfunction escape() -> int {let joined = concurrent {value: {return 1}}0}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-function-boundary at
example.tpz:4:13
An arm cannot break its enclosing loop
Ссылкаwhile (true) {let joined = concurrent {value: {break}}break}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-loop-boundary at
example.tpz:4:13
An arm cannot continue its enclosing loop
Ссылкаwhile (true) {let joined = concurrent {value: {continue}}break}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-loop-boundary at
example.tpz:4:13
An arm cannot propagate a Result to its enclosing function
Ссылкаfunction escape(value: Result<int, string>) -> Result<int, string> {let joined = concurrent {result: value?}Ok(0)}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-function-boundary at
example.tpz:3:17
An arm cannot break to an outer loop label
Ссылкаloop 'outer {let joined = concurrent {value: {loop {break 'outer}}}break}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-loop-label at
example.tpz:5:17
An arm cannot continue to an outer loop label
Ссылкаloop 'outer {let joined = concurrent {value: {loop {continue 'outer}}}break}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-arm-loop-label at
example.tpz:5:17
A function declared inside an arm consumes its own control transfers
Ссылкаimport std.iolet joined = concurrent {result: {function advance(value: Result<int, string>) -> Result<int, string> {let number: int = value?return Ok(number + 1)}advance(Ok(4))}}match (joined.result) {case Ok(value) => io.writeLine("{value}")case Err(message) => io.writeLine(message)}
5
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
5
Parentheses preserve a timeout value
Ссылкаimport std.iolet joined = concurrent(timeout: (0ms)) { value: 1 } else { { value: 7 } }io.writeLine("{joined.value}")
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
7
A bound Duration is the same timeout value
Ссылкаimport std.iolet budget: Duration = 0mslet joined = concurrent(timeout: budget) { value: 1 } else { { value: 7 } }io.writeLine("{joined.value}")
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
7
Evaluate the timeout once before any arm
Ссылкаimport std.iofunction budget() -> Duration {io.writeLine("budget")0ms}let joined = concurrent(timeout: budget()) {value: { io.writeLine("arm")1 }} else {io.writeLine("fallback"){ value: 7 }}io.writeLine("{joined.value}")
budget
fallback
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
budgetfallback7
The adopted zero-deadline rule selects the fallback before any arm. The budget marker occurs once and before fallback evaluation; no arm marker is permitted.
Functions and conditionals preserve Duration
Ссылкаfunction choose(first: bool) -> Duration { if (first) { 0ms } else { 1s } }let budget: Duration = choose(true)let joined = concurrent(timeout: if (true) { budget } else { 2m }) { value: 1 } else { { value: 7 } }
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
An integer does not implicitly become Duration
Ссылкаlet joined = concurrent(timeout: 1) { value: 1 } else { { value: 7 } }
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Код завершения 1.
concurrent-timeout-duration-type at
example.tpz:1:34
The target uses the existing expected-type mismatch identity. Current SELF rejects earlier with TPZ2001; that already-nonzero exit is not excused.
A timeout expression fault precedes the group
Ссылкаimport std.iofunction budget(divisor: int) -> Duration {io.writeLine("budget")let ratio = 42 / divisor0ms}let joined = concurrent(timeout: budget(0)) {value: { io.writeLine("arm")1 }} else {io.writeLine("fallback"){ value: 7 }}
budget
Ожидаемый результат
Ожидаемый результат
Этап отклонения run. Код завершения 1.
diagnostic-tpz4002 at
example.tpz:4:17
budget
An empty concurrent record passes through an explicit record signature
Ссылкаimport std.iofunction keep(value: {}) -> {} { value }let joined: {} = keep(concurrent {})io.writeLine("completed")
completed
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
completed
A zero deadline wins over empty-group completion
Ссылкаimport std.iofunction deadline() -> Duration { io.writeLine("timeout")0ms }let joined: {} = concurrent(timeout: deadline()) {} else {io.writeLine("fallback")concurrent {}}io.writeLine("completed")
timeout
fallback
completed
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
timeoutfallbackcompleted
The zero-field record is distinct from unit
Ссылкаlet joined: () = concurrent {}
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Этап отклонения check. Ненулевой код завершения.
concurrent-empty-result-is-not-unit at
example.tpz:1:18
Use the empty structural type in aliases, parameters, and results
Ссылкаtype Empty = {}function keep(value: Empty) -> {} { value }
Нет стандартного вывода.Ожидаемый результат
Ожидаемый результат
Проверка принимает программу. Код завершения 0.
A positive deadline ends an infinite loop
Ссылкаimport std.iolet joined = concurrent(timeout: 1ms) {value: {while (true) {}0}} else {io.writeLine("fallback"){ value: 7 }}io.writeLine("{joined.value}")
fallback
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
fallback7
An abandoned arm skips its registered defer
Ссылкаimport std.iolet joined = concurrent(timeout: 1ms) {value: {defer { io.writeLine("abandoned cleanup") }while (true) {}0}} else {io.writeLine("fallback"){ value: 7 }}
fallback
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
fallback
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
fallback
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
A normally completed arm runs its defer before the result
Ссылкаimport std.iolet joined = concurrent(timeout: 10s) {value: {defer { io.writeLine("completed cleanup") }7}} else {io.writeLine("fallback"){ value: 0 }}io.writeLine("{joined.value}")
completed cleanup
7
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
completed cleanup7
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
completed cleanup7
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
This example exercises an arm that completes before the deadline. Its defer output precedes the group result.
Completed cleanup followed by an abandoned arm
Ссылкаimport std.iolet completed = concurrent {value: {defer { io.writeLine("completed cleanup") }1}}let abandoned = concurrent(timeout: 1s) {value: {defer { io.writeLine("abandoned cleanup") }while (true) {}0}} else {io.writeLine("fallback"){ value: 0 }}
completed cleanup
fallback
Ожидаемый результат
Ожидаемый результат
Выполнение завершается. Код завершения 0.
completed cleanupfallback
Наблюдаемые утверждения · Пройдено · 5.21.3
Код завершения 0.
completed cleanupfallback
Нет вывода ошибок.
- Пройдено · expected 0; observed 0
- Пройдено · stdout matches the authored expectation
- Пройдено · stderr matches the authored expectation
The first group has no deadline and completes before the timed group starts. The second group abandons its nonterminating arm. Separate groups test completed cleanup and skipped abandoned cleanup without assuming any arm start or completion order.
Pending contracts
СсылкаRelated language and diagnostic references
СсылкаFunctions and generics defines the calls used by arms. Failure and propagation defines the language propagation form. Types, Bindings and scope, and Blocks and control flow own their respective general rules.
The diagnostic catalog owns complete diagnostic descriptions. The following entries are referenced here for the specific causes isolated by these examples.