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

문서 검색

명세 6.0

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

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

    언어 · 9장 · 12개 규칙

    패턴 매칭

    Defines patterns, matching, and accepted matches.

    Definition and scope

    링크

    A pattern describes a value to recognize and the names to bind from it. A match expression selects a case by applying a pattern and, when present, a guard.

    This page owns pattern syntax, case selection, and the checking rules stated below. The execution of if let and while let, including their branches and repetition, belongs to Blocks and control flow. Collection construction, nominal declarations, and general name resolution belong to their respective Language pages.

    This page defines source-order selection, exhaustive matches, and checking of unreachable cases. Each example states its expected result independently of recorded observations.

    Syntax

    링크
    EBNF
    1. Pattern = PrimaryPattern ("|" PrimaryPattern)* ;
    2. PrimaryPattern =
    3. "_" | Identifier | Literal | ConstructorPattern | ListPattern
    4. | RecordPattern | NominalRecordPattern | TypedPattern | RangePattern ;
    5. ConstructorPattern =
    6. Identifier "(" (Pattern ("," Pattern)* ","?)? ")" ;
    7. ListPattern = "[" (ListElement ("," ListElement)* ","?)? "]" ;
    8. ListElement = Pattern | ".." Pattern ;
    9. RecordPattern = "{" FieldPattern ("," FieldPattern)* ","? "}" ;
    10. FieldPattern = FieldName ":" Pattern ;
    11. NominalRecordPattern = Identifier RecordPattern ;
    12. TypedPattern = Identifier ":" Type ;
    13. RangePattern = "(" RangeEndpoint (".." | "..<") RangeEndpoint ")" ;

    This is a hand-transcribed source grammar excerpt. Type includes the type parser's own alternatives; the excerpt does not settle every interaction between a type annotation and an or-pattern. RangeEndpoint imports the expression subset accepted at a range-pattern boundary.

    The grammar defines pattern syntax. Scrutinee types, constructor arity, binding rules, and unresolved rest boundaries also affect valid programs.

    EBNF
    1. MatchShape = "match" "(" Expression ")" "{" CaseShape+ "}" ;
    2. CaseShape = "case" Pattern ("if" "(" Expression ")")? "=>" CaseBody ;
    3. CaseBody = Expression ;

    The + requires at least one case. This shape excerpt omits case separators and expression/block disambiguation. A case body is an expression, which may be a block expression. Write a return statement inside that block. Its transfer and cleanup follow Blocks and control flow.

    Pattern forms

    링크

    The table is a syntax index for the grammar excerpt. Its spellings are fragments, not separately executed programs. Constructor argument lists identify constructor patterns. A bare name attempts to bind, subject to the constructor-name collision rule.

    Pattern formRepresentative spelling
    Bindingname
    Wildcard_
    Literal0, true, "ready", ()
    ConstructorSome(item), None(), Empty(), Tag(payload)
    List[first, second], [head, ..tail]
    Rest within a list.._, ..tail
    Structural record{ x: x, y: other }
    Nominal recordPoint { x: x, y: y }
    Or-pattern1 \| 2
    Integer range(0 .. 9), (0 ..< 10)
    Typed bindingitem: int
    규칙topaz.rule.pattern-matching.forms

    Pattern forms and name interpretation

    The pattern forms are binding, wildcard, literal, constructor, list, record, nominal-record, or, range, typed. Rest patterns appear in list patterns. A record pattern has at least 1 field. Each field uses field: pattern. A field without a colon and pattern is rejected with TPZ2001 during parsing.

    Every constructor pattern has an argument list. A constructor with no payload uses Name(), including None(). List-element bindings have the array element type, and a rest binding has an array type.

    이유

    A shorthand field and an explicit mapping to the same name both bind that field value under that name. Explicit field mappings preserve this intent and use the same syntax for renaming and nested patterns. Pattern bindings preserve each field type.

    Use Name(...) to test a constructor and a fresh name or _ to capture or ignore the whole value. A bare constructor name is rejected instead of becoming a catch-all.

    규칙topaz.rule.pattern-matching.constructor-spelling

    Constructor syntax and binding names

    Write Name(patterns) in every pattern position. The payload list has the declared arity. A zero-payload constructor uses Name(), including None() and user enum variants such as Empty(). Nesting does not change this syntax. Parenthesized patterns with the wrong payload count retain the existing constructor-arity diagnostic.

    Write Name(arguments) in every value position at every arity. Constructor calls use None(), Empty(), or Some(value). Qualified enum construction uses the same argument list, as in Choice.Empty(). The grammar rejects a bare prelude None value. User enum constructor names are resolved and checked after parsing.

    A bare identifier in a pattern attempts to bind a new name. Its capitalization never selects a constructor role. A typed binding uses the same name rule.

    The constructor namespace includes prelude constructors, visible declarations and imports, and variants obtained from the known expected type after resolving aliases. A pattern binder that has the same identifier as one of those constructors is rejected with TPZ5712. This check applies at every nested pattern, to typed binders, and to constructors of another visible type. A value binding does not hide a constructor for this check. Choose a fresh name to capture the value or use _ to ignore it.

    None is already a reserved binding name. Without the constructor argument list it is rejected during parsing with TPZ2012. Other bare constructor names reach the namespace check. A removed bare enum pattern is never widened into a catch-all.

    이유

    Bare and parenthesized nullary constructors denote the same variant without a payload. Parentheses preserve that construction or matching intent and identify constructors at every arity. A bare pattern name attempts to bind. Rejecting constructor-name collisions prevents a former tag test from silently becoming a catch-all. Capitalization, type annotations, nesting, and value shadowing do not change this rule.

    Selecting a case

    링크
    규칙topaz.rule.pattern-matching.selection

    Case selection and guards

    A match has at least one case and evaluates its scrutinee once. It tries cases in source order and tests the pattern of each case in turn. After a pattern succeeds it installs the bindings and evaluates the guard once if present. The guard has type bool. Bindings are available in the guard and body.

    An absent guard counts as true. A false guard continues with the next case, including a case with the same pattern. The first case whose pattern and guard succeed is selected. A catch-all serves as a fallback at its written position. The selected body produces the match value. Other bodies are not evaluated.

    Every match must satisfy the exhaustiveness rule during checking.

    An arm body is an expression. Write a return statement inside a block, as in case true => { return value }. A return without that block is rejected during parsing with TPZ2001.

    Every match follows the exhaustiveness rule.

    이유

    Evaluating the scrutinee once avoids repeating its effects. Source order makes the exceptional case explicit before a more general case handles the remaining inputs. A failed guard leaves later cases available. Rejecting cases that earlier unguarded patterns make unreachable prevents an arm from being silently hidden. A bare return in an arm and a block containing that return request the same exit from the enclosing function with the same value. The block expresses that transfer through ordinary statement rules while each arm has an expression body.

    규칙topaz.rule.pattern-matching.wildcard

    Wildcard pattern

    _ matches any scrutinee. It is irrefutable and introduces no bindings.

    이유

    Ignoring a value should not introduce a name that could hide another binding. The wildcard makes that intent explicit.

    The selection example records scrutinee evaluation, guard visits, and body visits. The expected trace makes skipped guards and unselected bodies observable.

    Bindings and scalar patterns

    링크
    규칙topaz.rule.pattern-matching.or-bindings

    Names in or-pattern alternatives

    Each alternative of an or-pattern must bind the same set of names. Different name sets are rejected during checking with TPZ5710. The TPZ5711 examples reject a shared name with int and string payloads and accept matching int payloads. The full binding-type compatibility algorithm across alternatives remains Pending.

    이유

    Every successful alternative must provide the names used by the shared guard and body. Equal binding sets prevent a name from being absent on one path.

    규칙topaz.rule.pattern-matching.typed-binding

    Typed binding patterns

    For a known scrutinee type that overlaps the annotation, a typed binding has the overlapping part of those two types. The annotation selects the matched type.

    이유

    The overlap identifies values that can satisfy both the scrutinee type and the annotation. It gives the binding a type valid on a successful match.

    규칙topaz.rule.pattern-matching.integer-range

    Integer range patterns

    An integer range pattern compares an int scrutinee with int endpoints. The value must be greater than or equal to the lower endpoint and satisfy the upper comparison. Both comparisons must succeed. The pattern introduces no bindings.

    Pattern operatorUpper comparison
    ..Less than or equal to the upper endpoint
    ..<Less than the upper endpoint

    이유

    Using the same endpoint operators as range expressions keeps boundary meaning consistent between matching and iteration.

    규칙topaz.rule.pattern-matching.single-rest

    A single list rest and its surrounding elements

    A pattern after the rest marker is required. Write ..name to bind the rest or .._ to ignore it. An omitted pattern is rejected during parsing with TPZ2001.

    A list pattern with one rest may put it before, between, or after fixed elements. The input array must contain at least as many elements as the fixed prefix and suffix together. Those elements are matched in order. The rest has type Array<T> and may be empty. Admission of multiple rest elements remains Pending. Their implementation limitation is documented separately.

    이유

    An omitted rest pattern and an explicit wildcard both discard the unmatched slice. Writing the wildcard preserves that intent and distinguishes it from binding the slice. One rest determines the slice between the fixed prefix and suffix.

    규칙topaz.rule.pattern-matching.range-delimiters

    Range pattern boundaries

    Write a range pattern as (lower .. upper) or (lower ..< upper). The outer parentheses belong to the range pattern and close before the case arrow. Endpoints use the ordinary additive-expression grammar and must have type int. An arm may produce a lambda without taking the case arrow into an endpoint. An unwrapped range pattern is rejected during parsing with TPZ2001.

    이유

    A bare range pattern and the same range inside parentheses test the same endpoints with the same inclusive or exclusive upper bound. The parentheses preserve that interval intent and give the pattern a closing boundary before the case arrow. This separates endpoint expressions from an arm that produces a lambda without changing expression parsing according to the endpoint spelling.

    Accepted matches and coverage

    링크
    규칙topaz.rule.pattern-matching.bool-coverage

    Coverage of a known bool

    The bool examples apply the exhaustiveness rule to true, false. The missing-case example reports TPZ5021.

    이유

    These examples show the closed-type coverage required by the general exhaustiveness rule.

    The exhaustiveness rule applies to closed and open types, including nested payloads.

    Cases are tried in source order. A later case may overlap an earlier case when it still matches some reachable input. An unguarded wildcard or total binding selects at its written position. Earlier unguarded cases that cover every value a later pattern can match make that later case a checking error. Every arm is still type-checked.

    규칙topaz.rule.pattern-matching.unreachable-cases

    Reachable overlapping cases

    Cases are tried in source order. A case may overlap an earlier case if it can match an input that reaches it. A specific case can therefore precede a general case. An unguarded wildcard or total binding is an ordinary case and acts as a fallback at its written position. There is no separate residual fallback selection.

    A later case is unreachable when the union of preceding unguarded patterns covers every value its pattern could match. This includes a case shadowed by a single catch-all or by several earlier cases. Pattern typing runs before this comparison. A guard cannot establish unconditional coverage because it may fail. Overlapping cases with reachable inputs remain valid even when their intersection is unknown.

    Alternatives of one or-pattern describe one case domain. Their overlap does not make a later case unreachable. Binding consistency is checked by its separate rule. All case bodies are checked even when their patterns are unreachable.

    An unreachable case is rejected during checking with TPZ5713. A typed pattern incompatible with the known scrutinee type still uses TPZ5001. Match completeness follows the exhaustiveness rule.

    이유

    An exceptional case can intentionally precede a general case. That use of overlap has a different intent from dividing a domain into mutually exclusive categories. Source order expresses which matching case takes priority. A failed guard lets later cases handle the input. Rejecting a case hidden by earlier unguarded patterns prevents code order from silently disabling a branch.

    규칙topaz.rule.pattern-matching.exhaustiveness

    Every match is exhaustive

    Every match must be exhaustive during checking. A closed type has cases that can all be enumerated. Enums, Result, Option, bool, and closed unions must cover every case. Coverage also examines closed types inside payloads. For example, Option<bool> is covered by Some(true), Some(false), and None().

    Open types include int, float, string, arrays, ranges, type parameters, and other types whose cases cannot be enumerated. A match over an open type ends with an unguarded wildcard or name pattern. A guarded arm does not contribute to coverage, even when its guard is a literal true.

    Missing coverage is rejected during checking with TPZ5021. TPZ4006 is retired in 6.0.0 and is replaced by TPZ5021. This rule does not change refutable let or for patterns.

    Case selection follows source order. TPZ5021 reports missing coverage. TPZ4006 records the retired runtime failure.

    이유

    Checking every match removes execution-time match failure. A program handles each input before it runs.

    Examples and expected results

    링크

    Each example lists its expected result and the recorded public CLI observation.

    Observe the first successful case and guard

    링크
    example.tpzObserve the first successful case and guard플레이그라운드 열기 →
    1. import std.io
    2. function readValue() -> int {
    3. io.writeLine("scrutinee")
    4. 2
    5. }
    6. function testCase(label: string, answer: bool) -> bool {
    7. io.writeLine(label)
    8. answer
    9. }
    10. function selectedBody(label: string) -> string {
    11. io.writeLine("body: {label}")
    12. label
    13. }
    14. let answer = match (readValue()) {
    15. case 1 if (testCase("unmatched guard", true)) => selectedBody("one")
    16. case 2 if (testCase("selected guard", true)) => selectedBody("selected")
    17. case _ => selectedBody("fallback")
    18. }
    19. io.writeLine(answer)
    기대 출력종료 코드 0
    scrutinee
    selected guard
    body: selected
    selected
    
    $ topaz run example.tpz --compiler self
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. scrutinee
    2. selected guard
    3. body: selected
    4. selected

    The input selects one explicit pattern. Its guard and body run once. A guard belonging to another pattern is not evaluated. This revised expectation has no current product receipt.

    Literal alternatives and integer range boundaries

    링크
    example.tpzLiteral alternatives and integer range boundaries플레이그라운드 열기 →
    1. import std.io
    2. function classify(value: int) -> string {
    3. match (value) {
    4. case 1 | 2 => "choice"
    5. case (3..<6) => "inside"
    6. case (7..9) => "closed"
    7. case _ => "outside"
    8. }
    9. }
    10. io.writeLine(classify(1))
    11. io.writeLine(classify(2))
    12. io.writeLine(classify(3))
    13. io.writeLine(classify(5))
    14. io.writeLine(classify(6))
    15. io.writeLine(classify(9))
    16. io.writeLine(classify(10))
    기록된 출력종료 코드 0
    choice
    choice
    inside
    inside
    outside
    closed
    outside
    
    $ topaz run example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. choice
    2. choice
    3. inside
    4. inside
    5. outside
    6. closed
    7. outside
    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. choice
    2. choice
    3. inside
    4. inside
    5. outside
    6. closed
    7. outside

    표준 오류 출력 없음.

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

    The expected values exercise both endpoints of the half-open interval and the upper endpoint of the closed interval. They do not establish coverage of an integer domain.

    Check field, rest, typed and constructor bindings

    링크
    example.tpzCheck field, rest, typed and constructor bindings플레이그라운드 열기 →
    1. record Point {
    2. x: int,
    3. y: int,
    4. }
    5. function pointTotal(value: Point) -> int {
    6. match (value) {
    7. case Point { x: 0, y: other } => other
    8. case remaining => remaining.x + remaining.y
    9. }
    10. }
    11. function structuralTotal(value: { x: int, y: int }) -> int {
    12. match (value) {
    13. case { x: 0, y: other } => other
    14. case remaining => remaining.x + remaining.y
    15. }
    16. }
    17. function remainder(values: Array<int>) -> Array<int> {
    18. match (values) {
    19. case [_, ..tail] => tail
    20. case _ => []
    21. }
    22. }
    23. function integerPart(value: int | string) -> int {
    24. match (value) {
    25. case item: int => item
    26. case _ => 0
    27. }
    28. }
    29. function selected(value: Result<int, int>) -> int {
    30. match (value) {
    31. case Ok(item) | Err(item) => item
    32. }
    33. }
    기대 출력종료 코드 0
    $ topaz check example.tpz --compiler self
    기대 결과

    기대 결과

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

    This is a complete checking fixture. Explicit result types make the field, remainder and typed-binding uses visible to checking. The record declaration and collection literals provide context; their construction rules are owned by other Language pages.

    A known bool with one missing case

    링크
    example.tpzA known bool with one missing case플레이그라운드 열기 →
    1. function flag(value: bool) -> int {
    2. match (value) {
    3. case true => 1
    4. }
    5. }
    기록된 출력종료 코드 1
    표준 출력 없음.
    error[TPZ5021]: non-exhaustive match: missing `false`
     --> example.tpz:2:5
      |
    2 |     match value {
      |     ^^^^^^^^^^^^^
    
    example.tpz: 1 type diagnostic
    
    $ topaz check example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5021 →

      missing-unguarded-false-case-for-known-bool at example.tpz:2:5

    관측한 단언 · 통과 · 5.21.3

    종료 코드 1.

    표준 출력 없음.

    관측한 표준 오류 출력
    1. error[TPZ5021]: non-exhaustive match: missing `false`
    2. --> example.tpz:2:5
    3. |
    4. 2 | match value {
    5. | ^^^^^^^^^^^^^
    6. example.tpz: 1 type diagnostic
    • 통과 · expected nonzero; observed 1
    • 통과 · checking TPZ5021; cause missing-unguarded-false-case-for-known-bool; primary location asserted; additional diagnostics allow

    The independent rejection expectation requires the match's missing bool coverage. A different parsing or name-resolution failure does not prove this claim. Additional diagnostics may be present; exact prose and diagnostic count are not fixed.

    Cover both bool values

    링크
    example.tpzCover both bool values플레이그라운드 열기 →
    1. function flag(value: bool) -> int {
    2. match (value) {
    3. case true => 1
    4. case false => 0
    5. }
    6. }
    기록된 출력종료 코드 0
    example.tpz: types-ok (1 module)
    example.tpz: resolve-ok (1 module)
    
    $ topaz check example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

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

    관측한 단언 · 통과 · 5.21.3

    종료 코드 0.

    관측한 표준 출력
    1. example.tpz: types-ok (1 module)
    2. example.tpz: resolve-ok (1 module)

    표준 오류 출력 없음.

    • 통과 · expected 0; observed 0

    The repaired program adds the missing false case. Its expected result is successful checking of the complete fixture.

    Reject different names across alternatives

    링크
    example.tpzReject different names across alternatives플레이그라운드 열기 →
    1. function selected(value: Result<int, int>) -> int {
    2. match (value) {
    3. case Ok(left) | Err(right) => 0
    4. }
    5. }
    기록된 출력종료 코드 1
    표준 출력 없음.
    error[TPZ5710]: or-pattern alternatives must bind the same names — `left` is bound in one alternative but not another
     --> example.tpz:3:14
      |
    3 |         case Ok(left) | Err(right) => 0
      |              ^^^^^^^^
    
    error[TPZ5710]: or-pattern alternatives must bind the same names — `right` is bound in one alternative but not another
     --> example.tpz:3:25
      |
    3 |         case Ok(left) | Err(right) => 0
      |                         ^^^^^^^^^^
    
    example.tpz: 2 type diagnostics
    
    $ topaz check example.tpz --compiler self · 기록에 사용한 토파즈 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5710 →

      or-pattern-alternatives-bind-different-name-sets at example.tpz:3:14

    관측한 단언 · 통과 · 5.21.3

    종료 코드 1.

    표준 출력 없음.

    관측한 표준 오류 출력
    1. error[TPZ5710]: or-pattern alternatives must bind the same names — `left` is bound in one alternative but not another
    2. --> example.tpz:3:14
    3. |
    4. 3 | case Ok(left) | Err(right) => 0
    5. | ^^^^^^^^
    6. error[TPZ5710]: or-pattern alternatives must bind the same names — `right` is bound in one alternative but not another
    7. --> example.tpz:3:25
    8. |
    9. 3 | case Ok(left) | Err(right) => 0
    10. | ^^^^^^^^^^
    11. example.tpz: 2 type diagnostics
    • 통과 · expected nonzero; observed 1
    • 통과 · checking TPZ5710; cause or-pattern-alternatives-bind-different-name-sets; primary location asserted; additional diagnostics allow

    The intended cause is the unequal binding-name sets, not constructor arity or a missing case. The checker can report both directions of the disagreement. The accompanying accepted selected function binds item in both alternatives.

    An unguarded catch-all makes the following case unreachable

    링크
    example.tpzAn unguarded catch-all makes the following case unreachable플레이그라운드 열기 →
    1. let value: int = 7
    2. let selected = match (value) {
    3. case _ => "first"
    4. case later: int => "second"
    5. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    The first wildcard covers every integer. The later typed binding can never be selected and is rejected during checking. The rejection expects TPZ5713 during checking with cause match-unreachable-case.

    A later wildcard is covered by two earlier unguarded cases

    링크
    example.tpzA later wildcard is covered by two earlier unguarded cases플레이그라운드 열기 →
    1. let value: bool = true
    2. let result = match (value) {
    3. case true => "yes"
    4. case false => "no"
    5. case _ => "hidden"
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    The true and false cases together cover every Boolean value. Their union makes the final wildcard unreachable. The rejection expects TPZ5713 during checking with cause match-unreachable-case.

    Every case is checked even after a catch-all

    링크
    example.tpzEvery case is checked even after a catch-all플레이그라운드 열기 →
    1. let value: int = 7
    2. let selected = match (value) {
    3. case _ => "first"
    4. case impossible: string => "second"
    5. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5001 →

      pattern-cannot-match-scrutinee-type at example.tpz:4:10

    The expected result follows from current SELF source. Execution against public Topaz 5.21.3 is pending CI.

    One rest may precede, separate, or follow fixed elements

    링크
    example.tpzOne rest may precede, separate, or follow fixed elements플레이그라운드 열기 →
    1. import std.io
    2. let middle = match ([1, 2, 3, 4]) {
    3. case [first, ..rest, last] => "{first} {rest.length} {last}"
    4. case _ => "miss"
    5. }
    6. let leading = match ([1, 2, 3, 4]) {
    7. case [..rest, last] => "{rest.length} {last}"
    8. case _ => "miss"
    9. }
    10. let trailing = match ([1, 2, 3, 4]) {
    11. case [first, ..rest] => "{first} {rest.length}"
    12. case _ => "miss"
    13. }
    14. let empty: Array<int> = []
    15. let remaining = match (empty) {
    16. case [..rest] if (rest.length == 0) => rest.length
    17. case remaining => remaining.length
    18. }
    19. io.writeLine(middle)
    20. io.writeLine(leading)
    21. io.writeLine(trailing)
    22. io.writeLine("{remaining}")
    기대 출력종료 코드 0
    1 2 4
    3 4
    1 3
    0
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 1 2 4
    2. 3 4
    3. 1 3
    4. 0

    The expected result follows from current SELF source. Execution against public Topaz 5.21.3 is pending CI.

    Multiple rest elements retain an intended emission refusal

    링크
    example.tpzMultiple rest elements retain an intended emission refusal플레이그라운드 열기 →
    1. let value = match ([1, 2]) {
    2. case [..left, ..right] => 0
    3. case _ => 1
    4. }
    기대 출력0이 아닌 종료 코드
    $ topaz emit example.tpz --compiler self --target rust · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    필수 기본 위치 계약은 미정입니다.

    The existing Rust backend refuses this shape before generating output. Current SELF emission does not establish the same refusal. The rejection expectation is retained; its exact product diagnostic and location await verification.

    Rejecting a structural field shorthand

    링크
    example.tpzRejecting a structural field shorthand플레이그라운드 열기 →
    1. let { value } = { value: 1 }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self --format json
    기대 결과

    기대 결과

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

    • TPZ2001 →

      record-pattern-field-colon at example.tpz:1:13

    Write the field name, a colon, and its binding pattern. The missing colon is reported at the closing brace.

    Rejecting a nominal field shorthand

    링크
    example.tpzRejecting a nominal field shorthand플레이그라운드 열기 →
    1. record Point { x: int }
    2. let Point { x } = Point { x: 1 }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self --format json
    기대 결과

    기대 결과

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

    • TPZ2001 →

      record-pattern-field-colon at example.tpz:2:15

    Write the field name, a colon, and its binding pattern. The missing colon is reported at the closing brace.

    Binding and renaming fields explicitly

    링크
    example.tpzBinding and renaming fields explicitly플레이그라운드 열기 →
    1. import std.io
    2. record Point { x: int, y: int }
    3. let { value: value } = { value: 7 }
    4. let Point { x: first, y: second } = Point { x: 2, y: 3 }
    5. io.writeLine("{value} {first} {second}")
    기대 출력종료 코드 0
    7 2 3
    
    $ topaz run example.tpz --compiler self
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 7 2 3

    The same field mapping syntax binds a field to its own name or to a different name.

    Rejecting a return without an arm block

    링크
    example.tpzRejecting a return without an arm block플레이그라운드 열기 →
    1. function choose(flag: bool) -> int {
    2. while (true) {
    3. let value = match (flag) {
    4. case true => return 7
    5. case false => 3
    6. }
    7. return value
    8. }
    9. 0
    10. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2001 →

      match-arm-return-needs-block at example.tpz:4:26

    A return statement needs a block when used as a match arm body. The rejection points to the return keyword.

    Returning through a match arm block

    링크
    example.tpzReturning through a match arm block플레이그라운드 열기 →
    1. import std.io
    2. function choose(flag: bool) -> int {
    3. while (true) {
    4. let value = match (flag) {
    5. case true => { return 7 }
    6. case false => 3
    7. }
    8. return value
    9. }
    10. 0
    11. }
    12. io.writeLine("{choose(true)}")
    13. io.writeLine("{choose(false)}")
    기대 출력종료 코드 0
    7
    3
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

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

    The true arm returns from the function through the surrounding binding and loop. The false arm supplies a value to the ordinary return statement.

    Rejecting a rest marker without a pattern

    링크
    example.tpzRejecting a rest marker without a pattern플레이그라운드 열기 →
    1. let count = match ([1, 2]) {
    2. case [..] => 2
    3. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2001 →

      list-rest-pattern-required at example.tpz:2:13

    Write .._ to ignore the rest. The error points to the delimiter where the required pattern is missing.

    Rejecting an omitted middle rest pattern

    링크
    example.tpzRejecting an omitted middle rest pattern플레이그라운드 열기 →
    1. let total = match ([1, 2, 3]) {
    2. case [first, .., last] => first + last
    3. case _ => 0
    4. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2001 →

      list-rest-pattern-required at example.tpz:2:20

    Write .._ to ignore the rest. The error points to the delimiter where the required pattern is missing.

    Ignoring a rest with an explicit wildcard

    링크
    example.tpzIgnoring a rest with an explicit wildcard플레이그라운드 열기 →
    1. import std.io
    2. let middle = match ([1, 2, 3, 4]) {
    3. case [first, .._, last] => "{first} {last}"
    4. case _ => "miss"
    5. }
    6. let leading = match ([1, 2, 3, 4]) {
    7. case [.._, last] => last
    8. case _ => 0
    9. }
    10. let trailing = match ([1, 2, 3, 4]) {
    11. case [first, .._] => first
    12. case _ => 0
    13. }
    14. let empty: Array<int> = []
    15. let ignored = match (empty) {
    16. case [.._] if (empty.length == 0) => true
    17. case _ => false
    18. }
    19. io.writeLine(middle)
    20. io.writeLine("{leading}")
    21. io.writeLine("{trailing}")
    22. io.writeLine("{ignored}")
    기대 출력종료 코드 0
    1 4
    4
    1
    true
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 1 4
    2. 4
    3. 1
    4. true

    The wildcard ignores a leading, middle, or trailing slice. A rest wildcard also matches an empty array.

    Constructor patterns keep parentheses at every arity

    링크
    example.tpzConstructor patterns keep parentheses at every arity플레이그라운드 열기 →
    1. import std.io
    2. enum Choice { Empty, Filled(int), Pair(int, int) }
    3. function read(value: Choice) -> int {
    4. match (value) {
    5. case Empty() => 0
    6. case Filled(number) => number
    7. case Pair(left, right) => left + right
    8. }
    9. }
    10. function nested(value: Option<Choice>) -> int {
    11. match (value) {
    12. case None() => -1
    13. case Some(Empty()) => 0
    14. case Some(Filled(number)) => number
    15. case Some(Pair(left, right)) => left + right
    16. }
    17. }
    18. io.writeLine("{read(Choice.Empty())}")
    19. io.writeLine("{read(Choice.Filled(7))}")
    20. io.writeLine("{read(Choice.Pair(2, 3))}")
    21. io.writeLine("{nested(None())}")
    22. io.writeLine("{nested(Some(Choice.Empty()))}")
    기대 출력종료 코드 0
    0
    7
    5
    -1
    0
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 0
    2. 7
    3. 5
    4. -1
    5. 0

    Value expressions and constructor patterns keep parentheses at every arity. The nested match covers every Option and Choice variant.

    A fresh bare name captures an enum value

    링크
    example.tpzA fresh bare name captures an enum value플레이그라운드 열기 →
    1. import std.io
    2. enum Choice { Empty, Filled(int) }
    3. function identity(value: Choice) -> Choice {
    4. match (value) {
    5. case captured => captured
    6. }
    7. }
    8. function read(value: Choice) -> int {
    9. match (value) {
    10. case Empty() => 0
    11. case Filled(number) => number
    12. }
    13. }
    14. io.writeLine("{read(identity(Choice.Filled(8)))}")
    기대 출력종료 코드 0
    8
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 8

    The bare name captured is a binding in every expected type. SELF currently treats an unknown top-level enum-case spelling as a variant typo, so this intended acceptance is recorded under the implementation limitation.

    A fresh typed name captures the whole enum

    링크
    example.tpzA fresh typed name captures the whole enum플레이그라운드 열기 →
    1. import std.io
    2. enum Choice { Empty, Filled(int) }
    3. function identity(value: Choice) -> Choice {
    4. match (value) {
    5. case captured: Choice => captured
    6. }
    7. }
    8. function upper(value: int) -> int {
    9. match (value) {
    10. case UPPER => UPPER
    11. }
    12. }
    13. function read(value: Choice) -> int {
    14. match (value) {
    15. case Empty() => 0
    16. case Filled(number) => number
    17. }
    18. }
    19. io.writeLine("{read(identity(Choice.Filled(8)))}")
    20. io.writeLine("{upper(9)}")
    기대 출력종료 코드 0
    8
    9
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 8
    2. 9

    An annotation refines the matched type. It does not turn a binding into a constructor or permit a constructor-name collision. An uppercase fresh name is still a binding.

    A bare nullary variant cannot become a catch-all

    링크
    example.tpzA bare nullary variant cannot become a catch-all플레이그라운드 열기 →
    1. enum Choice { Empty, Filled(int) }
    2. function read(value: Choice) -> int {
    3. match (value) {
    4. case Empty => 0
    5. case Filled(number) => number
    6. }
    7. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5712 →

      pattern-constructor-binding-collision at example.tpz:4:14

    Write Empty() to test the nullary variant. The removed spelling must be rejected instead of accepting every Choice value.

    Nested constructors require the same argument list

    링크
    example.tpzNested constructors require the same argument list플레이그라운드 열기 →
    1. enum Choice { Empty, Filled(int) }
    2. function read(value: Option<Choice>) -> int {
    3. match (value) {
    4. case Some(Empty) => 0
    5. case _ => 1
    6. }
    7. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5712 →

      pattern-constructor-binding-collision at example.tpz:4:19

    Write Some(Empty()). Nesting does not turn a constructor spelling into a binding.

    A type annotation cannot bypass a constructor-name collision

    링크
    example.tpzA type annotation cannot bypass a constructor-name collision플레이그라운드 열기 →
    1. enum Choice { Empty, Filled(int) }
    2. function read(value: Choice) -> int {
    3. match (value) {
    4. case Empty: Choice => 0
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5712 →

      pattern-constructor-binding-collision at example.tpz:4:14

    Choose a fresh name such as captured: Choice for a typed catch-all, or write Empty() to test the variant.

    Constructor names stay reserved for patterns across expected types

    링크
    example.tpzConstructor names stay reserved for patterns across expected types플레이그라운드 열기 →
    1. enum Mode { Idle }
    2. function read(value: int) -> int {
    3. match (value) {
    4. case Idle => 0
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ5712 →

      pattern-constructor-binding-collision at example.tpz:4:14

    Idle is visible in the constructor namespace. Changing the scrutinee type or introducing a value with that name does not make this spelling a pattern binding.

    None needs parentheses in a constructor pattern

    링크
    example.tpzNone needs parentheses in a constructor pattern플레이그라운드 열기 →
    1. function read(value: Option<int>) -> int {
    2. match (value) {
    3. case Some(number) => number
    4. case None => 0
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2012 →

      pattern-reserved-none-binding at example.tpz:4:14

    Write None() for the constructor pattern. None remains a reserved binding name. The rejection uses the existing TPZ2012 identity and reserved-None producer message.

    None needs parentheses in a constructor value

    링크
    example.tpzNone needs parentheses in a constructor value플레이그라운드 열기 →
    1. let maybe: Option<int> = None
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2012 →

      pattern-reserved-none-binding at example.tpz:1:26

    Write None() when constructing an absent Option value. Bare None is rejected during parsing with TPZ2012 and the same reserved-None cause as the bare pattern example.

    Specific cases before a general fallback

    링크
    example.tpzSpecific cases before a general fallback플레이그라운드 열기 →
    1. import std.io
    2. function first(value: int) -> string {
    3. match (value) {
    4. case 1 => "one"
    5. case _ => "rest"
    6. }
    7. }
    8. function typed(value: int) -> string {
    9. match (value) {
    10. case 1 => "one"
    11. case captured: int => "rest"
    12. }
    13. }
    14. function last(value: int) -> string {
    15. match (value) {
    16. case 2 => "two"
    17. case 1 => "one"
    18. case _ => "rest"
    19. }
    20. }
    21. io.writeLine("{first(1)} {typed(1)} {last(1)}")
    22. io.writeLine("{first(3)} {typed(3)} {last(3)}")
    기대 출력종료 코드 0
    one one one
    rest rest rest
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. one one one
    2. rest rest rest

    Specific cases are tried first. The wildcard and total typed binding handle values that reach them. Putting the general case first makes the following specific cases unreachable and causes a checking error.

    A failed guard lets the same pattern match later

    링크
    example.tpzA failed guard lets the same pattern match later플레이그라운드 열기 →
    1. import std.io
    2. function check(label: string, ok: bool) -> bool {
    3. io.writeLine(label)
    4. ok
    5. }
    6. function choose(value: int) -> string {
    7. match (value) {
    8. case 2 if (check("guard for two", false)) => "guarded two"
    9. case 2 => "unguarded two"
    10. case _ => "other"
    11. }
    12. }
    13. io.writeLine(choose(2))
    14. io.writeLine(choose(3))
    기대 출력종료 코드 0
    guard for two
    unguarded two
    other
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. guard for two
    2. unguarded two
    3. other

    The first case matches 2 but its guard is false. Selection continues to the next case, which uses the same pattern without a guard. The other input reaches the wildcard.

    Cover type and list domains with a record fallback

    링크
    example.tpzCover type and list domains with a record fallback플레이그라운드 열기 →
    1. import std.io
    2. function kind(value: int | string) -> string {
    3. match (value) {
    4. case number: int => "integer"
    5. case text: string => "string"
    6. }
    7. }
    8. function row(value: { x: int, y: int }) -> string {
    9. match (value) {
    10. case { x: 0, y: _ } => "zero"
    11. case { x: 1, y: _ } => "one"
    12. case _ => "other"
    13. }
    14. }
    15. function size(values: Array<int>) -> string {
    16. match (values) {
    17. case [] => "empty"
    18. case remaining => "nonempty"
    19. }
    20. }
    21. io.writeLine(kind(1))
    22. io.writeLine(kind("a"))
    23. io.writeLine(row({ x: 0, y: 9 }))
    24. io.writeLine(row({ x: 1, y: 9 }))
    25. io.writeLine(size([]))
    26. io.writeLine(size([1]))
    기대 출력종료 코드 0
    integer
    string
    zero
    one
    empty
    nonempty
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. integer
    2. string
    3. zero
    4. one
    5. empty
    6. nonempty

    The typed cases cover the union. The list cases cover empty and nonempty arrays. The record match reaches its final case for other field values.

    Adjacent half-open and closed intervals do not overlap

    링크
    example.tpzAdjacent half-open and closed intervals do not overlap플레이그라운드 열기 →
    1. import std.io
    2. function band(value: int) -> string {
    3. match (value) {
    4. case (0 ..< 5) => "low"
    5. case (5 .. 9) => "high"
    6. case _ => "outside"
    7. }
    8. }
    9. io.writeLine(band(0))
    10. io.writeLine(band(4))
    11. io.writeLine(band(5))
    12. io.writeLine(band(9))
    13. io.writeLine(band(10))
    기대 출력종료 코드 0
    low
    low
    high
    high
    outside
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. low
    2. low
    3. high
    4. high
    5. outside

    The first interval excludes 5 and the second includes it. The wildcard follows both intervals and handles values outside them.

    Dynamic bounds with a later catch-all

    링크
    example.tpzDynamic bounds with a later catch-all플레이그라운드 열기 →
    1. import std.io
    2. function bound(value: int) -> int { value }
    3. function band(value: int, low: int, high: int) -> string {
    4. match (value) {
    5. case (low ..< bound(high)) => "inside"
    6. case _ => "outside"
    7. }
    8. }
    9. io.writeLine(band(2, 0, 5))
    10. io.writeLine(band(5, 0, 5))
    기대 출력종료 코드 0
    inside
    outside
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. inside
    2. outside

    The dynamic range is tried before the wildcard. Its runtime bound test selects the first case when it succeeds. Otherwise the wildcard handles the value.

    A repeated unguarded literal case is unreachable

    링크
    example.tpzA repeated unguarded literal case is unreachable플레이그라운드 열기 →
    1. function choose(value: int) -> int {
    2. match (value) {
    3. case 1 => 10
    4. case 1 => 20
    5. case _ => 0
    6. }
    7. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    The first unguarded case already handles every value the second identical literal pattern can match. The rejection expects TPZ5713 during checking with cause match-unreachable-case.

    A specific constructor can precede a general constructor

    링크
    example.tpzA specific constructor can precede a general constructor플레이그라운드 열기 →
    1. import std.io
    2. function choose(value: Option<int>) -> string {
    3. match (value) {
    4. case Some(0) => "zero"
    5. case Some(number) => "other {number}"
    6. case None() => "none"
    7. }
    8. }
    9. io.writeLine(choose(Some(0)))
    10. io.writeLine(choose(Some(7)))
    11. io.writeLine(choose(None()))
    기대 출력종료 코드 0
    zero
    other 7
    none
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. zero
    2. other 7
    3. none

    Some(0) matches both constructor patterns. The first handles zero while the next handles other payloads.

    Overlapping record patterns leave later inputs

    링크
    example.tpzOverlapping record patterns leave later inputs플레이그라운드 열기 →
    1. import std.io
    2. function choose(value: { x: int, y: int }) -> string {
    3. match (value) {
    4. case { x: 0 } => "x"
    5. case { y: 0 } => "y"
    6. case _ => "other"
    7. }
    8. }
    9. io.writeLine(choose({ x: 0, y: 0 }))
    10. io.writeLine(choose({ x: 3, y: 0 }))
    11. io.writeLine(choose({ x: 3, y: 4 }))
    기대 출력종료 코드 0
    x
    y
    other
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. x
    2. y
    3. other

    Both field tests succeed for the first value, so the first case wins. A value with nonzero x and zero y still reaches the second case.

    Overlapping list patterns follow source order

    링크
    example.tpzOverlapping list patterns follow source order플레이그라운드 열기 →
    1. import std.io
    2. function choose(values: Array<int>) -> string {
    3. match (values) {
    4. case [1, .._] => "starts with one"
    5. case [_, 1] => "ends with one"
    6. case _ => "other"
    7. }
    8. }
    9. io.writeLine(choose([1, 1]))
    10. io.writeLine(choose([2, 1]))
    11. io.writeLine(choose([2, 2]))
    기대 출력종료 코드 0
    starts with one
    ends with one
    other
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. starts with one
    2. ends with one
    3. other

    The first pattern handles arrays starting with one. The second can still handle arrays ending with one that do not start with one.

    Overlapping guarded cases follow source order

    링크
    example.tpzOverlapping guarded cases follow source order플레이그라운드 열기 →
    1. import std.io
    2. function choose(value: int) -> string {
    3. match (value) {
    4. case number if (number > 0) => "positive"
    5. case number if (number <= 0) => "nonpositive"
    6. case _ => "other"
    7. }
    8. }
    9. io.writeLine(choose(4))
    10. io.writeLine(choose(0))
    기대 출력종료 코드 0
    positive
    nonpositive
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. positive
    2. nonpositive

    Both binding patterns accept every integer. The first guard decides whether to continue to the next case, and neither guard establishes unconditional coverage.

    Overlapping alternatives describe one match case

    링크
    example.tpzOverlapping alternatives describe one match case플레이그라운드 열기 →
    1. import std.io
    2. function choose(value: int) -> string {
    3. match (value) {
    4. case 1 | 1 => "one"
    5. case _ => "other"
    6. }
    7. }
    8. io.writeLine(choose(1))
    9. io.writeLine(choose(3))
    기대 출력종료 코드 0
    one
    other
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. one
    2. other

    Two alternatives can recognize the same input without creating different case priorities. Both alternatives select the same body.

    Overlapping integer intervals keep later cases reachable

    링크
    example.tpzOverlapping integer intervals keep later cases reachable플레이그라운드 열기 →
    1. import std.io
    2. function choose(value: int) -> string {
    3. match (value) {
    4. case (0 .. 5) => "lower"
    5. case (5 ..< 9) => "upper"
    6. case _ => "outside"
    7. }
    8. }
    9. io.writeLine(choose(5))
    10. io.writeLine(choose(7))
    11. io.writeLine(choose(10))
    기대 출력종료 코드 0
    lower
    upper
    outside
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. lower
    2. upper
    3. outside

    Five belongs to both intervals and selects the first. Seven reaches the second interval. The intervals do not need a disjointness proof.

    Dynamic range overlap uses ordinary source order

    링크
    example.tpzDynamic range overlap uses ordinary source order플레이그라운드 열기 →
    1. import std.io
    2. function bound(value: int) -> int { value }
    3. function choose(value: int, low: int, high: int) -> string {
    4. match (value) {
    5. case (low ..< bound(high)) => "range"
    6. case 100 => "hundred"
    7. case _ => "outside"
    8. }
    9. }
    10. io.writeLine(choose(100, 0, 5))
    11. io.writeLine(choose(100, 0, 105))
    12. io.writeLine(choose(200, 0, 105))
    기대 출력종료 코드 0
    hundred
    range
    outside
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. hundred
    2. range
    3. outside

    When the dynamic range excludes 100, the literal case succeeds. When it includes 100, the earlier range succeeds. An unknown intersection does not require rejection.

    Reject an unwrapped range pattern

    링크
    example.tpzReject an unwrapped range pattern플레이그라운드 열기 →
    1. let value = match (2) {
    2. case 1 .. 3 => 1
    3. case _ => 0
    4. }
    기대 출력0이 아닌 종료 코드
    표준 출력 없음.
    $ topaz check example.tpz --compiler self --format json · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    • TPZ2001 →

      range-pattern-parentheses at example.tpz:2:10

    A delimited range precedes a lambda-valued arm

    링크
    example.tpzA delimited range precedes a lambda-valued arm플레이그라운드 열기 →
    1. import std.io
    2. let low = 1
    3. let high = 3
    4. let chosen = match (2) {
    5. case (low .. high) => (value: int) => value + 1
    6. case _ => (value: int) => value
    7. }
    8. io.writeLine("{chosen(6)}")
    기대 출력종료 코드 0
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 7

    A missing enum variant is rejected

    링크
    example.tpzA missing enum variant is rejected플레이그라운드 열기 →
    1. enum Choice { Left(int), Right(int) }
    2. function read(value: Choice) -> int {
    3. match (value) {
    4. case Left(number) => number
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    Both enum variants are covered

    링크
    example.tpzBoth enum variants are covered플레이그라운드 열기 →
    1. import std.io
    2. enum Choice { Left(int), Right(int) }
    3. function read(value: Choice) -> int {
    4. match (value) {
    5. case Left(number) => number
    6. case Right(number) => number + 10
    7. }
    8. }
    9. io.writeLine("{read(Choice.Left(2))}")
    10. io.writeLine("{read(Choice.Right(3))}")
    기대 출력종료 코드 0
    2
    13
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 2
    2. 13

    An integer match needs a final fallback

    링크
    example.tpzAn integer match needs a final fallback플레이그라운드 열기 →
    1. function read(value: int) -> int {
    2. match (value) {
    3. case 0 => 10
    4. }
    5. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    A final name pattern covers remaining integers

    링크
    example.tpzA final name pattern covers remaining integers플레이그라운드 열기 →
    1. import std.io
    2. function read(value: int) -> int {
    3. match (value) {
    4. case 0 => 10
    5. case remaining => remaining
    6. }
    7. }
    8. io.writeLine("{read(0)}")
    9. io.writeLine("{read(7)}")
    기대 출력종료 코드 0
    10
    7
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

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

    Guarded bool arms do not establish coverage

    링크
    example.tpzGuarded bool arms do not establish coverage플레이그라운드 열기 →
    1. function read(value: bool) -> int {
    2. match (value) {
    3. case true if (true) => 1
    4. case false if (true) => 0
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    A missing nested bool payload is rejected

    링크
    example.tpzA missing nested bool payload is rejected플레이그라운드 열기 →
    1. function read(value: Option<bool>) -> int {
    2. match (value) {
    3. case Some(true) => 1
    4. case None() => -1
    5. }
    6. }
    기대 출력0이 아닌 종료 코드
    $ topaz check example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    Option bool covers both payloads and None

    링크
    example.tpzOption bool covers both payloads and None플레이그라운드 열기 →
    1. import std.io
    2. function read(value: Option<bool>) -> int {
    3. match (value) {
    4. case Some(true) => 1
    5. case Some(false) => 0
    6. case None() => -1
    7. }
    8. }
    9. let flags = map { "on": true, "off": false }
    10. io.writeLine("{read(flags.get("on"))}")
    11. io.writeLine("{read(flags.get("off"))}")
    12. io.writeLine("{read(flags.get("missing"))}")
    기대 출력종료 코드 0
    1
    0
    -1
    
    $ topaz run example.tpz --compiler self · 대상 제품 5.21.3
    기대 결과

    기대 결과

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

    기대 표준 출력
    1. 1
    2. 0
    3. -1

    Map lookup supplies Some and None values. Exhaustiveness includes each closed bool payload inside Some.

    Pending contracts

    링크

    Related diagnostics and owners

    링크

    Non-exhaustive match →

    Or-pattern alternatives bind different names →

    See Blocks and control flow for if let, while let, and return; Expressions and operators for expression grouping and range expressions; and Functions and generics for function declarations and return inference. A pattern range is defined on this page; the expression form has its own owner.

    Unexpected token →

    TPZ5001 →

    Native emitter cannot lower this construct yet →

    Constructor name used as a pattern binding →

    Reserved binding name →

    Unreachable match case →

    Or-pattern binding types disagree →

    메뉴

    다운로드 →