Scope and ownership
LinkEdition: Topaz 5.21 language mode. Source references identify the SELF implementation behind these rules. Each example records its expected result and verification state.
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
LinkArrayLiteral = "[" (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.
Source evidence
- parseArray at
af88afbc1d99· 282-322 - parseComprehensionClauses and collection comprehension parsers at
af88afbc1d99· 415-528 - parseIdentifierAtom comprehension dispatch at
af88afbc1d99· 1014-1025 - parseCollectionAtom comprehension dispatch at
af88afbc1d99· 1161-1167 - parseSet and parseMap at
af88afbc1d99· 530-583
Collection literal entries
An array literal accepts expressions and . entries. A set literal contains expressions, and a map literal contains key: value entries.
Why
Each literal exposes whether it stores a sequence, unique values, or key and value associations. Map entries keep each key beside its value.
Source evidence
- parseArray at
af88afbc1d99· 282-322 - parseSet and parseMap at
af88afbc1d99· 530-583
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.
Why
Comprehensions reuse the existing for and if control forms. The final arrow separates selection of bindings from the value produced for them.
Source evidence
- parseComprehensionClauses and collection comprehension parsers at
af88afbc1d99· 415-528 - parseIdentifierAtom comprehension dispatch at
af88afbc1d99· 1014-1025 - parseCollectionAtom comprehension dispatch at
af88afbc1d99· 1161-1167
Literal types and array spread
LinkArray literal type
An array literal forms Array<T> from its element types.
Why
A shared element type gives indexing and iteration one type contract. Inferring it from the entries avoids repeating type information for every value.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752
Set literal type
A set literal forms Set<T> from its element types.
Why
A shared element type lets membership and duplicate checks use one value contract. The supplied entries provide the information needed to infer that type.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752
Map literal type
A map literal forms Map<K, V> from its key and value types.
Why
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.
Source evidence
- inferMapLiteralExpression at
af88afbc1d99· 754-823
Context for empty collections
Why
Collection syntax does not introduce a separate typing model.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - inferMapLiteralExpression at
af88afbc1d99· 754-823
Bare empty collections require context
Why
The reason a collection needs context is independent of its surface form.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - inferMapLiteralExpression at
af88afbc1d99· 754-823
Array spread element type
Spreading a concrete Array<T> contributes elements of type T to the containing array literal.
Why
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.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - iterableElement and arraySpreadElement at
af88afbc1d99· 55-122
Reject a non-array spread operand
An array spread whose concrete, non-union operand type is not Array<T> produces TPZ5001.
Why
Array spread copies stored array elements. Requiring an array avoids adding an implicit conversion from other iterable values during construction.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - iterableElement and arraySpreadElement at
af88afbc1d99· 55-122
Array construction order
Array construction appends ordinary values and inserts each spread operand’s elements at the spread position.
Why
Arrays preserve positions, so each entry must contribute where it appears. Expanding a spread in place preserves the relative order of its elements.
Source evidence
- emitArray and emitMap at
af88afbc1d99· 539-592 - array_spread_extend, called by SELF output at
af88afbc1d99· 830-849
Collection key checks
Key-capability checking applies to set elements and map keys in literals and comprehensions, independently of map values.
Why
Set elements and map keys determine membership and lookup identity. Map values are payloads, so they do not need the key comparison capability.
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - inferMapLiteralExpression at
af88afbc1d99· 754-823 - inferComprehension at
af88afbc1d99· 1690-1781 - nonKeyableType and gateCollectionKey at
af88afbc1d99· 520-647
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.
Why
Keys require a supported equality comparison throughout their structure. Rejecting incompatible components prevents membership and lookup from reaching an unsupported comparison.
Source evidence
- nonKeyableType and gateCollectionKey at
af88afbc1d99· 520-647
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.
Why
Stable stored values keep membership and lookup consistent. Insertion follows value semantics, including compound keys.
Source evidence
- nonKeyableType and gateCollectionKey at
151141d7bb44· 520-647 - canonical_key and freeze at
151141d7bb44· 62-175 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713 - issues/31 at
1162031127a0
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.
Why
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.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
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.
Why
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.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842 - inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
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.
Why
Filling an unknown element type must not erase a known incompatible value. Otherwise an annotation could admit values that violate the collection type.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Comprehension clauses and results
LinkCallback 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.
Why
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.
Source evidence
- issues/31 at
26da6a582932 - native array map and filter emission at
26da6a582932· 1539-1573 - prepare_callback_hof and callback execution transitions at
26da6a582932· 595-727 - comprehensionClauses and emitComprehension at
26da6a582932· 2489-2524
Nested comprehension clauses
Each later comprehension clause executes inside the preceding clauses.
Why
Later clauses can use earlier bindings because they execute inside those scopes. This gives the clause sequence the same meaning as explicit nested loops.
Source evidence
- comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925
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.
Why
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.
Source evidence
- comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925
Accumulate reached body results
Each successful comprehension body evaluation contributes one element or one map key/value pair.
Why
Each reached body supplies one result entry. This keeps the number and order of produced entries tied to successful body evaluations.
Source evidence
- comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925
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.
Why
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.
Source evidence
- iterableElement and arraySpreadElement at
af88afbc1d99· 55-122 - inferComprehension at
af88afbc1d99· 1690-1781
Reject a non-iterable source
A concrete non-iterable source in a comprehension produces TPZ5001.
Why
Iteration requires a defined sequence of elements. Rejecting other values avoids inventing an implicit conversion or a type-dependent notion of iteration.
Source evidence
- checkedIterableElement at
af88afbc1d99· 479-496 - inferComprehension at
af88afbc1d99· 1690-1781
Comprehension filters require bool
A comprehension if condition must have type bool. A non-boolean condition produces TPZ5001.
Why
A filter uses the same boolean condition rule as if. Requiring bool avoids an additional truthiness convention for numbers, strings, or collections.
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781
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.
Why
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781
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.
Why
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781
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.
Why
Independent inference supplies a useful collection type without context. A matching expectation supplies component types that remain intact after successful checking.
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781
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.
Why
A fixed operand order makes collection effects reproducible. Map construction receives evaluated pairs, so expression evaluation and duplicate validation have separate failure points.
Source evidence
- emitArray at
151141d7bb44· 539-567 - emitMap at
151141d7bb44· 570-587 - comprehensionClauses and emitComprehension at
151141d7bb44· 1889-1925 - builtin_map_of at
151141d7bb44· 698-713
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.
Why
A failed expression cannot supply a value for construction. Stopping at that point prevents later effects while preserving effects that already happened.
Source evidence
- emitArray at
151141d7bb44· 539-567 - emitMap at
151141d7bb44· 570-587 - comprehensionClauses and emitComprehension at
151141d7bb44· 1889-1925 - builtin_map_of at
151141d7bb44· 698-713 - array_spread_extend at
151141d7bb44· 836-849 - emitQuestion at
151141d7bb44· 1927-1934
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.
Why
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.
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
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.
Why
A binding pattern requires an element to have the stated shape. Filtering belongs to if, so a pattern mismatch must not silently discard data.
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
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.
Why
One pattern must give each bound name one value. Repeated names would silently choose between different positions in the same element.
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Duplicate elements and keys
LinkSet 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.
Why
Set membership ignores repeated equal elements. Preserving first encounter order also keeps iteration reproducible without rearranging the surviving values.
Source evidence
- builtin_set_of, called by SELF output at
af88afbc1d99· 628-637 - comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925 - issues/31 at
1cbf38d3d422
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.
Why
Map and Set use the same order rule. Preserving insertion order makes traversal and display reproducible. Replacing a value does not rearrange unrelated entries.
Source evidence
- OrderedMap::insert, OrderedMap::remove, OrderedSet::remove at
1cbf38d3d422· 385-524 - issues/31 at
1cbf38d3d422
Repeated map literal keys
Repeating a string or integer literal key in a map literal produces TPZ5602.
Why
Two entries for the same key cannot both survive as separate associations. Rejecting an evident collision before execution catches accidental overwrites early.
Source evidence
- inferMapLiteralExpression at
af88afbc1d99· 754-823
Computed map key collisions
When computed keys collide during map literal or comprehension construction, execution fails with TPZ4601 without replacing the earlier value.
Why
Computed keys can collide after evaluation. Rejecting the collision prevents source order from silently choosing which value survives.
Source evidence
- builtin_map_of, called by SELF output at
af88afbc1d99· 693-713 - emitArray and emitMap at
af88afbc1d99· 539-592 - comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925
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.
Why
A duplicate key is a conflict within the constructed map. Pointing to that construction identifies the operation that could not produce a value.
Source evidence
- parseMap at
151141d7bb44· 547-575 - emitMap at
151141d7bb44· 570-587 - builtin_map_of at
151141d7bb44· 693-713
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.
Why
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.
Source evidence
- canonical_key and freeze at
151141d7bb44· 62-175 - keys_equal at
151141d7bb44· 244-335 - inferMap constant duplicate detection at
151141d7bb44· 774-796 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713 - issues/31 at
1162031127a0
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.
Why
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.
Source evidence
- boolean expression syntax kind at
151141d7bb44· 1221-1230 - inferMap constant duplicate detection at
151141d7bb44· 774-796 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713
Examples and expected results
LinkArray, set, and map literals
Linklet 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)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Observed assertions · passed · 5.21.3
Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- parseArray at
af88afbc1d99· 282-322 - parseSet and parseMap at
af88afbc1d99· 530-583 - inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - inferMapLiteralExpression at
af88afbc1d99· 754-823
Give empty collections a contextual type
Linklet 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)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Observed assertions · passed · 5.21.3
Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - inferMapLiteralExpression at
af88afbc1d99· 754-823
Append an array at the spread position
Linkimport std.io { writeLine }let values = [0, ...[1, 2], 3]for value in (values) {writeLine("{value}")}
0 1 2 3
Expected result
Expected result
Execution completes. Exit code 0.
0123
Observed assertions · passed · 5.21.3
Exit code 0.
0123
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - emitArray and emitMap at
af88afbc1d99· 539-592 - array_spread_extend, called by SELF output at
af88afbc1d99· 830-849
Nest clauses and filter the remaining body
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
1222
Observed assertions · passed · 5.21.3
Exit code 0.
1222
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- parseComprehensionClauses and collection comprehension parsers at
af88afbc1d99· 415-528 - inferComprehension at
af88afbc1d99· 1690-1781 - comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925
Construct a set from repeated body values
Linkimport std.io { writeLine }let values = set { for n in ([1, 2, 3, 4]) => n % 2 }for value in (values) {writeLine("{value}")}
1 0
Expected result
Expected result
Execution completes. Exit code 0.
10
Observed assertions · passed · 5.21.3
Exit code 0.
10
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781 - comprehensionClauses and emitComprehension at
af88afbc1d99· 1889-1925 - builtin_set_of, called by SELF output at
af88afbc1d99· 628-637
Produce key/value pairs in a map comprehension
Linklet 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)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Observed assertions · passed · 5.21.3
Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- parseComprehensionClauses and collection comprehension parsers at
af88afbc1d99· 415-528 - inferComprehension at
af88afbc1d99· 1690-1781
Reject a bare empty array without context
Linklet values = []
No stdout.
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 result
Expected result
Rejection during check. Nonzero exit.
TPZ5020bare-empty-array-without-context atexample.tpz:1:14
Observed assertions · passed · 5.21.3
Exit code 1.
No stdout.
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
- Passed · expected nonzero; observed 1
- Passed · stdout matches the authored expectation
- Passed · checking TPZ5020; cause bare-empty-array-without-context; primary location asserted; additional diagnostics allow
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752
Reject a concrete non-array spread operand
Linklet values = [...1]
No stdout.
error[TPZ5001]: array spread needs an `Array`, found `1` --> example.tpz:1:18 | 1 | let values = [...1] | ^ example.tpz: 1 type diagnostic
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5001concrete-non-array-spread atexample.tpz:1:18
Observed assertions · passed · 5.21.3
Exit code 1.
No stdout.
error[TPZ5001]: array spread needs an `Array`, found `1`--> example.tpz:1:18|1 | let values = [...1]| ^example.tpz: 1 type diagnostic
- Passed · expected nonzero; observed 1
- Passed · stdout matches the authored expectation
- Passed · checking TPZ5001; cause concrete-non-array-spread; primary location asserted; additional diagnostics allow
Source evidence
- inferSequenceLiteralExpression at
af88afbc1d99· 659-752 - iterableElement and arraySpreadElement at
af88afbc1d99· 55-122
Reject an integer comprehension filter
Linklet values = [for n in ([1, 2]) if (1) => n]
No stdout.
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 result
Expected result
Rejection during check. Nonzero exit.
TPZ5001non-boolean-comprehension-filter atexample.tpz:1:37
Observed assertions · passed · 5.21.3
Exit code 1.
No stdout.
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
- Passed · expected nonzero; observed 1
- Passed · stdout matches the authored expectation
- Passed · checking TPZ5001; cause non-boolean-comprehension-filter; primary location asserted; additional diagnostics allow
Source evidence
- inferComprehension at
af88afbc1d99· 1690-1781
Reject a repeated identical string key
Linklet values = map { "same": 1, "same": 2 }
No stdout.
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 result
Expected result
Rejection during check. Nonzero exit.
TPZ5602repeated-identical-string-key-in-map-literal atexample.tpz:1:31
Observed assertions · passed · 5.21.3
Exit code 1.
No stdout.
error[TPZ5602]: duplicate key in `map { … }` literal--> example.tpz:1:31|1 | let values = map { "same": 1, "same": 2 }| ^^^^^^example.tpz: 1 type diagnostic
- Passed · expected nonzero; observed 1
- Passed · stdout matches the authored expectation
- Passed · checking TPZ5602; cause repeated-identical-string-key-in-map-literal; primary location asserted; additional diagnostics allow
Source evidence
- inferMapLiteralExpression at
af88afbc1d99· 754-823
Reject colliding computed map keys at runtime
Linkfunction key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(3): 30 }
No stdout.
Expected result
Expected result
Rejection during run. Nonzero exit.
TPZ4601computed-map-key-collision
The required primary-location contract is Pending.
Source evidence
- inferMapLiteralExpression at
af88afbc1d99· 754-823 - emitArray and emitMap at
af88afbc1d99· 539-592 - builtin_map_of, called by SELF output at
af88afbc1d99· 693-713
Repair the computed-key collision
Linkfunction key(value: int) -> int { value % 2 }let values: Map<int, int> = map { key(1): 10, key(2): 20 }
No stdout.
Expected result
Expected result
Execution completes. Exit code 0.
Observed assertions · passed · 5.21.3
Exit code 0.
No stdout.
No stderr.
- Passed · expected 0; observed 0
- Passed · stdout matches the authored expectation
- Passed · stderr matches the authored expectation
Source evidence
- inferMapLiteralExpression at
af88afbc1d99· 754-823 - emitArray and emitMap at
af88afbc1d99· 539-592 - builtin_map_of, called by SELF output at
af88afbc1d99· 693-713
Reject a computed collision at the map literal start
Linkfunction key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(3): 30 }
No stdout.
Expected result
Expected result
Rejection during run. Nonzero exit.
TPZ4601computed-map-key-collision atexample.tpz:2:14
Source evidence
- parseMap at
151141d7bb44· 547-575 - emitMap at
151141d7bb44· 570-587 - builtin_map_of at
151141d7bb44· 693-713
Run the corresponding map with distinct computed keys
Linkfunction key(value: int) -> int { value % 2 }let values = map { key(1): 10, key(2): 30 }
No stdout.
Expected result
Expected result
Execution completes. Exit code 0.
Source evidence
- emitMap at
151141d7bb44· 570-587 - builtin_map_of at
151141d7bb44· 693-713
Store and deduplicate array key values before later mutation
Linkimport std.iolet mut source = [1]let keys = set { source, [1], [2] }source.push(9)for key in (keys) {io.writeLine("{key.length}")}
1 1
Expected result
Expected result
Execution completes. Exit code 0.
11
Set elements follow value semantics. Changing source leaves the stored array values and their membership unchanged.
Source evidence
- nonKeyableType and gateCollectionKey at
151141d7bb44· 520-647 - canonical_key and freeze at
151141d7bb44· 62-175 - keys_equal at
151141d7bb44· 244-335 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713
Reject a Map used as a Set element
Linklet keys = set { map { "a": 1 } }
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5007structures-map-is-not-keyable atexample.tpz:1:12
Source evidence
- nonKeyableType and gateCollectionKey at
151141d7bb44· 520-647 - canonical_key and freeze at
151141d7bb44· 62-175
Use recursively keyable arrays as Set elements
Linklet keys = set { [1], [2] }
example.tpz: types-ok (1 module) example.tpz: resolve-ok (1 module)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Source evidence
- nonKeyableType and gateCollectionKey at
151141d7bb44· 520-647 - canonical_key and freeze at
151141d7bb44· 62-175
Keep numeric key families distinct and collapse signed floating zero
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
1:2
Source evidence
- canonical_key and freeze at
151141d7bb44· 62-175 - keys_equal at
151141d7bb44· 244-335 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713
Reject repeated true keys in a map literal
Linklet values = map { true: 1, true: 2 }
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5602structures-duplicate-boolean-map-key atexample.tpz:1:29
Source evidence
- boolean expression syntax kind at
151141d7bb44· 1221-1230 - inferMap constant duplicate detection at
151141d7bb44· 774-796 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713
Check distinct true and false keys
Linklet values = map { true: 1, false: 2 }
example.tpz: types-ok (1 module) example.tpz: resolve-ok (1 module)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Source evidence
- boolean expression syntax kind at
151141d7bb44· 1221-1230 - inferMap constant duplicate detection at
151141d7bb44· 774-796 - builtin_set_of and builtin_map_of at
151141d7bb44· 628-637;693-713
Observe literal and nested comprehension evaluation order
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
array1spreadarray3key1value1key2value2outer:0outer:1source:1filter:1body:1filter:11outer:2source:2filter:2body:2filter:12done
Source evidence
- emitArray at
151141d7bb44· 539-567 - emitMap at
151141d7bb44· 570-587 - comprehensionClauses and emitComprehension at
151141d7bb44· 1889-1925 - builtin_map_of at
151141d7bb44· 698-713
Stop producing elements after Result propagation
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
firstsecondstop
Source evidence
- emitArray at
151141d7bb44· 539-567 - emitQuestion at
151141d7bb44· 1927-1934
Reject a duplicate after evaluating all map pairs
Linkimport 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
Expected result
Expected result
Rejection during run. Nonzero exit.
TPZ4601computed-map-key-collision atexample.tpz:6:14
key1value1key2value2key3value3
Source evidence
- emitMap at
151141d7bb44· 570-587 - builtin_map_of at
151141d7bb44· 698-713
Check annotations, calls, returns, callbacks, and nested empties
Linkfunction 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 {}
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Reject a bare empty Set without context
Linklet missing = set {}
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5020structures-empty-collection-context atexample.tpz:1:15
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Give the empty Set an element type
Linklet present: Set<int> = set {}
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Reject a concrete mismatch in a nested array
Linklet nested: Array<Array<int>> = [["text"]]
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5001structures-nested-array-element-type atexample.tpz:1:35
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Match the nested array element expectation
Linklet nested: Array<Array<int>> = [[1]]
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Preserve a known mismatch beside a nested empty value
Linklet values: Array<Map<string, Array<int>>> = [map { "bad": ["text"], "empty": [] }]
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5001structures-nested-array-element-type atexample.tpz:2:17
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842 - inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Complete the empty value without a conflicting sibling
Linklet values: Array<Map<string, Array<int>>> = [map { "bad": [1], "empty": [] }]
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
151141d7bb44· 659-752 - inferMapLiteralExpression at
151141d7bb44· 754-823 - inferBindingValue / bareBindingExpression / block tail at
151141d7bb44· 139-214;922-949 - currentExpectedExpression / return context at
151141d7bb44· 514-594;638-658 - inferContextualCallArgument at
151141d7bb44· 167-208 - inferLambda at
151141d7bb44· 350-405 - parenthesized inference / inferComprehension at
151141d7bb44· 1375-1385;1690-1778 - checkExpressionExpectedResult / refineExpressionToExpected at
151141d7bb44· 1716-1747;1939-1979 - unionType at
151141d7bb44· 785-842
Shadow across clauses and delimit source or filter lambdas
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
111212selected:2
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Collect when every element matches the refutable pattern
Linkimport std.iolet values = [for Some(x) in ([Some(1), Some(2)]) => x]for value in (values) { io.writeLine("{value}") }
1 2
Expected result
Expected result
Execution completes. Exit code 0.
12
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Reject a repeated name within one list pattern
Linklet values = [for [x, x] in ([[1, 2]]) => x]
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5008structures-duplicate-pattern-binding atexample.tpz:1:23
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Use distinct names within the list pattern
Linklet values = [for [x, y] in ([[1, 2]]) => x + y]
example.tpz: types-ok (1 module) example.tpz: resolve-ok (1 module)
Expected result
Expected result
Checking accepts the program. Exit code 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Stop at a nonmatching element
Linkimport std.iolet values = [for Some(x) in ([Some(1), None(), Some(3)]) => x]io.writeLine("after")
No stdout.
Expected result
Expected result
Rejection during run. Nonzero exit.
TPZ5001structures-for-pattern-nonmatch atexample.tpz:2:14
Source evidence
- parseComprehensionClauses / nested and non-naked-lambda expression at
151141d7bb44· 415-456;1036-1084;1649-1687 - walkComprehensionExpression at
151141d7bb44· 563-616 - inferComprehension at
151141d7bb44· 1690-1781 - iterationBinding / emitPatternLet at
151141d7bb44· 1852-1864;2267-2272 - refutable pattern failure at
151141d7bb44· 85-98 - bindPattern at
151141d7bb44· 442-469 - bindNamedPatternType / OR-pattern duplicate check at
151141d7bb44· 542-585;1481-1496 - bindSymbol at
151141d7bb44· 266-307 - canonical diagnostic phase guard at
151141d7bb44· 279-291
Check every literal component from its collection context
Linknewtype 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") }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Check emitted comprehension components from their result context
Linknewtype 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}") }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Carry collection context through declared and expected callable results
Linknewtype 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()
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Reject a concrete mismatch inside a contextual set
Linklet values: Set<Array<int>> = set { ["text"] }
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5001structures-nested-array-element-type atexample.tpz:1:38
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Supply a compatible element in the same contextual set
Linklet values: Set<Array<int>> = set { [1] }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Keep map values outside the set key domain under an annotation
Linklet keys: Set<Map<string, int>> = set { map { "a": 1 } }
No stdout.
Expected result
Expected result
Rejection during check. Nonzero exit.
TPZ5007structures-map-is-not-keyable atexample.tpz:1:11
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Use a keyable collection element under an annotation
Linklet keys: Set<Array<int>> = set { [1] }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Inferred comprehension types
Linklet 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
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Array comprehension with an expected literal type
Linklet array: Array<1> = [for item in ([0]) => 1]
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Set comprehension with an expected literal type
Linklet keys: Set<1> = set { for item in ([0]) => 1 }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Map comprehension with an expected literal type
Linklet table: Map<1, "one"> = map { for item in ([0]) => 1: "one" }
No stdout.
Expected result
Expected result
Checking accepts the program. Exit code 0.
Source evidence
- inferSequenceLiteralExpression at
271329b482bc· 659-752 - inferMapLiteralExpression at
271329b482bc· 754-823 - inferComprehension at
271329b482bc· 1690-1778 - checkExpressionExpectedResult, refineExpressionToExpected at
271329b482bc· 1716-1747;1939-1979 - newtypeCallType at
271329b482bc· 1345-1370 - nonKeyableType, gateCollectionKey at
271329b482bc· 520-647 - pull/41 at
271329b482bc
Reuse functions through callback methods
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
callback 24callback 44comprehension 24comprehension 44
Source evidence
- issues/31 at
26da6a582932 - native array map and filter emission at
26da6a582932· 1539-1573 - prepare_callback_hof and callback execution transitions at
26da6a582932· 595-727 - comprehensionClauses and emitComprehension at
26da6a582932· 2489-2524
Construct a collection from filtered sources
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
2224
Source evidence
- issues/31 at
26da6a582932 - native array map and filter emission at
26da6a582932· 1539-1573 - prepare_callback_hof and callback execution transitions at
26da6a582932· 595-727 - comprehensionClauses and emitComprehension at
26da6a582932· 2489-2524
Observe complete callback passes and per-element comprehension work
Linkimport 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
Expected result
Expected result
Execution completes. Exit code 0.
callback chainsourcepredicateselect 1select 2select 3transformationconvert 2convert 3comprehensionsourceselect 1select 2convert 2select 3convert 3resultscallback 20callback 30comprehension 20comprehension 30
Source evidence
- issues/31 at
26da6a582932 - native array map and filter emission at
26da6a582932· 1539-1573 - prepare_callback_hof and callback execution transitions at
26da6a582932· 595-727 - comprehensionClauses and emitComprehension at
26da6a582932· 2489-2524
Keep a Map key in place when replacing its value
Linkimport 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}
Expected result
Expected result
Execution completes. Exit code 0.
firstmiddlelast1203first=1middle=20last=3Map{first: 1, middle: 20, last: 3}
Source evidence
- OrderedMap::insert, OrderedMap::remove, OrderedSet::remove at
1cbf38d3d422· 385-524 - issues/31 at
1cbf38d3d422
Keep surviving Map entries in order after removal
Linkimport 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}
Expected result
Expected result
Execution completes. Exit code 0.
first=1third=3last=4Map{first: 1, third: 3, last: 4}
Source evidence
- OrderedMap::insert, OrderedMap::remove, OrderedSet::remove at
1cbf38d3d422· 385-524 - issues/31 at
1cbf38d3d422
Keep surviving Set elements in order after removal
Linkimport 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}
Expected result
Expected result
Execution completes. Exit code 0.
342Set{3, 4, 2}
Source evidence
- OrderedMap::insert, OrderedMap::remove, OrderedSet::remove at
1cbf38d3d422· 385-524 - issues/31 at
1cbf38d3d422