본문으로 건너뛰기
토파즈6.0 · 출시 전
다운로드 →

문서 검색

명세 6.0

방향키로 결과를 고르고 Enter를 눌러 여세요.

API 이름, 진단 번호, 규칙 또는 프로젝트 주제를 입력하세요.

    언어 · 14장 · 19개 규칙

    동시성

    Write and check concurrent expressions with this reference. The examples cover result fields, duration spellings, and rejected forms.

    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

    링크
    EBNF
    1. Concurrent = Join | Timed ;
    2. Join = "concurrent" "{" ArmSequence? "}" ;
    3. Timed = "concurrent" "(" "timeout" ":" Expression ")"
    4. "{" ArmSequence? "}" "else" Block ;
    5. Arm = Identifier ":" Expression ;
    6. DurationLiteral = DecimalInteger DurationUnit ;
    7. DurationUnit = "ms" | "s" | "m" ;

    This grammar imports separators, expression grouping, blocks, and decimal integer spelling from their language chapters. ArmSequence names the arm sequence.

    규칙topaz.rule.concurrency.arm-form

    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.

    규칙topaz.rule.concurrency.nonempty-arms

    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.

    규칙topaz.rule.concurrency.timeout-pairing

    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.

    규칙topaz.rule.concurrency.timeout-literal

    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

    링크
    규칙topaz.rule.concurrency.arm-name-uniqueness

    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.

    규칙topaz.rule.concurrency.result-record

    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.

    규칙topaz.rule.concurrency.arm-scope-and-order

    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.

    규칙topaz.rule.concurrency.arm-control-boundary

    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

    링크
    규칙topaz.rule.concurrency.successful-completion

    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.

    규칙topaz.rule.concurrency.ordinary-result-values

    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.

    규칙topaz.rule.concurrency.execution-failure

    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.

    규칙topaz.rule.concurrency.timeout-fallback

    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.

    규칙topaz.rule.concurrency.deadline-race

    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.

    규칙topaz.rule.concurrency.timed-progress

    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.

    규칙topaz.rule.concurrency.abandoned-arm-cleanup

    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.

    규칙topaz.rule.concurrency.abandoned-arm-resources

    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

    링크
    규칙topaz.rule.concurrency.duration-conversion

    Duration units

    이유

    A shared literal definition keeps timeout expressions consistent with ordinary expressions.

    규칙topaz.rule.concurrency.duration-range

    Duration literal bounds

    이유

    Keeping literal bounds in one place prevents timeout syntax from acquiring a separate value range.

    규칙topaz.rule.concurrency.fallback-type

    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

    링크
    example.tpzRead both completed arm values플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent {
    3. first: 2
    4. second: 3
    5. }
    6. io.writeLine("{joined.first}")
    7. io.writeLine("{joined.second}")
    기록된 출력종료 코드 0
    2
    3
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 2
    2. 3
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. 2
    2. 3

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation

    Keep an Err value in the result record

    링크
    example.tpzKeep an Err value in the result record플레이그라운드 열기 →
    1. import std.io
    2. function completeError() -> Result<int, string> {
    3. Err("missing")
    4. }
    5. let joined = concurrent {
    6. value: completeError()
    7. count: 7
    8. }
    9. match (joined.value) {
    10. case Ok(_) => io.writeLine("unexpected")
    11. case Err(message) => io.writeLine(message)
    12. }
    13. io.writeLine("{joined.count}")
    기록된 출력종료 코드 0
    missing
    7
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. missing
    2. 7
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. missing
    2. 7

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation

    Distinct arm names and result fields

    링크
    example.tpzDistinct arm names and result fields플레이그라운드 열기 →
    1. let joined = concurrent {
    2. first: 1
    3. second: 2
    4. }
    5. let first: int = joined.first
    6. let second: int = joined.second
    기록된 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 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

    링크
    example.tpzA fallback with the corresponding result fields플레이그라운드 열기 →
    1. let joined = concurrent(timeout: 25ms) {
    2. count: 2 + 3
    3. label: "ready"
    4. } else {
    5. { count: 0, label: "timeout" }
    6. }
    7. let count: int = joined.count
    8. let label: string = joined.label
    기록된 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    표준 출력 없음.

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0
    • 통과 · stdout matches the authored expectation
    • 통과 · stderr matches the authored expectation

    The three duration units

    링크
    example.tpzThe three duration units플레이그라운드 열기 →
    1. let milliseconds = concurrent(timeout: 1ms) { value: 1 } else { { value: 0 } }
    2. let seconds = concurrent(timeout: 1s) { value: 1 } else { { value: 0 } }
    3. let minutes = concurrent(timeout: 1m) { value: 1 } else { { value: 0 } }
    기록된 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 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

    링크
    example.tpzRepeated name in one concurrent expression플레이그라운드 열기 →
    1. let joined = concurrent {
    2. value: 1
    3. value: 2
    4. }
    기록된 출력종료 코드 1
    표준 출력 없음.
    error[TPZ5008]: duplicate concurrent arm `value`
     --> example.tpz:3:5
      |
    3 |     value: 2
      |     ^^^^^
    
    example.tpz: 1 type diagnostic
    
    $ topaz check example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    관측한 단언 · 통과 · 5.21.3

    종료 코드 1.

    표준 출력 없음.

    관측한 표준 오류 출력
    1. error[TPZ5008]: duplicate concurrent arm `value`
    2. --> example.tpz:3:5
    3. |
    4. 3 | value: 2
    5. | ^^^^^
    6. 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

    링크
    example.tpzTimeout with no fallback block플레이그라운드 열기 →
    1. let joined = concurrent(timeout: 25ms) {
    2. count: 2 + 3
    3. label: "ready"
    4. }
    기록된 출력종료 코드 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
    
    $ topaz check example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    거절 단계 parse. 종료 코드가 0이 아닙니다.

    • TPZ2005 →

      concurrent-timeout-without-else at example.tpz:1:14

    관측한 단언 · 통과 · 5.21.3

    종료 코드 1.

    표준 출력 없음.

    관측한 표준 오류 출력
    1. error[TPZ2005]: the `concurrent(timeout: ...)` form requires an `else` block
    2. --> example.tpz:1:14
    3. |
    4. 1 | let joined = concurrent(timeout: 25ms) {
    5. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    6. 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

    링크
    example.tpzAn untimed group may have no arms플레이그라운드 열기 →
    1. let joined = concurrent {}
    기대 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    Arm blocks keep their own names and read the enclosing binding

    링크
    example.tpzArm blocks keep their own names and read the enclosing binding플레이그라운드 열기 →
    1. import std.io
    2. let base: int = 10
    3. let joined = concurrent {
    4. first: {
    5. let branchLocal = base + 1
    6. branchLocal
    7. }
    8. second: {
    9. let branchLocal = base + 2
    10. branchLocal
    11. }
    12. }
    13. io.writeLine("{joined.first},{joined.second}")
    기대 출력종료 코드 0
    11,12
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 11,12

    An arm label does not bind a value

    링크
    example.tpzAn arm label does not bind a value플레이그라운드 열기 →
    1. let joined = concurrent {
    2. first: 1
    3. second: first
    4. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5002 →

      concurrent-arm-label-not-bound at example.tpz:3:13

    An arm block does not expose its local to a sibling

    링크
    example.tpzAn arm block does not expose its local to a sibling플레이그라운드 열기 →
    1. let joined = concurrent {
    2. first: {
    3. let branchLocal = 1
    4. branchLocal
    5. }
    6. second: branchLocal
    7. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5002 →

      concurrent-sibling-local-not-bound at example.tpz:6:13

    A noncompleting arm selects the timeout fallback

    링크
    example.tpzA noncompleting arm selects the timeout fallback플레이그라운드 열기 →
    1. import std.io
    2. function waitForever() -> int {
    3. while (true) {}
    4. 0
    5. }
    6. let joined = concurrent(timeout: 0ms) {
    7. value: waitForever()
    8. } else {
    9. { value: 7 }
    10. }
    11. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 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

    링크
    example.tpzCalled functions and inner loops consume their own control transfer플레이그라운드 열기 →
    1. import std.io
    2. function advance(value: Result<int, string>) -> Result<int, string> {
    3. let number: int = value?
    4. return Ok(number + 1)
    5. }
    6. let joined = concurrent {
    7. result: advance(Err("missing"))
    8. count: {
    9. let mut count = 0
    10. while (count < 3) {
    11. count += 1
    12. if (count < 3) { continue }
    13. break
    14. }
    15. count
    16. }
    17. }
    18. match (joined.result) {
    19. case Ok(_) => io.writeLine("unexpected")
    20. case Err(message) => io.writeLine(message)
    21. }
    22. io.writeLine("{joined.count}")
    기대 출력종료 코드 0
    missing
    3
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. missing
    2. 3

    Zero duration takes the fallback for one ready arm

    링크
    example.tpzZero duration takes the fallback for one ready arm플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: 0ms) {
    3. value: 1
    4. } else {
    5. { value: 7 }
    6. }
    7. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7

    Zero duration takes the complete fallback for multiple ready arms

    링크
    example.tpzZero duration takes the complete fallback for multiple ready arms플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: 0ms) {
    3. left: 1
    4. right: 2
    5. } else {
    6. { left: 7, right: 8 }
    7. }
    8. io.writeLine("{joined.left}:{joined.right}")
    기대 출력종료 코드 0
    7:8
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7:8

    A zero-duration fallback can raise its own runtime fault

    링크
    example.tpzA zero-duration fallback can raise its own runtime fault플레이그라운드 열기 →
    1. function divide(divisor: int) -> int {
    2. 42 / divisor
    3. }
    4. let joined = concurrent(timeout: 0ms) {
    5. value: 1
    6. } else {
    7. { value: divide(0) }
    8. }
    기대 출력종료 코드 1
    표준 출력 없음.
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 run. 종료 코드 1.

    An arm cannot return from its enclosing function

    링크
    example.tpzAn arm cannot return from its enclosing function플레이그라운드 열기 →
    1. function escape() -> int {
    2. let joined = concurrent {
    3. value: {
    4. return 1
    5. }
    6. }
    7. 0
    8. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      concurrent-arm-function-boundary at example.tpz:4:13

    An arm cannot break its enclosing loop

    링크
    example.tpzAn arm cannot break its enclosing loop플레이그라운드 열기 →
    1. while (true) {
    2. let joined = concurrent {
    3. value: {
    4. break
    5. }
    6. }
    7. break
    8. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      concurrent-arm-loop-boundary at example.tpz:4:13

    An arm cannot continue its enclosing loop

    링크
    example.tpzAn arm cannot continue its enclosing loop플레이그라운드 열기 →
    1. while (true) {
    2. let joined = concurrent {
    3. value: {
    4. continue
    5. }
    6. }
    7. break
    8. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      concurrent-arm-loop-boundary at example.tpz:4:13

    An arm cannot propagate a Result to its enclosing function

    링크
    example.tpzAn arm cannot propagate a Result to its enclosing function플레이그라운드 열기 →
    1. function escape(value: Result<int, string>) -> Result<int, string> {
    2. let joined = concurrent {
    3. result: value?
    4. }
    5. Ok(0)
    6. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      concurrent-arm-function-boundary at example.tpz:3:17

    An arm cannot break to an outer loop label

    링크
    example.tpzAn arm cannot break to an outer loop label플레이그라운드 열기 →
    1. loop 'outer {
    2. let joined = concurrent {
    3. value: {
    4. loop {
    5. break 'outer
    6. }
    7. }
    8. }
    9. break
    10. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5720 →

      concurrent-arm-loop-label at example.tpz:5:17

    An arm cannot continue to an outer loop label

    링크
    example.tpzAn arm cannot continue to an outer loop label플레이그라운드 열기 →
    1. loop 'outer {
    2. let joined = concurrent {
    3. value: {
    4. loop {
    5. continue 'outer
    6. }
    7. }
    8. }
    9. break
    10. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5720 →

      concurrent-arm-loop-label at example.tpz:5:17

    A function declared inside an arm consumes its own control transfers

    링크
    example.tpzA function declared inside an arm consumes its own control transfers플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent {
    3. result: {
    4. function advance(value: Result<int, string>) -> Result<int, string> {
    5. let number: int = value?
    6. return Ok(number + 1)
    7. }
    8. advance(Ok(4))
    9. }
    10. }
    11. match (joined.result) {
    12. case Ok(value) => io.writeLine("{value}")
    13. case Err(message) => io.writeLine(message)
    14. }
    기대 출력종료 코드 0
    5
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 5

    Parentheses preserve a timeout value

    링크
    example.tpzParentheses preserve a timeout value플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: (0ms)) { value: 1 } else { { value: 7 } }
    3. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7

    A bound Duration is the same timeout value

    링크
    example.tpzA bound Duration is the same timeout value플레이그라운드 열기 →
    1. import std.io
    2. let budget: Duration = 0ms
    3. let joined = concurrent(timeout: budget) { value: 1 } else { { value: 7 } }
    4. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. 7

    Evaluate the timeout once before any arm

    링크
    example.tpzEvaluate the timeout once before any arm플레이그라운드 열기 →
    1. import std.io
    2. function budget() -> Duration {
    3. io.writeLine("budget")
    4. 0ms
    5. }
    6. let joined = concurrent(timeout: budget()) {
    7. value: { io.writeLine("arm")
    8. 1 }
    9. } else {
    10. io.writeLine("fallback")
    11. { value: 7 }
    12. }
    13. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    budget
    fallback
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. budget
    2. fallback
    3. 7

    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

    링크
    example.tpzFunctions and conditionals preserve Duration플레이그라운드 열기 →
    1. function choose(first: bool) -> Duration { if (first) { 0ms } else { 1s } }
    2. let budget: Duration = choose(true)
    3. let joined = concurrent(timeout: if (true) { budget } else { 2m }) { value: 1 } else { { value: 7 } }
    기대 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    An integer does not implicitly become Duration

    링크
    example.tpzAn integer does not implicitly become Duration플레이그라운드 열기 →
    1. let joined = concurrent(timeout: 1) { value: 1 } else { { value: 7 } }
    기대 출력종료 코드 1
    표준 출력 없음.
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드 1.

    • TPZ5001 →

      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

    링크
    example.tpzA timeout expression fault precedes the group플레이그라운드 열기 →
    1. import std.io
    2. function budget(divisor: int) -> Duration {
    3. io.writeLine("budget")
    4. let ratio = 42 / divisor
    5. 0ms
    6. }
    7. let joined = concurrent(timeout: budget(0)) {
    8. value: { io.writeLine("arm")
    9. 1 }
    10. } else {
    11. io.writeLine("fallback")
    12. { value: 7 }
    13. }
    기대 출력종료 코드 1
    budget
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 run. 종료 코드 1.

    기대 표준 출력
    1. budget

    An empty concurrent record passes through an explicit record signature

    링크
    example.tpzAn empty concurrent record passes through an explicit record signature플레이그라운드 열기 →
    1. import std.io
    2. function keep(value: {}) -> {} { value }
    3. let joined: {} = keep(concurrent {})
    4. io.writeLine("completed")
    기대 출력종료 코드 0
    completed
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. completed

    A zero deadline wins over empty-group completion

    링크
    example.tpzA zero deadline wins over empty-group completion플레이그라운드 열기 →
    1. import std.io
    2. function deadline() -> Duration { io.writeLine("timeout")
    3. 0ms }
    4. let joined: {} = concurrent(timeout: deadline()) {} else {
    5. io.writeLine("fallback")
    6. concurrent {}
    7. }
    8. io.writeLine("completed")
    기대 출력종료 코드 0
    timeout
    fallback
    completed
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. timeout
    2. fallback
    3. completed

    The zero-field record is distinct from unit

    링크
    example.tpzThe zero-field record is distinct from unit플레이그라운드 열기 →
    1. let joined: () = concurrent {}
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    거절 단계 check. 종료 코드가 0이 아닙니다.

    • TPZ5001 →

      concurrent-empty-result-is-not-unit at example.tpz:1:18

    Use the empty structural type in aliases, parameters, and results

    링크
    example.tpzUse the empty structural type in aliases, parameters, and results플레이그라운드 열기 →
    1. type Empty = {}
    2. function keep(value: Empty) -> {} { value }
    기대 출력종료 코드 0
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

    검사가 프로그램을 받아들입니다. 종료 코드 0.

    A positive deadline ends an infinite loop

    링크
    main.tpzA positive deadline ends an infinite loop플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: 1ms) {
    3. value: {
    4. while (true) {}
    5. 0
    6. }
    7. } else {
    8. io.writeLine("fallback")
    9. { value: 7 }
    10. }
    11. io.writeLine("{joined.value}")
    기대 출력종료 코드 0
    fallback
    7
    
    $ topaz run main.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. fallback
    2. 7

    An abandoned arm skips its registered defer

    링크
    main.tpzAn abandoned arm skips its registered defer플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: 1ms) {
    3. value: {
    4. defer { io.writeLine("abandoned cleanup") }
    5. while (true) {}
    6. 0
    7. }
    8. } else {
    9. io.writeLine("fallback")
    10. { value: 7 }
    11. }
    기록된 출력종료 코드 0
    fallback
    
    $ topaz run main.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. fallback
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. 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

    링크
    main.tpzA normally completed arm runs its defer before the result플레이그라운드 열기 →
    1. import std.io
    2. let joined = concurrent(timeout: 10s) {
    3. value: {
    4. defer { io.writeLine("completed cleanup") }
    5. 7
    6. }
    7. } else {
    8. io.writeLine("fallback")
    9. { value: 0 }
    10. }
    11. io.writeLine("{joined.value}")
    기록된 출력종료 코드 0
    completed cleanup
    7
    
    $ topaz run main.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. completed cleanup
    2. 7
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. completed cleanup
    2. 7

    표준 오류 출력 없음.

    • 통과 · 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

    링크
    main.tpzCompleted cleanup followed by an abandoned arm플레이그라운드 열기 →
    1. import std.io
    2. let completed = concurrent {
    3. value: {
    4. defer { io.writeLine("completed cleanup") }
    5. 1
    6. }
    7. }
    8. let abandoned = concurrent(timeout: 1s) {
    9. value: {
    10. defer { io.writeLine("abandoned cleanup") }
    11. while (true) {}
    12. 0
    13. }
    14. } else {
    15. io.writeLine("fallback")
    16. { value: 0 }
    17. }
    기록된 출력종료 코드 0
    completed cleanup
    fallback
    
    $ topaz run main.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

    실행을 마칩니다. 종료 코드 0.

    기대 표준 출력
    1. completed cleanup
    2. fallback
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. completed cleanup
    2. fallback

    표준 오류 출력 없음.

    • 통과 · 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.

    Unbound name →

    Unexpected token →

    Malformed concurrent form →

    Redeclaration →

    TPZ5001 →

    Division or remainder by zero →

    Unknown loop label →

    메뉴

    다운로드 →