From 6091eef14be50dbcd82c7707fa179e23310b1d8c Mon Sep 17 00:00:00 2001 From: Erik Ernst Date: Wed, 23 Aug 2023 18:02:05 +0200 Subject: [PATCH] Specify primary constructors (#3023) This is a proposed feature specification that specifies the feature _primary constructors_. A primary constructor is a syntactically concise notation for a constructor. For instance: ```dart // Using current Dart. class Point { final int x; final int y; const Point(this.x, [this.y = 0]); } // Using a primary constructor. class const Point(int x, [int y = 0]); ``` --- LICENSE | 4 +- .../feature-specification.md | 648 ++++++++++++++++++ .../scripts/class.json | 13 + .../scripts/class_namedpar.json | 16 + .../scripts/class_optpar.json | 15 + .../scripts/class_requiredpar.json | 15 + .../scripts/const_class.json | 16 + .../scripts/const_class_namedpar.json | 19 + .../scripts/const_class_optpar.json | 18 + .../scripts/const_class_requiredpar.json | 18 + .../scripts/generic_class.json | 14 + .../scripts/generic_class_namedpar.json | 17 + .../scripts/generic_class_optpar.json | 16 + .../scripts/generic_class_requiredpar.json | 16 + .../scripts/inline_class.json | 11 + .../scripts/inline_const_class.json | 12 + .../scripts/inline_generic_class.json | 12 + .../scripts/inline_named_class.json | 12 + .../scripts/inline_named_const_class.json | 13 + .../scripts/inline_subtyped_class.json | 12 + .../scripts/inline_subtyped_const_class.json | 13 + .../inline_subtyped_generic_class.json | 13 + .../inline_subtyped_generic_const_class.json | 14 + .../scripts/named_class.json | 14 + .../scripts/named_class_namedpar.json | 17 + .../scripts/named_class_optpar.json | 16 + .../scripts/named_class_requiredpar.json | 16 + .../scripts/named_const_class.json | 17 + .../scripts/named_const_class_namedpar.json | 20 + .../scripts/named_const_class_optpar.json | 19 + .../named_const_class_requiredpar.json | 19 + .../scripts/named_subtyped_class.json | 15 + .../named_subtyped_class_namedpar.json | 18 + .../scripts/named_subtyped_class_optpar.json | 17 + .../named_subtyped_class_requiredpar.json | 17 + .../scripts/named_subtyped_const_class.json | 18 + .../named_subtyped_const_class_namedpar.json | 21 + .../named_subtyped_const_class_optpar.json | 20 + ...amed_subtyped_const_class_requiredpar.json | 20 + .../scripts/named_subtyped_generic_class.json | 16 + ...named_subtyped_generic_class_namedpar.json | 19 + .../named_subtyped_generic_class_optpar.json | 18 + ...ed_subtyped_generic_class_requiredpar.json | 18 + .../named_subtyped_generic_const_class.json | 19 + ...subtyped_generic_const_class_namedpar.json | 22 + ...d_subtyped_generic_const_class_optpar.json | 21 + ...typed_generic_const_class_requiredpar.json | 21 + .../scripts/show_primary_constructors.dart | 476 +++++++++++++ .../scripts/subtyped_class.json | 14 + .../scripts/subtyped_class_namedpar.json | 17 + .../scripts/subtyped_class_optpar.json | 16 + .../scripts/subtyped_class_requiredpar.json | 16 + .../scripts/subtyped_const_class.json | 17 + .../subtyped_const_class_namedpar.json | 20 + .../scripts/subtyped_const_class_optpar.json | 19 + .../subtyped_const_class_requiredpar.json | 19 + .../scripts/subtyped_generic_class.json | 15 + .../subtyped_generic_class_namedpar.json | 18 + .../subtyped_generic_class_optpar.json | 17 + .../subtyped_generic_class_requiredpar.json | 17 + .../scripts/subtyped_generic_const_class.json | 18 + ...subtyped_generic_const_class_namedpar.json | 21 + .../subtyped_generic_const_class_optpar.json | 20 + ...typed_generic_const_class_requiredpar.json | 20 + 64 files changed, 2153 insertions(+), 2 deletions(-) create mode 100644 working/2364 - primary constructors/feature-specification.md create mode 100644 working/2364 - primary constructors/scripts/class.json create mode 100644 working/2364 - primary constructors/scripts/class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/const_class.json create mode 100644 working/2364 - primary constructors/scripts/const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/const_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/generic_class.json create mode 100644 working/2364 - primary constructors/scripts/generic_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/generic_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/generic_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/inline_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_const_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_generic_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_named_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_named_const_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_subtyped_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_subtyped_const_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_subtyped_generic_class.json create mode 100644 working/2364 - primary constructors/scripts/inline_subtyped_generic_const_class.json create mode 100644 working/2364 - primary constructors/scripts/named_class.json create mode 100644 working/2364 - primary constructors/scripts/named_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/named_const_class.json create mode 100644 working/2364 - primary constructors/scripts/named_const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_const_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_class.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_const_class.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_const_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_class.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_const_class.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_requiredpar.json create mode 100755 working/2364 - primary constructors/scripts/show_primary_constructors.dart create mode 100644 working/2364 - primary constructors/scripts/subtyped_class.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_const_class.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_const_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_class.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_class_requiredpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_const_class.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_const_class_namedpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_const_class_optpar.json create mode 100644 working/2364 - primary constructors/scripts/subtyped_generic_const_class_requiredpar.json diff --git a/LICENSE b/LICENSE index c21c643c1..b457c43c1 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ The following license applies to all parts of this repository. See https://github.com/dart-lang/sdk/blob/main/LICENSE for the license of the Dart language implementation. -Copyright 2018, the Dart project authors. +Copyright 2018, the Dart project authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -16,7 +16,7 @@ met: * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR diff --git a/working/2364 - primary constructors/feature-specification.md b/working/2364 - primary constructors/feature-specification.md new file mode 100644 index 000000000..af5de81e7 --- /dev/null +++ b/working/2364 - primary constructors/feature-specification.md @@ -0,0 +1,648 @@ +# Primary Constructors + +Author: Erik Ernst + +Status: Draft + +Version: 1.0 + +Experiment flag: primary-constructors + +This document specifies _primary constructors_. This is a feature that allows +one constructor and a set of instance variables to be specified in a concise +form in the header of the declaration. In order to use this feature, the given +constructor must satisfy certain constraints, e.g., it cannot have a body. + +A primary constructor can also be declared in the body of a class or +similar declaration, using the modifier `primary`, in which case it can +have an initializer list and a body, and it still has the ability to +introduce instance variable declarations implicitly. + +One variant of this feature has been proposed in the [struct proposal][], +several other proposals have appeared elsewhere, and prior art exists in +languages like [Kotlin][kotlin primary constructors] and Scala (with +specification [here][scala primary constructors] and some examples +[here][scala primary constructor examples]). Many discussions about the +feature have taken place in github issues marked with the +[primary-constructors label][]. + +[struct proposal]: https://github.com/dart-lang/language/blob/master/working/extension_structs/overview.md +[kotlin primary constructors]: https://kotlinlang.org/docs/classes.html#constructors +[scala primary constructors]: https://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#constructor-definitions +[scala primary constructor examples]: https://www.geeksforgeeks.org/scala-primary-constructor/ +[primary-constructors label]: https://github.com/dart-lang/language/issues?q=is%3Aissue+is%3Aopen+primary+constructor+label%3Aprimary-constructors + +## Introduction + +Primary constructors is a conciseness feature. It does not provide any new +semantics at all. It just allows us to express something which is already +possible in Dart, using a less verbose notation. Consider this sample class +with two fields and a constructor: + +```dart +// Current syntax. + +class Point { + int x; + int y; + Point(this.x, this.y); +} +``` + +A primary constructor allows us to define the same class much more +concisely: + +```dart +// A declaration with the same meaning, using a primary constructor. + +class Point(int x, int y); +``` + +In the examples below we show the current syntax directly followed by a +declaration using a primary constructor. The meaning of the two class +declarations with the same name is always the same. Of course, we would +have a name clash if we actually put those two declarations into the same +library, so we should read the examples as "you can write this _or_ you can +write that". So the example above would be shown as follows: + +```dart +class Point { + int x; + int y; + Point(this.x, this.y); +} + +class Point(int x, int y); +``` + +These examples will serve as an illustration of the proposed syntax, but +they will also illustrate the semantics of the primary constructor +declarations, because those declarations work exactly the same as the +declarations using the current syntax. + +Note that an empty class body, `{}`, can be replaced by `;`. + +The basic idea is that a parameter list that occurs just after the class +name specifies both a constructor declaration and a declaration of one +instance variable for each formal parameter in said parameter list. + +A primary constructor cannot have a body, and it cannot have an initializer +list (and hence, it cannot have a superinitializer, e.g., `super(...)`, and +it cannot have assertions). + +The motivation for these restrictions is that a primary constructor is +intended to be small and easy to read at a glance. If more machinery is +needed then it is always possible to express the same thing as a body +constructor (i.e., any constructor which isn't a primary constructor). + +The parameter list uses the same syntax as constructors and other functions +(specified in the grammar by the non-terminal ``). + +This implies that there is no way to indicate that the instance variable +declarations should have the modifiers `late` or `external` (because formal +parameters cannot have those modifiers). This omission is not seen as a problem +in this proposal: It is always possible to use a normal constructor declaration +and normal instance variable declarations, and it is probably a useful property +that the primary constructor uses a formal parameter syntax which is completely +like that of any other formal parameter list. + +Just use a normal declaration and use an initializing formal in a primary +constructor to initialize it from the primary constructor, if needed. An +`external` instance variable amounts to an `external` getter and an +`external` setter. Such "variables" cannot be initialized by an +initializing formal anyway, so they will just need to be declared using a +normal `external` variable declaration. + +```dart +class ModifierClass { + late int x; + external double d; + ModifierClass(this.x); +} + +class ModifierClass(this.x) { + late int x; + external double d; +} +``` + +`ModifierClass` as written does not make sense (`x` does not have to be +`late`), but there could be other constructors that do not initialize `x`. + +Super parameters can be declared in the same way as in a body constructor: + +```dart +class A { + final int a; + A(this.a); +} + +class B extends A { + B(super.a); +} + +class A(final int a); +class B(super.a) extends A; +``` + +Next, the constructor can be named, and it can be constant: + +```dart +class Point { + final int x; + final int y; + const Point._(this.x, this.y); +} + +class const Point._(final int x, final int y); +``` + +Note that the class header contains syntax that resembles the constructor +declaration, which may be helpful when reading the code. + +The modifier `const` could have been placed on the class (`const class`) +rather than on the class name. This proposal puts it on the class name +because the notion of a "constant class" conflicts with with actual +semantics: It is the constructor which is constant because it is able to be +invoked during constant expression evaluation; it can also be invoked at +run time, and there could be other (non-constant) constructors. This means +that it is at least potentially confusing to say that it is a "constant +class", but it is consistent with the rest of the language to say that this +particular primary constructor is a "constant constructor". Hence `class +const Name` rather than `const class Name`. + +The modifier `final` on a parameter in a primary constructor has no meaning +for the parameter itself, because there is no scope where the parameter can +be accessed. Hence, this modifier is used to specify that the instance +variable declared by this primary constructor parameter is `final`. + +In the case where the constructor is constant, and in the case where the +declaration is an `extension type` or an `enum` declaration, the modifier +`final` on every instance variable is required. Hence, it can be omitted +from the formal parameter in the primary constructor: + +```dart +extension type I.name(int x); // Must use a primary constructor. + +class Point { + final int x; + final int y; + const Point(this.x, this.y); +} + +class const Point(int x, int y); + +enum E { + one('a'), + two('b'); + + final String s; + const E(this.s); +} + +enum E(String s) { one('a'), two('b') } +``` + +This mechanism follows an existing pattern, where `const` modifiers can be +omitted in the case where the immediately syntactic context implies that +this modifier _must_ be present. For example, `const [const C()]` can be +written as `const [C()]`. In the examples above, the parameter-and-variable +declarations `final int x` and `final int y` are written as `int x` and +`int y`, and this is allowed because it would be a compile-time error to +omit `final` in an `extension type`, and in a class with a constant +constructor. In other words, when we see an `extension type` declaration, or we +see `const` on the name of a class, we know that `final` is implied on all +instance variables. + +Optional parameters can be declared as usual in a primary constructor, with +default values that must be constant as usual: + +```dart +class Point { + int x; + int y; + Point(this.x, [this.y = 0]); +} + +class Point(int x, [int y = 0]); +``` + +Similarly for named parameters, required or not: + +```dart +class Point { + int x; + int y; + Point(this.x, {required this.y}); +} + +class Point(int x, {required int y}); +``` + +In this declaration it is possible to omit the modifier `required` on the +named parameter `y`, because it is implied by the fact that the type of `y` +is non-nullable (potentially non-nullable is enough). + +The current scope for the default values in the primary constructor is the +enclosing library scope. This means that a naive copy/paste operation on +the source code could change the meaning of the default value. In that case +a new way to denote the given value is established. For example, consider +this class using a primary constructor: + +```dart +static const d = 42; + +class Point(int x, [int y = d]) { + void d() {} +} +``` + +This corresponds to the following class without a primary constructor: + +```dart +static const d = 42; +static const _freshName = d; // Eliminate the name clash. + +class Point { + int x; + int y; + Point(this.x, [this.y = _freshName]); + void d() {} +} +``` + +The class header can have additional elements, just like class headers +where there is no primary constructor: + +```dart +class D extends A with M implements B, C { + final int x; + final int y; + const D.named(this.x, [this.y = 0]); +} + +class const D.named(int x, [int y = 0]) + extends A with M implements B, C; +``` + +In the case where the header gets unwieldy it is possible to declare the +primary constructor in the body of the class, which is also equivalent to +the previous examples: + +```dart +class D extends A with M implements B, C { + primary const D.named(int x, [int y = 0]); +} +``` + +This approach offers more flexibility in that a primary constructor in the +body of the declaration can have initializers and a body, just like other +constructors. In other words, `primary` on a constructor has one effect +only, which is to introduce instance variables for formal parameters in the +same way as a primary constructor in the header of the declaration. For +example: + +```dart +class A { + A(String _); +} + +class E extends A { + LongTypeExpression x1; + LongTypeExpression x2; + LongTypeExpression x3; + LongTypeExpression x4; + LongTypeExpression x5; + LongTypeExpression x6; + LongTypeExpression x7; + LongTypeExpression x8; + external int y; + int z; + final List w; + + E({ + required this.x1, + required this.x2, + required this.x3, + required this.x4, + required this.x5, + required this.x6, + required this.x7, + required this.x8, + required this.y, + }) : z = 1, + w = const [], + super('Something') { + // A normal constructor body. + } +} + +class E extends A { + external int y; + int z; + final List w; + + primary E({ + LongTypeExpression x1, + LongTypeExpression x2, + LongTypeExpression x3, + LongTypeExpression x4, + LongTypeExpression x5, + LongTypeExpression x6, + LongTypeExpression x7, + LongTypeExpression x8, + this.y, + }) : z = 1, + w = const [], + super('Something') { + // A normal constructor body. + } +} +``` + +## Specification + +### Syntax + +The grammar is modified as follows. Note that the changes include support +for extension type declarations, because they're intended to use primary +constructors as well. + +``` + ::= + + | // New alternative. + | ...; + + ::= // First alternative modified. + ( | ) + 'class' ? ? + | ...; + + ::= // New rule. + 'const'? ? + | ; + + ::= // New rule. + '{' ( )* '}' + | ';'; + + ::= + 'extension' 'type' 'const'? + + ? + ; + + ::= + ('.' )? '(' ')'; + + ::= ; + + ::= + '{' ( )* '}' + | ';'; + + ::= // Modified rule. + 'enum' ? ? '{' + (',' )* (',')? + (';' ( )*)? + '}'; + + ::= + 'primary'? + | 'primary'? + | ... // Other cases unchanged. + | 'primary'? ; + + ::= + ... // Other cases unchanged. + | 'primary'? + | 'primary'? ( | )? + | 'primary'? ( | )?; +``` + +The word `type` is now used in the grammar, but it is not a reserved word +or a built-in identifier. A parser that encounters the tokens `extension` +and then `type` at a location where top-level declaration is expected shall +commit to parsing it as an ``. *This eliminates +an ambiguity with `extension` (not `extension type`) declarations.* + +A class declaration whose class body is `;` is treated as a class declaration +whose class body is `{}`. + +*The meaning of a primary constructor is defined in terms of rewriting it to a +body constructor and zero or more instance variable declarations. This implies +that there is a class body when there is a primary constructor. We do not wish +to define primary constructors such that the absence or presence of a primary +constructor can change the length of the superclass chain, and hence `class C;` +has a class body just like `class C(int i);` and just like `class C extends +Object {}`, and all three of them have `Object` as their direct superclass.* + +### Static processing + +Consider a class declaration or an extension type declaration with a +primary constructor *(note that it cannot be a ``, +because that kind of declaration does not support primary constructors, +it's just a syntax error)*. This declaration is desugared to a class or +extension type declaration without a primary constructor. An enum +declaration with a primary constructor is desugared using the same +steps. This determines the dynamic semantics of a primary constructor. + +A compile-time error occurs if a class, extension type, or enum declaration +has a primary constructor in the header as well as a constructor with the +modifier `primary` in the body. + +The following errors apply to formal parameters of a primary constructor. +Let _p_ be a formal parameter of a primary constructor in a class `C`: + +A compile-time error occurs if _p_ contains a term of the form `this.v`, or +`super.v` where `v` is an identifier, and _p_ has the modifier +`covariant`. *For example, `required covariant int this.v` is an error.* + +A compile-time error occurs if _p_ has both of the modifiers `covariant` +and `final`. *A final instance variable cannot be covariant, because being +covariant is a property of the setter.* + +Conversely, it is not an error for the modifier `covariant` to occur on +other formal parameters of a primary constructor (this extends the +existing allowlist of places where `covariant` can occur). + +The desugaring consists of the following steps, where _D_ is the class, +extension type, or enum declaration in the program that includes a primary +constructor in the header, and _D2_ is the result of desugaring. The +desugaring step will delete elements that amount to the primary +constructor; it will add a new constructor _k_; it will add zero or more +instance variable declarations; and it will add zero or more top-level +constants *(holding parameter default values)*. + +Where no processing is mentioned below, _D2_ is identical to _D_. Changes +occur as follows: + +The current scope of the formal parameter list of the primary constructor +in _D_ is the current scope of the class/enum declaration *(in other words, +the default values cannot see declarations in the class body)*. Every +default value in the primary constructor of _D_ is replaced by a fresh +private name `_n`, and a constant variable named `_n` is added to the +top-level of the current library, with an initializing expression which is +said default value. *(This means that we can move the parameter +declarations including the default value without changing its meaning.)* + +For each of these constant variable declarations, the declared type is the +formal parameter type of the corresponding formal parameter, except: In the +case where the corresponding formal parameter has a type `T` where one or +more type variables declared by _D_ occur, the declared type of the +constant variable is the least closure of `T` with respect to the type +parameters of the class. + +*For example, if the default value is `const []` and the parameter type is +`List`, the top-level constant will be `const List _n = [];` for +some fresh name `_n`.* + +Next, _k_ has the modifier `const` iff the keyword `const` occurs just +before the name of _D_, or _D_ is an `enum` declaration. + +If the name `C` in _D_ and the type parameter list, if any, is followed by +`.id` where `id` is an identifier then _k_ has the name `C.id`. If it is +followed by `.new` then _k_ has the name `C`. If it is not followed by `.` +then _k_ has the name `C`. + +If it exists, _D2_ omits the part derived from `'.' ` that +follows the name and type parameter list, if any, in _D_. + +_D2_ omits the formal parameter list _L_ that follows the name, type +parameter list, if any, and `.id`, if any. + +The formal parameter list _L2_ of _k_ is identical to _L_, except that each +formal parameter is processed as follows. + +In particular, the formal parameters in _L_ and _L2_ occur in the same +order, and mandatory positional parameters remain mandatory, and named +parameters preserve the name and the modifier `required`, if any. An +optional positional or named parameter remains optional; if it has a +default value `d` in _L_ then it has the transformed default value `_n` in +_L2_, where `_n` is the name of the constant variable created for that +default value. Finally, if `p` is an optional named parameter in _L_ with +no default value whose type is potentially non-nullable then `required` is +added to `p` in _L2_. + +- An initializing formal parameter *(e.g., `this.x`)* is copied from _L_ to + _L2_, using said transformed default value, if any, and otherwise + unchanged. +- A super parameter is copied from _L_ to _L2_ using said transformed + default value, if any, and is otherwise unchanged. +- A formal parameter (named or positional) of the form `T p` or `final T p` + where `T` is a type and `p` is an identifier is replaced in _L2_ by + `this.p`. A parameter of the same form but with a default value uses said + transformed default value. + Next, an instance variable declaration of the form `T p;` or `final T p;` + is added to _D2_. The instance variable has the modifier `final` if the + parameter in _L_ is `final`, or _D_ is an `extension type` declaration, + or _D_ is an `enum` declaration, or the modifier `const` occurs just + before the class name in _D_. + In all cases, if `p` has the modifier `covariant` then this modifier is + removed from the parameter in _L2_, and it is added to the instance + variable declaration named `p`. + +Finally, _k_ is added to _D2_, and _D_ is replaced by _D2_. + +Assume that _D_ is a class, extension type, or enum declaration in the +program that includes a constructor declaration _k_ in the body which has +the modifier `primary`. In this case, no transformations are applied to the +default values of formal parameters of _k_, but otherwise the formal +parameters of _k_ are processed in the same way as they are with a primary +constructor in the declaration header. + +### Discussion + +It could be argued that primary constructors should support arbitrary +superinvocations using the specified superclass: + +```dart +class B extends A { // OK. + B(int a): super(a); +} + +class B(int a) extends A(a); // Could be supported, but isn't! +``` + +There are several reasons why this is not supported. First, primary constructors +should be small and easy to read. Next, it is not obvious how the +superconstructor arguments would fit into a mixin application (e.g., when the +superclass is `A with M1, M2`), or how readable it would be if the +superconstructor is named (`class B(int a) extends A.name(a);`). For instance, +would it be obvious to all readers that the superclass is `A` and not `A.name`, +and that all other constructors than the primary constructor will ignore the +implied superinitialization `super.name(a)` and do their own thing (which might +be implicit). + +In short, if you need to write a complex superinitialization like +`super.name(e1, otherName: e2)` then you need to use a body constructor. + +There was a [proposal from Bob][] that the primary constructor should be +expressed at the end of the class header, in order to avoid readability +issues in the case where the superinterfaces contain a lot of text. It +would then use the keyword `new` or `const`, optionally followed by `'.' +`, just before the `(` of the primary constructor parameter +list: + +[proposal from Bob]: https://github.com/dart-lang/language/issues/2364#issuecomment-1203071697 + +```dart +class D extends A with M implements B, C + const.named( + LongTypeExpression x1, + LongTypeExpression x2, + LongTypeExpression x3, + LongTypeExpression x4, + LongTypeExpression x5, +) { + ... // Lots of stuff. +} +``` + +That proposal may certainly be helpful in the case where the primary +constructor receives a large number of arguments with long types, etc. +However, the proposal has not been included in this proposal. One reason is +that it could be better to use a body constructor whenever there is so much +text. Also, it could be helpful to be able to search for the named +constructor using `D.named`, and that would fail if we use the approach +where it occurs as `new.named` or `const.named` because that particular +constructor has been expressed as a primary constructor. + +A variant of this idea, from Leaf, is that we could allow one constructor +in a class with no primary constructor in the header to be marked as a +"primary constructor in the body". This proposal has now been made part +of the proposal. + +A proposal which was mentioned during the discussions about primary +constructors was that the keyword `final` could be used in order to specify +that all instance variables introduced by the primary constructor are +`final` (but the constructor wouldn't be constant, and hence there's more +freedom in the declaration of the rest of the class). However, that +proposal is not included here, because it may be a source of confusion that +`final` may also occur as a modifier on the class itself, and also because +the resulting class header does not contain syntax which is already similar +to a body constructor declaration. + +For example, `class final Point(int x, int y);` cannot use the similarity +to a body constructor declaration to justify the keyword `final`. + +```dart +class Point { + final int x; + final int y; + Point(this.x, this.y); +} + +class final Point(int x, int y); // Not supported! +``` + +### Changelog + +1.1 - August 22, 2023 + +* Update to refer to extension types rather than inline classes. + +1.0 - April 28, 2023 + +* First version of this document released. diff --git a/working/2364 - primary constructors/scripts/class.json b/working/2364 - primary constructors/scripts/class.json new file mode 100644 index 000000000..426e75143 --- /dev/null +++ b/working/2364 - primary constructors/scripts/class.json @@ -0,0 +1,13 @@ +{ + "name": "Point", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/class_namedpar.json b/working/2364 - primary constructors/scripts/class_namedpar.json new file mode 100644 index 000000000..f2c48f43a --- /dev/null +++ b/working/2364 - primary constructors/scripts/class_namedpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/class_optpar.json b/working/2364 - primary constructors/scripts/class_optpar.json new file mode 100644 index 000000000..64d8f17e5 --- /dev/null +++ b/working/2364 - primary constructors/scripts/class_optpar.json @@ -0,0 +1,15 @@ +{ + "name": "Point", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/class_requiredpar.json b/working/2364 - primary constructors/scripts/class_requiredpar.json new file mode 100644 index 000000000..35834f332 --- /dev/null +++ b/working/2364 - primary constructors/scripts/class_requiredpar.json @@ -0,0 +1,15 @@ +{ + "name": "Point", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/const_class.json b/working/2364 - primary constructors/scripts/const_class.json new file mode 100644 index 000000000..bb288a1c7 --- /dev/null +++ b/working/2364 - primary constructors/scripts/const_class.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "isConst": true, + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/const_class_namedpar.json b/working/2364 - primary constructors/scripts/const_class_namedpar.json new file mode 100644 index 000000000..cf0961726 --- /dev/null +++ b/working/2364 - primary constructors/scripts/const_class_namedpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "isConst": true, + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/const_class_optpar.json b/working/2364 - primary constructors/scripts/const_class_optpar.json new file mode 100644 index 000000000..edd4fddc7 --- /dev/null +++ b/working/2364 - primary constructors/scripts/const_class_optpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "isConst": true, + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/const_class_requiredpar.json b/working/2364 - primary constructors/scripts/const_class_requiredpar.json new file mode 100644 index 000000000..4c71f4677 --- /dev/null +++ b/working/2364 - primary constructors/scripts/const_class_requiredpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "isConst": true, + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/generic_class.json b/working/2364 - primary constructors/scripts/generic_class.json new file mode 100644 index 000000000..47623d4ab --- /dev/null +++ b/working/2364 - primary constructors/scripts/generic_class.json @@ -0,0 +1,14 @@ +{ + "name": "Point", + "typeParameters": "", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/generic_class_namedpar.json b/working/2364 - primary constructors/scripts/generic_class_namedpar.json new file mode 100644 index 000000000..555408ab5 --- /dev/null +++ b/working/2364 - primary constructors/scripts/generic_class_namedpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "typeParameters": "", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/generic_class_optpar.json b/working/2364 - primary constructors/scripts/generic_class_optpar.json new file mode 100644 index 000000000..aacfbbf22 --- /dev/null +++ b/working/2364 - primary constructors/scripts/generic_class_optpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "typeParameters": "", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/generic_class_requiredpar.json b/working/2364 - primary constructors/scripts/generic_class_requiredpar.json new file mode 100644 index 000000000..71d9b8812 --- /dev/null +++ b/working/2364 - primary constructors/scripts/generic_class_requiredpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "typeParameters": "", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_class.json b/working/2364 - primary constructors/scripts/inline_class.json new file mode 100644 index 000000000..ed66ba50b --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_class.json @@ -0,0 +1,11 @@ +{ + "isInline": true, + "name": "Point", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_const_class.json b/working/2364 - primary constructors/scripts/inline_const_class.json new file mode 100644 index 000000000..3f963365b --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_const_class.json @@ -0,0 +1,12 @@ +{ + "isInline": true, + "name": "Point", + "isConst": true, + "fields": [ + { + "name":"x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_generic_class.json b/working/2364 - primary constructors/scripts/inline_generic_class.json new file mode 100644 index 000000000..142ceb391 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_generic_class.json @@ -0,0 +1,12 @@ +{ + "isInline": true, + "name": "Point", + "typeParameters": "", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_named_class.json b/working/2364 - primary constructors/scripts/inline_named_class.json new file mode 100644 index 000000000..80e809ce8 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_named_class.json @@ -0,0 +1,12 @@ +{ + "isInline": true, + "name": "Point", + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_named_const_class.json b/working/2364 - primary constructors/scripts/inline_named_const_class.json new file mode 100644 index 000000000..eed0bc5b5 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_named_const_class.json @@ -0,0 +1,13 @@ +{ + "isInline": true, + "name": "Point", + "isConst": true, + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_subtyped_class.json b/working/2364 - primary constructors/scripts/inline_subtyped_class.json new file mode 100644 index 000000000..ebb1864c1 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_subtyped_class.json @@ -0,0 +1,12 @@ +{ + "isInline": true, + "name": "Point", + "superinterfaces": "implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_subtyped_const_class.json b/working/2364 - primary constructors/scripts/inline_subtyped_const_class.json new file mode 100644 index 000000000..a49a82e10 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_subtyped_const_class.json @@ -0,0 +1,13 @@ +{ + "isInline": true, + "name": "Point", + "isConst": true, + "superinterfaces": "implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_subtyped_generic_class.json b/working/2364 - primary constructors/scripts/inline_subtyped_generic_class.json new file mode 100644 index 000000000..6fb9f4e1d --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_subtyped_generic_class.json @@ -0,0 +1,13 @@ +{ + "isInline": true, + "name": "Point", + "typeParameters": "", + "superinterfaces": "implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/inline_subtyped_generic_const_class.json b/working/2364 - primary constructors/scripts/inline_subtyped_generic_const_class.json new file mode 100644 index 000000000..f13c2bd83 --- /dev/null +++ b/working/2364 - primary constructors/scripts/inline_subtyped_generic_const_class.json @@ -0,0 +1,14 @@ +{ + "isInline": true, + "name": "Point", + "isConst": true, + "typeParameters": "", + "superinterfaces": "implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_class.json b/working/2364 - primary constructors/scripts/named_class.json new file mode 100644 index 000000000..e3b8fd9a4 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_class.json @@ -0,0 +1,14 @@ +{ + "name": "Point", + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_class_namedpar.json b/working/2364 - primary constructors/scripts/named_class_namedpar.json new file mode 100644 index 000000000..ea294b96a --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_class_namedpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_class_optpar.json b/working/2364 - primary constructors/scripts/named_class_optpar.json new file mode 100644 index 000000000..a9256b3e1 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_class_optpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_class_requiredpar.json new file mode 100644 index 000000000..1a051cee3 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_class_requiredpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_const_class.json b/working/2364 - primary constructors/scripts/named_const_class.json new file mode 100644 index 000000000..2476e0f44 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_const_class.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "isConst": true, + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_const_class_namedpar.json b/working/2364 - primary constructors/scripts/named_const_class_namedpar.json new file mode 100644 index 000000000..cb6d791e9 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_const_class_namedpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "isConst": true, + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_const_class_optpar.json b/working/2364 - primary constructors/scripts/named_const_class_optpar.json new file mode 100644 index 000000000..fd0504062 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_const_class_optpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "isConst": true, + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_const_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_const_class_requiredpar.json new file mode 100644 index 000000000..a1b19643a --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_const_class_requiredpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "isConst": true, + "constructorName": "_", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_class.json b/working/2364 - primary constructors/scripts/named_subtyped_class.json new file mode 100644 index 000000000..867086797 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_class.json @@ -0,0 +1,15 @@ +{ + "name": "Point", + "constructorName": "_", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_class_namedpar.json b/working/2364 - primary constructors/scripts/named_subtyped_class_namedpar.json new file mode 100644 index 000000000..431dc8586 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_class_namedpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "constructorName": "_", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_class_optpar.json b/working/2364 - primary constructors/scripts/named_subtyped_class_optpar.json new file mode 100644 index 000000000..bd1196e55 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_class_optpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "constructorName": "_", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_subtyped_class_requiredpar.json new file mode 100644 index 000000000..f11504d06 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_class_requiredpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "constructorName": "_", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_const_class.json b/working/2364 - primary constructors/scripts/named_subtyped_const_class.json new file mode 100644 index 000000000..62b2e98b7 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_const_class.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_const_class_namedpar.json b/working/2364 - primary constructors/scripts/named_subtyped_const_class_namedpar.json new file mode 100644 index 000000000..9da9235e2 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_const_class_namedpar.json @@ -0,0 +1,21 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_const_class_optpar.json b/working/2364 - primary constructors/scripts/named_subtyped_const_class_optpar.json new file mode 100644 index 000000000..84a763bc4 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_const_class_optpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_const_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_subtyped_const_class_requiredpar.json new file mode 100644 index 000000000..d5a432335 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_const_class_requiredpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_class.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_class.json new file mode 100644 index 000000000..1b7a26f44 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_class.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "constructorName": "_", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_class_namedpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_namedpar.json new file mode 100644 index 000000000..37eb52ab7 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_namedpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "constructorName": "_", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_class_optpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_optpar.json new file mode 100644 index 000000000..a901f349e --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_optpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "constructorName": "_", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_requiredpar.json new file mode 100644 index 000000000..dea66686f --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_class_requiredpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "constructorName": "_", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class.json new file mode 100644 index 000000000..b17264f01 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_namedpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_namedpar.json new file mode 100644 index 000000000..e6cf194fa --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_namedpar.json @@ -0,0 +1,22 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_optpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_optpar.json new file mode 100644 index 000000000..d818c950e --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_optpar.json @@ -0,0 +1,21 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_requiredpar.json b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_requiredpar.json new file mode 100644 index 000000000..671d0a377 --- /dev/null +++ b/working/2364 - primary constructors/scripts/named_subtyped_generic_const_class_requiredpar.json @@ -0,0 +1,21 @@ +{ + "name": "Point", + "constructorName": "_", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/show_primary_constructors.dart b/working/2364 - primary constructors/scripts/show_primary_constructors.dart new file mode 100755 index 000000000..2ed71c47f --- /dev/null +++ b/working/2364 - primary constructors/scripts/show_primary_constructors.dart @@ -0,0 +1,476 @@ +#!/usr/bin/env dart + +import 'dart:convert'; +import 'dart:io'; + +abstract final class Options { + static bool identifyStyle = false; + static bool explicitFinal = false; + static bool includeBody = false; + static bool showNormal = false; + static bool showStruct = false; + static bool showKeyword = false; + static bool numberClassNames = false; +} + +var classNameNumber = 1; + +String get classNameNumberSuffix { + return Options.numberClassNames ? '$classNameNumber' : ''; +} + +var helpPrintedAlready = false; + +void help() { + if (helpPrintedAlready) return; + helpPrintedAlready = true; + print('Usage: show_primary_constructors.dart [options] [file]...'); + print(""" + +Every option is off by default, and specifying it will have an effect. + +Options: + --help, -h: Print this help text. + --identify-style, -i: Include comment `Normal`/`Struct`/`Keyword`. + --explicit-final, -f: Include `final` even when it is implied. + --include-body, -b: Include a class body (otherwise `;` is used if possible). + --show-normal, -n: Show a normal constructor and explicit field declarations. + --show-keyword, -k: Show the form that uses a keyword. + --show-struct, -s: Show the form which was proposed along with structs. + --show-all, -a: Show all forms; enabled if no other '--show' option is given. + --number-class-names: Append number to class names, to avoid name clashes. +"""); +} + +Never fail() { + print('\nStopping.'); + exit(-1); +} + +bool processOption(String option) { + if (option.startsWith('--')) { + var optionName = option.substring(2); + switch (optionName) { + case 'help': + help(); + return true; + case 'identify-style': + Options.identifyStyle = true; + return true; + case 'explicit-final': + Options.explicitFinal = true; + return true; + case 'include-body': + Options.includeBody = true; + return true; + case 'show-all': + Options.showNormal = true; + Options.showStruct = true; + Options.showKeyword = true; + return true; + case 'show-normal': + Options.showNormal = true; + return true; + case 'show-struct': + Options.showStruct = true; + return true; + case 'show-keyword': + Options.showKeyword = true; + return true; + case 'number-class-names': + Options.numberClassNames = true; + return true; + default: + return false; + } + } else if (option.startsWith('-')) { + var optionString = option.substring(1); + var usedTheOption = false; + for (var c in optionString.split('')) { + switch (c) { + case 'h': + help(); + usedTheOption = true; + case 'i': + Options.identifyStyle = true; + usedTheOption = true; + case 'f': + Options.explicitFinal = true; + usedTheOption = true; + case 'b': + Options.includeBody = true; + usedTheOption = true; + case 'a': + Options.showNormal = true; + Options.showStruct = true; + Options.showKeyword = true; + usedTheOption = true; + case 'n': + Options.showNormal = true; + usedTheOption = true; + case 's': + Options.showStruct = true; + usedTheOption = true; + case 'k': + Options.showKeyword = true; + usedTheOption = true; + default: + print('Unknown option: -$c'); + } + } + return usedTheOption; + } + return false; // This was not an option. +} + +List processOptions(List args) { + var result = []; + for (var arg in args) { + if (!processOption(arg)) result.add(arg); + } + return result; +} + +class ClassSpec { + final String provenance; // Identify where we got this class from. + final String name; + final String? constructorName; + final bool isInline; + final List fields; + final bool isConst; + final String? superinterfaces; + final String? typeParameters; + + ClassSpec( + this.provenance, + this.name, + this.constructorName, + this.isInline, + this.fields, + this.isConst, + this.typeParameters, + this.superinterfaces, + ); + + factory ClassSpec.fromJson(String source, Map jsonSpec) { + var name = jsonSpec['name']!; + var constructorName = jsonSpec['constructorName']; + var isInline = jsonSpec['isInline'] ?? false; + var jsonFields = jsonSpec['fields']!; + var isConst = jsonSpec['isConst'] ?? false; + var typeParameters = jsonSpec['typeParameters']; + var superinterfaces = jsonSpec['superinterfaces']; + var fields = []; + + for (var jsonField in jsonFields) { + var field = FieldSpec.fromJson(jsonField); + fields.add(field); + } + return ClassSpec( + source, + name, + constructorName, + isInline, + fields, + isConst, + typeParameters, + superinterfaces, + ); + } +} + +class FieldSpec { + String name; + String type; + bool isFinal; + bool isOptional; + bool isNamed; + String? defaultValue; + + FieldSpec( + this.name, + this.type, + this.isFinal, + this.isOptional, + this.isNamed, + this.defaultValue, + ); + + factory FieldSpec.fromJson(Map jsonField) { + var name = jsonField['name']!; + var type = jsonField['type']!; + var isFinal = jsonField['isFinal'] ?? false; + var isOptional = jsonField['isOptional'] ?? false; + var isNamed = jsonField['isNamed'] ?? false; + var defaultValue = jsonField['defaultValue']; + return FieldSpec(name, type, isFinal, isOptional, isNamed, defaultValue); + } +} + +String ppNormal(ClassSpec classSpec) { + var className = '${classSpec.name}$classNameNumberSuffix'; + var fieldsSource = StringBuffer(''); + var parametersSource = StringBuffer(''); + var constructorSource = StringBuffer(''); + + var first = true; + var firstOptionalOrNamed = true; + var hasOptionalsOrNamed = false; + var optionalOrNamedMeansNamed = false; + for (var field in classSpec.fields) { + var fieldName = field.name; + if (first) { + first = false; + fieldsSource.write('\n'); + } else { + parametersSource.write(', '); + } + var finality = field.isFinal ? 'final ' : ''; + fieldsSource.write(' $finality${field.type} $fieldName;\n'); + if ((field.isOptional || field.isNamed) && firstOptionalOrNamed) { + if (field.isNamed) { + optionalOrNamedMeansNamed = true; + parametersSource.write('{'); + } else { + parametersSource.write('['); + } + hasOptionalsOrNamed = true; + } + bool isRequired = field.isNamed && !field.isOptional; + var requiredness = isRequired ? 'required ' : ''; + parametersSource.write('${requiredness}this.$fieldName'); + if (field.isOptional) { + var defaultValue = field.defaultValue; + if (defaultValue != null) { + parametersSource.write(' = $defaultValue'); + } + } + } + if (hasOptionalsOrNamed) { + if (optionalOrNamedMeansNamed) { + parametersSource.write('}'); + } else { + parametersSource.write(']'); + } + } + var constNess = classSpec.isConst ? 'const ' : ''; + + var constructorName = className; + var constructorNameSpec = classSpec.constructorName; + if (constructorNameSpec != null) { + constructorName = '$className.$constructorNameSpec'; + } + + constructorSource.write(' $constNess$constructorName($parametersSource);\n'); + + var typeParameters = classSpec.typeParameters ?? ''; + String superinterfaces = ''; + var specSuperinterfaces = classSpec.superinterfaces; + if (specSuperinterfaces != null) { + superinterfaces = ' $specSuperinterfaces'; + } + + var inlinity = classSpec.isInline ? 'inline ' : ''; + + var body = Options.includeBody ? ' // ...\n' : ''; + return "${inlinity}class $className$typeParameters$superinterfaces" + " {$fieldsSource$constructorSource$body}"; +} + +String ppKeyword(ClassSpec classSpec) { + var className = '${classSpec.name}$classNameNumberSuffix'; + var fields = classSpec.fields; + var parametersSource = StringBuffer(''); + + var first = true; + var firstOptionalOrNamed = true; + var hasOptionalsOrNamed = false; + var optionalOrNamedMeansNamed = false; + for (var field in fields) { + if (first) { + first = false; + } else { + parametersSource.write(', '); + } + var finality = ''; + if (field.isFinal) { + if (classSpec.isConst || classSpec.isInline) { + if (Options.explicitFinal) finality = 'final '; + } else { + finality = 'final '; + } + } + if ((field.isOptional || field.isNamed) && firstOptionalOrNamed) { + if (field.isNamed) { + optionalOrNamedMeansNamed = true; + parametersSource.write('{'); + } else { + parametersSource.write('['); + } + hasOptionalsOrNamed = true; + } + bool isRequired = field.isNamed && !field.isOptional; + var requiredness = isRequired ? 'required ' : ''; + parametersSource.write('$requiredness$finality${field.type} ${field.name}'); + if (field.isOptional) { + var defaultValue = field.defaultValue; + if (defaultValue != null) { + parametersSource.write(' = $defaultValue'); + } + } + } + if (hasOptionalsOrNamed) { + if (optionalOrNamedMeansNamed) { + parametersSource.write('}'); + } else { + parametersSource.write(']'); + } + } + var keyword = classSpec.isConst ? 'const' : 'new'; + var typeParameters = classSpec.typeParameters ?? ''; + + String superinterfaces = ''; + var specSuperinterfaces = classSpec.superinterfaces; + if (specSuperinterfaces != null) { + superinterfaces = ' $specSuperinterfaces\n '; + } + + String constructorPhrase = '$keyword'; + var constructorNameSpec = classSpec.constructorName; + if (constructorNameSpec != null) { + constructorPhrase = '$keyword.$constructorNameSpec'; + } + + var inlinity = classSpec.isInline ? 'inline ' : ''; + var classHeader = + "${inlinity}class $className$typeParameters$superinterfaces" + " $constructorPhrase($parametersSource)"; + var body = Options.includeBody ? ' {\n // ...\n\}' : ';'; + return "$classHeader$body"; +} + +String ppStruct(ClassSpec classSpec) { + var className = '${classSpec.name}$classNameNumberSuffix'; + var fields = classSpec.fields; + var parametersSource = StringBuffer(''); + + var first = true; + var firstOptionalOrNamed = true; + var hasOptionalsOrNamed = false; + var optionalOrNamedMeansNamed = false; + for (var field in fields) { + if (first) { + first = false; + } else { + parametersSource.write(', '); + } + var finality = ''; + if (field.isFinal) { + if (classSpec.isConst || classSpec.isInline) { + if (Options.explicitFinal) finality = 'final '; + } else { + finality = 'final '; + } + } + if ((field.isOptional || field.isNamed) && firstOptionalOrNamed) { + if (field.isNamed) { + optionalOrNamedMeansNamed = true; + parametersSource.write('{'); + } else { + parametersSource.write('['); + } + hasOptionalsOrNamed = true; + } + bool isRequired = field.isNamed && !field.isOptional; + var requiredness = isRequired ? 'required ' : ''; + parametersSource.write('$requiredness$finality${field.type} ${field.name}'); + if (field.isOptional) { + var defaultValue = field.defaultValue; + if (defaultValue != null) { + parametersSource.write(' = $defaultValue'); + } + } + } + if (hasOptionalsOrNamed) { + if (optionalOrNamedMeansNamed) { + parametersSource.write('}'); + } else { + parametersSource.write(']'); + } + } + var constNess = classSpec.isConst ? 'const ' : ''; + var typeParameters = classSpec.typeParameters ?? ''; + + String superinterfaces = ''; + var specSuperinterfaces = classSpec.superinterfaces; + if (specSuperinterfaces != null) { + superinterfaces = '\n $specSuperinterfaces'; + } + + String constructorNamePart = '$className'; + var constructorNameSpec = classSpec.constructorName; + if (constructorNameSpec != null) { + constructorNamePart = '$className.$constructorNameSpec$typeParameters'; + } else { + constructorNamePart = '$className$typeParameters'; + } + + var inlinity = classSpec.isInline ? 'inline ' : ''; + var classHeader = + "${inlinity}class $constNess$constructorNamePart" + "($parametersSource)" + "$superinterfaces"; + var body = Options.includeBody ? ' {\n // ...\n\}' : ';'; + return "$classHeader$body"; +} + +void main(List args) { + // We expect arguments to be options or file paths. + var filePaths = processOptions(args); + if (filePaths.isEmpty) { + help(); + exit(0); + } + if (!Options.showNormal && !Options.showStruct && !Options.showKeyword) { + // Default is to show all formats. + Options.showNormal = Options.showStruct = Options.showKeyword = true; + } + + var classSpecs = []; + for (var filePath in filePaths) { + String source; + try { + source = File(filePath).readAsStringSync(); + } catch (_) { + print("Could not read '$filePath'."); + fail(); + } + var jsonSpec = jsonDecode(source); + classSpecs.add(ClassSpec.fromJson(filePath, jsonSpec)); + } + + + void show(String comment, String source) { + if (Options.identifyStyle){ + print('// $comment.\n\n$source\n'); + } else { + print('$source\n'); + } + } + + for (var classSpec in classSpecs) { + print('// ------------------------------ ${classSpec.provenance}\n'); + if (Options.showNormal) { + show("Normal", ppNormal(classSpec)); + ++classNameNumber; + } + if (Options.showStruct) { + show("Struct style", ppStruct(classSpec)); + ++classNameNumber; + } + if (Options.showKeyword) { + show("Rightmost, with keyword", ppKeyword(classSpec)); + ++classNameNumber; + } + } +} diff --git a/working/2364 - primary constructors/scripts/subtyped_class.json b/working/2364 - primary constructors/scripts/subtyped_class.json new file mode 100644 index 000000000..edbbbbf61 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_class.json @@ -0,0 +1,14 @@ +{ + "name": "Point", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_class_namedpar.json b/working/2364 - primary constructors/scripts/subtyped_class_namedpar.json new file mode 100644 index 000000000..bd9870464 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_class_namedpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_class_optpar.json b/working/2364 - primary constructors/scripts/subtyped_class_optpar.json new file mode 100644 index 000000000..e9c6331b5 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_class_optpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_class_requiredpar.json b/working/2364 - primary constructors/scripts/subtyped_class_requiredpar.json new file mode 100644 index 000000000..09aa8c38c --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_class_requiredpar.json @@ -0,0 +1,16 @@ +{ + "name": "Point", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_const_class.json b/working/2364 - primary constructors/scripts/subtyped_const_class.json new file mode 100644 index 000000000..4506134ab --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_const_class.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_const_class_namedpar.json b/working/2364 - primary constructors/scripts/subtyped_const_class_namedpar.json new file mode 100644 index 000000000..2ae913856 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_const_class_namedpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_const_class_optpar.json b/working/2364 - primary constructors/scripts/subtyped_const_class_optpar.json new file mode 100644 index 000000000..1974fc7f4 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_const_class_optpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_const_class_requiredpar.json b/working/2364 - primary constructors/scripts/subtyped_const_class_requiredpar.json new file mode 100644 index 000000000..f7f5ede3a --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_const_class_requiredpar.json @@ -0,0 +1,19 @@ +{ + "name": "Point", + "isConst": true, + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_class.json b/working/2364 - primary constructors/scripts/subtyped_generic_class.json new file mode 100644 index 000000000..312ae6c4b --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_class.json @@ -0,0 +1,15 @@ +{ + "name": "Point", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_class_namedpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_class_namedpar.json new file mode 100644 index 000000000..f738ff81d --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_class_namedpar.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_class_optpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_class_optpar.json new file mode 100644 index 000000000..c62f506d7 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_class_optpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_class_requiredpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_class_requiredpar.json new file mode 100644 index 000000000..ac21923ab --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_class_requiredpar.json @@ -0,0 +1,17 @@ +{ + "name": "Point", + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int" + }, + { + "name": "y", + "type": "int", + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_const_class.json b/working/2364 - primary constructors/scripts/subtyped_generic_const_class.json new file mode 100644 index 000000000..d4d337c94 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_const_class.json @@ -0,0 +1,18 @@ +{ + "name": "Point", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_const_class_namedpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_namedpar.json new file mode 100644 index 000000000..acb883878 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_namedpar.json @@ -0,0 +1,21 @@ +{ + "name": "Point", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "isNamed": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_const_class_optpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_optpar.json new file mode 100644 index 000000000..181dc76eb --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_optpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isOptional": true, + "defaultValue": "0" + } + ] +} diff --git a/working/2364 - primary constructors/scripts/subtyped_generic_const_class_requiredpar.json b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_requiredpar.json new file mode 100644 index 000000000..6350ae673 --- /dev/null +++ b/working/2364 - primary constructors/scripts/subtyped_generic_const_class_requiredpar.json @@ -0,0 +1,20 @@ +{ + "name": "Point", + "isConst": true, + "typeParameters": "", + "superinterfaces": "extends A with M implements B, C", + "fields": [ + { + "name": "x", + "type": "int", + "isFinal": true + }, + { + "name": "y", + "type": "int", + "isFinal": true, + "isNamed": true, + "defaultValue": "0" + } + ] +}