Skip to content

Commit af9b347

Browse files
committed
Review response
1 parent 5432dbe commit af9b347

File tree

1 file changed

+120
-64
lines changed

1 file changed

+120
-64
lines changed

working/0723-static-extensions/feature-specification-variant2.md

Lines changed: 120 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,19 @@ Map<String, List<bool>> string2listOfBool = Map.fromString([]);
125125

126126
The grammar remains unchanged.
127127

128-
However, it is no longer an error to declare a factory constructor in an
129-
extension declaration that has an on-class, be it redirecting or not,
130-
constant or not. *Such declarations may of course give rise to errors as
131-
usual, e.g., if a redirecting factory constructor redirects to a
132-
constructor that does not exist, or there is a redirection cycle.*
128+
However, it is no longer an error to declare a factory constructor
129+
(redirecting or not) or a redirecting generative constructor in an
130+
extension declaration that has an on-class, possibly constant. *Such
131+
declarations may of course give rise to errors as usual, e.g., if a
132+
redirecting factory constructor redirects to a constructor that does not
133+
exist, or there is a redirection cycle.*
133134

134135
In an extension declaration of the form `extension E on C {...}` where `C`
135136
is an identifier or an identifier with an import prefix that denotes a
136137
class, mixin, enum, or extension type declaration, we say that the
137138
_on-class_ of the extension is `C`. If `C` denotes a non-generic class,
138-
mixin, mixin class, or extension type then we say that the _constructor return
139-
type_ of the extension is `C`.
139+
mixin, mixin class, or extension type then we say that the _constructor
140+
return type_ of the extension is `C`.
140141

141142
If `C` denotes a generic class then `E` is treated as
142143
`extension E on C<T1 .. Tk> {...}` where `T1 .. Tk` are obtained by
@@ -193,44 +194,79 @@ on-class. The warning above is aimed at static members and constructors,
193194
but a similar warning would probably be useful for instance members as
194195
well.*
195196

196-
#### Invocation of a static member of an extension
197+
#### Invocation of a static member
197198

198-
An _explicitly resolved invocation_ of a static member of an extension
199-
named `E` is an expression of the form `E.m()` (or any other member access,
200-
*e.g., `E.m`, `E.m = e`, etc*), where `m` is a static member declared by
201-
`E`.
199+
*The language specification defines the notion of a _member invocation_ in
200+
the section [Member Invocations][], which is used below. This concept
201+
includes method invocations like `e.aMethod<int>(24)`, property extractions
202+
like `e.aGetter` or `e.aMethod` (tear-offs), operator invocations like
203+
`e1 + e2` or `aListOrNull?[1] = e`, function invocations like `f()`. Each
204+
of these expressions has a _syntactic receiver_ and an _associated member
205+
name_. With `e.aMethod<int>(24)`, the receiver is `e` and the associated
206+
member name is `aMethod`, with `e1 + e2` the receiver is `e1` and the
207+
member name is `+`, and with `f()` the receiver is `f` and the member name
208+
is `call`. Note that the syntactic receiver is a type literal in the case
209+
where the member invocation invokes a static member. In the following we
210+
will specify invocations of static members using this concept.*
211+
212+
[Member Invocations]: https://github.com/dart-lang/language/blob/94194cee07d7deadf098b1f1e0475cb424f3d4be/specification/dartLangSpec.tex#L13903
213+
214+
Consider an expression `e` which is a member invocation with syntactic
215+
receiver `E` and associated member name `m`, where `E` denotes an extension
216+
and `m` is a static member declared by `E`. We say that `e` is an
217+
_explicitly resolved invocation_ of said static member of `E`.
202218

