chharvey / counterpoint

A robust programming language.
GNU Affero General Public License v3.0
2 stars 0 forks source link

Spread — Collection Literals #64

Open chharvey opened 3 years ago

chharvey commented 3 years ago

Spread syntax is a way of injecting collection entries into other collections.

Discussion

Fixed-Size Spread

Tuple Spread

Tuples may be spread into other tuple literals, wherin the items of the first tuple are injected into the second tuple, in order, where the spread syntax is.

let cde: str[3] = [c, d, e]; % assume these variables are strings
let abcdefg = str[7] = [a, b, #cde, f, g];
abcdefg == [a, b, c, d, e, f, g];

The symbol # is called the single-spread symbol. It’s technically not an operator, since it doesn’t produce an expression, and it doesn’t have the same precedence as unary operators. For example, [#a || b, c] is interpreted as [#(a || b), c].

Tuples may also be spread into set literals.

let cde: [str, str, str] = [c, d, e]; % assume these variables are strings
let def = str{} = [d, e, #cde, f];
def == {d, e, c, f};

Record Spread

Records can be spread into other records, but since records have keys, the rules for record spreading is stricter than for tuple spreading. Record spreading uses the symbol ##, and duplicate record keys are overwritten in source order. The symbol ## is called the double-spread symbol (again, not an actual operator).

type Car = [
    make:  str,
    model: str,
    color: str,
    year:  int,
];
let my_car: Car = [
    make=  'Mazda',
    model= 'Protegé',
    color= 'black',
    year=  2003,
];
let new_car: Car = [
    color= 'red',
    ##my_car,
    year= 2010,
];
new_car == [
    make=  'Mazda',
    model= 'Protegé',
    color= 'black',
    year=  2010,
];

Notice that new_car.color == 'black' but new_car.year == 2010. This is because the spread ##my_car overwrote the color = 'red', but the new year overwrote the year in my_car. Properties later in source order have higher precedence. When multiple records are spread, properties cascde over each other in source order.

let newer_car: Car = [
    make=  'Honda',
    model= 'Civic',
    color= 'blue',
    year=  2008,
    ##[make= 'Mazda', model= 'Protegé'], % overwrite make and model
    ##[year= 2010],                      % overwrite year
];
newer_car == [
    make=  'Mazda',
    model= 'Protegé',
    color= 'blue',
    year=  2010,
]

Variable-Size Spread

List Spread

Lists can be spread into sets only.

let cde: str[] = List.<str>([c, d, e]); % assume these variables are strings
let def = str{} = {d, e, #cde, f};
def == {d, e, c, f};

Since there is not yet a literal construction syntax for lists, lists cannot be spread into lists.

let cde: str[] = List.<str>([c, d, e]); % assume these variables are strings
let abcdefg = str[] = List.<str>([a, b, #cde, f, g]); %> error (see below): cannot spread list into tuple

Hash Spread

Likewise, we cannot yet spread hashes into hashes.

let my_car: [:str | int] = Hash.<str | int>([
    make=  'Mazda',
    model= 'Protegé',
    color= 'black',
    year=  2003,
]);
let new_car: [:str | int] = Hash.<str | int>([
    color= 'red',
    ##Hash.<unknown>(old_car), %> error (see below): cannot spread hash into record
    year= 2010,
]);

Set Spread

Sets can be spread into other sets.

let cde: str{} = {c, d, e}; % assume these variables are strings
let def = str{} = {d, e, #cde, f};
def == {d, e, c, f};

Sets cannot yet be spread into lists, since there is not yet a list literal syntax.

Map Spread

Maps can be spread into one another with the triple-spread symbol ###.

let office: Map.<C, C> = {
    jim    -> pam,
    dwight -> angela,
    andy   -> erin,
};
let parks: Map.<C, C> = {
    leslie -> ben,
    ann    -> chris,
    april  -> andy,
};
[###office, ###parks] == {
    jim    -> pam,
    dwight -> angela,
    andy   -> erin,
    leslie -> ben,
    ann    -> chris,
    april  -> andy,
};

Maps overwrite cases in the same way that records overwrite properties.

Errors

We get syntax errors by using the wrong arity of spread inside the wrong syntaxes…

[1,  ##x]; %> ParseError: double-spread inside tuple literal
[1, ###x]; %> ParseError: triple-spread inside tuple literal
[ ##x, 1]; %> ParseError: expression inside record literal
[###x, 1]; %> ParseError: triple-spread inside tuple/record literal
[a= 1,   #y]; %> ParseError: single-spread inside record literal
[a= 1, ###y]; %> ParseError: triple-spread inside record literal
[  #y, a= 1]; %> ParseError: property inside tuple literal
[###y, a= 1]; %> ParseError: triple-spread inside tuple/record literal
{1,  ##x}; %> ParseError: double-spread inside set literal
{1, ###x}; %> ParseError: triple-spread inside set literal
{ ##x, 1}; %> ParseError: double-spread inside set/map literal
{###x, 1}; %> ParseError: expression inside map literal
{'a' -> 1,  #z}; %> ParseError: single-spread inside map literal
{'a' -> 1, ##z}; %> ParseError: double-spread inside map literal
{ #z, 'a' -> 1}; %> ParseError: case inside set literal
{##z, 'a' -> 1}; %> ParseError: double-spread inside set/map literal

and we get type errors by using the wrong arity of spread on the wrong types:

[1, #[b= 2, c= 3]];         %> TypeError: single-spread on record type
[1, #{'b' -> 2, 'c' -> 3}]; %> TypeError: single-spread on map type
[a= 1, ##[2, 3]];               %> TypeError: double-spread on tuple type
[a= 1, ##{2, 3}];               %> TypeError: double-spread on set type
[a= 1, ##{'b' -> 2, 'c' -> 3}]; %> TypeError: double-spread on map type
{'a' -> 1, ###[2, 3]};       %> TypeError: triple-spread on tuple type
{'a' -> 1, ###{2, 3},};      %> TypeError: triple-spread on set type
{'a' -> 1, ###[b= 2, c= 3]}; %> TypeError: triple-spread on record type

Since the counts of tuples are static (known at compile-time), we get type errors where counts don’t match up.

let failure: str[5] = [a, #[c, d, e]];             %> TypeError (count 4 not assignable to count 5)
let failure: str[3] = [a, #[c, d, e]];             %> TypeError (count 4 not assignable to count 3)
let failure: str[5] = [a, #List.<str>([c, d, e])]; %> TypeError (count unknown int not assignable to count 5)
let failure: str[3] = [a, #List.<str>([c, d, e])]; %> TypeError (count unknown int not assignable to count 3)

Similarly for records, since record keys are static.

let failure: [a: int, b: bool, c: str] = [a= 42, ##[b= 'bool', c= true]];   %> TypeError: true not assignable to str
let failure: [a: int, b: bool, c: str] = [a= 42, ##[b= true, d= 'string']]; %> TypeError: missing property `c`

Specification

Lexicon

Punctuator :::=
    // unary
+       | "#" | "##" | "###"
;

TokenWorth

+TokenWorth(Punctuator :::= "#")   -> RealNumber := \x06;
+TokenWorth(Punctuator :::= "##")  -> RealNumber := \x07;
+TokenWorth(Punctuator :::= "###") -> RealNumber := \x08;
-TokenWorth(Punctuator :::= "!")   -> RealNumber := \x06;
-TokenWorth(Punctuator :::= "?")   -> RealNumber := \x07;
+TokenWorth(Punctuator :::= "!")   -> RealNumber := \x09;
+TokenWorth(Punctuator :::= "?")   -> RealNumber := \x0a;
# and so on…

Syntax

-TupleLiteral  ::= "[" ( ","?                     Expression#  ","? )? "]";
-RecordLiteral ::= "["   ","?                     Property#    ","?    "]";
-SetLiteral    ::= "{" ( ","?                     Expression#  ","? )? "}";
-MapLiteral    ::= "{"   ","?                     Case#        ","?    "}";
+TupleLiteral  ::= "[" ( ","? ("#"   Expression | Expression)# ","? )? "]";
+RecordLiteral ::= "["   ","? ("##"  Expression | Property)#   ","?    "]";
+SetLiteral    ::= "{" ( ","? ("#"   Expression | Expression)# ","? )? "}";
+MapLiteral    ::= "{"   ","? ("###" Expression | Case)#       ","?    "}";

Semantics

+SemanticSpread[arity: 1 | 2 | 3]
+   ::= Expression;

-SemanticTuple   ::=  SemanticExpression*;
-SemanticRecord  ::=  SemanticProperty+;
-SemanticSet     ::=  SemanticExpression*;
-SemanticMap     ::=  SemanticCase+;
+SemanticTuple   ::= (SemanticExpression | SemanticSpread[arity: 1])*;
+SemanticRecord  ::= (SemanticProperty   | SemanticSpread[arity: 2])+;
+SemanticSet     ::= (SemanticExpression | SemanticSpread[arity: 1])*;
+SemanticMapping ::= (SemanticCase       | SemanticSpread[arity: 3])+;

Decorate

+   Decorate(TupleLiteral__0__List ::= "#" Expression) -> Vector<SemanticSpread>
+       := [(SemanticSpread[arity=1] Decorate(Expression))];
    Decorate(TupleLiteral__0__List ::= Expression) -> Vector<SemanticExpression>
        := [Decorate(Expression)];
+   Decorate(TupleLiteral__0__List ::= TupleLiteral__0__List "," "#" Expression) -> Sequence<SemanticExpression | SemanticSpread>
+       := [
+           ...Decorate(TupleLiteral__0__List),
+           (SemanticSpread[arity=1] Decorate(Expression)),
+       ];
-   Decorate(TupleLiteral__0__List ::= TupleLiteral__0__List "," Expression) -> Sequence<SemanticExpression>
+   Decorate(TupleLiteral__0__List ::= TupleLiteral__0__List "," Expression) -> Sequence<SemanticExpression | SemanticSpread>
        := [
            ...Decorate(TupleLiteral__0__List),
            Decorate(Expression),
        ];

+   Decorate(RecordLiteral__0__List ::= "##" Expression) -> Vector<SemanticSpread>
+       := [(SemanticSpread[arity=2] Decorate(Expression))];
    Decorate(RecordLiteral__0__List ::= Property) -> Vector<SemanticProperty>
        := [Decorate(Property)];
+   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," "##" Expression) -> Sequence<SemanticProperty | SemanticSpread>
+       := [
+           ...Decorate(RecordLiteral__0__List),
+           (SemanticSpread[arity=2] Decorate(Expression)),
+       ];
-   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," Property) -> Sequence<SemanticProperty>
+   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," Property) -> Sequence<SemanticProperty | SemanticSpread>
        := [
            ...Decorate(RecordLiteral__0__List),
            Decorate(Property),
        ];

+   Decorate(MapLiteral__0__List ::= "###" Expression) -> Vector<SemanticSpread>
+       := [(SemanticSpread[arity=3] Decorate(Expression))];
    Decorate(MapLiteral__0__List ::= Case) -> Vector<SemanticCase>
        := [Decorate(Case)];
+   Decorate(MapLiteral__0__List ::= MapLiteral__0__List "," "###" Expression) -> Sequence<SemanticCase | SemanticSpread>
+       := [
+           ...Decorate(MapLiteral__0__List),
+           (SemanticSpread[arity=3] Decorate(Expression)),
+       ];
-   Decorate(MapLiteral__0__List ::= MapLiteral__0__List "," Case) -> Sequence<SemanticCase>
+   Decorate(MapLiteral__0__List ::= MapLiteral__0__List "," Case) -> Sequence<SemanticCase | SemanticSpread>
        := [
            ...Decorate(MapLiteral__0__List),
            Decorate(Case),
        ];

Workaround

If this feature is not implemented, a sufficient workround is to manually list out the entries.

let tup: int[3] = [2, 3, 4];
[1, tup.0, tup.1, tup.2, 5]; % [1, #tup, 5]
chharvey commented 3 years ago

Alternate suggestion for spread syntax: .*.

Discussion

A new suggestion for the spread symbol .* has the familiarity of the bash-like glob selector. x.* has the same precedence as the dot-accessor (#25), but it’s not technically an accessor; it stands for “select all the elements in x”. For example, the entries of [!x.*, y ^ z.*, x.*.0, z.* ^ y] are all ill-formed. The .* syntax must only be used on compound expressions (awaits, property accesses, and function calls), and it must be the last “operation” in a collection’s entry. The entries of [(!x).*, (y ^ z).*, x.0.*, 42 . *] are all well-formed (even if type-invalid).

This proposal suggests using the same symbol .* for all 3 kinds of spreads: tuples, records, and mappings. With the current grammar, this would make an expression such as [x.*, y.*, z.*] syntactically ambiguous — Is it a tuple literal, record literal, or mapping literal? Therefore we need a new syntax production for a literal containing only spread items (whose compile-time type could not be determined by syntax), and then modify the tuple, record, and mapping literal productions such that they must, respectively, contain at least 1 expression, property, or case.

Tuple Spread

let cde: [str, str, str] = [c, d, e]; % assume these variables are strings
let abcdefg = [str, str, str, str, str, str, str] = [a, b, cde.*, f, g];
abcdefg == [a, b, c, d, e, f, g];

Record Spread

type Car = [
    make:  str,
    model: str,
    color: str,
    year:  int,
];
let my_car: Car = [
    make=  'Mazda',
    model= 'Protegé',
    color= 'black',
    year=  2003,
];
let new_car: Car = [
    color= 'red',
    my_car.*,
    year= 2010,
];
new_car == [
    make=  'Mazda',
    model= 'Protegé',
    color= 'black',
    year=  2010,
];

Mapping Spread

let office: obj = [
    jim    |-> pam,
    dwight |-> angela,
    andy   |-> erin,
];
let parks: obj = [
    leslie |-> ben,
    ann    |-> chris,
    april  |-> andy,
];
[office.*, parks.*] == [
    jim    |-> pam,
    dwight |-> angela,
    andy   |-> erin,
    leslie |-> ben,
    ann    |-> chris,
    april  |-> andy,
];

Errors

let failure: [str, str, str, str, str] = [a, [c, d, e].*]; %> TypeError (count 4 not assignable to count 5)
let failure: [str, str, str]           = [a, [c, d, e].*]; %> TypeError (count 4 not assignable to count 3)
let failure: [a: int, b: bool, c: str] = [a= 42, [b= 'bool', c= true].*];   %> TypeError: `true` not assignable to `str`
let failure: [a: int, b: bool, c: str] = [a= 42, [b= true, d= 'string'].*]; %> TypeError: missing property `c`
[1, [b= 2, c= 3].*];           %> TypeError: record  spread into tuple
[[b= 2, c= 3].*, 1];           %> TypeError: record  spread into tuple
[1, ['b' |-> 2, 'c' |-> 3].*]; %> TypeError: mapping spread into tuple
[['b' |-> 2, 'c' |-> 3].*, 1]; %> TypeError: mapping spread into tuple
[a= 1, [2, 3].*];                 %> TypeError: tuple   spread into record
[[2, 3].*, a= 1];                 %> TypeError: tuple   spread into record
[a= 1, ['b' |-> 2, 'c' |-> 3].*]; %> TypeError: mapping spread into record
[['b' |-> 2, 'c' |-> 3].*, a= 1]; %> TypeError: mapping spread into record
['a' |-> 1, [2, 3].*];       %> TypeError: tuple  spread into mapping
[[2, 3].*, 'a' |-> 1];       %> TypeError: tuple  spread into mapping
['a' |-> 1, [b= 2, c= 3].*]; %> TypeError: record spread into mapping
[[b= 2, c= 3].*, 'a' |-> 1]; %> TypeError: record spread into mapping

[[b= 2, c= 3].*, [1].*];           %> TypeError: tuple spread into record
[['b' |-> 2, 'c' |-> 3].*, [1].*]; %> TypeError: tuple spread into mapping
[[2, 3].*, [a= 1].*];                 %> TypeError: record spread into tuple
[['b' |-> 2, 'c' |-> 3].*, [a= 1].*]; %> TypeError: record spread into mapping
[[2, 3].*, ['a' |-> 1].*];       %> TypeError: mapping spread spread into tuple
[[b= 2, c= 3].*, ['a' |-> 1].*]; %> TypeError: mapping spread spread into record

Specification

Syntax

+Spread
+   ::= ExpressionCompound "." "*";

-ListLiteral      ::= "[" ","?                Expression#                              ","? "]";
-RecordLiteral    ::= "[" ","?                Property#                                ","? "]";
-MappingLiteral   ::= "[" ","?                Case#                                    ","? "]";
+CollectionSpread ::= "[" ","?                Spread#                                  ","? "]";
+ListLiteral      ::= "[" ","? (Spread# ",")? Expression ("," (Spread | Expression)#)? ","? "]";
+RecordLiteral    ::= "[" ","? (Spread# ",")? Property   ("," (Spread | Property)#)?   ","? "]";
+MappingLiteral   ::= "[" ","? (Spread# ",")? Case       ("," (Spread | Case)#)?       ","? "]";

ExpressionUnit ::=
    | "[" "]"
    | IDENTIFIER
    | PrimitiveLiteral
    | StringTemplate
+   | CollectionSpread
    | ListLiteral
    | RecordLiteral
    | MappingLiteral
    | "(" Expression ")"
;

ExpressionCompound ::=
    | ExpressionUnit
    | ExpressionCompound PropertyAccess
;

Semantics

+SemanticSpread
+   ::= Expression;

SemanticEmptyCollection   ::= ();
-SemanticList             ::= SemanticExpression+;
-SemanticRecord           ::= SemanticProperty+;
-SemanticMapping          ::= SemanticCase+;
+SemanticSpreadCollection ::= SemanticSpread+;
+SemanticList             ::= SemanticSpread* SemanticExpression (SemanticSpread | SemanticExpression)*;
+SemanticRecord           ::= SemanticSpread* SemanticProperty   (SemanticSpread | SemanticProperty)*;
+SemanticMapping          ::= SemanticSpread* SemanticCase       (SemanticSpread | SemanticCase)*;

Decorate

+Decorate(Spread ::= ExpressionCompound "." "*") -> SemanticSpread
+   := (SemanticSpread Decorate(ExpressionCompound));

+Decorate(CollectionSpread ::= "[" ","? CollectionSpread__0__List ","? "]") -> SemanticSpreadCollection
+   := (SemanticSpreadCollection
+       ...Decorate(CollectionSpread__0__List)
+   );

+   Decorate(CollectionSpread__0__List ::= Spread) -> Tuple<SemanticSpread>
+       := [Decorate(Spread)];
+   Decorate(CollectionSpread__0__List ::= CollectionSpread__0__List "," Spread) -> Sequence<SemanticSpread>
+       := [
+           ...Decorate(CollectionSpread__0__List),
+           Decorate(Spread),
+       ];

-Decorate(ListLiteral ::= "[" ","? ListLiteral__0__List ","? "]") -> SemanticList
-   := (SemanticList
-       ...Decorate(ListLiteral__0__List)
-   );
+Decorate(ListLiteral ::= "[" ","? Expression ","? "]") -> SemanticList
+   := (SemanticList Decorate(Expression));
+Decorate(ListLiteral ::= "[" ","? Expression "," ListLiteral__0__List ","? "]") -> SemanticList
+   := (SemanticList
+       Decorate(Expression)
+       ...Decorate(ListLiteral__0__List)
+   );
+Decorate(ListLiteral ::= "[" ","? CollectionSpread__0__List "," Expression ","? "]") -> SemanticList
+   := (SemanticList
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Expression)
+   );
+Decorate(ListLiteral ::= "[" ","? CollectionSpread__0__List "," Expression "," ListLiteral__0__List ","? "]") -> SemanticList
+   := (SemanticList
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Expression)
+       ...Decorate(ListLiteral__0__List)
+   );

    Decorate(ListLiteral__0__List ::= Expression) -> Tuple<SemanticExpression>
        := [Decorate(Expression)];
+   Decorate(ListLiteral__0__List ::= Spread) -> Tuple<SemanticSpread>
+       := [Decorate(Spread)];
-   Decorate(ListLiteral__0__List ::= ListLiteral__0__List "," Expression) -> Sequence<SemanticExpression>
+   Decorate(ListLiteral__0__List ::= ListLiteral__0__List "," Expression) -> Sequence<SemanticExpression | SemanticSpread>
        := [
            ...Decorate(ListLiteral__0__List),
            Decorate(Expression),
        ];
+   Decorate(ListLiteral__0__List ::= ListLiteral__0__List "," Spread) -> Sequence<SemanticExpression | SemanticSpread>
+       := [
+           ...Decorate(ListLiteral__0__List),
+           Decorate(Spread),
+       ];

-Decorate(RecordLiteral ::= "[" ","? RecordLiteral__0__List ","? "]") -> SemanticRecord
-   := (SemanticRecord
-       ...Decorate(RecordLiteral__0__List)
-   );
+Decorate(RecordLiteral ::= "[" ","? Property ","? "]") -> SemanticRecord
+   := (SemanticRecord Decorate(Property));
+Decorate(RecordLiteral ::= "[" ","? Property "," RecordLiteral__0__List ","? "]") -> SemanticRecord
+   := (SemanticRecord
+       Decorate(Property)
+       ...Decorate(RecordLiteral__0__List)
+   );
+Decorate(RecordLiteral ::= "[" ","? CollectionSpread__0__List "," Property ","? "]") -> SemanticRecord
+   := (SemanticRecord
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Property)
+   );
+Decorate(RecordLiteral ::= "[" ","? CollectionSpread__0__List "," Property "," RecordLiteral__0__List ","? "]") -> SemanticRecord
+   := (SemanticRecord
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Property)
+       ...Decorate(RecordLiteral__0__List)
+   );

    Decorate(RecordLiteral__0__List ::= Property) -> Tuple<SemanticProperty>
        := [Decorate(Property)];
+   Decorate(RecordLiteral__0__List ::= Spread) -> Tuple<SemanticSpread>
+       := [Decorate(Spread)];
-   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," Property) -> Sequence<SemanticProperty>
+   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," Property) -> Sequence<SemanticProperty | SemanticSpread>
        := [
            ...Decorate(RecordLiteral__0__List),
            Decorate(Property),
        ];
+   Decorate(RecordLiteral__0__List ::= RecordLiteral__0__List "," Spread) -> Sequence<SemanticProperty | SemanticSpread>
+       := [
+           ...Decorate(RecordLiteral__0__List),
+           Decorate(Spread),
+       ];

-Decorate(MappingLiteral ::= "[" ","? MappingLiteral__0__List ","? "]") -> SemanticMapping
-   :=(SemanticMapping
-       ...Decorate(MappingLiteral__0__List)
-   );
+Decorate(MappingLiteral ::= "[" ","? Case ","? "]") -> SemanticMapping
+   := (SemanticMapping Decorate(Case));
+Decorate(MappingLiteral ::= "[" ","? Case "," MappingLiteral__0__List ","? "]") -> SemanticMapping
+   := (SemanticMapping
+       Decorate(Case)
+       ...Decorate(MappingLiteral__0__List)
+   );
+Decorate(MappingLiteral ::= "[" ","? CollectionSpread__0__List "," Case ","? "]") -> SemanticMapping
+   := (SemanticMapping
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Case)
+   );
+Decorate(MappingLiteral ::= "[" ","? CollectionSpread__0__List "," Case "," MappingLiteral__0__List ","? "]") -> SemanticMapping
+   := (SemanticMapping
+       ...Decorate(CollectionSpread__0__List)
+       Decorate(Case)
+       ...Decorate(MappingLiteral__0__List)
+   );

    Decorate(MappingLiteral__0__List ::= Case) -> Tuple<SemanticCase>
        := [Decorate(Case)];
+   Decorate(MappingLiteral__0__List ::= Spread) -> Tuple<SemanticSpread>
+       := [Decorate(Spread)];
-   Decorate(MappingLiteral__0__List ::= MappingLiteral__0__List "," Case) -> Sequence<SemanticCase>
+   Decorate(MappingLiteral__0__List ::= MappingLiteral__0__List "," Case) -> Sequence<SemanticCase | SemanticSpread>
        := [
            ...Decorate(MappingLiteral__0__List),
            Decorate(Case),
        ];
+   Decorate(MappingLiteral__0__List ::= MappingLiteral__0__List "," Spread) -> Sequence<SemanticCase | SemanticSpread>
+       := [
+           ...Decorate(MappingLiteral__0__List),
+           Decorate(Spread),
+       ];

Workaround

let tup: [int, int, int] = [2, 3, 4];
[1, tup.0, tup.1, tup.2, 5]; % [1, tup.*, 5]