mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Adjusted the optional-const/new specs.
The informal specifications of optional-const and optional-new used to be incomplete, and this CL adds missing parts (transformation rules for lists and maps, and for `assignableExpression`). This version of the documents preserves the property that no `const` is added without immediate syntactic justification. The alternative (where `const` is used also in other contexts where either `const` or `new` must be added, just because we can do that) is not specified here, that'll be another CL. The corrections done in this CL will be needed, anyway, so I separated the two. R=lrn@google.com Review-Url: https://codereview.chromium.org/3005833002 .
This commit is contained in:
parent
07d16559f2
commit
00e98af7ef
2 changed files with 145 additions and 99 deletions
|
@ -2,9 +2,9 @@
|
|||
|
||||
Author: eernst@.
|
||||
|
||||
Version: 0.1 (2017-08-10)
|
||||
Version: 0.2 (2017-08-30)
|
||||
|
||||
Status: Under discussion
|
||||
Status: Under implementation.
|
||||
|
||||
**This document** is an informal specification of the *optional const* feature.
|
||||
**The feature** adds support for omitting the reserved word `const` in list and
|
||||
|
@ -26,8 +26,8 @@ literal provides no extra information: It is a compile-time error if that
|
|||
object expression is modified to use `new` rather than `const`. In that
|
||||
situation it carries no extra information whether `new` or `const` is used, and
|
||||
it is even possible to omit the reserved word entirely. It is also required for
|
||||
certain other expressions to be constant, e.g., default values on formal
|
||||
parameters and initializing expressions for constant variables.
|
||||
certain other expressions to be constant, e.g., initializing expressions for
|
||||
constant variables.
|
||||
|
||||
In all these cases the presence of `const` is required, and hence such a
|
||||
`const` may be inferred by compilers and similar tools if it is omitted.
|
||||
|
@ -35,9 +35,9 @@ In all these cases the presence of `const` is required, and hence such a
|
|||
Developers reading the source code are likely to find it easy to understand
|
||||
that a required `const` was omitted and is implied, because the reason for
|
||||
the requirement is visible in the enclosing syntax: The expression where
|
||||
`const` is inferred is a subexpression of an expression with `const`, it is
|
||||
used to initialize a constant variable, or it is a default value for a formal
|
||||
parameter.
|
||||
`const` is inferred is a subexpression of an expression with `const` or it
|
||||
is used in another situation where a constant value is required, e.g., to
|
||||
initialize a constant variable.
|
||||
|
||||
In summary, tools do not need the required occurrences of `const`, and they
|
||||
are also unimportant for developers. Conversely, omitting required occurrences
|
||||
|
@ -80,42 +80,21 @@ postfixExpression ::=
|
|||
primary selector*
|
||||
constructorInvocation ::= // NEW
|
||||
typeName typeArguments '.' identifier arguments
|
||||
assignableExpression ::=
|
||||
SUPER unconditionalAssignableSelector |
|
||||
typeName typeArguments '.' identifier arguments
|
||||
(arguments* assignableSelector)+ | // NEW
|
||||
identifier |
|
||||
primary (arguments* assignableSelector)+
|
||||
```
|
||||
|
||||
*A complete grammar which includes these changes is available
|
||||
[here](https://gist.github.com/eernstg/024a997f4f8c7ef885d459c3703a35f6).*
|
||||
|
||||
*Note that the alternative which is added in the rule for `assignableExpression`
|
||||
is required in order to allow expressions which are obtained by constructing a
|
||||
constant object expression in Dart without optional const and removing the
|
||||
`const`. That particular case will not match any of the cases where the `const`
|
||||
is required (because `assignableExpression` is only used in contexts which
|
||||
cannot be constant expressions). However, this approach yields syntactic support
|
||||
for omitting `const` in every `constantObjectExpression`, and it also allows for
|
||||
omitting `new` from every `newExpression`, which is useful for the
|
||||
associated
|
||||
[optional new feature](https://gist.github.com/eernstg/7e819b44acd8dd9d71f0cc510b618a3d).*
|
||||
|
||||
*The grammar only needs to be adjusted for one case, namely invocations of named
|
||||
constructors for generic classes. In this case we can derive expressions like
|
||||
`const Foo<int>.bar()`, and the corresponding `Foo<int>.bar()` is not derivable
|
||||
in the same situations where the variant with `const` can be derived. In other
|
||||
words, we must add support for constructs like `Foo<int>.bar()` as part of a
|
||||
`postfixExpression` and as part of an `assignableExpression`. For all other
|
||||
situations, the variant with `const` becomes a construct which is already
|
||||
syntactically correct Dart when the `const` is removed. For instance `const
|
||||
C(42)` becomes `C(42)` which could already be a function invocation and is hence
|
||||
already allowed syntactically.*
|
||||
`postfixExpression`. For all other situations, the variant with `const` becomes
|
||||
a construct which is already syntactically correct Dart when the `const` is
|
||||
removed. For instance `const C(42)` becomes `C(42)` which is already allowed
|
||||
syntactically (syntactically, it could be a function invocation).*
|
||||
|
||||
## Static analysis
|
||||
|
||||
We specify a type directed source code transformation which eliminates the
|
||||
We specify a type directed source code transformation which eliminates the
|
||||
feature. The static analysis proceeds to work on the transformed program.
|
||||
|
||||
*This means that the feature is "sugar", but because of the need to refer
|
||||
|
@ -123,44 +102,63 @@ to types it could be described as static semantic sugar rather than
|
|||
syntactic sugar. We do not specify the dynamic semantics for this feature,
|
||||
because the feature is eliminated in this transformation step.*
|
||||
|
||||
We need to treat expressions differently in different locations, hence the
|
||||
following definition: An expression _e_ is said to *occur in a constant
|
||||
context*,
|
||||
|
||||
- if _e_ is an immediate subexpression of a constant list literal or a
|
||||
constant map literal.
|
||||
- if _e_ is an immediate subexpression of a constant object expression.
|
||||
- if _e_ is the initializing expression of a constant variable declaration.
|
||||
- if _e_ is an immediate subexpression of an expression which occurs in a
|
||||
constant context.
|
||||
|
||||
*Note that the default value of an optional formal parameter is not a
|
||||
constant context. This choice reserves some freedom to modify the
|
||||
semantics of default values.*
|
||||
|
||||
An expression on one of the following forms must be modified to be or
|
||||
contain a `constantObjectExpression` as described:
|
||||
|
||||
With a `postfixExpression` _e_,
|
||||
With a `postfixExpression` _e_ occurring in a constant context,
|
||||
|
||||
- if _e_ is on the form `constructorInvocation`, i.e.,
|
||||
`typeName typeArguments '.' identifier arguments` then replace _e_ by
|
||||
`'const' typeName typeArguments '.' identifier arguments`.
|
||||
- if _e_ is on the form `constructorInvocation` then replace _e_ by
|
||||
`const` _e_.
|
||||
- if _e_ is on the form
|
||||
`typeIdentifier arguments` where `typeIdentifier` denotes a class then
|
||||
replace _e_ by
|
||||
`'const' typeIdentifier arguments`.
|
||||
replace _e_ by `const` _e_.
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' identifier2 arguments` where `identifier1` denotes
|
||||
a class and `identifier2` is the name of a named constructor in that class,
|
||||
or `identifier1` denotes a prefix for a library _L_ and `identifier2` denotes
|
||||
a class exported by _L_, replace _e_ by
|
||||
`'const' identifier1 '.' identifier2 arguments`.
|
||||
a class and `identifier2` is the name of a named constructor in that
|
||||
class, or `identifier1` denotes a prefix for a library _L_ and
|
||||
`identifier2` denotes a class exported by _L_, replace _e_ by
|
||||
`const` _e_.
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' typeIdentifier '.' identifier2 arguments` where
|
||||
`identifier1` denotes a library prefix for a library _L_, `typeIdentifier`
|
||||
denotes a class _C_ exported by _L_, and `identifier2` is the name of a named
|
||||
constructor in _C_, replace _e_ by
|
||||
`'const' identifier1 '.' typeIdentifier '.' identifier2 arguments`.
|
||||
`identifier1 '.' typeIdentifier '.' identifier2 arguments` where
|
||||
`identifier1` denotes a library prefix for a library _L_,
|
||||
`typeIdentifier` denotes a class _C_ exported by _L_, and `identifier2`
|
||||
is the name of a named constructor in _C_, replace _e_ by
|
||||
`const` _e_.
|
||||
|
||||
For a list literal _e_ occurring in a constant context, replace _e_ by
|
||||
`const` _e_. For a map literal _e_ occurring in a constant context,
|
||||
replace _e_ by `const` _e_.
|
||||
|
||||
*In short, in these specific situations: "just add `const`". It is easy to
|
||||
verify that each of the replacements can be derived from
|
||||
`constObjectExpression`, which can be derived from `postfixExpression` via
|
||||
`primary selector*`; hence the transformation preserves syntactic correctness.*
|
||||
`primary selector*`. Hence, the transformation preserves syntactic
|
||||
correctness.*
|
||||
|
||||
The remaining static analysis proceeds to work on the transformed program.
|
||||
|
||||
*It is possible that this transformation will create
|
||||
`constObjectExpressions` which violate the constraints on constant object
|
||||
expressions. It is recommended that the error messages emitted by tools in
|
||||
response to such violations include information about the transformative
|
||||
step that added this `const` to the given construct and informs developers
|
||||
that they may add `new` explicitly if that matches the intention.*
|
||||
expressions, e.g., when `const [[new A()]]` is transformed to
|
||||
`const [const [new A()]]` where the inner list is an error that was created
|
||||
by the transformation (so the error was moved from the outer to the inner
|
||||
list). It is recommended that the error messages emitted by tools in response
|
||||
to such violations include information about the transformation.*
|
||||
|
||||
## Dynamic Semantics
|
||||
|
||||
|
@ -170,7 +168,12 @@ eliminated by code transformation.
|
|||
|
||||
## Revisions
|
||||
|
||||
- 0.1 (2017-08-10) Stand-alone proposal for optional const created, using
|
||||
version 0.8 of the combined proposal
|
||||
- 0.2 (2017-08-30) Updated the document to specify the previously missing
|
||||
transformations for composite literals (lists and maps), and to specify a
|
||||
no-magic approach (where no `const` is introduced except when forced by
|
||||
the syntactic context).
|
||||
|
||||
- 0.1 (2017-08-10) Stand-alone informal specification for optional const
|
||||
created, using version 0.8 of the combined proposal
|
||||
[optional-new-const.md](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-new-const.md)
|
||||
as the starting point.
|
||||
|
|
|
@ -2,20 +2,21 @@
|
|||
|
||||
Author: eernst@.
|
||||
|
||||
Version: 0.1 (2017-08-15)
|
||||
Version: 0.2 (2017-08-30)
|
||||
|
||||
Status: Under discussion
|
||||
Status: Under implementation.
|
||||
|
||||
**This document** is an informal specification of the *optional new* feature.
|
||||
**The feature** adds support for omitting the reserved word `new` in instance
|
||||
creation expressions.
|
||||
|
||||
This feature relies on
|
||||
[optional const](https://gist.github.com/eernstg/4f498836e73d5f003928e8bbe1683d68),
|
||||
and it is assumed that the reader knows the optional const feature. Otherwise,
|
||||
this informal specification is derived from a
|
||||
This feature extends and includes the
|
||||
[optional const feature](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-const.md),
|
||||
and it is assumed that the reader knows about optional const. Beyond
|
||||
that, this informal specification is derived from a
|
||||
[combined proposal](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-new-const.md)
|
||||
which presents optional new and several other features.
|
||||
which presents optional new together with several other features.
|
||||
|
||||
|
||||
## Motivation
|
||||
|
||||
|
@ -23,18 +24,16 @@ In Dart without optional new, the reserved word `new` is present in every
|
|||
expression whose evaluation invokes a constructor (except constant
|
||||
expressions). These expressions are known as *instance creation expressions*. If
|
||||
`new` is removed from such an instance creation expression, the remaining phrase
|
||||
is still syntactically correct in almost all cases, and the required grammar
|
||||
update that makes them all syntactically correct is exactly the one that is
|
||||
specified for
|
||||
[optional const](https://gist.github.com/eernstg/4f498836e73d5f003928e8bbe1683d68).
|
||||
is still syntactically correct in almost all cases. The required grammar
|
||||
update that makes them all syntactically correct is a superset of the one that
|
||||
is specified for
|
||||
[optional const](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-const.md).
|
||||
|
||||
Assuming the grammar update in
|
||||
[optional const](https://gist.github.com/eernstg/4f498836e73d5f003928e8bbe1683d68),
|
||||
all instance creation expressions can technically omit the `new` because tools
|
||||
(compilers, analyzers) are able to parse these expressions, and they are able
|
||||
to recognize that they denote instance creations (rather than, say, static
|
||||
function invocations), because the part before the left parenthesis is
|
||||
statically known to denote a constructor.
|
||||
With that grammar update, all instance creation expressions can technically
|
||||
omit the `new` because tools (compilers, analyzers) are able to parse these
|
||||
expressions, and they are able to recognize that they denote instance creations
|
||||
(rather than, say, static function invocations), because the part before the
|
||||
left parenthesis is statically known to denote a constructor.
|
||||
|
||||
For instance, `p.C.foo` may resolve statically to a constructor named `foo` in
|
||||
a class `C` imported with prefix `p`. Similarly, `D` may resolve to a class, in
|
||||
|
@ -48,8 +47,8 @@ For human readers, it may be helpful to document that a particular expression
|
|||
is guaranteed to yield a fresh instance, and this is the most common argument
|
||||
why `new` should *not* be omitted. However, Dart already allows instance
|
||||
creation expressions to invoke a factory constructor, so Dart developers never
|
||||
had any local guarantees that any particular expression would yield a fresh
|
||||
object.
|
||||
had any firm local guarantees that any particular expression would yield a
|
||||
fresh object.
|
||||
|
||||
Developers may thus prefer to omit `new` in order to obtain more concise code,
|
||||
and possibly also in order to achieve greater uniformity among invocations of
|
||||
|
@ -60,6 +59,7 @@ the `new` in all cases, but also preserves the permission to include `new` in
|
|||
all cases. It is a matter of style to use `new` in a manner that developers
|
||||
find helpful.
|
||||
|
||||
|
||||
## Syntax
|
||||
|
||||
The syntax changes associated with this feature are the following:
|
||||
|
@ -73,41 +73,50 @@ constructorInvocation ::= // NEW
|
|||
typeName typeArguments '.' identifier arguments
|
||||
assignableExpression ::=
|
||||
SUPER unconditionalAssignableSelector |
|
||||
typeName typeArguments '.' identifier arguments
|
||||
(arguments* assignableSelector)+ | // NEW
|
||||
constructorInvocation (arguments* assignableSelector)+ | // NEW
|
||||
identifier |
|
||||
primary (arguments* assignableSelector)+
|
||||
```
|
||||
|
||||
This grammar update is identical to the grammar update for optional const.
|
||||
For more information including a complete grammar, please consult
|
||||
[that specification](https://gist.github.com/eernstg/4f498836e73d5f003928e8bbe1683d68).
|
||||
*As mentioned, this grammar update is a superset of the grammar updates for
|
||||
[optional const](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-const.md).*
|
||||
|
||||
|
||||
## Static analysis
|
||||
|
||||
We specify a type directed source code transformation which eliminates the
|
||||
feature. The static analysis proceeds to work on the transformed program.
|
||||
We specify a type directed source code transformation which eliminates the
|
||||
feature by expressing the same semantics with different syntax. The static
|
||||
analysis proceeds to work on the transformed program.
|
||||
|
||||
*Similarly to optional const, this means that the feature is "static semantic
|
||||
sugar". We do not specify the dynamic semantics for this feature, because the
|
||||
feature is eliminated in this transformation step.*
|
||||
|
||||
We need to treat expressions differently in different locations, hence the
|
||||
following definition: An expression _e_ is said to *occur in a constant
|
||||
context*,
|
||||
following definition, which is identical to the one in
|
||||
[optional const](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-const.md):
|
||||
An expression _e_ is said to *occur in a constant context*,
|
||||
|
||||
- if _e_ is an immediate subexpression of a constant list literal or a constant
|
||||
map literal.
|
||||
- if _e_ is an immediate subexpression of a constant list literal or a
|
||||
constant map literal.
|
||||
- if _e_ is an immediate subexpression of a constant object expression.
|
||||
- if _e_ is the initializing expression of a constant variable declaration.
|
||||
- if _e_ is the default value of a formal parameter. **[This case is under discussion and may be removed]**
|
||||
- if _e_ is an immediate subexpression of an expression which occurs in a
|
||||
constant context.
|
||||
|
||||
We define *new/const insertion* as the following transformation:
|
||||
|
||||
- if _e_ occurs in a constant context, replace `e` by `const e`.
|
||||
- otherwise, replace `e` by `new e`
|
||||
- if the expression _e_ occurs in a constant context, replace _e_ by
|
||||
`const` _e_,
|
||||
- otherwise replace _e_ by `new` _e_.
|
||||
|
||||
For the purposes of describing the main transformation we need the following
|
||||
syntactic entity:
|
||||
|
||||
```
|
||||
assignableExpressionTail ::=
|
||||
arguments assignableSelector (arguments* assignableSelector)*
|
||||
```
|
||||
|
||||
An expression on one of the following forms must be modified to be or
|
||||
contain a `constantObjectExpression` or `newExpression` as described:
|
||||
|
@ -125,29 +134,63 @@ With a `postfixExpression` _e_,
|
|||
a class and `identifier2` is the name of a named constructor in that class,
|
||||
or `identifier1` denotes a prefix for a library _L_ and `identifier2` denotes
|
||||
a class exported by _L_, perform new/const insertion on _e_.
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' typeIdentifier '.' identifier2 arguments` where
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' typeIdentifier '.' identifier2 arguments` where
|
||||
`identifier1` denotes a library prefix for a library _L_, `typeIdentifier`
|
||||
denotes a class _C_ exported by _L_, and `identifier2` is the name of a named
|
||||
constructor in _C_, perform new/const insertion on _e_.
|
||||
|
||||
With an `assignableExpression` _e_,
|
||||
|
||||
- if _e_ is on the form
|
||||
`constructorInvocation (arguments* assignableSelector)+`
|
||||
then replace _e_ by `new` _e_.
|
||||
- if _e_ is on the form
|
||||
`typeIdentifier assignableExpressionTail`
|
||||
where `typeIdentifier` denotes a class then replace _e_ by `new` _e_.
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' identifier2 assignableExpressionTail`
|
||||
where `identifier1` denotes a class and `identifier2` is the name of
|
||||
a named constructor in that class, or `identifier1` denotes a prefix
|
||||
for a library _L_ and `identifier2` denotes a class exported by _L_
|
||||
then replace _e_ by `new` _e_.
|
||||
- if _e_ is on the form
|
||||
`identifier1 '.' typeIdentifier '.' identifier2 assignableExpressionTail`
|
||||
where `identifier1` denotes a library prefix for a library _L_,
|
||||
`typeIdentifier` denotes a class _C_ exported by _L_, and `identifier2`
|
||||
is the name of a named constructor in _C_ then replace _e_ by `new` _e_.
|
||||
|
||||
*In short, add `const` in const contexts and otherwise add `new`. With
|
||||
`assignableExpression` we always add `new`, because such an expression
|
||||
can never be a subexpression of a correct constant expression. It is easy
|
||||
to verify that each of the replacements can be derived from
|
||||
`postfixExpression` via `primary selector*` and similarly for
|
||||
`assignableExpression`. Hence, the transformation preserves syntactic
|
||||
correctness.*
|
||||
|
||||
|
||||
## Dynamic Semantics
|
||||
|
||||
There is no dynamic semantics to specify for this feature because it is
|
||||
eliminated by code transformation.
|
||||
|
||||
|
||||
## Interplay with optional const
|
||||
|
||||
The optional new and optional const feature can easily be introduced at the same
|
||||
time: Just update the grammar as specified for optional const (and mentioned
|
||||
again here) and use the program transformation specified in this document. The
|
||||
program transformation in this document subsumes the program transformation
|
||||
specified for optional const, and hence this will provide support for both
|
||||
features.
|
||||
This informal specification includes optional const as well as optional new,
|
||||
that is, if this specification is implemented then
|
||||
[optional const](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-const.md)
|
||||
may be considered as background material.
|
||||
|
||||
|
||||
## Revisions
|
||||
|
||||
- 0.1 (2017-08-15) Stand-alone proposal for optional new created, using version
|
||||
0.8 of the combined proposal
|
||||
- 0.2 (2017-07-30) Updated the document to specify the previously missing
|
||||
transformations for `assignableExpression`, and to specify a no-magic
|
||||
approach (where no `const` is introduced except when forced by the
|
||||
syntactic context).
|
||||
|
||||
- 0.1 (2017-08-15) Stand-alone informal specification for optional new created,
|
||||
using version 0.8 of the combined proposal
|
||||
[optional-new-const.md](https://github.com/dart-lang/sdk/blob/master/docs/language/informal/optional-new-const.md)
|
||||
as the starting point.
|
||||
|
|
Loading…
Reference in a new issue