Integrated nosuchmethod-forwarding.md into dartLangSpec.tex

Change-Id: I7a29b83a69f43cb695b4305442808fa45b745faa
Reviewed-on: https://dart-review.googlesource.com/c/77440
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
This commit is contained in:
Erik Ernst 2018-10-10 13:35:50 +00:00
parent 327a1a9a00
commit a9b47bd0b1
2 changed files with 368 additions and 110 deletions

View file

@ -1,4 +1,5 @@
\documentclass{article} \documentclass{article}
\usepackage{xspace}
\usepackage{epsfig} \usepackage{epsfig}
\usepackage{color} \usepackage{color}
\usepackage{syntax} \usepackage{syntax}
@ -61,6 +62,7 @@
% program such that it takes exports into account. % program such that it takes exports into account.
% - Eliminate all references to checked and production mode, Dart 2 does % - Eliminate all references to checked and production mode, Dart 2 does
% not have modes. % not have modes.
% - Integrate feature specification on noSuchMethod forwarders.
% %
% 2.0 % 2.0
% - Don't allow functions as assert test values. % - Don't allow functions as assert test values.
@ -1629,6 +1631,298 @@ The rationale for this behavior is that assignments should be guaranteed to eval
} }
\subsubsection{The Method \code{noSuchMethod}}
\LMLabel{theMethodNoSuchMethod}
\LMHash{}
The method \code{noSuchMethod} is invoked implicitly during execution
in situations where one or more member lookups fail
(\ref{ordinaryInvocation},
\ref{getterAccessAndMethodExtraction},
\ref{assignment}).
\commentary{
We may think of \code{noSuchMethod} as a backup
which kicks in when an invocation of a member $m$ is attempted,
but there is no member named $m$,
or it exists,
but the given invocation has an argument list shape
that does not fit the declaration of $m$
(passing fewer positional arguments than required or more than supported,
or passing named arguments with names not declared by $m$).
% The next sentence covers both function objects and instances of
% a class with a method named \code{call}, because we would have a
% compile-time error invoking \code{call} with a wrongly shaped argument
% list unless the type is \DYNAMIC{} or \FUNCTION.
This can only occur for an ordinary method invocation
when the receiver has static type \DYNAMIC,
or for a function invocation when
the invoked function has static type \FUNCTION{} or \DYNAMIC.
%
The method \code{noSuchMethod} can also be invoked in other ways, e.g.,
it can be called explicitly like any other method,
and it can be invoked from a \code{noSuchMethod} forwarder,
as explained below.
}
\LMHash{}
We say that a class $C$ {\em has a non-trivial \code{noSuchMethod}}
if $C$ has a concrete member named \code{noSuchMethod}
which is distinct from the one declared in the built-in class \code{Object}.
\commentary{
Note that it must be a method that accepts one positional argument,
in order to correctly override \code{noSuchMethod} in \code{Object}.
For instance, it can have signature
\code{noSuchMethod(Invocation i)} or
\code{noSuchMethod(Object i, [String s])},
but not
\code{noSuchMethod(Invocation i, String s)}.
This implies that the situation where \code{noSuchMethod} is invoked
(explicitly or implicitly)
with one actual argument cannot fail for the reason that
``there is no such method'',
such that we would enter an infinite loop trying to invoke \code{noSuchMethod}.
It \emph{is} possible, however, to encounter a dynamic error
during an invocation of \code{noSuchMethod}
because the actual argument fails to satisfy a type check,
but that situation will give rise to a dynamic type error
rather than a repeated attempt to invoke \code{noSuchMethod}
(\ref{bindingActualsToFormals}).
Here is an example where a dynamic type error occurs because
an attempt is made to pass an \code{Invocation}
where only the null object is accepted:
}
\begin{dartCode}
\CLASS{} A \{
noSuchMethod(\COVARIANT{} Null n) => n;
\}
\\
\VOID{} main() \{
\DYNAMIC{} d = A();
d.foo(42); // Dynamic type error when invoking noSuchMethod.
\}
\end{dartCode}
\LMHash{}
Let $C$ be a concrete class and
let $L$ be the library that contains the declaration of $C$.
The member $m$ is {\em noSuchMethod forwarded in} $C$ if{}f
one of the following is true:
\begin{itemize}
\item $C$ has a non-trivial \code{noSuchMethod},
the interface of $C$ contains $m$,
and $C$ has no concrete declaration of $m$
(\commentary{that is, no member $m$ is declared or inherited by $C$}).
\item
% Inaccessible private methods are not present in the interface of a class,
% so we need to find a class that can access $m$.
There exists a direct or indirect superinterface
$D$ of $C$ which is declared in the library $L_2$,
the interface of $D$ contains $m$
(\commentary{which implies that $m$ is accessible to $L_2$}),
$m$ is inaccessible to $L$,
and no superclass of $C$ has
a concrete declaration of $m$ accessible to $L_2$.
\end{itemize}
\LMHash{}
For a concrete class $C$, a {\em \code{noSuchMethod} forwarder}
is implicitly induced for each member $m$
which is \code{noSuchMethod} forwarded.
This is a concrete member of $C$
with the signature taken from the interface of $C$ respectively $D$ above,
and with the same default value for each optional parameter.
It can be invoked in an ordinary invocation and in a superinvocation,
and when $m$ is a method it can be closurized
(\ref{ordinaryMemberClosurization})
using a property extraction
(\ref{propertyExtraction}).
\commentary{
This implies that a \code{noSuchMethod} forwarder has the same
properties as an explicitly declared concrete member,
except of course that a \code{noSuchMethod} forwarder
does not prevent itself from being induced.
We do not specify the body of a \code{noSuchMethod} forwarder,
but it will invoke \code{noSuchMethod},
and we specify the dynamic semantics of executing it below.
}
\commentary{
At the beginning of this section we mentioned that implicit invocations
of \code{noSuchMethod} can only occur
with a receiver of static type \DYNAMIC{}
or a function of static type \DYNAMIC{} or \FUNCTION{}.
With a \code{noSuchMethod} forwarder,
\code{noSuchMethod} can also be invoked
on a receiver whose static type is not \DYNAMIC{}.
No similar situation exists for functions,
because it is impossible to induce a \code{noSuchMethod} forwarder
into the class of a function object.
}
\commentary{
For a concrete class $C$,
we may think of a non-trivial \code{noSuchMethod}
(declared in or inherited by $C$)
as a request for ``automatic implementation'' of all unimplemented members
in the interface of $C$ as \code{noSuchMethod} forwarders.
Similarly, there is an implicit request for
automatic implementation of all unimplemented
inaccessible members of any concrete class,
whether or not there is a non-trivial \code{noSuchMethod}.
Note that the latter cannot be written explicitly in Dart,
because their names are inaccessible;
but the language can still specify that they are induced implicitly,
because compilers control the treatment of private names.
}
\LMHash{}
It is a compile-time error if a concrete class $C$ has
a \code{noSuchMethod} forwarded method signature $S$
for a method named $m$,
and a superclass of $C$ has a concrete declaration of $m$
which is not a \code{noSuchMethod} forwarder.
\commentary{
This can only happen if that concrete declaration does not
correctly override $S$. Consider the following example:
}
\begin{dartCode}
\CLASS{} A \{
foo(int i) => \NULL;
\}
\ABSTRACT{} \CLASS{} B \{
foo([int i]);
\}
\CLASS{} C \EXTENDS{} A \IMPLEMENTS{} B \{
noSuchMethod(Invocation i) => ...;
// Error: Forwarder would override `A.foo`.
\}
\end{dartCode}
\commentary{
In this example,
an implementation with signature \code{foo(int i)} is inherited by \code{C},
and the superinterface \code{B} declares
the signature \code{foo([int i])}.
This is a compile-time error because \code{C} does not have
a method implementation with signature \code{foo([int])}.
We do not wish to implicitly induce
a \code{noSuchMethod} forwarder with signature \code{foo([int])}
because it would override \code{A.foo},
and that is likely to be highly confusing for developers.
%
In particular, it would cause an invocation like \code{C().foo(42)}
to invoke \code{noSuchMethod},
even though that is an invocation which is correct for
the declaration of \code{foo} in \code{A}.
%
Hence, we require developers to explicitly resolve the conflict
whenever an implicitly induced \code{noSuchMethod} forwarder
would override an explicitly declared inherited implementation.
%
It is no problem, however,
to let a \code{noSuchMethod} forwarder override
another \code{noSuchMethod} forwarder,
and hence there is no error in that situation.
}
\LMHash{}
For the dynamic semantics,
assume that a class $C$ has an implicitly induced
\code{noSuchMethod} forwarder named $m$,
with formal type parameters
\code{$X_1,\ \ldots,\ X_r$},
positional formal parameters
\code{$a1,\ \ldots,\ a_k$}
(\commentary{some of which may be optional when $m = 0$}),
and named formal parameters with names
\code{$x_1,\ \ldots,\ x_m$}
(\commentary{with default values as mentioned above}).
\commentary{
For this purpose we need not distinguish between
a signature that has optional positional parameters and
a signature that has named parameters,
because the former is covered by $m = 0$.
}
\LMHash{}
The execution of the body of $m$ creates
an instance $im$ of the predefined class \code{Invocation}
such that:
\begin{itemize}
\item \code{$im$.isMethod} evaluates to \code{\TRUE{}} if{}f $m$ is a method.
\item \code{$im$.isGetter} evaluates to \code{\TRUE{}} if{}f $m$ is a getter.
\item \code{$im$.isSetter} evaluates to \code{\TRUE{}} if{}f $m$ is a setter.
\item \code{$im$.memberName} evaluates to the symbol \code{m}.
\item \code{$im$.positionalArguments} evaluates to an unmodifiable list
with the same values as the list resulting from evaluation of
\code{<Object>[$a_1, \ldots,\ a_k$]}.
\item \code{$im$.namedArguments} evaluates to an unmodifiable map
with the same keys and values as the map resulting from evaluation of
\code{<Symbol, Object>\{$\#x_1$: $x_1, \ldots,\ \#x_m$: $x_m$\}}.
\item \code{$im$.typeArguments} evaluates to an unmodifiable list
with the same values as the list resulting from evaluation of
\code{<Type>[$X_1, \ldots,\ X_r$]}.
\end{itemize}
\LMHash{}
Next, \code{noSuchMethod} is invoked with $i$ as the actual argument,
and the result obtained from there is returned by the execution of $m$.
\commentary{
This is an ordinary method invocation of \code{noSuchMethod}
(\ref{ordinaryInvocation}).
That is, a \code{noSuchMethod} forwarder in a class $C$ can invoke
an implementation of \code{noSuchMethod} that is declared in
a subclass of $C$.
Dynamic type checks on the actual arguments passed to $m$
are performed in the same way as for an invocation of an
explicitly declared method.
In particular, an actual argument passed to a covariant parameter
will be checked dynamically.
Also, like other ordinary method invocations,
it is a dynamic type error if the result returned by
a \code{noSuchMethod} forwarder has a type which is not a subtype
of the return type of the forwarder.
One special case to be aware of is where a forwarder is torn off
and then invoked with an actual argument list which does not match
the formal parameter list.
In that situation we will get an invocation of
\code{Object.noSuchMethod}
rather than the \code{noSuchMethod} in the original receiver,
because this is an invocation of a function object
(and they do not override \code{noSuchMethod}):
}
\begin{dartCode}
\CLASS{} A \{
noSuchMethod(Invocation i) => \NULL;
\VOID{} foo();
\}
\\
\VOID{} main() \{
A a = A();
\FUNCTION{} f = a.foo;
// Invokes `Object.noSuchMethod`, which throws.
f(42);
\}
\end{dartCode}
\subsection{Getters} \subsection{Getters}
\LMLabel{getters} \LMLabel{getters}
@ -1747,7 +2041,11 @@ In classes used as mixins, it is often useful to introduce such declarations for
} }
\LMHash{} \LMHash{}
%% TODO(eernst): Revise this to use the concepts of interfaces, and do not say that an abstract member is inherited by a class. %% TODO(eernst): This is semi-redundant: We should define what it means for
%% a class to be 'fully implemented' and require once and for all that it is
%% a compile-time error if a concrete class is not fully implemented. That
%% is very nearly what line 2706++ already says. This will then be commentary,
%% just focusing on the case where a concrete $C$ _declares_ an abstract $m$.
It is a compile-time error if an abstract member $m$ is declared or inherited in a concrete class $C$ unless: It is a compile-time error if an abstract member $m$ is declared or inherited in a concrete class $C$ unless:
\begin{itemize} \begin{itemize}
\item $m$ overrides a concrete member, or \item $m$ overrides a concrete member, or
@ -2787,7 +3085,7 @@ The controlling language is in the relevant sections of the specification.
\item Rule \ref{typeSigAssignable} applies to interfaces as well as classes \item Rule \ref{typeSigAssignable} applies to interfaces as well as classes
(\ref{interfaceInheritanceAndOverriding}). (\ref{interfaceInheritanceAndOverriding}).
\item It is an error if a concrete class does not have an implementation \item It is an error if a concrete class does not have an implementation
for a method in any of its superinterfaces for a method in its interface
unless it has a concrete \code{noSuchMethod} method unless it has a concrete \code{noSuchMethod} method
(\ref{superinterfaces}) (\ref{superinterfaces})
distinct from the one in class \code{Object}. distinct from the one in class \code{Object}.
@ -2867,11 +3165,6 @@ It is a compile-time error if the implicit interface of a class $C$ has an insta
However, if a class does explicitly declare a member that conflicts with its superinterface, this always yields an error. However, if a class does explicitly declare a member that conflicts with its superinterface, this always yields an error.
} }
% TODO(eernst): When integrating nosuchmethod-forwarders.md, delete this and make sure that we mention the
% case where there is no `noSuchMethod` and we still generate forwarders.
% Consider: It is a compile-time error if an imported superinterface of a class $C$ declares private members.
% Should we ignore unimplemented private members?
\subsection{Class Member Conflicts} \subsection{Class Member Conflicts}
\LMLabel{classMemberConflicts} \LMLabel{classMemberConflicts}
@ -3680,6 +3973,13 @@ when it is used in any of the following ways:
(\ref{classes}). (\ref{classes}).
\end{itemize} \end{itemize}
\commentary{
It is \emph{not} an error if a super-bounded type occurs
as an immediate subterm of an \EXTENDS{} clause
that specifies the bound of a type variable
(\ref{generics}).
}
\commentary{ \commentary{
Types of members from super-bounded class types are computed using the same Types of members from super-bounded class types are computed using the same
rules as types of members from other types. Types of function applications rules as types of members from other types. Types of function applications
@ -6177,6 +6477,8 @@ Then the method invocation \code{f.noSuchMethod($im$)} is evaluated,
and its result is then the result of evaluating $i$. and its result is then the result of evaluating $i$.
\commentary{ \commentary{
The situation where \code{noSuchMethod} is invoked can only arise
when the static type of $e_f$ is \DYNAMIC{}.
The run-time semantics ensures that The run-time semantics ensures that
a function invocation may amount to an invocation of the instance method \CALL{}. a function invocation may amount to an invocation of the instance method \CALL{}.
However, an interface type with a method named \CALL{} is not itself a subtype of any function type. However, an interface type with a method named \CALL{} is not itself a subtype of any function type.
@ -6496,16 +6798,9 @@ Then the method \code{noSuchMethod()} is looked up in $o$ and invoked with argum
and the result of this invocation is the result of evaluating $i$. and the result of this invocation is the result of evaluating $i$.
\commentary{ \commentary{
The situation where \code{noSuchMethod} is invoked can only arise
when the static type of $e$ is \DYNAMIC{}.
Notice that the wording avoids re-evaluating the receiver $o$ and the arguments $a_i$. Notice that the wording avoids re-evaluating the receiver $o$ and the arguments $a_i$.
Also note that there is no need to specify how to handle an invocation of \code{noSuchMethod}
that fails because ``there is no such method'':
It is not possible to override the \code{noSuchMethod} of class \code{Object}
in such a way that it cannot be invoked with one argument of type \code{Invocation}.
It can fail with a dynamic type error if the parameter type is overridden with a
proper subtype of \code{Invocation},
but that does not give rise to yet another invocation of \code{noSuchMethod}.
% We might want to mention `noSuchMethod(covariant Null n) => n;`, but
% `covariant` is not yet specified, and it is not a big problem to omit it.
} }
@ -6739,14 +7034,10 @@ If the getter lookup has failed, then a new instance $im$ of the predefined clas
Then the method \code{noSuchMethod()} is looked up in $o$ and invoked with argument $im$, Then the method \code{noSuchMethod()} is looked up in $o$ and invoked with argument $im$,
and the result of this invocation is the result of evaluating $i$. and the result of this invocation is the result of evaluating $i$.
% TODO(eernst): We have removed the description of how to invoke noSuchMethod \commentary {
% in Object if the overriding noSuchMethod does not accept one argument of The situation where \code{noSuchMethod} is invoked can only arise
% type Invocation, because that will be a compile-time error soon. At this when the static type of $e$ is \DYNAMIC{}.
% point we just keep a commentary ready to say that: }
%
%% \commentary {
%% It is a compile-time error to override the \code{noSuchMethod} of class \code{Object} in such a way that it cannot be invoked with one positional argument of type \code{Invocation}.
%% }
\LMHash{} \LMHash{}
It is a compile-time error if $m$ is a member of class \code{Object} and $e$ is either a prefix object (\ref{imports}) or a constant type literal. It is a compile-time error if $m$ is a member of class \code{Object} and $e$ is either a prefix object (\ref{imports}) or a constant type literal.
@ -6800,32 +7091,11 @@ Let $f$ be the result of looking up getter $m$ in $S_{dynamic}$ with respect to
The body of $f$ is executed with \THIS{} bound to the current value of \THIS{}. The body of $f$ is executed with \THIS{} bound to the current value of \THIS{}.
The value of $i$ is the result returned by the call to the getter function. The value of $i$ is the result returned by the call to the getter function.
\LMHash{} \commentary{
If the getter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that: The getter lookup will not fail, because it is a compile-time error to have
\begin{itemize} a super property extraction of a member $m$ when the superclass $S_{dynamic}$
\item \code{$im$.isGetter} evaluates to \code{\TRUE{}}. does not have a concrete member named $m$.
\item \code{$im$.memberName} evaluates to the symbol \code{m}. }
\item \code{$im$.positionalArguments} evaluates to an empty, unmodifiable instance of
\code{List<Object>}.
\item \code{$im$.namedArguments} evaluates to an empty, unmodifiable instance of
\code{Map<Symbol, Object>}.
\item \code{$im$.typeArguments} evaluates to an empty, unmodifiable instance of
\code{List<Type>}.
\end{itemize}
\LMHash{}
Then the method \code{noSuchMethod()} is looked up in $S_{dynamic}$ and invoked with argument $im$, and the result of this invocation is the result of evaluating $i$.
% TODO(eernst): We have removed the description of how to invoke noSuchMethod
% in Object if the overriding noSuchMethod does not accept one argument of
% type Invocation, because that will be a compile-time error soon. At this
% point we just keep a commentary ready to say that:
%
%% \commentary {
%% It is a compile-time error to override the \code{noSuchMethod} of class \code{Object} in such a way that it cannot be invoked with one positional argument of type \code{Invocation}.
%% }
\LMHash{} \LMHash{}
Let $S_{static}$ be the superclass of the immediately enclosing class. Let $S_{static}$ be the superclass of the immediately enclosing class.
@ -7080,6 +7350,11 @@ An assignment changes the value associated with a mutable variable or property.
\LMHash{} \LMHash{}
\Case{\code{$v$ = $e$}} \Case{\code{$v$ = $e$}}
%% TODO(eernst): This _only_ works if we assume that `v = e` has already
%% been expanded to `this.v = e` "when that's the right thing to do".
%% Otherwise `denotes` below cannot be interpreted as the result of a lookup,
%% and we have no precise alternative which would work. We might be able
%% to repair this by giving a definition of `denotes` somewhere.
Consider an assignment $a$ of the form \code{$v$ = $e$}, Consider an assignment $a$ of the form \code{$v$ = $e$},
where $v$ is an identifier or an identifier qualified by an import prefix, where $v$ is an identifier or an identifier qualified by an import prefix,
and $v$ denotes a variable (\ref{variables}) or \code{$v$=} denotes a setter and $v$ denotes a variable (\ref{variables}) or \code{$v$=} denotes a setter
@ -7147,8 +7422,8 @@ of $v$.
\LMHash{} \LMHash{}
\Case{\code{$e_1$?.$v$ = $e_2$}} \Case{\code{$e_1$?.$v$ = $e_2$}}
Consider an assignment $a$ of the form \code{$e_1$?.$v$ = $e_2$}. Consider an assignment $a$ of the form \code{$e_1$?.$v$ = $e_2$}.
Let $S$ be the static type of the formal parameter of the setter \code{$v$=}. Exactly the same compile-time errors that would be caused by
It is a compile-time error if the static type of $e_2$ may not be assigned to $S$. \code{$e_1$.$v$ = $e_2$} are also generated in the case of $a$.
The static type of $a$ is the static type of $e_2$. The static type of $a$ is the static type of $e_2$.
\LMHash{} \LMHash{}
@ -7164,9 +7439,14 @@ Then $a$ evaluates to $r$.
\LMHash{} \LMHash{}
\Case{\code{$e_1$.$v$ = $e_2$}} \Case{\code{$e_1$.$v$ = $e_2$}}
Consider an assignment $a$ of the form \code{$e_1$.$v$ = $e_2$}. Consider an assignment $a$ of the form \code{$e_1$.$v$ = $e_2$}.
Let $S$ be the static type of the formal parameter of the setter \code{$v$=}. Let $T$ be the static type of $e_1$.
It is a compile-time error if the static type of $e_2$ may not be assigned to $S$. If $T$ is \DYNAMIC{}, no further checks are performed.
The static type of $a$ is the static type of $e_2$. Otherwise, it is a compile-time error unless
$T$ has an accessible instance setter named \code{$v$=}.
It is a compile-time error unless the static type of $e_2$
may be assigned to the declared type of the formal parameter of said setter.
Whether or not $T$ is \DYNAMIC{},
the static type of $a$ is the static type of $e_2$.
\LMHash{} \LMHash{}
Evaluation of an assignment of the form \code{$e_1$.$v$ = $e_2$} Evaluation of an assignment of the form \code{$e_1$.$v$ = $e_2$}
@ -7174,10 +7454,10 @@ proceeds as follows:
The expression $e_1$ is evaluated to an object $o_1$. The expression $e_1$ is evaluated to an object $o_1$.
Then, the expression $e_2$ is evaluated to an object $o_2$. Then, the expression $e_2$ is evaluated to an object $o_2$.
Then, the setter \code{$v$=} is looked up (\ref{lookup}) in $o_1$ with respect to the current library. Then, the setter \code{$v$=} is looked up (\ref{lookup}) in $o_1$ with respect to the current library.
%% TODO(eernst): This is metaclass stuff, should be deleted. It is a dynamic type error if the dynamic type of $o_2$
If $o_1$ is an instance of \code{Type} but $e_1$ is not a constant type literal, is not a subtype of the actual parameter type of said setter
then if \code{$v$=} is a setter that forwards (\ref{functionDeclarations}) to a static setter, setter lookup fails. (\ref{actualTypeOfADeclaration}).
Otherwise, the body of \code{$v$=} is executed with its formal parameter bound to $o_2$ and \THIS{} bound to $o_1$. Otherwise, the body of the setter is executed with its formal parameter bound to $o_2$ and \THIS{} bound to $o_1$.
\LMHash{} \LMHash{}
If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that: If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
@ -7197,36 +7477,21 @@ $\code{<Object>}[o_2]$.
\LMHash{} \LMHash{}
Then the method \code{noSuchMethod()} is looked up in $o_1$ and invoked with argument $im$. Then the method \code{noSuchMethod()} is looked up in $o_1$ and invoked with argument $im$.
% TODO(eernst): We have removed the description of how to invoke noSuchMethod \commentary{
% in Object if the overriding noSuchMethod does not accept one argument of The situation where \code{noSuchMethod} is invoked can only arise
% type Invocation, because that will be a compile-time error soon. At this when the static type of $e_1$ is \DYNAMIC{}.
% point we just keep a commentary ready to say that: }
%
%% \commentary {
%% It is a compile-time error to override the \code{noSuchMethod} of class \code{Object} in such a way that it cannot be invoked with one positional argument of type \code{Invocation}.
%% }
\LMHash{} \LMHash{}
The value of the assignment expression is $o_2$ irrespective of whether setter lookup has failed or succeeded. The value of the assignment expression is $o_2$ irrespective of whether setter lookup has failed or succeeded.
\LMHash{}
It is a dynamic type error if $o_2$ is not the null object (\ref{null})
and the dynamic type of $o_2$ is
not a subtype of the actual type of $e_1.v$
(\ref{actualTypeOfADeclaration}).
\LMHash{}
Let $T$ be the static type of $e_1$.
It is a compile-time error if $T$ does not have an accessible instance setter named \code{$v$=}
%% TODO(eernst): This is metaclass stuff, should be deleted.
unless $T$ is \code{Type}, $e_1$ is a constant type literal and the class corresponding to $e_1$ has a static setter named \code{$v$=}.
\LMHash{} \LMHash{}
\Case{\code{\SUPER.$v$ = $e$}} \Case{\code{\SUPER.$v$ = $e$}}
Consider an assignment $a$ of the form \code{\SUPER.$v$ = $e$}. Consider an assignment $a$ of the form \code{\SUPER.$v$ = $e$}.
Let $S_{static}$ be the superclass of the immediately enclosing class. Let $S_{static}$ be the superclass of the immediately enclosing class.
It is a compile-time error if $S_{static}$ does not have an accessible instance setter named \code{$v$=}. It is a compile-time error if $S_{static}$ does not have a concrete accessible instance setter named \code{$v$=}.
Otherwise, it is a compile-time error if the static type of $e$ may not be assigned to the static type of the formal parameter of the setter \code{$v$=}. Otherwise, it is a compile-time error if the static type of $e$
may not be assigned to the static type of the formal parameter of said setter.
The static type of $a$ is the static type of $e$. The static type of $a$ is the static type of $e$.
\LMHash{} \LMHash{}
@ -7239,42 +7504,34 @@ Then, the setter \code{$v$=} is looked up (\ref{lookup}) in $S_{dynamic}$ with r
The body of \code{$v$=} is executed with its formal parameter bound to $o$ The body of \code{$v$=} is executed with its formal parameter bound to $o$
and \THIS{} bound to the current value of \THIS{}. and \THIS{} bound to the current value of \THIS{}.
\LMHash{} \commentary{
If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that: The setter lookup will not fail, because it is a compile-time error
\begin{itemize} when no concrete setter named \code{$v$=} exists in $S_{static}$.
\item \code{$im$.isSetter} evaluates to \code{\TRUE{}}. }
\item \code{$im$.memberName} evaluates to the symbol \code{v=}.
\item \code{$im$.positionalArguments} evaluates to an unmodifiable list
with the same values as \code{<Object>[$o$]}.
\item \code{$im$.namedArguments} evaluates to an empty unmodifiable instance of
\code{Map<Symbol, Object>}.
\item \code{$im$.typeArguments} evaluates to an empty, unmodifiable instance of
\code{List<Type>}.
\end{itemize}
\LMHash{} \LMHash{}
Then the method \code{noSuchMethod()} is looked up in $S_{dynamic}$ and invoked with argument $im$. The value of the assignment expression is $o$.
\LMHash{}
The value of the assignment expression is $o$ irrespective of whether setter lookup has failed or succeeded.
\LMHash{} \LMHash{}
It is a dynamic type error if $o$ is not the null object (\ref{null}) It is a dynamic type error if $o$ is not the null object (\ref{null})
and the dynamic type of $o$ is and the dynamic type of $o$ is
not a subtype of the actual type of \code{$S$.$v$} not a subtype of the actual type of the formal parameter of \code{$v$=}
(\ref{actualTypeOfADeclaration}). (\ref{actualTypeOfADeclaration}) in $S_{static}$.
\LMHash{} \LMHash{}
\Case{\code{$e_1$[$e_2$] = $e_3$}} \Case{\code{$e_1$[$e_2$] = $e_3$}}
Consider an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$}. Consider an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$}.
It is a compile-time error if the static type of $e_1$ does not have a method named \code{[]=}. Let $T$ be the static type of $e_1$.
Otherwise, let $S_2$ be the static type of the first formal parameter of the method \code{[]=} If $T$ is \DYNAMIC{}, no further checks are performed.
Otherwise, it is a compile-time error unless
$T$ has a method named \code{[]=}.
Let $S_2$ be the static type of the
first formal parameter of the method \code{[]=},
and $S_3$ the static type of the second. and $S_3$ the static type of the second.
It is a compile-time error if the static type of $e_2$ may not be assigned to $S_2$, It is a compile-time error unless the static type of $e_2$ respectively $e_3$
and if the static type of $e_3$ may not be assigned to $S_3$. may be assigned to $S_2$ respectively $S_3$.
The static type of $a$ is the static type of $e_3$. Whether or not $T$ is \DYNAMIC{},
the static type of $a$ is the static type of $e_3$.
\LMHash{} \LMHash{}
Evaluation of an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$} Evaluation of an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$}
@ -7289,10 +7546,11 @@ Then $a$ evaluates to $v$.
Consider an assignment $a$ of the form \code{\SUPER[$e_1$] = $e_2$}. Consider an assignment $a$ of the form \code{\SUPER[$e_1$] = $e_2$}.
Let $S_{static}$ be the superclass of the immediately enclosing class. Let $S_{static}$ be the superclass of the immediately enclosing class.
It is a compile-time error if $S_{static}$ does not have a method \code{[]=}. It is a compile-time error if $S_{static}$ does not have a method \code{[]=}.
Otherwise, let $S_1$ be the static type of the first formal parameter of the method \code{[]=} Otherwise, let $S_1$ be the static type of the
first formal parameter of the method \code{[]=},
and $S_2$ the static type of the second. and $S_2$ the static type of the second.
It is a compile-time error if the static type of $e_1$ may not be assigned to $S_1$, It is a compile-time error if the static type of $e_1$ respectively $e_2$
and if the static type of $e_2$ may not be assigned to $S_2$. may not be assigned to $S_1$ respectively $S_2$.
The static type of $a$ is the static type of $e_2$. The static type of $a$ is the static type of $e_2$.
\LMHash{} \LMHash{}

View file

@ -2,7 +2,7 @@
Author: eernst@ Author: eernst@
**Status**: Implemented. **Status**: Background material, normative language now in dartLangSpec.tex.
**Version**: 0.7 (2018-07-10) **Version**: 0.7 (2018-07-10)