203219
*This can be used to invoke a static member of a specific extension in
204-
order to manually resolve a name clash. At the same time, in current Dart
205-
(without the feature which is specified in this document), this is the only
206-
way we can invoke a static member of an extension, so it may be useful for
207-
backward compatibility reasons.*
208-
209-
A static member invocation on a class `C`, of the form `C.m()` (or any
210-
other member access), is resolved by looking up static members in `C` named
211-
`m` and looking up static members of every accessible extension with
212-
on-class `C` and a static member named `m`.
213-
214-
If `C` contains such a declaration then the expression is an invocation of
215-
that static member of `C`, with the same static analysis and dynamic
216-
semantics as before the introduction of this feature.
217-
218-
Otherwise, if `C` declares a constructor named `C.m` then the given
219-
expression is not a static member invocation. It is then handled with the
220-
same static analysis and dynamic semantics as before the introduction of
221-
this feature *(it may be an error, or it may be an instance creation
222-
expression; in any case, declarations in `C` are given a higher priority
223-
than declarations in extensions)*.
224-
225-
Otherwise, an error occurs if no declarations named `m` or more than one
226-
declaration named `m` were found, or if both static members named `m` and
227-
constructors named `C.m` were found. *They would necessarily be declared in
228-
extensions.*
229-
230-
Otherwise, the invocation is resolved to the given static member
231-
declaration in an extension named `Ej`, and the invocation is treated
232-
as `Ej.m()` *(this is an explicitly resolved invocation, which is specified
233-
above)*.
220+
order to manually resolve a name clash. At the same time, in Dart without
221+
the feature which is specified in this document, this is the only way we
222+
can invoke a static member of an extension (except when it is in scope, see
223+
below), so it may be useful for backward compatibility.*
224+
225+
Consider an expression `e` which is a member invocation with syntactic
226+
receiver `C` and an associated member name `m`, where `C` denotes a class
227+
and `m` is a static member declared by `C`. The static analysis and dynamic
228+
semantics of this expression is the same as in Dart before the introduction
229+
of this feature.
230+
231+
When `C` declares a static member whose basename is the basename of `m`,
232+
but `C` does not declare a static member named `m` or a constructor named
233+
`C.m`, a compile-time error occurs. *This is the same behavior as in
234+
pre-feature Dart.*
235+
236+
In the case where `C` does not declare any static members whose basename is
237+
the basename of `m`, and `C` does not declare any constructors named `C.m2`
238+
where `m2` is the basename of `m`, let _M_ be the set of each accessible
239+
extension whose on-class is `C`, and whose static members include one with
240+
the name `m`, or which declares a constructor named `C.m`.
241+
242+
*If `C` does declare a constructor with such a name `C.m2` then the given
243+
expression is not a static member invocation. This case is described in a
244+
section below.*
245+
246+
Otherwise, an error occurs if _M_ is empty or _M_ contains more than one
247+
member.
248+
249+
Otherwise, assume that _M_ contains exactly one element which is an
250+
extension `E` that declares a static member named `m`. The invocation is
251+
then treated as `E.m()` *(this is an explicitly resolved invocation, which
252+
is specified above)*.
253+
254+
Otherwise, _M_ will contain exactly one element which is a constructor
255+
named `C.m`. This is not a static member invocation, and it is specified in
256+
a section below.
257+
258+
In addition to these rules for invocations of static members of a class or
259+
an extension, a corresponding set of rules exist for the following: An
260+
enumerated declaration *(`enum ...`)*, a mixin class, a mixin, and an
261+
extension type. They only differ by being concerned with a different kind
262+
of declaration.
263+
264+
In addition to the member invocations specified above, it is also possible
265+
to invoke a static member of the enclosing declaration based on lexical
266+
lookup. This case is applicable when an expression in a class, enum, mixin
267+
or extension type resolves to an invocation of a static member of the
268+
enclosing declaration. It will never invoke a static member of an extension
269+
which is not the enclosing declaration.
234270

235271
#### The instantiated constructor return type of an extension
236272

@@ -255,11 +291,11 @@ and it has a constructor return type of the form `C<S1 .. Sk>`. In this
255291
case the instantiated constructor return type of _D_ is `C<S1 .. Sk>`,
256292
which is a ground type, and it is the same for all call sites.*
257293

258-
#### Explicit invocation of a constructor in an extension
294+
#### Invocation of a constructor in an extension
259295

260-
Explicit constructor invocations are similar to static member invocations,
261-
but they need more detailed rules because they can use the formal type
262-
parameters declared by an extension.
296+
Explicit constructor invocations are similar to explicitly resolved static
297+
member invocations, but they need more detailed rules because they can use
298+
the formal type parameters declared by an extension.
263299

264300
An _explicitly resolved invocation_ of a constructor named `C.name` in a
265301
extension declaration _D_ named `E` with `s` type parameters and on-class
@@ -269,10 +305,10 @@ similarly for a constructor named `C` using `E<S1 .. Ss>.C(args)`, etc).
269305

270306
A compile-time error occurs if the type arguments passed to `E` violate the
271307
declared bounds. A compile-time error occurs if no type arguments are
272-
passed to `E`, and type arguments `U1 .. Uk` are passed to `C`, but no list
273-
of actual type arguments for the type variables of `E` can be found such
274-
that the instantiated constructor return type of `E` with said type
275-
arguments is `C<U1 .. Uk>`.
308+
passed to `E`, and type arguments `U1 .. Uk` are passed to `C`, but no
309+
actual type arguments for the type variables of `E` can be found such that
310+
the instantiated constructor return type of `E` with said type arguments is
311+
`C<U1 .. Uk>`.
276312

