mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:07:06 +00:00
Add specification of set literals.
Bug: 63d164fa7a/accepted/future-releases/set-literals/implementation-plan.md
(Task 10)
Change-Id: I9728706e235162318aec824484274aea58210e8a
Reviewed-on: https://dart-review.googlesource.com/c/84600
Commit-Queue: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
Reviewed-by: Erik Ernst <eernst@google.com>
This commit is contained in:
parent
e98701ea33
commit
8dd03bee13
|
@ -27,6 +27,7 @@
|
|||
% 2.2
|
||||
% - Specify whether the values of literal expressions override Object.==.
|
||||
% - Allow Type objects as case expressions and const map keys.
|
||||
% - Introduce set literals.
|
||||
%
|
||||
% 2.1
|
||||
% - Remove 64-bit constraint on integer literals compiled to JavaScript numbers.
|
||||
|
@ -5628,6 +5629,12 @@ not a constant expression (\ref{const}).
|
|||
that occurs in a constant context, is a potentially constant expression if $T$ is a constant type expression, and $e_1$, \ldots{} , $e_n$ are constant expressions.
|
||||
It is further a constant expression if the list literal evaluates to a value.
|
||||
|
||||
\item A constant set literal (\ref{set}),
|
||||
\code{\CONST{} <$T$>\{$e_1$, \ldots{}, $e_n$\}}, or
|
||||
\code{<$T$>\{$e_1$, \ldots{}, $e_n$\}}
|
||||
that occurs in a constant context, is a potentially constant expression if $T$ is a constant type expression, and $e_1$, \ldots{} , $e_n$ are constant expressions.
|
||||
It is further a constant expression if the list literal evaluates to a value.
|
||||
|
||||
\item A constant map literal (\ref{maps}),
|
||||
\code{\CONST{} <$K$, $V$>\{$k_1$: $v_1$, \ldots{}, $k_n$: $v_n$\}}, or
|
||||
\code{<$K$, $V$>\{$k_1$: $v_1$, \ldots{}, $k_n$: $v_n$\}} that occurs in a constant context,
|
||||
|
@ -5820,6 +5827,8 @@ As an example, consider:
|
|||
\alt <stringLiteral>
|
||||
\alt <symbolLiteral>
|
||||
\alt <mapLiteral>
|
||||
\alt <setLiteral>
|
||||
\alt <setOrMapLiteral>
|
||||
\alt <listLiteral>
|
||||
\end{grammar}
|
||||
|
||||
|
@ -6412,15 +6421,36 @@ A \IndexCustom{map literal}{literal!map} denotes a map object.
|
|||
|
||||
\begin{grammar}
|
||||
<mapLiteral> ::= \CONST{}? <typeArguments>?
|
||||
\gnewline{} `{' (<mapLiteralEntry> (`,' <mapLiteralEntry>)* `,'?)? `\}'
|
||||
\gnewline{} `{' <mapLiteralEntry> (`,' <mapLiteralEntry>)* `,'? `}'
|
||||
|
||||
<mapLiteralEntry> ::= <expression> `:' <expression>
|
||||
|
||||
<setOrMapLiteral> ::= \CONST{}? <typeArguments>? `{' `}'
|
||||
\end{grammar}
|
||||
|
||||
\LMHash{}%
|
||||
A \synt{setOrMapLiteral} is either set literal (\ref {sets}) or a map literal,
|
||||
determined by the type parameters or static context type.
|
||||
If the literal expression has exactly one type argument,
|
||||
then it is a set literal.
|
||||
If it has two type arguments, then it is a map literal.
|
||||
If it has three or more type arguments, it is a compile-time error.
|
||||
If it has \emph{no} type arguments,
|
||||
then if \code{LinkedHashSet<Null>} is assignable to the
|
||||
static context type of the literal,
|
||||
and \code{LinkedHashMap<Null, Null>} is not,
|
||||
it is set literal,
|
||||
and otherwise it is a map literal.
|
||||
A map literal derived from \synt{setOrMapLiteral}
|
||||
is treated the same way as one derived from \synt{mapLiteral},
|
||||
as described below.
|
||||
|
||||
\LMHash{}%
|
||||
A map literal consists of zero or more entries.
|
||||
Each entry has a \Index{key} and a \Index{value}.
|
||||
Each key and each value is denoted by an expression.
|
||||
It is a compile-time error if a map literal has one type argument,
|
||||
or more than two type arguments.
|
||||
|
||||
\LMHash{}%
|
||||
If a map literal begins with the reserved word \CONST{}, it is a
|
||||
|
@ -6473,6 +6503,10 @@ If{}f \code{identical($o_{1i}$, $o_{2i}$)} and \code{identical($s_{1i}$, $s_{2i}
|
|||
In other words, constant map literals are canonicalized.
|
||||
}
|
||||
|
||||
\LMHash{}%
|
||||
It is a compile-time error if two keys of a constant map literal are equal
|
||||
according to their \code{==} operator (\ref{equality}).
|
||||
|
||||
\LMHash{}%
|
||||
A run-time map literal
|
||||
\code{<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}}
|
||||
|
@ -6483,8 +6517,8 @@ For each $i \in 1 .. n$ in numeric order,
|
|||
first the expression $k_i$ is evaluated producing object $u_i$,
|
||||
and then $e_i$ is evaluated producing object $o_i$.
|
||||
This produces all the objects $u_1, o_1, \ldots, u_n, o_n$.
|
||||
\item A fresh instance (\ref{generativeConstructors}) $m$ whose class implements the built-in class
|
||||
\code{Map<$K, V$>} is allocated.
|
||||
\item A fresh instance (\ref{generativeConstructors}) $m$
|
||||
whose class implements the built-in class \code{Map<$K, V$>}, is allocated.
|
||||
\item
|
||||
The operator \syntax{`[]='} is invoked on $m$ with first argument $u_i$ and second argument $o_i$ for each $i \in 1 .. n$.
|
||||
\item
|
||||
|
@ -6502,9 +6536,6 @@ is evaluated as
|
|||
|
||||
\code{<\DYNAMIC{}, \DYNAMIC{}>\{$k_1:e_1, \ldots, k_n:e_n$\}}.
|
||||
|
||||
\LMHash{}%
|
||||
It is a compile-time error if two keys of a constant map literal are equal.
|
||||
|
||||
\LMHash{}%
|
||||
A map literal is ordered: iterating over the keys and/or values of the maps always happens in the
|
||||
order the keys appeared in the source code.
|
||||
|
@ -6527,6 +6558,121 @@ or the form
|
|||
\code{Map<\DYNAMIC{}, \DYNAMIC{}>}.
|
||||
|
||||
|
||||
\subsection{Sets}
|
||||
\LMLabel{sets}
|
||||
|
||||
\LMHash{}%
|
||||
A \IndexCustom{set literal}{literal!set} denotes a set object.
|
||||
|
||||
\begin{grammar}
|
||||
<setLiteral> ::= \CONST{}? <typeArguments>?
|
||||
\gnewline{} `{' <expression> (`,' <expression>)* `,'? `\}'
|
||||
\end{grammar}
|
||||
|
||||
\LMHash{}%
|
||||
A \synt{setOrMapLiteral} is either set literal or a map literal (\ref {maps}).
|
||||
A set literal derived from \synt{setOrMapLiteral}
|
||||
is treated the same way as one derived from \synt{setLiteral},
|
||||
as described below.
|
||||
|
||||
\LMHash{}%
|
||||
A set literal consists of zero or more element expressions.
|
||||
It is a compile-time error if a set literal has more than one type argument.
|
||||
|
||||
\LMHash{}%
|
||||
\rationale{
|
||||
A set literal with no type argument is always converted to a literal
|
||||
with a type argument by type inference (\ref{overview}), so the following
|
||||
section only address the behavior of literals with type arguments.}
|
||||
|
||||
\LMHash{}%
|
||||
If a set literal begins with the reserved word \CONST{},
|
||||
or if it occurs in a constant context, then it is a
|
||||
\IndexCustom{constant set literal}{literal!set!constant}
|
||||
which is a constant expression (\ref{constants}) and therefore evaluated at compile time.
|
||||
Otherwise, it is a
|
||||
\IndexCustom{run-time set literal}{literal!set!run-time}
|
||||
and it is evaluated at run time.
|
||||
Only run-time set literals can be mutated after they are created.
|
||||
Attempting to mutate a constant set literal will result in a dynamic error.
|
||||
|
||||
\LMHash{}%
|
||||
It is a compile-time error if an element expression in a constant set literal is not a constant expression.
|
||||
It is a compile-time error if the element object in a constant set literal is an instance of
|
||||
a class that has a concrete operator \syntax{`=='} declaration different from the one in \code{Object},
|
||||
unless the element is a string or an integer,
|
||||
the element expression evaluates to an instance of the built-in
|
||||
class \code{Symbol} which was originally obtained by evaluation of a
|
||||
literal symbol or
|
||||
a constant invocation of a constructor of the \code{Symbol} class,
|
||||
or to an object implementing the built-in class \code{Type}
|
||||
which was originally obtained by evaluating a constant type literal
|
||||
(\ref{dynamicTypeSystem}).
|
||||
It is a compile-time error if the type argument of a constant set literal
|
||||
is not a constant type expression \ref{constants}.
|
||||
It is a compile-time error if two elements of a constant set literal are equal
|
||||
according to their \code{==} operator (\ref{equality}).
|
||||
|
||||
\LMHash{}%
|
||||
The value of a constant set literal with element expressions
|
||||
$e_1, \dots, e_n$ and type argument $E$
|
||||
is an object $s$ whose class implements the built-in class
|
||||
\code{Set<$E$>}.
|
||||
The elements of $m$ are $v_i, i \in 1 .. n$, where $v_i$ is the value of the constant expression $e_i$.
|
||||
|
||||
\LMHash{}%
|
||||
Let $set_1$ be a constant set literal with type argument $E$
|
||||
and element expressions, in source order, $e_{11}, \ldots, e_{1n}$ evaluating
|
||||
to values $v_{11}, \ldots, v_{1n}$.
|
||||
Let $set_2$ be a constant set literal with type argument $F$
|
||||
and element expressions, in source order, $e_{21}, \ldots, e_{2n}$ evaluating
|
||||
to values $v_{21}, \ldots, v_{2n}$.
|
||||
If{}f \code{identical($v_{1i}$, $v_{2i}$)}
|
||||
for $i \in 1 .. n$, and $E$ and $F$ is the same type,
|
||||
then \code{identical($set_1$, $set_2$)}.
|
||||
\commentary{
|
||||
In other words, constant set literals are canonicalized if they have
|
||||
the same type and the same values in the same order.
|
||||
}
|
||||
Two constant set literals are never identical if they have different numbers
|
||||
of elements.
|
||||
|
||||
\LMHash{}%
|
||||
A run-time set literal with element expressions $e_1, \ldots, e_n$
|
||||
(in source order) and with type argument $E$
|
||||
is evaluated as follows:
|
||||
\begin{itemize}
|
||||
\item
|
||||
For each $i \in 1 .. n$ in numeric order,
|
||||
the expression $e_i$ is evaluated producing object $v_i$.
|
||||
\item A fresh instance (\ref{generativeConstructors}) $s$
|
||||
of the built-in class \code{LinkedHashSet<$E$>}, is allocated.
|
||||
\item
|
||||
The operator \code{add} is invoked on $s$ with argument $v_i$ for each $i \in 1 .. n$ in numerical order.
|
||||
\item
|
||||
The result of the evaluation is $s$.
|
||||
\end{itemize}
|
||||
|
||||
\LMHash{}%
|
||||
The objects created by set literals do not override
|
||||
the \code{==} operator inherited from the \code{Object} class.
|
||||
|
||||
\LMHash{}%
|
||||
A set literal is ordered: iterating over the elements of the sets
|
||||
always happens in the order the elements first appeared in the source code.
|
||||
|
||||
\commentary{
|
||||
If a value repeats, the order is defined by first occurrence, but the value is defined by the last.
|
||||
}
|
||||
|
||||
\LMHash{}%
|
||||
The static type of a set literal of the form
|
||||
\code{\CONST{} <$E$>\{$e_1, \ldots, e_n$\}}
|
||||
or the form
|
||||
\code{<$E$>\{$e_1, \ldots, e_n$\}}
|
||||
is
|
||||
\code{Set<$E$>}.
|
||||
|
||||
\subsection{Throw}
|
||||
\LMLabel{throw}
|
||||
|
||||
|
|
23
tests/language_2/set_literals/const_set_flag_test.dart
Normal file
23
tests/language_2/set_literals/const_set_flag_test.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Canary test to check that set literals are not enabled *without* an
|
||||
// experimental flag.
|
||||
|
||||
// Remove this test when the set literals feature is enabled without a flag.
|
||||
|
||||
main() {
|
||||
var _ = {1}; //# 01: compile-time error
|
||||
var _ = <int>{}; //# 02: compile-time error
|
||||
Set _ = {}; //# 03: compile-time error
|
||||
Set _ = <int>{}; //# 04: compile-time error
|
||||
var _ = const {1}; //# 05: compile-time error
|
||||
var _ = const <int>{}; //# 06: compile-time error
|
||||
Set _ = const {}; //# 07: compile-time error
|
||||
Set _ = const <int>{}; //# 08: compile-time error
|
||||
const _ = {1}; //# 09: compile-time error
|
||||
const _ = <int>{}; //# 10: compile-time error
|
||||
const Set _ = {}; //# 11: compile-time error
|
||||
const Set _ = <int>{}; //# 12: compile-time error
|
||||
}
|
|
@ -20,8 +20,8 @@ void main() {
|
|||
= const <int, int, int>{1} //# 06: compile-time error
|
||||
= const <int, int>{1} //# 07: compile-time error
|
||||
= const {Duration(seconds: 0)} // Overrides ==. //# 08: compile-time error
|
||||
= {4.2} // Overrides ==. //# 09: compile-time error
|
||||
= {d} // Overrides ==. //# 10: compile-time error
|
||||
= const {4.2} // Overrides ==. //# 09: compile-time error
|
||||
= const {d} // Overrides ==. //# 10: compile-time error
|
||||
= {,} //# 11: compile-time error
|
||||
= {1,,} //# 12: compile-time error
|
||||
= {1,,1} //# 13: compile-time error
|
||||
|
@ -33,7 +33,6 @@ void main() {
|
|||
= {4.2} //# 15: compile-time error
|
||||
= {1: 1} //# 16: compile-time error
|
||||
= {{}} //# 17: compile-time error
|
||||
= <Object>{} // Exact type. //# 18: compile-time error
|
||||
;
|
||||
Expect.isNull(s);
|
||||
|
||||
|
@ -50,16 +49,6 @@ void main() {
|
|||
;
|
||||
Expect.isNull(hs);
|
||||
|
||||
LinkedHashSet<int> lhs //
|
||||
= const {} // exact type is Set //# 24: compile-time error
|
||||
;
|
||||
Expect.isNull(lhs);
|
||||
|
||||
LinkedHashSet<LinkedHashSet<int>> lhs2 //
|
||||
= {const {}} // exact type LHS<Set>. //# 25: compile-time error
|
||||
;
|
||||
Expect.isNull(lhs2);
|
||||
|
||||
<T>(x) {
|
||||
// Type constants are allowed, type variables are not.
|
||||
var o //
|
||||
|
@ -77,4 +66,25 @@ void main() {
|
|||
= {}; //# 28: compile-time error
|
||||
;
|
||||
}();
|
||||
|
||||
// Constant sets must not contain equal elements.
|
||||
const s = {
|
||||
1,
|
||||
"s",
|
||||
#foo,
|
||||
int,
|
||||
C(1),
|
||||
{1},
|
||||
1, //# 29: compile-time error
|
||||
"s", //# 30: compile-time error
|
||||
#foo, //# 31: compile-time error
|
||||
int, //# 32: compile-time error
|
||||
C(1), //# 33: compile-time error
|
||||
{1}, //# 34: compile-time error
|
||||
};
|
||||
}
|
||||
|
||||
class C {
|
||||
final Object id;
|
||||
const C(this.id);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue