diff --git a/accepted/future-releases/class-modifiers/feature-specification.md b/accepted/future-releases/class-modifiers/feature-specification.md
index 2c91f5e7da..b69abef75a 100644
--- a/accepted/future-releases/class-modifiers/feature-specification.md
+++ b/accepted/future-releases/class-modifiers/feature-specification.md
@@ -4,7 +4,7 @@ Author: Bob Nystrom, Lasse Nielsen
Status: Accepted
-Version 1.6
+Version 1.7
Experiment flag: class-modifiers
@@ -20,7 +20,9 @@ Informally, the new syntax is:
* `base`: As a modifier on a class, allows the class to be extended but not
implemented. As a modifier on a mixin, allows it to be mixed in but not
implemented. In other words, it takes away being able to implement
- the interface of the declaration.
+ the interface of the declaration. _This also applies transitively
+ to all subtypes, since implementing a subtype also means implementing
+ the superinterface._
* `interface`: As a modifier on a class or mixin, allows the type to be
implemented but not extended or mixed in. In other words, it takes away
@@ -347,10 +349,10 @@ does `MySubclass` now expose externally? We have a few options:
implementing class must also be marked `base` or `final`.
This avoids any confusion about whether a subtype removes a restriction. But
- it comes at the expense of flexiblity. If a user *wants* to remove a
+ it comes at the expense of flexibility. If a user *wants* to remove a
restriction, they have no ability to.
- This would constrast with `sealed` where you can have subtypes of a sealed
+ This would contrast with `sealed` where you can have subtypes of a sealed
type that are not themselves sealed. This is a deliberate choice because
there's no *need* for the direct subtypes of a sealed to be sealed in order
for exhaustiveness checking to be sound. Since exhaustiveness is the goal
@@ -358,7 +360,7 @@ does `MySubclass` now expose externally? We have a few options:
unsealed.
It also prevents API designs that seem reasonable and useful to me. Imagine
- a library for transportion with classes like:
+ a library for transportation with classes like:
```dart
abstract final class Vehicle {}
@@ -447,7 +449,7 @@ safe.
Now consider:
-```
+```dart
// lib_b.dart
import 'lib_a.dart';
@@ -501,8 +503,8 @@ class UsesAsMixin extends OtherSuperclass with Both {} // OK.
This proposal builds on the existing sealed types proposal so the grammar
includes those changes. The full set of modifiers that can appear before a class
-or mixin declaration are `abstract`, `sealed`, `base`, `interface`, `final`, and
-`mixin`.
+declaration are `abstract`, `sealed`, `base`, `interface`, `final`, and
+`mixin`. Only the `base` modifier can appear before a `mixin` declaration.
*The modifiers do not apply to other declarations like `enum`, `typedef`, or
`extension`.*
@@ -513,24 +515,20 @@ Many combinations don't make sense:
are mutually exclusive.
* `sealed` types cannot be constructed so it's redundant to combine with
`abstract`.
-* `sealed` types cannot be extended or implemented, so it's redundant to
- combine with `final`, `base`, or `interface`.
-* `sealed` types cannot be mixed in outside of their library, so it
- contradicts `mixin` on a class. *It's useful to allow `sealed` on a mixin
- declaration because the mixin can be applied within the same library.
- A `sealed mixin class` does not provide any significant extra
- functionality over a `sealed mixin`, you can replace `extends MixinClass`
- with `with Mixin`, so a `sealed mixin class` is not allowed.*
-* `interface` and `final` classes would prevent a mixin class from being used
- as a superclass or mixin outside of its library. *Like for `sealed`, an
- `interface mixin class` and `final mixin class` are not allowed, and
- `interface mixin` and `final mixin` declaration are recommended instead.*
+* `sealed` types already cannot be mixed in, extended or implemented
+ from another library, so it's redundant to combine with `final`,
+ `base`, or `interface`.
* `mixin` as a modifier can obviously only be applied to a `class`
- declaration, which makes it also a `mixin` declaration.
+ declaration, which makes it also introduce a mixin.
* `mixin` as a modifier cannot be applied to a mixin-application `class`
declaration (the `class C = S with M;` syntax for declaring a class). The
remaining modifiers can.
-* Mixin declarations cannot be constructed, so `abstract` is redundant.
+* A `mixin` or `mixin class` declaration is intended to be mixed in,
+ so its declaration cannot have an `interface`, `final` or `sealed` modifier.
+* A `mixin` declaration cannot be constructed, so `abstract` is redundant.
+* `enum` declarations cannot be extended, implemented, mixed in,
+ and can always be instantiated, so no modifiers apply to `enum`
+ declarations.
The remaining valid combinations and their capabilities are:
@@ -551,9 +549,6 @@ The remaining valid combinations and their capabilities are:
|`abstract base mixin class`|No |**Yes**|No |**Yes**|No |
|`mixin` |No |No |**Yes**|**Yes**|No |
|`base mixin` |No |No |No |**Yes**|No |
-|`interface mixin` |No |No |**Yes**|No |No |
-|`final mixin` |No |No |No |No |No |
-|`sealed mixin` |No |No |No |No |**Yes**|
The grammar is:
@@ -568,16 +563,22 @@ classModifiers ::= 'sealed'
mixinClassModifiers ::= 'abstract'? 'base'? 'mixin'
-mixinDeclaration ::= mixinModifier? 'mixin' typeIdentifier typeParameters?
+mixinDeclaration ::= 'base'? 'mixin' typeIdentifier typeParameters?
('on' typeNotVoidList)? interfaces?
'{' (metadata classMemberDeclaration)* '}'
-
-mixinModifier ::= 'sealed' | 'base' | 'interface' | 'final'
```
## Static semantics
-A pair of definitions:
+The modifiers introduce restrictions on which other declarations can
+depend on the modified declaration, and how.
+To express this, we first introduce some terminology that makes it
+easy to express the relations between declarations.
+
+### Terminology.
+
+We distinguish libraries by whether they have this feature enabled,
+and whether they are platform libraries.
* A *pre-feature library* is a library whose language version is lower than
the version this feature is released in.
@@ -585,289 +586,312 @@ A pair of definitions:
* A *post-feature library* is a library whose language version is at or above
the version this feature is released in.
+* A *platform library* is a library with a `dart:...` URI. A platform library
+ is always a post-feature library in an SDK supporting the feature,
+ but for backwards compatibility, pre-feature libraries may ignore
+ some modifiers in platform libraries, as if the library was also a
+ pre-feature library.
+
+We define the relations between declarations and the other declarations
+they are declared as subtypes of as follow.
+
+* A declaration *S* is _the declared superclass_ of a `class` declaration
+ *D* iff:
+ * *D* has an `extends T` clause and `T` denotes *S*.
+ * *D* has the form `... class ... = T with ...` and `T` denotes *S*.
+
+ _A type clause `T` denotes a declaration *S* if `T` of the from
+ *id*
or *id*\
, and *id*
+ is an identifier or qualified identifier which resolves to *S*,
+ or which resolves to a type alias with a right-hand-side which
+ denotes *S*._
+ _(This allows us to refer to the "declared superclass" uniformly
+ across mixin-application `class` declaration and a "normal" `class`
+ declaration, even though the former cannot have any `extends` clause.
+ A `class` declaration has at most one declared superclass declaration,
+ it can have none if it's a non-mixin application declaration with no
+ `extends` clause.)
+
+* A declaration *S* is a _declared mixin_ of a `class` or `enum` declaration
+ which has a `with T1, ..., Tn` clause where any of `T1`,...,`Tn`
+ denotes *S*.
+
+* A declaration *S* is a _declared interface_ of a `class`, `mixin class`,
+ `mixin` or `enum` declaration which has an `implements T1, ..., Tn` clause
+ where any of `T1`,...,`Tn` denotes *S*.
+
+* A declaration *S* is a _declared `on` type_ of a `mixin` declaration
+ which has an `on T1, ..., Tn` clause where any of `T1`,...,`Tn` denotes *S*.
+
+_We need these independently, but we also need the union of these relations,
+capturing that a declaration depends directly on another in *any* way._
+
+* A declaration *S* is a direct superdeclaration of a declaration *D*
+ iff *S* is a declared superclass, mixin, interface or `on` type of *D*.
+
+_We then define the transitive closure of this relation, expression
+that a declaration depends on another through any number of intermediate
+declarations._
+
+* A declaration *S* is a proper superdeclaration of a declaration *D* iff
+ either *S* is a direct superdeclaration of *D*, or there exists a
+ declaration *P* such that *P* is a direct superdeclaration of *D* and
+ *S* is a proper superdeclaration of *P*.
+
+_The language prevents dependency cycles in declarations, because cycles prevent
+subtyping from being well-defined. Because of that, the
+"proper superdeclaration" relation is a directed acyclic relation.
+Or alternatively, we could write the rule against cycles as it being
+a compile-time error if any declaration *S* is a proper superdeclaration
+of itself._
+
+_Finally we define the reflexive closure of the proper superdeclaration
+relations, because it's sometimes useful to talk about a the entire
+super-hierarchy of a declaration including itself._
+
+* A declaration is a superdeclaration of a declaration *D* iff
+ *S* is *D* or *S* is a proper superdeclaration of *D*.
+
+_With all these syntactic relations between declarations in place,
+we can specify the restrictions imposed by modifiers._
+
### Basic restrictions
-It is a compile-time error to:
+It's a compile-time error if:
+
+* A declaration depends directly on a `sealed` declaration from another
+ library. _No exceptions, not even for platform libraries._
-* Extend a class marked `interface`, `final` or `sealed` outside of the
- library where it is declared.
+ More formally:
+ A declaration *D* from library *L* has a direct superdeclaration *S*
+ marked `sealed` (so necessarily a `class` declaration) in a library
+ different from *L*.
```dart
// a.dart
- interface class I {}
- final class F {}
sealed class S {}
// b.dart
import 'a.dart';
- class C1 extends I {} // Error.
- class C2 extends F {} // Error.
- class C3 extends S {} // Error.
+ class E extends S {} // Error.
+ class I implements S {} // Error.
+ mixin O on S {} // Error.
+ class M with S {} // Error, for several reasons.
```
-* Implement the interface of a class, mixin, or mixin class marked `base`,
- `final` or `sealed` outside of the library where it is declared.
-
- ```dart
- // a.dart
- base class B {}
- final class F {}
- sealed class S {}
-
- base mixin BM {}
- final mixin FM {}
- sealed mixin SM {}
-
- // b.dart
- import 'a.dart';
-
- class C1 implements B {} // Error.
- class C2 implements F {} // Error.
- class C3 implements S {} // Error.
+* A class extends or mixes in a declaration marked `interface` or `final`
+ from another library _(with some exceptions for platform libraries)_.
- class C1 implements BM {} // Error.
- class C2 implements FM {} // Error.
- class C3 implements SM {} // Error.
- ```
+ _(You cannot inherit implementation from a class marked `interface`
+ or `final` except inside the same library. Unless you are in a
+ pre-feature library and you are inheriting from a platform library.)_
-* Mix in a mixin or mixin class marked `interface`, `final` or `sealed`
- outside of the library where it is declared.
+ More formally:
+ A declaration *C* from library *L* has a declared superclass or mixin
+ declaration *S* marked `interface` or `final` from library *K*, and neither
+ * *L* and *K* is the same library, nor
+ * *K* is a platform library and *L* is a pre-feature library.
```dart
// a.dart
- interface mixin class I {}
- final mixin class F {}
- sealed mixin class S {}
-
- interface mixin IM {}
- final mixin FM {}
- sealed mixin SM {}
+ interface class I {}
+ final class F {}
// b.dart
import 'a.dart';
- class C1 with I {} // Error.
- class C2 with F {} // Error.
- class C3 with S {} // Error.
-
- class C1 with IM {} // Error.
- class C2 with FM {} // Error.
- class C3 with SM {} // Error.
+ class C1 extends I {} // Error.
+ class C2 extends F {} // Error.
```
-A typedef cannot be used to subvert these restrictions or any of the
-restrictions below. When extending, implementing, or mixing in a typedef, we
-look at the library where class or mixin the typedef resolves to is defined to
-determine if the behavior is allowed. *Note that the library where the _typedef_
-is defined does not come into play. Typedefs cannot be marked with any of the
-new modifiers.*
-
-### Disallowing implementation
+* A declaration implements another declaration, and the other
+ declaration itself, or any of its super-declarations,
+ are marked `base` or `final` and are not from the first declaration's
+ library _(with some exceptions for platform libraries)_.
-It is a compile-time error if a subtype of a declaration marked `base` or
-`final` is not marked `base`, `final`, or `sealed`. This restriction applies to
-both direct and indirect subtypes and along all paths that introduce subtypes:
-`implements` clauses, `extends` clauses, `with` clauses, and `on` clauses. This
-restriction applies even to types within the same library.
+ _(You can only implement an interface if *all* `base` or `final`
+ superdeclarations are inside your own library. Or if you're in
+ a pre-feature library and all `base` or `final` superdeclarations
+ are in platform libraries.)_
-*Once the ability to use as an interface is removed, it cannot be reintroduced
-in a subtype. If a class is marked `base` or `final`, you may still implement
-the class's interface inside the same library, but the implementing class must
-again be marked `base`, `final`, or `sealed` to avoid it exposing an
-implementable interface.*
-
-Further, while you can ignore some restrictions on declarations within the same
-library, you cannot use that to ignore restrictions inherited from other
-libraries.
-
-We say that `S` is a _direct declared superinterface_ of a class, mixin, or
-mixin class declaration `D` if `D` has a superclass clause of the form
-`C with M1 .. Mk` (where `k` may be zero when there is no `with` clause)
-and `S` is `C`, or `S` is `Mj` for some `j` in 1 .. k,
-or if `D` has an `implements` or `on` clause and `S` occurs as one of the operands of
-that clause.
-
-We then say that a class or mixin declaration `D` *cannot be implemented locally* if it
-has a direct declared superinterface `S` such that:
-
-* `S` is from another library than `D`, and `S` has the modifier `base`,
- `final` or `sealed`, or
+ More formally:
+ A declaration *C* in library *L* has a declared interface *P*,
+ and *P* has any superdeclaration *S*, from a library *K*,
+ which is marked `base` or `final` _(including *S* being *P* itself)_,
+ and neither:
+ * *K* and *L* is the same library, mor
+ * *K* is a platform library and *L* is a pre-feature library.
```dart
// a.dart
- base mixin class S {}
-
- // b.dart
- import 'a.dart';
-
- // These cannot be implemented locally:
- sealed class DE extends S {}
- final class DM with S {}
- base mixin MO on S {}
- ```
-
-* `S` is from the same library as `D`, and `S` cannot be implemented locally.
-
- ```dart
- // a.dart
- base class B {}
+ base class S {}
+ base mixin M {}
+ final class F {}
// b.dart
import 'a.dart';
- // These cannot be implemented locally (from the previous rule):
- base class S extends B {}
- base mixin M on B {}
+ // Direct implementation of other-library `base` class.
+ base class D implements S {} // Error
+ mixin N implements M {} // Error.
+ enum E implements F { e } // Error.
- // And thus these also cannot be implemented locally:
- base class DE extends S {}
- base class DM extends B with M {} // (from this and the previous rule).
- base mixin MO on S {}
- base mixin M2 on M {}
+ // Indirect implementation of other-library `base` class.
+ base class P extends S {}
+ base class C implements P {} // Error.
```
-Otherwise, `D` can be implemented locally.
+* A declaration has a `base` or `final` superdeclaration,
+ and is not itself marked `base`, `final` or `sealed`.
+ _This also applies to declarations inside the same library._
-It is a compile-time error if:
+ _(A `base` or `final` declaration doesn't expose an implementable
+ interface, and for that to matter, nor must any of its subclasses.
+ The entire subclass tree below such a declaration must prevent
+ implementation too.)_
-* A class, mixin, or mixin class declaration `D` has an `implements` clause
- where `S` is an operand, and `S` is a class, mixin, or mixin class
- declaration declared in the same library as `D`, and `S` cannot be
- implemented locally.
+ More formally:
+ A `class`, `mixin class` or `mixin` declaration *D* in a post-feature
+ library has any proper superdeclaration marked `base` or `final`,
+ and *D* is not itself marked `base`, `final` or `sealed`.
```dart
// a.dart
base class B {}
+ sealed class S extends B {}
+ enum E extends S { e }
- // b.dart
- import 'a.dart';
+ class C0 extends B {} // Error.
+ class C1 implements B {} // Error.
- base class S extends B {} // Cannot be implemented locally but OK.
+ base mixin BM {}
+ final mixin FM {}
- base class D implements S {} // Error, cannot use "implements".
- ```
+ mixin M0 implements B {} // Error
+ mixin M1 on B {} // Error
-* A class, mixin, or mixin class declaration `D` cannot be implemented
- locally, and `D` does not have a `base`, `final` or `sealed` modifier.
- _A declaration which cannot be implemented locally also cannot
- be allowed to be implemented in another library._
+ // b.dart
+ import 'a.dart';
-### Mixin restrictions
+ base class V1 extends B {}
+ final class V2 extends B {}
+ sealed class V3 extends B {}
-There are a few changes around mixins to support `mixin class` and disallow
-using normal `class` declarations as mixins while dealing with language
-versioning and backwards compatibility.
+ enum E2 with BM { e } // Not a class/mixin class/mixin declaration.
-Currently, a class may only be used as a mixin if it has a default constructor.
-This prevents the class from defining a `const` constructor or any factory
-constructors. We loosen this somewhat.
+ class C2 extends B {} // Error.
+ class C3 with BM {} // Error.
+ ```
-Define a *trivial generative constructor* to be a generative constructor that:
+_An `enum` declaration still cannot be implemented, extended or mixed in
+anywhere, independently of modifiers._
-* Is not a redirecting constructor,
+A type alias (`typedef`) cannot be used to subvert these restrictions
+or any of the restrictions below. The actual superdeclaration used in
+these checks is the one that the type alias expands to. *Note that
+the library where the _type alias_ is defined does not come into play.
+Type aliases cannot be marked with any of the new modifiers.*
-* declares no parameters,
+### Mixin restrictions
+As before, a declared superclass declaration must be a `class` declaration
+_(you can only extend another class)_ and a declared interface declaration
+must be a `class` or `mixin` declaration, and now it may also
+be a `mixin class` declaration _(you can only implement something which
+has an interface, and not `enum`s which cannot be implemented at all)_.
+
+The new `mixin class` declaration has a set of syntactic rules which
+ensures that it can be used as both a `class` and a `mixin`.
+
+It's a compile-time error if a `mixin class` declaration:
+* has an `interface`, `final` or `sealed` modifier. _This is baked
+ into the grammar, but it bears repeating._
+* has an `extends` clause,
+* has a `with` clause, or
+* declares any non-trivial generative constructor.
+
+A *trivial generative constructor* is a generative constructor that:
+* Is not a redirecting constructor _(`Foo(...) : this.other(...);`),
+* declares no parameters (parameter list is precisely `()`),
* has no initializer list (no `: ...` part, so no asserts or initializers, and
- no super constructor invocation),
-
+ no explicit super constructor invocation),
* has no body (only `;`), and
+* is not `external`. _An `external` constructor is considered to have an
+ externally provided initializer list and/or body._
-* is not `external`. *An `external` constructor is considered to have an
- externally provided initializer list and/or body.*
+_A trivial generative constructor may be named or unnamed,
+and may be `const` or non-`const`._
+A *non-trivial generative constructor* is a generative constructor which
+is not a trivial generative constructor.
-A trivial constructor may be named or unnamed, and `const` or non-`const`.
-A *non-trivial generative constructor* is a generative constructor which is not a
-trivial generative constructor.
+_A trivial generative constructor has no effect on object construction,
+so it can be safely ignored and omitted when the `mixin class` is used
+as a mixin, but it allows the `mixin class` declaration to also be used a
+superclass, even for subclasses with constant constructors._
Examples:
```dart
-class C {
+mixin class C {
// Trivial generative constructors:
C();
const C();
+ C.named();
+ const C.alsoNamed();
// Non-trivial generative constructors:
- C(int x);
- C(this.x);
- C() {}
- C(): assert(true);
- C(): super();
+ C(int x); // Error.
+ C(this.x); // Error.
+ C() {} // Error.
+ C(): x = 0;
+ C(): assert(true); // Error.
+ C(): super(); // Error.
+ C(): this.named();
// Not generative constructors, so neither trivial generative nor non-trivial
// generative:
factory C.f = C;
factory C.f2() { ... }
-}
-```
-
-It's a compile-time error if:
-* A `mixin class` declaration has a superclass other than `Object`. *The
- declaration is limited to an `extends Object` clause or no `extends` clause,
- and no `with` clauses. The class grammar prohibits `on` clauses.*
+ int? x;
+}
-* A `mixin class` declaration declares any non-trivial generative constructor.
- *It may declare no constructors, in which case it gets a default
- constructor, or it can declare factory constructors and/or trivial
- generative constructors.*
+// Invalid mixin classes.
+mixin class E extends Object {} // Error.
+mixin class E with C {} // Error.
+```
-These rules ensure that when you mark a `class` with `mixin` that it *can* be
-used as one.
+There are also changes to which declarations can be mixed in.
-A class not marked `mixin` can still be used as a mixin when the class's
-declaration is in a pre-feature library and it satisfies specific requirements.
-Specifically:
+A post-feature class can no longer be used as a mixin unless it's declared
+as a `mixin class`. In post-feature code, you can *only* mix in
+`mixin` or `mixin class` declarations
+Pre-feature code is not changed, so some pre-feature classes can still
+be mixed in, and the SDK exception allows pre-feature code to pretend
+platform libraries are still pre-feature libraries.
-It's a compile-time error for a declaration in library `L` to mix in a
-non-`mixin` class declaration `D` from library `K` if any of:
+The formal rules for which declarations can be mixed in become:
-* `K` is a post-feature library,
-* The superclass of `D` is not `Object`, or
+It's a compile-time error if a `class` or `enum` declaration *D* from
+library *L* has *S* from library *K* as a declared mixin, unless:
+* `S` is a `mixin` or `mixin class` declaration _(necessarily from
+ a post-feature library)_, or
+* `S` is a non-mixin `class` declaration which has `Object` as superclass
+ and declares no generative constructor, and either
+ * *K* is a pre-feature library, or
+ * *K* is a platform library and *L* is a pre-feature library.
-* `D` declares any constructors.
+_That is, a class not marked `mixin` can still be used as a mixin when the
+class's declaration is in a pre-feature library and it satisfies specific
+requirements._
-*For pre-feature libraries, we cannot tell if the intent of `class` was
+_For pre-feature libraries, we cannot tell if the intent of `class` was
"just a class" or "both a class and a mixin". For compatibility, we assume
the latter, even if the class is being used as a mixin in a post-feature
library where it does happen to be possible to distinguish those two
-intents.*
-
-### Anonymous mixin applications
-
-An *anonymous mixin application* class is a class resulting from a mixin application
-that does not have its own declaration.
-That is all mixin applications classes other than the final class
-of a class C = S with M1, …, Mn;
declaration, the mixin application of Mn
to
-the superclass S with M1, …, Mn-1
, which is denoted by declaration and name `C`.
-
-An anonymous mixin application class cannot be referenced anywhere except in
-the context where the application occurs, so its only role is to be a superclass of
-another class in the same library.
-
-To ensure reasonable and correct behavior, we infer class modifiers on anonymous
-mixin application classes as follows.
-
-Let *C* be an anonymous mixin application with superclass *S* and mixin *M*. Then:
-
-* If any of *S* or *M* has a `sealed` modifier, *C* is has a `sealed` modifier.
-* Otherwise:
- * *C* is `abstract`, and
- * If either of *S* or *M* has a `base` or `final` modifier, then *C* has a `final` modifier.
-
-_We do not distinguish whether *S* or *M* has `base` or `final` modifiers.
-The modifier on *C* is there to satisfy the requirement that a subtype of a `base` or `final`
-declaration is itself `base`, `final` or `sealed`. The anonymous mixin application class will
-be immediately extended inside the same library, which is allowed by both `base` and `final`.,
-and will not be used for anything else._
-
-Adding `sealed` to an anonymous mixin application class with only one subclass ensures
-that the subclass extending the mixin application class can be used
-in exhaustiveness checking of the sealed superclass.
-This is necessary since the anonymous mixin application class itself cannot be referenced.
+intents._
### `@reopen` lint
@@ -880,7 +904,9 @@ A metadata annotation `@reopen` is added to package [meta][] and a lint
warning is reported if a class or mixin is not annotated `@reopen` and it:
* Extends or mixes in a class, mixin, or mixin class marked `interface` or
- `final` and is not itself marked `interface` or `final`.
+ `final` and is not itself marked `interface` or `final`,
+ or extends or mixes in a `sealed` declaration which itself
+ transitively extends or mixes in an `interface` or `final` declaration.
[meta]: https://pub.dev/packages/meta
[linter]: https://dart.dev/guides/language/analysis-options#enabling-linter-rules
@@ -907,21 +933,38 @@ non-breaking.
to all other libraries, regardless of the versions of those libraries.
"Ignorance of the law is no defense."*
-* We would like to add modifiers to some classes in platform (i.e. `dart:`)
- libraries when this feature ships. But we would also like to not immediately
+* We will add modifiers to some classes in platform (i.e., `dart:`)
+ libraries when this feature ships. But we will also like to not immediately
break existing code. To avoid forcing users to immediately migrate,
declarations in pre-feature libraries can ignore *some*
- `base`, `interface` and `final` modifiers on *some* declarations
- in platform libraries.
- Instead, users will only have to abide by those restrictions
- when they upgrade their library's language version.
+ `base`, `interface` and `final` modifiers on *some* declarations in platform
+ libraries, and can mix in non-`mixin` classes from platform libraries,
+ as long as such a class has `Object` as superclass and declares
+ no constructors. ([legacy-mixin-tests][]).
+ Instead, users will only have to abide by those restrictions when they
+ upgrade their library's language version to 3.0 or later.
_It will still not be possible to, e.g., extend or implement the `int` class,
even if will now have a `final` modifier._
-
- This is a special case behavior only available to platform libraries.
- Package libraries should use versioning to to introduce breaking
- restrictions instead, and those libraries can then rely on the restrictions
- being enforced.
+ Going through a pre-feature library does not remove transitive restrictions
+ for code in post-feature libraries. Any post-feature library declaration
+ which has a platform library class marked `base` or `final` as a
+ superinterface must be marked `base`, `final` or `sealed`,
+ and cannot be implemented locally, even if the superinterface chain goes
+ through a pre-feature library declaration, and even if that declaration
+ ignores the `base` modifier.
+
+ This ability to ignore modifiers only apply to platform libraries
+ accessed from pre-feature libraries, because code doesn't get to
+ decide the version of the SDK that it runs on, unlike how a package
+ can depend on specific versions of another package.
+ Packages should use package versioning to introduce breaking restrictions
+ instead (a major version semantic version upgrade), but those libraries
+ can then rely on the restrictions being enforced.
+ The platform libraries will bear the cost of not being able to rely
+ on its own modifiers until all code in a program is language version 3.0
+ later.
+
+[legacy-mixin-tests]: https://dart-review.googlesource.com/c/sdk/+/287665
### Compatibility
@@ -1059,6 +1102,15 @@ errors and fixups would help keep them on the rails.
## Changelog
+1.7
+
+* Update the modifiers applied to anonymous mixin applications to closer
+ match the superclass/mixin modifiers.
+* State that `enum` declarations count as `final`.
+* Rephrase semantics completely, based only on relations between declarations.
+* Say that pre-feature libraries can mix in non-`mixin` platform library classes
+ which satisfy the old requirements for being used as a mixin.
+
1.6
- Add implementation suggestions about errors, error recovery, and fixups for