277313
*Note that we must be able to choose the values of the type parameters
278314
`X1 .. Xs` such that the instantiated constructor return type is
@@ -288,7 +324,7 @@ normalization occurs. *In other words, the types must be equal, not
288324
just mutual subtypes.*
289325

290326
*Note that explicitly resolved invocations of constructors declared in
291-
extensions are an exception in real code, usable in the case where a
327+
extensions are a rare exception in real code, usable in the case where a
292328
name clash prevents an implicitly resolved invocation. However, implicitly
293329
resolved invocations are specified in the rest of this section by reducing
294330
them to explicitly resolved ones.*
@@ -303,16 +339,26 @@ If a constructor in `C` with the requested name was found, the pre-feature
303339
static analysis and dynamic semantics apply. *That is, the class always
304340
wins.*
305341

306-
Otherwise, the invocation is partially resolved to a set of candidate
307-
constructors found in extensions. Each of the candidates _kj_ is
308-
vetted as follows:
342+
Otherwise, if `m` is zero *(which means that the invocation is
343+
`C.name(args)`)*, and `C` declares a static member whose basename is the
344+
basename of `name`, the invocation is a static member invocation *(which is
345+
specified in an earlier section)*.
346+
347+
Otherwise, the invocation is partially resolved to a set _M_ of candidate
348+
constructors and static members found in extensions. Each of the candidates
349+
_kj_ is vetted as follows:
350+
351+
If `m` is zero and `E` is an accessible extension with on-class `C`
352+
that declares a static member whose basename is `name` then the invocation
353+
is a static member invocation *(which is specified in an earlier section)*.
309354

310-
Assume that _kj_ is a constructor declared by an extension _D_ named
311-
`E` with type parameters `X1 extends B1 .. Xs extends Bs` and on-type
312-
`C<S1 .. Sm>`. Find actual values `U1 .. Us` for `X1 .. Xs` satisfying the
313-
bounds `B1 .. Bs`, such that `([U1/X1 .. Us/Xs]C<S1 .. Sm>) == C<T1 .. Tm>`.
314-
If this fails then remove _kj_ from the set of candidate constructors.
315-
Otherwise note that _kj_ uses actual type arguments `U1 .. Us`.
355+
Otherwise, assume that _kj_ is a constructor declared by an extension _D_
356+
named `E` with type parameters `X1 extends B1 .. Xs extends Bs`, on-class
357+
`C`, and on-type `C<S1 .. Sm>`. Find actual values `U1 .. Us` for
358+
`X1 .. Xs` satisfying the bounds `B1 .. Bs`, such that
359+
`([U1/X1 .. Us/Xs]C<S1 .. Sm>) == C<T1 .. Tm>`. If this fails then remove
360+
_kj_ from the set of candidate constructors. Otherwise note that _kj_
361+
uses actual type arguments `U1 .. Us`.
316362

317363
If all candidate constructors have been removed, or more than one candidate
318364
remains, a compile-time error occurs. Otherwise, the invocation is
@@ -338,13 +384,19 @@ In the case where the invocation resolves to exactly one constructor
338384
`C.name` (or `C`) declared by an extension named `E`, the invocation
339385
is treated as `E.C.name(args)` (respectively `E.C(args)`).
340386

341-
Otherwise, when there are two or more candidates from extensions,
342-
an error occurs. *We do not wish to specify an approach whereby `args` is
343-
subject to type inference multiple times, and hence we do not support type
344-
inference for `C.name(args)` in the case where there are multiple distinct
387+
Otherwise, when there are two or more candidates from extensions, an error
388+
occurs. *We do not wish to specify an approach whereby `args` is subject to
389+
type inference multiple times, and hence we do not support type inference
390+
for `C.name(args)` in the case where there are multiple distinct
345391
declarations whose signature could be used during the static analysis of
346392
that expression.*
347393

394+
In addition to these rules for invocations of constructors of a class or an
395+
extension, a corresponding set of rules exist for the following: An
396+
enumerated declaration *(`enum ...`)*, a mixin class, a mixin, and an
397+
extension type. They only differ by being concerned with a different kind
398+
of declaration.
399+
348400
### Dynamic Semantics
349401

350402
The dynamic semantics of static members of an extension is the same
@@ -362,6 +414,10 @@ This fully determines the dynamic semantics of this feature.
362414

363415
### Changelog
364416

417+
1.1 - Aug 21, 2024
418+
419+
* Extensive revision of this document based on thorough review.
420+
365421
1.0 - May 31, 2024
366422

367423
* First version of this document released.

0 commit comments

Comments
 (0)