diff --git a/accepted/future-releases/generalized-typedef-2018/feature-specification.md b/accepted/future-releases/generalized-typedef-2018/feature-specification.md index d0b15afe42..47634d4caa 100644 --- a/accepted/future-releases/generalized-typedef-2018/feature-specification.md +++ b/accepted/future-releases/generalized-typedef-2018/feature-specification.md @@ -2,7 +2,7 @@ Author: eernst@google.com (@eernst). -Version: 0.1. +Version: 0.2. ## Motivation and Scope @@ -114,14 +114,32 @@ evaluated as an expression, it is subject to instantiation to bound. *This treatment of generic type aliases is again the same as it was previously, but it involves a larger set of types.* -*Note that type aliases introduce types and not classes. Consequently, a -type alias can **not** be used in a position where a class is expected: in the -`extends`, `with`, `implements`, or `on` clause of a class or mixin -declaration; for a static member access; or in an instance creation -expression (`new F()`, `const F()`). On the other hand, it **can** be -used as a type annotation, as a type argument, as part of a function type -or function signature, as a type literal, in an `on` clause of a `try` -statement, in a type test (`e is F`), and in a type cast (`e as F`).* +A type alias application of the form _F_ or the form +_F<T1..Tk>_ can be used as a type annotation, +as a type argument, as part of a function type or a function signature, as +a type literal, in an `on` clause of a `try` statement, in a type test +(`e is F`), and in a type cast (`e as F`). + +**The following is under discussion. Exactly one rule will be confirmed. +The following two variants are considered, along with small variations or +hybrids thereof:** + +* A type alias can _not_ be used in a position where a class is + expected: in the `extends`, `with`, `implements`, or `on` clause of a + class or mixin declaration; for a static member access; or in an + instance creation expression (`new F()`, `const F()`). OR + +* A type alias can _not_ be used for static member accesses. When a type + alias _F_ resp. _F<T1..Tk>_ occurs as the + entity that a class `extends` and when it occurs in a `with` clause or + `implements` clause of a class or an `on` clause of a mixin, or it is + used in an instance creation expression, it is a compile-time error + unless it denotes a class, otherwise it is treated as if that class had + been specified explicitly. + (*E.g., `class C extends myPrefix.F {}` would be equivalent to + `class C extends D, int> {}` if the library imported as + `myPrefix` contains `typedef F = D, X>;`, assuming that + `D` is accessible to the current library and has no prefix.*) ### Dynamic Semantics @@ -146,4 +164,7 @@ fresh type variable bound to the denoted type. ## Versions +* Nov 8th, 2018, version 0.2: Marking the design decision of where to allow + usages of type aliases denoting classes as under discussion. + * Nov 6th, 2018, version 0.1: Initial version of this document. diff --git a/working/spread-collections/feature-specification.md b/working/spread-collections/feature-specification.md index e2b0a39b8c..f51f798c33 100644 --- a/working/spread-collections/feature-specification.md +++ b/working/spread-collections/feature-specification.md @@ -281,9 +281,9 @@ become strict subtype checks instead. ### Const spreads -Spread elements are not allowed in const lists or maps. Because the spread must -be imperatively unpacked, this could require arbitrary code to be executed at -compile time: +We must be careful with spread elements in const collections. Because the spread +is imperatively unpacked, even a "const" object could cause arbitrary +computation at compile time: ```dart class InfiniteSequence implements Iterable { @@ -300,6 +300,43 @@ class InfiniteSequence implements Iterable { const forever = [...InfiniteSequence()]; ``` +However, if the spread expression is a valid const expression and the resulting +value is exactly the built-in List or Map classes, then it's safe because we +know exactly how constants of those classes behave. Thus, we state: + +* In a constant list, a spread element expands at compile time to the series + of elements contained in the spread object list. + +* In a constant map, a spread element expands to the series of entries + contained in the spread object map. + +* It is a compile-time error to use a spread element in a constant list unless + the spread object was created by a constant list literal expression. + +* It is a compile-time error to use a spread element in a constant map unless + the spread object was created by from a constant map literal expression. + +This enables in-place literals (which aren't very useful): + +```dart +const list = [...["why"]]; +``` + +It also enables const expressions that refer to constant lists and maps defined +elsewhere, which is useful: + +```dart +const list = [2, 3]; +const another = [1, ...list, 4]; // [1, 2, 3, 4]. +``` + +The existing rules against self-reference prohibit a list or map from spreading +into itself: + +```dart +const list = [...list]; // Error. +``` + ### Type inference Inference propagates upwards and downwards like you would expect: