From 9205420644a94adb2496b3e60bfdd938084638da Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Thu, 26 Oct 2023 12:13:04 +0200 Subject: [PATCH 1/6] Adjusted the extension type spec to match proposal #3415 --- .../extension-types/feature-specification.md | 57 +++++++------------ 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index 618a624a72..793ea4f5d9 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -976,24 +976,18 @@ declaration itself, or we're talking about a particular generic instantiation of an extension type. *For non-generic extension type declarations, the representation type is the same in either case.* -Let `V` be an extension type of the form -Name\1, .. Ts>, and let -`R` be the corresponding instantiated representation type. If `R` is -non-nullable then `V` is a proper subtype of `Object`, and `V` is -non-nullable. Otherwise, `V` is a proper subtype of `Object?`, and -`V` is potentially nullable. +An extension type `V` is a proper subtype of `Object?`. It is potentially +non-nullable, unless it implements `Object` or a subtype thereof +*(as described in the section about extension types with superinterfaces)*. *That is, an expression of an extension type can be assigned to a top type -(like all other expressions), and if the representation type is -non-nullable then it can also be assigned to `Object`. Non-extension types -(except bottom types and `dynamic`) cannot be assigned to extension types -without an explicit cast. Similarly, null cannot be assigned to an -extension type without an explicit cast, even in the case where the -representation type is nullable (even better: don't use a cast, call a -constructor instead). Another consequence of the fact that the extension -type is potentially non-nullable is that it is an error to have an instance -variable whose type is an extension type, and then relying on implicit -initialization to null.* +(like all other expressions). Non-extension types (except bottom types and +`dynamic`) cannot be assigned to extension types without an explicit cast. +Similarly, null cannot be assigned to an extension type without an explicit +cast (even better: don't use a cast, call a constructor instead). Another +consequence of the fact that the extension type is potentially non-nullable is +that it is an error to have an instance variable whose type is an extension +type, and then relying on implicit initialization to null.* In the body of a member of an extension type declaration _DV_ named `Name` and declaring the type parameters @@ -1137,8 +1131,7 @@ Assume that _DV_ is an extension type declaration named `Name`, and this case we say that `V1` is a _superinterface_ of _DV_. If _DV_ does not include an `` clause then _DV_ has -`Object?` or `Object` as a direct superinterface, according to the subtype -relation which was specified earlier. +`Object?` as a direct superinterface. A compile-time error occurs if `V1` is a type name or a parameterized type which occurs as a superinterface in an extension type declaration _DV_, and @@ -1303,12 +1296,7 @@ rather than from `Object`)*. *This change is needed because some extension types are subtypes of `Object?` and not subtypes of `Object`, and they need to have a -well-defined depth. Note that the depth of an extension type can be -determined by its actual type arguments, if any, because type parameters of -the extension type may occur in its representation type. In particular, the -depth of an extension type is a property of the type itself, and it is not -always possible to determine the depth from the associated extension type -declaration.* +well-defined depth.* ## Dynamic Semantics of Extension Types @@ -1377,21 +1365,20 @@ used as an expression *(also known as the ultimate representation type)*. ### Summary of Typing Relationships *Here is an overview of the subtype relationships of an extension type `V0` -with instantiated representation type `R` and instantiated superinterface -types `V1 .. Vk`, as well as other typing relationships involving `V0`:* +with instantiated representation type `R` (whose extension type erasure is `R0`) +and instantiated superinterface types `V1 .. Vk`, as well as other typing +relationships involving `V0`:* - *`V0` is a proper subtype of `Object?`.* -- *`V0` is a supertype of `Never`.* -- *If `R` is a non-nullable type then `V0` is a proper subtype of - `Object`, and a non-nullable type.* +- *`V0` is a proper supertype of `Never`.* - *`V0` is a proper subtype of each of `V1 .. Vk`.* -- *At run time, the type `V0` is identical to the type `R`. In - particular, `o is V0` and `o as V0` have the same dynamic - semantics as `o is R` respectively `o as R`, and +- *At run time, the type `V0` is identical to the extension type erasure + `R0`. In particular, `o is V0` and `o as V0` have the same dynamic + semantics as `o is R0` respectively `o as R0`, and `t1 == t2` evaluates to true if `t1` is a `Type` that reifies - `V0` and `t2` reifies `R`, and the equality also holds if - `t1` and `t2` reify types where `V0` and `R` occur as subterms - (e.g., `List` is equal to `List`).* + `V0` and `t2` reifies `R0`, and the equality also holds if + `t1` and `t2` reify types where `V0` and `R0` occur as subterms + (e.g., `List` is equal to `List`).* ## Discussion From c682da4741e3cc8a2a03705527e1da13f10f6b20 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Tue, 31 Oct 2023 23:21:10 +0100 Subject: [PATCH 2/6] Review response --- .../extension-types/feature-specification.md | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index 793ea4f5d9..e76fb087f0 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -15,6 +15,10 @@ information about the process, including in their change logs. [1]: https://github.com/dart-lang/language/blob/master/working/1426-extension-types/feature-specification-views.md [2]: https://github.com/dart-lang/language/blob/master/working/extension_structs/overview.md +2023.10.31 + - Simplify the rules about the relationship between extension types and the + types `Object` and `Object?`. + 2023.10.25 - Allow an extension type to have `implements T` where `T` is a supertype of the representation type (the old rule only allows @@ -983,11 +987,10 @@ non-nullable, unless it implements `Object` or a subtype thereof *That is, an expression of an extension type can be assigned to a top type (like all other expressions). Non-extension types (except bottom types and `dynamic`) cannot be assigned to extension types without an explicit cast. -Similarly, null cannot be assigned to an extension type without an explicit -cast (even better: don't use a cast, call a constructor instead). Another -consequence of the fact that the extension type is potentially non-nullable is -that it is an error to have an instance variable whose type is an extension -type, and then relying on implicit initialization to null.* +Similarly, the null object cannot be assigned to an extension type without +an explicit cast (or a constructor invocation). Since an extension type is +potentially non-nullable, an instance variable whose type is an extension +type must be initialized. It will not be implicitly initialized to null.* In the body of a member of an extension type declaration _DV_ named `Name` and declaring the type parameters @@ -1372,12 +1375,13 @@ relationships involving `V0`:* - *`V0` is a proper subtype of `Object?`.* - *`V0` is a proper supertype of `Never`.* - *`V0` is a proper subtype of each of `V1 .. Vk`.* -- *At run time, the type `V0` is identical to the extension type erasure - `R0`. In particular, `o is V0` and `o as V0` have the same dynamic - semantics as `o is R0` respectively `o as R0`, and - `t1 == t2` evaluates to true if `t1` is a `Type` that reifies - `V0` and `t2` reifies `R0`, and the equality also holds if - `t1` and `t2` reify types where `V0` and `R0` occur as subterms +- *Let `R0` be the extension type erasure of `V0`. At run time, the type + `V0` has the same representation and semantics as `R0`. In particular, + `o is V0` and `o as V0` have the same dynamic semantics as `o is R0` + respectively `o as R0`. `t1 == t2` evaluates to true if `t1` is a + `Type` that reifies `V0` and `t2` reifies `R0`. Similarly, two types `t1` + and `t2` are equal if they are structurally equal except that `V0` occurs + in `t1` and `R0` occurs at the corresponding location in `t2` (e.g., `List` is equal to `List`).* From 878dca3d351539fe08c7742f68289455363b76a0 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Fri, 3 Nov 2023 20:49:58 +0100 Subject: [PATCH 3/6] Review response, eliminated most controversies --- .../extension-types/feature-specification.md | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index e76fb087f0..991cf4aba6 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -723,7 +723,7 @@ _not_ eliminated by the existence of other declarations (of any kind) named `_n` in the same library. Conversely, the existence of an extension type with a representation -variable with a private name `_n` does not eliminate promotion of +variable with a private name `_n` does not eliminate promotion of any private instance variables named `_n` of a class, mixin, enum, or mixin class in the same library. @@ -1133,9 +1133,6 @@ Assume that _DV_ is an extension type declaration named `Name`, and `V1` occurs as one of the ``s in the `` of _DV_. In this case we say that `V1` is a _superinterface_ of _DV_. -If _DV_ does not include an `` clause then _DV_ has -`Object?` as a direct superinterface. - A compile-time error occurs if `V1` is a type name or a parameterized type which occurs as a superinterface in an extension type declaration _DV_, and `V1` denotes a non-extension type which is not a supertype of the @@ -1299,7 +1296,12 @@ rather than from `Object`)*. *This change is needed because some extension types are subtypes of `Object?` and not subtypes of `Object`, and they need to have a -well-defined depth.* +well-defined depth. We could define the depth to be zero for `Object`, for +`Null`, and for every extension type that has no `implements` clause, and +insist that `Object?` isn't an interface type and doesn't have a depth, but +in that case we no longer have a guarantee that the sets of superinterfaces +with the same maximal depth that the Dart 1 least upper bound algorithm +uses will have at least one singleton set.* ## Dynamic Semantics of Extension Types @@ -1377,12 +1379,9 @@ relationships involving `V0`:* - *`V0` is a proper subtype of each of `V1 .. Vk`.* - *Let `R0` be the extension type erasure of `V0`. At run time, the type `V0` has the same representation and semantics as `R0`. In particular, - `o is V0` and `o as V0` have the same dynamic semantics as `o is R0` - respectively `o as R0`. `t1 == t2` evaluates to true if `t1` is a - `Type` that reifies `V0` and `t2` reifies `R0`. Similarly, two types `t1` - and `t2` are equal if they are structurally equal except that `V0` occurs - in `t1` and `R0` occurs at the corresponding location in `t2` - (e.g., `List` is equal to `List`).* + they behave identically with respect to `is`, `is!`, `as`, and `==`, + both when `V0` and `R0` are used as types, and when they occur as + subterms of another type. ## Discussion From 0435d34e858cd9d413c9a1aa03e3d67a7dc1a627 Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 15 Nov 2023 14:51:13 +0100 Subject: [PATCH 4/6] Improve comment --- .../extension-types/feature-specification.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index 991cf4aba6..bd8b689a54 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -988,9 +988,10 @@ non-nullable, unless it implements `Object` or a subtype thereof (like all other expressions). Non-extension types (except bottom types and `dynamic`) cannot be assigned to extension types without an explicit cast. Similarly, the null object cannot be assigned to an extension type without -an explicit cast (or a constructor invocation). Since an extension type is -potentially non-nullable, an instance variable whose type is an extension -type must be initialized. It will not be implicitly initialized to null.* +an explicit cast (or if it has a static type which is an extension type, +e.g., `E(null)`). Since an extension type is potentially non-nullable, an +instance variable whose type is an extension type must be initialized. It +will not be implicitly initialized to null.* In the body of a member of an extension type declaration _DV_ named `Name` and declaring the type parameters From 4343f14f2383198f2d72a4125e6c21d2b094444c Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 15 Nov 2023 15:01:07 +0100 Subject: [PATCH 5/6] Improve commentary --- .../extension-types/feature-specification.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index bd8b689a54..55e4fdfdb7 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -1298,11 +1298,11 @@ rather than from `Object`)*. *This change is needed because some extension types are subtypes of `Object?` and not subtypes of `Object`, and they need to have a well-defined depth. We could define the depth to be zero for `Object`, for -`Null`, and for every extension type that has no `implements` clause, and -insist that `Object?` isn't an interface type and doesn't have a depth, but +`Null`, and for every extension type that has no `implements` clause, but in that case we no longer have a guarantee that the sets of superinterfaces with the same maximal depth that the Dart 1 least upper bound algorithm -uses will have at least one singleton set.* +uses will have at least one singleton set. All in all it's simpler if we +preserve the property that the superinterface graph has a single root.* ## Dynamic Semantics of Extension Types From d45c42cd32d429ccfa1068189d6af8027b84608e Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 15 Nov 2023 15:01:58 +0100 Subject: [PATCH 6/6] Typo --- .../future-releases/extension-types/feature-specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/future-releases/extension-types/feature-specification.md b/accepted/future-releases/extension-types/feature-specification.md index 55e4fdfdb7..d85e665bf6 100644 --- a/accepted/future-releases/extension-types/feature-specification.md +++ b/accepted/future-releases/extension-types/feature-specification.md @@ -1301,7 +1301,7 @@ well-defined depth. We could define the depth to be zero for `Object`, for `Null`, and for every extension type that has no `implements` clause, but in that case we no longer have a guarantee that the sets of superinterfaces with the same maximal depth that the Dart 1 least upper bound algorithm -uses will have at least one singleton set. All in all it's simpler if we +uses will have at least one singleton set. All in all, it's simpler if we preserve the property that the superinterface graph has a single root.*