Scope and ownership
링크This page covers collection construction.
See Blocks and control flow for general loops and control transfer, Expressions and operators for indexing, and the Standard library for receiver methods. Records, enums and newtypes covers record updates. Functions and generics covers spread arguments in calls.
Construction syntax
링크ArrayLiteral = "[" (ArrayElement ("," ArrayElement)* ","?)? "]" ;ArrayElement = Expression | "..." Expression ;SetLiteral = "set" "{" (Expression ("," Expression)* ","?)? "}" ;MapLiteral = "map" "{" (MapEntry ("," MapEntry)* ","?)? "}" ;MapEntry = Expression ":" Expression ;ArrayComprehension = "[" Clauses "=>" Expression "]" ;SetComprehension = "set" "{" Clauses "=>" Expression "}" ;MapComprehension = "map" "{" Clauses "=>" Expression ":" Expression "}" ;Clauses = ForClause (ForClause | IfClause)* ;ForClause = "for" Pattern "in" ControlOperand ;IfClause = "if" ControlOperand ;
The grammar is transcribed from the linked parser evidence. Expression, Pattern, and ControlOperand are supplied by their respective language definitions.
Collection literal entries
An array literal accepts expressions and . entries. A set literal contains expressions, and a map literal contains key: value entries.
이유
Each literal exposes whether it stores a sequence, unique values, or key and value associations. Map entries keep each key beside its value.
Comprehension clauses and body
A comprehension starts with for pattern in (source). Additional clauses use for pattern in (source) or if (condition). The => token introduces the body. A map body has the form key: value.
이유
Comprehensions reuse the existing for and if control forms. The final arrow separates selection of bindings from the value produced for them.
Literal types and array spread
링크Array literal type
An array literal forms Array<T> from its element types.
이유
A shared element type gives indexing and iteration one type contract. Inferring it from the entries avoids repeating type information for every value.
Set literal type
A set literal forms Set<T> from its element types.
이유
A shared element type lets membership and duplicate checks use one value contract. The supplied entries provide the information needed to infer that type.
Map literal type
A map literal forms Map<K, V> from its key and value types.
이유
Separate key and value types let lookup check a key without requiring the payload to have the same type. Each side is inferred from its own entries.
Context for empty collections
이유
Collection syntax does not introduce a separate typing model.
Bare empty collections require context
이유
The reason a collection needs context is independent of its surface form.
Array spread element type
Spreading a concrete Array<T> contributes elements of type T to the containing array literal.
이유
Spread inserts the contents of an array into the surrounding sequence. Its element type must therefore contribute to the result instead of introducing another array layer.
Reject a non-array spread operand
An array spread whose concrete, non-union operand type is not Array<T> produces TPZ5001.
이유
Array spread copies stored array elements. Requiring an array avoids adding an implicit conversion from other iterable values during construction.
Array construction order
Array construction appends ordinary values and inserts each spread operand’s elements at the spread position.
이유
Arrays preserve positions, so each entry must contribute where it appears. Expanding a spread in place preserves the relative order of its elements.
Collection key checks
Key-capability checking applies to set elements and map keys in literals and comprehensions, independently of map values.
이유
Set elements and map keys determine membership and lookup identity. Map values are payloads, so they do not need the key comparison capability.
Rejected collection key types
A function, Map, Set, Range, or ByteBuffer used as a set element or map key produces TPZ5007. A compound key containing one of these types also produces TPZ5007.
이유
Keys require a supported equality comparison throughout their structure. Rejecting incompatible components prevents membership and lookup from reaching an unsupported comparison.
Admitted keys and stored values
Map keys and Set elements follow value semantics at insertion. Scalars include integer and floating values, strings, booleans, unit/null, Bytes, Path, URL, Date, BigInt, and Decimal. Option/Result payloads, arrays, records, enum payloads, and newtype contents must recursively be keyable. Map, Set, Range, ByteBuffer, functions, templates, File, JSONValue, Regex, Match, TOMLValue, and RoundingMode are rejected as keys. Imported namespaces and host-provided opaque values are also not keys. Structural guards bound recursive key checks. A generic type parameter passing the static gate is not evidence that every substitution is keyable; the concrete runtime value must still pass this domain check.
이유
Stable stored values keep membership and lookup consistent. Insertion follows value semantics, including compound keys.
Where collection expectations come from
Binding annotations, expected call parameters, declared returns, block tails, parentheses, and expected function result types can supply a collection expectation. Empty literals follow empty collection context. A collection expectation does not select one arm from a union. Contextual literal typing does not change collection variance or general assignability.
이유
A surrounding type remains useful through grouping and block tails. Sharing that context across bindings, calls, and returns avoids making empty collection typing depend on presentation.
Context through collection components
A matching Array<E>, Set<E>, or Map<K, V> expectation supplies the component types for each emitted element, key, and value. Nonempty literals and comprehension bodies receive those component expectations, including through declared or expected callable results. After successful component checking, a comprehension retains the expected type arguments in its result without further widening. Comprehension iterator sources keep their own inferred types, and filters require bool. A rigid type parameter remains rigid. An incompatible concrete component must still be rejected. Callable result inference retains the actual body constraints for its enclosing comparison. Array spread checks its contributed element type. Collection variance, assignability, and key eligibility are unchanged.
A matching collection expectation may contain a type parameter fixed by the surrounding generic declaration; that parameter remains a constraint. Fresh call inference still follows the ordinary per-call rules. Context completes missing information and checks concrete expressions using the existing assignability rules. It does not choose a collection arm from a union expectation. An array spread contributes its actual element type, so the spread operand retains its own array type. Set elements and map keys still pass the key-capability checks.
이유
A collection expectation already identifies the types of the values being assembled. Passing those component types into every literal and comprehension body gives the same information to nested expressions across collection forms. Comprehension sources can have different element types from their outputs, so their types come from the source expressions. Preserving concrete component constraints keeps contextual inference sound.
An empty sibling cannot erase a known type mismatch
Completing an empty collection from context must preserve the constraints of its concrete siblings. A nested string array cannot satisfy an int-array expectation merely because another map value is empty. SELF currently has a whole-type refinement path that can erase this mismatch; retain the intended rejection while that implementation limitation is reviewed.
이유
Filling an unknown element type must not erase a known incompatible value. Otherwise an annotation could admit values that violate the collection type.
Comprehension clauses and results
링크Callback methods and comprehensions
Callback methods such as values. and values. apply existing function values and chain their transformations. A comprehension states source bindings, filters, and emitted values together. It constructs an array, set, or map and can combine several sources.
Array map and filter evaluate their receiver and callback expression once in ordinary call order. Each method then makes a complete eager pass in element order. It calls its function once per element. A filter retains successful elements in that order. Each method finishes before the next method in a chain begins. Thus values. finishes every call to p before its first call to f.
A comprehension eagerly builds its result. Its first source evaluates once. Each later source evaluates again for each earlier binding combination that reaches it. Clauses run in written order. Each filter decides whether later clauses and the body run for the current bindings. The body runs before traversal advances to the next reached combination.
For the same array and fixed pure functions that complete, values. and [for value in (values) => f(value)] produce the same ordered values. A pure function has the same result for the same arguments and has no observable effects. values. and [for value in (values) if (p(value)) => f(value)] also produce the same ordered values. The second comprehension calls f immediately after a successful p for each element. Effects and failures retain these evaluation boundaries.
A lambda callback owns its postfix ? return destination under lambda and callback propagation. A map of Result-returning callbacks produces an array of Results. Filter still requires a bool callback result. Comprehensions retain their existing evaluation and failure boundaries.
이유
A callback chain communicates reuse of function values through successive transformations. A comprehension communicates how source bindings and filters construct a new collection. These intentions and their evaluation boundaries differ even when pure functions produce equal values. Both forms preserve that distinction.
Nested comprehension clauses
Each later comprehension clause executes inside the preceding clauses.
이유
Later clauses can use earlier bindings because they execute inside those scopes. This gives the clause sequence the same meaning as explicit nested loops.
Comprehension filter scope
A comprehension if filter runs the remaining clauses and body when its condition is true and skips them when it is false.
이유
A filter decides whether the remaining work runs for the current bindings. Skipping that work on false avoids computing values that will not enter the result.
Accumulate reached body results
Each successful comprehension body evaluation contributes one element or one map key/value pair.
이유
Each reached body supplies one result entry. This keeps the number and order of produced entries tied to successful body evaluations.
Comprehension source and pattern types
For a concrete Array<T>, Set<T>, or Range<T> source, a comprehension checks its pattern against the source element type T.
이유
The iteration pattern receives an element, not the collection itself. Using the source element type makes pattern checking agree with each value encountered at runtime.
Reject a non-iterable source
A concrete non-iterable source in a comprehension produces TPZ5001.
이유
Iteration requires a defined sequence of elements. Rejecting other values avoids inventing an implicit conversion or a type-dependent notion of iteration.
Comprehension filters require bool
A comprehension if condition must have type bool. A non-boolean condition produces TPZ5001.
이유
A filter uses the same boolean condition rule as if. Requiring bool avoids an additional truthiness convention for numbers, strings, or collections.
Array comprehension type
Without a matching array expectation, an array comprehension independently infers and widens its body type T, producing Array<T>. With a matching expectation, component checking and the result type follow collection context propagation.
이유
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Set comprehension type
Without a matching set expectation, a set comprehension independently infers and widens its body type T, producing Set<T>. With a matching expectation, component checking and the result type follow collection context propagation.
이유
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Map comprehension type
Without a matching map expectation, a map comprehension independently infers and widens its key type K and value type V, producing Map<K, V>. With a matching expectation, component checking and the result type follow collection context propagation.
이유
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Collection and comprehension evaluation order
Literal elements and spread sources evaluate in source order. Each map key evaluates before its value. A comprehension reevaluates each later iterator source for every earlier binding combination that reaches it; an if filter controls only the following clauses and body. Map literals and comprehensions evaluate all pairs before the constructor checks for duplicate keys. A duplicate does not erase effects already performed by later pairs.
이유
A fixed operand order makes collection effects reproducible. Map construction receives evaluated pairs, so expression evaluation and duplicate validation have separate failure points.
Failure while producing a collection
If an element, iterator source, filter, key, or value faults or propagates an early result, later expressions are not evaluated and no collection result is produced on that path. Effects already performed remain observable. This production failure is distinct from duplicate-map validation, which starts only after all pairs have been accumulated; ordinary faults follow the fault cleanup rule.
이유
A failed expression cannot supply a value for construction. Stopping at that point prevents later effects while preserving effects that already happened.
Comprehension scopes and arrow boundaries
Each for source is resolved before that clause introduces its fresh immutable pattern bindings. Later clauses and the body see earlier bindings, and a later for clause may shadow an earlier name. Each source and filter uses the required outer parentheses and ordinary expression grammar inside them. The comprehension body arrow follows the complete parenthesized operand.
이유
A source is evaluated before its new pattern binds names, so it cannot accidentally refer to its own new binding. Required operand parentheses separate ordinary lambda syntax from the comprehension body arrow.
A refutable pattern does not silently filter
A comprehension may use a refutable pattern. Each reached element must match. The first mismatch raises runtime TPZ5001 and stops construction. Use an explicit filter or match expression to skip elements.
이유
A binding pattern requires an element to have the stated shape. Filtering belongs to if, so a pattern mismatch must not silently discard data.
Names inside one pattern must be distinct
One pattern introduces one scope and must not bind the same name twice. This differs from valid shadowing across separate for clauses. SELF currently misses the same-scope duplicate guard on plain list patterns; the intended TPZ5008 rejection is retained as an implementation limitation.
이유
One pattern must give each bound name one value. Repeated names would silently choose between different positions in the same element.
Duplicate elements and keys
링크Set order and duplicate elements
Set literals and comprehensions preserve the order of first occurrence and collapse duplicate elements.
Reinsertion, removal, traversal, and display follow Map and Set insertion order.
이유
Set membership ignores repeated equal elements. Preserving first encounter order also keeps iteration reproducible without rearranging the surviving values.
Map and Set insertion order
Map keys, values, and entries are observed in insertion order. Traversing those views with for preserves that order. Map display uses the same order. Inserting a new key appends it. Inserting an existing key replaces its value without moving the key. Removing a key preserves the relative order of surviving entries.
Set traversal and display follow insertion order. Adding an existing element keeps its position. Removing an element preserves the relative order of surviving elements. Set construction follows first occurrence order. Map and Set equality remains independent of this observation order.
Insertion and transfer follow collection value semantics. Collection equality is independent of insertion order.
이유
Map and Set use the same order rule. Preserving insertion order makes traversal and display reproducible. Replacing a value does not rearrange unrelated entries.
Repeated map literal keys
Repeating a string or integer literal key in a map literal produces TPZ5602.
이유
Two entries for the same key cannot both survive as separate associations. Rejecting an evident collision before execution catches accidental overwrites early.
Computed map key collisions
When computed keys collide during map literal or comprehension construction, execution fails with TPZ4601 without replacing the earlier value.
이유
Computed keys can collide after evaluation. Rejecting the collision prevents source order from silently choosing which value survives.
Computed map collision location
A computed duplicate key faults at the span of the complete map literal, whose start is the map keyword. The fault location is not the second key expression. The source-backed expectation for this fixture is example.tpz:2:14; the public CLI emission is tracked as an implementation limitation.
이유
A duplicate key is a conflict within the constructed map. Pointing to that construction identifies the operation that could not produce a value.
Canonical key equality
Key insertion follows value semantics. Canonical key equality compares the stored value family and then its contents recursively. Arrays compare elementwise; records compare field names and values; nominal records, enums, and newtypes retain declaration identity. Floating signed zeros compare equal, while NaN does not equal any key, including itself. Integer and floating keys have distinct tags. Equivalent constant spellings do not define different language values merely because static duplicate detection recognizes only some forms.
이유
Key comparison uses stored value contents while preserving scalar tags and nominal identity. A nominal Eq method does not replace that key identity. Different constant spellings must not create a separate key identity.
Duplicate constant boolean keys
A repeated constant boolean key is a duplicate just as a repeated constant string or integer key is. SELF currently parses booleans as expression/boolean but its constant-key checker tests expression/bool. The intended TPZ5602 rejection is retained as a product test, and the mismatched syntax kind is an implementation limitation.
이유
A boolean key has the same identity whether it is written directly or computed. Detecting a known collision early preserves the runtime duplicate-key rule.
Examples and expected results
링크Array, set, and map literals
링크let values: Array<int> = [1, 2, 3]let names: Set<string> = set { "Ada", "Lin" }let counts: Map<string, int> = map { "Ada": 1, "Lin": 2 }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Give empty collections a contextual type
링크let values: Array<int> = []let names: Set<string> = set {}let counts: Map<string, int> = map {}
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Append an array at the spread position
링크import std.io { writeLine }let values = [0, ...[1, 2], 3]for value in (values) {writeLine("{value}")}
0
1
2
3
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
0123
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
0123
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Nest clauses and filter the remaining body
링크import std.io { writeLine }let values = [for x in ([1, 2]) for y in ([10, 20]) if (x == 2) => x + y]for value in (values) {writeLine("{value}")}
12
22
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
1222
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
1222
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Construct a set from repeated body values
링크import std.io { writeLine }let values = set { for n in ([1, 2, 3, 4]) => n % 2 }for value in (values) {writeLine("{value}")}
1
0
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
10
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
10
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Produce key/value pairs in a map comprehension
링크let squares: Map<int, int> = map { for n in ([1, 2, 3]) if (n > 1) => n: n * n }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Reject a bare empty array without context
링크let values = []
표준 출력 없음.error[TPZ5020]: `[]` needs a contextual type (§22.1): annotate the binding or the expected element type
--> example.tpz:1:14
|
1 | let values = []
| ^^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5020]: `[]` needs a contextual type (§22.1): annotate the binding or the expected element type--> example.tpz:1:14|1 | let values = []| ^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5020; cause bare-empty-array-without-context; primary location asserted; additional diagnostics allow
Reject a concrete non-array spread operand
링크let values = [...1]
표준 출력 없음.error[TPZ5001]: array spread needs an `Array`, found `1`
--> example.tpz:1:18
|
1 | let values = [...1]
| ^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5001]: array spread needs an `Array`, found `1`--> example.tpz:1:18|1 | let values = [...1]| ^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5001; cause concrete-non-array-spread; primary location asserted; additional diagnostics allow
Reject an integer comprehension filter
링크let values = [for n in ([1, 2]) if (1) => n]
표준 출력 없음.error[TPZ5001]: expected `bool`, found `int`
--> example.tpz:1:34
|
1 | let values = [for n in [1, 2] if 1 => n]
| ^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5001]: expected `bool`, found `int`--> example.tpz:1:34|1 | let values = [for n in [1, 2] if 1 => n]| ^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5001; cause non-boolean-comprehension-filter; primary location asserted; additional diagnostics allow
Reject a repeated identical string key
링크let values = map { "same": 1, "same": 2 }
표준 출력 없음.error[TPZ5602]: duplicate key in `map { … }` literal
--> example.tpz:1:31
|
1 | let values = map { "same": 1, "same": 2 }
| ^^^^^^
example.tpz: 1 type diagnostic
기대 결과
기대 결과
거절 단계 check. 종료 코드가 0이 아닙니다.
repeated-identical-string-key-in-map-literal at
example.tpz:1:31
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5602]: duplicate key in `map { … }` literal--> example.tpz:1:31|1 | let values = map { "same": 1, "same": 2 }| ^^^^^^example.tpz: 1 type diagnostic
- 통과 · expected nonzero; observed 1
- 통과 · stdout matches the authored expectation
- 통과 · checking TPZ5602; cause repeated-identical-string-key-in-map-literal; primary location asserted; additional diagnostics allow
Reject colliding computed map keys at runtime
링크function key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(3): 30 }
표준 출력 없음.기대 결과
Repair the computed-key collision
링크function key(value: int) -> int { value % 2 }let values: Map<int, int> = map { key(1): 10, key(2): 20 }
표준 출력 없음.기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
표준 출력 없음.
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Reject a computed collision at the map literal start
링크function key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(3): 30 }
표준 출력 없음.기대 결과
Run the corresponding map with distinct computed keys
링크function key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(2): 30 }
표준 출력 없음.기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
Store and deduplicate array key values before later mutation
링크import std.iolet mut source = [1]let keys = set { source, [1], [2] }source.push(9)for key in (keys) {io.writeLine("{key.length}")}
1
1
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
11
Set elements follow value semantics. Changing source leaves the stored array values and their membership unchanged.
Reject a Map used as a Set element
링크let keys = set { map { "a": 1 } }
표준 출력 없음.기대 결과
Use recursively keyable arrays as Set elements
링크let keys = set { [1], [2] }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Keep numeric key families distinct and collapse signed floating zero
링크import std.iolet zeros = set { 0.0, -0.0 }let tagged = set { 1, 1.0 }let mut zeroCount = 0for value in (zeros) { zeroCount += 1 }let mut taggedCount = 0for value in (tagged) { taggedCount += 1 }io.writeLine("{zeroCount}:{taggedCount}")
1:2
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
1:2
Reject repeated true keys in a map literal
링크let values = map { true: 1, true: 2 }
표준 출력 없음.기대 결과
Check distinct true and false keys
링크let values = map { true: 1, false: 2 }
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Observe literal and nested comprehension evaluation order
링크import std.iofunction mark(label: string, value: int) -> int {io.writeLine(label)value}function source(n: int) -> Array<int> {io.writeLine("source:{n}")[n, n + 10]}function outerAllowed(n: int) -> bool {io.writeLine("outer:{n}")n > 0}function keep(n: int) -> bool {io.writeLine("filter:{n}")n < 10}let values = [mark("array1", 1), ...[mark("spread", 2)], mark("array3", 3)]let pairs = map { mark("key1", 1): mark("value1", 10), mark("key2", 2): mark("value2", 20) }let nested = [for outer in ([0, 1, 2]) if (outerAllowed(outer)) for inner in (source(outer)) if (keep(inner)) => mark("body:{inner}", inner)]io.writeLine("done")
array1
spread
array3
key1
value1
key2
value2
outer:0
outer:1
source:1
filter:1
body:1
filter:11
outer:2
source:2
filter:2
body:2
filter:12
done
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
array1spreadarray3key1value1key2value2outer:0outer:1source:1filter:1body:1filter:11outer:2source:2filter:2body:2filter:12done
Stop producing elements after Result propagation
링크import std.iofunction item(label: string, fail: bool) -> Result<int, string> {io.writeLine(label)if (fail) { Err("stop") } else { Ok(1) }}function build() -> Result<Array<int>, string> {let values = [item("first", false)?, item("second", true)?, item("third", false)?]Ok(values)}let outcome = build()match (outcome) {case Err(message) => io.writeLine(message)case Ok(_) => io.writeLine("unexpected success")}
first
second
stop
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
firstsecondstop
Reject a duplicate after evaluating all map pairs
링크import std.iofunction mark(label: string, value: int) -> int {io.writeLine(label)value}let values = map { mark("key1", 1): mark("value1", 10), mark("key2", 1): mark("value2", 20), mark("key3", 3): mark("value3", 30) }io.writeLine("after")
key1
value1
key2
value2
key3
value3
기대 결과
기대 결과
거절 단계 run. 종료 코드가 0이 아닙니다.
computed-map-key-collision at
example.tpz:6:14
key1value1key2value2key3value3
Check annotations, calls, returns, callbacks, and nested empties
링크function empty<T>() -> Array<T> { [] }function count(values: Array<int>) -> int { values.length }function invoke(callback: () -> Array<int>) -> Array<int> { callback() }let nested: Array<Array<int>> = [[], [1]]let items: Array<int | string> = [1, "text"]let n = count([])let callback: () -> Array<int> = () => []let result = invoke(() => [])let parenthesized: Array<int> = ([])let block: Array<int> = { [] }let keys: Set<int> = set {}let table: Map<string, int> = map {}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Reject a bare empty Set without context
링크let missing = set {}
표준 출력 없음.기대 결과
Give the empty Set an element type
링크let present: Set<int> = set {}
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Reject a concrete mismatch in a nested array
링크let nested: Array<Array<int>> = [["text"]]
표준 출력 없음.기대 결과
Match the nested array element expectation
링크let nested: Array<Array<int>> = [[1]]
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Preserve a known mismatch beside a nested empty value
링크let values: Array<Map<string, Array<int>>> = [map { "bad": ["text"], "empty": [] }]
표준 출력 없음.기대 결과
Complete the empty value without a conflicting sibling
링크let values: Array<Map<string, Array<int>>> = [map { "bad": [1], "empty": [] }]
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Shadow across clauses and delimit source or filter lambdas
링크import std.iolet values = [for x in ([1, 2]) for x in ([x, x + 10]) => x]for value in (values) { io.writeLine("{value}") }let selected = [for x in ((() => [1, 2])()) if (((n: int) => n > 1)(x)) => x]for value in (selected) { io.writeLine("selected:{value}") }
1
11
2
12
selected:2
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
111212selected:2
Collect when every element matches the refutable pattern
링크import std.iolet values = [for Some(x) in ([Some(1), Some(2)]) => x]for value in (values) { io.writeLine("{value}") }
1
2
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
12
Reject a repeated name within one list pattern
링크let values = [for [x, x] in ([[1, 2]]) => x]
표준 출력 없음.기대 결과
Use distinct names within the list pattern
링크let values = [for [x, y] in ([[1, 2]]) => x + y]
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Stop at a nonmatching element
링크import std.iolet values = [for Some(x) in ([Some(1), None(), Some(3)]) => x]io.writeLine("after")
표준 출력 없음.기대 결과
Check every literal component from its collection context
링크newtype Wrapped<T> = Tlet array: Array<Wrapped<int>> = [Wrapped(1)]let keys: Set<Wrapped<int>> = set { Wrapped(2) }let table: Map<Wrapped<int>, Wrapped<string>> = map { Wrapped(3): Wrapped("three") }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Check emitted comprehension components from their result context
링크newtype Wrapped<T> = Tlet array: Array<Wrapped<int>> = [for item in ([1, 2]) => Wrapped(item)]let keys: Set<Wrapped<int>> = set { for item in ([1, 2]) => Wrapped(item) }let table: Map<Wrapped<int>, Wrapped<string>> = map { for item in ([1, 2]) => Wrapped(item): Wrapped("{item}") }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Carry collection context through declared and expected callable results
링크newtype Wrapped<T> = Tfunction wrap<T>(value: T) -> Array<Wrapped<T>> { [Wrapped(value)] }let callback: () -> Set<Wrapped<int>> = () => set { Wrapped(1) }let result: Array<Wrapped<int>> = wrap(2)let keys = callback()
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Reject a concrete mismatch inside a contextual set
링크let values: Set<Array<int>> = set { ["text"] }
표준 출력 없음.기대 결과
Supply a compatible element in the same contextual set
링크let values: Set<Array<int>> = set { [1] }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Keep map values outside the set key domain under an annotation
링크let keys: Set<Map<string, int>> = set { map { "a": 1 } }
표준 출력 없음.기대 결과
Use a keyable collection element under an annotation
링크let keys: Set<Array<int>> = set { [1] }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Inferred comprehension types
링크let inferredArray = [for item in ([0]) => 1]let array: Array<int> = inferredArraylet inferredSet = set { for item in ([0]) => 1 }let keys: Set<int> = inferredSetlet inferredMap = map { for item in ([0]) => 1: "one" }let table: Map<int, string> = inferredMap
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Array comprehension with an expected literal type
링크let array: Array<1> = [for item in ([0]) => 1]
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Set comprehension with an expected literal type
링크let keys: Set<1> = set { for item in ([0]) => 1 }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Map comprehension with an expected literal type
링크let table: Map<1, "one"> = map { for item in ([0]) => 1: "one" }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Reuse functions through callback methods
링크import std.iofunction addPadding(width: int) -> int { width + 2 }function double(width: int) -> int { width * 2 }let widths = [10, 20]let chained = widths.map(addPadding).map(double)let constructed = [for width in (widths) => double(addPadding(width))]for width in (chained) {io.writeLine("callback {width}")}for width in (constructed) {io.writeLine("comprehension {width}")}
callback 24
callback 44
comprehension 24
comprehension 44
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
callback 24callback 44comprehension 24comprehension 44
Construct a collection from filtered sources
링크import std.iolet widths = [10, 20]let paddings = [1, 2]let outerWidths = [for width in (widths) if (width > 10) for padding in (paddings) => width + padding * 2]for width in (outerWidths) {io.writeLine("{width}")}
22
24
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
2224
Observe complete callback passes and per-element comprehension work
링크import std.iofunction source() -> Array<int> {io.writeLine("source")[1, 2, 3]}function selected(value: int) -> bool {io.writeLine("select {value}")value > 1}function convert(value: int) -> int {io.writeLine("convert {value}")value * 10}function predicate() -> (int) -> bool {io.writeLine("predicate")selected}function transformation() -> (int) -> int {io.writeLine("transformation")convert}io.writeLine("callback chain")let chained = source().filter(predicate()).map(transformation())io.writeLine("comprehension")let constructed = [for value in (source()) if (selected(value)) => convert(value)]io.writeLine("results")for value in (chained) {io.writeLine("callback {value}")}for value in (constructed) {io.writeLine("comprehension {value}")}
callback chain
source
predicate
select 1
select 2
select 3
transformation
convert 2
convert 3
comprehension
source
select 1
select 2
convert 2
select 3
convert 3
results
callback 20
callback 30
comprehension 20
comprehension 30
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
callback chainsourcepredicateselect 1select 2select 3transformationconvert 2convert 3comprehensionsourceselect 1select 2convert 2select 3convert 3resultscallback 20callback 30comprehension 20comprehension 30
Keep a Map key in place when replacing its value
링크import std.io { writeLine }let mut values = map { "first": 1, "middle": 2, "last": 3 }values.insert("middle", 20)for key in (values.keys) { writeLine(key) }for value in (values.values) { writeLine("{value}") }for entry in (values.entries) { writeLine("{entry.key}={entry.value}") }writeLine("{values}")
first
middle
last
1
20
3
first=1
middle=20
last=3
Map{first: 1, middle: 20, last: 3}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
firstmiddlelast1203first=1middle=20last=3Map{first: 1, middle: 20, last: 3}
Keep surviving Map entries in order after removal
링크import std.io { writeLine }let mut values = map { "first": 1, "removed": 2, "third": 3, "last": 4 }values.remove("removed")for entry in (values.entries) { writeLine("{entry.key}={entry.value}") }writeLine("{values}")
first=1
third=3
last=4
Map{first: 1, third: 3, last: 4}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
first=1third=3last=4Map{first: 1, third: 3, last: 4}
Keep surviving Set elements in order after removal
링크import std.io { writeLine }let mut values = set { 3, 1, 4, 2 }values.add(1)values.remove(1)for value in (values) { writeLine("{value}") }writeLine("{values}")
3
4
2
Set{3, 4, 2}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
342Set{3, 4, 2}
Pending contracts
링크Related diagnostics and references
링크Value is not comparable or keyable →