blob: 7e381b9a3b14708c50da22c0616408a6b4101670 [file] [log] [blame]
\documentclass{article}
\usepackage{xspace}
\usepackage{epsfig}
\usepackage{color}
\usepackage{syntax}
\usepackage{dart}
\usepackage{hyperref}
\usepackage{lmodern}
\usepackage[T1]{fontenc}
\title{Dart Programming Language Specification\\
{5th edition draft}\\
{\large Version 2.1.0-dev}}
\author{}
% For information about Location Markers (and in particular the
% commands \LMHash and \LMLabel), see the long comment at the
% end of this file.
% CHANGES
% =======
% Significant changes to the specification.
%
% 2.1
% - Remove 64-bit constraint on integer literals compiled to JavaScript numbers.
% - Allow integer literals in a double context to evaluate to a double value.
% - Specify dynamic error for a failing downcast in redirecting factory
% constructor invocation.
% - Specify that type arguments passed in a redirecting factory constructor
% declaration must be taken into account during static checks.
% - Disallow any expression statement starting with `{`, not just
% those that are map literals.
% - Define a notion of lookup that is needed for super invocations, adjust
% specification of super invocations accordingly.
% - Specify that it is a dynamic error to initialize a non-static variable
% with a value that does not have the declared type (e.g., a failed cast).
% - Specify for constructor initializers that target variable must exist and
% the initializing expression must have a type which is assignable to its
% type.
% - Specify for superinitializers that the target constructor must exist and
% the argument part must have a matching shape and pass type and value
% arguments satisfying the relevant constraints.
% - Reword rules about abstract methods and inheritance to use 'class
% interface'.
% - Specify that it is an error for a concrete class with no non-trivial
% \code{noSuchMethod} to not have a concrete declaration for some member
% in its interface, or to have one which is not a correct override.
% - Use \ref{bindingActualsToFormals} in 3 locations, eliminating 2 extra
% copies of nearly the same text.
% - Add figure in \ref{bindingActualsToFormals} for improved readability.
% - Introduce a notion of lookup which is needed for superinvocations.
% - Use new lookup concept to simplify specification of getter, setter, method
% lookup.
% - Introduce several `Case<SomeTopic>` markers in order to improve
% readability.
% - Reorganize several sections to specify static analysis first and then
% dynamic semantics; clarify many details along the way. The sections are:
% \ref{variables}, \ref{new}, \ref{const}, \ref{bindingActualsToFormals},
% \ref{unqualifiedInvocation}, \ref{functionExpressionInvocation},
% \ref{superInvocations}, \ref{assignment}, \ref{compoundAssignment},
% \ref{localVariableDeclaration}, and \ref{return}.
% - Corrected error involving multiple uses of the same part in the same
% program such that it takes exports into account.
% - Eliminate all references to checked and production mode, Dart 2 does
% not have modes.
% - Integrate feature specification on noSuchMethod forwarders.
%
% 2.0
% - Don't allow functions as assert test values.
% - Start running "async" functions synchronously.
% - It is a static warning and dynamic error to assign to a final local.
% - Specify what "is equivalent to" means.
% - Remove @proxy.
% - Don't specify the exact object used for empty positionalArguments and
% namedArguments on Invocation.
% - Remove the, now unnecessary, handling of invalid overrides of noSuchMethod.
% - Add >>> as overridable operator.
% - If initializing formal has type annotation, require subtype of field type.
% - Constant `==` operations now also allowed if just one operand is null.
% - Make flatten not be recursive.
% - Disallow implementing two instantiations of the same generic interface.
% - Update "FutureOr" specification for Dart 2.0.
% - Require that a top-level "main" declaration is a valid script-entry
% function declaration.
% - State that the return type of a setter or []= is void when not specified.
% - Clarify that "noSuchMethod" must be implemented, not just redeclared
% abstractly, to eliminate certain diagnostic messages.
% - Add generic functions and methods to the language.
% - Don't cause warning if a non-system library import shadows a system library.
% - Update mixin application forwarding constructors to correctly handle
% optional parameters and const constructors.
% - Specify `call` for Dart 2 (no function type given to enclosing class).
% - Clarify that an identifier reference denoting a top-level, static, or
% local function evaluates to the closurization of that declaration.
% - Make `mixin` and `interface` built-in identifiers.
% - Make `async` *not* a reserved word inside async functions.
% - Add 'Class Member Conflicts', simplifying and adjusting rules about
% member declaration conflicts beyond "`n` declared twice in one scope".
% - Specify that integer literals are limited to signed 64-bit values,
% and that the `int` class is intended as signed 64-bit integer, but
% that platforms may differ.
% - Specify variance and super-bounded types.
% - Introduce `subterm` and `immediate subterm`.
% - Introduce `top type`.
% - Specify configurable imports.
% - Specify the dynamic type of the Iterable/Future/Stream returned from
% invocations of functions marked sync*/async/async*.
% - Add appendix listing the major differences between 64-bit integers
% and JavaScript integers.
% - Remove appendix on naming conventions.
% - Make it explicit that "dynamic" is exported from dart:core.
% - Remove "boolean conversion". It's just an error to not be a bool.
% - Adjust cyclic subtype prevention rule for type variables.
% - Clarify that it is an error to use FutureOr<T> as a superinterface etc.
% - Eliminate the notion of static warnings, all program faults are now errors.
% - It is no longer an error for a getter to have return type `void`.
% - Specify that each redirection of a constructor is checked, statically and
% dynamically.
% - Specify that it is an error for a superinitializer to occur anywhere else
% than at the end of an initializer list.
% - Update the potentially/compile-time constant expression definitions
% so that "potentially constant" depends only on the grammar, not the types
% of sub-expressions.
% - Make `==` recognize `null` and make `&&` and `||` short-circuit in constant
% expressions.
% - Add `as` and `is` expressions as constant expressions
% - Make `^`, `|` and `&` operations on `bool` constant operations.
%
% 1.15
% - Change how language specification describes control flow.
% - Object initialization now specifies initialization order correctly.
% - Specifies that leaving an await-for loop must wait for the subscription
% to be canceled.
% - An await-for loop only pauses the subscription if it does something async.
% - Assert statements allows a "message" operand and a trailing comma.
% - The Null type is now considered a subtype of all types in most cases.
% - Specify what NEWLINE means in multiline strings.
% - Specified the FutureOf type.
% - Asserts can occur in initializer lists.
%
% 1.14
% - The call "C()" where "C" is a class name, is a now compile-time error.
% - Changed description of rewrites that depended on a function literal.
% In many cases, the rewrite wasn't safe for asynchronous code.
% - Removed generalized tear-offs.
% - Allow "rethrow" to also end a switch case. Allow braces around switch cases.
% - Allow using '=' as default-value separator for named parameters.
% - Make it a compile-time error if a library includes the same part twice.
% - Now more specific about the return types of sync*/async/async* functions
% in relation to return statements.
% - Allow Unicode surrogate values in String literals.
% - Make an initializing formal's value accessible in the initializer list.
% - Allow any expression in assert statements (was only conditionalExpression).
% - Allow trailing commas in argument and parameter lists.
%
% 1.11 - ECMA 408 - 4th Edition
% - Specify that potentially constant expressions must be valid expressions
% if the parameters are non-constant.
% - Make "??" a compile-time constant operator.
% - Having multiple unnamed libraries no longer causes warnings.
% - Specify null-aware operators for static methods.
%
% 1.10
% - Allow mixins to have super-classes and super-calls.
% - Specify static type checking for the implicit for-in iterator variable.
% - Specify static types for a number of expressions where it was missing.
% - Make calls on the exact type "Function" not cause warnings.
% - Specify null-aware behavior of "e?.v++" and similar expressions.
% - Specify that `package:` URIs are treated in an implementation dependent way.
% - Require warning if for-in is used on object with no "iterator" member.
%
% 1.9 - ECMA-408 - 3rd Edition
%
\begin{document}
\maketitle
\tableofcontents
\newpage
\pagestyle{myheadings}
\markright{Dart Programming Language Specification}
% begin Ecma boilerplate
\section{Scope}
\LMLabel{ecmaScope}
\LMHash{}
This Ecma standard specifies the syntax and semantics of the Dart programming language.
It does not specify the APIs of the Dart libraries except where those library elements are essential to the correct functioning of the language itself (e.g., the existence of class \code{Object} with methods such as \code{noSuchMethod}, \code{runtimeType}).
\section{Conformance}
\LMLabel{ecmaConformance}
\LMHash{}
A conforming implementation of the Dart programming language must provide and support all the APIs (libraries, types, functions, getters, setters, whether top-level, static, instance or local) mandated in this specification.
\LMHash{}
A conforming implementation is permitted to provide additional APIs, but not additional syntax, except for experimental features in support of null-aware cascades that are likely to be introduced in the next revision of this specification.
\section{Normative References}
\LMLabel{ecmaNormativeReferences}
\LMHash{}
The following referenced documents are indispensable for the application of this document.
For dated references, only the edition cited applies.
For undated references, the latest edition of the referenced document (including any amendments) applies.
\begin{enumerate}
\item
The Unicode Standard, Version 5.0, as amended by Unicode 5.1.0, or successor.
\item
Dart API Reference, https://api.dartlang.org/
\end{enumerate}
\section{Terms and Definitions}
\LMLabel{ecmaTermsAndDefinitions}
\LMHash{}
Terms and definitions used in this specification are given in the body of the specification proper.
Such terms are highlighted in italics when they are introduced, e.g., `we use the term {\em verbosity} to refer to the property of excess verbiage'.
% End Ecma Boilerplate
\section{Notation}
\LMLabel{notation}
\LMHash{}
We distinguish between normative and non-normative text.
Normative text defines the rules of Dart.
It is given in this font.
At this time, non-normative text includes:
\begin{itemize}
\item[Rationale]
Discussion of the motivation for language design decisions appears in italics.
\rationale{
Distinguishing normative from non-normative helps clarify what part of the text is binding and what part is merely expository.
}
\item[Commentary]
Comments such as ``\commentary{The careful reader will have noticed that the name Dart has four characters}'' serve to illustrate or clarify the specification, but are redundant with the normative text.
\commentary{
The difference between commentary and rationale can be subtle.
}
\rationale{
Commentary is more general than rationale, and may include illustrative examples or clarifications.
}
\item[Open questions] (\Q{in this font}).
Open questions are points that are unsettled in the mind of the author(s) of the specification; expect them (the questions, not the authors; precision is important in a specification) to be eliminated in the final specification.
\Q{Should the text at the end of the previous bullet be rationale or commentary?}
\end{itemize}
\LMHash{}
Reserved words and built-in identifiers (\ref{identifierReference}) appear in {\bf bold}.
\commentary{
Examples would be \SWITCH{} or \CLASS{}.
}
\LMHash{}
Grammar productions are given in a common variant of EBNF.
The left hand side of a production ends with a colon.
On the right hand side, alternation is represented by vertical bars, and sequencing by spacing.
As in PEGs, alternation gives priority to the left.
Optional elements of a production are suffixed by a question mark like so: \code{anElephant?}.
Appending a star to an element of a production means it may be repeated zero or more times.
Appending a plus sign to a production means it occurs one or more times.
Parentheses are used for grouping.
Negation is represented by prefixing an element of a production with a tilde.
Negation is similar to the not combinator of PEGs, but it consumes input if it matches.
In the context of a lexical production it consumes a single character if there is one; otherwise, a single token if there is one.
\commentary{
An example would be:
}
\begin{grammar}
<aProduction> ::= <anAlternative>
\alt <anotherAlternative>
\alt <oneThing> <after> <another>
\alt <zeroOrMoreThings>*
\alt <oneOrMoreThings>+
\alt <anOptionalThing>?
\alt (<some> <grouped> <things>)
\alt \~{}<notAThing>
\alt `aTerminal'
\alt <A\_LEXICAL\_THING>
\end{grammar}
\LMHash{}
Both syntactic and lexical productions are represented this way.
Lexical productions are distinguished by their names.
The names of lexical productions consist exclusively of upper case characters and underscores.
As always, within grammatical productions, whitespace and comments between elements of the production are implicitly ignored unless stated otherwise.
Punctuation tokens appear in quotes.
\LMHash{}
Productions are embedded, as much as possible, in the discussion of the constructs they represent.
\LMHash{}
A {\em term} is a syntactic construct.
It may be considered to be a piece of text which is derivable in the grammar,
and it may be considered to be a tree created by such a derivation.
An {\em immediate subterm} of a given term $t$ is a syntactic construct
which corresponds to an immediate subtree of $t$ considered as a derivation tree.
A {\em subterm} of a given term $t$ is $t$,
or an immediate subterm of $t$,
or a subterm of an immediate subterm of $t$.
\LMHash{}
A list $x_1, \ldots, x_n$ denotes any list of $n$ elements of the form $x_i, 1 \le i \le n$.
Note that $n$ may be zero, in which case the list is empty.
We use such lists extensively throughout this specification.
\LMHash{}
For $j \in 1 .. n$,
let $y_j$ be an atomic syntactic entity (like an identifier),
$x_j$ a composite syntactic entity (like an expression or a type),
and $E$ again a composite syntactic entity.
The notation $[x_1/y_1, \ldots, x_n/y_n]E$ then denotes a copy of $E$
in which each occurrence of $y_i, 1 \le i \le n$ has been replaced by $x_i$.
\LMHash{}
This operation is also known as substitution, and it is the variant that avoids capture.
That is, when $E$ contains a construct that introduces $y_i$ into a nested scope for some $i \in 1 .. n$,
the substitution will not replace $y_i$ in that scope.
Conversely, if such a replacement would put an identifier \id{} (a subterm of $x_i$) into a scope where \id{} is declared,
the relevant declarations in $E$ are systematically renamed to fresh names.
\commentary{
In short, capture freedom ensures that the ``meaning'' of each identifier is preserved during substitution.
}
\LMHash{}
We sometimes abuse list or map literal syntax, writing $[o_1, \ldots, o_n]$ (respectively $\{k_1: o_1, \ldots, k_n: o_n\}$) where the $o_i$ and $k_i$ may be objects rather than expressions.
The intent is to denote a list (respectively map) object whose elements are the $o_i$ (respectively, whose keys are the $k_i$ and values are the $o_i$).
\LMHash{}
The specifications of operators often involve statements such as $x$ $op$ $y$ is equivalent to the method invocation $x.op(y)$.
Such specifications should be understood as a shorthand for:
\begin{itemize}
\item
$x$ $op$ $y$ is equivalent to the method invocation $x.op'(y)$, assuming the class of $x$ actually declared a non-operator method named $op'$ defining the same function as the operator $op$.
\end{itemize}
\rationale{
This circumlocution is required because x.op(y), where op is an operator, is not legal syntax.
However, it is painfully verbose, and we prefer to state this rule once here, and use a concise and clear notation across the specification.
}
\LMHash{}
When the specification refers to the order given in the program, it means the order of the program source code text, scanning left-to-right and top-to-bottom.
\LMHash{}
When the specification refers to a {\em fresh variable}, it means a variable with a name that doesn't occur anywhere in the current program.
When the specification introduces a fresh variable bound to a value, the fresh variable is implicitly bound in a surrounding scope.
\LMHash{}
References to otherwise unspecified names of program entities (such as classes or functions) are interpreted as the names of members of the Dart core library.
\commentary{
Examples would be the classes \code{Object} and \code{Type} representing the root of the class hierarchy and the reification of run-time types respectively.
}
\LMHash{}
When the specification says that one piece of syntax {\em is equivalent to} another piece of syntax, it means that it is equivalent in all ways, and the former syntax should generate the same compile-time errors and have the same run-time behavior as the latter, if any.
\commentary{
Error messages, if any, should always refer to the original syntax.
}
If execution or evaluation of a construct is said to be equivalent to execution or evaluation of another construct, then only the run-time behavior is equivalent, and compile-time errors apply only for the original syntax.
\section{Overview}
\LMLabel{overview}
\LMHash{}
Dart is a class-based, single-inheritance, pure object-oriented programming language.
Dart is optionally typed (\ref{types}) and supports reified generics.
The run-time type of every object is represented as an instance of class \code{Type} which can be obtained by calling the getter \code{runtimeType} declared in class \code{Object}, the root of the Dart class hierarchy.
\LMHash{}
Dart programs may be statically checked.
Programs with compile-time errors do not have a specified dynamic semantics.
This specification makes no attempt to answer additional questions
about a library or program at the point
where it is known to have a compile-time error.
\commentary{
However, tools may choose to support execution of some programs with errors.
For instance, a compiler may compile certain constructs with errors such that
a dynamic error will be raised if an attempt is made to
execute such a construct,
or an IDE integrated runtime may support opening
an editor window when such a construct is executed,
allowing developers to correct the error.
It is expected that such features would amount to a natural extension of the
dynamic semantics of Dart as specified here, but, as mentioned,
this specification makes no attempt to specify exactly what that means.
}
\LMHash{}
As specified in this document,
dynamic checks are guaranteed to be performed in certain situations,
and certain violations of the type system throw exceptions at run time.
\commentary{
An implementation is free to omit such checks whenever they are
guaranteed to succeed, e.g., based on results from the static analysis.
}
\commentary{
The coexistence between optional typing and reification is based on the following:
\begin{enumerate}
\item
Reified type information reflects the types of objects at run time
and may always be queried by dynamic typechecking constructs
(the analogs of instanceOf, casts, typecase etc.\ in other languages).
Reified type information includes
access to instances of class \code{Type} representing types,
the run-time type (aka class) of an object,
and the actual values of type parameters
to constructors and generic function invocations.
\item
Type annotations declare the types of
variables and functions (including methods and constructors).
\item
%% TODO(eernst): Change when integrating instantiate-to-bounds.md.
Type annotations may be omitted, in which case they are generally
filled in with the type \DYNAMIC{}
(\ref{typeDynamic}).
\end{enumerate}
}
%% TODO(eernst): Update when we add inference.
\commentary{
Dart as implemented includes extensive support for inference of omitted types.
This specification makes the assumption that inference has taken place,
and hence inferred types are considered to be present in the program already.
However, in some cases no information is available
to infer an omitted type annotation,
and hence this specification still needs to specify how to deal with that.
A future version of this specification will also specify type inference.
}
\LMHash{}
Dart programs are organized in a modular fashion into units called {\em libraries} (\ref{librariesAndScripts}).
Libraries are units of encapsulation and may be mutually recursive.
\commentary{
However they are not first class.
To get multiple copies of a library running simultaneously, one needs to spawn an isolate.
}
\LMHash{}
A dart program execution may occur with assertions enabled or disabled.
The method used to enable or disable assertions is implementation specific.
\subsection{Scoping}
\LMLabel{scoping}
\LMHash{}
A {\em namespace} is a mapping of names denoting declarations to actual declarations.
Let $NS$ be a namespace.
We say that a name $n$ {\em is in }$NS$ if $n$ is a key of $NS$.
We say a declaration $d$ {\em is in }$NS$ if a key of $NS$ maps to $d$.
\LMHash{}
A scope $S_0$ induces a namespace $NS_0$ that maps the simple name of each variable, type or function declaration $d$ declared in $S_0$ to $d$.
Labels are not included in the induced namespace of a scope; instead they have their own dedicated namespace.
\commentary{
It is therefore impossible, e.g., to define a class that declares a method and a getter with the same name in Dart.
Similarly one cannot declare a top-level function with the same name as a library variable or a class.
}
\LMHash{}
It is a compile-time error if there is more than one entity with the same name declared in the same scope.
\commentary{
In some cases, the name of the declaration differs from the identifier used to declare it.
Setters have names that are distinct from the corresponding getters because they always have an = automatically added at the end, and unary minus has the special name unary-.
}
\LMHash{}
Dart is lexically scoped.
Scopes may nest.
A name or declaration $d$ is {\em available in scope} $S$ if $d$ is in the namespace induced by $S$ or if $d$ is available in the lexically enclosing scope of $S$.
We say that a name or declaration $d$ is {\em in scope} if $d$ is available in the current scope.
\LMHash{}
If a declaration $d$ named $n$ is in the namespace induced by a scope $S$, then $d$ {\em hides} any declaration named $n$ that is available in the lexically enclosing scope of $S$.
\commentary{
A consequence of these rules is that it is possible to hide a type with a method or variable.
Naming conventions usually prevent such abuses.
Nevertheless, the following program is legal:
}
\begin{dartCode}
\CLASS{} HighlyStrung \{
String() => "?";
\}
\end{dartCode}
\LMHash{}
Names may be introduced into a scope by declarations within the scope or by other mechanisms such as imports or inheritance.
\rationale{
The interaction of lexical scoping and inheritance is a subtle one.
Ultimately, the question is whether lexical scoping takes precedence over inheritance or vice versa.
Dart chooses the former.
Allowing inherited names to take precedence over locally declared names could create unexpected situations as code evolves.
Specifically, the behavior of code in a subclass could silently change if a new name is introduced in a superclass.
Consider:
}
\begin{dartCode}
\LIBRARY{} L1;
\CLASS{} S \{\}
\LIBRARY{} L2;
\IMPORT{} `L1.dart';
foo() => 42;
\CLASS{} C \EXTENDS{} S\{ bar() => foo();\}
\end{dartCode}
\rationale{
Now assume a method \code{foo()} is added to \code{S}.
}
\begin{dartCode}
\LIBRARY{} L1;
\CLASS{} S \{foo() => 91;\}
\end{dartCode}
\rationale{
If inheritance took precedence over the lexical scope, the behavior of \code{C} would change in an unexpected way.
Neither the author of \code{S} nor the author of \code{C} are necessarily aware of this.
In Dart, if there is a lexically visible method \code{foo()}, it will always be called.
Now consider the opposite scenario.
We start with a version of \code{S} that contains \code{foo()}, but do not declare \code{foo()} in library \code{L2}.
Again, there is a change in behavior - but the author of \code{L2} is the one who introduced the discrepancy that effects their code, and the new code is lexically visible.
Both these factors make it more likely that the problem will be detected.
These considerations become even more important if one introduces constructs such as nested classes, which might be considered in future versions of the language.
Good tooling should of course endeavor to inform programmers of such situations (discreetly).
For example, an identifier that is both inherited and lexically visible could be highlighted (via underlining or colorization).
Better yet, tight integration of source control with language aware tools would detect such changes when they occur.
}
\subsection{Privacy}
\LMLabel{privacy}
\LMHash{}
Dart supports two levels of privacy: {\em public} and {\em private}.
A declaration is {\em private} if{}f its name is private, otherwise it is {\em public}.
A name $q$ is private if{}f any one of the identifiers that comprise $q$ is private, otherwise it is {\em public}.
An identifier is private if{}f it begins with an underscore (the \_ character) otherwise it is {\em public}.
\LMHash{}
A declaration $m$ is {\em accessible to library $L$} if $m$ is declared in $L$ or if $m$ is public.
\commentary{
This means private declarations may only be accessed within the library in which they are declared.
}
\LMHash{}
Privacy applies only to declarations within a library, not to library declarations themselves.
\rationale{
Libraries do not reference each other by name and so the idea of a private library is meaningless.
Thus, if the name of a library begins with an underscore, it has no effect on the accessibility of the library or its members.
}
\rationale{
Privacy is, at this point, a static notion tied to a particular piece of code (a library).
It is designed to support software engineering concerns rather than security concerns.
Untrusted code should always run in an another isolate.
It is possible that libraries will become first class objects and privacy will be a dynamic notion tied to a library instance.
Privacy is indicated by the name of a declaration - hence privacy and naming are not orthogonal.
This has the advantage that both humans and machines can recognize access to private declarations at the point of use without knowledge of the context from which the declaration is derived.
}
\subsection{Concurrency}
\LMLabel{concurrency}
\LMHash{}
Dart code is always single threaded.
There is no shared-state concurrency in Dart.
Concurrency is supported via actor-like entities called {\em isolates}.
\LMHash{}
An isolate is a unit of concurrency.
It has its own memory and its own thread of control.
Isolates communicate by message passing (\ref{sendingMessages}).
No state is ever shared between isolates.
Isolates are created by spawning (\ref{spawningAnIsolate}).
\section{Errors and Warnings}
\LMLabel{errorsAndWarnings}
\LMHash{}
This specification distinguishes between several kinds of errors.
\LMHash{}
{\em Compile-time errors} are errors that preclude execution.
A compile-time error must be reported by a Dart compiler before the erroneous code is executed.
\rationale{
A Dart implementation has considerable freedom as to when compilation takes place.
Modern programming language implementations often interleave compilation and execution, so that compilation of a method may be delayed, e.g., until it is first invoked.
Consequently, compile-time errors in a method $m$ may be reported as late as the time of $m$'s first invocation.
Dart is often loaded directly from source, with no intermediate binary representation.
In the interests of rapid loading, Dart implementations may choose to avoid full parsing of method bodies, for example.
This can be done by tokenizing the input and checking for balanced curly braces on method body entry.
In such an implementation, even syntax errors will be detected only when the method needs to be executed, at which time it will be compiled (JITed).
In a development environment a compiler should of course report compilation errors eagerly so as to best serve the programmer.
A Dart development environment might choose to support error eliminating program transformations, e.g.,
replacing an erroneous expression by the invocation of a debugger.
It is outside the scope of this document to specify how such transformations work, and where they may be applied.
}
\LMHash{}
If an uncaught compile-time error occurs within the code of a running isolate $A$, $A$ is immediately suspended.
The only circumstance where a compile-time error could be caught would be via code run reflectively, where the mirror system can catch it.
\rationale{
Typically, once a compile-time error is thrown and $A$ is suspended, $A$ will then be terminated.
However, this depends on the overall environment.
A Dart engine runs in the context of an {\em embedder},
a program that interfaces between the engine and the surrounding computing environment.
The embedder will often be a web browser, but need not be; it may be a C++ program on the server for example.
When an isolate fails with a compile-time error as described above, control returns to the embedder, along with an exception describing the problem.
This is necessary so that the embedder can clean up resources etc.
It is then the embedder's decision whether to terminate the isolate or not.
}
\LMHash{}
{\em Compile-time warnings} are situations that do not preclude execution,
but which are unlikely to be intended,
and likely to cause bugs or inconveniences.
A compile-time warning must be reported by a Dart compiler before the associated code is executed.
\LMHash{}
When this specification says that a {\em run-time error} occurs,
it means that a corresponding error object is thrown.
When it says that a {\em dynamic type error} occurs,
it represents a failed run-time type check,
and the object which is thrown implements \code{TypeError}.
\LMHash{}
Whenever we say that an exception $ex$ is {\em thrown},
it acts like an expression had {\em thrown} (\ref{completion}) with $ex$ as exception object and with a stack trace corresponding to the current system state.
When we say that {\em a} $C$ {\em is thrown}, where $C$ is a class, we mean that an instance of class $C$ is thrown.
\LMHash{}
If an uncaught exception is thrown by a running isolate $A$, $A$ is immediately suspended.
\section{Variables}
\LMLabel{variables}
\LMHash{}
Variables are storage locations in memory.
\begin{grammar}
<variableDeclaration> ::= <declaredIdentifier> (`,' <identifier>)*
<declaredIdentifier> ::= <metadata> <finalConstVarOrType> <identifier>
<finalConstVarOrType> ::= \FINAL{} <type>?
\alt \CONST{} <type>?
\alt <varOrType>
<varOrType> ::= \VAR{}
\alt <type>
<initializedVariableDeclaration> ::=
<declaredIdentifier> (`=' <expression>)? (`,' <initializedIdentifier>)*
<initializedIdentifier> ::= <identifier> (`=' <expression>)?
<initializedIdentifierList> ::= <initializedIdentifier> (`,' <initializedIdentifier>)*
\end{grammar}
\LMHash{}
A variable declaration that contains one or more terms of the form
\syntax{<identifier>}
(\commentary{i.e., a declaration that declares two or more variables})
is equivalent to multiple variable declarations declaring
the same set of variable names in the same order,
with the same type and modifiers.
\LMHash{}
An \syntax{<initializedVariableDeclaration>} that contains one or more terms of the form
\syntax{<initializedIdentifier>}
(\commentary{that is, a declaration that declares two or more initialized variables})
is equivalent to multiple variable declarations declaring
the same set of variable names, in the same order,
with the same initialization, type, and modifiers.
\commentary{
For example,
\code{\VAR{} x, y;}
is equivalent to
\code{\VAR{} x; \VAR{} y;}
and
\code{\STATIC{} \FINAL{} String s1, s2 = "foo";}
is equivalent to
\code{\STATIC{} \FINAL{} String s1; \STATIC{} \FINAL{} String s2 = "foo";}.
}
\LMHash{}
In a variable declaration of one of the forms
\code{$N$ $v$;}
\code{$N$ $v$ = $e$;}
where $N$ is derived from
\syntax{<metadata> <finalConstVarOrType>},
we say that $v$ is the {\em declaring occurrence} of the identifier.
For every identifier which is not a declaring occurrence,
we say that it is an {\em referencing occurrence}.
We also abbreviate that to say that an identifier is
a {\em declaring identifier} respectively an {\em referencing identifier}.
\commentary{
In an expression of the form \code{$e$.\id} it is possible that
$e$ has static type \DYNAMIC{} and \id{} cannot be associated with
any declaration named \id{} at compile-time,
but in this situation \id{} is still a referencing identifier.
}
\LMHash{}
An {\em initializing variable declaration}
is a variable declaration whose declaring identifier is
immediately followed by `\code{=}' and an {\em initializing expression}.
\LMHash{}
A variable declared at the top-level of a library is referred to as either a {\em library variable} or a top-level variable.
\LMHash{}
A {\em static variable} is a variable that is not associated with a particular instance, but rather with an entire library or class.
Static variables include library variables and class variables.
Class variables are variables whose declaration is immediately nested inside a class declaration and includes the modifier \STATIC{}.
A library variable is implicitly static.
It is a compile-time error to preface a top-level variable declaration with the built-in identifier (\ref{identifierReference}) \STATIC{}.
\LMHash{}
A {\em constant variable} is a variable whose declaration includes the modifier \CONST{}.
A constant variable must be initialized to a constant expression (\ref{constants}) or a compile-time error occurs.
\LMHash{}
A {\em final variable} is a variable whose binding is fixed upon initialization;
a final variable $v$ will always refer to the same object after $v$ has been initialized.
A variable is final if{}f its declaration includes the modifier \FINAL{} or the modifier \CONST{}.
\LMHash{}
A {\em mutable variable} is a variable which is not final.
%% Note that the following relies on the assumption that inference has
%% already taken place, including member signature inference. For instance,
%% if `var x;` is an instance variable declaration that overrides `T get x;`
%% then we treat `var x;` as if it had been `T x;`.
\LMHash{}
The following rules apply to all static and instance variables.
\LMHash{}
A variable declaration of one of the forms
\code{$T$ $v$;}
\code{$T$ $v$ = $e$;}
\code{\CONST{} $T$ $v$ = $e$;}
\code{\FINAL{} $T$ $v$;}
or \code{\FINAL{} $T$ $v$ = $e$;}
induces an implicit getter function (\ref{getters}) with signature
\code{$T$ \GET{} $v$}
whose invocation evaluates as described below
(\ref{evaluationOfImplicitVariableGetters}).
In these cases the static type of $v$ is $T$.
\LMHash{}
A variable declaration of one of the forms
\code{\VAR{} $v$;}
\code{\VAR{} $v$ = $e$;}
\code{\CONST{} $v$ = $e$;}
\code{\FINAL{} $v$;}
or \code{\FINAL{} $v$ = $e$;}
induces an implicit getter function with signature
\code{\DYNAMIC{} \GET{} $v$}
whose invocation evaluates as described below
(\ref{evaluationOfImplicitVariableGetters}).
%% TODO[inference]: We assume inference has taken place, i.e., inferred types
%% are written explicitly. Does this mean that the initialized variants
%% cannot exist (not even for `$e$` of type `dynamic`?). We probably don't
%% want to start talking about a grammar before inference and another one
%% after inference.
In these cases, the static type of $v$ is \DYNAMIC{}
(\ref{typeDynamic}).
\LMHash{}
A mutable variable declaration of the form
\code{{} $T$ $v$;}
or \code{$T$ $v$ = $e$;}
induces an implicit setter function (\ref{setters}) with signature
\code{\VOID{} \SET{} $v$=($T$ $x$)}
whose execution sets the value of $v$ to the incoming argument $x$.
\LMHash{}
A mutable variable declaration of the form
\code{\VAR{} $v$;}
or \code{\VAR{} $v$ = $e$;}
induces an implicit setter function with signature
\code{\VOID{} \SET{} $v$=(\DYNAMIC{} $x$)}
whose execution sets the value of $v$ to the incoming argument $x$.
\LMHash{}
The scope into which the implicit getters and setters are introduced depends on the kind of variable declaration involved.
\LMHash{}
A library variable introduces a getter into the top level scope of the enclosing library.
A static class variable introduces a static getter into the immediately enclosing class.
An instance variable introduces an instance getter into the immediately enclosing class.
\LMHash{}
A mutable library variable introduces a setter into the top level scope of the enclosing library.
A mutable static class variable introduces a static setter into the immediately enclosing class.
A mutable instance variable introduces an instance setter into the immediately enclosing class.
\LMHash{}
Let $v$ be variable declared in an initializing variable declaration,
and let $e$ be the associated initializing expression.
It is a compile-time error if the static type of $e$ is not assignable to the declared type of $v$.
It is a compile-time error if a final instance variable whose declaration has an initializer expression
is also initialized by a constructor, either by an initializing formal or an initializer list entry.
\commentary{
It is a compile-time error if a final instance variable
that has been initialized by means of an initializing formal of a constructor $k$
is also initialized in the initializer list of $k$ (\ref{initializerLists}).
A static final variable $v$ does not induce a setter,
so unless a setter named \code{$v$=} is in scope
it is a compile-time error to assign to $v$.
Similarly, assignment to a final instance variable $v$
is a compile-time error,
unless a setter named \code{$v$=} is in scope,
or the receiver has type \DYNAMIC{}.
$v$ can be initialized in its declaration or in initializer lists,
but initialization and assignment is not the same thing.
When the receiver has type \DYNAMIC{}
such an assignment is not a compile-time error,
but if there is no setter it will cause a dynamic error.
}
\LMHash{}
A variable that has no initializing expression has the null object (\ref{null}) as its initial value.
Otherwise, variable initialization proceeds as follows:
\LMHash{}
Static variable declarations with an initializing expression are initialized lazily
(\ref{evaluationOfImplicitVariableGetters}).
\rationale{
The lazy semantics are given because we do not want a language where one tends to define expensive initialization computations, causing long application startup times.
This is especially crucial for Dart, which must support the coding of client applications.
}
\commentary{
Initialization of an instance variable with no initializing expression
takes place during constructor execution
(\ref{initializerLists}).
}
\LMHash{}
Initialization of an instance variable $v$
with an initializing expression $e$
proceeds as follows:
$e$ is evaluated to an object $o$
and the variable $v$ is bound to $o$.
\commentary{
It is specified elsewhere when this initialization occurs,
and in which environment
(p.\,\pageref{executionOfGenerativeConstructors},
\ref{localVariableDeclaration},
\ref{bindingActualsToFormals}).
}
\commentary{
If the initializing expression throws then
access to the uninitialized variable is prevented,
because the instance creation
that caused this initialization to take place
will throw.
}
\LMHash{}
It is a dynamic type error if $o$ is not the null object (\ref{null})
and the dynamic type of $o$ is not
a subtype of the actual type of the variable $v$
(\ref{actualTypeOfADeclaration}).
\subsection{Evaluation of Implicit Variable Getters}
\LMLabel{evaluationOfImplicitVariableGetters}
\LMHash{}
Let $d$ be the declaration of a static or instance variable $v$.
If $d$ is an instance variable,
then the invocation of the implicit getter of $v$ evaluates to
the value stored in $v$.
If $d$ is a static variable
(\commentary{which can be a library variable})
then the implicit getter method of $v$ executes as follows:
\begin{itemize}
\item {\bf Non-constant variable declaration with initializer}.
If $d$ is of one of the forms
\code{\VAR{} $v$ = $e$;},
\code{$T$ $v$ = $e$;},
\code{\FINAL{} $v$ = $e$;},
\code{\FINAL{} $T$ $v$ = $e$;},
\code{\STATIC{} $v$ = $e$;},
\code{\STATIC{} $T$ $v$ = $e$; },
\code{\STATIC{} \FINAL{} $v$ = $e$; } or
\code{\STATIC{} \FINAL{} $T$ $v$ = $e$;}
and no value has yet been stored into $v$
then the initializing expression $e$ is evaluated.
If, during the evaluation of $e$, the getter for $v$ is invoked,
a \code{CyclicInitializationError} is thrown.
If the evaluation of $e$ throws an exception $e$ and stack trace $s$,
the null object (\ref{null}) is stored into $v$;
the execution of the getter then throws $e$ and stack trace $s$.
Otherwise, the evaluation of $e$ succeeded yielding an object $o$;
then $o$ is stored into $v$ and
the execution of the getter completes by returning $o$.
Otherwise,
(\commentary{when a value $o$ has been stored in $v$})
execution of the getter completes by returning $o$.
\item {\bf Constant variable declaration}.
If $d$ is of one of the forms
\code{\CONST{} $v$ = $e$;},
\code{\CONST{} $T$ $v$ = $e$;},
\code{\STATIC{} \CONST{} $v$ = $e$;} or
\code{\STATIC{} \CONST{} $T$ $v$ = $e$;}
the result of the getter is the value of the constant expression $e$.
\commentary{
Note that a constant expression cannot depend on itself,
so no cyclic references can occur.
}
\item {\bf Variable declaration without initializer}.
The result of executing the getter method is the value stored in $v$.
\commentary{This may be the initial value, that is, the null object.}
\end{itemize}
\section{Functions}
\LMLabel{functions}
\LMHash{}
Functions abstract over executable actions.
\begin{grammar}
<functionSignature> ::= <metadata> <returnType>? <identifier> <formalParameterPart>
<formalParameterPart> ::= <typeParameters>? <formalParameterList>
<returnType> ::= \VOID{}
\alt <type>
<functionBody> ::= \ASYNC{}? `=>' <expression> `;'
\alt (\ASYNC{} | \ASYNC `*' | \SYNC `*')? <block>
<block> ::= `{' <statements> `}'
\end{grammar}
\LMHash{}
Functions can be introduced by function declarations (\ref{functionDeclarations}),
method declarations (\ref{instanceMethods}, \ref{staticMethods}),
getter declarations (\ref{getters}),
setter declarations (\ref{setters}),
and constructor declarations (\ref{constructors});
and they can be introduced by function literals (\ref{functionExpressions}).
\LMHash{}
Each declaration that introduces a function has a signature that specifies its return type, name, and formal parameter part,
except that the return type may be omitted, and getters never have a formal parameter part.
Function literals have a formal parameter part, but no return type and no name.
The formal parameter part optionally specifies the formal type parameter list of the function,
and it always specifies its formal parameter list.
A function body is either:
\begin{itemize}
\item A block statement (\ref{blocks}) containing the statements (\ref{statements}) executed by the function, optionally marked with one of the modifiers: \ASYNC, \code{\ASYNC*} or \code{\SYNC*}.
\commentary{
Because Dart is optionally typed, we cannot guarantee that a function that does not return a value will not be used in the context of an expression.
Therefore, every function must return a value.
A function body that ends without doing a throw or return will cause the function to return the null object (\ref{null}),
as will a \RETURN{} without an expression.
For generator functions, the situation is more subtle.
See further discussion in section \ref{return}.
}
OR
\item of the form \code{=> $e$} or the form \code{\ASYNC{} => $e$}, which both return the value of the expression $e$ as if by a \code{return $e$}.
\commentary{
The other modifiers do not apply here, because they apply only to generators, discussed below,
and generators are not allowed to return a value, values are added to the generated stream or iterable using \YIELD{} instead.
}
Let $R$ be the static type of $e$
and let $T$ be the declared return type of the function that has this body.
It is a compile-time error unless one of the following conditions hold:
\begin{itemize}
\item $T$ is \VOID{}.
\item The function is synchronous and $R$ is assignable to $T$.
\item The function is asynchronous and \code{Future<\flatten{R}>} is assignable to $T$.
\end{itemize}
\end{itemize}
\LMHash{}
A function is {\em asynchronous} if its body is marked with the \ASYNC{} or \code{\ASYNC*} modifier.
Otherwise the function is {\em synchronous}.
A function is a {\em generator} if its body is marked with the \code{\SYNC*} or \code{\ASYNC*} modifier.
\commentary{
Whether a function is synchronous or asynchronous is orthogonal to whether it is a generator or not.
Generator functions are a sugar for functions that produce collections in a systematic way,
by lazily applying a function that {\em generates} individual elements of a collection.
Dart provides such a sugar in both the synchronous case, where one returns an iterable, and in the asynchronous case, where one returns a stream.
Dart also allows both synchronous and asynchronous functions that produce a single value.
}
\LMHash{}
It is a compile-time error if an \ASYNC, \code{\ASYNC*} or \code{\SYNC*} modifier is attached to the body of a setter or constructor.
\rationale{
An asynchronous setter would be of little use, since setters can only be used in the context of an assignment (\ref{assignment}),
and an assignment expression always evaluates to the value of the assignment's right hand side.
If the setter actually did its work asynchronously,
one might imagine that one would return a future that resolved to the assignment's right hand side after the setter did its work.
An asynchronous constructor would, by definition, never return an instance of the class it purports to construct, but instead return a future.
Calling such a beast via \NEW{} would be very confusing.
If you need to produce an object asynchronously, use a method.
One could allow modifiers for factories.
A factory for \code{Future} could be modified by \ASYNC{}, a factory for \code{Stream} could be modified by \code{\ASYNC*} and a factory for \code{Iterable} could be modified by \code{\SYNC*}.
No other scenario makes sense because the object returned by the factory would be of the wrong type.
This situation is very unusual so it is not worth making an exception to the general rule for constructors in order to allow it.
}
\LMHash{}
It is a compile-time error if the declared return type of a function marked \ASYNC{} is not a supertype of \code{Future<$T$>} for some type $T$.
It is a compile-time error if the declared return type of a function marked \code{\SYNC*} is not a supertype of \code{Iterable<$T$>} for some type $T$.
It is a compile-time error if the declared return type of a function marked \code{\ASYNC*} is not a supertype of \code{Stream<$T$>} for some type $T$.
\subsection{Function Declarations}
\LMLabel{functionDeclarations}
\LMHash{}
A {\em function declaration} is a function that is neither a member of a class nor a function literal.
Function declarations include {\em library functions}, which are function declarations
%(including getters and setters)
at the top level of a library, and {\em local functions}, which are function declarations declared inside other functions.
Library functions are often referred to simply as top-level functions.
\LMHash{}
A function declaration consists of an identifier indicating the function's name, possibly prefaced by a return type.
The function name is followed by a signature and body.
For getters, the signature is empty.
The body is empty for functions that are external.
\LMHash{}
The scope of a library function is the scope of the enclosing library.
The scope of a local function is described in section \ref{localFunctionDeclaration}.
In both cases, the name of the function is in scope in its formal parameter scope (\ref{formalParameters}).
\LMHash{}
It is a compile-time error to preface a function declaration with the built-in identifier \STATIC{}.
\LMHash{}
When we say that a function $f_1$ {\em forwards} to another function $f_2$, we mean that invoking $f_1$ causes $f_2$ to be executed with the same arguments and/or receiver as $f_1$, and returns the result of executing $f_2$ to the caller of $f_1$, unless $f_2$ throws an exception, in which case $f_1$ throws the same exception.
Furthermore, we only use the term for synthetic functions introduced by the specification.
\subsection{Formal Parameters}
\LMLabel{formalParameters}
\LMHash{}
Every non-getter function declaration includes a {\em formal parameter list},
which consists of a list of required positional parameters (\ref{requiredFormals}),
followed by any optional parameters (\ref{optionalFormals}).
The optional parameters may be specified either as a set of named parameters or as a list of positional parameters, but not both.
\LMHash{}
Some function declarations include a {\em formal type parameter list} (\ref{functions}),
in which case we say that it is a {\em generic function}.
A {\em non-generic function} is a function which is not generic.
\LMHash{}
The {\em formal parameter part} of a function declaration consists of the formal type parameter list, if any, and the formal parameter list.
\commentary{
The following kinds of functions cannot be generic:
Getters, setters, operators, and constructors.
}
\LMHash{}
The formal type parameter list of a function declaration introduces a new scope known as the function's {\em type parameter scope}.
The type parameter scope of a generic function $f$ is enclosed in the scope where $f$ is declared.
Every formal type parameter introduces a type into the type parameter scope.
\LMHash{}
If it exists, the type parameter scope of a function $f$ is the current scope for the signature of $f$, and for the formal type parameter list itself;
otherwise the scope where $f$ is declared is the current scope for the signature of $f$.
\commentary{
This means that formal type parameters are in scope in the bounds of parameter declarations,
allowing for so-called F-bounded type parameters like
\code{class C<X \EXTENDS{} Comparable<X>{}> \{ \ldots{} \}},
\noindent
and the formal type parameters are in scope for each other, allowing dependencies like
\code{class D<X \EXTENDS{} Y, Y> \{ \ldots{} \}}.
}
\LMHash{}
The formal parameter list of a function declaration introduces a new scope known as the function's {\em formal parameter scope}.
The formal parameter scope of a non-generic function $f$ is enclosed in the scope where $f$ is declared.
The formal parameter scope of a generic function $f$ is enclosed in the type parameter scope of $f$.
Every formal parameter introduces a local variable into the formal parameter scope.
The current scope for the function's signature is the scope that encloses the formal parameter scope.
\commentary{
This means that in a generic function declaration,
the return type and parameter type annotations can use the formal type parameters,
but the formal parameters are not in scope in the signature.
}
\LMHash{}
The body of a function declaration introduces a new scope known as the function's {\em body scope}.
The body scope of a function $f$ is enclosed in the scope introduced by the formal parameter scope of $f$.
%The formal parameter scope of a function maps the name of each formal parameter $p$ to the value $p$ is bound to.
% The formal parameters of a function are processed in the enclosing scope of the function.
% \commentary{this means that the parameters themselves may not be referenced within the formal parameter list.}
\LMHash{}
It is a compile-time error if a formal parameter is declared as a constant variable (\ref{variables}).
\begin{grammar}
<formalParameterList> ::= `(' `)'
\alt `(' <normalFormalParameters> `,'? `)'
\alt `(' <normalFormalParameters> `,' <optionalFormalParameters> `)'
\alt `(' <optionalFormalParameters> `)'
<normalFormalParameters> ::= <normalFormalParameter> (`,' <normalFormalParameter>)*
<optionalFormalParameters> ::= <optionalPositionalFormalParameters>
\alt <namedFormalParameters>
<optionalPositionalFormalParameters> ::= `[' <defaultFormalParameter> (`,' <defaultFormalParameter>)* `,'? `]'
<namedFormalParameters> ::= `{' <defaultNamedParameter> (`,' <defaultNamedParameter>)* `,'? `}'
\end{grammar}
Formal parameter lists allow an optional trailing comma after the last parameter (\syntax{`,'?}).
A parameter list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma.
All parameter lists in this specification are shown without a trailing comma, but the rules and semantics apply equally to the corresponding parameter list with a trailing comma.
\subsubsection{Required Formals}
\LMLabel{requiredFormals}
\LMHash{}
A {\em required formal parameter} may be specified in one of three ways:
\begin{itemize}
\item By means of a function signature that names the parameter and describes its type as a function type (\ref{functionTypes}).
It is a compile-time error if any default values are specified in the signature of such a function type.% explain what the type is in this case? Where is this described in general?
\item As an initializing formal, which is only valid as a parameter to a generative constructor (\ref{generativeConstructors}). % do we need to say this, or anything more?
\item Via an ordinary variable declaration (\ref{variables}).
\end{itemize}
\begin{grammar}
<normalFormalParameter> ::= <functionFormalParameter>
\alt <fieldFormalParameter>
\alt <simpleFormalParameter>
<functionFormalParameter> ::= <metadata> \COVARIANT{}? <returnType>? <identifier>
\gnewline{} <formalParameterPart>
<simpleFormalParameter> ::= <metadata> \COVARIANT{}? <finalConstVarOrType>? <identifier>
<fieldFormalParameter> ::= <metadata> <finalConstVarOrType>? \THIS{} `.' <identifier>
\gnewline{} <formalParameterPart>?
\end{grammar}
\LMHash{}
It is possible to include the modifier \COVARIANT{} in some forms of parameter declarations.
This modifier has no effect.
\rationale{
The modifier \COVARIANT{} is used in strong mode.
The modifier is allowed here even though it has no effect, such that source code can be used in both contexts.
}
\LMHash{}
It is a compile-time error if the modifier \COVARIANT{} occurs on a parameter of a function which is not an instance method, instance setter, or instance operator.
\subsubsection{Optional Formals}
\LMLabel{optionalFormals}
\LMHash{}
Optional parameters may be specified and provided with default values.
\begin{grammar}
<defaultFormalParameter> ::= <normalFormalParameter> (`=' <expression>)?
<defaultNamedParameter> ::= <normalFormalParameter> (`=' <expression>)?
\alt <normalFormalParameter> ( `:' <expression>)?
\end{grammar}
A \syntax{<defaultNamedParameter>} of the form
\syntax{<normalFormalParameter> `:' <expression>}
is equivalent to one of the form:
\syntax{<normalFormalParameter> `=' <expression>}.
The colon-syntax is included only for backwards compatibility.
It is deprecated and will be removed in a later version of the language specification.
\LMHash{}
It is a compile-time error if the default value of an optional parameter is not a constant expression (\ref{constants}).
If no default is explicitly specified for an optional parameter an implicit default of \NULL{} is provided.
\LMHash{}
It is a compile-time error if the name of a named optional parameter begins with an `_' character.
\rationale{
The need for this restriction is a direct consequence of the fact that naming and privacy are not orthogonal.
If we allowed named parameters to begin with an underscore, they would be considered private and inaccessible to callers from outside the library where it was defined.
If a method outside the library overrode a method with a private optional name, it would not be a subtype of the original method.
The static checker would of course flag such situations, but the consequence would be that adding a private named formal would break clients outside the library in a way they could not easily correct.
}
\subsection{Type of a Function}
\LMLabel{typeOfAFunction}
\LMHash{}
If a function declaration does not declare a return type explicitly, its return type is \DYNAMIC{} (\ref{typeDynamic}),
unless it is a constructor function, in which case its return type is the immediately enclosing class,
or it is a setter or operator \code{[]=}, in which case its return type is \VOID{}.
\LMHash{}
A function declaration may declare formal type parameters.
The type of the function includes the names of the type parameters and their upper bounds.
When consistent renaming of type parameters can make two function types identical,
they are considered to be the same type.
\commentary{
It is convenient to include the type parameter names in function types because they are needed in order to express such things as relations among different type parameters, and F-bounds.
However, we do not wish to distinguish two function types if they have the same structure and only differ in the choice of names.
This treatment of names is also known as alpha-equivalence.
}
\LMHash{}
In the following three paragraphs,
if the number $m$ of formal type parameters is zero then the type parameter list in the function type should be omitted.
\LMHash{}
Let $F$ be a function with
formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
return type $T_0$
and no optional parameters.
Then the type of $F$ is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n$) $ \rightarrow T_0$}.
\LMHash{}
Let $F$ be a function with
formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
return type $T_0$
and positional optional parameters $T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$.
Then the type of $F$ is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$]) $ \rightarrow T_0$}.
\LMHash{}
Let $F$ be a function with
formal type parameters $X_1\ B_1, \ldots,\ X_m\ B_m$,
required formal parameters $T_1\ p_1, \ldots,\ T_n\ p_n$,
return type $T_0$
and named optional parameters $T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$.
Then the type of $F$ is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}$\}) $ \rightarrow T_0$}.
\LMHash{}
The run-time type of a function object always implements the class \FUNCTION{}.
\commentary{
One cannot assume, based on the above, that given a function \code{f}, \code{f.runtimeType} will actually be \FUNCTION{}, or that any two distinct function objects necessarily have the same run-time type.
}
\rationale{
It is up to the implementation to choose an appropriate representation for function objects.
For example, consider that a function object produced via property extraction treats equality differently from other function objects, and is therefore likely a different class.
Implementations may also use different classes for function objects based on arity and or type.
Arity may be implicitly affected by whether a function is an instance method (with an implicit receiver parameter) or not.
The variations are manifold, and so this specification only guarantees that function objects are instances of some class that implements \FUNCTION{}.
}
\subsection{External Functions}
\LMLabel{externalFunctions}
\LMHash{}
An {\em external function} is a function whose body is provided separately from its declaration.
An external function may be a top-level function (\ref{librariesAndScripts}), a method (\ref{instanceMethods}, \ref{staticMethods}), a getter (\ref{getters}), a setter (\ref{setters}) or a non-redirecting constructor (\ref{generativeConstructors}, \ref{factories}).
External functions are introduced via the built-in identifier \EXTERNAL{} (\ref{identifierReference}) followed by the function signature.
\rationale{
External functions allow us to introduce type information for code that is not statically known to the Dart compiler.
}
\commentary{
Examples of external functions might be foreign functions (defined in C, or Javascript etc.), primitives of the implementation (as defined by the Dart run-time system), or code that was dynamically generated but whose interface is statically known.
However, an abstract method is different from an external function, as it has {\em no} body.
}
\LMHash{}
An external function is connected to its body by an implementation specific mechanism.
Attempting to invoke an external function that has not been connected to its body will throw a \code{NoSuchMethodError} or some subclass thereof.
\LMHash{}
The actual syntax is given in sections \ref{classes} and \ref{librariesAndScripts} below.
\section{Classes}
\LMLabel{classes}
\LMHash{}
A {\em class} defines the form and behavior of a set of objects which are its {\em instances}.
Classes may be defined by class declarations as described below, or via mixin applications (\ref{mixinApplication}).
\begin{grammar}
<classDefinition> ::= <metadata> \ABSTRACT{}? \CLASS{} <identifier> <typeParameters>?
\gnewline{} <superclass>? <mixins>? <interfaces>?
\gnewline{} `{' (<metadata> <classMemberDefinition>)* `}'
\alt <metadata> \ABSTRACT{}? \CLASS{} <mixinApplicationClass>
<mixins> ::= \WITH{} <typeList>
<classMemberDefinition> ::= <declaration> `;'
\alt <methodSignature> <functionBody>
<methodSignature> ::= <constructorSignature> <initializers>?
\alt <factoryConstructorSignature>
% This doesn't work: `static @override foo() => 42`, but `functionSignature` starts with metadata. https://github.com/dart-lang/sdk/issues/29614
\alt \STATIC{}? <functionSignature>
\alt \STATIC{}? <getterSignature>
\alt \STATIC{}? <setterSignature>
\alt <operatorSignature>
<declaration> ::= <constantConstructorSignature> (<redirection> | <initializers>)?
\alt <constructorSignature> (<redirection> | <initializers>)?
\alt \EXTERNAL{} <constantConstructorSignature>
\alt \EXTERNAL{} <constructorSignature>
\alt ((\EXTERNAL{} \STATIC{}?))? <getterSignature>
\alt ((\EXTERNAL{} \STATIC{}?))? <setterSignature>
\alt \EXTERNAL{}? <operatorSignature>
% This doesn't work: `static @override foo() => 42`, but `functionSignature` starts with metadata. https://github.com/dart-lang/sdk/issues/29614
\alt ((\EXTERNAL{} \STATIC{}?))? <functionSignature>
\alt \STATIC{} (\FINAL{} | \CONST{}) <type>? <staticFinalDeclarationList>
% \CONST{} type? staticFinalDeclarationList;
\alt \FINAL{} <type>? <initializedIdentifierList>
\alt (\STATIC{} | \COVARIANT{})? (\VAR{} | <type>) <initializedIdentifierList>
<staticFinalDeclarationList> ::= <staticFinalDeclaration> (`,' <staticFinalDeclaration>)*
<staticFinalDeclaration> ::= <identifier> `=' <expression>
\end{grammar}
\LMHash{}
It is possible to include the modifier \COVARIANT{} in some forms of declarations.
This modifier has no effect.
\rationale{
The modifier \COVARIANT{} is used in strong mode.
The modifier is allowed here even though it has no effect, such that source code can be used in both contexts.
}
\LMHash{}
A class has constructors, instance members and static members.
The instance members of a class are its instance methods, getters, setters and instance variables.
The static members of a class are its static methods, getters, setters and class variables.
The members of a class are its static and instance members.
\LMHash{}
A class has several scopes:
\begin{itemize}
\item A {\em type-parameter scope}, which is empty if the class is not generic (\ref{generics}).
The enclosing scope of the type-parameter scope of a class is the enclosing scope of the class declaration.
\item A {\em static scope}.
The enclosing scope of the static scope of a class is the type parameter scope (\ref{generics}) of the class.
\item An {\em instance scope}.
The enclosing scope of a class' instance scope is the class' static scope.
\end{itemize}
\LMHash{}
The enclosing scope of an instance member declaration is the instance scope of the class in which it is declared.
\LMHash{}
The enclosing scope of a static member declaration is the static scope of the class in which it is declared.
\LMHash{}
Every class has a single superclass except class \code{Object} which has no superclass.
A class may implement a number of interfaces by declaring them in its implements clause (\ref{superinterfaces}).
\LMHash{}
An {\em abstract class} is a class that is explicitly declared with the \ABSTRACT{} modifier, either by means of a class declaration or via a type alias (\ref{typedef}) for a mixin application (\ref{mixinApplication}).
A {\em concrete class} is a class that is not abstract.
\rationale{
We want different behavior for concrete classes and abstract classes.
If $A$ is intended to be abstract, we want the static checker to warn about any attempt to instantiate $A$, and we do not want the checker to complain about unimplemented methods in $A$.
In contrast, if $A$ is intended to be concrete, the checker should warn about all unimplemented methods, but allow clients to instantiate it freely.
}
\LMHash{}
The {\em interface of class $C$} is an implicit interface that declares instance members that correspond to the instance members declared by $C$, and whose direct superinterfaces are the direct superinterfaces of $C$ (\ref{superinterfaces}).
When a class name appears as a type, that name denotes the interface of the class.
% making an exception for the setters generated for final fields is tempting but problematic.
% If a super type defines a setter, it will be overridden yet have no impact on the interface.
% Maybe the final field hides the setter in scope?
% I think the original rules were best.
\commentary{
It is a compile-time error if a class declares two members of the same name,
either because it declares the same name twice in the same scope (\ref{scoping}),
or because it declares a static member and an instance member with the same name
(\ref{classMemberConflicts}).
}
\commentary{
Here are simple examples, that illustrate the difference between ``has a member'' and ``declares a member''.
For example, \code{B} {\em declares} one member named \code{f}, but {\em has} two such members.
The rules of inheritance determine what members a class has.
}
\begin{dartCode}
\CLASS{} A \{
\VAR{} i = 0;
\VAR{} j;
f(x) => 3;
\}
\\
\CLASS{} B \EXTENDS{} A \{
int i = 1; // \comment{getter i and setter i= override versions from A}
\STATIC{} j; // \comment{compile-time error: static getter \& setter conflict with}
// \comment{instance getter \& setter}
\\
// \comment{compile-time error: static method conflicts with instance method}
\STATIC{} f(x) => 3;
\}
\end{dartCode}
\LMHash{}
It is a compile-time error if a class named $C$ declares
a member with basename (\ref{classMemberConflicts}) $C$.
If a generic class named $G$ declares a type variable named $X$,
it is a compile-time error
if $X$ is equal to $G$,
if $G$ has a member whose basename is $X$,
and if $G$ has a constructor named \code{$G$.$X$}.
\subsection{Instance Methods}
\LMLabel{instanceMethods}
\LMHash{}
Instance methods are functions (\ref{functions}) whose declarations are immediately contained within a class declaration and that are not declared \STATIC{}.
The instance methods of a class $C$ are those instance methods declared by $C$ and the instance methods inherited by $C$ from its superclass.
\LMHash{}
It is a compile-time error if an instance method $m_1$ overrides (\ref{inheritanceAndOverriding}) an instance member $m_2$ and $m_1$ has a greater number of required parameters than $m_2$.
It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ has fewer positional parameters than $m_2$.
It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and $m_1$ does not declare all the named parameters declared by $m_2$.
\LMHash{}
%% TODO(eernst): We need to use the concept of 'correctly overrides' rather than 'is a subtype of', e.g., to treat `void` correctly.
It is a compile-time error if an instance method $m_1$ overrides an instance member $m_2$ and the type of $m_1$ is not a subtype of the type of $m_2$.
It is a compile-time warning if an instance method $m_1$ overrides an instance member $m_2$, the signature of $m_2$ explicitly specifies a default value for a formal parameter $p$, and the signature of $m_1$ implies a different default value for $p$.
\commentary{
A method declaration may conflict with other declarations
(\ref{classMemberConflicts}).
}
\subsubsection{Operators}
\LMLabel{operators}
\LMHash{}
{\em Operators} are instance methods with special names.
\begin{grammar}
<operatorSignature> ::= <returnType>? \OPERATOR{} <operator> <formalParameterList>
<operator> ::= `~'
\alt <binaryOperator>
\alt `[]'
\alt `[]='
<binaryOperator> ::= <multiplicativeOperator>
\alt <additiveOperator>
\alt <shiftOperator>
\alt <relationalOperator>
\alt `=='
\alt <bitwiseOperator>
\end{grammar}
\LMHash{}
An operator declaration is identified using the built-in identifier (\ref{identifierReference}) \OPERATOR{}.
\LMHash{}
The following names are allowed for user-defined operators:
\syntax{`<'},
\syntax{`>'},
\syntax{`<='},
\syntax{`>='},
\syntax{`=='},
\syntax{`-'},
\syntax{`+'},
\syntax{`/'},
\syntax{`~'},
\syntax{`*'},
\syntax{`\%'},
\syntax{`|'},
\syntax{`^'},
\syntax{`\&'},
\syntax{`\ltlt'},
\syntax{`\gtgt'},
\syntax{`\gtgtgt'},
\syntax{`[]='},
\syntax{`[]'},
\syntax{`~'}.
\LMHash{}
It is a compile-time error if the arity of the user-declared operator
\syntax{`[]='} is not 2.
It is a compile-time error if the arity of a user-declared operator with one of the names:
\syntax{`<'},
\syntax{`>'},
\syntax{`<='},
\syntax{`>='},
\syntax{`=='},
\syntax{`-'},
\syntax{`+'},
\syntax{`~/'},
\syntax{`/'},
\syntax{`*'},
\syntax{`\%'},
\syntax{`|'},
\syntax{`^'},
\syntax{`\&'},
\syntax{`\ltlt'},
\syntax{`\gtgt'},
\syntax{`\gtgtgt'},
\syntax{`[]'}
is not 1.
It is a compile-time error if the arity of the user-declared operator
\syntax{`-'}
is not 0 or 1.
\commentary{
The \syntax{`-'} operator is unique
in that two overloaded versions are permitted.
If the operator has no arguments, it denotes unary minus.
If it has an argument, it denotes binary subtraction.
}
\LMHash{}
The name of the unary operator \syntax{`-'} is \code{unary-}.
\rationale{
This device allows the two methods to be distinguished for purposes of method lookup, override and reflection.
}
\LMHash{}
It is a compile-time error if the arity of the user-declared operator
\syntax{`~'}
is not 0.
\LMHash{}
It is a compile-time error to declare an optional parameter in an operator.
\LMHash{}
It is a compile-time warning if the return type of a user-declared operator
\syntax{`[]='}
is explicitly declared and not \VOID{}.
\commentary{
If no return type is specified for a user-declared operator
\syntax{`[]='},
its return type is \VOID{} (\ref{typeOfAFunction}).
}
\rationale{
The return type is \VOID{} because
a return statement in an implementation of operator
\syntax{`[]='}
does not return a value.
Consider a non-throwing evaluation of an expression $e$ of the form \code{$e_1$[$e_2$] = $e_3$},
and assume that the evaluation of $e_3$ yields an instance $o$.
$e$ will then evaluate to $o$,
and even if the executed body of operator
\syntax{`[]='}
completes with a value $o'$,
that is, if $o'$ is returned, that value is simply ignored.
The rationale for this behavior is that assignments should be guaranteed to evaluate to the assigned value.
}
\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}
\LMLabel{getters}
\LMHash{}
Getters are functions (\ref{functions}) that are used to retrieve the values of object properties.
\begin{grammar}
<getterSignature> ::= <returnType>? \GET{} <identifier>
\end{grammar}
\LMHash{}
If no return type is specified, the return type of the getter is \DYNAMIC{}.
\LMHash{}
A getter definition that is prefixed with the \STATIC{} modifier defines a static getter.
Otherwise, it defines an instance getter.
The name of the getter is given by the identifier in the definition.
The effect of a static getter declaration in class $C$ is to add an instance getter with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static getter.
\LMHash{}
The instance getters of a class $C$ are those instance getters declared by $C$, either implicitly or explicitly, and the instance getters inherited by $C$ from its superclass.
The static getters of a class $C$ are those static getters declared by $C$.
\commentary{
A getter declaration may conflict with other declarations
(\ref{classMemberConflicts}).
In particular, a getter can never override a method,
and a method can never override a getter or an instance variable.
}
\LMHash{}
It is a compile-time error if a getter $m_1$ overrides (\ref{inheritanceAndOverriding}) a getter $m_2$
and the return type of $m_1$ is not a subtype of the return type of $m_2$.
\subsection{Setters}
\LMLabel{setters}
\LMHash{}
Setters are functions (\ref{functions}) that are used to set the values of object properties.
\begin{grammar}
<setterSignature> ::= <returnType>? \SET{} <identifier> <formalParameterList>
\end{grammar}
\commentary{
If no return type is specified, the return type of the setter is \VOID{} (\ref{typeOfAFunction}).
}
\LMHash{}
A setter definition that is prefixed with the \STATIC{} modifier defines a static setter.
Otherwise, it defines an instance setter.
The name of a setter is obtained by appending the string `=' to the identifier given in its signature.
The effect of a static setter declaration in class $C$ is to add an instance setter with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static setter.
\commentary{
Hence, a setter name can never conflict with, override or be overridden by a getter or method.
}
\LMHash{}
The instance setters of a class $C$ are those instance setters declared by $C$ either implicitly or explicitly, and the instance setters inherited by $C$ from its superclass.
The static setters of a class $C$ are those static setters declared by $C$.
\LMHash{}
It is a compile-time error if a setter's formal parameter list does not consist of exactly one required formal parameter $p$.
\rationale{
We could enforce this via the grammar, but we'd have to specify the evaluation rules in that case.
}
\LMHash{}
It is a compile-time warning if a setter declares a return type other than \VOID{}.
It is a compile-time error if a setter $m_1$ overrides (\ref{inheritanceAndOverriding}) a setter $m_2$
and the parameter type of $m_1$ is not a supertype of the parameter type of $m_2$.
It is a compile-time warning if a class has
a setter named $v=$ with argument type $T$ and
a getter named $v$ with return type $S$,
and $S$ may not be assigned to $T$.
\commentary{
A setter declaration may conflict with other declarations
(\ref{classMemberConflicts}).
}
\subsection{Abstract Instance Members}
\LMLabel{abstractInstanceMembers}
\LMHash{}
An {\em abstract method} (respectively, {\em abstract getter} or {\em abstract setter)} is an instance method, getter or setter that is not declared \EXTERNAL{} and does not provide an implementation.
A {\em concrete method} (respectively, {\em concrete getter} or {\em concrete setter)} is an instance method, getter or setter that is not abstract.
\rationale{
Earlier versions of Dart required that abstract members be identified by prefixing them with the modifier \ABSTRACT{}.
The elimination of this requirement is motivated by the desire to use abstract classes as interfaces.
Every Dart class induces an implicit interface.
Using an abstract class instead of an interface has important advantages.
An abstract class can provide default implementations; it can also provide static methods, obviating the need for service classes such as \code{Collections} or \code{Lists}, whose entire purpose is to group utilities related to a given type.
Eliminating the requirement for an explicit modifier on members makes abstract classes more concise, making abstract classes an attractive substitute for interface declarations.
}
\commentary{
Invocation of an abstract method, getter, or setter cannot occur,
because lookup (\ref{lookup}) will never yield an abstract member as its result.
One way to think about this is that
an abstract member declaration in a subclass
does not override or shadow an inherited member implementation.
It only serves to specify the signature of the given member that
every concrete subtype must have an implementation of;
that is, it contributes to the interface of the class,
not to the class itself.
}
\rationale{
The purpose of an abstract method is to provide a declaration for purposes such as type checking and reflection.
In classes used as mixins, it is often useful to introduce such declarations for methods that the mixin expects will be provided by the superclass the mixin is applied to.
}
\LMHash{}
%% 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:
\begin{itemize}
\item $m$ overrides a concrete member, or
\item $C$ has a concrete \code{noSuchMethod()} method distinct from the one declared in class \code{Object}.
\end{itemize}
\rationale{
We wish to detect if one declares a concrete class with abstract members.
However, code like the following should work:
}
\begin{dartCode}
class Base \{
int get one => 1;
\}
\\
\ABSTRACT{} \CLASS{} Mix \{
int get one;
int get two => one + one;
\}
\\
\CLASS{} C extends Base with Mix \{ \}
\end{dartCode}
\rationale{
At run time, the concrete method \code{one} declared in \code{Base} will be executed, and no problem should arise.
Therefore no error should be raised if a corresponding concrete member exists in the hierarchy.
}
\subsection{Instance Variables}
\LMLabel{instanceVariables}
\LMHash{}
Instance variables are variables whose declarations are immediately contained within a class declaration and that are not declared \STATIC{}.
The instance variables of a class $C$ are those instance variables declared by $C$ and the instance variables inherited by $C$ from its superclass.
\LMHash{}
It is a compile-time error if an instance variable is declared to be constant.
\rationale{
The notion of a constant instance variable is subtle and confusing to programmers.
An instance variable is intended to vary per instance.
A constant instance variable would have the same value for all instances, and as such is already a dubious idea.
The language could interpret const instance variable declarations as instance getters that return a constant.
However, a constant instance variable could not be treated as a true compile-time constant, as its getter would be subject to overriding.
Given that the value does not depend on the instance, it is better to use a static class variable.
An instance getter for it can always be defined manually if desired.
}
\subsection{Constructors}
\LMLabel{constructors}
\LMHash{}
A {\em constructor} is a special function that is used in instance creation expressions (\ref{instanceCreation}) to obtain objects, typically by creating or initializing them.
Constructors may be generative (\ref{generativeConstructors}) or they may be factories (\ref{factories}).
\LMHash{}
A {\em constructor name} always begins with the name of its immediately enclosing class, and may optionally be followed by a dot and an identifier \id.
It is a compile-time error if the name of a constructor is not a constructor name.
\LMHash{}
The {\em function type of a constructor} $k$ is the function type whose
return type is the class that contains the declaration of $k$,
and whose formal parameter types, optionality, and names of named parameters
correspond to the declaration of $k$.
\commentary{
Note that the function type $F$ of a constructor $k$ may contain
type variables declared by the enclosing class $C$.
In that case we can apply a substitution to $F$, as in
$[T_1/X_1, \ldots, T_m/X_m]F$,
where $X_j, j \in 1 .. m$ are the formal type parameters of $C$
and $T_j, j \in 1 .. m$ are specified in the given context.
We may also omit such a substitution when the given context is
the instance scope of $C$, where $X_1, \ldots, X_m$ are in scope.
}
\commentary{
A constructor declaration may conflict with static member declarations
(\ref{classMemberConflicts}).
}
% In what scope do constructors go? The simple names of named constructors go in the static scope of the class. Unnamed ones go nowhere, but we use the class name to refer to them; the class name could also in the static scope of the class as well to prevent weird errors, or we could ban it explicitly and avoiding duplication. Similarly, the instance scope could contain the constructor names and class name, or we could have special rules to prevent collisions between instance members and constructors or the class.
% The enclosing scope of a generative constructor is the instance scope of the class in which it is declared (but what about redirecting?)
\LMHash{}
If{}f no constructor is specified for a class $C$, it implicitly has a default constructor \code{C() : \SUPER{}() \{\}}, unless $C$ is class \code{Object}.
\subsubsection{Generative Constructors}
\LMLabel{generativeConstructors}
\LMHash{}
A {\em generative constructor} consists of a constructor name, a constructor parameter list, and either a redirect clause or an initializer list and an optional body.
\begin{grammar}
<constructorSignature> ::= <identifier> (`.' <identifier>)? <formalParameterList>
\end{grammar}
\LMHash{}
A {\em constructor parameter list} is a parenthesized, comma-separated list of formal constructor parameters.
A {\em formal constructor parameter} is either a formal parameter (\ref{formalParameters}) or an initializing formal.
An {\em initializing formal} has the form \code{\THIS{}.\id}, where \id{} is the name of an instance variable of the immediately enclosing class.
It is a compile-time error if \id{} is not an instance variable of the immediately enclosing class.
It is a compile-time error if an initializing formal is used by a function other than a non-redirecting generative constructor.
\LMHash{}
If an explicit type is attached to the initializing formal, that is its static type.
Otherwise, the type of an initializing formal named \id{} is $T_{id}$, where $T_{id}$ is the type of the instance variable named \id{} in the immediately enclosing class.
It is a compile-time error if the static type of \id{} is not a subtype of $T_{id}$.
\LMHash{}
Initializing formals constitute an exception to the rule that every formal parameter introduces a local variable into the formal parameter scope (\ref{formalParameters}).
When the formal parameter list of a non-redirecting generative constructor contains any initializing formals, a new scope is introduced, the {\em formal parameter initializer scope}, which is the current scope of the initializer list of the constructor, and which is enclosed in the scope where the constructor is declared.
Each initializing formal in the formal parameter list introduces a final local variable into the formal parameter initializer scope, but not into the formal parameter scope; every other formal parameter introduces a local variable into both the formal parameter scope and the formal parameter initializer scope.
\commentary{
This means that formal parameters, including initializing formals, must have distinct names, and that initializing formals are in scope for the initializer list, but they are not in scope for the body of the constructor.
When a formal parameter introduces a local variable into two scopes, it is still one variable and hence one storage location.
The type of the constructor is defined in terms of its formal parameters, including the initializing formals.
}
\LMHash{}
Initializing formals are executed during the execution of generative constructors detailed below.
Executing an initializing formal \code{\THIS{}.\id} causes the instance variable \id{} of the immediately surrounding class to be assigned the value of the corresponding actual parameter,
unless \id{} is a final variable that has already been initialized, in which case a run-time error occurs.
\commentary{
The above rule allows initializing formals to be used as optional parameters:
}
\begin{dartCode}
class A \{
int x;
A([this.x]);
\}
\end{dartCode}
\commentary{
is legal, and has the same effect as
}
\begin{dartCode}
class A \{
int x;
A([int x]): this.x = x;
\}
\end{dartCode}
\LMHash{}
A {\em fresh instance} is an instance whose identity is distinct from any previously allocated instance of its class.
A generative constructor always operates on a fresh instance of its immediately enclosing class.
\commentary{
The above holds if the constructor is actually run, as it is by \NEW{}.
If a constructor $c$ is referenced by \CONST{}, $c$ may not be run; instead, a canonical object may be looked up.
See the section on instance creation (\ref{instanceCreation}).
}
\LMHash{}
If a generative constructor $c$ is not a redirecting constructor and no body is provided, then $c$ implicitly has an empty body \code{\{\}}.
\paragraph{Redirecting Generative Constructors}
\LMLabel{redirectingGenerativeConstructors}
\LMHash{}
A generative constructor may be {\em redirecting}, in which case its only action is to invoke another generative constructor.
A redirecting constructor has no body;
instead, it has a redirect clause that specifies which constructor the invocation is redirected to, and with which arguments.
\begin{grammar}
<redirection> ::= `:' \THIS{} (`.' <identifier>)? <arguments>
\end{grammar}
\def\ConstMetavar{\mbox{\CONST{}?}}
\LMHash{}
Assume that
\code{$C$<$X_1\ \EXTENDS\ B_1 \ldots,\ X_m\ \EXTENDS\ B_m$>}
is the name and formal type parameters of the enclosing class,
$\ConstMetavar$ stands for either \CONST{} or nothing,
$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$,
and \id{} is an identifier.
Consider a declaration of a redirecting generative constructor $k$ of one of the forms
\code{$\ConstMetavar$ $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1} = d_1 \ldots,\ T_{n+k}\ x_{n+k} = d_k$]): $R$;}
\code{$\ConstMetavar$ $N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1} = d_1 \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}): $R$;}
\noindent
where $R$ is of one of the forms
\code{$\THIS{}$($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)}
\code{$\THIS{}.\id$($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)}
\LMHash{}
The {\em redirectee constructor} for this declaration is then the constructor denoted by
\code{$C$<$X_1 \ldots,\ X_m$>} respectively \code{$C$<$X_1 \ldots,\ X_m$>.\id}.
It is a compile-time error if the static argument list type (\ref{actualArgumentLists}) of
\code{($e_1 \ldots,\ e_p,\ x_1$: $e_{p+1}, \ldots,\ x_q$: $e_{p+q}$)}
is not an assignable match for the formal parameter list of the redirectee.
\commentary{
Note that the case where no named parameters are passed is covered by letting $q$ be zero,
and the case where $C$ is a non-generic class is covered by letting $m$ be zero,
in which case the formal type parameter list and actual type argument lists are omitted (\ref{generics}).
}
\rationale{
We require an assignable match rather than the stricter subtype match
because a generative redirecting constructor $k$ invokes its redirectee $k'$
in a manner which resembles function invocation in general.
For instance, $k$ could accept an argument \code{x}
and pass on an expression $e_j$ using \code{x} such as \code{x.f(42)} to $k'$,
and it would be surprising
if $e_j$ were subject to more strict constraints than the ones applied to
actual arguments to function invocations in general.
}
\LMHash{}
When $\ConstMetavar$ is \CONST{},
it is a compile-time error if the redirectee is not a constant constructor.
Moreover, when $\ConstMetavar$ is \CONST{}, each
$e_i,\ i \in 1 .. p+q$,
must be a potentially constant expression (\ref{constantConstructors}).
\LMHash{}
It is a dynamic type error if an actual argument passed in an invocation of a redirecting generative constructor $k$
is not a subtype of the actual type (\ref{actualTypeOfADeclaration})
of the corresponding formal parameter in the declaration of $k$.
It is a dynamic type error if an actual argument passed to the redirectee $k'$ of a redirecting generative constructor
is not a subtype of the actual type
(\ref{actualTypeOfADeclaration})
of the corresponding formal parameter in the declaration of the redirectee.
\paragraph{Initializer Lists}
\LMLabel{initializerLists}
\LMHash{}
An initializer list begins with a colon, and consists of a comma-separated list of individual {\em initializers}.
\commentary{
There are three kinds of initializers.
\begin{itemize}
\item[$\bullet$] A {\em superinitializer} identifies a {\em superconstructor}\,---\,that is, a specific constructor of the superclass.
Execution of the superinitializer causes the initializer list of the superconstructor to be executed.
\item[$\bullet$] An {\em instance variable initializer} assigns a value to an individual instance variable.
\item[$\bullet$] An assertion.
\end{itemize}
}
\begin{grammar}
<initializers> ::= `:' <initializerListEntry> (`,' <initializerListEntry>)*
<initializerListEntry> ::= \SUPER{} <arguments>
\alt \SUPER{} `.' <identifier> <arguments>
\alt <fieldInitializer>
\alt <assertion>
<fieldInitializer> ::= (\THIS{} `.')? <identifier> `=' <conditionalExpression> <cascadeSection>*
\end{grammar}
\LMHash{}
An initializer of the form \code{$v$ = $e$} is equivalent to
an initializer of the form \code{\THIS{}.$v$ = $e$},
both forms are called {\em instance variable initializers}.
It is a compile-time error if the enclosing class does not declare an instance variable named $v$.
Otherwise, let $T$ be the static type of $v$.
It is a compile-time error unless the static type of $e$ is assignable to $T$.
\LMHash{}
Consider a {\em superinitializer} $s$ of the form
\code{\SUPER{}($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
respectively
\code{\SUPER{}.\id($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\noindent{}%
Let $S$ be the superclass of the enclosing class of $s$.
It is a compile-time error if class $S$ does not declare a generative constructor named $S$ (respectively \code{$S$.\id}).
Otherwise, the static analysis of $s$ is performed as specified in Section~\ref{bindingActualsToFormals},
as if \code{\SUPER{}} respectively \code{\SUPER{}.\id}
had had the function type of the denoted constructor,
%% TODO(eernst): The following is very imprecise, it just serves to remember
%% that we must specify how to deal with the type variables in that parameter
%% part. One thing that we weasel over is that the superclass may be a mixin
%% application.
and substituting the formal type variables of the superclass
for the corresponding actual type arguments passed to the superclass
in the header of the current class.
\LMHash{}
Let $k$ be a generative constructor.
Then $k$ may include at most one superinitializer in its initializer list or a compile-time error occurs.
If no superinitializer is provided, an implicit superinitializer of the form \SUPER{}() is added at the end of $k$'s initializer list,
unless the enclosing class is class \code{Object}.
It is a compile-time error if a superinitializer appears in $k$'s initializer list at any other position than at the end.
It is a compile-time error if more than one initializer corresponding to a given instance variable appears in $k$'s initializer list.
It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is initialized by means of an initializing formal of $k$.
It is a compile-time error if $k$'s initializer list contains an initializer for a final variable $f$ whose declaration includes an initialization expression.
It is a compile-time error if $k$ includes an initializing formal for a final variable $f$ whose declaration includes an initialization expression.
\LMHash{}
Let $f$ be a final instance variable declared in
the immediately enclosing class.
A compile-time error occurs unless $f$ is initialized
by one of the following means:
\begin{itemize}
\item $f$ is declared by an initializing variable declaration.
\item $f$ is initialized by means of an initializing formal of $k$.
\item $f$ has an initializer in $k$'s initializer list.
\end{itemize}
\LMHash{}
It is a compile-time error if $k$'s initializer list contains an initializer for a variable that is not an instance variable declared in the immediately surrounding class.
\commentary{
The initializer list may of course contain an initializer for any instance variable declared by the immediately surrounding class, even if it is not final.
}
\LMHash{}
It is a compile-time error if a generative constructor of class \code{Object} includes a superinitializer.
\paragraph{Execution of Generative Constructors}
\LMLabel{executionOfGenerativeConstructors}
\LMHash{}
Execution of a generative constructor $k$ of type $T$ to initialize a fresh instance $i$
is always done with respect to a set of bindings for its formal parameters
and the type parameters of the immediately enclosing class bound to
a set of actual type arguments of $T$, $t_1, \ldots, t_m$.
\commentary{
These bindings are usually determined by the instance creation expression that invoked the constructor (directly or indirectly).
However, they may also be determined by a reflective call.
}
\LMHash{}
If $k$ is redirecting then its redirect clause has the form
\code{\THIS{}.$g$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
where $g$ identifies another generative constructor of the immediately surrounding class.
Then execution of $k$ to initialize $i$ proceeds by evaluating the argument list
\code{($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
to an actual argument list $a$ of the form
\code{($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1}, \ldots,\ x_{n+k}$: $o_{n+k}$)}
in an environment where the type parameters of the enclosing class are bound to
$t_1, \ldots, t_m$.
\LMHash{}
Next, the body of $g$ is executed to initialize $i$ with respect to the bindings that map
the formal parameters of $g$ to the corresponding objects in the actual argument list $a$,
with \THIS{} bound to $i$,
and the type parameters of the immediately enclosing class bound to $t_1, \ldots, t_m$.
\LMHash{}
Otherwise, $k$ is not redirecting.
Execution then proceeds as follows:
\LMHash{}
The instance variable declarations of the immediately enclosing class are visited in the order they appear in the program text.
For each such declaration $d$, if $d$ has the form
\code{\syntax{finalConstVarOrType} $v$ = $e$; }
then $e$ is evaluated to an object $o$
and the instance variable $v$ of $i$ is bound to $o$.
\LMHash{}
Any initializing formals declared in $k$'s parameter list are executed in the order they appear in the program text.
% In fact, this order is unobservable; this could be done any time prior to running the body, since
% these only effect \THIS{}.
Then, the initializers of $k$'s initializer list are executed to initialize $i$
in the order they appear in the program, as described below
(p.\,\pageref{executionOfInitializerLists}).
\rationale{
We could observe the order by side effecting external routines called.
So we need to specify the order.
}
\LMHash{}
Then if any instance variable of $i$ declared by the immediately enclosing class
is not yet bound to a value,
all such variables are initialized with the null object (\ref{null}).
\LMHash{}
Then, unless the enclosing class is \code{Object}, the explicitly specified or
implicitly added superinitializer (\ref{initializerLists}) is executed to
further initialize $i$.
\LMHash{}
After the superinitializer has completed, the body of $k$ is executed in a scope where \THIS{} is bound to $i$.
\rationale{
This process ensures that no uninitialized final instance variable is ever seen by code.
Note that \THIS{} is not in scope on the right hand side of an initializer (see \ref{this}) so no instance method can execute during initialization:
an instance method cannot be directly invoked,
nor can \THIS{} be passed into any other code being invoked in the initializer.
}
\paragraph{Execution of Initializer Lists}
\LMLabel{executionOfInitializerLists}
\LMHash{}
During the execution of a generative constructor to initialize an instance $i$,
execution of an initializer of the form \code{\THIS{}.$v$ = $e$}
proceeds as follows:
\LMHash{}
First, the expression $e$ is evaluated to an object $o$.
Then, the instance variable $v$ of $i$ is bound to $o$.
It is a dynamic type error if $o$ is not the null object
(\ref{null})
and the dynamic type of $o$ is not a subtype of the actual type
(\ref{actualTypeOfADeclaration})
of the instance variable $v$.
\LMHash{}
Execution of an initializer that is an assertion proceeds by executing the assertion (\ref{assert}).
\LMHash{}
Consider a superinitializer $s$ of the form
\code{\SUPER{}($a_1, \ldots,\ a_n,\ x_{n+1}: a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
respectively
\code{\SUPER{}.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
Let $C$ be the class in which $s$ appears and let $S$ be the superclass of $C$.
If $S$ is generic (\ref{generics}),
let $u_1, \ldots, u_p$ be the actual type arguments passed to $S$,
obtained by substituting $t_1, \ldots, t_m$
for the formal type parameters of $C$
in the superclass as specified in the header of $C$, and
$t_1, \ldots, t_m$
are the actual bindings of the type variables of $C$.
Let $k$ be the constructor declared in $S$ and named
$S$ respectively \code{$S$.\id}.
\LMHash{}
Execution of $s$ proceeds as follows:
The argument list
\code{($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
is evaluated to an actual argument list $a$ of the form
\code{($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1}, \ldots,\ x_{n+k}$: $o_{n+k}$)}.
Then the body of the superconstructor $k$ is executed
in an environment where the formal parameters of $k$ are bound to
the corresponding actual arguments from $a$,
and the formal type parameters of $S$ are bound to $u_1, \ldots, u_p$.
\subsubsection{Factories}
\LMLabel{factories}
\LMHash{}
A {\em factory} is a constructor prefaced by the built-in identifier (\ref{identifierReference}) \FACTORY{}.
\begin{grammar}
<factoryConstructorSignature> ::= \FACTORY{} <identifier> (`.' <identifier>)? <formalParameterList>
\end{grammar}
%The enclosing scope of a factory constructor is the static scope \ref{} of the class in which it is declared.
\LMHash{}
The {\em return type} of a factory whose signature is of the form \FACTORY{} $M$ or the form \FACTORY{} \code{$M$.\id} is $M$ if $M$ is not a generic type;
otherwise the return type is \code{$M$<$T_1, \ldots,\ T_n$>} where $T_1, \ldots, T_n$ are the type parameters of the enclosing class.
\LMHash{}
It is a compile-time error if $M$ is not the name of the immediately enclosing class.
\LMHash{}
It is a dynamic type error if a factory returns a non-null object
whose type is not a subtype of its actual
(\ref{actualTypeOfADeclaration})
return type.
\rationale{
It seems useless to allow a factory to return the null object (\ref{null}).
But it is more uniform to allow it, as the rules currently do.
}
\rationale{
Factories address classic weaknesses associated with constructors in other languages.
Factories can produce instances that are not freshly allocated: they can come from a cache.
Likewise, factories can return instances of different classes.
}
\paragraph{Redirecting Factory Constructors}
\LMLabel{redirectingFactoryConstructors}
\LMHash{}
A {\em redirecting factory constructor} specifies a call to a constructor of another class that is to be used whenever the redirecting constructor is called.
\begin{grammar}
<redirectingFactoryConstructorSignature> ::= \CONST{}? \FACTORY{} <identifier> (`.' <identifier>)? <formalParameterList>
\gnewline{} `=' <type> (`.' <identifier>)?
\end{grammar}
Assume that
\code{$C$<$X_1\ \EXTENDS\ B_1 \ldots,\ X_m\ \EXTENDS\ B_m$>}
is the name and formal type parameters of the enclosing class,
$\ConstMetavar$ is \CONST{} or empty,
$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$,
$T$ is a type name, and \id{} is an identifier,
then consider a declaration of a redirecting factory constructor $k$ of one of the forms
\begin{dartCode}
$\ConstMetavar$ \FACTORY{}
$N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$]) = $R$;
\\
$\ConstMetavar$ \FACTORY{}
$N$($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1}$=$d_1, \ldots,\ T_{n+k}\ x_{n+k}$=$d_k$\}) = $R$;
\end{dartCode}
\noindent
where $R$ is of one of the forms
\code{$T$<$S_1 \ldots,\ S_p$>} or
\code{$T$<$S_1 \ldots,\ S_p$>.\id}.
\LMHash{}
It is a compile-time error if $T$ does not denote
a class accessible in the current scope.
If $T$ does denote such a class $D$,
it is a compile-time error if $R$ does not denote a constructor.
% It is by induction sufficient to check for abstractness one level down,
% because it is an error on the redirectee if this occurs after multiple
% redirections:
Otherwise, it is a compile-time error
if $R$ denotes a generative constructor and $D$ is abstract.
Otherwise, the {\em redirectee constructor} for this declaration is
the constructor denoted by $R$.
\LMHash{}
A redirecting factory constructor $q'$ is {\em redirection-reachable}
from a redirecting factory constructor $q$ if{}f
$q'$ is the redirectee constructor of $q$,
or $q''$ is the redirectee constructor of $q$
and $q'$ is redirection-reachable from $q''$.
It is a compile-time error if a redirecting factory constructor
is redirection-reachable from itself.
\LMHash{}
Let $\argumentList{T}$ be the static argument list type (\ref{actualArgumentLists})
\code{($T_1 \ldots,\ T_{n+k}$)}
when $k$ takes no named arguments, and
\code{($T_1 \ldots,\ T_n,\ T_{n+1}\ x_{n+1},\ \ldots,\ T_{n+k}\ x_{n+k}$)}
when $k$ takes some named arguments.
It is a compile-time error if $\argumentList{T}$
is not a subtype match for the formal parameter list of the redirectee.
\rationale{
We require a subtype match
(rather than the more forgiving assignable match which is used with a generative redirecting constructor),
because a factory redirecting constructor $k$ always invokes its redirectee $k'$
with exactly the same actual arguments that $k$ received.
This means that a downcast on an actual argument
``between'' $k$ and $k'$
would either be unused because the actual argument has the type required by $k'$,
or it would amount to a dynamic error which is simply delayed a single step.
}
\commentary{
Note that the non-generic case is covered by letting $m$ or $p$ or both be zero,
in which case the formal type parameter list of the class $C$
and/or the actual type argument list of the redirectee constructor is omitted (\ref{generics}).
}
\LMHash{}
It is a compile-time error if $k$ explicitly specifies a default value for an optional parameter.
\commentary{
Default values specified in $k$ would be ignored, since it is the {\em actual} parameters that are passed to $k'$.
Hence, default values are disallowed.
}
\LMHash{}
It is a compile-time error if a formal parameter of $k'$ has a default value
whose type is not a subtype of the type annotation
on the corresponding formal parameter in $k$.
\commentary{
Note that it is not possible to modify the arguments being passed to $k'$.
}
\rationale{
At first glance, one might think that ordinary factory constructors could simply create instances of other classes and return them, and that redirecting factories are unnecessary.
However, redirecting factories have several advantages:
\begin{itemize}
\item An abstract class may provide a constant constructor that utilizes the constant constructor of another class.
\item A redirecting factory constructor avoids the need for forwarders to repeat the formal parameters and their default values.
\end{itemize}
}
\LMHash{}
It is a compile-time error if $k$ is prefixed with the \CONST{} modifier but $k'$ is not a constant constructor (\ref{constantConstructors}).
\LMHash{}
Let $T_1, \ldots, T_m$ be the actual type arguments passed to $k'$
in the declaration of $k$.
Let $X_1, \ldots, X_m$ be the formal type arguments declared by
the class that contains the declaration of $k'$.
Let $F'$ be the function type of $k'$ (\ref{constructors}).
It is a compile-time error if $[T_1/X_1, \ldots, T_m/X_m]F'$
is not a subtype of the function type of $k$.
\commentary{
In the case where the two classes are non-generic
this is just a subtype check on the function types of the two constructors.
In general, this implies that the resulting object conforms to
the interface of the immediately enclosing class of $k$.
}
\LMHash{}
For the dynamic semantics,
assume that $k$ is a redirecting factory constructor
and $k'$ is the redirectee of $k$.
\LMHash{}
It is a dynamic type error if an actual argument passed in an invocation of $k$
is not a subtype of the actual type (\ref{actualTypeOfADeclaration})
of the corresponding formal parameter in the declaration of $k$.
\LMHash{}
When the redirectee $k'$ is a factory constructor,
execution of $k$ amounts to execution of $k'$ with the actual arguments passed to $k$.
The result of the execution of $k'$ is the result of $k$.
\LMHash{}
When the redirectee $k'$ is a generative constructor,
let $o$ be a fresh instance (\ref{generativeConstructors})
of the class that contains $k'$.
Execution of $k$ then amounts to execution of $k'$ to initialize $o$,
governed by the same rules as an instance creation expression (\ref{instanceCreation}).
If $k$ completed normally then the execution of $k'$ completes normally returning $o$,
otherwise $k'$ completes by throwing the exception and stack trace thrown by $k$.
\subsubsection{Constant Constructors}
\LMLabel{constantConstructors}
\LMHash{}
A {\em constant constructor} may be used to create compile-time constant (\ref{constants}) objects.
A constant constructor is prefixed by the reserved word \CONST{}.
\begin{grammar}
<constantConstructorSignature> ::= \CONST{} <qualified> <formalParameterList>
\end{grammar}
%\commentary{Spell out subtleties: a constant constructor call within the initializer of a constant constructor is treated as a ordinary constructor call (a new), because the arguments cannot be assumed constant anymore. In practice, this means two versions are compiled and analyzed. One for new and one for const.}
\commentary{
All the work of a constant constructor must be handled via its initializers.
}
\LMHash{}
It is a compile-time error if a constant constructor is declared by a class that has a mutable instance variable.
\commentary{
The above refers to both locally declared and inherited instance variables.
}
\LMHash{}
It is a compile-time error if a constant constructor is declared by a class $C$ if any instance variable declared in $C$ is initialized with an expression that is not a constant expression.
\commentary{
A superclass of $C$ cannot declare such an initializer either, because it must necessarily declare constant constructor as well (unless it is \code{Object}, which declares no instance variables).
}
\LMHash{}
The superinitializer that appears, explicitly or implicitly, in the initializer list of a constant constructor must specify a constant constructor of the superclass of the immediately enclosing class or a compile-time error occurs.
\LMHash{}
Any expression that appears within the initializer list of a constant constructor must be a potentially constant expression, or a compile-time error occurs.
\LMHash{}
A {\em potentially constant expression} is an expression $e$ that could be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants of appropriate types, and where $e$ is also a valid expression if all the formal parameters are treated as non-constant variables.
\commentary{
The difference between a potentially constant expression and a constant expression (\ref{const}) deserves some explanation.
The key issue is how one treats the formal parameters of a constructor.
If a constant constructor is invoked from a constant object expression, the actual arguments will be required to be constant expressions.
Therefore, if we were assured that constant constructors were always invoked from constant object expressions, we could assume that the formal parameters of a constructor were compile-time constants.
However, constant constructors can also be invoked from ordinary instance creation expressions (\ref{new}), and so the above assumption is not generally valid.
Nevertheless, the use of the formal parameters of a constant constructor within the constructor is of considerable utility.
The concept of potentially constant expressions is introduced to facilitate limited use of such formal parameters.
Specifically, we allow the usage of the formal parameters of a constant constructor for expressions that involve built-in operators, but not for constant objects, lists and maps.
This allows for constructors such as:
}
\begin{dartCode}
\CLASS{} C \{
\FINAL{} x; \FINAL{} y; \FINAL{} z;
\CONST{} C(p, q): x = q, y = p + 100, z = p + q;
\}
\end{dartCode}
\commentary{
The assignment to \code{x} is allowed under the assumption that \code{q} is constant (even though \code{q} is not, in general a compile-time constant).
The assignment to \code{y} is similar, but raises additional questions.
In this case, the superexpression of \code{p} is \code{p + 100}, and it requires that \code{p} be a numeric constant expression for the entire expression to be considered constant.
The wording of the specification allows us to assume that \code{p} evaluates to an integer.
A similar argument holds for \code{p} and \code{q} in the assignment to \code{z}.
However, the following constructors are disallowed:
}
\begin{dartCode}
\CLASS{} D \{
\FINAL{} w;
\CONST{} D.makeList(p): w = \CONST{} [p]; // \comment{compile-time error}
\CONST{} D.makeMap(p): w = \CONST{} \{``help'': q\}; // \comment{compile-time error}
\CONST{} D.makeC(p): w = \CONST{} C(p, 12); // \comment{compile-time error}
\}
\end{dartCode}
\commentary{
The problem is not that the assignments to \code{w} are not potentially constant; they are.
However, all these run afoul of the rules for constant lists (\ref{lists}), maps (\ref{maps}) and objects (\ref{const}), all of which independently require their subexpressions to be constant expressions.
}
\rationale{
All of the illegal constructors of \code{D} above could not be sensibly invoked via \NEW{}, because an expression that must be constant cannot depend on a formal parameter, which may or may not be constant.
In contrast, the legal examples make sense regardless of whether the constructor is invoked via \CONST{} or via \NEW{}.
Careful readers will of course worry about cases where the actual arguments to \code{C()} are constants, but are not numeric.
This is precluded by the following rule, combined with the rules for evaluating constant objects (\ref{const}).
}
\LMHash{}
When a constant constructor $k$ is invoked from a constant object expression,
it is a compile-time error if
the invocation of $k$ at run time would throw an exception,
and it is a compile-time error if
substitution of the actual arguments for the formal parameters
yields an initializing expression $e$ in the initializer list of $k$
which is not a constant expression.
\commentary{
For instance, if $e$ is \code{a.length}
where \code{a} is a formal argument of $k$ with type \DYNAMIC{},
$e$ is potentially constant and can be used in the initializer list of $k$.
It is an error to invoke $k$ with an argument of type \code{C}
if \code{C} is a class different from \code{String},
even if \code{C} has a \code{length} getter,
and that same expression would evaluate without errors at run time.
}
%Discuss External Constructors in ne subsubsection here
\subsection{Static Methods}
\LMLabel{staticMethods}
\LMHash{}
{\em Static methods} are functions, other than getters or setters, whose declarations are immediately contained within a class declaration and that are declared \STATIC{}.
The static methods of a class $C$ are those static methods declared by $C$.
\LMHash{}
The effect of a static method declaration in class $C$ is to add an instance method with the same name and signature to the \code{Type} object for class $C$ that forwards (\ref{functionDeclarations}) to the static method.
\rationale{
Inheritance of static methods has little utility in Dart.
Static methods cannot be overridden.
Any required static function can be obtained from its declaring library, and there is no need to bring it into scope via inheritance.
Experience shows that developers are confused by the idea of inherited methods that are not instance methods.
Of course, the entire notion of static methods is debatable, but it is retained here because so many programmers are familiar with it.
Dart static methods may be seen as functions of the enclosing library.
}
\commentary{
Static method declarations may conflict with other declarations
(\ref{classMemberConflicts}).
}
\subsection{Superclasses}
\LMLabel{superclasses}
%% TODO(eernst): We need to say that the superclass which is obtained
%% by mixin application is generic when $C$ is generic, or at least
%% when one or more of $C$'s type variables are used by the classes
%% in the \EXTENDS{} or \WITH{} clause of $C$. It says below that
%% these clauses are in the type parameter scope of $C$, but that does
%% not allow us to talk about the superclass as an actual, stand-alone
%% class (unless we start defining nested classes, such that the
%% superclass can be declared in that scope).
\LMHash{}
The superclass $S'$ of a class $C$ whose declaration has a with clause
\code{\WITH{} $M_1, \ldots,\ M_k$}
and an extends clause
\code{\EXTENDS{} $S$}
is the abstract class obtained by application of
mixin composition (\ref{mixins}) $M_k* \cdots * M_1$ to $S$.
The name $S'$ is a fresh identifier.
If no \WITH{} clause is specified then the \EXTENDS{} clause of
a class $C$ specifies its superclass.
If no \EXTENDS{} clause is specified, then either:
\begin{itemize}
\item $C$ is \code{Object}, which has no superclass. OR
\item Class $C$ is deemed to have an \EXTENDS{} clause of the form
\code{\EXTENDS{} Object}, and the rules above apply.
\end{itemize}
\LMHash{}
It is a compile-time error to specify an \EXTENDS{} clause
for class \code{Object}.
\begin{grammar}
<superclass> ::= \EXTENDS{} <type>
\end{grammar}
%The superclass clause of a class C is processed within the enclosing scope of the static scope of C.
%\commentary{
%This means that in a generic class, the type parameters of the generic are available in the superclass clause.
%}
\LMHash{}
The scope of the \EXTENDS{} and \WITH{} clauses of a class $C$ is the type-parameter scope of $C$.
\LMHash{}
It is a compile-time error if the type in the \EXTENDS{} clause of a class $C$ is
a type variable (\ref{generics}), a type alias (\ref{typedef}),
an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
\commentary{
The type parameters of a generic class are available in the lexical scope of the superclass clause, potentially shadowing classes in the surrounding scope.
The following code is therefore illegal and should cause a compile-time error:
}
\begin{dartCode}
class T \{\}
\\
/* Compilation error: Attempt to subclass a type parameter */
class G<T> extends T \{\}
\end{dartCode}
\LMHash{}
%% TODO(eernst): Consider replacing all occurrences of `a superclass`
%% by `a direct or indirect superclass`, because it's too confusing.
A class $S$ is {\em a superclass} of a class $C$ if{}f either:
\begin{itemize}
\item $S$ is the superclass of $C$, or
\item $S$ is a superclass of a class $S'$,
and $S'$ is the superclass of $C$.
\end{itemize}
\LMHash{}
It is a compile-time error if a class $C$ is a superclass of itself.
\subsubsection{Inheritance and Overriding}
\LMLabel{inheritanceAndOverriding}
\LMHash{}
Let $C$ be a class, let $A$ be a superclass of $C$, and
let $S_1, \ldots, S_k$ be superclasses of $C$ that are also subclasses of $A$.
$C$ {\em inherits} all concrete, accessible instance members of $A$
that have not been overridden by a concrete declaration in $C$ or in at least one of $S_1, \ldots, S_k$.
\rationale{
It would be more attractive to give a purely local definition of inheritance, that depended only on the members of the direct superclass $S$.
However, a class $C$ can inherit a member $m$ that is not a member of its superclass $S$.
This can occur when the member $m$ is private to the library $L_1$ of $C$,
whereas $S$ comes from a different library $L_2$,
but the superclass chain of $S$ includes a class declared in $L_1$.
}
\LMHash{}
A class may override instance members that would otherwise have been inherited from its superclass.
\LMHash{}
Let $C = S_0$ be a class declared in library $L$, and
let $\{S_1, \ldots, S_k\}$ be the set of all superclasses of $C$,
where $S_i$ is the superclass of $S_{i-1}$ for $i \in 1 .. k$.
\commentary{This means that $S_k$ is the built-in class \code{Object}.}
Let $C$ declare a concrete member $m$, and
let $m'$ be a concrete member of $S_j, j \in 1 .. k$, that has the same name as $m$,
such that $m'$ is accessible to $L$.
Then $m$ overrides $m'$
if $m'$ is not already overridden by a concrete member of at least one of $S_1, \ldots, S_{j-1}$
and neither $m$ nor $m'$ are instance variables.
\commentary{
Instance variables never override each other.
The getters and setters induced by instance variables do.
}
\rationale{
Again, a local definition of overriding would be preferable, but fails to account for library privacy.
}
\LMHash{}
Whether an override is legal or not is described elsewhere in this specification (see \ref{instanceMethods}, \ref{getters} and \ref{setters}).
\commentary{
For example getters may not legally override methods and vice versa.
Setters never override methods or getters, and vice versa, because their names always differ.
}
\rationale{
It is nevertheless convenient to define the override relation between members in this way, so that we can concisely describe the illegal cases.
}
\commentary{
Note that instance variables do not participate in the override relation, but the getters and setters they induce do.
Also, getters don't override setters and vice versa.
Finally, static members never override anything.
}
\LMHash{}
Let $C$ be a concrete class
whose interface has an accessible member $m$ named \id{}.
It is a compile-time error if $C$ does not have
a concrete member $m'$ named \id{} which is a correct override of $m$,
unless $C$ has a concrete method named \code{noSuchMethod}
which is different from the one in the built-in class \code{Object},
and $C$ does not have a concrete member named \id.
\commentary{
So it is an error even if $C$ does have a concrete member $m'$ named \id{}
if $m'$ is an \emph{incorrect} override of $m$,
also when $C$ has a \code{noSuchMethod} which is not from \code{Object}.
Note that it is allowed to let inaccessible methods remain unimplemented;
invocations of such methods will be redirected to \code{noSuchMethod}.
}
%% TODO(eernst): Why don't we just get rid of this list entirely?
%% It's 'for convenience', but that's not otherwise a priority in this
%% document, it is more important that it is correct and consistent.
\commentary{
For convenience, here is a summary of the relevant rules,
using `error' to denote compile-time errors.
Remember that this is not normative.
The controlling language is in the relevant sections of the specification.
\begin{enumerate}
\item There is only one namespace
for getters, setters, methods and constructors (\ref{scoping}).
An instance or static variable $f$ introduces a getter $f$,
and a mutable instance or static variable $f$ also introduces a setter
\code{$f$=} (\ref{instanceVariables}, \ref{variables}).
When we speak of members here, we mean
accessible instance or static variables, getters, setters, and methods
(\ref{classes}).
\item You cannot have two members with the same name in the same class---be
they declared or inherited (\ref{scoping}, \ref{classes}).
\item Static members are never inherited.
\item It is an error if you have a static member named $m$ in your class
and an instance member of the same name (\ref{classMemberConflicts}).
\item It is an error if you have a static setter \code{$v$=},
and an instance member $v$ (\ref{setters}).
\item It is an error if you have a static getter $v$
and an instance setter \code{$v$=} (\ref{getters}).
\item If you define an instance member named $m$,
and your superclass has an instance member of the same name,
they override each other.
This may or may not be legal.
\item \label{typeSigAssignable}
%% TODO(eernst): This is commentary, but we may need to adjust it
%% to say 'correctly overrides'.
If two members override each other,
it is an error if their type signatures are not assignable to each other
(\ref{instanceMethods}, \ref{getters}, \ref{setters})
%% TODO(eernst): Revisit relative to the new subtyping.md rules.
(and since these are function types, this means the same as
"subtypes of each other").
\item \label{requiredParams}
If two members override each other,
it is an error if the overriding member has
more required parameters than the overridden one (\ref{instanceMethods}).
\item \label{optionalPositionals}
If two members override each other,
it is an error if the overriding member has
fewer positional parameters than the overridden one (\ref{instanceMethods}).
\item \label{namedParams}
If two members override each other,
it is an error if the overriding member does not have
all the named parameters that the overridden one has (\ref{instanceMethods}).
\item Setters, getters and operators never have
optional parameters of any kind;
it's an error (\ref{operators}, \ref{getters}, \ref{setters}).
\item
It is an error if a member has the same name as its enclosing class
(\ref{classes}).
\item A class has an implicit interface (\ref{classes}).
\item Superinterface members are not inherited by a class,
but are inherited by its implicit interface.
Interfaces have their own inheritance rules
(\ref{interfaceInheritanceAndOverriding}).
\item A member is abstract if
it has no body and is not labeled \EXTERNAL{}
(\ref{abstractInstanceMembers}, \ref{externalFunctions}).
\item A class is abstract if{}f it is explicitly labeled \ABSTRACT{}.
\item It is an error if a concrete class has an abstract member
(declared or inherited), and there is no \code{noSuchMethod}.
\item It is an error to call a non-factory constructor of an abstract class
using an instance creation expression (\ref{instanceCreation}),
such a constructor may only be invoked from another constructor
using a super invocation (\ref{superInvocation}).
\item If a class defines an instance member named $m$,
and any of its superinterfaces have a member named $m$,
the interface of the class contains the $m$ from the class itself.
\item
%% TODO(eernst): This needs to be updated when we introduce the
%% new override/conflict rules.
An interface inherits all members of its superinterfaces
that are not overridden and not members of multiple superinterfaces.
\item
%% TODO(eernst): This must be rewritten when we introduce the new
%% override/conflict rules.
If multiple superinterfaces of an interface
define a member with the same name $m$,
then at most one member is inherited.
%% TODO(eernst): Switch to use 'correctly overrides' terminology.
That member (if it exists) is the one whose type is a subtype
of all the others.
If there is no such member, then an error occurs
(\ref{interfaceInheritanceAndOverriding}).
\item Rule \ref{typeSigAssignable} applies to interfaces as well as classes
(\ref{interfaceInheritanceAndOverriding}).
\item It is an error if a concrete class does not have an implementation
for a method in its interface
unless it has a concrete \code{noSuchMethod} method
(\ref{superinterfaces})
distinct from the one in class \code{Object}.
\item The identifier of a named constructor cannot be
the same as the name of a static member declared in the same class
(\ref{classMemberConflicts}).
\end{enumerate}
}
\subsection{Superinterfaces}
\LMLabel{superinterfaces}
% what about rules about classes that fail to implement their interfaces?
\LMHash{}
A class has a set of direct superinterfaces.
This set includes the interface of its superclass and the interfaces specified in the \IMPLEMENTS{} clause of the class.
\begin{grammar}
<interfaces> ::= \IMPLEMENTS{} <typeList>
\end{grammar}
\LMHash{}
The scope of the \IMPLEMENTS{} clause of a class $C$ is the type-parameter scope of $C$.
\LMHash{}
It is a compile-time error if an element in the type list of the \IMPLEMENTS{} clause of a class $C$ is
a type variable (\ref{generics}), a type alias (\ref{typedef}),
an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
It is a compile-time error if two elements in the type list of the \IMPLEMENTS{} clause of a class $C$ specifies the same type $T$.
It is a compile-time error if the superclass of a class $C$ is one of the elements of the type list of the \IMPLEMENTS{} clause of $C$.
It is a compile-time error if a class $C$ has two superinterfaces that are different instantiations of the same generic class.
\commentary{For example, a class may not have both `List<int>` and `List<num>` as superinterfaces.}
% If we need to allow multiple instantiations, they'll need to have a most
% specific one, and then we can add the following clause
%, unless it implements one that is a subtype of all the other. \commentary{This ensures that each class implements one {\em most specific} version of a generic class' interface.}
\rationale{
One might argue that it is harmless to repeat a type in the superinterface list, so why make it an error? The issue is not so much that the situation described in program source is erroneous, but that it is pointless.
As such, it is an indication that the programmer may very well have meant to say something else - and that is a mistake that should be called to her or his attention.
}
\LMHash{}
It is a compile-time error if the interface of a class $C$ is a superinterface of itself.
\LMHash{}
Let $C$ be a concrete class that does not have a concrete \code{noSuchMethod()} method distinct from the one declared in class \code{Object}.
%% TODO(eernst): Adjust to use 'correctly overrides' terminology.
It is a compile-time error if the implicit interface of $C$ has an accessible instance member $m$ of type $F$,
and $C$ does not declare or inherit a corresponding concrete instance member $m$ of type $F'$ such that $F' <: F$.
\commentary{
A class does not inherit members from its superinterfaces.
However, its implicit interface does.
}
\rationale{
We choose to raise these compile-time errors only for concrete classes;
an abstract class might legitimately be designed with the expectation that concrete subclasses will implement part of the interface.
We also disable these errors if a concrete \code{noSuchMethod()} declaration is present or inherited from any class other than \code{Object},
unless a concrete member $m$ is declared or inherited.
The point is that there is an error to disable,
so the signature of the concrete $m$ is not a correct override of the signature in the class interface.
Otherwise, when all such errors have been disabled,
the supported interface is going to be implemented via \code{noSuchMethod()}
and no actual declarations of the implemented interface's members are needed.
This allows proxy classes for specific types to be implemented without provoking errors.
}
\LMHash{}
%% TODO(eernst): Switch to use 'correctly overrides' terminology.
It is a compile-time error if the implicit interface of a class $C$ has an instance member $m$ of type $F$ and $C$ declares or inherits a corresponding instance member $m$ of type $F'$ if $F'$ is not a subtype of $F$.
\rationale{
However, if a class does explicitly declare a member that conflicts with its superinterface, this always yields an error.
}
\subsection{Class Member Conflicts}
\LMLabel{classMemberConflicts}
\LMHash{}
Some pairs of class member declarations cannot coexist,
even though they do not both introduce the same name into the same scope.
This section specifies these errors.
\LMHash{}
The {\em basename} of a getter or method named $n$ is $n$;
the basename of a setter named \code{$n$=} is $n$.
\LMHash{}
Let $C$ be a class.
It is a compile-time error if $C$ declares a
\begin{itemize}
\item constructor named \code{$C$.$n$} and a static member with basename $n$.
\item getter or a setter with basename $n$, and has a method named $n$.
\item method named $n$, and has a getter or a setter with basename $n$.
\item static member with basename $n$, and has an instance member with basename $n$.
\end{itemize}
These errors occur when the getters or setters are defined explicitly
as well as when they are induced by variable declarations.
\section{Interfaces}
\LMLabel{interfaces}
\LMHash{}
An {\em interface} defines how one may interact with an object.
An interface has methods, getters and setters and a set of superinterfaces.
\subsection{Superinterfaces}
\LMLabel{interfaceSuperinterfaces}
\LMHash{}
An interface has a set of direct superinterfaces.
\LMHash{}
An interface $J$ is a superinterface of an interface $I$ if{}f either $J$ is a direct superinterface of $I$ or $J$ is a superinterface of a direct superinterface of $I$.
\subsubsection{Inheritance and Overriding}
\LMLabel{interfaceInheritanceAndOverriding}
\LMHash{}
Let $J$ be an interface and $K$ be a library.
We define $inherited(J, K)$ to be the set of members $m$ such that all of the following hold:
\begin{itemize}
\item $m$ is accessible to $K$ and
\item $A$ is a direct superinterface of $J$ and either
\begin{itemize}
\item $A$ declares a member $m$ or
\item $m$ is a member of $inherited(A, K)$.
\end{itemize}
\item $m$ is not overridden by $J$.
\end{itemize}
\LMHash{}
Furthermore, we define $overrides(J, K)$ to be the set of members $m'$ such that all of the following hold:
\begin{itemize}
\item $J$ is the implicit interface of a class $C$.
\item $C$ declares a member $m$.
\item $m'$ has the same name as $m$.
\item $m'$ is accessible to $K$.
\item $A$ is a direct superinterface of $J$ and either
\begin{itemize}
\item $A$ declares a member $m'$ or
\item $m'$ is a member of $inherited(A, K)$.
\end{itemize}
\end{itemize}
\LMHash{}
Let $I$ be the implicit interface of a class $C$ declared in library $L$.
$I$ {\em inherits} all members of $inherited(I, L)$ and $I$ {\em overrides} $m'$ if $m' \in overrides(I, L)$.
\LMHash{}
All the compile-time errors pertaining to the overriding of instance members given in section \ref{classes} above hold for overriding between interfaces as well.
\LMHash{}
It is a compile-time error if $m$ is a method and $m'$ is a getter, or if $m$ is a getter and $m'$ is a method.
%Let $I = S_0$ be the implicit interface of a class $C$ declared in library $L$, and let $\{S_1, \ldots, S_k\}$ be the set of all superinterfaces of $I$.
%Let $I$ be the implicit interface of a class $C$. $I$ inherits any instance members of its superinterfaces that are not overridden by members declared in $C$.
% tighten definition? do we need chain as for classes? Definition for interface override?
\LMHash{}
However, if the above rules would cause multiple members $m_1, \ldots, m_k$ with the same name $n$ to be inherited (because identically named members existed in several superinterfaces) then at most one member is inherited.
\LMHash{}
If some but not all of the $m_i, 1 \le i \le k$ are getters, a compile-time error occurs.
\LMHash{}
%% TODO(eernst): Adjust to use 'correctly overrides' terminology.
Otherwise, if the static types $T_1, \ldots, T_k$ of the members $m_1, \ldots, m_k$ are not identical then there must be an $x \in 1 .. k$ such that $T_x <: T_i$ for all $i \in 1 .. k$,
or a compile-time error occurs.
The member that is inherited is $m_x$, if it exists.
\section{Mixins}
\LMLabel{mixins}
\LMHash{}
A mixin describes the difference between a class and its superclass.
A mixin is always derived from an existing class declaration.
\LMHash{}
It is a compile-time error to derive a mixin from a class which explicitly declares a generative constructor.
It is a compile-time error to derive a mixin from a class which has a superclass other than \code{Object}.
\rationale{
This restriction is temporary.
We expect to remove it in later versions of Dart.
The restriction on constructors simplifies the construction of mixin applications because the process of creating instances is simpler.
}
\subsection{Mixin Application}
\LMLabel{mixinApplication}
\LMHash{}
A mixin may be applied to a superclass, yielding a new class.
Mixin application occurs when one or more mixins are mixed into a class declaration via its \WITH{} clause.
The mixin application may be used to extend a class per section \ref{classes};
alternatively, a class may be defined as a mixin application as described in this section.
It is a compile-time error if an element in the type list of the \WITH{} clause of a mixin application is
a type variable (\ref{generics}), a type alias (\ref{typedef}),
an enumerated type (\ref{enums}), a malformed type (\ref{staticTypes}),
a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}),
or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}).
\begin{grammar}
<mixinApplicationClass> ::= <identifier> <typeParameters>? `=' <mixinApplication> `;'
<mixinApplication> ::= <type> <mixins> <interfaces>?
\end{grammar}
\LMHash{}
A mixin application of the form \code{$S$ \WITH{} $M$;} for the name $N$ defines a class $C$ with superclass $S$ and name $N$.
\LMHash{}
A mixin application of the form \code{$S$ \WITH{} $M_1,\ \ldots,\ M_k$;} for the name $N$ defines a class $C$ whose superclass is the application of the mixin composition (\ref{mixinComposition}) $M_{k-1} * \ldots * M_1$ to $S$ of a name that is a fresh identifer, and whose name is $N$.
\rationale{The name of the resulting class is necessary because it is part of the names of the introduced constructors.}
\LMHash{}
In both cases above, $C$ declares the same instance members as $M$ (respectively, $M_k$),
and it does not declare any static members.
If any of the instance variables of $M$ (respectively, $M_k$) have initializers,
they are executed in the instance scope of $M$ (respectively, $M_k$)
to initialize the corresponding instance variables of $C$.
\LMHash{}
Let $L_C$ be the library containing the mixin application.
\commentary{That is, the library containing the clause \code{$S$ \WITH{} $M$}
or the clause \code{$S_0$ \WITH{} $M_1$, \ldots,\ $M_k$, $M$}.}
Let $N_C$ be the name of the mixin application class $C$,
let $S$ be the superclass of $C$, and let $S_N$ be the name of $S$.
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, $\ldots$, $T_{k}$ $a_{k}$)} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
\begin{dartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots, $T_{k}$ $a_{k}$): $\SUPER_q$($a_{1}$, $\ldots$, $a_{k}$);
\end{dartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
which denote the superclass, by $N_C$, and $\SUPER_q$ is obtained from $S_q$ by
replacing occurrences of $S_N$ which denote the superclass by \SUPER{}.
If $S_q$ is a generative const constructor, and $M$ does not declare any
fields, $C_q$ is also a const constructor.
\LMHash{}
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d_p$])} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
\begin{dartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, [$T_{k+1}$ $a_{k+1}$ = $d'_{1}$, \ldots , $T_{k+p}$ $a_{k+p}$ = $d'_p$])
: $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$, \ldots, $a_p$);
\end{dartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$,
which denote the superclass, by $N_C$,
$\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
which denote the superclass by \SUPER{},
and $d'_i$, $i \in 1..p$, is a constant expression evaluating
to the same value as $d_i$.
If $S_q$ is a generative const constructor, and $M$ does not declare any
fields, $C_q$ is also a const constructor.
\LMHash{}
For each generative constructor of the form \code{$S_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d_n$\})} of $S$ that is accessible to $L_C$, $C$ has an implicitly declared constructor of the form
\begin{dartCode}
$C_q$($T_{1}$ $a_{1}$, \ldots , $T_{k}$ $a_{k}$, \{$T_{k+1}$ $a_{k+1}$ = $d'_1$, \ldots , $T_{k+n}$ $a_{k+n}$ = $d'_n$\})
: $\SUPER_q$($a_{1}$, \ldots , $a_{k}$, $a_{k+1}$: $a_{k+1}$, \ldots, $a_p$: $a_p$);
\end{dartCode}
\noindent
where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
which denote the superclass by $N_C$,
$\SUPER_q$ is obtained from $S_q$ by replacing occurrences of $S_N$
which denote the superclass by \SUPER{},
and $d'_i$, $i \in 1..n$, is a constant expression evaluating to the same value as $d_i$.
If $S_q$ is a generative const constructor, and $M$ does not declare any
fields, $C_q$ is also a const constructor.
\LMHash{}
If the mixin application class declares interfaces, the resulting class also implements those interfaces.
\LMHash{}
It is a compile-time error if $S$ is an enumerated type (\ref{enums}) or a malformed type.
It is a compile-time error if $M$ (respectively, any of $M_1, \ldots, M_k$) is an enumerated type (\ref{enums}) or a malformed type.
It is a compile-time error if a well formed mixin cannot be derived from $M$ (respectively, from each of $M_1, \ldots, M_k$).
\LMHash{}
Let $K$ be a class declaration with the same constructors, superclass and interfaces as $C$, and the instance members declared by $M$ (respectively $M_1, \ldots, M_k$).
It is a compile-time error if the declaration of $K$ would cause a compile-time error.
\commentary{
If, for example,
$M$ declares an instance member $im$ whose type is at odds with the type of a member of the same name in $S$,
this will result in a compile-time error just as if we had defined $K$ by means of an ordinary class declaration extending $S$, with a body that included $im$.
}
\LMHash{}
The effect of a class definition of the form \code{\CLASS{} $C$ = $M$; } or the form \code{\CLASS{} $C<T_1, \ldots,\ T_n>$ = $M$; } in library $L$ is to introduce the name $C$ into the scope of $L$, bound to the class (\ref{classes}) defined by the mixin application $M$ for the name $C$.
The name of the class is also set to $C$.
If{}f the class is prefixed by the built-in identifier \ABSTRACT{}, the class being defined is an abstract class.
\LMHash{}
Let $M_A$ be a mixin derived from a class $M$ with direct superclass $S_{static}$, e.g., as defined by the class declaration \code{class M extends S$_{static}$ \{ \ldots \}}.
\LMHash{}
Let $A$ be an application of $M_A$.
It is a compile-time error if the superclass of $A$ is not a subtype of $S_{static}$.
\LMHash{}
Let $C$ be a class declaration that includes $M_A$ in a with clause.
It is a compile-time error if $C$ does not implement, directly or indirectly, all the direct superinterfaces of $M$.
\subsection{Mixin Composition}
\LMLabel{mixinComposition}
\rationale{
Dart does not directly support mixin composition, but the concept is useful when defining how the superclass of a class with a mixin clause is created.
}
\LMHash{}
The {\em composition of two mixins}, $M_1<T_1, \ldots, T_{k_{M_1}}>$ and $M_2<U_1, \ldots, U_{k_{M_2}}>$, written $M_1<T_1, \ldots, T_{k_{M_1}}> * M_2<U_1, \ldots, U_{k_{M_2}}>$ defines an anonymous mixin such that for any class $S<V_1, \ldots, V_{k_S}>$, the application of
$M_1<T_1, \ldots, T_{k_{M_1}}> * M_2<U_1, \ldots, U_{k_{M_2}}>$
to $S<V_1, \ldots, V_{k_S}>$ for the name $C$ is equivalent to
\begin{dartCode}
\ABSTRACT{} \CLASS{} $C<T_1, \ldots, T_{k_{M_1}}, U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> = $
$Id_2<U_1, \ldots, U_{k_{M_2}}, V_1 \ldots V_{k_S}>$ \WITH{} $M_1 <T_1, \ldots, T_{k_{M_1}}>$;
\end{dartCode}
where $Id_2$ denotes
\begin{dartCode}
\ABSTRACT{} \CLASS{} $Id_2<U_1, \ldots, U_{k_{M_2}}, V_1, \ldots, V_{k_S}> =$
$S<V_1, \ldots, V_{k_S}>$ \WITH{} $M_2<U_1, \ldots, U_{k_{M_2}}>$;
\end{dartCode}
and $Id_2$ is a unique identifier that does not exist anywhere in the program.
\rationale{
The intermediate classes produced by mixin composition are regarded as abstract because they cannot be instantiated independently.
They are only introduced as anonymous superclasses of ordinary class declarations and mixin applications.
Consequently, no errors are raised if a mixin composition includes abstract members, or incompletely implements an interface.
}
\LMHash{}
Mixin composition is associative.
\commentary{
Note that any subset of $M_1$, $M_2$ and $S$ may or may not be generic.
For any non-generic declaration, the corresponding type parameters may be elided, and if no type parameters remain in the derived declarations $C$ and/or $Id_2$ then the those declarations need not be generic either.
}
\section{Enums}
\LMLabel{enums}
\LMHash{}
An {\em enumerated type}, or {\em enum}, is used to represent a fixed number of constant values.
\begin{grammar}
<enumType> ::= <metadata> \ENUM{} <identifier>
\gnewline{} `{' <enumEntry> (`,' <enumEntry>)* (`,')? `}'
<enumEntry> ::= <metadata> <identifier>
\end{grammar}
\LMHash{}
The declaration of an enum of the form
\code{$m$ \ENUM{} $E$ \{$m_0\,\,\id_0, \ldots,\ m_{n-1}\,\,\id_{n-1}$\}}
has the same effect as a class declaration
\begin{dartCode}
$m$ \CLASS{} $E$ \{
\FINAL{} int index;
\CONST{} $E$(\THIS{}.index);
$m_0$ \STATIC{} \CONST{} $E$ $\id_0$ = \CONST{} $E$(0);
$\ldots$
$m_{n-1}$ \STATIC{} \CONST{} $E$ $\id_{n-1}$ = const $E$(n - 1);
\STATIC{} \CONST{} List<$E$> values = const <$E$>[\id$_0, \ldots, $ \id$_{n-1}$];
String toString() => \{ 0: `$E$.\id$_0$', $\ldots$, n-1: `$E$.\id$_{n-1}$'\}[index]
\}
\end{dartCode}
\commentary{
It is also a compile-time error to subclass, mix-in or implement an enum or to explicitly instantiate an enum.
These restrictions are given in normative form in sections \ref{superclasses}, \ref{superinterfaces}, \ref{mixinApplication} and \ref{instanceCreation} as appropriate.
}
\section{Generics}
\LMLabel{generics}
\LMHash{}
A class declaration (\ref{classes}), type alias (\ref{typedef}), or function (\ref{functions}) $G$ may be {\em generic}, that is, $G$ may have formal type parameters declared.
\LMHash{}
When an entity in this specification is described as generic,
and the special case is considered where the number of type arguments is zero,
the type argument list should be omitted.
\commentary{
This allows non-generic cases to be included implicitly as special cases.
For example,
an invocation of a non-generic function arises as the special case
where the function takes zero type arguments,
and zero type arguments are passed.
In this situation some operations are also omitted (have no effect), e.g.,
operations where formal type parameters are replaced by actual type arguments.
}
\LMHash{}
A {\em generic class declaration} introduces a generic class into the enclosing library scope.
A {\em generic class} is a mapping that accepts a list of actual type arguments and maps them to a class.
Consider a generic class declaration $G$ named \code{C} with formal type parameter declarations
$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$,
and a parameterized type $T$ of the form \code{C<$T_1, \ldots,\ T_l$>}.
\LMHash{}
It is a compile-time error if $m \not= l$.
It is a compile-time error if $T$ is not well-bounded
(\ref{superBoundedTypes}).
\commentary{
That is, if the number of type arguments is wrong,
or one or more of the upper bounds has been violated.
}
\LMHash{}
Otherwise, said parameterized type \code{C<$T_1, \ldots,\ T_m$>} denotes an application of the generic class declared by $G$ to the type arguments $T_1, \ldots, T_m$.
This yields a class $C'$ whose members are equivalent to those of a class declaration which is obtained from the declaration of $G$ by replacing each occurrence of $X_j$ by $T_j$.
\commentary{
% TODO(eernst): make sure this list of properties is complete.
Other properties of $C'$ such as the subtype relationships are specified elsewhere (\ref{interfaceTypes}).
}
\LMHash{}
A {\em generic type alias} introduces a mapping from actual type argument lists to types.
Consider a generic type alias declaration $G$ named \code{F} with formal type parameter declarations
$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$,
and right hand side $T$,
and the parameterized type $S$ of the form \code{F<$T_1, \ldots,\ T_l$>}.
\LMHash{}
It is a compile-time error if $m \not= l$.
It is a compile-time error if $S$ is not well-bounded
(\ref{superBoundedTypes}).
\commentary{
That is, if the number of type arguments is wrong,
or one or more of the upper bounds has been violated.
}
\LMHash{}
Otherwise, said parameterized type
\code{F<$T_1, \ldots,\ T_m$>}
denotes an application of the mapping denoted by $G$ to the type arguments
$T_1, \ldots, T_m$.
This yields the type
$[T_1/X_1, \ldots, T_m/X_m]T$.
\commentary{
A generic type alias does not correspond to any entities at run time,
it is only an alias for an existing type.
Hence, we may consider it as syntactic sugar which is eliminated before the program runs.
}
\LMHash{}
A {\em generic type} is a type which is introduced by
a generic class declaration or a generic type alias,
or it is the type \code{FutureOr}.
\LMHash{}
A {\em generic function declaration} introduces a generic function (\ref{formalParameters}) into the enclosing scope.
Consider a function invocation expression of the form
\code{f<$T_1, \ldots,\ T_l$>(\ldots)},
where the static type of \code{f} is a generic function type with formal type parameters
$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$.
\LMHash{}
It is a compile-time error if $m \not= l$.
It is a compile-time error if there exists a $j$
such that $T_j$ is not a subtype of $[T_1/X_1, \ldots, T_m/X_m]B_j$.
\commentary{
That is, if the number of type arguments is wrong,
or if the $j$th actual type argument is not a subtype of the corresponding bound,
where each formal type parameter has been replaced by the corresponding actual type argument.
}
\begin{grammar}
<typeParameter> ::= <metadata> <identifier> (\EXTENDS{} <type>)?
<typeParameters> ::= `<' <typeParameter> (`,' <typeParameter>)* `>'
\end{grammar}
\LMHash{}
A type parameter $T$ may be suffixed with an \EXTENDS{} clause that specifies the {\em upper bound} for $T$.
If no \EXTENDS{} clause is present, the upper bound is \code{Object}.
It is a compile-time error if a type parameter is a supertype of its upper bound
when that upper bound is itself a type variable.
\commentary{
This prevents circular declarations like
\code{X \EXTENDS{} X}
and
\code{X \EXTENDS{} Y, Y \EXTENDS{} X}.
}
\LMHash{}
Type parameters are declared in the type parameter scope of a class or function.
The type parameters of a generic $G$ are in scope in the bounds of all of the type parameters of $G$.
The type parameters of a generic class declaration $G$ are also in scope in the \EXTENDS{} and \IMPLEMENTS{} clauses of $G$ (if these exist) and in the body of $G$.
However, a type parameter of a generic class is considered to be a malformed type when referenced by a static member.
\commentary{
The scopes associated with the type parameters of a generic function are described in (\ref{formalParameters}).
}
\rationale{
The restriction on static members is necessary since a type variable has no meaning in the context of a static member,
because statics are shared among all generic instantiations of a generic class.
However, a type variable may be referenced from an instance initializer,
even though \THIS{} is not available.
}
\commentary{
Because type parameters are in scope in their bounds, we support F-bounded quantification (if you don't know what that is, don't ask).
This enables typechecking code such as:
}
\begin{dartCode}
\CLASS{} Ordered<T> \{
operator >(T x);
\}
\CLASS{} Sorter<T \EXTENDS{} Ordered<T\gtgt{} \{
sort(List<T> l) {... l[n] < l[n+1] ...}
\}
\end{dartCode}
\commentary{
Even where type parameters are in scope there are numerous restrictions at this time:
\begin{itemize}
\item[$\bullet$] A type parameter cannot be used to name a constructor in an instance creation expression (\ref{instanceCreation}).
\item[$\bullet$] A type parameter cannot be used as a superclass or superinterface (\ref{superclasses}, \ref{superinterfaces}, \ref{interfaceSuperinterfaces}).
\item[$\bullet$] A type parameter cannot be used as a generic type.
\end{itemize}
The normative versions of these are given in the appropriate sections of this specification.
Some of these restrictions may be lifted in the future.
}
%The {\em induced type set}, $S$, of a parameterized type $T$ is the set consisting of
%\begin{itemize}
%\item The supertypes of any type in $S$.
%\item The type arguments of any parameterized type in $S$.
%\end{itemize}
%Let $P$ be the generic instantiation of a generic type with its own type parameters. It is a compile-time error if the induced type set of $P$ is not finite.
%\rationale {A typical recursive type declaration such as}
%\begin{dartCode}
%\CLASS{} B<S> \{\}
%\CLASS{} D<T> \EXTENDS{} B<D<T$>>$ \{\}
%\end{dartCode}
%\rationale{
%poses no problem under this rule. The generic instantiation \code{D<T>} has an induced
%set consisting of: \code{B<D<T$>>$, Object, D<T>, T}. However, the following variant
%}
%\begin{dartCode}
%\CLASS{} B<S> \{\}
%\CLASS{} D<T> \EXTENDS{} B<D<D<T$>>>$ \{\}
%\end{dartCode}
%\rationale{
%is disallowed. Consider again the generic instantiation \code{D<T>}. It leads to the
%superclass \code{B<D<D<T$>>>$}, and so adds \code{D<D$<$T$>>$} to the induced set. The latter in turn leads to \code{B<D<D<D<T$>>>>$} and \code{D<D<D<T$>>>$}
%and so on ad infinitum.}
%\commentary{
%The above requirement does not preclude the use of arbitrary recursive types in the body of a generic class. }
%A generic has a type parameter scope. The enclosing scope of a type parameter scope of a generic G is the enclosing scope of G.
%class T {...}
%class G<T> extends T;
%By current rules, this is illegal. Make sure we preserve this.
\subsection{Variance}
\LMLabel{variance}
\LMHash{}
We say that a type $S$ {\em occurs covariantly} in a type $T$ if{}f
$S$ occurs in a covariant position in $T$,
but not in a contravariant position,
and not in an invariant position.
\LMHash{}
We say that a type $S$ {\em occurs contravariantly} in a type $T$ if{}f
$S$ occurs in a contravariant position in $T$,
but not in a covariant position,
and not in an invariant position.
\LMHash{}
We say that a type $S$ {\em occurs invariantly} in a type $T$ if{}f
$S$ occurs in an invariant position in $T$,
or $S$ occurs in a covariant position as well as a contravariant position.
\LMHash{}
We say that a type $S$ occurs {\em in a covariant position} in a type $T$
if{}f one of the following conditions is true:
\begin{itemize}
\item $T$ is $S$
\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>}
where $G$ denotes a generic class
and $S$ occurs in a covariant position in $S_j$ for some $j \in 1 .. n$.
\item $T$ is of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>($S_1\ x_1, \ldots$)}
where the type parameter list may be omitted,
and $S$ occurs in a covariant position in $S_0$.
\item $T$ is of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])}
\noindent
or of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})}
\noindent
where the type parameter list and each default value may be omitted,
and $S$ occurs in a contravariant position in $S_j$
for some $j \in 1 .. n$.
\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a parameterized type alias such that
$j \in 1 .. n$,
the formal type parameter corresponding to $S_j$ is covariant,
and $S$ occurs in a covariant position in $S_j$.
\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a parameterized type alias such that
$j \in 1 .. n$,
the formal type parameter corresponding to $S_j$ is contravariant,
and $S$ occurs in a contravariant position in $S_j$.
\end{itemize}
\LMHash{}
We say that a type $S$ occurs {\em in a contravariant position} in a type $T$
if{}f one of the following conditions is true:
\begin{itemize}
\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>}
where $G$ denotes a generic class
and $S$ occurs in a contravariant position in $S_j$
for some $j \in 1 .. n$.
\item $T$ is of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>($S_1\ x_1, \ldots$)}
where the type parameter list may be omitted,
and $S$ occurs in a contravariant position in $S_0$.
\item $T$ is of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])}
\noindent
or of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})}
\noindent
where the type parameter list and each default value may be omitted,
and $S$ occurs in a covariant position in $S_j$
for some $j \in 1 .. n$.
\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a parameterized type alias such that
$j \in 1 .. n$,
the formal type parameter corresponding to $S_j$ is covariant,
and $S$ occurs in a contravariant position in $S_j$.
\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a parameterized type alias such that
$j \in 1 .. n$,
the formal type parameter corresponding to $S_j$ is contravariant,
and $S$ occurs in a covariant position in $S_j$.
\end{itemize}
\LMHash{}
We say that a type $S$ occurs {\em in an invariant position} in a type $T$
if{}f one of the following conditions is true:
\begin{itemize}
\item $T$ is of the form \code{$G$<$S_1,\ \ldots,\ S_n$>}
where $G$ denotes a generic class or a parameterized type alias,
and $S$ occurs in an invariant position in $S_j$ for some $j \in 1 .. n$.
\item $T$ is of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ [$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$])}
\noindent
or of the form
\code{$S_0$ \FUNCTION<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>}
\code{\quad($S_1\ x_1, \ldots,\ S_k\ x_k,
$ \{$S_{k+1}\ x_{k+1} = d_{k+1}, \ldots,\ S_n\ x_n = d_n$\})}
\noindent
where the type parameter list and each default value may be omitted,
and $S$ occurs in an invariant position in $S_j$
for some $j \in 0 .. n$,
or $S$ occurs in $B_i$
for some $i \in 1 .. m$.
\item $T$ is of the form \code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a parameterized type alias,
$j \in 1 .. n$,
the formal type parameter corresponding to $S_j$ is invariant,
and $S$ occurs in $S_j$.
\end{itemize}
\LMHash{}
Consider a generic type alias declaration $G$
with formal type parameter declarations
$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$,
and right hand side $T$.
Let $j \in 1 .. m$.
%
We say that {\em the formal type parameter} $X_j$ {\em is invariant}
if{}f $X_j$ occurs invariantly in $T$,
$X_j$ {\em is covariant} if{}f $X_j$ occurs covariantly in $T$,
and $X_j$ {\em is contravariant} if{}f $X_j$ occurs contravariantly in $T$.
\rationale{
Variance gives a characterization of the way a type varies
as the value of a subterm varies, e.g., a type variable:
Assume that $T$ is a type where a type variable $X$ occurs,
and $L$ and $U$ are types such that $L$ is a subtype of $U$.
If $X$ occurs covariantly in $T$
then $[L/X]T$ is a subtype of $[U/X]T$.
Similarly, if $X$ occurs contravariantly in $T$
then $[U/X]T$ is a subtype of $[L/X]T$.
If $X$ occurs invariantly
then $[L/X]T$ and $[U/X]T$ are not guaranteed to be subtypes of each other in any direction.
In short: with covariance, the type covaries;
with contravariance, the type contravaries;
with invariance, all bets are off.
}
\subsection{Super-Bounded Types}
\LMLabel{superBoundedTypes}
\LMHash{}
This section describes how
the declared upper bounds of formal type parameters are enforced,
including some cases where a limited form of violation is allowed.
\LMHash{}
A {\em top type} is a type $T$ such that \code{Object} is a subtype of $T$.
\commentary{
For instance, \code{Object}, \DYNAMIC, and \VOID{} are top types,
and so are \code{FutureOr<\VOID>} and \code{FutureOr<FutureOr<\DYNAMIC>{}>}.
}
% We define the property of being regular-bounded for all types,
% being super-bounded for parameterized types, and being well-bounded
% for all types. We require that all types are well-bounded, which
% covers every subterm of a type that is itself a type, and then we
% require that types must be regular-bounded when used in certain
% situations.
\LMHash{}
Every type which is not a parameterized type is {\em regular-bounded}.
Let $T$ be a parameterized type of the form
\code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a generic class or a parameterized type alias.
Let
\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_n\ \EXTENDS\ B_n$}
be the formal type parameter declarations of $G$.
$T$ is {\em regular-bounded} if{}f
$S_j$ is a subtype of
$[S_1/X_1, \ldots,\ S_n/X_n]B_j$,
for all $j \in 1 .. n$.
\commentary{
This means that each actual type argument satisfies the declared upper
bound for the corresponding formal type parameter.
}
\LMHash{}
Let $T$ be a parameterized type of the form
\code{$G$<$S_1, \ldots,\ S_n$>}
where $G$ denotes a generic class or a parameterized type alias.
$T$ is {\em super-bounded} if{}f the following conditions are both true:
\begin{itemize}
\item
$T$ is not regular-bounded.
\item
For each $j \in 1 .. n$, let $S'_j$ be the result of replacing
every occurrence of a top type
in a covariant position in $S_j$ by \code{Null},
and every occurrence of \code{Null}
in a contravariant position in $S_j$ by \code{Object}.
It is then required that
\code{$G$<$S'_1, \ldots,\ S'_n$>}
is regular-bounded.
\end{itemize}
\commentary{
In short, at least one type argument violates its bound, but the type is
regular-bounded after replacing all occurrences of an extreme type by an
opposite extreme type, depending on their variance.
}
\LMHash{}
A type $T$ is {\em well-bounded} if{}f
it is either regular-bounded or super-bounded.
\LMHash{}
Any use of a type $T$ which is not well-bounded is a compile-time error.
\LMHash{}
It is a compile-time error if a parameterized type $T$ is super-bounded
when it is used in any of the following ways:
\begin{itemize}
\item $T$ is an immediate subterm of a new expression
(\ref{new})
or a constant object expression
(\ref{const}).
\item $T$ is an immediate subterm of a redirecting factory constructor
signature
(\ref{redirectingFactoryConstructors}).
\item $T$ is an immediate subterm of an \EXTENDS{} clause
(\ref{superclasses}),
or it occurs as an element in the type list of an \IMPLEMENTS{} clause
(\ref{superinterfaces}),
or a \WITH{} clause
(\ref{classes}).
\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{
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
involving super-bounded types are computed using the same rules as types of
function applications involving other types. Here is an example:
}
\begin{dartCode}
\CLASS{} A<X \EXTENDS{} num> \{
X x;
\}
\\
A<Object> a;
\end{dartCode}
\commentary{
With this, \code{a.x} has static type \code{Object},
even though the upper bound on the type variable \code{X} is \code{num}.
}
\rationale{
Super-bounded types enable the expression of informative common supertypes
of some sets of types whose common supertypes would otherwise be much less informative.
For example, consider the following class:
}
\begin{dartCode}
\CLASS{} C<X \EXTENDS{} C<X>$\!$> \{
X next;
\}
\end{dartCode}
\rationale{
Without super-bounded types,
there is no type $T$ which makes \code{C<$T$>} a common supertype of
all types of the form \code{C<$S$>}
(noting that all types must be regular-bounded
when we do not have the notion of super-bounded types).
So if we wish to allow a variable to hold any instance ``of type \code{C}''
then that variable must use \code{Object} or another top type
as its type annotation,
which means that a member like \code{next} is not known to exist
(which is what we mean by saying that the type is `less informative').
We could introduce a notion of recursive (infinite) types, and express
the least upper bound of all types of the form \code{C<$S$>} as
some syntax whose meaning could be approximated by
\code{C<C<C<C<$\ldots$>$\!$>$\!$>$\!$>}.
However, we expect that any such concept in Dart would incur a significant cost
on developers and implementations in terms of added complexity and subtlety,
so we have chosen not to do that.
Super-bounded types are finite,
but they offer a useful developer-controlled approximation to such infinite types.
}
\commentary{
For example,
\code{C<Object>} and
\code{C<C<C<\VOID>{}>{}>}
are types that a developer may choose to use as a type annotation.
This choice serves as a commitment to
a finite level of unfolding of the infinite type,
and it allows for a certain amount of control
at the point where the unfolding ends:
%
If \code{c} has type \code{C<C<\DYNAMIC>{}>}
then \code{c.next.next} has type \DYNAMIC{}
and \code{c.next.next.whatever} has no compile-time error,
but if \code{c} has type \code{C<C<\VOID>{}>} then
\code{Object x = c.next.next;} is a compile-time error.
It is thus possible for developers to get a more or less strict treatment
of expressions whose type proceeds beyond the given finite unfolding.
}
\section{Metadata}
\LMLabel{metadata}
\LMHash{}
Dart supports metadata which is used to attach user defined annotations to program structures.
\begin{grammar}
<metadata> ::= (`@' <qualified> (`.' <identifier>)? (<arguments>)?)*
\end{grammar}
\LMHash{}
Metadata consists of a series of annotations, each of which begin with the character @, followed by a constant expression that starts with an identifier.
It is a compile-time error if the expression is not one of the following:
\begin{itemize}
\item A reference to a constant variable.
\item A call to a constant constructor.
\end{itemize}
\LMHash{}
Metadata is associated with the abstract syntax tree of the program construct $p$ that immediately follows the metadata, assuming $p$ is not itself metadata or a comment.
Metadata can be retrieved at run time via a reflective call, provided the annotated program construct $p$ is accessible via reflection.
\commentary{
Obviously, metadata can also be retrieved statically by parsing the program and evaluating the constants via a suitable interpreter.
In fact many if not most uses of metadata are entirely static.
}
\rationale{
It is important that no run-time overhead be incurred by the introduction of metadata that is not actually used.
Because metadata only involves constants, the time at which it is computed is irrelevant so that implementations may skip the metadata during ordinary parsing and execution and evaluate it lazily.
}
\commentary{
It is possible to associate metadata with constructs that may not be accessible via reflection, such as local variables (though it is conceivable that in the future, richer reflective libraries might provide access to these as well).
This is not as useless as it might seem.
As noted above, the data can be retrieved statically if source code is available.
}
\LMHash{}
Metadata can appear before a library, part header, class, typedef, type parameter, constructor, factory, function, parameter, or variable declaration and before an import, export or part directive.
\LMHash{}
The constant expression given in an annotation is type checked and evaluated in the scope surrounding the declaration being annotated.
\section{Expressions}
\LMLabel{expressions}
\LMHash{}
\label{evaluation}
An {\em expression} is a fragment of Dart code that can be evaluated at run time.
Evaluating an expression either {\em produces a value} (an object),
or it {\em throws} an exception object and an associated stack trace.
In the former case, we also say that the expression {\em evaluates to a value}.
\LMHash{}
Every expression has an associated static type (\ref{staticTypes}) and
may have an associated static context type.
\commentary{The static context type represents
the type expectation of the surrounding context,
the expression or statement that the expression itself is part of.
Some contexts may not introduce any static context type.}
The static context type may affect the static type and evaluation
of the expression.
Every value has an associated dynamic type (\ref{dynamicTypeSystem}).
\LMHash{}
If evaluation of one expression, $e$, is defined in terms of evaluation of another expression, typically a subexpression of $e$,
and the evaluation of the other expression throws an exception and a stack trace,
the evaluation of $e$ stops at that point and throws the same exception object and stack trace.
\begin{grammar}
<expression> ::= <assignableExpression> <assignmentOperator> <expression>
\alt <conditionalExpression> <cascadeSection>*
\alt <throwExpression>
<expressionWithoutCascade> ::= <assignableExpression> <assignmentOperator>
\gnewline{} <expressionWithoutCascade>
\alt <conditionalExpression>
\alt <throwExpressionWithoutCascade>
<expressionList> ::= <expression> (`,' <expression>)*
<primary> ::= <thisExpression>
\alt \SUPER{} <unconditionalAssignableSelector>
\alt <functionExpression>
\alt <literal>
\alt <identifier>
\alt <newExpression>
\alt <constObjectExpression>
\alt `(' <expression> `)'
\end{grammar}
\LMHash{}
An expression $e$ may always be enclosed in parentheses, but this never has any semantic effect on $e$.
\commentary{
Sadly, it may have an effect on the surrounding expression.
Given a class $C$ with static method $m => 42$, $C.m()$ returns 42, but $(C).m()$ produces a \code{NoSuchMethodError}.
}
\subsection{Object Identity}
\LMLabel{objectIdentity}
\LMHash{}
The predefined Dart function \code{identical()} is defined such that \code{identical($c_1$, $c_2$)} if{}f:
\begin{itemize}
\item $c_1$ evaluates to either the null object (\ref{null}) or an instance of \code{bool} and \code{$c_1$ == $c_2$}, OR
\item $c_1$ and $c_2$ are instances of \code{int} and \code{$c_1$ == $c_2$}, OR
\item $c_1$ and $c_2$ are constant strings and \code{$c_1$ == $c_2$}, OR
\item $c_1$ and $c_2$ are instances of \code{double} and one of the following holds:
\begin{itemize}
\item $c_1$ and $c_2$ are non-zero and \code{$c_1$ == $c_2$}.
\item Both $c_1$ and $c_2$ are $+0.0$.
\item Both $c_1$ and $c_2$ are $-0.0$.
\item Both $c_1$ and $c_2$ represent a NaN value with the same underlying bit pattern.
\end{itemize}
OR
\item $c_1$ and $c_2$ are constant lists that are defined to be identical in the specification of literal list expressions (\ref{lists}), OR
\item $c_1$ and $c_2$ are constant maps that are defined to be identical in the specification of literal map expressions (\ref{maps}), OR
\item $c_1$ and $c_2$ are constant objects of the same class $C$ and the value of each instance variable of $c_1$ is identical to the value of the corresponding instance variable of $c_2$. OR
\item $c_1$ and $c_2$ are the same object.
\end{itemize}
\commentary{
The definition of \code{identity} for doubles differs from that of equality in that a NaN is identical to itself, and that negative and positive zero are distinct.
}
\rationale{
The definition of equality for doubles is dictated by the IEEE 754 standard, which posits that NaNs do not obey the law of reflexivity.
Given that hardware implements these rules, it is necessary to support them for reasons of efficiency.
The definition of identity is not constrained in the same way.
Instead, it assumes that bit-identical doubles are identical.
The rules for identity make it impossible for a Dart programmer to observe whether a boolean or numerical value is boxed or unboxed.
}
\subsection{Constants}
\LMLabel{constants}
\commentary{
All usages of the word 'constant' in Dart are associated with compile time.
A potentially constant expression is an expression that will generally yield
a constant value when the value of certain parameters is given.
The constant expressions is a subset of the potentially constant expressions that {\em can} be evaluated entirely at compile time.
}
\rationale{
The constant expressions are restricted to expressions that
perform only simple arithmetic operations, boolean conditions, and string and instance creation.
No user written function body is executed during constant expression evaluation,
only members of the system classes \code{int}, \code{double}, \code{bool}, \code{String} or \code{Null}.
}
\LMHash{}
The {\em potentially constant expressions} and {\em constant expressions} are the following:
\begin{itemize}
\item A literal boolean, \TRUE{} or \FALSE{} (\ref{booleans}), is a potentially constant and constant expression.
\item A literal number (\ref{numbers}) is a potentially constant and constant expression if it evaluates to a value of type \code{int} or \code{double}.
% A too-large integer literal does not evaluate to a value.
\item A literal string (\ref{strings}) with string interpolations (\ref{stringInterpolation} with expressions $e_1$, \ldots{}, $e_n$ is a potentially constant expression if $e_1$, \ldots{}, $e_n$ are potentially constant expressions.
The literal is further a constant expression if $e_1$, \ldots{}, $e_n$ are constant expressions evaluating to values that are instances of \code{int}, \code{double} \code{String}, \code{bool} or \code{Null}.
\commentary{These requirements hold trivially if there are no interpolations in the string}.
\rationale{It would be tempting to allow string interpolation where the
interpolated value is any compile-time constant. However, this would require
running the \code{toString()} method for constant objects, which could contain
arbitrary code.}
\item A literal symbol (\ref{symbols}) is a potentially constant and constant expression.
\item The literal \NULL{} (\ref{null}) is a potentially constant and constant expression.
\item An identifier that denotes a constant variable is a potentially constant and constant expression.
\item A qualified reference to a static constant variable (\ref{variables}) that is not qualified by a deferred prefix, is a potentially constant and constant expression.
\commentary{
For example, If class $C$ declares a constant static variable $v$, \code{$C$.$v$} is a constant.
The same is true if $C$ is accessed via a prefix $p$; \code{$p$.$C$.$v$} is a constant unless $p$ is a deferred prefix.
}
\item A simple or qualified identifier denoting a class, a mixin or a type alias that is not qualified by a deferred prefix, is a potentially constant and constant expression.
\commentary{
The constant expression always evaluates to a \code{Type} object.
For example, if $C$ is the name of a class or type alias, the expression \code{$C$} is a constant, and if $C$ is imported with a prefix $p$, \code{$p$.$C$} is a constant \code{Type} instance representing the type of $C$ unless $p$ is a deferred prefix.
}
\item A simple or qualified identifier denoting a top-level function (\ref{functions}) or a static method (\ref{staticMethods}) that is not qualified by a deferred prefix, is a potentially constant and constant expression.
\item An identifier expression denoting a parameter of a constant constructor (\ref{constantConstructors}) that occurs in the initializer list of the constructor, is a potentially constant expression.
\item A constant object expression (\ref{const}),
\code{\CONST{} $C$<$T_1,\ \ldots,\ T_k$>(\metavar{arguments})} or
\code{\CONST{} $C$<$T_1,\ \ldots,\ T_k$>.\id(\metavar{arguments})},
or either expression without the leading \CONST{} that occurs in a constant context, is a potentially constant expression if $T_1$, \ldots{}, $T_k$ are constant type expressions, and the actual argument expressions in \metavar{arguments} are constant expressions.
It is further a constant expression if the invocation evaluates to a value.
% \ref{const} requires each actual argument to be a constant expression,
% but here we also catch errors during evaluation, e.g., `C(1, 0)` where
% `C(double x, double y): z = x / y;`.
It is a compile-time error if a constant object expression is
not a constant expression (\ref{const}).
\item A constant list literal (\ref{lists}),
\code{\CONST{} <$T$>[$e_1$, \ldots{}, $e_n$]}, or
\code{<$T$>[$e_1$, \ldots{}, $e_n$]}
that occurs in a constant context, is a potentially constant expression if $T$ is a constant type expression, and $e_1$, \ldots{} , $e_n$ are constant expressions.
It is further a constant expression if the list literal evaluates to a value.
\item A constant map literal (\ref{maps}),
\code{\CONST{} <$K$, $V$>\{$k_1$: $v_1$, \ldots{}, $k_n$: $v_n$\}}
is a potentially constant expression if
\begin{itemize}
\item $K$ and $V$ are constant type expressions,
\item $k_1$, \ldots{}, $k_n$ are constant expressions evaluating to values that are either \code{int} or \code{String} instances, created using a symbol literal or a const invocation of the \code{Symbol} constructor, or instances of classes that that do not override the \code{==} operator inherited from \code{Object}, and
\item $v_1$, \ldots{}, $v_n$ are constant expressions.
\end{itemize}
It is further a constant expression if the map literal evaluates to a value.
%Should we also require the key instances to not override hashCode? Because Symbols do.
\item A parenthesized expression \code{($e$)} is a potentially constant expression if $e$ is a potentially constant expression. It is further a constant expression if $e$ is a constant expression.
\item An expression of the form \code{identical($e_1$, $e_2$)} is a potentially constant expression if $e_1$ and $e_2$ are potentially constant expressions and \code{identical} is statically bound to the predefined dart function \code{identical()} discussed above (\ref{objectIdentity}). It is further a constant expression if $e_1$ and $e_2$ are constant expressions.
\item An expression of the form \code{$e_1$\,!=\,$e_2$} is equivalent to \code{!($e_1$\,==\,$e_2$)} in every way, including whether it is potentially constant or constant.
\item An expression of the form \code{$e_1$\,==\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if both $e_1$ and $e_2$ are constant and either $e_1$ evaluates to a value that is an instance of \code{int}, \code{double}, \code{String}, \code{bool} or \code{Null}, or if $e_2$ evaluates to the null object (\ref{null}).
%TODO: Consider adding enum instances here.
\item An expression of the form \code{!$e_1$} is potentially constant if $e_1$ is potentially constant. It is further constant if $e_1$ is a constant expression that evaluates to a value of type \code{bool}.
\item An expression of the form \code{$e_1$\,\&\&\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if $e_1$ is a constant expression and either
\begin{enumerate}
\item $e_1$ evaluates to \FALSE{}, or
\item $e_1$ evaluates to \TRUE{} and $e_2$ is a constant expression that evaluates to a value of type \code{bool}.
\end{enumerate}
\item An expression of the form \code{$e_1$\,||\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if $e_1$ is a constant expression and either
\begin{enumerate}
\item $e_1$ evaluates to \TRUE{}, or
\item $e_1$ evaluates to \FALSE{} and $e_2$ is a constant expression that evaluates to a value of type \code{bool}.
\end{enumerate}
\item An expression of the form \code{~$e_1$} is a potentially constant expression if $e_1$ is a potentially constant expression. It is further a constant expression if $e_1$ is a constant expression that evaluates to a value of type \code{int}.
\item An expression of one of the forms \code{$e_1$\,\&\,$e_2$}, \code{$e_1$\,|\,$e_2$}, or \code{$e_1$\,\^\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if both $e_1$ and $e_2$ are constant expressions that both evaluate to values that are both instances of \code{int}, or that are both instances of \code{bool}.
% The bool case is new in 2.1.
\item An expression of one of the forms \code{$e_1$\,\~{}/\,$e_2$}, \code{$e_1$\,\gtgt\,$e_2$}, \code{$e_1$\,\gtgtgt\,$e_2$}, or \code{$e_1$\,\ltlt\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if both $e_1$ and $e_2$ are constant expressions that evaluate to values that are instances of \code{int}.
\item An expression of the form \code{$e_1$\,+\,$e_2$} is a potentially constant expression if $e_1$ and $e_2$ are both potentially constant expressions. It is further a constant expression if both $e_1$ and $e_2$ are constant expressions and either both evaluate to values that are instances of \code{int} or \code{double}, or both evaluate to values of type \code{String}.
\item An expression of the form \code{-$e_1$} is a potentially constant expression if $e_1$ is a potentially constant expression. It is further a constant expression if $e_1$ is a constant expression that evaluates to a value that is an instance of \code{int} or \code{double}.
\item An expression of the form \code{$e_1$\,-\,$e_2$}, \code{$e_1$\,*\,$e_2$}, \code{$e_1$\,/\,$e_2$}, \code{$e_1$\,\%\,$e_2$}, \code{$e_1$\,<\,$e_2$}, \code{$e_1$\,<=\,$e_2$}, \code{$e_1$\,>\,$e_2$}, or \code{$e_1$\,>=\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if both $e_1$ and $e_2$ are constant expressions that evaluate to values that are instances of \code{int} or \code{double}.
\item An expression of the form \code{$e_1$\,?\,$e_2$\,:\,$e_3$} is potentially constant if $e_1$, $e_2$, and $e_3$ are all potentially constant expressions. It is constant if $e_1$ is a constant expression and either
\begin{enumerate}
\item $e_1$ evaluates to \TRUE{} and $e_2$ is a constant expression, or
\item $e_1$ evaluates to \FALSE{} and $e_3$ is a constant expression.
\end{enumerate}
\item An expression of the form \code{$e_1$\,??\,$e_2$} is potentially constant if $e_1$ and $e_2$ are both potentially constant expressions. It is further constant if $e_1$ is a constant expression and either
\begin{enumerate}
\item $e_1$ evaluates to a non-\NULL{} value, or
\item $e_1$ evaluates to \NULL{} and $e_2$ is a constant expression.
\end{enumerate}
\item An expression of the form \code{$e$.length} is potentially constant if $e$ is a potentially constant expression. It is further constant if $e$ is a constant expression that evaluates to a \code{String}.
% New in 2.1.
\item An expression of the form \code{$e$ as $T$} is potentially constant if $e$ is a potentially constant expression and $T$ is a constant type expression, and it is further constant if $e$ is constant.
\commentary{
It is a compile-time error to evaluate the constant expression
if the cast operation would throw, that is,
if the value the $e$ evaluates to is not \NULL{} and not of type $T$.
}
% New in 2.1.
\item An expression of the form \code{$e$ is $T$} is potentially constant if $e$ is a potentially constant expression and $T$ is a constant type expression, and it is further constant if $e$ is constant.
% New in 2.1.
\item{}
An expression of the form \code{$e$ is! $T$} is equivalent to \code{!($e$ is $T$)} in every way,
including whether it's potentially constant or constant.
\end{itemize}
\LMHash{}
% New in 2.1.
A constant type expression is one of:
\begin{itemize}
\item An simple or qualified identifier denoting a type declaration (a type alias, class or mixin declaration) that is not qualified by a deferred prefix,
optionally followed by type arguments on the form
\code{<$T_1$,\ \ldots,\ $T_n$>}
where $T_1$, \ldots{}, $T_n$ are constant type expressions.
\item A type of the form \code{FutureOr<$T$>} where $T$ is a constant type expression.
\item A function type
\code{$R$ Function<\metavar{typeParameters}>(\metavar{argumentTypes})}
(where $R$ and \code{<\metavar{typeParameters}>} may be omitted)
and where $R$, \metavar{typeParameters} and \metavar{argumentTypes} (if present) contain only constant type expressions.
\item The type \VOID{}.
\item The type \DYNAMIC{}.
\end{itemize}
% Being potentially constant is entirely structural, not type based,
% but the program still has to satisfy strong-mode typing.
% Constant expressions (like "const Foo(42)") always evaluate to the
% same value, with at most one value per source location.
% Potentially constant expressions that are not constant only
% allow simple operations on basic types (num, String, bool, Null). These can
% be computed statically without running user code.
% A validly typed potentially constant expression can still fail when evaluated.
% If that happens in a const invociation, it's a compile-time error.
\LMHash{}
It is a compile-time error if an expression is required to be a constant expression but its evaluation would throw an exception.
It is a compile-time error if an assertion is evaluated as part of a constant object expression evaluation, and the assertion would throw an exception.
\commentary{
Note that there is no requirement that every constant expression evaluate correctly.
Only when a constant expression is required (e.g., to initialize a constant variable, or as a default value of a formal parameter, or as metadata) do we insist that a constant expression actually be evaluated successfully at compile time.
The above is not dependent on program control-flow.
The mere presence of a required compile-time constant whose evaluation would fail within a program is an error.
This also holds recursively: since compound constants are composed out of constants, if any subpart of a constant would throw an exception when evaluated, that is an error.
On the other hand, since implementations are free to compile code late, some compile-time errors may manifest quite late.
}
\begin{dartCode}
\CONST{} x = 1 \~{}/ 0;
\FINAL{} y = 1 \~{}/ 0;
\\
\CLASS{} K \{
m1() \{
\VAR{} z = \FALSE{};
\IF{} (z) \{ \RETURN{} x; \}
\ELSE{} \{ \RETURN{} 2; \}
\}
\\
m2() \{
\IF{} (\TRUE{}) \{ \RETURN{} y; \}
\ELSE{} \{ \RETURN{} 3; \}
\}
\}
\end{dartCode}
\commentary{
An implementation is free to immediately issue a compilation error for \code{x}, but it is not required to do so.
It could defer errors if it does not immediately compile the declarations that reference \code{x}.
For example, it could delay giving a compilation error about the method \code{m1} until the first invocation of \code{m1}.
However, it could not choose to execute \code{m1}, see that the branch that refers to \code{x} is not taken and return 2 successfully.
The situation with respect to an invocation \code{m2} is different.
Because \code{y} is not a compile-time constant (even though its value is), one need not give a compile-time error upon compiling \code{m2}.
An implementation may run the code, which will cause the getter for \code{y} to be invoked.
At that point, the initialization of \code{y} must take place, which requires the initializer to be compiled, which will cause a compilation error.
}
\rationale{
The treatment of \code{\NULL{}} merits some discussion.
Consider \code{\NULL{} + 2}.
This expression always causes an error.
We could have chosen not to treat it as a constant expression (and in general, not to allow \code{\NULL{}} as a subexpression of numeric or boolean constant expressions).
There are two arguments for including it:
\begin{enumerate}
\item It is constant.
We can evaluate it at compile time.
\item It seems more useful to give the error stemming from the evaluation explicitly.
\end{enumerate}
}
\rationale{
One might reasonably ask why $e_1$\,?\,$e_1$\,:\,$e_3$ and $e_1$\,??\,$e_2$ have constant forms.
For example, if $e_1$ is known statically, why do we need to test it?
The answer is that there are contexts where $e_1$ is a variable.
In particular, constant constructor initializers such as
\code{\CONST{} C(foo): \THIS.foo = foo ?? someDefaultValue;}
}
\LMHash{}
It is a compile-time error if the value of a constant expression depends on itself.
\commentary{
As an example, consider:
}
\begin{dartCode}
\CLASS{} CircularConsts \{
// \comment{Illegal program - mutually recursive compile-time constants}
\STATIC{} \CONST{} i = j; // \comment{a compile-time constant}
\STATIC{} \CONST{} j = i; // \comment{a compile-time constant}
\}
\end{dartCode}
\begin{grammar}
<literal> ::= <nullLiteral>
\alt <booleanLiteral>
\alt <numericLiteral>
\alt <stringLiteral>
\alt <symbolLiteral>
\alt <mapLiteral>
\alt <listLiteral>
\end{grammar}
\subsection{Null}
\LMLabel{null}
\LMHash{}
The reserved word \NULL{} evaluates to the {\em null object}.
\begin{grammar}
<nullLiteral> ::= \NULL{}
\end{grammar}
\LMHash{}
The null object is the sole instance of the built-in class \code{Null}.
Attempting to instantiate \code{Null} causes a run-time error.
It is a compile-time error for a class to extend, mix in or implement \code{Null}.
The \code{Null} class extends the \code{Object} class and declares no methods except those also declared by \code{Object}.
\commentary{As such, it does not override the \code{==} operator inherited
from the \code{Object} class.}
\LMHash{}
The static type of \NULL{} is the \code{Null} type.
\subsection{Numbers}
\LMLabel{numbers}
\LMHash{}
A {\em numeric literal} is either a decimal or hexadecimal numeral representing an integer value, or a decimal double representation.
\begin{grammar}
<numericLiteral> ::= <NUMBER>
\alt <HEX\_NUMBER>
<NUMBER> ::= <DIGIT>+ (`.' <DIGIT>+)? <EXPONENT>?
\alt `.' <DIGIT>+ <EXPONENT>?
<EXPONENT> ::= (`e' | `E') (`+' | `-')? <DIGIT>+
<HEX\_NUMBER> ::= `0x' <HEX\_DIGIT>+
\alt `0X' <HEX\_DIGIT>+
<HEX\_DIGIT> ::= `a' .. `f'
\alt `A' .. `F'
\alt <DIGIT>
\end{grammar}
\LMHash{}
A numeric literal starting with `0x' or `0X'
is a {\em hexadecimal integer literal}.
It has the numeric integer value of the hexadecimal numeral
following `0x' (respectively `0X').
\LMHash{}
A numeric literal that contains only decimal digits is a {\em decimal integer literal}.
It has the numeric integer value of the decimal numeral.
\LMHash{}
An {\em integer literal} is either a hexadecimal integer literal or a decimal integer literal.
\LMHash{}
Let $l$ be an integer literal that is not the operand
of by a unary minus operator,
and let $T$ be the static context type of $l$.
If \code{double} is assignable to $T$ and \code{int} is not assignable to $T$,
then the static type of $l$ is \code{double};
otherwise the static type of $l$ is \code{int}.
\commentary{
This means that an integer literal denotes a \code{double}
when it would satisfy the type requirement, and an \code{int} would not. Otherwise it is an \code{int}, even in situations where that is an error.
}
\LMHash{}
A numeric literal that is not an integer literal is a {\em double literal}.
\commentary{A double literal always contains either a decimal point or an exponent part.}
The static type of a double literal is \code{double}.
\LMHash{}
If $l$ is an integer literal with numeric value $i$ and static type \code{int},
and $l$ is not the operand of a unary minus operator,
then evaluation of $l$ proceeds as follows:
\begin{itemize}
\item{} If $l$ is a hexadecimal integer literal,
$2^{63} \le i < 2^{64}$ and the \code{int} class is implemented as
signed 64-bit two's complement integers,
then $l$ evaluates to an instance of the \code{int} class
representing the numeric value $i - 2^{64}$,
\item{} Otherwise $l$ evaluates to an instance of the \code{int} class
representing the numeric value $i$.
It is a compile-time error if the integer $i$ cannot be represented
exactly by an instance of \code{int}.
\end{itemize}
\commentary{
Integers in Dart are designed to be implemented as
64-bit two's complement integer representations.
In practice, implementations may be limited by other considerations.
For example, Dart compiled to JavaScript may use the JavaScript number type,
equivalent to Dart \code{double}, to represent integers, and if so,
integer literals with more than 53 bits of precision cannot be represented
exactly.
}
\LMHash{}
A double literal evaluates to a an instance of the \code{double} class
representing a 64 bit double precision floating point number
as specified by the IEEE 754 standard.
\LMHash{}
An integer literal with static type \code{double} and numeric value $i$
evaluates to an instance of the \code{double} class representing
the value $i$. It is a compile-time error if the value $i$ cannot be
represented {\em precisely} by the an instance of \code{double}.
\commentary{
A 64 bit double precision floating point number
is usually taken to represent a range of real numbers
around the precise value denoted by the number's
sign, mantissa and exponent.
For integer literals evaluating to \code{double}
values we insist that the integer literal's numeric value
is the precise value of the \code{double} instance.
}
\LMHash{}
It is a compile-time error for a class to extend, mix in or implement \code{int}.
It is a compile-time error for a class to extend, mix in or implement \code{double}.
It is a compile-time error for any class other than \code{int} and \code{double} to extend, mix in or implement \code{num}.
\LMHash{}
The instances of \code{int} and \code{double} all override the \code{==} operator inherited from the \code{Object} class.
\subsection{Booleans}
\LMLabel{booleans}
\LMHash{}
The reserved words \TRUE{} and \FALSE{} evaluate to objects {\em true} and {\em false} that represent the boolean values true and false respectively.
They are the {\em boolean literals}.
\begin{grammar}
<booleanLiteral> ::= \TRUE{}
\alt \FALSE{}
\end{grammar}
\LMHash{}
Both {\em true} and {\em false} are instances of the built-in class \code{bool},
and there are no other objects that implement \code{bool}.
It is a compile-time error for a class to extend, mix in or implement \code{bool}.
\LMHash{}
The \code{bool} class does not override the \code{==} operator inherited from
the \code{Object} class.
\LMHash{}
Invoking the getter \code{runtimeType} on a boolean value returns the \code{Type} object that is the value of the expression \code{bool}.
The static type of a boolean literal is \code{bool}.
\subsection{Strings}
\LMLabel{strings}
\LMHash{}
A {\em string} is a sequence of UTF-16 code units.
\rationale{
This decision was made for compatibility with web browsers and Javascript.
Earlier versions of the specification required a string to be a sequence of valid Unicode code points.
Programmers should not depend on this distinction.
}
\begin{grammar}
<stringLiteral> ::= (<multilineString> | <singleLineString>)+
\end{grammar}
\LMHash{}
A string can be a sequence of single line strings and multiline strings.
\begin{grammar}
<singleLineString> ::= `"' <stringContentDQ>* `"'
\alt `\'' <stringContentSQ>* `\''
\alt `r\'' (\~{}( `\'' | <NEWLINE>))* `\''
\alt `r"' (\~{}( `"' | <NEWLINE>))* `"'
\end{grammar}
\LMHash{}
A single line string is delimited by either matching single quotes or matching double quotes.
\commentary{
Hence, `abc' and ``abc'' are both legal strings, as are `He said ``To be or not to be'' did he not?' and ``He said `To be or not to be' didn't he''.
However ``This ` is not a valid string, nor is `this''.
}
\commentary{
The grammar ensures that a single line string cannot span more than one line of source code, unless it includes an interpolated expression that spans multiple lines.
}
\LMHash{}
Adjacent strings are implicitly concatenated to form a single string literal.
\commentary{
Here is an example
}
\begin{dartCode}
print("A string" "and then another"); // \comment{A stringand then another}
\end{dartCode}
\rationale{
Dart also supports the operator + for string concatenation.
The + operator on Strings requires a String argument.
It does not coerce its argument into a string.
This helps avoid puzzlers such as
}
\begin{dartCode}
print("A simple sum: 2 + 2 = " +
2 + 2);
\end{dartCode}
\rationale{
which this prints 'A simple sum: 2 + 2 = 22' rather than 'A simple sum: 2 + 2 = 4'.
However, the use of the concatenation operation is still discouraged for efficiency reasons.
Instead, the recommended Dart idiom is to use string interpolation.
}
\begin{dartCode}
print("A simple sum: 2 + 2 = \$\{2+2\}");
\end{dartCode}
\rationale{
String interpolation works well for most cases.
The main situation where it is not fully satisfactory is for string literals that are too large to fit on a line.
Multiline strings can be useful, but in some cases, we want to visually align the code.
This can be expressed by writing smaller strings separated by whitespace, as shown here:
}
\begin{dartCode}
'Imagine this is a very long string that does not fit on a line. What shall we do? '
'Oh what shall we do? '
'We shall split it into pieces '
'like so'.
\end{dartCode}
\begin{grammar}
<multilineString> ::= `"""' <stringContentTDQ>* `"""'
\alt `\'\mbox\'\mbox\'' <stringContentTSQ>* `\'\mbox\'\mbox\''
\alt `r"""' (\~{} `"""')* `"""'
\alt `r\'\mbox\'\mbox\'' (\~{} `\'\mbox\'\mbox\'')* `\'\mbox\'\mbox\''
<ESCAPE\_SEQUENCE> ::= `\\n'
\alt `\\r'
\alt `\\f'
\alt `\\b'
\alt `\\t'
\alt `\\v'
\alt `\\x' <HEX\_DIGIT> <HEX\_DIGIT>
\alt `\\u' <HEX\_DIGIT> <HEX\_DIGIT> <HEX\_DIGIT> <HEX\_DIGIT>
\alt `\\u{' <HEX\_DIGIT\_SEQUENCE> `}'
<HEX\_DIGIT\_SEQUENCE> ::= <HEX\_DIGIT> <HEX\_DIGIT>? <HEX\_DIGIT>?
\gnewline{} <HEX\_DIGIT>? <HEX\_DIGIT>? <HEX\_DIGIT>?
\end{grammar}
\LMHash{}
Multiline strings are delimited by either matching triples of single quotes or matching triples of double quotes.
If the first line of a multiline string consists solely of the whitespace characters defined by the production {\em WHITESPACE} (\ref{lexicalRules}), possibly prefixed by \syntax{`\\'}, then that line is ignored, including the line break at its end.
\rationale{
The idea is to ignore a whitespace-only first line of a multiline string, where whitespace is defined as tabs, spaces and the final line break.
These can be represented directly, but since for most characters prefixing by backslash is an identity in a non-raw string, we allow those forms as well.
}
% could be clearer. Is the first line in """\t
% """ ignored not. It depends if we mean whitespace before escapes are interpreted,
% or after, or both. See https://code.google.com/p/dart/issues/detail?id=23020
\LMHash{}
Strings support escape sequences for special characters.
The escapes are:
\begin{itemize}
\item \syntax{`\\n'} for newline, equivalent to \syntax{`\\x0A'}.
\item \syntax{`\\r'} for carriage return, equivalent to \syntax{`\\x0D'}.
\item \syntax{`\\f'} for form feed, equivalent to \syntax{`\\x0C'}.
\item \syntax{`\\b'} for backspace, equivalent to \syntax{`\\x08'}.
\item \syntax{`\\t'} for tab, equivalent to \syntax{`\\x09'}.
\item \syntax{`\\v'} for vertical tab, equivalent to \syntax{`\\x0B'}.
\item \syntax{`\\x' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$}, equivalent to
\syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ `}'}.
\item \syntax{`\\u' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$},
equivalent to
\syntax{`\\u{' <HEX\_DIGIT>$_1$ <HEX\_DIGIT>$_2$ <HEX\_DIGIT>$_3$ <HEX\_DIGIT>$_4$ `}'}.
\item \syntax{`\\u{' <HEX\_DIGIT\_SEQUENCE> `}'} is the Unicode code point represented by the
\syntax{<HEX\_DIGIT\_SEQUENCE>}.
It is a compile-time error if the value of the
\syntax{<HEX\_DIGIT\_SEQUENCE>}
is not a valid Unicode code point.
\item \syntax{`$'} indicating the beginning of an interpolated expression.
\item Otherwise, \syntax{`\\'$k$} indicates the character $k$ for any $k$ not in
\syntax{$\{$`n', `r', `f', `b', `t', `v', `x', `u'$\}$}.
\end{itemize}
\LMHash{}
Any string may be prefixed with the character \syntax{`r'},
indicating that it is a {\em raw string},
in which case no escapes or interpolations are recognized.
\LMHash{}
Line breaks in a multiline string are represented by the \syntax{<NEWLINE>} production.
A line break introduces a single newline character into the string value.
\LMHash{}
It is a compile-time error if a non-raw string literal contains a character sequence of the form \syntax{`\\x'} that is not followed by a sequence of two hexadecimal digits.
It is a compile-time error if a non-raw string literal contains a character sequence of the form \syntax{`\\u'} that is not followed by either a sequence of four hexadecimal digits, or by curly brace delimited sequence of hexadecimal digits.
\begin{grammar}
<stringContentDQ> ::= \~{}( `\\' | `"' | `$' | <NEWLINE> )
\alt `\\' \~{}( <NEWLINE> )
\alt <stringInterpolation>
<stringContentSQ> ::= \~{}( `\\' | `\'' | `$' | <NEWLINE> )
\alt `\\' \~{}( <NEWLINE> )
\alt <stringInterpolation>
<stringContentTDQ> ::= \~{}( `\\' | `"""' | `$')
\alt `\\' \~{}( <NEWLINE> )
\alt <stringInterpolation>
<stringContentTSQ> ::= \~{}( `\\' | `\'\'\'' | `$')
\alt `\\' \~{}( <NEWLINE> )
\alt <stringInterpolation>
<NEWLINE> ::= `\\n'
\alt `\\r'
\alt `\\r\\n'
\end{grammar}
\LMHash{}
All string literals evaluate to instances of the built-in class \code{String}.
It is a compile-time error for a class to extend, mix in or implement \code{String}.
The \code{String} class overrides the \code{==} operator inherited from
the \code{Object} class.
The static type of a string literal is \code{String}.
\subsubsection{String Interpolation}
\LMLabel{stringInterpolation}
\LMHash{}
It is possible to embed expressions within non-raw string literals, such that these expressions are evaluated, and the resulting values are converted into strings and concatenated with the enclosing string.
This process is known as {\em string interpolation}.
\begin{grammar}
<stringInterpolation> ::= `$' <IDENTIFIER\_NO\_DOLLAR>
\alt `${' <expression> `}'
\end{grammar}
\commentary{
The reader will note that the expression inside the interpolation could itself include strings, which could again be interpolated recursively.
}
\LMHash{}
An unescaped \syntax{`$'} character in a string signifies the beginning of an interpolated expression.
The \syntax{`$'} sign may be followed by either:
\begin{itemize}
\item A single identifier \id{} that must not contain the \syntax{`$'} character.
\item An expression $e$ delimited by curly braces.
\end{itemize}
\LMHash{}
The form \code{\$\id} is equivalent to the form \code{\$\{\id\}}.
An interpolated string, $s$, with content
`\code{$s_0$\$\{$e_1$\}$s_1\ldots{}s_{n-1}$\$\{$e_n$\}$s_{n}$}' (where any of $s_0, \ldots, s_n$ can be empty)
is evaluated by evaluating each expression $e_i$ ($1 \le i \le n$) in to a string $r_i$ in the order they occur in the source text, as follows:
\begin{itemize}
\item{} Evaluate $e_i$ to an object $o_i$.
\item{} Invoke the \code{toString} method on $o_i$ with no arguments, and let
$r_i$ be the returned value.
\item{} If $r_i$ is not an instance of the built-in type \code{String}, throw an \code{Error}.
\end{itemize}
Finally, the result of the evaluation of $s$ is the concatenation of the strings $s_0$, $r_1$, \ldots, $r_n$, and $s_n$.
\subsection{Symbols}
\LMLabel{symbols}
\LMHash{}
A {\em symbol literal} denotes a name that would be either
a valid declaration name or a valid library name in a Dart program.
\begin{grammar}
<symbolLiteral> ::= `#' (<operator> | (<identifier> (`.' <identifier>)*))
\end{grammar}
\LMHash{}
A symbol literal \code{\#\id} where \id{} is an identifier
that does not begin with an underscore ('\code{\_}'),
evaluates to an instance of \code{Symbol} representing the identifier \id.
All occurrences of \code{\#\id} evaluate to the same instance
\commentary{(symbol instances are canonicalized)},
and no other symbol literals evaluate to that \code{Symbol} instance
or to a \code{Symbol} instance that is equal
(according to the \code{==} operator \ref{equality}) to that instance.
\LMHash{}
A symbol literal \code{\#$\id.\id_2\ldots\id_n$}
where $\id{} \ldots \id_n$ are identifiers,
evaluates to an instance of \code{Symbol} representing that particular sequence of identifiers.
All occurrences of \code{\#$\id.\id_2\ldots\id_n$} with the same sequence of identifiers
evaluate to the same instance,
and no other symbol literals evaluate to that \code{Symbol} instance
or to a \code{Symbol} instance that is \code{==} to that instance.
\commentary{This kind of symbol literal denotes the name of a library declaration. Library names are not subject to library privacy, even
if some of its identifiers begin with an underscore.}
\LMHash{}
A symbol literal \code{\#\metavar{operator}} evaluates to an instance of \code{Symbol}
representing that particular operator name.
All occurrences of \code{\#\metavar{operator}} evaluate to the same instance,
and no other symbol literals evaluate to that \code{Symbol} instance
or to a \code{Symbol} instance that is \code{==} to that instance.
\LMHash{}
A symbol literal \code{\#\_\id}, evaluates to an instance of \code{Symbol}
representing the private identifier \code{\_\id} of the containing library.
All occurrences of \code{\#\_\id} {\em in the same library} evaluate to the same instance,
and no other symbol literals evaluate to that \code{Symbol} instance
or to a \code{Symbol} instance that is \code{==} to that instance.
\LMHash{}
The objects created by symbol literals all override
the \code{==} operator inherited from the \code{Object} class.
\rationale{
One may well ask what is the motivation for introducing literal symbols? In some languages, symbols are canonicalized whereas strings are not.
However literal strings are already canonicalized in Dart.
Symbols are slightly easier to type compared to strings and their use can become strangely addictive, but this is not nearly sufficient justification for adding a literal form to the language.
The primary motivation is related to the use of reflection and a web specific practice known as minification.
Minification compresses identifiers consistently throughout a program in order to reduce download size.
This practice poses difficulties for reflective programs that refer to program declarations via strings.
A string will refer to an identifier in the source, but the identifier will no longer be used in the minified code, and reflective code using these would fail.
Therefore, Dart reflection uses objects of type \code{Symbol} rather than strings.
Instances of \code{Symbol} are guaranteed to be stable with respect to minification.
Providing a literal form for symbols makes reflective code easier to read and write.
The fact that symbols are easy to type and can often act as convenient substitutes for enums are secondary benefits.
}
\LMHash{}
The static type of a symbol literal is \code{Symbol}.
\subsection{Lists}
\LMLabel{lists}
\LMHash{}
A {\em list literal} denotes a list, which is an integer indexed collection of objects.
\begin{grammar}
<listLiteral> ::= \CONST{}? <typeArguments>? `[' (<expressionList> `,'?)? `]'
\end{grammar}
\LMHash{}
A list may contain zero or more objects.
The number of elements in a list is its size.
A list has an associated set of indices.
An empty list has an empty set of indices.
A non-empty list has the index set $\{0, \ldots, n - 1\}$ where $n$ is the size of the list.
It is a run-time error to attempt to access a list using an index that is not a member of its set of indices.
\LMHash{}
If a list literal begins with the reserved word \CONST{}, it is a {\em constant list literal} which is a constant expression (\ref{constants}) and therefore evaluated at compile time.
Otherwise, it is a {\em run-time list literal} and it is evaluated at run time.
Only run-time list literals can be mutated
after they are created.
Attempting to mutate a constant list literal will result in a dynamic error.
\LMHash{}
It is a compile-time error if an element of a constant list literal is not a constant expression.
% Need 'free': `const <Function(Function<X>(X))>[]` is OK, but `X` is not free.
It is a compile-time error if the type argument of a constant list literal is or contains a free type variable.
\rationale{
The binding of a type parameter is not known at compile time, so we cannot use type parameters inside constant expressions.
}
\LMHash{}
The value of a constant list literal
\code{\CONST{} <$E$>[$e_1, \ldots, e_n$]}
is an object $a$ whose class implements the built-in class
\code{List<$E$>}.
The $i$th element of $a$ is $v_{i+1}$, where $v_i$ is the value of the compile-time expression $e_i$.
The value of a constant list literal
\code{\CONST{} [$e_1, \ldots, e_n$]}
is defined as the value of the constant list literal
\code{\CONST{} <\DYNAMIC{}>[$e_1, \ldots, e_n$]}.
\LMHash{}
Let
$list_1 =$ \code{\CONST{} <$V$>[$e_{11}, \ldots, e_{1n}$]}
and
$list_2 =$ \code{\CONST{} <$U$>[$e_{21}, \ldots, e_{2n}$]}
be two constant list literals and let the elements of $list_1$ and $list_2$ evaluate to $o_{11}, \ldots, o_{1n}$ and $o_{21}, \ldots, o_{2n}$ respectively.
If{}f \code{identical($o_{1i}$, $o_{2i}$)} for $i \in 1 .. n$ and $V = U$ then \code{identical($list_1$, $list_2$)}.
\commentary{
In other words, constant list literals are canonicalized.
}
\LMHash{}
A run-time list literal
\code{<$E$>[$e_1, \ldots, e_n$]}
is evaluated as follows:
\begin{itemize}
\item
First, the expressions $e_1, \ldots, e_n$ are evaluated in order they appear in the program, producing objects $o_1, \ldots, o_n$.
\item A fresh instance (\ref{generativeConstructors}) $a$, of size $n$, whose class implements the built-in class
\code{List<$E$>}
is allocated.
\item
The operator \syntax{`[]='} is invoked on $a$ with first argument $i$ and second argument
%The $i$th element of $a$ is set to
$o_{i+1}, 0 \le i < n$.
\item
The result of the evaluation is $a$.
\end{itemize}
\LMHash{}
The objects created by list literals do not override
the \code{==} operator inherited from the \code{Object} class.
\commentary{
Note that this document does not specify an order in which the elements are set.
This allows for parallel assignments into the list if an implementation so desires.
The order can only be observed (and may not be relied upon):
if element $i$ is not a subtype of the element type of the list,
a dynamic type error will occur when $a[i]$ is assigned $o_{i-1}$.
}
\LMHash{}
A run-time list literal
\code{[$e_1, \ldots, e_n$]}
is evaluated as
\code{<\DYNAMIC{}>[$e_1, \ldots, e_n$]}.
\commentary{
There is no restriction precluding nesting of list literals.
It follows from the rules above that
\code{<List<int>{}>[<int>[1, 2, 3], <int>[4, 5, 6]]}
is a list with type parameter \code{List<int>},
containing two lists with type parameter \code{int}.
}
\LMHash{}
The static type of a list literal of the form
\code{\CONST{} <$E$>[$e_1, \ldots, e_n$]}
or the form
\code{<$E$>[$e_1, \ldots, e_n$]}
is \code{List<$E$>}.
The static type a list literal of the form
\code{\CONST{} [$e_1, \ldots, e_n$]}
or the form
\code{[$e_1, \ldots, e_n$]}
is \code{List<\DYNAMIC{}>}.
\subsection{Maps}
\LMLabel{maps}
\LMHash{}
A {\em map literal} denotes a map object.
\begin{grammar}
<mapLiteral> ::= \CONST{}? <typeArguments>?
\gnewline{} `{' (<mapLiteralEntry> (`,' <mapLiteralEntry>)* `,'?)? `\}'
<mapLiteralEntry> ::= <expression> `:' <expression>
\end{grammar}
\LMHash{}
A {\em map literal} consists of zero or more entries.
Each entry has a {\em key} and a {\em value}.
Each key and each value is denoted by an expression.
\LMHash{}
If a map literal begins with the reserved word \CONST{}, it is a {\em constant map literal} which is a constant expression (\ref{constants}) and therefore evaluated at compile time.
Otherwise, it is a {\em run-time map literal} and it is evaluated at run time.
Only run-time map literals can be mutated after they are created.
Attempting to mutate a constant map literal will result in a dynamic error.
\LMHash{}
It is a compile-time error if either a key or a value of an entry in a constant map literal is not a constant expression.
It is a compile-time error if the key of an entry in a constant map literal is an instance of
a class that has a concrete operator \syntax{`=='} declaration different from the one in \code{Object},
unless the key is a string or an integer,
or the key expression evaluates to an instance of the built-in
class \code{Symbol} which was originally obtained by evaluation of a
literal symbol or
a constant invocation of a constructor of the \code{Symbol} class.
% Needs 'free': `const <int, Function(Function<X>(X))>{}` is OK, but
% `X` is not free.
It is a compile-time error if a type argument of a constant map literal
is or contains a free type variable.
\LMHash{}
The value of a constant map literal
\code{\CONST{} <$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}}
is an object $m$ whose class implements the built-in class
\code{Map<$K, V$>}.
The entries of $m$ are $u_i:v_i, i \in 1 .. n$, where $u_i$ is the value of the compile-time expression $k_i$ and $v_i$ is the value of the compile-time expression $e_i$.
The value of a constant map literal
\code{\CONST{} \{$k_1:e_1, \ldots, k_n:e_n$\}}
is defined as the value of a constant map literal
\code{\CONST{} <\DYNAMIC{}, \DYNAMIC{}>\{$k_1:e_1, \ldots, k_n:e_n$\}}.
\LMHash{}
Let
$map_1 =$ \code{\CONST{} <$K, V$>\{$k_{11}:e_{11}, \ldots, k_{1n}:e_{1n}$\}}
and
$map_2 =$ \code{\CONST{} <$J, U$>\{$k_{21}:e_{21}, \ldots, k_{2n}:e_{2n}$\}}
be two constant map literals.
Let the keys of $map_1$ and $map_2$ evaluate to $s_{11}, \ldots, s_{1n}$ and $s_{21}, \ldots, s_{2n}$ respectively, and let the elements of $map_1$ and $map_2$ evaluate to $o_{11}, \ldots, o_{1n}$ and $o_{21}, \ldots, o_{2n}$ respectively.
If{}f \code{identical($o_{1i}$, $o_{2i}$)} and \code{identical($s_{1i}$, $s_{2i}$)} for $i \in 1 .. n$, and $K = J, V = U$ then \code{identical($map_1$, $map_2$)}.
\commentary{
In other words, constant map literals are canonicalized.
}
\LMHash{}
A run-time map literal
\code{<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}}
is evaluated as follows:
\begin{itemize}
\item
For each $i \in 1 .. n$ in numeric order,
first the expression $k_i$ is evaluated producing object $u_i$,
and then $e_i$ is evaluated producing object $o_i$.
This produces all the objects $u_1, o_1, \ldots, u_n, o_n$.
\item A fresh instance (\ref{generativeConstructors}) $m$ whose class implements the built-in class
\code{Map<$K, V$>} is allocated.
\item
The operator \syntax{`[]='} is invoked on $m$ with first argument $u_i$ and second argument $o_i$ for each $i \in 1 .. n$.
\item
The result of the evaluation is $m$.
\end{itemize}
\LMHash{}
The objects created by map literals do not override
the \code{==} operator inherited from the \code{Object} class.
\LMHash{}
A run-time map literal
\code{\{$k_1:e_1, \ldots, k_n:e_n$\}}
is evaluated as
\code{<\DYNAMIC{}, \DYNAMIC{}>\{$k_1:e_1, \ldots, k_n:e_n$\}}.
\LMHash{}
It is a compile-time error if two keys of a constant map literal are equal.
\LMHash{}
A map literal is ordered: iterating over the keys and/or values of the maps always happens in the
order the keys appeared in the source code.
\commentary{
Of course, if a key repeats, the order is defined by first occurrence, but the value is defined by the last.
}
\LMHash{}
The static type of a map literal of the form
\code{\CONST{} <$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}}
or the form
\code{<$K, V$>\{$k_1:e_1, \ldots, k_n:e_n$\}}
is
\code{Map<$K, V$>}.
The static type of a map literal of the form
\code{\CONST{} \{$k_1:e_1, \ldots, k_n:e_n$\}}
or the form
\code{\{$k_1:e_1, \ldots, k_n:e_n$\}} is
\code{Map<\DYNAMIC{}, \DYNAMIC{}>}.
\subsection{Throw}
\LMLabel{throw}
\LMHash{}
The {\em throw expression} is used to throw an exception.
\begin{grammar}
<throwExpression> ::= \THROW{} <expression>
<throwExpressionWithoutCascade> ::= \THROW{} <expressionWithoutCascade>
\end{grammar}
\LMHash{}
Evaluation of a throw expression of the form \code{\THROW{} $e$;} proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to a value $v$ (\ref{evaluation}).
\commentary{
There is no requirement that the expression $e$ must evaluate to any special kind of object.
}
\LMHash{}
If $v$ is the null object (\ref{null}), then a \code{NullThrownError} is thrown.
Otherwise let $t$ be a stack trace corresponding to the current execution state,
and the \THROW{} statement throws with $v$ as exception object
and $t$ as stack trace (\ref{evaluation}).
\LMHash{}
If $v$ is an instance of class \code{Error} or a subclass thereof,
and it is the first time that \code{Error} object is thrown,
the stack trace $t$ is stored on $v$ so that it will be returned
by the $v$'s \code{stackTrace} getter
\commentary{
If the same \code{Error} object is thrown more than once, its \code{stackTrace} getter will return the stack trace from the {\em first} time it was thrown.
}
\LMHash{}
The static type of a throw expression is $\bot$.
\subsection{Function Expressions}
\LMLabel{functionExpressions}
\LMHash{}
%% TODO(eernst): A function literal is a syntactic construct, and we may use
%% function closurization to obtain a corresponding function object.
A {\em function literal} is an object that encapsulates an executable unit of code.
\begin{grammar}
<functionExpression> ::= <formalParameterPart> <functionBody>
\end{grammar}
%% TODO[inference]: The static and dynamic type of a function literal
%% interacts with inference: If a type-from-context $T$ exists and the
%% function literal can be given a type which is a subtype of $T$, we may
%% end up typing both the function as a whole and the body of the function
%% very differently than we would in a situation where no type-from-context
%% exists. So the rules below must be changed to be the default case (where
%% no type-from-context is available, or it is `Object` or some other
%% non-constraing type, and other cases where the type-from-context is
%% actually used to select the function literal signature must be described
%% specifically for each relevant type of situation.
\LMHash{}
The class of a function literal implements the built-in class \FUNCTION{}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) => $e$}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow T_0$},
\noindent
%% TODO[inference]: The static type of the function literal may come from context.
where $T_0$ is the static type of $e$.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) \ASYNC{} => $e$}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Future<\flatten{T_0}>},
\noindent
where $T_0$ is the static type of $e$.
\LMHash{}
In the previous two paragraphs, the type argument lists are omitted in the case where $m = 0$, and \flatten{T} is defined as follows:
\begin{itemize}
\item If $T$ is \code{FutureOr<$S$>} for some $S$ then $\flatten{T} = S$.
\item Otherwise if
\code{$T <:$ Future}
then let $S$ be a type such that
\code{$T <<$ Future<$S$>}
and for all $R$, if
\code{$T <<$ Future<$R$>}
then $S << R$.
\rationale{
This ensures that
\code{Future<$S$>}
is the most specific generic instantiation of \code{Future} that is a supertype of $T$.
%% TODO[class-interfaces]: When we have finished the specification of class
%% interface computations we may have the following property, but it is not
%% true at this point. Adjust the following by then!
Note that $S$ is well-defined because of the requirements on superinterfaces.
}
Then $\flatten{T} = S$.
\item In any other circumstance, $\flatten{T} = T$.
\end{itemize}
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) => $e$}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow T_0$},
\noindent
where $T_0$ is the static type of $e$.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1 B_1, \ldots,\ X_m B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC{} => $e$}
\noindent
is
\code{<$X_1 B_1, \ldots,\ X_m B_m$>}
\code{($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Future<\flatten{T_0}>},
\noindent
where $T_0$ is the static type of $e$.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ \DYNAMIC{}}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$]) \ASYNC{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Future}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \ASYNC*{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Stream}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \SYNC*{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ Iterable}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ [$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k}= d_k$]) \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ [$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$]) $ \rightarrow$ \DYNAMIC{}}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Future}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \ASYNC*{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Stream}.
\LMHash{}
The static type of a function literal of the form
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>}
\code{($T_1\ a_1, \ldots,\ T_n\ a_n, $ \{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\}) \SYNC*{} \{ $s$ \}}
\noindent
is
\code{<$X_1\ B_1, \ldots,\ X_m\ B_m$>($T_1, \ldots,\ T_n, $ \{$T_{n+1}\ x_{n+1}, \ldots,\ T_{n+k}\ x_{n+k}$\}) $ \rightarrow$ Iterable}.
\LMHash{}
In all of the above cases,
the type argument lists are omitted when $m=0$,
and whenever $T_i, 1 \le i \le n+k$, is not specified,
it is considered to have been specified as \DYNAMIC{}.
\subsection{This}
\LMLabel{this}
\LMHash{}
The reserved word \THIS{} denotes the target of the current instance member invocation.
\begin{grammar}
<thisExpression> ::= \THIS{}
\end{grammar}
\LMHash{}
The static type of \THIS{} is the interface of the immediately enclosing class.
\commentary{
We do not support self-types at this point.
}
\LMHash{}
It is a compile-time error if \THIS{} appears, implicitly or explicitly, in a top-level function or variable initializer, in a factory constructor, or in a static method or variable initializer, or in the initializer of an instance variable.
\subsection{Instance Creation}
\LMLabel{instanceCreation}
\LMHash{}
Instance creation expressions generally produce instances
and invoke constructors to initialize them.
\commentary{
The exception is that
a factory constructor invocation works like a regular function call.
It may of course evaluate an instance creation expression and thus
produce a fresh instance,
but no fresh instances are created as a direct consequence of
the factory constructor invocation.
}
%It is a compile-time error if any of the type arguments to a constructor of a generic type invoked by a new expression or a constant object expression do not denote types in the enclosing lexical scope.
%It is a compile-time error if a constructor of a non-generic type invoked by a new expression or a constant object expression is passed any type arguments. It is a compile-time error if a constructor of a generic type with $n$ type parameters invoked by a new expression or a constant object expression is passed $m$ type arguments where $m \ne n$, or if any of its type arguments is misconstructed (\ref{parameterizedTypes}).
\LMHash{}
It is a compile-time error if
the type $T$ in an instance creation expression of one of the forms
\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
\noindent
is malformed (\ref{staticTypes}),
is malbounded (\ref{parameterizedTypes}),
or is an enumerated type (\ref{enums}).
\subsubsection{New}
\LMLabel{new}
\LMHash{}
The {\em new expression} invokes a constructor (\ref{constructors}).
\begin{grammar}
<newExpression> ::= \NEW{} <type> (`.' <identifier>)? <arguments>
\end{grammar}
\LMHash{}
Let $e$ be a new expression of the form
\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
or the form
\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
It is a compile-time error if $T$ is not
a class or a parameterized type accessible in the current scope,
or if $T$ is a parameterized type which is not a class.
\commentary{
For instance, \code{\NEW{} F<int>()} is an error if \code{F} is a type alias.
}
\LMHash{}
If $T$ is a parameterized type (\ref{parameterizedTypes})
\code{$S$<$U_1, \ldots,\ U_m$>},
let $R$ be the generic class $S$,
and let
\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_p\ \EXTENDS\ B_p$}
be the formal type parameters of $S$.
If $T$ is not a parameterized type, let $R$ be $T$.
\begin{itemize}
\item
If $e$ is of the form
\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
it is a compile-time error if \code{$R$.\id} is not the name of
a constructor declared by $R$, or \id{} is not accessible.
\item
If $e$ is of the form
\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
it is a compile-time error if $R$ is not the name of
a constructor declared by $R$.
\end{itemize}
\LMHash{}
Let $q$ be the above-mentioned constructor named \code{$R$.\id} or $R$.
\LMHash{}
It is a compile-time error if $R$ is abstract
and $q$ is not a factory constructor.
It is a compile-time error if $R$ is a non-generic class
and $T$ is a parameterized type.
%% We assume that inference has taken place, so actual type arguments
%% are always given explicitly.
It is a compile-time error if $R$ is a generic class
and $T$ is not a parameterized type.
It is a compile-time error if $R$ is a generic class,
$T$ is a parameterized type, and $m \not= p$.
\commentary{That is, the number of type arguments is incorrect.}
It is a compile-time error if $R$ is a generic class,
$T$ is a parameterized type,
and $T$ is not regular-bounded
(\ref{superBoundedTypes}).
\LMHash{}
If $q$ is a redirecting factory constructor,
it is a compile-time error if $q$ in some number of
redirecting factory redirections redirects to itself.
\commentary{
It is possible and allowed for a redirecting factory $q'$
to enter an infinite loop, e.g.,
because $q'$ redirects to a non-redirecting factory constructor
$q''$ whose body uses $q'$ in an instance creation expression.
Only loops that consist exclusively of redirecting factory redirections
are detected at compile time.
}
\LMHash{}
Let $S_i$ be the static type of
the formal parameter of the constructor \code{$R$.\id} (respectively $R$)
corresponding to the actual argument $a_i$, $i \in 1 .. n+k$.
It is a compile-time error if the static type of
$a_i, i \in 1 .. n + k$
is not assignable to $[U_1/X_1, \ldots, U_m/X_m]S_i$.
\commentary{
The non-generic case is covered with $m = 0$.
}
\LMHash{}
The static type of $e$ is $T$.
\LMHash{}
Evaluation of $e$ proceeds as follows:
\LMHash{}
First, the argument part
\code{<$U_1, \ldots,\ U_m$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
\noindent
is evaluated, yielding the evaluated actual argument part
\code{<$u_1, \ldots,\ u_m$>($o_1, \ldots,\ o_n,\ x_{n+1}$: $o_{n+1},\ \ldots,\ x_{n+k}$: $o_{n+k}$)}.
\noindent
\commentary{Note that the non-generic case is covered by letting $m = 0$.}
If for any
$j \in 1 .. n + k$
the run-time type of $o_j$ is not a subtype of
$[u_1/X_1, \ldots, u_m/X_m]S_j$,
a dynamic type error occurs.
\LMHash{}
\Case{Non-loaded deferred constructors}
If $T$ is a deferred type with prefix $p$, then if $p$ has not been successfully loaded, a dynamic error occurs.
\LMHash{}
\Case{Generative constructors}
When $q$ is a generative constructor
(\ref{generativeConstructors})
evaluation proceeds to allocate a fresh instance
(\ref{generativeConstructors}), $i$, of class $T$.
% We provide the type arguments as part of the class of the instance
% because $T$ includes the type arguments; but we also provide them
% as a binding accessible to the constructor: Otherwise we couldn't
% access the type parameters in the initializing expressions of the
% initializer list where there is no access to \THIS{}.
Then $q$ is executed to initialize $i$ with respect to
the bindings that resulted from the evaluation of the argument list, and,
if $R$ is a generic class,
with its type parameters bound to $u_1, \ldots, u_m$.
\LMHash{}
If execution of $q$ completes normally (\ref{completion}), $e$ evaluates to $i$.
Otherwise execution of $q$ throws an exception object $x$ and stack trace $t$,
and then evaluation of $e$ also throws exception object $x$ and stack trace $t$
(\ref{evaluation}).
\LMHash{}
\Case{Redirecting factory constructors}
When $q$ is a redirecting factory constructor
(\ref{factories})
of the form \code{\CONST{}? $T$($p_1, \ldots,\ p_{n+k}$) = $c$;} or
of the form \code{\CONST{}? $T$.\id($p_1, \ldots,\ p_{n+k}$) = $c$;}
where \code{\CONST{}?} indicates that \CONST{} may be present or absent,
the remaining evaluation of $e$ is equivalent to
evaluating
\code{\NEW{} $c$($v_1, \ldots,\ v_n,\ x_{n+1}$: $v_{n+1}, \ldots,\ x_{n+k}$: $v_{n+k}$)}
in an environment where
$v_j$ is a fresh variable bound to $o_j$ for $j \in 1 .. n + k$, and
$X_j$ is bound to $u_j$ for $j \in 1 .. m$.
\commentary{
We need access to the type variables because $c$ may contain them.
}
\LMHash{}
\Case{Non-redirecting factory constructors}
When $q$ is a non-redirecting factory constructor,
the body of $q$ is executed with respect to
the bindings that resulted from the evaluation of the argument list,
and with the type parameters, if any, of $q$ bound to
the actual type arguments $u_1, \ldots, u_m$.
If this execution returns a value (\ref{completion}),
then $e$ evaluates to the returned value.
Otherwise, if the execution completes normally or returns with no value,
then $e$ evaluates to the null object (\ref{null}).
Otherwise the execution throws an exception $x$ and stack trace $t$,
and then evaluation of $e$ also throws $x$ and $t$ (\ref{evaluation}).
\rationale{
A factory constructor can be declared in an abstract class and used safely,
as it will either produce a valid instance or throw.
}
\subsubsection{Const}
\LMLabel{const}
\LMHash{}
A {\em constant object expression} invokes a constant constructor
(\ref{constantConstructors}).
\begin{grammar}
<constObjectExpression> ::= \CONST{} <type> (`.' <identifier>)? <arguments>
\end{grammar}
\LMHash{}
Let $e$ be a constant object expression of the form
\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
or the form
\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
It is a compile-time error if $T$ is not
a class or a parameterized type accessible in the current scope,
or if $T$ is a parameterized type which is not a class.
It is a compile-time error if $T$ is a deferred type
(\ref{staticTypes}).
\commentary{
In particular, $T$ must not be a type variable.
}
\LMHash{}
It is a compile-time error if $a_i$ is not a constant expression
for some $i \in 1 .. n + k$.
\LMHash{}
If $T$ is a parameterized type (\ref{parameterizedTypes})
\code{$S$<$U_1, \ldots,\ U_m$>},
let $R$ be the generic class $S$,
and let
\code{$X_1\ \EXTENDS\ B_1, \ldots,\ X_p\ \EXTENDS\ B_p$}
be the formal type parameters of $S$.
If $T$ is not a parameterized type, let $R$ be $T$.
\LMHash{}
If $T$ is a parameterized type,
it is a compile-time error if $U_j$ contains a type variable for any
$j \in 1 .. m$.
\begin{itemize}
\item
If $e$ is of the form
\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
it is a compile-time error if \code{$R$.\id} is not the name of
a constant constructor declared by $R$, or \id{} is not accessible.
\item
If $e$ is of the form
\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
it is a compile-time error if $R$ is not the name of
a constant constructor declared by $R$.
\end{itemize}
\LMHash{}
Let $q$ be the above-mentioned constant constructor named \code{$R$.\id} or $R$.
%% TODO(eernst): These errors are the same as with `new`. Can we avoid
%% stating them twice? We'd need to refer to an awkwardly shaped portion
%% of text in the previous subsection, or just loosely say "exactly the
%% same errors"..
\LMHash{}
It is a compile-time error if $R$ is abstract
and $q$ is not a factory constructor.
It is a compile-time error if $R$ is a non-generic class
and $T$ is a parameterized type.
%% We assume that inference has taken place, so actual type arguments
%% are always given explicitly.
It is a compile-time error if $R$ is a generic class
and $T$ is not a parameterized type.
It is a compile-time error if $R$ is a generic class,
$T$ is a parameterized type, and $m \not= p$.
\commentary{That is, the number of type arguments is incorrect.}
It is a compile-time error if $R$ is a generic class,
$T$ is a parameterized type,
and $T$ is not regular-bounded
(\ref{superBoundedTypes}).
\LMHash{}
Let $S_i$ be the static type of
the formal parameter of the constructor \code{$R$.\id} (respectively $R$)
corresponding to the actual argument $a_i$, $i \in 1 .. n+k$.
It is a compile-time error if the static type of
$a_i, i \in 1 .. n + k$
is not assignable to $[U_1/X_1, \ldots, U_m/X_m]S_i$.
\commentary{
The non-generic case is covered with $m = 0$.
}
\LMHash{}
The static type of $e$ is $T$.
\LMHash{}
Evaluation of $e$ proceeds as follows:
\LMHash{}
If $e$ is of the form
\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
let $i$ be the value of the expression $e'$:
\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\commentary{
Let $o$ be the result of an evaluation of $e'$,
at some point in time of some execution of the program
in the library $L$ where $e$ occurs.
The result of an evaluation of $e'$ in $L$
at some other time and/or in some other execution will
yield a result $o'$, such that $o'$ would be replaced by $o$
by canonicalization as described below.
This means that the value is well-defined.
}
\LMHash{}
If $e$ is of the form
\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
let $i$ be the value of
\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\commentary{
Which is well-defined for the same reason.
}
\LMHash{}
\begin{itemize}
\item If during execution of the program,
a constant object expression has already evaluated to
an instance $j$ of class $R$ with type arguments $U_i, 1 \le i \le m$, then:
\begin{itemize}
\item For each instance variable $f$ of $i$,
let $v_{if}$ be the value of the instance variable $f$ in $i$, and
let $v_{jf}$ be the value of the instance variable $f$ in $j$.
If \code{identical($v_{if}$, $v_{jf}$)} for all instance variables $f$ in $i$
then the value of $e$ is $j$, otherwise the value of $e$ is $i$.
\end{itemize}
\item Otherwise the value of $e$ is $i$.
\end{itemize}
\commentary{
In other words, constant objects are canonicalized.
In order to determine if an object is actually new, one has to compute it;
then it can be compared to any cached instances.
If an equivalent object exists in the cache,
we throw away the newly created object and use the cached one.
Objects are equivalent if
they have identical type arguments and identical instance variables.
Since the constructor cannot induce any side effects,
the execution of the constructor is unobservable.
The constructor need only be executed once per call site, at compile time.
}
\LMHash{}
It is a compile-time error if evaluation of a constant object
results in an uncaught exception being thrown.
\commentary{
To see how such situations might arise, consider the following examples:
}
%% TODO(eernst): Delete some \CONST{} when integrating implicit-creation.md
\begin{dartCode}
\CLASS{} A \{
\FINAL{} x;
\CONST{} A(p): x = p * 10;
\}
\\
\CLASS{} IntPair \{
\CONST{} IntPair(\THIS{}.x, \THIS{}.y);
\FINAL{} int x;
\FINAL{} int y;
\OPERATOR *(v) => \NEW{} IntPair(x*v, y*v);
\}
\\
\CONST a1 = \CONST{} A(true); // \comment{compile-time error}
\CONST a2 = \CONST{} A(5); // \comment{legal}
\CONST a3 = \CONST{} A(\CONST{} IntPair(1,2)); // \comment{compile-time error}
\end{dartCode}
\commentary{
Due to the rules governing constant constructors,
evaluating the constructor \code{A()}
with the argument \code{"x"} or the argument \code{\CONST{} IntPair(1, 2)}
would cause it to throw an exception, resulting in a compile-time error.
In the latter case, the error is caused by the fact that
\code{\OPERATOR{} *} can only be used with a few ``well-known'' types,
which is required in order to avoid running arbitrary code during
the evaluation of constant expressions.
}
\subsection{Spawning an Isolate}
\LMLabel{spawningAnIsolate}
\LMHash{}
Spawning an isolate is accomplished via what is syntactically an ordinary library call, invoking one of the functions \code{spawnUri()} or \code{spawn()} defined in the \code{dart:isolate} library.
However, such calls have the semantic effect of creating a new isolate with its own memory and thread of control.
\LMHash{}
An isolate's memory is finite, as is the space available to its thread's call stack.
It is possible for a running isolate to exhaust its memory or stack, resulting in a run-time error that cannot be effectively caught, which will force the isolate to be suspended.
\commentary{
As discussed in section \ref{errorsAndWarnings}, the handling of a suspended isolate is the responsibility of the embedder.
}
\subsection{Function Invocation}
\LMLabel{functionInvocation}
\LMHash{}
Function invocation occurs in the following cases:
when a function expression (\ref{functionExpressions}) is invoked (\ref{functionExpressionInvocation}),
when a method (\ref{methodInvocation}), getter (\ref{topLevelGetterInvocation}, \ref{propertyExtraction}) or setter (\ref{assignment}) is invoked,
or when a constructor is invoked
(either via instance creation (\ref{instanceCreation}), constructor redirection (\ref{redirectingGenerativeConstructors}), or super initialization).
The various kinds of function invocation differ as to how the function to be invoked, $f$, is determined, as well as whether \THIS{} (\ref{this}) is bound.
Once $f$ has been determined,
formal type parameters of $f$ are bound to the corresponding actual type arguments,
and the formal parameters of $f$ are bound to corresponding actual arguments.
When the body of $f$ is executed it will be executed with the aforementioned bindings.
\LMHash{}
Executing a body of the form \code{=> $e$} is equivalent to executing a body of the form \code{\{ return $e$; \}}.
Execution a body of the form \code{\ASYNC{} => $e$} is equivalent to executing a body of the form \code{\ASYNC{} \{ return $e$; \}}.
\LMHash{}
If $f$ is synchronous and is not a generator (\ref{functions}) then execution of the body of $f$ begins immediately.
If the execution of the body of $f$ returns a value, $v$, (\ref{completion}), the invocation evaluates to $v$.
If the execution completes normally or it returns without a value, the invocation evaluates to the null object (\ref{null}).
If the execution throws an exception object and stack trace, the invocation throws the same exception object and stack trace (\ref{evaluation}).
\commentary{
A complete function body can never break or contine (\ref{completion})
because a \BREAK{} or \CONTINUE{} statement must always occur inside the statement that is the target of the \BREAK{} or \CONTINUE{}.
This means that a function body can only either complete normally, throw, or return.
Completing normally or returning without a value is treated the same as returning the null object (\ref{null}), so the result of executing a function body can always be used as the result of evaluating an expression, either by evaluating to a value or by the evaluation throwing.
}
\LMHash{}
If $f$ is marked \code{\SYNC*} (\ref{functions}),
then a fresh instance (\ref{generativeConstructors}) $i$
implementing \code{Iterable<$U$>} is immediately returned,
where $U$ is determined as follows:
Let $T$ be the actual return type of $f$ (\ref{actualTypeOfADeclaration}).
If $T$ is \code{Iterable<$S$>} for some type $S$, then $U$ is $S$,
otherwise $U$ is \code{Object}.
\commentary{
A Dart implementation will need to provide a specific implementation of \code{Iterable} that will be returned by \code{\SYNC*} methods.
A typical strategy would be to produce an instance of a subclass of class \code{IterableBase} defined in \code{dart:core}.
The only method that needs to be added by the Dart implementation in that case is \code{iterator}.
}
\LMHash{}
The iterable implementation must comply with the contract of \code{Iterable} and should not take any steps identified as exceptionally efficient in that contract.
\commentary{
The contract explicitly mentions a number of situations where certain iterables could be more efficient than normal.
For example, by precomputing their length.
Normal iterables must iterate over their elements to determine their length.
This is certainly true in the case of a synchronous generator, where each element is computed by a function.
It would not be acceptable to pre-compute the results of the generator and cache them, for example.
}
\LMHash{}
When iteration over the iterable is started, by getting an iterator $j$ from the iterable and calling \code{moveNext()}, execution of the body of $f$ will begin.
When execution of the body of $f$ completes (\ref{completion}),
\begin{itemize}
\item If it returns without a value or it completes normally (\ref{completion}), $j$ is positioned after its last element, so that its current value is the null object (\ref{null}) and the current call to \code{moveNext()} on $j$ returns false, as must all further calls.
\item If it throws an exception object $e$ and stack trace $t$ then the current value of $j$ is the null object (\ref{null}) and the current call to \code{moveNext()} throws $e$ and $t$ as well.
Further calls to \code{moveNext()} must return false.
\end{itemize}
Each iterator starts a separate computation.
If the \code{\SYNC*} function is impure, the sequence of values yielded by each iterator may differ.
\commentary{
One can derive more than one iterator from a given iterable.
Note that operations on the iterable itself can create distinct iterators.
An example would be \code{length}.
It is conceivable that different iterators might yield sequences of different length.
The same care needs to be taken when writing \code{\SYNC*} functions as when
writing an \code{Iterator} class.
In particular, it should handle multiple simultaneous iterators gracefully.
If the iterator depends on external state that might change, it should check that the state is still valid after every yield (and maybe throw a \code{ConcurrentModificationError} if it isn't).
}
\LMHash{}
Each iterator runs with its own shallow copies of all local variables; in particular, each iterator has the same initial arguments, even if their bindings are modified by the function.
\commentary{
Two executions of an iterator interact only via state outside the function.
}
% The alternative would be to cache the results of an iterator in the iterable, and check the cache at each \YIELD{}. This would have strange issues as well. The yielded value might differ from the expression in the yield. And it is a potential memory leak as the cache is kept alive by any iterator.
\LMHash{}
If $f$ is marked \ASYNC{} (\ref{functions}),
then a fresh instance (\ref{generativeConstructors}) $o$ is associated with the invocation,
where the dynamic type of $o$ implements \code{Future<$flatten(T)$>},
and $T$ is the actual return type of $f$ (\ref{actualTypeOfADeclaration}).
Then the body of $f$ is executed until it either suspends or completes, at which point $o$ is returned.
\commentary{
The body of $f$ may suspend during the evaluation of an \AWAIT{} expression or execution of an asynchronous \FOR{} loop.
}
The future $o$ is completed when execution of the body of $f$ completes (\ref{completion}).
If execution of the body returns a value, $o$ is completed with that value,
if it completes normally or returns without a value,
$o$ is completed with the null object (\ref{null}),
and if it throws an exception $e$ and stack trace $t$,
$o$ is completed with the error $e$ and stack trace $t$.
If execution of the body throws before the body suspends the first time,
completion of $o$ happens at some future time after the invocation has returned.
\rationale{
The caller needs time to set up error handling for the returned future,
so the future is not completed with an error {\em before} it has been returned.
}
\LMHash{}
If $f$ is marked \code{\ASYNC*} (\ref{functions}),
then a fresh instance (\ref{generativeConstructors}) $s$
implementing \code{Stream<$U$>} is immediately returned,
where $U$ is determined as follows:
Let $T$ be the actual return type of $f$ (\ref{actualTypeOfADeclaration}).
If $T$ is \code{Stream<$S$>} for some type $S$, then $U$ is $S$,
otherwise $U$ is \code{Object}.
When $s$ is listened to, execution of the body of $f$ will begin.
When execution of the body of $f$ completes:
\begin{itemize}
\item If it completes normally or returns with no value (\ref{completion}), then if $s$ has been canceled then its cancellation future is completed with the null object (\ref{null}).
\item If it throws an exception object $e$ and stack trace $t$:
\begin{itemize}
\item If $s$ has been canceled then its cancellation future is completed with error $e$ and stack trace $t$.
\item otherwise the error $e$ and stack trace $t$ are emitted by $s$.
\end{itemize}
\item $s$ is closed.
\end{itemize}
\commentary{
The body of an asynchronous generator function cannot break, continue or return a value (\ref{completion}).
The first two are only allowed in contexts that will handle the break or continue, and return statements with an expression are not allowed in generator functions.
}
\rationale{
When an asynchronous generator's stream has been canceled, cleanup will occur in the \FINALLY{} clauses (\ref{try}) inside the generator.
We choose to direct any exceptions that occur at this time to the cancellation future rather than have them be lost.
}
%\LMHash{}
%When a stream is canceled, the implementation must wait for the cancelation future returned by \code{cancell()} to complete before proceeding.
\subsubsection{Actual Argument Lists}
\LMLabel{actualArgumentLists}
\LMHash{}
Actual argument lists have the following syntax:
\begin{grammar}
<arguments> ::= `(' (<argumentList> `,'?)? `)'
<argumentList> ::= <namedArgument> (`,' <namedArgument>)*
\alt <expressionList> (`,' <namedArgument>)*
<namedArgument> ::= <label> <expression>
\end{grammar}
\LMHash{}
Argument lists allow an optional trailing comma after the last argument (\syntax{`,'?}).
An argument list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma.
All argument lists in this specification are shown without a trailing comma,
but the rules and semantics apply equally to the corresponding argument list with a trailing comma.
\LMHash{}
Let $L$ be an argument list of the form
\code{($e_1 \ldots,\ e_m,\ y_{m+1}$: $e_{m+1} \ldots,\ y_{m+p}$: $e_{m+p}$)}
and assume that the static type of $e_i$ is $S_i$, $i \in 1 .. m+p$.
The {\em static argument list type} of $L$ is then
\code{($S_1 \ldots,\ S_m,\ S_{m+1}\ y_{m+1} \ldots,\ S_{m+p}\ y_{m+p}$)}.
\LMHash{}
Let $\argumentList{S}$ be the static argument list type
\code{($S_1 \ldots,\ S_m,\ S_{m+1}\ y_{m+1} \ldots,\ S_{m+p}\ y_{m+p}$)}
\noindent
and let $\parameterList{P}$ be the formal parameter list
\code{($T_1\ x_1 \ldots,\ T_n\ x_n,\ $[$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$])}
\noindent
where each parameter may be marked \COVARIANT{} (\commentary{not shown, but allowed}).
\LMHash{}
We say that $\argumentList{S}$ {\em is a subtype match} for $\parameterList{P}$
if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is a subtype of $T_i$ for all $i \in 1 .. m$.
We say that $\argumentList{S}$ {\em is an assignable match} for $\parameterList{P}$
if{}f $p = 0$, $n \leq m \leq n+k$, and $S_i$ is assignable to $T_i$ for all $i \in 1 .. m$.
\LMHash{}
Let $\argumentList{S}$ be the static argument list type
\code{($S_1 \ldots,\ S_m,\ S_{m+1}\ y_{m+1} \ldots,\ S_{m+p}\ y_{m+p}$)}
\noindent
and let $\parameterList{P}$ be the formal parameter list
\code{($T_1\ x_1 \ldots,\ T_n\ x_n,\ $\{$T_{n+1}\ x_{n+1} = d_1, \ldots,\ T_{n+k}\ x_{n+k} = d_k$\})}
\noindent
where each parameter may be marked \COVARIANT{} (\commentary{not shown, but allowed}).
\LMHash{}
We say that $\argumentList{S}$ {\em is a subtype match} for $\parameterList{P}$
if{}f $m = n$,
$\{y_{m+1}\ldots,\ y_{m+p}\} \subseteq \{x_{n+1}\ldots,\ x_{n+k}\}$,
$S_i$ is a subtype of $T_i$ for all $i \in 1 .. m$,
and $S_i$ is a subtype of $T_j$ whenever $y_i = x_j$ and
$j \in n + 1 .. n + k$, for all
$i \in m + 1 .. m + p$.
We say that $\argumentList{S}$ {\em is an assignable match} for $\parameterList{P}$
if{}f $m = n$,
$\{y_{m+1}\ldots,\ y_{m+p}\} \subseteq \{x_{n+1}\ldots,\ x_{n+k}\}$,
$S_i$ is assignable to $T_i$ for all $i \in 1 .. m$,
and $S_i$ is assignable to $T_j$ whenever $y_i = x_j$ and
$j \in n + 1 .. n + k$, for all
$i \in m + 1 .. m + p$.
\commentary{
In short, an actual argument list is a match for a formal parameter list
whenever the former can safely be passed to the latter.
}
\subsubsection{Actual Argument List Evaluation}
\LMLabel{actualArguments}
\LMHash{}
Function invocation involves evaluation of the list of actual arguments to the function,
and binding of the results to the function's formal parameters.
\LMHash{}
When parsing an argument list, an ambiguity may arise because the same source code could be one generic function invocation,
and it could be two or more relational expressions and/or shift expressions.
In this situation, the expression is always parsed as a generic function invocation.
% Should we specify the precise disambiguation rule here?:
% We have seen 'a', '<', a matching '>', and '(', where
% 'a' is tricky because we can have things like 'new Foo().m<...>(...',
% 'x..y(...).m<...>(...', etc, basically everything that can precede
% argumentPart in the grammar.
\commentary{
An example is \code{f(a<B, C>($d$))}, which may be an invocation of \code{f} passing two actual arguments of type \code{bool}, or an invocation of \code{f} passing the result returned by an invocation of the generic function \code{a}.
Note that the ambiguity can be eliminated by omitting the parentheses around the expression $d$, or adding parentheses around one of the relational expressions.
}
\rationale{
When the intention is to pass several relational or shift expressions as actual arguments and there is an ambiguity, the source code can easily be adjusted to a form which is unambiguous.
Also, we expect that it will be more common to have generic function invocations as actual arguments than having relational or shift expressions that happen to match up and have parentheses at the end, such that the ambiguity arises.
}
\LMHash{}
Evaluation of an actual argument part of the form
\code{<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_m,\ q_1$: $a_{m+1}, \ldots,\ q_l$: $a_{m+l}$)}
proceeds as follows:
\LMHash{}
The type arguments $A_1, \ldots, A_r$ are evaluated in the order they appear in the program, producing types $t_1, \ldots, t_r$.
The arguments $a_1, \ldots, a_{m+l}$ are evaluated in the order they appear in the program, producing objects $o_1, \ldots, o_{m+l}$.
\commentary{
Simply stated, an argument part consisting of $s$ type arguments, $m$ positional arguments, and $l$ named arguments is evaluated from left to right.
Note that the type argument list is omitted when $r = 0$ (\ref{generics}).
}
\subsubsection{Binding Actuals to Formals}
\LMLabel{bindingActualsToFormals}
\commentary{
In the following, the non-generic case is covered implicitly:
When the number of actual type arguments is zero
the entire type argument list \code{<\ldots{}>} is omitted,
and similarly for empty type parameter lists (\ref{generics}).
}
\LMHash{}
Consider an invocation $i$ of a function $f$ with an actual argument part of the form
\code{<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_m,\ q_1$: $a_{m+1}, \ldots,\ q_l$: $a_{m+l}$)}.
\commentary{
Note that $f$ denotes a function in a semantic sense,
rather than a syntactic construct.
A reference to this section is used in other sections
when the static analysis of an invocation is specified,
and the static type of $f$ has been determined.
The function itself may have been obtained from a function declaration,
from an instance bound to \THIS{} and an instance method declaration,
or as a function object obtained by evaluation of an expression.
Because of that, we cannot indicate here which syntactic construct
corresponds to $f$.
%
A reference to this section is also used in other sections
when actual arguments are to be bound to the corresponding formal parameters,
and $f$ is about to be invoked, to specify the dynamic semantics.
}
\commentary{
We do not call $f$ a `function object' here, because we do not wish to imply
that every function invocation must involve a separate evaluation
of an expression that yields a function object,
followed by an invocation of that function object.
For instance, an implementation should be allowed to compile the invocation
of a top-level function as a series of steps whereby a stack frame is
created, followed by a low-level jump to the generated code for the body.
So, in this section,
the word `function' is more low-level than `function object',
but `function' still denotes a semantic entity
which is associated with a function declaration,
even though there may not be corresponding entity in the heap at run time.
}
\LMHash{}
% We cannot pass the same named parameter twice.
It is a compile-time error if $q_j = q_k$ for any $j \ne k$.
\LMHash{}
If the static type of $f$ is \DYNAMIC{} or the built-in class \FUNCTION{},
no further static checks are performed and the static type of $i$ is \DYNAMIC{};
otherwise, it is a compile-time error if the static type of $f$ is not a function type.
\LMHash{}
Otherwise, the static type of $f$ is a function type $F$.
Let $S_0$ be the return type of $F$,
let $X_1\ \EXTENDS\ B_1, \ldots, X_s\ \EXTENDS\ B_s$
be the formal type parameters,
let $h$ be the number of required parameters,
let $p_1, \ldots, p_n$ be the positional parameters,
and let $p_{h+1}, \ldots, p_{h+k}$ be the optional parameters of $F$.
Let $S_i$ be the static type of the formal parameters $p_i, i \in 1 .. h+k$,
and for each $q$ let $S_q$ be the type of the parameter named $q$,
where each parameter type is obtained by replacing $X_j$ by $A_j, j \in 1 .. s$, in the given parameter type annotation.
Finally, let $T_i$ be the static type of $a_i$.
\commentary{
We have an actual argument list consisting of $r$ type arguments, $m$ positional arguments, and $l$ named arguments.
We have a function with $s$ type parameters, $h$ required parameters, and $k$ optional parameters.
Figure~\ref{fig:argumentsAndParameters} shows how this situation may arise.
}
% View on declaration:
%
% |** ... *|** ... *|** ... *|
% <-s type par.s--> <--h required par.s---> <--k optional par.s->
% <--n pos, par.s, h=n--> <---k named par.s---> NAMED
% <----------n positional par.s, n=h+k--------> POS
%
% Actual argument part:
%
% |** ... *|** ... *|** ... *|
% <-r type arg.s--> <----m positional arg.s---> <--l named arg.s->
\begin{figure}[h]
\def\A#1{\mbox{\commentary{{#1} arguments}}}
\def\P#1{\mbox{\commentary{{#1} parameters}}}
%
\flushleft{\commentary{Actual arguments:}}
\begin{displaymath}
\begin{array}{rl}
\left<\A{$r$ type}\right>
\left(
\begin{array}{r@{,\;}l}
\A{$m$ positional}&\A{$l$ named}
\end{array}
\right)
\end{array}
\end{displaymath}
%
\flushleft{\commentary{Declaration with named parameters: $n = h$}}
\begin{displaymath}
\begin{array}{rl}
\left<\P{$s$ type}\right>
\left(
\begin{array}{r@{,\;}l}
\P{$h$ required}&\P{$k$ optional}\\
\multicolumn{2}{c}{\mbox{\scriptsize\textit{which may also be viewed as}}}\\
\P{$n$ positional}&\P{$k$ named}\\
\end{array}
\right)
\end{array}
\end{displaymath}
%
\flushleft{\commentary{Declaration with optional positional parameters: $n = h + k$}}
\begin{displaymath}
\begin{array}{rl}
\left<\P{$s$ type}\right>
\left(
\begin{array}{r@{,\;}l}
\P{$h$ required}&\P{$k$ optional}\\
\multicolumn{2}{c}{\mbox{\scriptsize\textit{which may also be viewed as}}}\\
\multicolumn{2}{c}{\P{$n$ positional}}
\end{array}
\right)
\end{array}
\end{displaymath}
%
\caption{Possible actual argument parts and formal parameter parts}
\label{fig:argumentsAndParameters}
\end{figure}
\LMHash{}
% Type inference is assumed complete, so we must have the correct number of type arguments.
It is a compile-time error if $r \not= s$.
It is a compile-time error if $r = s$ and for some $j \in 1 .. s$,
$A_j \not<: [A_1/X_1, \ldots, A_r/X_s]B_j$.
It is a compile-time error unless $h \le m \le n$.
If $l > 0$,
it is a compile-time error unless $F$ has named parameters and
$q_j \in \{p_{h+1}, \ldots, p_{h+k}\}, j \in 1 .. l$.
\commentary{
That is, the number of type arguments must match the number of type parameters,
and the bounds must be respected.
We must receive at least the required number of positional arguments,
and not more than the total number of positional parameters.
For each named argument there must be a named parameter with the same name.
}
\LMHash{}
The static type of $i$ is $[A_1/X_1, \ldots, A_r/X_s]S_0$.
\LMHash{}
It is a compile-time error if $T_j$ may not be assigned to $S_j, j \in 1 .. m$.
It is a compile-time error if $T_{m+j}$ may not be assigned to $S_{q_j}, j \in 1 .. l$.
\LMHash{}
For the dynamic semantics,
let $f$ be a function with $s$ type parameters and $h$ required parameters;
let $p_1, \ldots, p_n$ be the positional parameters of $f$;
and let $p_{h+1}, \ldots, p_{h+k}$ be the optional parameters declared by $f$.
\LMHash{}
An evaluated actual argument part
\code{<$t_1, \ldots,\ t_r$>($o_1, \ldots,\ o_m,\ q_1$: $o_{m+1},\ \ldots,\ q_l$: $o_{m+l}$)}
\noindent
derived from an actual argument part of the form
\code{<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_m,\ q_1$: $a_{m+1}, \ldots,\ q_l$: $a_{m+l}$)}
\noindent
is bound to the formal type parameters and formal parameters of $f$ as follows:
\LMHash{}
% Passing a wrong number of actual type arguments.
If $r = 0$ and $s > 0$ then replace the actual type argument list:
%% TODO[instantiate-to-bound]: The actual type arguments passed here
%% should be chosen based on the instantiate-to-bound algorithm, but we
%% cannot yet refer to that because it hasn't yet been specified here.
let $r$ be $s$ and $t_i = \DYNAMIC{}$ for $i \in 1 .. s$.
Then, if $r \not= s$, a \code{NoSuchMethodError} is thrown.
% Passing named arguments to a function with optional positional parameters.
If $l > 0$ and $n \not= h$, a \code{NoSuchMethodError} is thrown.
% Passing too few or too many positional arguments.
If $m < h$, or $m > n$, a \code{NoSuchMethodError} is thrown.
% When l>0, h=n and there are k named parameters p_{h+1}..p_{h+k}.
Furthermore, each
$q_i, i \in 1 .. l$,
must have a corresponding named parameter in the set
$\{p_{h+1}, \ldots, p_{h+k}\}$,
or a \code{NoSuchMethodError} is thrown.
% Finally, bindings!
Then $p_i$ is bound to
$o_i, i \in 1 .. m$,
and $q_j$ is bound to $o_{m+j}, j \in 1 .. l$.
All remaining formal parameters of $f$ are bound to their default values.
\commentary{
All of these remaining parameters are necessarily optional and thus have default values.
}
\LMHash{}
% Check the type arguments.
It is a dynamic type error if $t_i$ is not a subtype of the actual bound
(\ref{actualTypeOfADeclaration})
of the $i$th type argument of $f$, for actual type arguments $t_1, \ldots, t_r$.
% Check the types of positional arguments.
It is a dynamic type error if $o_i$ is not the null object (\ref{null})
and the actual type
(\ref{actualTypeOfADeclaration})
of $p_i$ is not a supertype of the dynamic type of $o_i, i \in 1 .. m$.
% Check the types of named arguments.
It is a dynamic type error if $o_{m+j}$ is
not the null object and the actual type
(\ref{actualTypeOfADeclaration})
of $q_j$ is not a supertype of the dynamic type of $o_{m+j}, j \in 1 .. l$.
\subsubsection{Unqualified Invocation}
\LMLabel{unqualifiedInvocation}
\LMHash{}
An unqualified function invocation $i$ has the form
\code{\id<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
\noindent
where \id{} is an identifier.
\commentary{
Note that the type argument list is omitted when $r = 0$ (\ref{generics}).
}
\LMHash{}
It is a compile-time error if $i$ occurs inside a top-level or static function
(be it function, method, getter, or setter)
or a top-level or static variable initializer,
and there is no lexically visible declaration named \id{} in scope.
\LMHash{}
If there exists a lexically visible declaration named \id,
let $f_{id}$ be the innermost such declaration.
Then:
\begin{itemize}
\item It is a compile-time error if $f_{id}$ denotes a type
(\commentary{that is, if \id{} is a type literal or type variable}),
unless \id{} denotes a constructor.
\item It is a compile-time error if $f_{id}$ is an import directive
where \id{} is declared to be a library prefix.
\item
If $f_{id}$ is
a local function,
a library function,
a library or static getter or a variable,
$i$ is interpreted as a function expression invocation
(\ref{functionExpressionInvocation}).
\item
Otherwise, if $f_{id}$ is a static method of the enclosing class $C$,
$i$ is equivalent to
\code{$C$.\id<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\item Otherwise, if $i$ occurs in an instance method body,
$i$ is equivalent to the ordinary method invocation
\code{\THIS{}.\id<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\end{itemize}
\commentary{
Otherwise $i$ must occur inside a top-level or static function
(be it function, method, getter, or setter)
or a top-level or static variable initializer,
in which case a compile-time error occurs
(\ref{unqualifiedInvocation}).
}
\subsubsection{Function Expression Invocation}
\LMLabel{functionExpressionInvocation}
\LMHash{}
A function expression invocation $i$ has the form
\code{$e_f$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)},
\noindent
where $e_f$ is an expression.
\commentary{
Note that the type argument list is omitted when $r = 0$ (\ref{generics}).
}
\LMHash{}
If $e_f$ is an identifier \id, then \id{} must necessarily denote
a local function, a library function, a library or static getter or a variable as described above,
or $i$ is not considered a function expression invocation.
It is a compile-time error if $e_f$ is a type literal,
unless $e_f$ denotes a constructor.
\commentary{
This error was already specified elsewhere
(\ref{unqualifiedInvocation})
for the case where $e_f$ is an identifier,
but $e_f$ may also have other forms, e.g., \code{p.C}.
}
\LMHash{}
If $e_f$ is a property extraction expression (\ref{propertyExtraction}),
then $i$ isn't a function expression invocation and is instead recognized as an ordinary method invocation (\ref{ordinaryInvocation}).
\commentary{
\code{$a.b(x)$} is parsed as a method invocation of method \code{$b()$} on object \code{$a$}, not as an invocation of getter \code{$b$} on \code{$a$} followed by a function call \code{$(a.b)(x)$}.
If a method or getter \code{$b$} exists, the two will be equivalent.
However, if \code{$b$} is not defined on \code{$a$}, the resulting invocation of \code{noSuchMethod()} would differ.
The \code{Invocation} passed to \code{noSuchMethod()} would describe a call to a method \code{$b$} with argument \code{$x$} in the former case, and a call to a getter \code{$b$} (with no arguments) in the latter.
}
\LMHash{}
Let $F$ be the static type of $e_f$.
The static analysis of $i$ is performed as specified in Section~\ref{bindingActualsToFormals},
and the static type of $i$ is as specified there.
\LMHash{}
Evaluation of a function expression invocation
\code{$e_f$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
\noindent
proceeds to evaluate $e_f$, yielding an object $o$.
Let $f$ be a fresh variable bound to $o$.
If $o$ is a function object then the function invocation
\code{$f$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
is evaluated by binding actuals to formals as specified in Section~\ref{bindingActualsToFormals},
and executing the body of $f$ with those bindings;
the returned result is then the result of evaluating $i$.
\LMHash{}
Otherwise $o$ is not a function object.
If $o$ has a method named \CALL{}
the following ordinary method invocation is evaluated,
and its result is then the result of evaluating $i$:
\code{$f$.call<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
Otherwise $o$ has no method named \CALL{}.
A new instance $im$ of the predefined class \code{Invocation} is created, such that:
\begin{itemize}
\item \code{$im$.isMethod} evaluates to \code{\TRUE{}}.
\item \code{$im$.memberName} evaluates to the symbol \code{\#call}.
\item \code{$im$.positionalArguments} evaluates to an unmodifiable list with the values
resulting from evaluation of
\code{<Object>[$a_1, \ldots,\ a_n$]}.
\item \code{$im$.namedArguments} evaluates to an unmodifiable map
with the keys and values resulting from evaluation of
\code{<Symbol, Object>\{$\#x_{n+1}$: $a_{n+1}, \ldots,\ \#x_{n+k}$: $a_{n+k}$\}}.
\item \code{$im$.typeArguments} evaluates to an unmodifiable list
with the values resulting from evaluation of
\code{<Type>[$A_1, \ldots,\ A_r$]}.
\end{itemize}
\LMHash{}
Then the method invocation \code{f.noSuchMethod($im$)} is evaluated,
and its result is then the result of evaluating $i$.
\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
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.
}
\subsection{Function Closurization}
\LMLabel{functionClosurization}
\LMHash{}
Let $f$ be an expression denoting
a declaration of a local function, a static method, or a top-level function
(\ref{identifierReference})
or let $f$ be a function literal
(\ref{functionExpressions}).
Evaluation of $f$ yields a function object
which is the outcome of a {\em function closurization}
applied to the declaration denoted by $f$
respectively to the function literal $f$ considered as a function declaration.
% Note that we do not promise that this will be a fresh function object,
% such that constant expressions are covered as well, and others may be
% identical even if not required, e.g., local functions with no free variables.
{\em Closurization} denotes instance method closurization
(\ref{ordinaryMemberClosurization})
as well as function closurization,
and it is also used as a shorthand for either of them when there is no ambiguity.
\LMHash{}
Function closurization applied to a function declaration $f$
amounts to the creation of a function object $o$
which is an instance of a class whose interface is a subtype of the actual type
(\ref{actualTypeOfADeclaration})
corresponding to the signature in the function declaration $f$,
using the current bindings of type variables, if any.
If $f$ denotes a static method or top-level function,
the corresponding class does not override the \code{==} operator
inherited from the \code{Object} class.
%
An invocation of $o$ with a given argument list will bind actuals to formals
in the same way as an invocation of $f$
(\ref{bindingActualsToFormals}),
and then execute the body of $f$
in the captured scope amended with the bound parameter scope,
yielding the same completion
(\ref{completion})
as the invocation of $f$ would have yielded.
\subsection{Lookup}
\LMLabel{lookup}
\LMHash{}
A {\em lookup} is a procedure which selects
a concrete instance member declaration based on a traversal of
a sequence of classes, starting with a given class $C$
and proceeding with the superclass of the current class at each step.
A lookup may be part of the static analysis, and it may be performed
at run time. It may succeed or fail.
\commentary{
We define several kinds of lookup with a very similar structure.
We spell out each of them in spite of the redundancy,
in order to avoid introducing meta-level abstraction mechanisms just for this purpose.
The point is that we must indicate for each lookup which kind of member it is looking for,
because, e.g., a `method lookup' and a `getter lookup' are used in different situations.
}
{ % Scope for 'lookup' definition.
\def\LookupDefinitionWithStart#1{
\LMHash{}
The result of a
{\em {#1} lookup for $m$ in $o$ with respect to $L$ starting in class $C$}
is the result of a {#1} lookup for $m$ in $C$ with respect to $L$.
The result of a {\em {#1} lookup for $m$ in $C$ with respect to $L$} is:
If $C$ declares a concrete instance {#1} named $m$
that is accessible to $L$,
then that {#1} declaration is the result of the {#1} lookup,
and we say that the {#1} was {\em looked up in $C$}.
Otherwise, if $C$ has a superclass $S$,
the result of the {#1} lookup is
the result of a {#1} lookup for $m$ in $S$ with respect to $L$.
Otherwise, we say that the {#1} lookup has failed.
}
\LMHash{}
Let $m$ be an identifier, $o$ an object, $L$ a library,
and $C$ a class which is the class of $o$ or a superclass thereof.
\LookupDefinitionWithStart{method}
\LookupDefinitionWithStart{getter}
\LookupDefinitionWithStart{setter}
\def\LookupDefinition#1{%
The result of a
{\em {#1} lookup for $m$ in $o$ with respect to $L$}
is the result of a
{#1} lookup for $m$ in $o$ with respect to $L$
starting with the class of $o$.
}
\LMHash{}
Let $m$ be an identifier, $o$ an object, and $L$ a library.
\LookupDefinition{method}
\LookupDefinition{getter}
\LookupDefinition{setter}
} % End of scope for lookup definitions.
\commentary{
Note that for getter (setter) lookup, the result may be
a getter (setter) which has been induced by an instance variable
declaration.
}
\commentary{
Note that we sometimes use phrases like `looking up method $m$'
to indicate that a method lookup is performed,
and similarly for setter lookups and getter lookups.
}
\rationale{
The motivation for ignoring abstract members during lookup is largely to allow smoother mixin composition.
}
\subsection{Top level Getter Invocation}
\LMLabel{topLevelGetterInvocation}
\LMHash{}
Evaluation of a top-level getter invocation $i$ of the form $m$, where $m$ is an identifier, proceeds as follows:
\LMHash{}
The getter function $m$ is invoked.
The value of $i$ is the result returned by the call to the getter function.
\commentary{
Note that the invocation is always defined.
Per the rules for identifier references, an identifier will not be treated as a top-level getter invocation unless the getter $i$ is defined.
}
\LMHash{}
The static type of $i$ is the declared return type of $m$.
\subsection{Method Invocation}
\LMLabel{methodInvocation}
\LMHash{}
Method invocation can take several forms as specified below.
\subsubsection{Ordinary Invocation}
\LMLabel{ordinaryInvocation}
\LMHash{}
An ordinary method invocation can be {\em conditional} or {\em unconditional}.
\LMHash{}
\Case{\code{$e$?.$m$<$\cdots$>($\cdots$)}}
Consider a {\em conditional ordinary method invocation} $i$ of the form
\code{$e$?.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\commentary{
Note that non-generic invocations arise as the special case where the number of type arguments is zero,
in which case the type argument list is omitted,
and similarly for formal type parameter lists (\ref{generics}).
}
\LMHash{}
The static type of $i$ is the same as the static type of
\code{$e$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\noindent
Exactly the same compile-time errors that would be caused by
\code{$e$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
\noindent
are also generated in the case of $i$.
\LMHash{}
Evaluation of $i$ proceeds as follows:
\LMHash{}
If $e$ is a type literal, $i$ is equivalent to
\code{$e$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
Otherwise, evaluate $e$ to an object $o$.
If $o$ is the null object, $i$ evaluates to the null object (\ref{null}).
Otherwise let $v$ be a fresh variable bound to $o$ and evaluate
\code{$v$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
to a value $r$.
Then $e$ evaluates to $r$.
\LMHash{}
\Case{\code{$e$.$m$<$\cdots$>($\cdots$)}}
An {\em unconditional ordinary method invocation} $i$ has the form
\code{$e$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\commentary{
Non-generic invocations again arise as the special case
where the number of type arguments is zero (\ref{generics}).
}
\LMHash{}
Let $T$ be the static type of $e$.
It is a compile-time error if $T$ does not have an accessible (\ref{privacy}) instance member named $m$, unless either:
\begin{itemize}
\item
%% TODO(eernst): This is metaclass stuff, should be deleted.
$T$ is \code{Type}, $e$ is a constant type literal,
and the class corresponding to $e$ has a static getter named $m$.
Or
\item $T$ is \DYNAMIC{}.
Or
\item $T$ is \FUNCTION{} and $m$ is \CALL.
\rationale{
This means that for invocations of an instance method named \CALL,
a receiver of type \FUNCTION{} is treated like a receiver of type \DYNAMIC{}.
The expectation is that any concrete subclass of \FUNCTION{} will implement \CALL,
but there is no method signature which can be assumed for \CALL{} in \FUNCTION{}
because every signature will conflict with some potential overriding declarations.
Note that any use of \CALL{} on a subclass of \FUNCTION{} that fails to implement \CALL{} will provoke a compile-time error,
as this exemption is limited to type \FUNCTION{}, and does not apply to its subtypes.
}
\end{itemize}
\LMHash{}
If $T$ did not have an accessible member named $m$ the static type of $i$ is \DYNAMIC{},
and no further static checks are performed on $i$
(\commentary{except that subexpressions of $i$ are subject to their own static analysis}).
\LMHash{}
Otherwise \code{$T$.$m$} denotes an instance member.
Let $L$ be the library that contains $i$.
Let $d$ be the result of method lookup for $m$ in $T$ with respect to $L$,
and if the method lookup succeeded then let $F$ be the static type of $d$.
Otherwise, let $d$ be the result of getter lookup for $m$ in $T$ with respect to $L$
and let $F$ be the return type of $d$.
(\commentary{Since \code{$T$.$m$} exists we cannot have a failure in both lookups.})
\LMHash{}
The static analysis of $i$ is performed as specified in Section~\ref{bindingActualsToFormals},
and the static type of $i$ is as specified there.
\LMHash{}
It is a compile-time error to invoke any of the methods of class \code{Object} on a prefix object (\ref{imports})
or on a constant type literal that is immediately followed by the token `.'\,.
\rationale{
The reason for the latter is that this syntax is reserved for invocation of static methods.
For instance, \code{int.toString()} is similar to \code{C.someStaticMethod()}, and
it would be confusing if just a couple of expressions of this form were instance method invocations.
If needed, \code{(int).toString()} may be used instead.
}
\LMHash{}
Evaluation of an unconditional ordinary method invocation $i$ of the form
\code{$e$.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
proceeds as follows:
\LMHash{}
First, the expression $e$ is evaluated to a value $o$.
Let $f$ be the result of looking up (\ref{lookup}) method $m$ in $o$ with respect to the current library $L$.
\LMHash{}
%% TODO(eernst): This is metaclass stuff, should be deleted.
If method lookup succeeded,
but $o$ is an instance of \code{Type} and $e$ is not a constant type literal,
then if $m$ is a method that forwards (\ref{functionDeclarations}) to a static method,
method lookup is considered to have failed.
\LMHash{}
If the method lookup succeeded,
the binding of actual arguments to formal parameters is performed as specified in Section~\ref{bindingActualsToFormals}.
The body of $f$ is then executed with respect to the bindings that resulted from the evaluation of the argument list,
and with \THIS{} bound to $o$.
The value of $i$ is the value returned by the execution of $f$'s body.
\LMHash{}
If the method lookup failed,
then let $g$ be the result of looking up getter (\ref{lookup}) $m$ in $o$ with respect to $L$.
%% TODO(eernst): This is metaclass stuff, should be deleted.
If getter lookup succeeded,
but $o$ is an instance of \code{Type} and $e$ is not a constant type literal,
then if $g$ is a getter that forwards to a static getter,
getter lookup is considered to have failed.
\LMHash{}
If the getter lookup succeeded then invoke the getter $o.m$
and let $v_g$ be the returned value.
Then the value of $i$ is the value of
\code{$v_g$<$A_1, \ldots,\ A_r$>($a_1,\ \ldots,\ a_n,\ x_{n+1}$: $a_{n+1},\ \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\LMHash{}
If getter lookup has also failed,
then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
\begin{itemize}
\item \code{$im$.isMethod} evaluates to \code{\TRUE{}}.
\item \code{$im$.memberName} evaluates to the symbol \code{m}.
\item \code{$im$.positionalArguments} evaluates to an unmodifiable list
with the values resulting from the evaluation of
\code{<Object>[$a_1, \ldots,\ a_n$]}.
\item \code{$im$.namedArguments} evaluates to an unmodifiable map
with the keys and values resulting from the evaluation of
\code{<Symbol, Object>\{$\#x_{n+1}$: $a_{n+1}, \ldots,\ \#x_{n+k}$: $a_{n+k}$\}}.
\item \code{$im$.typeArguments} evaluates to an unmodifiable list
with the values resulting from the evaluation of
\code{<Type>[$A_1, \ldots,\ A_r$]}.
\end{itemize}
\LMHash{}
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$.
\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$.
}
\subsubsection{Cascaded Invocations}
\LMLabel{cascadedInvocations}
\LMHash{}
A {\em cascaded method invocation} has the form \code{$e$..\metavar{suffix}}
where $e$ is an expression and \metavar{suffix} is a sequence of operator, method, getter or setter invocations.
\begin{grammar}
<cascadeSection> ::= `..' (<cascadeSelector> <argumentPart>*)
\gnewline{} (<assignableSelector> <argumentPart>*)*
\gnewline{} (<assignmentOperator> <expressionWithoutCascade>)?
<cascadeSelector> ::= `[' <expression> `]'
\alt <identifier>
<argumentPart> ::=
<typeArguments>? <arguments>
\end{grammar}
\LMHash{}
Evaluation of a cascaded method invocation expression $c$ of the form \code{$e$..\metavar{suffix}} proceeds as follows:
Evaluate $e$ to an object $o$.
Let $t$ be a fresh variable bound to $o$.
Evaluate \code{$t$.\metavar{suffix}} to an object.
Then $c$ evaluates to $o$.
\LMHash{}
The static type of $c$ is the static type of $e$.
\rationale{
With the introduction of null-aware conditional assignable expressions (\ref{assignableExpressions}), it would make sense to extend cascades with a null-aware conditional form as well.
One might define \code{$e$?..\metavar{suffix}} to be equivalent to the expression \code{$t$ == \NULL{} ? \NULL{} : $t$.\metavar{suffix}} where $t$ is a fresh variable bound to the value of $e$.
The present specification has not added such a construct, in the interests of simplicity and rapid language evolution.
However, Dart implementations may experiment with such constructs, as noted in section \ref{ecmaConformance}.
}
\subsubsection{Super Invocation}
\LMLabel{superInvocation}
% Conditional super invocation is meaningless: \THIS{} is not null.
\LMHash{}
A super method invocation $i$ has the form
\code{\SUPER{}.$m$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}.
\commentary{
Note that non-generic invocations arise as the special case where the number of type arguments is zero,
in which case the type argument list is omitted,
and similarly for formal type parameter lists (\ref{generics}).
}
\LMHash{}
It is a compile-time error if a super method invocation occurs in a top-level function or variable initializer,
in an instance variable initializer or initializer list,
in class \code{Object},
in a factory constructor,
or in a static method or variable initializer.
{ % Scope for superclass name.
\def\SuperClass{\ensuremath{S_{\mbox{\scriptsize{}super}}}}
\LMHash{}
Let \SuperClass{} be the superclass (\ref{superclasses})
of the immediately enclosing class for $i$,
and let $L$ be the library that contains $i$.
Let the declaration $d$ be
the result of looking up the method $m$ in \SuperClass{}
with respect to $L$ (\ref{lookup}),
and let $F$ be the static type of $d$.
Otherwise, if the method lookup failed,
let the declaration $d$ be the result of looking up
the getter $m$ with respect to $L$ in \SuperClass{}
(\ref{lookup}),
and let $F$ be the return type of $d$.
If both lookups failed, a compile-time error occurs.
\LMHash{}
Otherwise (\commentary{when one of the lookups succeeded}),
the static analysis of $i$ is performed as specified in Section~\ref{bindingActualsToFormals},
considering the function to have static type $F$,
and the static type of $i$ is as specified there.
\commentary{
Note that member lookups ignore abstract declarations,
which means that there will be a compile-time error if the targeted member $m$ is abstract,
as well as when it does not exist at all.
}
\LMHash{}
Evaluation of $i$ proceeds as follows:
Let $o$ be the current binding of \THIS{},
let $C$ be the enclosing class for $i$,
and let \SuperClass{} be the superclass (\ref{superclasses}) of $C$.
Let the declaration $d$ be the result of looking up
the method $m$ with respect to $L$ in $o$ starting with \SuperClass{}
(\ref{lookup}).
If the lookup succeeded,
let $f$ denote the function associated with $d$.
%
Otherwise (\commentary{when method lookup failed}),
let the declaration $d$ be the result of looking up
the getter $m$ with respect to $L$ in $o$ starting with \SuperClass{}
(\ref{lookup}).
If the getter lookup succeeded,
invoke said getter with \THIS{} bound to $o$,
and let $f$ denote the returned object.
\commentary{
If both lookups failed, the exact same lookups would have failed
at compile-time, and the program then has a compile-time error.
}
\LMHash{}
Otherwise perform the binding of actual arguments to formal parameters for
\code{$f$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}
as specified in Section~\ref{bindingActualsToFormals},
and execute the body of $f$ with said bindings
plus a binding of \THIS{} to $o$.
The result returned by $f$ is then the result of evaluating $i$.
} % End of scope for superclass name.
\subsubsection{Sending Messages}
\LMLabel{sendingMessages}
\LMHash{}
Messages are the sole means of communication among isolates.
Messages are sent by invoking specific methods in the Dart libraries; there is no specific syntax for sending a message.
\commentary{
In other words, the methods supporting sending messages embody primitives of Dart that are not accessible to ordinary code, much like the methods that spawn isolates.
}
\subsection{Property Extraction}
\LMLabel{propertyExtraction}
\LMHash{}
{\em Property extraction} allows for a member to be accessed as a property rather than a function.
A property extraction can be either:
\begin{enumerate}
\item An instance method closurization,
which converts a method into a function object
(\ref{ordinaryMemberClosurization}).
Or
\item A getter invocation, which returns the result of invoking of a getter method
(\ref{getterAccessAndMethodExtraction}).
\end{enumerate}
\commentary{
Function objects derived from members via closurization are colloquially known as tear-offs.
}
Property extraction can be either {\em conditional} or {\em unconditional}.
\LMHash{}
Evaluation of a {\em conditional property extraction expression} $e$
of the form \code{$e_1$?.\id} proceeds as follows:
\LMHash{}
If $e_1$ is a type literal, $e$ is equivalent to \code{$e_1$.$m$}.
\LMHash{}
Otherwise evaluate $e_1$ to an object $o$.
If $o$ is the null object, $e$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $o$
and evaluate \code{$x$.\id} to a value $r$.
Then $e$ evaluates to $r$.
The static type of $e$ is the same as the static type of \code{$e_1$.\id}.
Let $T$ be the static type of $e_1$ and let $y$ be a fresh variable of type $T$.
Exactly the same compile-time errors that would be caused by \code{$y$.\id} are also generated in the case of \code{$e_1$?.\id}.
\LMHash{}
Unconditional property extraction has one of two syntactic forms: $e.m$ (\ref{getterAccessAndMethodExtraction}) or $\SUPER.m$ (\ref{superGetterAccessAndMethodClosurization}), where $e$ is an expression and $m$ is an identifier.
\subsubsection{Getter Access and Method Extraction}
\LMLabel{getterAccessAndMethodExtraction}
\LMHash{}
Evaluation of a property extraction $i$ of the form $e.m$ proceeds as follows:
\LMHash{}
First, the expression $e$ is evaluated to an object $o$.
Let $f$ be the result of looking up (\ref{lookup}) method (\ref{instanceMethods}) $m$ in $o$ with respect to the current library $L$.
%% TODO(eernst): This is metaclass stuff, should be deleted.
If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a method that forwards (\ref{functionDeclarations}) to a static method, method lookup fails.
If method lookup succeeds then $i$ evaluates to the closurization of method $f$ on object $o$ (\ref{ordinaryMemberClosurization}).
\commentary{
Note that $f$ is never an abstract method, because method lookup skips abstract methods.
Hence, if $m$ refers to an abstract method, we will continue to the next step.
However, since methods and getters never override each other, getter lookup will necessarily fail as well, and \code{noSuchMethod()} will ultimately be invoked.
The regrettable implication is that the error will refer to a missing getter rather than an attempt to closurize an abstract method.
}
\LMHash{}
Otherwise, $i$ is a getter invocation.
Let $f$ be the result of looking up (\ref{lookup}) getter (\ref{getters}) $m$ in $o$ with respect to $L$.
%% TODO(eernst): This is metaclass stuff, should be deleted.
If $o$ is an instance of \code{Type} but $e$ is not a constant type literal, then if $f$ is a getter that forwards to a static getter, getter lookup fails.
Otherwise, the body of $f$ is executed with \THIS{} bound to $o$.
The value of $i$ is the result returned by the call to the getter function.
\LMHash{}
If the getter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
\begin{itemize}
\item \code{$im$.isGetter} evaluates to \code{\TRUE{}}.
\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 $o$ and invoked with argument $im$,
and the result of this invocation is the result of evaluating $i$.
\commentary {
The situation where \code{noSuchMethod} is invoked can only arise
when the static type of $e$ is \DYNAMIC{}.
}
\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.
\commentary{
This precludes \code{int.toString} but not \code{(int).toString} because in the latter case, $e$ is a parenthesized expression.
}
\LMHash{}
Let $T$ be the static type of $e$.
It is a compile-time error if $T$ does not have a method or getter named $m$,
%% TODO(eernst): This is metaclass stuff, should be deleted.
unless $T$ is \code{Type},
$e$ is a constant type literal,
and the class corresponding to $e$ has a static method or getter named $m$.
\LMHash{}
The static type of $i$ is:
\begin{itemize}
\item The declared return type of \code{$T$.$m$}, if $T$ has an accessible instance getter named $m$.
\item
%% TODO(eernst): This is metaclass stuff, should be deleted.
The declared return type of $m$, if $T$ is \code{Type},
$e$ is a constant type literal
and the class corresponding to $e$ declares an accessible static getter named $m$.
\item The static type of function \code{$T$.$m$} if $T$ has an accessible instance method named $m$.
\item
%% TODO(eernst): This is metaclass stuff, should be deleted.
The static type of function $m$, if $T$ is \code{Type},
$e$ is a constant type literal
and the class corresponding to $e$ declares an accessible static method named $m$.
\item The type \DYNAMIC{} otherwise.
\end{itemize}
\subsubsection{Super Getter Access and Method Closurization}
\LMLabel{superGetterAccessAndMethodClosurization}
\LMHash{}
Evaluation of a property extraction $i$ of the form $\SUPER.m$ proceeds as follows:
\LMHash{}
Let $g$ be the method currently executing, and let $C$ be the class in which $g$ was looked up.
Let $S_{dynamic}$ be the superclass of $C$.
Let $f$ be the result of looking up method $m$ in $S_{dynamic}$ with respect to the current library $L$.
If method lookup succeeds then $i$ evaluates to the closurization of method $f$ with respect to superclass $S_{dynamic}$ (\ref{superClosurization}).
\LMHash{}
Otherwise, $i$ is a getter invocation.
Let $f$ be the result of looking up getter $m$ in $S_{dynamic}$ with respect to $L$.
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.
\commentary{
The getter lookup will not fail, because it is a compile-time error to have
a super property extraction of a member $m$ when the superclass $S_{dynamic}$
does not have a concrete member named $m$.
}
\LMHash{}
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 method or getter named $m$.
The static type of $i$ is:
\begin{itemize}
\item The declared return type of $S_{static}.m$, if $S_{static}$ has an accessible instance getter named $m$.
\item The static type of function $S_{static}.m$, if $S_{static}$ has an accessible instance method named $m$.
\item The type \DYNAMIC{} otherwise.
\end{itemize}
\subsubsection{Ordinary Member Closurization}
\LMLabel{ordinaryMemberClosurization}
\commentary{
Note that the non-generic case is covered implicitly using $s = 0$,
in which case the type parameter declarations are omitted (\ref{generics}).
}
\LMHash{}
An {\em instance method closurization}
is a closurization of some method on some object, defined below,
or a super closurization (\ref{superClosurization}).
\LMHash{}
Let $o$ be an object, and let $u$ be a fresh final variable bound to $o$.
The {\em closurization of method $f$ on object $o$} is defined to be equivalent
(\commentary{except for equality, as noted below}) to:
\begin{itemize}
%\item $(a) \{\RETURN{}$ $u$ $op$ $a;$\} if $f$ is named $op$ and $op$ is one of \code{<, >, <=, >=, ==, -, +, /, \~{}/, *, \%, $|$, \^{}, \&, $<<$, $>>$} (this precludes closurization of unary -).
%\item $() \{\RETURN{}$ \~{} $u;$\} if $f$ is named \~{}.
%\item $(a) \{\RETURN{}$ $u[a];$\} if $f$ is named \code{[]}.
%\item $(a, b) \{\RETURN{}$ $u[a] = b;$\} if $f$ is named \code{[]=}.
\item
\begin{dartCode}
<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
($T_1\ r_1, \ldots,\ T_n\ r_n,\ $\{$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$\}) =>
$u.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1$: $p_1, \ldots,\ p_k$: $p_k$);
\end{dartCode}
if $f$ is named $m$ and has type parameter declarations
$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
required parameters $r_1, \ldots, r_n$,
and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\item
\begin{dartCode}
<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
($T_1\ r_1, \ldots,\ T_n\ r_n,\ $[$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$]) =>
$u.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1, \ldots,\ p_k$);
\end{dartCode}
if $f$ is named $m$ and has type parameter declarations
$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
required parameters $r_1, \ldots, r_n$,
and optional positional parameters
$p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\end{itemize}
\LMHash{}
$B'_j, j \in 1 .. s$, are determined as follows:
If $o$ is an instance of a non-generic class, $B'_j = B_j, j \in 1 .. s$.
Otherwise, let $X'_1, \ldots, X'_{s'}$ be the formal type parameters of the class of $o$,
and $t'_1, \ldots, t'_{s'}$ be the actual type arguments.
Then $B'_j = [t'_1/X'_1, \ldots, t'_{s'}/X'_{s'}]B_j, j \in 1 .. s$.
\commentary{
That is, we replace the formal type parameters of the enclosing class, if any, by the corresponding actual type arguments.
}
%% TODO: We should specify tear-offs by means of their (static and dynamice)
%% semantics, not via syntactic sugar, because the syntactic sugar causes
%% weird phenomena like `a type annotation that denotes the same type as`
%% etc.
%% TODO[covariant-parameters]: When adding a specification of covariant
%% parameters we will need to indicate that the dynamic parameter type is
%% `Object` for such a parameter, and that the static type of the function
%% as a whole will be taken from the statically known type of the receiver
%% of the tear-off invocation.
\LMHash{}
The parameter types $T_j, j \in 1 .. n+k$, are determined as follows:
Let the method declaration $D$ be the implementation of $m$ which is invoked by the expression in the body.
Let $T$ be the class that contains $D$.
\commentary{
Note that $T$ is the dynamic type of $o$, or a superclass thereof.
}
\LMHash{}
If $T$ is a non-generic class then for $j \in 1 .. n+k$,
$T_j$ is a type annotation that denotes the same type as that which is denoted by the type annotation on the corresponding parameter declaration in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}
Otherwise $T$ is a generic instantiation of a generic class $G$.
Let $X''_1, \ldots, X''_{s''}$ be the formal type parameters of $G$,
and $t''_1, \ldots, t''_{s''}$ be the actual type arguments of $o$ at $T$.
Then $T_j$ is a type annotation that denotes $[t''_1/X''_1, \ldots, t''_{s''}/X''_{s''}]S_j$,
where $S_j$ is the type annotation of the corresponding parameter in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}
There is one way in which
the function object yielded by the instance method closurization differs from
the function object obtained by function closurization on the above mentioned function literal:
Assume that $o_1$ and $o_2$ are objects, $m$ is an identifier,
and $c_1$ and $c_2$ are function objects
obtained by closurization of $m$ on $o_1$ respectively $o_2$.
Then \code{$c_1$ == $c_2$} evaluates to true if and only if $o_1$ and $o_2$ is the same object.
%% TODO(eernst): This being a comment, it's presumably spelled out somewhere
%% else. Find it and check that it does actually say that it is an error
%% except when the type of $e$ is \DYNAMIC{}.
%\item The static type of the property extraction is the static type of function \code{$T$.$m$}, where $T$ is the static type of $e$, if \code{$T$.$m$} is defined. Otherwise the static type of $e.m$ is \DYNAMIC{}.
\commentary{
% Spell out the consequences for `==` and for `identical`, for the receivers
% and for the closurizations.
In particular, two closurizations of a method $m$ from the same object are equal,
and two closurizations of a method $m$ from non-identical objects are not equal.
Assuming that $v_i$ is a fresh variable bound to an object, $i \in 1 .. 2$,
it also follows that \code{identical($v_1.m, v_2.m$)} must be false when $v_1$ and $v_2$ are not bound to the same object.
However, Dart implementations are not required to canonicalize function objects,
which means that \code{identical($v_1.m, v_2.m$)} is not guaranteed to be true,
even when it is known that $v_1$ and $v_2$ are bound to the same object.
}
\rationale{
The special treatment of equality in this case facilitates the use of extracted property functions in APIs where callbacks such as event listeners must often be registered and later unregistered.
A common example is the DOM API in web browsers.
}
\subsubsection{Super Closurization}
\LMLabel{superClosurization}
\commentary{
Note that the non-generic case is covered implicitly using $s = 0$,
in which case the type parameter declarations are omitted (\ref{generics}).
}
\LMHash{}
Consider expressions in the body of a class $T$ which is a subclass of a given class $S$,
where a method declaration that implements $f$ exists in $S$,
and there is no class $U$ which is a subclass of $S$ and a superclass of $T$ which implements $f$.
\commentary{
In short, consider a situation where a super invocation of $f$ will execute $f$ as declared in $S$.
}
\LMHash{}
A {\em super closurization}
is a closurization of a method with respect to a class, as defined next.
The {\em closurization of the method $f$ with respect to the class $S$}
is defined to be equivalent
(\commentary{except for equality, as noted below}) to:
\LMHash{}
\begin{itemize}
%\item $(a) \{\RETURN{}$ \SUPER{} $op$ $a;$\} if $f$ is named $op$ and $op$ is one of \code{<, >, <=, >=, ==, -, +, /, \~{}/, *, \%, $|$, \^{}, \&, $<<$, $>>$}.
%\item $() \{\RETURN{}$ \~{}\SUPER;\} if $f$ is named \~{}.
%\item $(a) \{\RETURN{}$ $\SUPER[a];$\} if $f$ is named \code{[]}.
%\item $(a, b) \{\RETURN{}$ $\SUPER[a] = b;$\} if $f$ is named \code{[]=}.
\item
\begin{dartCode}
<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
($T_1\ r_1, \ldots,\ T_n\ r_n,\ $\{$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$\}) =>
\SUPER$.m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1$: $p_1, \ldots,\ p_k$: $p_k$);
\end{dartCode}
if $f$ is named $m$ and has type parameter declarations
$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
required parameters $r_1, \ldots, r_n$,
and named parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\item
\begin{dartCode}
<$X_1\ \EXTENDS\ B'_1, \ldots,\ X_s\ \EXTENDS\ B'_s$>
($T_1\ r_1, \ldots,\ T_n\ r_n,\ $[$T_{n+1}\ p_1 = d_1, \ldots,\ T_{n+k}\ p_k = d_k$]) =>
\SUPER.$m$<$X_1, \ldots,\ X_s$>($r_1, \ldots,\ r_n,\ p_1, \ldots,\ p_k$);
\end{dartCode}
if $f$ is named $m$ and has type parameter declarations
$X_1\ \EXTENDS\ B_1$, \ldots,\ $X_s\ \EXTENDS\ B_s$,
required parameters $r_1, \ldots, r_n$,
and optional positional parameters $p_1, \ldots, p_k$ with defaults $d_1, \ldots, d_k$.
\end{itemize}
\commentary{
Note that a super closurization is an {\em instance method closurization},
as defined in (\ref{ordinaryMemberClosurization}).
}
\LMHash{}
$B'_j, j \in 1 .. s$, are determined as follows:
If $S$ is a non-generic class then $B'_j = B_j, j \in 1 .. s$.
Otherwise, let $X'_1, \ldots, X'_{s'}$ be the formal type parameters of $S$,
and $t'_1, \ldots, t'_{s'}$ be the actual type arguments of \THIS{} at $S$.
Then $B'_j = [t'_1/X'_1, \ldots, t'_{s'}/X'_{s'}]B_j, j \in 1 .. s$.
\commentary{
That is, we replace the formal type parameters of the enclosing class, if any, by the corresponding actual type arguments.
We need to consider the type arguments with respect to a specific class because it is possible for a class to pass different type arguments to its superclass than the ones it receives itself.
}
%% TODO: We should specify tear-offs by means of their (static and dynamice)
%% semantics, not via syntactic sugar, because the syntactic sugar causes
%% weird phenomena like `a type annotation that denotes the same type as`
%% etc.
%% TODO[covariant-parameters]: When adding a specification of covariant
%% parameters we will need to indicate that the dynamic parameter type is
%% `Object` for such a parameter, and that the static type of the function
%% as a whole will be taken from the statically known type of the receiver
%% of the tear-off invocation.
\LMHash{}
The parameter types $T_j, j \in 1 .. n+k$, are determined as follows:
Let the method declaration $D$ be the implementation of $m$ in $S$.
\LMHash{}
If $S$ is a non-generic class then for $j \in 1 .. n+k$,
$T_j$ is a type annotation that denotes the same type as that which is denoted by the type annotation on the corresponding parameter declaration in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}
Otherwise $S$ is a generic instantiation of a generic class $G$.
Let $X''_1, \ldots, X''_{s''}$ be the formal type parameters of $G$,
and $t''_1, \ldots, t''_{s''}$ be the actual type arguments of $o$ at $S$.
Then $T_j$ is a type annotation that denotes $[t''_1/X''_1, \ldots, t''_{s''}/X''_{s''}]S_j$,
where $S_j$ is the type annotation of the corresponding parameter in $D$.
If that parameter declaration has no type annotation then $T_j$ is \DYNAMIC{}.
\LMHash{}
There is one way in which
the function object yielded by the super closurization differs from
the function object obtained by function closurization on the above mentioned function literal:
Assume that an occurrence of the expression \SUPER{}.$m$ in a given class
is evaluated on two occasions where \THIS{} is bound to $o_1$ respectively $o_2$,
and the resulting function objects are $c_1$ respectively $c_2$:
\code{$c_1$ == $c_2$} is then true if and only if $o_1$ and $o_2$ is the same object.
\subsection{Assignment}
\LMLabel{assignment}
\LMHash{}
An assignment changes the value associated with a mutable variable or property.
\begin{grammar}
<assignmentOperator> ::= `='
\alt <compoundAssignmentOperator>
\end{grammar}
\LMHash{}
\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$},
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
(\commentary{which may be declared explicitly or induced by an instance variable, etc}).
Let $T$ be the static type of $v$ when $v$ denotes a variable,
otherwise let $T$ be the static type of the formal parameter of the setter \code{$v$=}.
It is a compile-time error if the static type of $e$ may not be assigned to $T$.
The static type of $a$ is the static type of $e$.
\LMHash{}
It is a compile-time error if an assignment of the form \code{$v$ = $e$} occurs
inside a top level or static function (be it function, method, getter, or setter) or variable initializer,
and there is neither a mutable local variable declaration with name $v$
nor a setter declaration with name \code{$v$=} in the lexical scope enclosing the assignment.
\LMHash{}
Evaluation of an assignment $a$ of the form \code{$v$ = $e$}
proceeds as follows:
%% TODO(eernst): $d$ is defined ambiguously: both getter & setter may exist.
Let $d$ be the innermost declaration whose name is $v$ or \code{$v$=}, if it exists.
It is a compile-time error if $d$ denotes
a prefix object, type declaration, or function declaration.
\LMHash{}
If $d$ is the declaration of a local variable, the expression $e$ is evaluated to an object $o$.
Then, the variable $v$ is bound to $o$.
If no error occurs, the value of the assignment expression is $o$.
\commentary{
If $v$ is a final variable, a compile-time error has occurred and execution is unspecified.
But a program with no compile-time errors may incur a dynamic type error.
}
% add local functions per bug 23218
\LMHash{}
% TODO(eernst): $d$ defined ambiguously, re-check next sentence when fixing.
If $d$ is the declaration of a library variable, top level getter or top level setter, the expression $e$ is evaluated to an object $o$.
% TODO(eernst): $d$ defined ambiguously, re-check when fixing: Case $d$ is the getter and there is no setter.
Then the setter \code{$v$=} is invoked with its formal parameter bound to $o$.
The value of the assignment expression is $o$.
\LMHash{}
Otherwise, if $d$ is the declaration of a class variable, static getter or static setter in class $C$,
then the assignment is equivalent to the assignment \code{$C$.$v$ = $e$}.
\commentary{
Otherwise, if $a$ occurs inside a top level or static function
(be it function, method, getter, or setter) or variable initializer,
a compile-time error has occurred.
}
\LMHash{}
%% TODO(eernst): We don't want to transform code and than complain, see if this
%% can be reworded to rely on static checks such that it only happens when it
%% works, or maybe that's already true.
Otherwise, the assignment is equivalent to the assignment \code{\THIS{}.$v$ = $e$}.
\LMHash{}
It is a dynamic type error if $o$ is not the null object (\ref{null})
and the dynamic type of $o$ is not a subtype of the actual type
(\ref{actualTypeOfADeclaration})
of $v$.
\LMHash{}
\Case{\code{$e_1$?.$v$ = $e_2$}}
Consider an assignment $a$ of the form \code{$e_1$?.$v$ = $e_2$}.
Exactly the same compile-time errors that would be caused by
\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$.
\LMHash{}
Evaluation of an assignment $a$ of the form \code{$e_1$?.$v$ = $e_2$}
proceeds as follows:
If $e_1$ is a type literal, $a$ is equivalent to \code{$e_1$.$v$ = $e_2$}.
Otherwise evaluate $e_1$ to an object $o$.
If $o$ is the null object, $a$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $o$
and evaluate \code{$x$.$v$ = $e_2$} to an object $r$.
Then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$.$v$ = $e_2$}}
Consider an assignment $a$ of the form \code{$e_1$.$v$ = $e_2$}.
Let $T$ be the static type of $e_1$.
If $T$ is \DYNAMIC{}, no further checks are performed.
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{}
Evaluation of an assignment of the form \code{$e_1$.$v$ = $e_2$}
proceeds as follows:
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 setter \code{$v$=} is looked up (\ref{lookup}) in $o_1$ with respect to the current library.
It is a dynamic type error if the dynamic type of $o_2$
is not a subtype of the actual parameter type of said setter
(\ref{actualTypeOfADeclaration}).
Otherwise, the body of the setter is executed with its formal parameter bound to $o_2$ and \THIS{} bound to $o_1$.
\LMHash{}
If the setter lookup has failed, then a new instance $im$ of the predefined class \code{Invocation} is created, such that:
\begin{itemize}
\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_2]$.
\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 $o_1$ and invoked with argument $im$.
\commentary{
The situation where \code{noSuchMethod} is invoked can only arise
when the static type of $e_1$ is \DYNAMIC{}.
}
\LMHash{}
The value of the assignment expression is $o_2$ irrespective of whether setter lookup has failed or succeeded.
\LMHash{}
\Case{\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.
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 said setter.
The static type of $a$ is the static type of $e$.
\LMHash{}
Evaluation of an assignment of the form \code{\SUPER.$v$ = $e$}
proceeds as follows:
Let $g$ be the currently executing method, and let $C$ be the class in which $g$ was looked up.
Let $S_{dynamic}$ be the superclass of $C$.
The expression $e$ is evaluated to an object $o$.
Then, the setter \code{$v$=} is looked up (\ref{lookup}) in $S_{dynamic}$ with respect to the current library.
The body of \code{$v$=} is executed with its formal parameter bound to $o$
and \THIS{} bound to the current value of \THIS{}.
\commentary{
The setter lookup will not fail, because it is a compile-time error
when no concrete setter named \code{$v$=} exists in $S_{static}$.
}
\LMHash{}
The value of the assignment expression is $o$.
\LMHash{}
It is a dynamic type error if $o$ is not the null object (\ref{null})
and the dynamic type of $o$ is
not a subtype of the actual type of the formal parameter of \code{$v$=}
(\ref{actualTypeOfADeclaration}) in $S_{static}$.
\LMHash{}
\Case{\code{$e_1$[$e_2$] = $e_3$}}
Consider an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$}.
Let $T$ be the static type of $e_1$.
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.
It is a compile-time error unless the static type of $e_2$ respectively $e_3$
may be assigned to $S_2$ respectively $S_3$.
Whether or not $T$ is \DYNAMIC{},
the static type of $a$ is the static type of $e_3$.
\LMHash{}
Evaluation of an assignment $a$ of the form \code{$e_1$[$e_2$] = $e_3$}
proceeds as follows:
Evaluate $e_1$ to an object $a$, then evaluate $e_2$ to an object $i$, and finally evaluate $e_3$ to an object $v$.
Call the method \code{[]=} on $a$ with $i$ as first argument and $v$ as second argument.
Then $a$ evaluates to $v$.
% Should we add: It is a dynamic error if $e_1$ evaluates to a constant list or map?
\LMHash{}
\Case{\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.
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{[]=},
and $S_2$ the static type of the second.
It is a compile-time error if the static type of $e_1$ respectively $e_2$
may not be assigned to $S_1$ respectively $S_2$.
The static type of $a$ is the static type of $e_2$.
\LMHash{}
For evaluation, an assignment of the form \code{\SUPER[$e_1$] = $e_2$}
is equivalent to the expression \code{\SUPER.[$e_1$] = $e_2$}.
\subsubsection{Compound Assignment}
\LMLabel{compoundAssignment}
\LMHash{}
\Case{\code{$v$ ??= $e$}}
Consider a compound assignment $a$ of the form \code{$v$ ??= $e$}
where $v$ is an identifier or an identifier qualified by an import prefix,
such that $v$ denotes a variable or $v$ denotes a getter, and \code{$v$=} denotes a setter.
Exactly the same compile-time errors that would be caused by \code{$v$ = $e$} are also generated in the case of $a$.
%% TODO(eernst): We should mention other cases, e.g., `v=` denotes a setter, but there is no getter.
The static type of $a$ is the least upper bound of the static type of $v$ and the static type of $e$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$v$ ??= $e$}
proceeds as follows:
Evaluate $v$ to an object $o$.
If $o$ is not the null object (\ref{null}), $a$ evaluates to $o$.
Otherwise evaluate \code{$v$ = $e$} to a value $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$C$.$v$ ??= $e$}}
Consider a compound assignment $a$ of the form \code{$C$.$v$ ??= $e$}
where $C$ is a type literal
that may or may not be qualified by an import prefix,
such that \code{$C$.$v$} denotes a getter and \code{$C$.$v$=} denotes a setter.
Exactly the same compile-time errors that would be caused by \code{$C$.$v$ = $e$} are also generated in the case of $a$.
%% TODO(eernst): We should mention other cases, e.g., `C.v=` denotes a setter, but there is no getter.
The static type of $a$ is the least upper bound of the static type of \code{$C$.$v$} and the static type of $e$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$C$.$v$ ??= $e$}
where $C$ is a type literal proceeds as follow:
Evaluate \code{$C$.$v$} to an object $o$.
If $o$ is not the null object (\ref{null}), $a$ evaluates to $o$.
Otherwise evaluate \code{$C$.$v$ = $e$} to a value $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$.$v$ ??= $e_2$}}
Consider a compound assignment $a$ of the form \code{$e_1$.$v$ ??= $e_2$}.
Let $T$ be the static type of $e_1$ and let $x$ be a fresh variable of type $T$.
Except for errors inside $e_1$ and references to the name $x$,
exactly the same compile-time errors that would be caused by \code{$x$.$v$ = $e_2$} are also generated in the case of $a$.
%% TODO(eernst): Also, we should mention other cases, e.g., there is no getter `z.v`.
The static type of $a$ is the least upper bound of the static type of \code{$e_1$.$v$} and the static type of $e_2$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$e_1$.$v$ ??= $e_2$}
proceeds as follows:
Evaluate $e_1$ to an object $u$.
Let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$} to an object $o$.
If $o$ is not the null object (\ref{null}), $a$ evaluates to $o$.
Otherwise evaluate \code{$x$.$v$ = $e_2$} to an object $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$[$e_2$] ??= $e_3$}}
Consider a compound assignment $a$ of the form \code{$e_1$[$e_2$] ??= $e_3$}.
Exactly the same compile-time errors that would be caused by \code{$e_1$[$e_2$] = $e_3$} are also generated in the case of $a$.
%% TODO(eernst): We should mention other cases, e.g., there is no `operator []`.
The static type of $a$ is the least upper bound of the static type of \code{$e_1$[$e_2$]} and the static type of $e_3$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$e_1$[$e_2$] ??= $e_3$}
proceeds as follows:
Evaluate $e_1$ to an object $u$ and then evaluate $e_2$ to an object $i$.
Call the \code{[]} method on $u$ with argument $i$, and let $o$ be the returned value.
If $o$ is not the null object (\ref{null}), $a$ evaluates to $o$.
Otherwise evaluate $e_3$ to an object $v$
and then call the \code{[]=} method on $u$ with $i$ as first argument and $v$ as second argument.
Then $a$ evaluates to $v$.
\LMHash{}
\Case{\code{\SUPER.$v$ ??= $e$}}
Consider a compound assignment $a$ of the form \code{\SUPER.$v$ ??= $e$}.
Exactly the same compile-time errors that would be caused by \code{\SUPER.$v$ = $e$} are also generated in the case of $a$.
%% TODO(eernst): We should mention other cases, e.g., there is no getter `\SUPER.v`.
The static type of $a$ is the least upper bound of the static type of \code{\SUPER.$v$} and the static type of $e$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{\SUPER.$v$ ??= $e$}
proceeds as follows:
Evaluate \code{\SUPER.$v$} to an object $o$.
If $o$ is not the null object (\ref{null}) then $a$ evaluates to $o$.
Otherwise evaluate \code{\SUPER.$v$ = $e$} to an object $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$?.$v$ ??= $e_2$}}
Consider a compound assignment $a$ of the form \code{$e_1$?.$v$ ??= $e_2$}.
Exactly the same compile-time errors that would be caused by \code{$e_1$.$v$ ??= $e_2$} are also generated in the case of $a$.
% Note: We use the static type of \code{$e_1$?.$v$} rather than \code{$e_1$.$v$} even
% though the latter would be simpler. This is because the former will remain correct
% if NNBD is introduced, and because it reduces the amount of synthetic syntax.
The static type of $a$ is the least upper bound of the static type of \code{$e_1$?.$v$} and the static type of $e_2$.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$e_1$?.$v$ ??= $e_2$}
proceeds as follows:
Evaluate $e_1$ to an object $u$.
If $u$ is the null object (\ref{null}) then $a$ evaluates to the null object.
Otherwise, let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$} to an object $o$.
If $o$ is not the null object (\ref{null}) then $a$ evaluates to $o$.
Otherwise evaluate \code{$x$.$v$ = $e_2$} to an object $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$C$?.$v$ ??= $e_2$}}
A compound assignment of the form \code{$C$?.$v$ ??= $e_2$}
where $C$ is a type literal
that may or may not be be qualified by an import prefix
is equivalent to the expression \code{$C$.$v$ ??= $e$}.
\LMHash{}
\Case{\code{$v$ $op$= $e$}}
For any other valid operator $op$, a compound assignment of the form \code{$v$ $op$= $e$}
is equivalent to \code{$v$ = $v$ $op$ $e$},
where $v$ is an identifier or an identifier qualified by an import prefix.
\LMHash{}
\Case{\code{$C$.$v$ $op$= $e$}}
A compound assignment of the form \code{$C$.$v$ $op$= $e$}
where $C$ is a type literal
that may or may not be qualified by an import prefix
is equivalent to \code{$C$.$v$ = $C$.$v$ $op$ $e$}.
\LMHash{}
\Case{\code{$e_1$.$v$ $op$= $e_2$}}
Consider a compound assignment $a$ of the form \code{$e_1$.$v$ $op$= $e_2$}.
Let $x$ be a fresh variable whose static type is the static type of $e_1$.
Except for errors inside $e_1$ and references to the name $x$,
exactly the same compile-time errors that would be caused by \code{$x$.$v$ = $x$.$v$ $op$ $e_2$} are also generated in the case of $a$.
The static type of $a$ is the static type of \code{$e_1$.$v$ $op$ $e_2$}.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$e_1$.$v$ $op$= $e_2$}
proceeds as follows:
Evaluate $e_1$ to an object $u$ and let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$ = $x$.$v$ $op$ $e_2$} to an object $r$
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$[$e_2$] $op$= $e_3$}}
Consider a compound assignment $a$ of the form \code{$e_1$[$e_2$] $op$= $e_3$}.
Let $x$ and $i$ be fresh variables
where the static type of the former is the static type of $e_1$
and the static type of the latter is the static type of $e_2$.
Except for errors inside $e_1$ and $e_2$ and references to the names $x$ and $i$,
exactly the same compile-time errors that would be caused by \code{$x$[$i$] = $x$[$i$] $op$ $e_3$} are also generated in the case of $a$.
The static type of $a$ is the static type of \code{$x$[$i$] $op$ $e_3$}.
\LMHash{}
Evaluation of s compound assignment $a$ of the form \code{$e_1$[$e_2$] $op$= $e_3$}
proceeds as follows:
Evaluate $e_1$ to an object $u$ and evaluate $e_2$ to an object $v$.
Let $x$ and $i$ be fresh variables bound to $u$ and $v$ respectively.
Evaluate \code{$x$[$i$] = $x$[$i$] $op$ $e_3$} to an object $r$,
and then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$e_1$?.$v$ $op$= $e_2$}}
Consider a compound assignment $a$ of the form \code{$e_1$?.$v$ $op$= $e_2$}.
Exactly the same compile-time errors that would be caused by \code{$e_1$.$v$ $op$= $e_2$} are also generated in the case of $a$.
The static type of $a$ is the static type of \code{$e_1$.$v$ $op$= $e_2$}.
\LMHash{}
Evaluation of a compound assignment $a$ of the form \code{$e_1$?.$v$ $op$= $e_2$}
proceeds as follows:
Evaluate $e_1$ to an object $u$.
If $u$ is the null object, then $a$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$ $op$= $e_2$} to an object $r$.
Then $a$ evaluates to $r$.
\LMHash{}
\Case{\code{$C$?.$v$ $op$ = $e_2$}}
A compound assignment of the form \code{$C$?.$v$ $op$ = $e_2$}
where $C$ is a type literal
is equivalent to the expression \code{$C$.$v$ $op$ = $e_2$}.
\begin{grammar}
<compoundAssignmentOperator> ::= `*='
\alt `/='
\alt `~/='
\alt `\%='
\alt `+='
\alt `-='
\alt `\ltlt='
\alt `\gtgt='
\alt `\gtgtgt='
\alt `\&='
\alt `^='
\alt `|='
\alt `??='
\end{grammar}
\subsection{Conditional}
\LMLabel{conditional}
\LMHash{}
A {\em conditional expression} evaluates one of two expressions based on a boolean condition.
\begin{grammar}
<conditionalExpression> ::= <ifNullExpression>
\gnewline{} (`?' <expressionWithoutCascade> `:' <expressionWithoutCascade>)?
\end{grammar}
\LMHash{}
Evaluation of a conditional expression $c$ of the form $e_1 ? e_2 : e_3$ proceeds as follows:
\LMHash{}
First, $e_1$ is evaluated to an object $o_1$.
It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
If $r$ is \TRUE, then the value of $c$ is the result of evaluating the expression $e_2$.
Otherwise the value of $c$ is the result of evaluating the expression $e_3$.
\LMHash{}
If $e_1$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $e_2$,
unless any of the following are true:
\begin{itemize}
\item $v$ is potentially mutated in $e_2$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $e_2$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
\LMHash{}
It is a compile-time error if the static type of $e_1$ may not be assigned to \code{bool}.
The static type of $c$ is the least upper bound (\ref{leastUpperBounds}) of the static type of $e_2$ and the static type of $e_3$.
\subsection{If-null Expressions}
\LMLabel{ifNull}
\LMHash{}
An {\em if-null expression} evaluates an expression and if the result is the null object (\ref{null}), evaluates another.
\begin{grammar}
<ifNullExpression> ::= <logicalOrExpression> (`??' <logicalOrExpression>)*
\end{grammar}
\LMHash{}
Evaluation of an if-null expression $e$ of the form \code{$e_1$ ?? $e_2$}
proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $o$.
If $o$ is not the null object (\ref{null}), then $e$ evaluates to $o$.
Otherwise evaluate $e_2$ to an object $r$,
and then $e$ evaluates to $r$.
\LMHash{}
The static type of $e$ is the least upper bound (\ref{leastUpperBounds}) of the static type of $e_1$ and the static type of $e_2$.
\subsection{Logical Boolean Expressions}
\LMLabel{logicalBooleanExpressions}
\LMHash{}
The logical boolean expressions combine boolean objects using the boolean conjunction and disjunction operators.
\begin{grammar}
<logicalOrExpression> ::= <logicalAndExpression> (`||' <logicalAndExpression>)*
<logicalAndExpression> ::= <equalityExpression> (`\&\&' <equalityExpression>)*
\end{grammar}
\LMHash{}
A {\em logical boolean expression} is either an equality expression (\ref{equality}), or an invocation of a logical boolean operator on an expression $e_1$ with argument $e_2$.
\LMHash{}
Evaluation of a logical boolean expression $b$ of the form $e_1 || e_2$ causes the evaluation of $e_1$ to a value $o_1$.
It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
If $o_1$ is \TRUE, the result of evaluating $b$ is \TRUE, otherwise $e_2$ is evaluated to an object $o_2$.
It is a run-time error if the run-time type of $o_2$ is not \code{bool}.
Otherwise the result of evaluating $b$ is $o_2$.
\LMHash{}
Evaluation of a logical boolean expression $b$ of the form $e_1 \&\& e_2$ causes the evaluation of $e_1$ producing an object $o_1$.
It is a run-time error if the run-time type of $o_1$ is not \code{bool}.
If $o_1$ is \FALSE, the result of evaluating $b$ is \FALSE, otherwise $e_2$ is evaluated to an object $o_2$.
It is a run-time error if the run-time type of $o_2$ is not \code{bool}.
Otherwise the result of evaluating $b$ is $o_2$.
\LMHash{}
A logical boolean expression $b$ of the form $e_1 \&\& e_2$
shows that a local variable $v$ has type $T$
if both of the following conditions hold:
\begin{itemize}
\item Either $e_1$ shows that $v$ has type $T$ or $e_2$ shows that $v$ has type $T$.
\item $v$ is not mutated in $e_2$ or within a function other than the one where $v$ is declared.
\end{itemize}
\LMHash{}
If $e_1$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $e_2$,
unless any of the following are true:
\begin{itemize}
%% The first item here is unnecessary for soundness,
%% and is retained mainly for backwards compatibility.
%% If $e_1$ shows that $v$ has type $T$, then any assignment
%% in $e_1$ does not invalidate that.
%% Removing the line is visible in the semantics, though, because:
%% num x;
%% (x ??= 42) != null && x is int & x.toRadixString(16) != ""
%% is allowed without the line, and disallowed with.
%% At time of writing, the analyzer disallows the code.
\item $v$ is potentially mutated in $e_1$,
\item $v$ is potentially mutated in $e_2$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $e_2$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
\LMHash{}
It is a compile-time error if the static type of $e_1$ may not be assigned to \code{bool} or if the static type of $e_2$ may not be assigned to \code{bool}.
The static type of a logical boolean expression is \code{bool}.
\subsection{Equality}
\LMLabel{equality}
\LMHash{}
Equality expressions test objects for equality.
\begin{grammar}
<equalityExpression> ::= <relationalExpression> (<equalityOperator> <relationalExpression>)?
\alt \SUPER{} <equalityOperator> <relationalExpression>
<equalityOperator> ::= `=='
\alt `!='
\end{grammar}
\LMHash{}
An {\em equality expression} is either a relational expression (\ref{relationalExpressions}), or an invocation of an equality operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
Evaluation of an equality expression $ee$ of the form \code{$e_1$ == $e_2$} proceeds as follows:
\begin{itemize}
\item The expression $e_1$ is evaluated to an object $o_1$.
\item The expression $e_2$ is evaluated to an object $o_2$.
\item If either $o_1$ or $o_2$ is the null object (\ref{null}), then $ee$ evaluates to \TRUE{} if both $o_1$ and $o_2$ are the null object and to \FALSE{} otherwise.
Otherwise,
\item evaluation of $ee$ is equivalent to the method invocation \code{$o_1$.==($o_2$)}.
\end{itemize}
\LMHash{}
Evaluation of an equality expression $ee$ of the form \code{\SUPER{} == $e$} proceeds as follows:
\begin{itemize}
\item The expression $e$ is evaluated to an object $o$.
\item If either \THIS{} or $o$ is the null object (\ref{null}), then $ee$ evaluates to evaluates to \TRUE{} if both \THIS{} and $o$ are the null object and to \FALSE{} otherwise.
Otherwise,
\item evaluation of $ee$ is equivalent to the method invocation \code{\SUPER{}.==($o$)}.
\end{itemize}
\commentary{
As a result of the above definition, user defined \code{==} methods can assume that their argument is non-null, and avoid the standard boiler-plate prelude:
\code{if (identical(\NULL{}, arg)) return \FALSE{};}
Another implication is that there is never a need to use \code{identical()} to test against \NULL{}, nor should anyone ever worry about whether to write \NULL{} == $e$ or $e$ == \NULL{}.
}
\LMHash{}
An equality expression of the form \code{$e_1$ != $e_2$} is equivalent to the expression \code{!($e_1$ == $e_2$)}.
An equality expression of the form \code{\SUPER{} != $e$} is equivalent to the expression \code{!(\SUPER{} == $e$)}.
%The expression $e_1$ is evaluated to an object $o_1$; then the expression $e_2$ is evaluated to an object $o_2$. Next, if $o_1$ and $o_2$ are the same object, then $ee$ evaluates to \TRUE{}, otherwise $ee$ evaluates to \FALSE{}.
\LMHash{}
The static type of an equality expression is \code{bool}.
\subsection{Relational Expressions}
\LMLabel{relationalExpressions}
\LMHash{}
Relational expressions invoke the relational operators on objects.
\begin{grammar}
<relationalExpression> ::= <bitwiseOrExpression> (<typeTest> | <typeCast> |
\gnewline{} <relationalOperator> <bitwiseOrExpression>)?
\alt \SUPER{} <relationalOperator> <bitwiseOrExpression>
<relationalOperator> ::= `>='
\alt `>'
\alt `<='
\alt `<'
\end{grammar}
\LMHash{}
A {\em relational expression} is either a bitwise expression (\ref{bitwiseExpressions}), or an invocation of a relational operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
A relational expression of the form $e_1$ $op$ $e_2$ is equivalent to the method invocation \code{$e_1$.$op$($e_2$)}.
A relational expression of the form \SUPER{} $op$ $e_2$ is equivalent to the method invocation \code{\SUPER{}.$op$($e_2$)}.
\subsection{Bitwise Expressions}
\LMLabel{bitwiseExpressions}
\LMHash{}
Bitwise expressions invoke the bitwise operators on objects.
\begin{grammar}
<bitwiseOrExpression> ::= <bitwiseXorExpression> (`|' <bitwiseXorExpression>)*
\alt \SUPER{} (`|' <bitwiseXorExpression>)+
<bitwiseXorExpression> ::= <bitwiseAndExpression> (`^' <bitwiseAndExpression>)*
\alt \SUPER{} (`^' <bitwiseAndExpression>)+
<bitwiseAndExpression> ::= <shiftExpression> (`\&' <shiftExpression>)*
\alt \SUPER{} (`\&' <shiftExpression>)+
<bitwiseOperator> ::= `\&'
\alt `^'
\alt `|'
\end{grammar}
\LMHash{}
A {\em bitwise expression} is either a shift expression (\ref{shift}), or an invocation of a bitwise operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
A bitwise expression of the form \code{$e_1$ $op$ $e_2$} is equivalent to the method invocation $e_1.op(e_2)$.
A bitwise expression of the form \code{\SUPER{} $op$ $e_2$} is equivalent to the method invocation \code{\SUPER{}.$op$($e_2$)}.
\commentary{
It should be obvious that the static type rules for these expressions are defined by the equivalence above - ergo, by the type rules for method invocation and the signatures of the operators on the type $e_1$.
The same holds in similar situations throughout this specification.
}
\subsection{Shift}
\LMLabel{shift}
\LMHash{}
Shift expressions invoke the shift operators on objects.
\begin{grammar}
<shiftExpression> ::= <additiveExpression> (<shiftOperator> <additiveExpression>)*
\alt \SUPER{} (<shiftOperator> <additiveExpression>)+
<shiftOperator> ::= `\ltlt'
\alt `\gtgt'
\alt `\gtgtgt'
\end{grammar}
\LMHash{}
A {\em shift expression} is either an additive expression (\ref{additiveExpressions}), or an invocation of a shift operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
A shift expression of the form $e_1$ $op$ $e_2$ is equivalent to the method invocation \code{$e_1$.$op$($e_2$)}.
A shift expression of the form \SUPER{} $op$ $e_2$ is equivalent to the method invocation \code{\SUPER{}.$op$($e_2$)}.
\commentary{
Note that this definition implies left-to-right evaluation order among shift expressions:
\code{$e_1$\,<\mbox<\,$e_2$\,<\mbox<\,$e_3$}
is evaluated as
\code{($e_1$\,<\mbox<\,$e_2$).<\mbox< ($e_3$)} which is equivalent to
\code{($e_1$\,<\mbox<\,$e_2$)\,<\mbox<\,$e_3$}.
The same holds for additive and multiplicative expressions.
}
\subsection{Additive Expressions}
\LMLabel{additiveExpressions}
\LMHash{}
Additive expressions invoke the addition operators on objects.
\begin{grammar}
<additiveExpression> ::= <multiplicativeExpression>
\gnewline{} (<additiveOperator> <multiplicativeExpression>)*
\alt \SUPER{} (<additiveOperator> <multiplicativeExpression>)+
<additiveOperator> ::= `+'
\alt `-'
\end{grammar}
\LMHash{}
An {\em additive expression} is either a multiplicative expression (\ref{multiplicativeExpressions}), or an invocation of an additive operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
An additive expression of the form $e_1$ $op$ $e_2$ is equivalent to the method invocation \code{$e_1$.$op$($e_2$)}.
An additive expression of the form \SUPER{} $op$ $e_2$ is equivalent to the method invocation \code{\SUPER{}.$op$($e_2$)}.
\LMHash{}
The static type of an additive expression is usually determined by the signature given in the declaration of the operator used.
However, invocations of the operators \code{+} and \code{-} of class \code{int} are treated specially by the typechecker.
The static type of an expression $e_1 + e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
The static type of an expression $e_1 - e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
\subsection{Multiplicative Expressions}
\LMLabel{multiplicativeExpressions}
\LMHash{}
Multiplicative expressions invoke the multiplication operators on objects.
\begin{grammar}
<multiplicativeExpression> ::= <unaryExpression> (<multiplicativeOperator> <unaryExpression>)*
\alt \SUPER{} (<multiplicativeOperator> <unaryExpression>)+
<multiplicativeOperator> ::= `*'
\alt `/'
\alt `\%'
\alt `~/'
\end{grammar}
\LMHash{}
A {\em multiplicative expression} is either a unary expression (\ref{unaryExpressions}), or an invocation of a multiplicative operator on either \SUPER{} or an expression $e_1$, with argument $e_2$.
\LMHash{}
A multiplicative expression of the form $e_1$ $op$ $e_2$ is equivalent to the method invocation \code{$e_1$.$op$($e_2$)}.
A multiplicative expression of the form \SUPER{} $op$ $e_2$ is equivalent to the method invocation \code{\SUPER{}.$op$($e_2$)}.
\LMHash{}
The static type of an multiplicative expression is usually determined by the signature given in the declaration of the operator used.
However, invocations of the operators \code{*} and \code{\%} of class \code{int} are treated specially by the typechecker.
The static type of an expression $e_1 * e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
The static type of an expression $e_1 \% e_2$ where $e_1$ has static type \code{int} is \code{int} if the static type of $e_2$ is \code{int}, and \code{double} if the static type of $e_2$ is \code{double}.
\subsection{Unary Expressions}
\LMLabel{unaryExpressions}
\LMHash{}
Unary expressions invoke unary operators on objects.
\begin{grammar}
<unaryExpression> ::= <prefixOperator> <unaryExpression>
\alt <awaitExpression>
\alt <postfixExpression>
\alt (<minusOperator> | <tildeOperator>) \SUPER{}
\alt <incrementOperator> <assignableExpression>
<prefixOperator> ::= <minusOperator>
\alt <negationOperator>
\alt <tildeOperator>
<minusOperator> ::= `-'
<negationOperator> ::= `!'
<tildeOperator> ::= `~'
\end{grammar}
\LMHash{}
A {\em unary expression} is either a postfix expression (\ref{postfixExpressions}), an await expression (\ref{awaitExpressions}) or an invocation of a prefix operator on an expression or an invocation of a unary operator on either \SUPER{} or an expression $e$.
\LMHash{}
The expression $!e$ is equivalent to the expression \code{$e$\,?\,\FALSE\,:\,\TRUE}.
\LMHash{}
Evaluation of an expression of the form \code{++$e$} is equivalent to \code{$e$\,+=\,1}.
Evaluation of an expression of the form \code{-{}-$e$} is equivalent to \code{$e$\,-=\,1}.
\LMHash{}
Let $e$ be an expression of the form \code{-$l$}
where $l$ is an integer literal (\ref{numbers}) with numeric integer value $i$,
and with static context type $T$.
If \code{double} is assignable to $T$ and \code{int} is not assignable to $T$,
then the static type of $e$ is \code{double};
otherwise the static type of $e$ is \code{int}.
\LMHash{}
If the static type of $e$ is \code{int} then $e$ evaluates to
to an instance of the \code{int} class representing the numeric value $-i$.
If $i$ is zero and the \code{int} class can represent a negative zero value,
then the resulting instance instead represents that negative zero value.
It is a compile-time error if the integer $-i$ cannot be represented
exactly by an instance of \code{int}.
\LMHash{}
If the static type of $e$ is \code{double} then $e$ evaluates to
to an instance of the \code{double} class representing the numeric value $-i$.
If $i$ is zero, the resulting instance instead represents the
\emph{negative} zero double value, \code{-0.0}.
It is a compile-time error if the integer $-i$ cannot be represented
exactly by an instance of \code{double}.
\commentary{
We treat \code{-$l$} \emph{as if} it is a single integer literal
with a negative numeric value.
We do not evaluate $l$ individually as an expression,
or concern ourselves with its static type.
}
\LMHash{}
Any other expression of the form \code{$op$ $e$} is equivalent to the method invocation \code{$e.op()$}.
An expression of the form \code{$op$ \SUPER{}} is equivalent to the method invocation (\ref{superInvocation}) \code{\SUPER{}.$op()$}.
\subsection{Await Expressions}
\LMLabel{awaitExpressions}
\LMHash{}
An {\em await expression} allows code to yield control until an asynchronous operation (\ref{functions}) completes.
\begin{grammar}
<awaitExpression> ::= \AWAIT{} <unaryExpression>
\end{grammar}
\LMHash{}
Evaluation of an await expression $a$ of the form \AWAIT{} $e$ proceeds as follows:
First, the expression $e$ is evaluated to an object $o$.
\LMHash{}
% NOTICE: Removed the requirement that an error thrown by $e$ is caught in a
% future. There is no reason $var x = e; await x;$ and $await e$ should behave
% differently, and no implementation actually implemented it.
Then, if $o$ is not an instance of \code{Future}, then let $f$ be the result of creating a new object using the constructor \code{Future.value()} with $o$ as its argument; otherwise let $f$ be $o$.
\LMHash{}
Next, the stream associated with the innermost enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused.
The current invocation of the function body immediately enclosing $a$ is suspended until after $f$ completes.
At some time after $f$ is completed, control returns to the current invocation.
If $f$ has completed with an error $x$ and stack trace $t$, $a$ throws $x$ and $t$ (\ref{evaluation}).
If $f$ completes with a value $v$, $a$ evaluates to $v$.
%Otherwise, the value of $a$ is the value of $e$. If evaluation of $e$ raises an exception $x$, $a$ raises $x$.
\commentary{
It is a compile-time error if the function immediately enclosing $a$ is not declared asynchronous.
However, this error is simply a syntax error, because in the context of a normal function, \AWAIT{} has no special meaning.
% TODO(lrn): Update this, it's not actually correct,
% the expression "await(expr)" is valid non-async syntax *and* a valid
% async await expression.
}
\rationale{
An await expression has no meaning in a synchronous function.
If such a function were to suspend waiting for a future, it would no longer be synchronous.
}
\commentary{
It is not a compile-time error if the type of $e$ is not a subtype of \code{Future}.
Tools may choose to give a hint in such cases.
}
\LMHash{}
The static type of $a$ is \flatten{T} (\flatten{} is defined in section \ref{functionExpressions}) where $T$ is the static type of $e$.
\subsection{Postfix Expressions}
\LMLabel{postfixExpressions}
\LMHash{}
Postfix expressions invoke the postfix operators on objects.
\begin{grammar}
<postfixExpression> ::= <assignableExpression> <postfixOperator>
\alt <primary> <selector>*
<postfixOperator> ::= <incrementOperator>
<selector> ::= <assignableSelector>
\alt <argumentPart>
<incrementOperator> ::= `++'
\alt `-\mbox-'
\end{grammar}
\LMHash{}
A {\em postfix expression} is either a primary expression, a function, method or getter invocation, or an invocation of a postfix operator on an expression $e$.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$v$++}, where $v$ is an identifier, proceeds as follows:
\LMHash{}
Evaluate $v$ to an object $r$ and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$v$ = $y$ + 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of $v$.
\rationale{
The above ensures that if $v$ is a variable, the getter gets called exactly once.
Likewise in the cases below.
}
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$C$.$v$++}
where $C$ is a type literal proceeds as follows:
\LMHash{}
Evaluate \code{$C$.$v$} to a value $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$C$.$v$ = $y$ + 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$C$.$v$}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$e_1$.$v$++}
proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $u$ and let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$} to a value $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$x$.$v$ = $y$ + 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$.$v$}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$e_1$[$e_2$]++}
proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $u$ and $e_2$ to an object $v$.
Let $a$ and $i$ be fresh variables bound to $u$ and $v$ respectively.
Evaluate \code{$a$[$i$]} to an object $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$a$[$i$] = $y$ + 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$[$e_2$]}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$v$-{}-}, where $v$ is an identifier, proceeds as follows:
\LMHash{}
Evaluate the expression $v$ to an object $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$v$ = $y$ - 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of $v$.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$C$.$v$-{}-}
proceeds as follows:
\LMHash{}
Evaluate \code{$C$.$v$} to a value $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$C$.$v$ = $y$ - 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$C$.$v$}.
\LMHash{}
Evaluation of a postfix expression of the form \code{$e_1$.$v$-{}-}
proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $u$ and let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$} to a value $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$x$.$v$ = $y$ - 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$.$v$}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$e_1$[$e_2$]-{}-}
proceeds as follows:
\LMHash{}
Evaluate $e_1$ to an object $u$ and $e_2$ to an object $v$.
Let $a$ and $i$ be fresh variables bound to $u$ and $v$ respectively.
Evaluate \code{$a$[$i$]} to an object $r$
and let $y$ be a fresh variable bound to $r$.
Evaluate \code{$a$[$i$] = $y$ - 1}.
Then $e$ evaluates to $r$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$[$e_2$]}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$e_1$?.$v$++}
proceeds as follows:
\LMHash{}
If $e_1$ is a type literal, evaluation of $e$ is equivalent to
evaluation of \code{$e_1$.$v$++}.
\LMHash{}
Otherwise evaluate $e_1$ to an object $u$.
if $u$ is the null object, $e$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$++} to an object $o$.
Then $e$ evaluates to $o$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$.$v$}.
\LMHash{}
Evaluation of a postfix expression $e$ of the form \code{$e_1$?.$v$-{}-}
proceeds as follows:
If $e_1$ is a type literal, evaluation of $e$ is equivalent to
evaluation of \code{$e_1$.$v$-{}-}.
Otherwise evaluate $e_1$ to an object $u$.
If $u$ is the null object, $e$ evaluates to the null object (\ref{null}).
Otherwise let $x$ be a fresh variable bound to $u$.
Evaluate \code{$x$.$v$-{}-} to an object $o$.
Then $e$ evaluates to $o$.
\LMHash{}
The static type of such an expression is the static type of \code{$e_1$.$v$}.
\subsection{Assignable Expressions}
\LMLabel{assignableExpressions}
\LMHash{}
Assignable expressions are expressions that can appear on the left hand side of an assignment.
This section describes how to evaluate these expressions when they do not constitute the complete left hand side of an assignment.
\rationale{
Of course, if assignable expressions always appeared {\em as} the left hand side, one would have no need for their value, and the rules for evaluating them would be unnecessary.
However, assignable expressions can be subexpressions of other expressions and therefore must be evaluated.
}
\begin{grammar}
<assignableExpression> ::= <primary> (<argumentPart>* <assignableSelector>)+
\alt \SUPER{} <unconditionalAssignableSelector>
<identifier>
<unconditionalAssignableSelector> ::= `[' <expression> `]'
\alt `.' <identifier>
<assignableSelector> ::= <unconditionalAssignableSelector>
\alt `?.' <identifier>
\end{grammar}
\LMHash{}
An {\em assignable expression} is either:
\begin{itemize}
\item An identifier.
\item An invocation (possibly conditional) of a getter (\ref{getters}) or list access operator on an expression $e$.
\item An invocation of a getter or list access operator on \SUPER{}.
\end{itemize}
\LMHash{}
An assignable expression of the form \id{} is evaluated as an identifier expression (\ref{identifierReference}).
%An assignable expression of the form \code{$e$.\id($a_1, \ldots,\ a_n$)} is evaluated as a method invocation (\ref{methodInvocation}).
\LMHash{}
An assignable expression of the form \code{$e$.\id} or \code{$e$?.\id} is evaluated as a property extraction (\ref{propertyExtraction}).
\LMHash{}
An assignable expression of the form \code{$e_1$[$e_2$]} is evaluated as a method invocation of the operator method \code{[]} on $e_1$ with argument $e_2$.
\LMHash{}
An assignable expression of the form \code{\SUPER{}.\id} is evaluated as a property extraction.
\LMHash{}
Evaluation of an assignable expression of the form \code{\SUPER{}[$e_2$]} is equivalent to evaluation of the method invocation \code{\SUPER{}.[]($e_2$)}.
\subsection{Identifier Reference}
\LMLabel{identifierReference}
\LMHash{}
An {\em identifier expression} consists of a single identifier; it provides access to an object via an unqualified name.
\begin{grammar}
<identifier> ::= <IDENTIFIER>
.
<IDENTIFIER\_NO\_DOLLAR> ::= <IDENTIFIER\_START\_NO\_DOLLAR>
\gnewline{} <IDENTIFIER\_PART\_NO\_DOLLAR>*
<IDENTIFIER> ::= <IDENTIFIER\_START IDENTIFIER\_PART>*
<BUILT\_IN\_IDENTIFIER> ::= \ABSTRACT{}
\alt \AS{}
\alt \COVARIANT{}
\alt \DEFERRED{}
\alt \DYNAMIC{}
\alt \EXPORT{}
\alt \EXTERNAL{}
\alt \FACTORY{}
\alt \FUNCTION{}
\alt \GET{}
\alt \IMPLEMENTS{}
\alt \IMPORT{}
\alt \INTERFACE{}
\alt \LIBRARY{}
\alt \OPERATOR{}
\alt \MIXIN{}
\alt \PART{}
\alt \SET{}
\alt \STATIC{}
\alt \TYPEDEF{}
<IDENTIFIER\_START> ::= <IDENTIFIER\_START\_NO\_DOLLAR>
\alt `$'
<IDENTIFIER\_START\_NO\_DOLLAR> ::= <LETTER>
\alt `_'
<IDENTIFIER\_PART\_NO\_DOLLAR> ::= <IDENTIFIER\_START\_NO\_DOLLAR>
\alt <DIGIT>
<IDENTIFIER\_PART> ::= <IDENTIFIER\_START>
\alt <DIGIT>
<qualified> ::= <identifier> (`.' <identifier>)?
\end{grammar}
\LMHash{}
A built-in identifier is one of the identifiers produced by the production {\em BUILT\_IN\_IDENTIFIER}.
It is a compile-time error if a built-in identifier is used as the declared name of a prefix, class, type parameter or type alias.
It is a compile-time error to use a built-in identifier other than \DYNAMIC{} in a type annotation or type parameter.
\rationale{
Built-in identifiers are identifiers that are used as keywords in Dart, but are not reserved words in Javascript.
To minimize incompatibilities when porting Javascript code to Dart, we do not make these into reserved words.
A built-in identifier may not be used to name a class or type.
In other words, they are treated as reserved words when used as types.
This eliminates many confusing situations without causing compatibility problems.
After all, a Javascript program has no type declarations or annotations so no clash can occur.
Furthermore, types should begin with an uppercase letter (see the appendix) and so no clash should occur in any Dart user program anyway.
}
\LMHash{}
It is a compile-time error if either of the identifiers \AWAIT{} or \YIELD{} is used as an identifier in a function body marked with either \ASYNC{}, \code{\ASYNC*} or \code{\SYNC*}.
\rationale{
For compatibility reasons, new constructs cannot rely upon new reserved words or even built-in identifiers.
However, the constructs above are only usable in contexts that require special markers introduced concurrently with these constructs, so no old code could use them.
Hence the restriction, which treats these names as reserved words in a limited context.
}
\LMHash{}
Evaluation of an identifier expression $e$ of the form \id{} proceeds as follows:
\LMHash{}
Let $d$ be the innermost declaration in the enclosing lexical scope whose name is \id{} or \code{\id=}.
If no such declaration exists in the lexical scope, let $d$ be the declaration of the inherited member named \id{} if it exists.
\begin{itemize}
\item if $d$ is a prefix $p$, a compile-time error occurs unless the token immediately following $d$ is \code{'.'}.
\item If $d$ is a class or type alias $T$, the value of $e$ is an instance of class \code{Type} (or a subclass thereof) reifying $T$.
\item If $d$ is a type parameter $T$, then the value of $e$ is the value of the actual type argument corresponding to $T$ that was passed to the generative constructor that created the current binding of \THIS{}.
If, however, $e$ occurs inside a static member, a compile-time error occurs.
%\commentary{We are assured that \THIS{} is well defined, because if we were in a static member the reference to $T$ is a compile-time error (\ref{generics}.)}
%\item If $d$ is a library variable then:
% \begin{itemize}
% \item If $d$ is of one of the forms \code{\VAR{} $v$ = $e_i$;} , \code{$T$ $v$ = $e_i$;} , \code{\FINAL{} $v$ = $e_i$;} or \code{\FINAL{} $T$ $v$ = $e_i$;} and no value has yet been stored into $v$ then the initializer expression $e_i$ is evaluated. If, during the evaluation of $e_i$, the getter for $v$ is referenced, a \code{CyclicInitializationError} is thrown. If the evaluation succeeded yielding an object $o$, let $r$ be $o$, otherwise let $r$ be the null object (\ref{null}). In any case, $r$ is stored into $v$. The value of $e$ is $r$.
\item If $d$ is a constant variable of one of the forms \code{\CONST{} $v$ = $e$;} or \code{\CONST{} $T$ $v$ = $e$;} then the value \id{} is the value of the constant expression $e$.
% Otherwise
% \item $e$ evaluates to the current binding of \id.
% \end{itemize}
\item If $d$ is a local variable (\commentary{which can be a formal parameter}) then $e$ evaluates to the current binding of \id.
\item If $d$ is a static method, top-level function or local function then $e$ evaluates to the function object obtained by closurization (\ref{functionClosurization}) of the declaration denoted by $d$.
\item If $d$ is the declaration of a class variable, static getter or static setter declared in class $C$, then evaluation of $e$ is equivalent to evaluation of the property extraction (\ref{propertyExtraction}) \code{$C$.\id}.
\item If $d$ is the declaration of a library variable, top-level getter or top-level setter, then evaluation of $e$ is equivalent to evaluation of the top level getter invocation (\ref{topLevelGetterInvocation}) \id.
\item Otherwise, if $e$ occurs inside a top level or static function (be it function, method, getter, or setter) or variable initializer, evaluation of $e$ causes a \code{NoSuchMethod} to be thrown.
\item Otherwise, evaluation of $e$ is equivalent to evaluation of the property extraction (\ref{propertyExtraction}) \code{\THIS.\id}.
\end{itemize}
\LMHash{}
The static type of $e$ is determined as follows:
\begin{itemize}
\item If $d$ is a class, type alias or type parameter the static type of $e$ is \code{Type}.
\item If $d$ is a local variable (\commentary{which can be a formal parameter})
the static type of $e$ is the type of the variable \id,
unless \id{} is known to have some type $T$,
in which case the static type of $e$ is $T$,
provided that $T$ is more specific than any other type $S$ such that $v$ is known to have type $S$.
\item If $d$ is a static method, top-level function or local function the static type of $e$ is the function type defined by $d$.
\item If $d$ is the declaration of a class variable, static getter or static setter declared in class $C$,
the static type of $e$ is the static type of the getter invocation (\ref{propertyExtraction}) \code{$C$.\id}.
\item If $d$ is the declaration of a library variable, top-level getter or top-level setter,
the static type of $e$ is the static type of the top level getter invocation \id.
\item Otherwise, if $e$ occurs inside a top level or static function (be it function, method, getter, or setter) or variable initializer,
the static type of $e$ is \DYNAMIC{}.
\item Otherwise, the static type of $e$ is the type of the property extraction (\ref{propertyExtraction}) \code{\THIS.\id}.
\end{itemize}
\commentary{
Note that if one declares a setter, we bind to the corresponding getter even if it does not exist.
}
\rationale{
This prevents situations where one uses uncorrelated setters and getters.
The intent is to prevent errors when a getter in a surrounding scope is used accidentally.
}
\LMHash{}
It is a compile-time error if an identifier expression \id{} occurs inside a top level or static function
(be it function, method, getter, or setter)
or in an instance variable initializer,
or in an initializer list expression,
and there is no declaration $d$ with name \id{} in the lexical scope enclosing the expression.
\subsection{Type Test}
\LMLabel{typeTest}
\LMHash{}
The {\em is-expression} tests if an object is a member of a type.
\begin{grammar}
<typeTest> ::= <isOperator> <type>
<isOperator> ::= \IS{} `!'?
\end{grammar}
\LMHash{}
Evaluation of the is-expression \code{$e$ \IS{} $T$} proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to a value $v$.
% TODO(eernst): https://github.com/dart-lang/sdk/issues/34521.
Then, if $T$ is a malformed or deferred type (\ref{staticTypes}), a dynamic error occurs.
Otherwise, if the dynamic type of $v$ is a subtype of $T$, the is-expression evaluates to \TRUE.
Otherwise it evaluates to \FALSE.
\commentary{
It follows that \code{$e$ \IS{} Object} is always true.
This makes sense in a language where everything is an object.
Also note that \code{\NULL{} \IS{} $T$} is false unless $T = \code{Object}$, $T = \code{\DYNAMIC{}}$ or $T = \code{Null}$.
The former two are useless, as is anything of the form \code{$e$ \IS{} Object} or \code{$e$ \IS{} \DYNAMIC{}}.
Users should test for the null object (\ref{null}) directly rather than via type tests.
}
\LMHash{}
The is-expression \code{$e$ \IS{}! $T$} is equivalent to \code{!($e$ \IS{} $T$)}.
% Add flow dependent types
\LMHash{}
Let $v$ be a local variable (\commentary{which can be a formal parameter}).
An is-expression of the form \code{$v$ \IS{} $T$} shows that $v$ has type $T$ if{}f $T$ is more specific than the type $S$ of the expression $v$ and both $T \ne \DYNAMIC{}$ and $S \ne \DYNAMIC{}$.
\rationale{
The motivation for the ``shows that v has type T" relation is to reduce spurious errors thereby enabling a more natural coding style.
The rules in the current specification are deliberately kept simple.
It would be upwardly compatible to refine these rules in the future; such a refinement would accept more code without errors, but not reject any code now error-free.
The rule only applies to locals and parameters, as instance and static variables could be modified via side-effecting functions or methods that are not accessible to a local analysis.
It is pointless to deduce a weaker type than what is already known.
Furthermore, this would lead to a situation where multiple types are associated with a variable at a given point, which complicates the specification.
Hence the requirement that $T << S$ (we use $<<$ rather than subtyping because subtyping is not a partial order).
We do not want to refine the type of a variable of type \DYNAMIC{}, as this could lead to more errors rather than fewer.
The opposite requirement, that $T \ne \DYNAMIC{}$ is a safeguard lest $S$ ever be $\bot$.
}
\LMHash{}
The static type of an is-expression is \code{bool}.
\subsection{Type Cast}
\LMLabel{typeCast}
\LMHash{}
The {\em cast expression} ensures that an object is a member of a type.
\begin{grammar}
<typeCast> ::= <asOperator> <type>
<asOperator> ::= \AS{}
\end{grammar}
\LMHash{}
Evaluation of the cast expression \code{$e$ \AS{} $T$} proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to a value $v$.
%% TODO(eernst): https://github.com/dart-lang/sdk/issues/34521
Then, if $T$ is a malformed or deferred type (\ref{staticTypes}), a dynamic error occurs.
It is a dynamic type error if $o$ is not the null object (\ref{null})
and the dynamic type of $o$ is not a subtype of $T$.
Otherwise $e$ evaluates to $v$.
\LMHash{}
The static type of a cast expression \code{$e$ \AS{} $T$} is $T$.
\section{Statements}
\LMLabel{statements}
\LMHash{}
A {\em statement} is a fragment of Dart code that can be executed at run time.
Statements, unlike expressions, do not evaluate to a value, but are instead executed for their effect on the program state and control flow.
\label{completion}
Execution of a statement {\em completes} in one of five ways: either it {\em completes normally}, it {\em breaks} or it {\em continues} (either to a label or without a label), it {\em returns} (with or without a value), or it {\em throws} an exception object and an associated stack trace.
In the description of statement execution, the default is that the execution
completes normally unless otherwise stated.
If the execution of a statement, $s$, is defined in terms of executing
another statement,
and the execution of that other statement does not complete normally,
then, unless otherwise stated, the execution of $s$ stops
at that point and completes in the same way.
\commentary{
For example, if execution of the body of a \DO{} loop returns a value, so does execution of the \DO{} loop statement itself.
}
If the execution of a statement is defined in terms of evaluating an expression
and the evaluation of that expression throws,
then, unless otherwise stated, the execution of the statement stops
at that point and throws the same exception object and stack trace.
\commentary{
For example, if evaluation of the condition expression of an \IF{} statement throws,
then so does execution of the \IF{} statement.
Likewise, if evaluation of the expression of a \RETURN{} statement throws, so does execution of the \RETURN{} statement.
}
\LMHash{}
\begin{grammar}
<statements> ::= <statement>*
<statement> ::= <label>* <nonLabelledStatement>
<nonLabelledStatement> ::= <block>
\alt <localVariableDeclaration>
\alt <forStatement>
\alt <whileStatement>
\alt <doStatement>
\alt <switchStatement>
\alt <ifStatement>
\alt <rethrowStatement>
\alt <tryStatement>
\alt <breakStatement>
\alt <continueStatement>
\alt <returnStatement>
\alt <yieldStatement>
\alt <yieldEachStatement>
\alt <expressionStatement>
\alt <assertStatement>
\alt <localFunctionDeclaration>
\end{grammar}
\subsection{Blocks}
\LMLabel{blocks}
\LMHash{}
A {\em block statement} supports sequencing of code.
\LMHash{}
Execution of a block statement $\{s_1, \ldots, s_n\}$ proceeds as follows:
\LMHash{}
For $i \in 1 .. n, s_i$ is executed.
\LMHash{}
A block statement introduces a new scope, which is nested in the lexically enclosing scope in which the block statement appears.
\subsection{Expression Statements}
\LMLabel{expressionStatements}
\LMHash{}
An {\em expression statement} consists of an expression that does not
begin with a \syntax{`{'} character.
\begin{grammar}
<expressionStatement> ::= <expression>? `;'
\end{grammar}
\LMHash{}
The expression of an expression statement is not allowed to begin with a \syntax{`\{'}.
\commentary{
This means that if some source text could otherwise be parsed as an expression
followed by a \syntax{`;'}, then this grammar production does not apply
when the expression starts with a \syntax{`\{'}.
}
\rationale{
The restriction resolves an ambiguity while parsing where a
\syntax{`\{'} can start either a block (\ref{blocks}) or a map literal (\ref{maps}).
By disallowing the latter from starting an expression statement,
the parser does not need to look further ahead
before deciding that it is parsing a block statement.
}
\LMHash{}
Execution of an expression statement \code{$e$;} proceeds by evaluating $e$.
If the expression evaluates to a value, then the value is ignored
and the execution completes normally.
\subsection{Local Variable Declaration}
\LMLabel{localVariableDeclaration}
\LMHash{}
A {\em variable declaration statement},
also known as a {\em local variable declaration},
has the following form:
\begin{grammar}
<localVariableDeclaration> ::= <initializedVariableDeclaration> `;'
\end{grammar}
\LMHash{}
Each local variable declaration introduces
a {\em local variable} into the innermost enclosing scope.
\commentary{
Local variables do not induce getters and setters.
Note that a formal parameter declaration also introduces
a local variable into the associated formal parameter scope
(\ref{formalParameters}).
}
\LMHash{}
The properties of being
{\em initialized}, {\em constant}, {\em final}, and {\em mutable}
apply to local variables with the same definitions as for other variables
(\ref{variables}).
\LMHash{}
We say that a local variable $v$ is {\em potentially mutated} in some scope $s$
if $v$ is mutable, and an assignment to $v$ occurs in $s$.
\LMHash{}
A local variable declaration of the form \code{\VAR{} $v$;} is equivalent to \code{\VAR{} $v$ = \NULL{};}.
A local variable declaration of the form \code{$T$ $v$;} is equivalent to \code{$T$ $v$ = \NULL{};}.
\commentary{
This holds regardless of the type $T$.
E.g., \code{int i;} is equivalent to \code{int i = null;}.
}
\LMHash{}
The type of a local variable with a declaration of one of the forms
\code{$T$ $v$ = $e$;}
\code{\CONST{} $T$ $v$ = $e$;}
\code{\FINAL{} $T$ $v$ = $e$;}
is $T$.
The type of a local variable with a declaration of one of the forms
\code{\VAR{} $v$ = $e$;}
\code{\CONST{} $v$ = $e$;}
\code{\FINAL{} $v$ = $e$;}
is \DYNAMIC{}.
\LMHash{}
Let $v$ be a local variable declared by an initializing variable declaration,
and let $e$ be the associated initializing expression.
It is a compile-time error if the static type of $e$ is not assignable to the type of $v$.
It is a compile-time error if a local variable $v$ is final,
and the declaration of $v$ is not an initializing variable declaration.
\commentary{
It is also a compile-time error to assign to a final local variable
(\ref{assignment}).
}
\LMHash{}
It is a compile-time error if
a local variable is referenced at a source code location that is before
the end of its initializing expression, if any,
and otherwise before the declaring occurrence of
the identifier which names the variable.
\commentary{
The example below illustrates the expected behavior.
A variable `\code{x}' is declared at the library level,
and another `\code{x}' is declared inside the function `\code{f}'.
}
\begin{dartCode}
\VAR{} x = 0;
\\
f(y) \{
\VAR{} z = x; // \comment{compile-time error}
if (y) \{
x = x + 1; // \comment{two compile-time errors}
print(x); // \comment{compile-time error}
\}
\VAR{} x = x++; // \comment{compile-time error}
print(x);
\}
\end{dartCode}
\commentary{
The declaration inside `\code{f}' hides the enclosing one.
So all references to `\code{x}' inside `\code{f}'
refer to the inner declaration of `\code{x}'.
However, many of these references are illegal,
because they appear before the declaration.
The assignment to `\code{z}' is one such case.
The assignment to `\code{x}' in the \IF{} statement
suffers from multiple problems.
The right hand side reads `\code{x}' before its declaration,
and the left hand side assigns to `\code{x}' before its declaration.
Each of these are, independently, compile-time errors.
The print statement inside the \IF{} is also illegal.
The inner declaration of `\code{x}' is itself erroneous
because its right hand side attempts to
read `\code{x}' before the declaration has terminated.
The occurrence of `\code{x}' that declares and names the variable
(that is, the one to the left of `\code{=}' in the inner declaration)
is not a reference, and so is legal.
The last print statement is perfectly legal as well.
}
\commentary{
As another example \code{\VAR{} x = 3, y = x;} is legal,
because \code{x} is referenced after its initializer.
A particularly perverse example involves
a local variable name shadowing a type.
This is possible because Dart has a
single namespace for types, functions and variables.
}
\begin{dartCode}
\CLASS{} C \{\}
perverse() \{
\VAR{} v = \NEW{} C(); // \comment{compile-time error}
C aC; // \comment{compile-time error}
\VAR{} C = 10;
\}
\end{dartCode}
\commentary{
Inside \code{perverse()}, `\code{C}' denotes a local variable.
The type `\code{C}' is hidden by the variable of the same name.
The attempt to instantiate `\code{C}' causes a compile-time error
because it references a local variable prior to its declaration.
Similarly, for the declaration of `\code{aC}'.
}
\LMHash{}
Execution of a variable declaration statement of one of the forms
\code{\VAR{} $v$ = $e$;}
\code{$T$ $v$ = $e$;}
\code{\CONST{} $v$ = $e$;}
\code{\CONST{} $T$ $v$ = $e$;}
\code{\FINAL{} $v$ = $e$;} or
\code{\FINAL{} $T$ $v$ = $e$;}
proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to an object $o$.
Then, the variable $v$ is set to $o$.
A dynamic type error occurs
if the dynamic type of $o$ is not a subtype of the actual type
(\ref{actualTypeOfADeclaration})
of $v$.
% The local variable discussion does not mention how to read/write locals.
% Consider spelling this out, in terms of storage.
\subsection{Local Function Declaration}
\LMLabel{localFunctionDeclaration}
\LMHash{}
A function declaration statement declares a new local function (\ref{functionDeclarations}).
\begin{grammar}
<localFunctionDeclaration> ::= <functionSignature> <functionBody>
\end{grammar}
\LMHash{}
A function declaration statement of one of the forms
\code{\id{} \metavar{signature} \{ \metavar{statements} \}}
or
\code{$T$ \id{} \metavar{signature} \{ \metavar{statements} \}}
causes a new function named \id{} to be added to the innermost enclosing scope.
It is a compile-time error to reference a local function before its declaration.
\commentary{
This implies that local functions can be directly recursive, but not mutually recursive.
Consider these examples:
}
\begin{dartCode}
f(x) => x++; // \comment{a top level function}
\\
top() \{ // \comment{another top level function}
f(3); // \comment{illegal}
f(x) => x > 0? x*f(x-1): 1; // \comment{recursion is legal}
g1(x) => h(x, 1); // \comment{error: h is not declared yet}
h(x, n) => x > 1? h(x-1, n*x): n; // \comment{again, recursion is fine}
g2(x) => h(x, 1); // \comment{legal}
\\
p1(x) => q(x,x); // \comment{illegal}
q1(a, b)$ =>$ a > 0 ? p1(a-1): b; // \comment{fine}
\\
q2(a, b) => a > 0 ? p2(a-1): b; // \comment{illegal}
p1(x) => q2(x,x); // \comment{fine}
\}
\end{dartCode}
\commentary{
There is no way to write a pair of mutually recursive local functions,
because one always has to come before the other is declared.
These cases are quite rare,
and can always be managed by defining a pair of variables first,
then assigning them appropriate function literals:
}
\begin{dartCode}
top2() \{ // \comment{a top level function}
\VAR{} p, q;
p = (x) => q(x,x);
q = (a, b) => a > 0 ? p(a-1): b;
\}
\end{dartCode}
\rationale{
The rules for local functions differ slightly from those for local variables in that a function can be accessed within its declaration but a variable can only be accessed after its declaration.
This is because recursive functions are useful whereas recursively defined variables are almost always errors.
It therefore makes sense to harmonize the rules for local functions with those for functions in general rather than with the rules for local variables.
}
\subsection{If}
\LMLabel{if}
\LMHash{}
The {\em if statement} allows for conditional execution of statements.
\begin{grammar}
<ifStatement> ::= \IF{} `(' <expression> `)' <statement> (\ELSE{} <statement>)?
\end{grammar}
\LMHash{}
An if statement of the form \code{\IF{} ($e$) $s_1$ \ELSE{} $s_2$} where $s_1$ is not a block statement is equivalent to the statement \code{\IF{} ($e$) \{$s_1$\} \ELSE{} $s_2$}.
An if statement of the form \code{\IF{} ($e$) $s_1$ \ELSE{} $s_2$} where $s_2$ is not a block statement is equivalent to the statement \code{\IF{} ($e$) $s_1$ \ELSE{} \{$s_2$\}}.
\rationale{
The reason for this equivalence is to catch errors such as
}
\begin{dartCode}
\VOID{} main() \{
\IF{} (somePredicate)
\VAR{} v = 2;
print(v);
\}
\end{dartCode}
\rationale{
Under reasonable scope rules such code is problematic.
If we assume that \code{v} is declared in the scope of the method \code{main()}, then when \code{somePredicate} is false, \code{v} will be uninitialized when accessed.
The cleanest approach would be to require a block following the test, rather than an arbitrary statement.
However, this goes against long standing custom, undermining Dart's goal of familiarity.
Instead, we choose to insert a block, introducing a scope, around the statement following the predicate (and similarly for \ELSE{} and loops).
This will cause a compile-time error in the case above.
Of course, if there is a declaration of \code{v} in the surrounding scope, programmers might still be surprised.
We expect tools to highlight cases of shadowing to help avoid such situations.
}
\LMHash{}
Execution of an if statement of the form \code{\IF{} ($b$) $s_1$ \ELSE{} $s_2$} where $s_1$ and $s_2$ are block statements, proceeds as follows:
\LMHash{}
First, the expression $b$ is evaluated to an object $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
If $o$ is \TRUE{}, then the block statement $s_1$ is executed, otherwise the block statement $s_2$ is executed.
\LMHash{}
It is a compile-time error if the type of the expression $b$ may not be assigned to \code{bool}.
\LMHash{}
If $b$ shows that a local variable $v$ has type $T$,
then the type of $v$ is known to be $T$ in $s_2$,
unless any of the following are true
\begin{itemize}
\item $v$ is potentially mutated in $s_1$,
\item $v$ is potentially mutated within a function other
than the one where $v$ is declared, or
\item $v$ is accessed by a function defined in $s_1$ and
$v$ is potentially mutated anywhere in the scope of $v$.
\end{itemize}
\LMHash{}
An if statement of the form \code{\IF{} ($e$) $s$} is equivalent to the if statement \code{\IF{} ($e$) $s$ \ELSE{} \{\}}.
\subsection{For}
\LMLabel{for}
\LMHash{}
The {\em for statement} supports iteration.
\begin{grammar}
<forStatement> ::= \AWAIT? \FOR{} `(' <forLoopParts> `)' <statement>
<forLoopParts> ::= <forInitializerStatement> <expression>? `;' <expressionList>?
\alt <declaredIdentifier> \IN{} <expression>
\alt <identifier> \IN{} <expression>
<forInitializerStatement> ::= <localVariableDeclaration>
\alt <expression>? `;'
\end{grammar}
\LMHash{}
The for statement has three forms - the traditional for loop and two forms of the for-in statement - synchronous and asynchronous.
\subsubsection{For Loop}
\LMLabel{forLoop}
\LMHash{}
Execution of a for statement of the form \code{\FOR{} (\VAR{} $v$ = $e_0$; $c$; $e$) $s$} proceeds as follows:
\LMHash{}
If $c$ is empty then let $c'$ be \TRUE{} otherwise let $c'$ be $c$.
\LMHash{}
First the variable declaration statement \VAR{} $v = e_0$ is executed.
Then:
\begin{enumerate}
\item
\label{beginFor}
If this is the first iteration of the for loop, let $v'$ be $v$.
Otherwise, let $v'$ be the variable $v''$ created in the previous execution of step \ref{allocateFreshVar}.
\item
The expression $[v'/v]c$ is evaluated to a value $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
If $o$ is \FALSE{}, the for loop completes normally.
Otherwise, execution continues at step \ref{beginIteration}.
\item
\label{beginIteration}
The statement $[v'/v]\{s\}$ is executed.
If this execution completes normally, continues without a label,
or continues to a label (\ref{labels}) that prefixes this \FOR{} statement (\ref{completion}),
then execution of the statement is treated as if it had completed normally.
\label{allocateFreshVar}
Let $v''$ be a fresh variable.
$v''$ is bound to the value of $v'$.
\item
The expression $[v''/v]e$ is evaluated, and the process recurses at step \ref{beginFor}.
\end{enumerate}
\rationale{
The definition above is intended to prevent the common error where users create a function object inside a for loop,
intending to close over the current binding of the loop variable, and find
(usually after a painful process of debugging and learning)
that all the created function objects have captured the same value---the one current in the last iteration executed.
Instead, each iteration has its own distinct variable.
The first iteration uses the variable created by the initial declaration.
The expression executed at the end of each iteration uses a fresh variable $v''$,
bound to the value of the current iteration variable,
and then modifies $v''$ as required for the next iteration.
}
\LMHash{}
It is a compile-time error if the static type of $c$ may not be assigned to \code{bool}.
%A for statement of the form \code{\FOR{} ($d$ ; $c$; $e$) $s$} is equivalent to the following code:
%\code{
%\{$d$;
%\WHILE{} ($c$) \{
% \{$s$\}
% $e$;
%\}\}
%}
%If $c$ is empty, it is interpreted as \TRUE{}.
\subsubsection{For-in}
\LMLabel{for-in}
\LMHash{}
Let $D$ be derived from \syntax{<finalConstVarOrType>?}
and let $n0$ be an identifier that does not occur anywhere in the program.
A for statement of the form \code{\FOR{} ($D$ \id{} \IN{} $e$) $s$} is equivalent to the following code:
\begin{dartCode}
\VAR{} $n0$ = $e$.iterator;
\WHILE{} ($n0$.moveNext()) \{
$D$ \id{} = $n0$.current;
$s$
\}
\end{dartCode}
For purposes of static typechecking,
this code is checked under the assumption that $n0$ is declared to be of type $T$,
where $T$ is the static type of \code{$e$.iterator}.
\commentary{
It follows that it is a compile-time error if $D$ is empty and \id{} is a final variable.
}
\subsubsection{Asynchronous For-in}
\LMLabel{asynchronousFor-in}
\LMHash{}
A for-in statement may be asynchronous.
The asynchronous form is designed to iterate over streams.
An asynchronous for loop is distinguished by the keyword \AWAIT{} immediately preceding the keyword \FOR.
\LMHash{}
Let $D$ be derived from \syntax{<finalConstVarOrType>?}.
Execution of a for-in statement, $f$, of the form
\code{\AWAIT{} \FOR{} ($D$ \id{} \IN{} $e$) $s$}
proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to an object $o$.
It is a dynamic type error if $o$ is not an instance of a class that implements \code{Stream}.
It is a compile-time error if $D$ is empty and \id{} is a final variable.
\LMHash{}
The stream associated with the innermost enclosing asynchronous for loop, if any, is paused.
The stream $o$ is listened to, producing a stream subscription $u$,
and execution of the asynchronous for-in loop is suspended
until a stream event is available.
\commentary{
This allows other asynchronous events to execute while this loop is waiting for stream events.
}
Pausing an asynchronous for loop means pausing the associated stream subscription.
A stream subscription is paused by calling its \code{pause} method.
If the subscription is already paused, an implementation may omit further calls to \code{pause}.
\commentary{
The \code{pause} call can throw, although that should never happen for a correctly implemented stream.
}
\LMHash{}
For each {\em data event} from $u$,
the statement $s$ is executed with \id{} bound to the value of the current data event.
\commentary{
Either execution of $s$ is completely synchronous, or it contains an
asynchronous construct (\AWAIT{}, \AWAIT{} \FOR{}, \YIELD{} or \YIELD*)
which will pause the stream subscription of its surrounding asynchronous loop.
This ensures that no other event of $u$ occurs before execution of $s$ is complete, if $o$ is a correctly implemented stream.
If $o$ doesn't act as a valid stream, for example by not respecting pause requests, the behavior of the asynchronous loop may become unpredictable.
}
\LMHash{}
If execution of $s$ continues without a label, or to a label (\ref{labels}) that prefixes the asynchronous for statement (\ref{completion}), then the execution of $s$ is treated as if it had completed normally.
If execution of $s$ otherwise does not complete normally, the subscription $u$ is canceled by evaluating \code{\AWAIT{} $v$.cancel()} where $v$ is a fresh variable referencing the stream subscription $u$.
If that evaluation throws,
execution of $f$ throws the same exception and stack trace.
Otherwise execution of $f$ completes in the same way as the execution of $s$.
% Notice: The previous specification was unclear about what happened when
% a subscripton is canceled. This text is explicit, and existing
% implementations may not properly await the cancel call.
Otherwise the execution of $f$ is suspended again, waiting for the next stream subscription event, and $u$ is resumed if it has been paused.
\commentary{
The \code{resume} call can throw, in which case the asynchronous for
loop also throws.
That should never happen for a correctly implemented stream.
}
\LMHash{}
On an {\em error event} from $u$,
with error object $e$ and stack trace $st$,
the subscription $u$ is canceled by evaluating \code{\AWAIT{} v.cancel()}
where $v$ is a fresh variable referencing the stream subscription $u$.
If that evaluation throws,
execution of $f$ throws the same exception object and stack trace.
Otherwise execution of $f$ throws with $e$ as exception object and $st$ as stack trace.
\LMHash{}
When $u$ is done, execution of $f$ completes normally.
\LMHash{}
It is a compile-time error if an asynchronous for-in statement appears inside a synchronous function (\ref{functions}).
It is a compile-time error if a traditional for loop (\ref{forLoop}) is prefixed by the \AWAIT{} keyword.
\rationale{
An asynchronous loop would make no sense within a synchronous function, for the same reasons that an await expression makes no sense in a synchronous function.
}
\subsection{While}
\LMLabel{while}
\LMHash{}
The while statement supports conditional iteration, where the condition is evaluated prior to the loop.
\begin{grammar}
<whileStatement> ::= \WHILE{} `(' <expression> `)' <statement>
\end{grammar}
\LMHash{}
Execution of a while statement of the form \code{\WHILE{} ($e$) $s$;} proceeds as follows:
\LMHash{}
The expression $e$ is evaluated to an object $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
\LMHash{}
If $o$ is \FALSE{}, then execution of the while statement completes normally (\ref{completion}).
\LMHash{}
Otherwise $o$ is \TRUE{} and then the statement $\{s\}$ is executed.
If that execution completes normally or it continues with no label or to a label (\ref{labels}) that prefixes the \WHILE{} statement (\ref{completion}), then the while statement is re-executed.
If the execution breaks without a label, execution of the while statement completes normally.
\commentary{
If the execution breaks with a label that prefixes the \WHILE{} statement,
it does end execution of the loop, but the break itself is handled by the surrounding labeled statement (\ref{labels}).
}
\LMHash{}
It is a compile-time error if the static type of $e$ may not be assigned to \code{bool}.
\subsection{Do}
\LMLabel{do}
\LMHash{}
The do statement supports conditional iteration, where the condition is evaluated after the loop.
\begin{grammar}
<doStatement> ::= \DO{} <statement> \WHILE{} `(' <expression> `)' `;'
\end{grammar}
\LMHash{}
Execution of a do statement of the form \code{\DO{} $s$ \WHILE{} ($e$);} proceeds as follows:
\LMHash{}
The statement $\{s\}$ is executed.
If that execution continues with no label, or to a label (\ref{labels}) that prefixes the do statement (\ref{completion}), then the execution of $s$ is treated as if it had completed normally.
\LMHash{}
Then, the expression $e$ is evaluated to an object $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
If $o$ is \FALSE{}, execution of the do statement completes normally (\ref{completion}).
If $o$ is \TRUE{}, then the do statement is re-executed.
\LMHash{}
It is a compile-time error if the static type of $e$ may not be assigned to \code{bool}.
\subsection{Switch}
\LMLabel{switch}
\LMHash{}
The {\em switch statement} supports dispatching control among a large number of cases.
\begin{grammar}
<switchStatement> ::= \SWITCH{} `(' <expression> `)' `{' <switchCase>* <defaultCase>? `}'
<switchCase> ::= <label>* \CASE{} <expression> `:' <statements>
<defaultCase> ::= <label>* \DEFAULT{} `:' <statements>
\end{grammar}
\LMHash{}
Given a switch statement of the form
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
\end{dartCode}
or the form
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
\end{dartCode}
it is a compile-time error unless the expressions $e_k$ are constant expressions for all $k \in 1 .. n$.
It is a compile-time error if the values of the expressions $e_k$ are not either:
\begin{itemize}
\item instances of the same class $C$, for all $k \in 1 .. n$, or
\item instances of a class that implements \code{int}, for all $k \in 1 .. n$, or
\item instances of a class that implements \code{String}, for all $k \in 1 .. n$.
\end{itemize}
\commentary{
In other words, all the expressions in the cases evaluate to constants of the exact same user defined class or are of certain known types.
%% TODO(eernst): Update when we specify inference: const List<int> xs = [];
%% may be a counter-example: The value is a list that "knows" it is a
%% `List<int>` independently of the type annotation, but it wouldn't be a
%% `List<int>` if that type annotation hadn't been there.
Note that the values of the expressions are known at compile time, and are independent of any type annotations.
}
\LMHash{}
It is a compile-time error if the class $C$ has an implementation of
the operator \code{==} other than the one inherited from \code{Object},
unless the expression evaluates to a string or an integer,
or the expression evaluates to an instance of the built-in
class \code{Symbol} which was initially obtained by evaluation of a
literal symbol or
a constant invocation of a constructor of the \code{Symbol} class.
\rationale{
The prohibition on user defined equality allows us to implement the switch efficiently for user defined types.
We could formulate matching in terms of identity instead with the same efficiency.
However, if a type defines an equality operator, programmers would find it quite surprising that equal objects did not match.
}
\commentary{
The \SWITCH{} statement should only be used in very limited situations (e.g., interpreters or scanners).
}
\LMHash{}
Execution of a switch statement of the form
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
\end{dartCode}
or the form
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
\end{dartCode}
proceeds as follows:
\LMHash{}
The statement \code{\VAR{} \id{} = $e$;} is evaluated, where \id{} is a fresh variable.
It is a run-time error if the value of $e$ is
not an instance of the same class as the constants $e_1, \ldots, e_n$.
\commentary{
Note that if there are no case clauses ($n = 0$), the type of $e$ does not matter.
}
\LMHash{}
Next, the case clause \CASE{} $e_{1}$: $s_{1}$ is matched against \id, if $n > 0$.
Otherwise if there is a \DEFAULT{} clause, the case statements $s_{n+1}$ are executed (\ref{case-execute}).
\LMHash{}
Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
\end{dartCode}
against the value of a variable \id{} proceeds as follows:
\LMHash{}
The expression \code{$e_k$ == \id} is evaluated to an object $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
If $o$ is \FALSE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against \id{} if $k < n$, and if $k = n$, then the \DEFAULT{} clause's statements are executed (\ref{case-execute}).
If $o$ is \TRUE{}, let $h$ be the smallest number such that $h \ge k$ and $s_h$ is non-empty.
If no such $h$ exists, let $h = n + 1$.
The case statements $s_h$ are then executed (\ref{case-execute}).
\LMHash{}
Matching of a \CASE{} clause \CASE{} $e_{k}: s_{k}$ of a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
\end{dartCode}
against the value of a variable \id{} proceeds as follows:
\LMHash{}
The expression \code{$e_k$ == \id} is evaluated to an object $o$.
It is a run-time error if the run-time type of $o$ is not \code{bool}.
If $o$ is \FALSE{} the following case, \CASE{} $e_{k+1}: s_{k+1}$ is matched against \id{} if $k < n$.
If $o$ is \TRUE{}, let $h$ be the smallest integer such that $h \ge k$ and $s_h$ is non-empty.
If such a $h$ exists, the case statements $s_h$ are executed (\ref{case-execute}).
Otherwise the switch statement completes normally (\ref{completion}).
\LMHash{}
It is a compile-time error if the type of $e$ may not be assigned to the type of $e_k$.
Let $s$ be the last statement of the statement sequence $s_k$.
If $s$ is a non-empty block statement, let $s$ instead be the last statement of the block statement.
It is a compile-time error if $s$ is not a \BREAK{}, \CONTINUE{}, \RETHROW{} or \RETURN{} statement
or an expression statement where the expression is a \THROW{} expression.
\rationale{
The behavior of switch cases intentionally differs from the C tradition.
Implicit fall through is a known cause of programming errors and therefore disallowed.
Why not simply break the flow implicitly at the end of every case, rather than requiring explicit code to do so?
This would indeed be cleaner.
It would also be cleaner to insist that each case have a single (possibly compound) statement.
We have chosen not to do so in order to facilitate porting of switch statements from other languages.
Implicitly breaking the control flow at the end of a case would silently alter the meaning of ported code that relied on fall-through, potentially forcing the programmer to deal with subtle bugs.
Our design ensures that the difference is immediately brought to the coder's attention.
The programmer will be notified at compile time if they forget to end a case with a statement that terminates the straight-line control flow.
The sophistication of the analysis of fall-through is another issue.
For now, we have opted for a very straightforward syntactic requirement.
There are obviously situations where code does not fall through, and yet does not conform to these simple rules, e.g.:
}
\begin{dartCode}
\SWITCH{} (x) \{
\CASE{} 1: \TRY{} \{ $\ldots$ \RETURN{}; \} \FINALLY{} \{ $\ldots$ \RETURN{}; \}
\}
\end{dartCode}
\rationale{
Very elaborate code in a case clause is probably bad style in any case, and such code can always be refactored.
}
\LMHash{}
It is a compile-time warning if all of the following conditions hold:
\begin{itemize}
\item The switch statement does not have a default clause.
\item The static type of $e$ is an enumerated type with elements $\id_1, \ldots, \id_n$.
\item The sets $\{e_1, \ldots, e_k\} $ and $\{\id_1, \ldots, \id_n\}$ are not the same.
\end{itemize}
\commentary{
In other words, a warning will be emitted if a switch statement over an enum is not exhaustive.
}
\subsubsection{Switch case statements}
\LMLabel{case-execute}
\LMHash{}
Execution of the case statements $s_h$ of a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
\}
\end{dartCode}
or a switch statement
\begin{dartCode}
\SWITCH{} ($e$) \{
$label_{11} \ldots label_{1j_1}$ \CASE{} $e_1: s_1$
$\ldots$
$label_{n1} \ldots label_{nj_n}$ \CASE{} $e_n: s_n$
$label_{(n+1)1} \ldots label_{(n+1)j_{n+1}}$ \DEFAULT{}: $s_{n+1}$
\}
\end{dartCode}
proceeds as follows:
\LMHash{}
Execute $\{s_h\}$.
If this execution completes normally,
and if $s_h$ is not the statements of the last case of the switch
($h = n$ if there is no \DEFAULT{} clause,
$h = n+1$ if there is a \DEFAULT{} clause),
then the execution of the switch case throws an error.
Otherwise $s_h$ are the last statements of the switch case,
and execution of the switch case completes normally.
\commentary{
In other words, there is no implicit fall-through between non-empty cases.
The last case in a switch (default or otherwise) can `fall-through' to the end of the statement.
}
If execution of $\{s_h\}$ breaks with no label (\ref{completion}), then the execution of the switch statement completes normally.
If execution of $\{s_h\}$ continues to a label (\ref{completion}), and the label is $label_{ij}$, where $1 \le i \le n+1$ if the \SWITCH{} statement has a \DEFAULT{}, or $1 \le i \le n$ if there is no \DEFAULT{}, and where $1 \le j \le j_{i}$, then
let $h$ be the smallest number such that $h \ge i$ and $s_h$ is non-empty.
If no such $h$ exists, let $h = n + 1$ if the \SWITCH{} statement has a \DEFAULT{}, otherwise let $h = n$.
The case statements $s_h$ are then executed (\ref{case-execute}).
If execution of $\{s_h\}$ completes in any other way, execution of the \SWITCH{} statement completes in the same way.
\subsection{Rethrow}
\LMLabel{rethrow}
\LMHash{}
The {\em rethrow statement} is used to re-throw an exception and its associated stack trace.
\begin{grammar}
<rethrowStatement> ::= \RETHROW{} `;'
\end{grammar}
\LMHash{}
Execution of a \code{\RETHROW{}} statement proceeds as follows:
\LMHash{}
Let $f$ be the immediately enclosing function, and let \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$)} be the immediately enclosing catch clause (\ref{try}).
\rationale{
A \RETHROW{} statement always appears inside a \CATCH{} clause, and any \CATCH{} clause is semantically equivalent to some \CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} (p1, p2)}.
So we can assume that the \RETHROW{} is enclosed in a \CATCH{} clause of that form.
}
\LMHash{}
The \RETHROW{} statement {\em throws} (\ref{completion}) with $p_1$ as the exception object and $p_2$ as the stack trace.
\LMHash{}
It is a compile-time error if a \code{\RETHROW{}} statement is not enclosed within an \ON-\CATCH{} clause.
\subsection{Try}
\LMLabel{try}
\LMHash{}
The try statement supports the definition of exception handling code in a structured way.
\begin{grammar}
<tryStatement> ::= \TRY{} <block> (<onPart>+ <finallyPart>? | <finallyPart>)
<onPart> ::= <catchPart> <block>
\alt \ON{} <type> <catchPart>? <block>
<catchPart> ::= \CATCH{} `(' <identifier> (`,' <identifier>)? `)'
<finallyPart> ::= \FINALLY{} <block>
\end{grammar}
\LMHash{}
A try statement consists of a block statement, followed by at least one of:
\begin{enumerate}
\item
A set of \ON{}-\CATCH{} clauses, each of which specifies (either explicitly or implicitly) the type of exception object to be handled, one or two exception parameters, and a block statement.
\item
A \FINALLY{} clause, which consists of a block statement.
\end{enumerate}
\rationale{
The syntax is designed to be upward compatible with existing Javascript programs.
The \ON{} clause can be omitted, leaving what looks like a Javascript catch clause.
}
\LMHash{}
A try statement of the form \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$;} is equivalent to the statement \code{\TRY{} $s_1$ $on-catch_1 \ldots on-catch_n$ \FINALLY{} $\{\}$}.
\LMHash{}
An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} where $p_2$ is a fresh identifier.
\LMHash{}
An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} where $p_1$ and $p_2$ are fresh identifiers.
\LMHash{}
An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p$, $p_2$) $s$} where $p_2$ is a fresh identifier.
An \ON{}-\CATCH{} clause of the form \code{\CATCH{} ($p_1$, $p_2$) $s$} is equivalent to an \ON{}-\CATCH{} clause \code{\ON{} \DYNAMIC{} \CATCH{} ($p_1$, $p_2$) $s$}.
\LMHash{}
An \ON{}-\CATCH{} clause of the form \code{\ON{} $T$ \CATCH{} ($p_1$, $p_2$) $s$} introduces a new scope $CS$ in which final local variables specified by $p_1$ and $p_2$ are defined.
The statement $s$ is enclosed within $CS$.
The static type of $p_1$ is $T$ and the static type of $p_2$ is \code{StackTrace}.
\LMHash{}
Execution of a \TRY{} statement $s$ of the form:
\begin{dartCode}
\TRY{} $b$
\ON{} $T_1$ \CATCH{} ($e_1$, $t_1$) $c_1$
\ldots{}
\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) $c_n$
\FINALLY{} $f$
\end{dartCode}
proceeds as follows:
\LMHash{}
First $b$ is executed.
If execution of $b$ throws (\ref{completion}) with exception object $e$ and stack trace $t$, then $e$ and $t$ are matched against the \ON{}-\CATCH{} clauses to yield a new completion (\ref{on-catch}).
Then, even if execution of $b$ did not complete normally or matching against the \ON{}-\CATCH{} clauses did not complete normally, the $f$ block is executed.
If execution of $f$ does not complete normally,
execution of the \TRY{} statement completes in the same way.
Otherwise if execution of $b$ threw (\ref{completion}), the \TRY{} statement completes in the same way as the matching against the \ON{}-\CATCH{} clauses.
Otherwise the \TRY{} statement completes in the same way as the execution of $b$.
\LMHash{}
If $T_1$ is a malformed or deferred type (\ref{staticTypes}), then performing a match causes a run-time error.
It is a compile-time error if $T_i$, $1 \le i \le n$ is a deferred or malformed type.
\subsubsection{\ON{}-\CATCH{} clauses}
\LMLabel{on-catch}
\LMHash{}
Matching an exception object $e$ and stack trace $t$ against a (potentially empty) sequence of \ON{}-\CATCH{} clauses of the form
\begin{dartCode}
\ON{} $T_1$ \CATCH{} ($e_1$, $st_1$) \{ $s_1$ \}
\ldots
\ON{} $T_n$ \CATCH{} ($e_n$, $st_n$) \{ $s_n$ \}
\end{dartCode}
proceeds as follows:
\LMHash{}
If there are no \ON{}-\CATCH{} clauses ($n = 0$), matching throws the exception object $e$ and stack trace $t$ (\ref{completion}).
\LMHash{}
Otherwise the exception is matched against the first clause.
\LMHash{}
Otherwise, if the type of $e$ is a subtype of $T_1$, then the first clause matches, and then $e_1$ is bound to the exception object $e$ and $t_1$ is bound to the stack trace $t$, and $s_1$ is executed in this scope.
The matching completes in the same way as this execution.
\LMHash{}
Otherwise, if the first clause did not match $e$, $e$ and $t$ are recursively matched against the remaining \ON{}-\CATCH{} clauses:
\begin{dartCode}
\ON{} $T_2$ \CATCH{} ($e_2$, $t_2$) \{ $s_2$ \}
\ldots
\ON{} $T_n$ \CATCH{} ($e_n$, $t_n$) \{ $s_n$ \}
\end{dartCode}
\subsection{Return}
\LMLabel{return}
\LMHash{}
The {\em return statement} returns a result to the caller of a synchronous function,
completes the future associated with an asynchronous function,
or terminates the stream or iterable associated with a generator (\ref{functions}).
\begin{grammar}
<returnStatement> ::= \RETURN{} <expression>? `;'
\end{grammar}
\LMHash{}
Consider a return statement of the form \code{\RETURN{} $e$;}.
Let $T$ be the static type of $e$, let $f$ be the immediately enclosing function,
and let $S$ be the declared return type of $f$.
\LMHash{}
It is a compile-time error if the body of $f$ is marked \ASYNC{}
and the type \code{Future<\flatten{T}>} (\ref{functionExpressions}) may not be assigned to $S$.
Otherwise, it is a compile-time error if $T$ may not be assigned to $S$.
\LMHash{}
It is a compile-time error if a return statement of the form \code{\RETURN{} $e$;} appears in a generative constructor (\ref{generativeConstructors}).
\rationale{
It is quite easy to forget to add the factory prefix for a constructor, accidentally converting a factory into a generative constructor.
The static checker may detect a type mismatch in some, but not all, of these cases.
The rule above helps catch such errors, which can otherwise be very hard to recognize.
There is no real downside to it, as returning a value from a generative constructor is meaningless.
}
\LMHash{}
It is a compile-time error if a return statement of the form \code{\RETURN{} $e$;} appears in a generator function.
\rationale{
In the case of a generator function, the value returned by the function is the iterable or stream associated with it, and individual elements are added to that iterable using yield statements, and so returning a value makes no sense.
}
\LMHash{}
Let $f$ be the function immediately enclosing a return statement of the form \code{\RETURN{};}.
It is a compile-time warning if $f$ is neither a generator nor a generative constructor and either:
\begin{itemize}
%% TODO(eernst): Integrating generalized-void.md, "may not be assigned
%% to void" is useless. Update, also considering invalid_returns.md.
\item $f$ is synchronous and the return type of $f$ may not be assigned to \VOID{} (\ref{typeVoid}) or,
%% TODO(eernst): Revisit when integrating invalid_returns.md.
\item $f$ is asynchronous and the return type of $f$ may not be assigned to \code{Future<Null>}.
\end{itemize}
\commentary{
Hence, a compile-time warning will not be raised if $f$ has no declared return type,
%% TODO(eernst): Update when integrating generalized-void.md!
since the return type would be \DYNAMIC{} and \DYNAMIC{} may be assigned to \VOID{} and to \code{Future<Null>}.
However, any synchronous non-generator function that declares a return type must return an expression explicitly.
}
\rationale{
This helps catch situations where users forget to return a value in a return statement.
}
\rationale{
An asynchronous non-generator always returns a future of some sort.
If no expression is given, the future will be completed with the null object (\ref{null}) and this motivates the requirement above.
}
\commentary{
Leaving the return type of a function marked \ASYNC{} blank will be interpreted as \DYNAMIC{} as always, and cause no type error.
}
\LMHash{}
Executing a return statement \code{\RETURN{} $e$;} proceeds as follows:
\LMHash{}
First the expression $e$ is evaluated, producing an object $o$.
Let $T$ be the run-time type of $o$ and
let $S$ be the actual return type of $f$
(\ref{actualTypeOfADeclaration}).
If the body of $f$ is marked \ASYNC{} (\ref{functions})
and $T$ is a subtype of \code{Future<\flatten{S}>}
then let $r$ be the result of evaluating \code{await $v$}
where $v$ is a fresh variable bound to $o$.
Otherwise let $r$ be $o$.
Then the return statement returns the value $r$ (\ref{completion}).
%% TODO(eernst): We have some special cases with the dynamic semantics
%% specified above that we may wish to consider:
%%
%% Future<int> foo() async {
%% return new Future<Object>.value(42);
%% }
%%
%% Statically we will allow this because `Future<flatten(Future<Object>)>`,
%% i.e., `Future<Object>`, is assignable to `Future<int>`. But at run time
%% we get an error because `Future<Object>` is is not a subtype of
%% `Future<flatten(Future<int>)>` = `Future<int>`. We could have awaited
%% the value just because we're about to return a `Future`, and it would
%% then have succeeded. Are we doing the right thing? Might be fine, but
%% it seems surprising that the compiler will sometimes insert `await`,
%% and here we have to do it explicitly in order to succeed.
%%
%% Object /* or dynamic, etc. */ foo() async {
%% Object o;
%% if (someCondition) o = 42; else o = new Future<T>.value(42);
%% return o;
%% }
%%
%% Here we will interject an `await` on the returned value whenever
%% we return a future (for all `T`). This means that we will `await o`
%% in some situations and not in others. It may surprise developers
%% that we can have this dynamic variation at a location in the code
%% where there is no static justification for expecting a future.
\LMHash{}
Let $U$ be the run-time type of $r$.
\begin{itemize}
\item If the body of $f$ is marked \ASYNC{} (\ref{functions})
it is a dynamic type error if $o$ is not the null object (\ref{null}),
% TODO(lrn): Remove the next line when void is a proper supertype of all types.
$S$ is not \VOID,
and \code{Future<$U$>} is not a subtype of $S$.
\item Otherwise,
it is a dynamic type error if $r$ is not the null object (\ref{null}),
% TODO(lrn): Remove the next line when void is a proper supertype of all types.
$S$ is not \VOID{},
and $U$ is not a subtype of $S$.
\end{itemize}
\LMHash{}
Executing a return statement with no expression, \code{\RETURN;} returns with no value (\ref{completion}).
\subsection{Labels}
\LMLabel{labels}
\LMHash{}
A {\em label} is an identifier followed by a colon.
A {\em labeled statement} is a statement prefixed by a label $L$.
A {\em labeled case clause} is a case clause within a switch statement (\ref{switch}) prefixed by a label $L$.
\rationale{
The sole role of labels is to provide targets for the break (\ref{break}) and continue (\ref{continue}) statements.
}
\begin{grammar}
<label> ::= <identifier> `:'
\end{grammar}
\LMHash{}
Execution a labeled statement $s$, $label: s_l$, consists of executing $s_l$.
If execution of $s_l$ breaks to the label $label$ (\ref{completion}),
then execution of $s$ completes normally,
otherwise execution of $s$ completes in the same ways as the execution of $s_l$.
\LMHash{}
The namespace of labels is distinct from the one used for types, functions and variables.
\LMHash{}
The scope of a label that labels a statement $s$ is $s$.
The scope of a label that labels a case clause of a switch statement $s$ is $s$.
\rationale{
Labels should be avoided by programmers at all costs.
The motivation for including labels in the language is primarily making Dart a better target for code generation.
}
\subsection{Break}
\LMLabel{break}
\LMHash{}
The {\em break statement} consists of the reserved word \BREAK{} and an optional label (\ref{labels}).
\begin{grammar}
<breakStatement> ::= \BREAK{} <identifier>? `;'
\end{grammar}
\LMHash{}
Let $s_b$ be a \BREAK{} statement.
If $s_b$ is of the form \code{\BREAK{} $L$;},
then it is a compile-time error if $s_b$ is not enclosed in a labeled statement
with the label $L$ within the innermost function in which $s_b$ occurs.
If $s_b$ is of the form \code{\BREAK{};},
then it is a compile-time error if $s_b$ is not enclosed in an
\code{\AWAIT{} \FOR{}} (\ref{asynchronousFor-in}),
\DO{} (\ref{do}), \FOR{} (\ref{for}), \SWITCH{} (\ref{switch})
or \WHILE{} (\ref{while}) statement within the innermost function in which $s_b$ occurs.
\LMHash{}
Execution of a \BREAK{} statement \code{\BREAK{} $L$;} breaks to the label $L$ (\ref{completion}).
Execution of a \BREAK{} statement \code{\BREAK{};} breaks without a label (\ref{completion}).
\subsection{Continue}
\LMLabel{continue}
\LMHash{}
The {\em continue statement} consists of the reserved word \CONTINUE{} and an optional label (\ref{labels}).
\begin{grammar}
<continueStatement> ::= \CONTINUE{} <identifier>? `;'
\end{grammar}
\LMHash{}
Let $s_c$ be a \CONTINUE{} statement.
If $s_c$ is of the form \code{\CONTINUE{} $L$;},
then it is a compile-time error if $s_c$ is not enclosed in either an
\code{\AWAIT{} \FOR{}} (\ref{asynchronousFor-in}),
\DO{} (\ref{do}), \FOR{} (\ref{for}), or \WHILE{} (\ref{while})
statement labeled with $L$, or in a \SWITCH{} statement with a case clause
labeled with $L$, within the innermost function in which $s_c$ occurs.
If $s_c$ is of the form \code{\CONTINUE{};}
then it is a compile-time error if $s_c$ is not enclosed in an
\code{\AWAIT{} \FOR{}} (\ref{asynchronousFor-in})
\DO{} (\ref{do}), \FOR{} (\ref{for}), or \WHILE{} (\ref{while}) statement
within the innermost function in which $s_c$ occurs.
\LMHash{}
Execution of a \CONTINUE{} statement \code{\CONTINUE{} $L$;} continues to the label $L$ (\ref{completion}).
Execution of a \CONTINUE{} statement \code{\CONTINUE{};} continues without a label (\ref{completion}).
\subsection{Yield and Yield-Each}
\LMLabel{yieldAndYieldEach}
\subsubsection{Yield}
\LMLabel{yield}
\LMHash{}
The {\em yield statement} adds an element to the result of a generator function (\ref{functions}).
\begin{grammar}
<yieldStatement> ::= \YIELD{} <expression> `;'
\end{grammar}
\LMHash{}
Execution of a statement $s$ of the form \code{\YIELD{} $e$;} proceeds as follows:
\LMHash{}
First, the expression $e$ is evaluated to an object $o$.
If the enclosing function $m$ is marked \code{\ASYNC*} (\ref{functions}) and the stream $u$ associated with $m$ has been paused, then the nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused and execution of $m$ is suspended until $u$ is resumed or canceled.
\LMHash{}
Next, $o$ is added to the iterable or stream associated with the immediately enclosing function.
\LMHash{}
If the enclosing function $m$ is marked \code{\ASYNC*} and the stream $u$ associated with $m$ has been canceled, then the \YIELD{} statement returns without a value (\ref{completion}), otherwise it completes normally.
\rationale{
The stream associated with an asynchronous generator could be canceled by any code with a reference to that stream at any point where the generator was passivated.
Such a cancellation constitutes an irretrievable error for the generator.
At this point, the only plausible action for the generator is to clean up after itself via its \FINALLY{} clauses.
}
\LMHash{}
Otherwise, if the enclosing function $m$ is marked \code{\ASYNC*} (\ref{functions}) then the enclosing function may suspend, in which case the nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused first.
\rationale{
If a \YIELD{} occurred inside an infinite loop and the enclosing function never suspended, there might not be an opportunity for consumers of the enclosing stream to run and access the data in the stream.
The stream might then accumulate an unbounded number of elements.
Such a situation is untenable.
Therefore, we allow the enclosing function to be suspended when a new value is added to its associated stream.
However, it is not essential (and in fact, can be quite costly) to suspend the function on every \YIELD{}.
The implementation is free to decide how often to suspend the enclosing function.
The only requirement is that consumers are not blocked indefinitely.
}
\LMHash{}
If the enclosing function $m$ is marked \code{\SYNC*} (\ref{functions}) then:
\begin{itemize}
\item
Execution of the function $m$ immediately enclosing $s$ is suspended until the nullary method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$.
\item
The current call to \code{moveNext()} returns \TRUE.
\end{itemize}
\LMHash{}
It is a compile-time error if a yield statement appears in a function that is not a generator function.
\LMHash{}
Let $T$ be the static type of $e$ and let $f$ be the immediately enclosing function.
It is a compile-time error if either:
\begin{itemize}
\item
the body of $f$ is marked \code{\ASYNC*} and the type \code{Stream<T>} may not be assigned to the declared return type of $f$.
\item
the body of $f$ is marked \code{\SYNC*} and the type \code{Iterable<T>} may not be assigned to the declared return type of $f$.
\end{itemize}
\subsubsection{Yield-Each}
\LMLabel{yieldEach}
\LMHash{}
The {\em yield-each statement} adds a series of values to the result of a generator function (\ref{functions}).
\begin{grammar}
<yieldEachStatement> ::= \YIELD{} `*' <expression> `;'
\end{grammar}
\LMHash{}
Execution of a statement $s$ of the form \code{\YIELD* $e$;} proceeds as follows:
\LMHash{}
First, the expression $e$ is evaluated to an object $o$.
\LMHash{}
If the immediately enclosing function $m$ is marked \code{\SYNC*} (\ref{functions}), then:
\begin{enumerate}
\item It is a dynamic type error if the class of $o$ does not implement \code{Iterable}.
Otherwise
\item The method \code{iterator} is invoked upon $o$ returning an object $i$.
\item \label{moveNext} The \code{moveNext} method of $i$ is invoked on it with no arguments.
If \code{moveNext} returns \FALSE{} execution of $s$ is complete.
Otherwise
\item The getter \code{current} is invoked on $i$.
If the invocation throws (\ref{evaluation}), execution of $s$ throws the same exception object and stack trace (\ref{completion}).
Otherwise, the result $x$ of the getter invocation is added to the iterable associated with $m$.
Execution of the function $m$ immediately enclosing $s$ is suspended until the nullary method \code{moveNext()} is invoked upon the iterator used to initiate the current invocation of $m$, at which point execution of $s$ continues at \ref{moveNext}.
\item
The current call to \code{moveNext()} returns \TRUE.
\end{enumerate}
\LMHash{}
If $m$ is marked \code{\ASYNC*} (\ref{functions}), then:
\begin{itemize}
\item It is a dynamic type error if the class of $o$ does not implement \code{Stream}.
Otherwise
\item The nearest enclosing asynchronous for loop (\ref{asynchronousFor-in}), if any, is paused.
\item The $o$ stream is listened to, creating a subscription $s$, and for each event $x$, or error $e$ with stack trace $t$, of $s$:
\begin{itemize}
\item
If the stream $u$ associated with $m$ has been paused, then execution of $m$ is suspended until $u$ is resumed or canceled.
\item
If the stream $u$ associated with $m$ has been canceled,
then $s$ is canceled by evaluating \code{\AWAIT{} v.cancel()} where $v$ is a fresh variable referencing the stream subscription $s$.
Then, if the cancel completed normally, the stream execution of $s$ returns without a value (\ref{completion}).
\item
Otherwise, $x$, or $e$ with $t$, are added to the stream associated with $m$ in the order they appear in $o$.
The function $m$ may suspend.
\end{itemize}
\item If the stream $o$ is done, execution of $s$ completes normally.
\end{itemize}
\LMHash{}
It is a compile-time error if a yield-each statement appears in a function that is not a generator function.
\LMHash{}
Let $T$ be the static type of $e$ and let $f$ be the immediately enclosing function.
It is a compile-time error if $T$ may not be assigned to the declared return type of $f$.
If $f$ is synchronous it is a compile-time error if $T$ may not be assigned to \code{Iterable}.
If $f$ is asynchronous it is a compile-time error if $T$ may not be assigned to \code{Stream}.
\subsection{Assert}
\LMLabel{assert}
\LMHash{}
An {\em assert statement} is used to disrupt normal execution if a given boolean condition does not hold.
\begin{grammar}
<assertStatement> ::= <assertion> `;'
<assertion> ::= \ASSERT{} `(' <expression> (`,' <expression> )? `,'? `)'
\end{grammar}
\LMHash{}
The grammar allows a trailing comma before the closing parenthesis,
similarly to an argument list.
That comma, if present, has no effect.
An assertion with a trailing comma is equivalent to one with that comma removed.
\LMHash{}
An assertion of the form \code{\ASSERT($e$)} is equivalent to an assertion of the form \code{\ASSERT($e$, \NULL{})}.
\LMHash{}
Execution of an assert statement executes the assertion as described below
and completes in the same way as the assertion.
\LMHash{}
When assertions are not enabled,
execution of an assertion immediately completes normally
(\ref{completion}).
\commentary{That is, no subexpressions of the assertion are evaluated.}
When assertions are enabled,
execution of an assertion \code{\ASSERT{}($c$, $e$)} proceeds as follows:
\LMHash{}
The expression $c$ is evaluated to an object $r$.
It is a dynamic type error if $r$ is not of type \code{bool}.
\commentary{
Hence it is a compile-time error if that situation arises during evaluation of an assertion in a \CONST{} constructor invocation.
}
If $r$ is \TRUE{} then execution of the assert statement completes normally (\ref{completion}).
Otherwise, $e$ is evaluated to an object $m$
and then the execution of the assert statement throws (\ref{completion}) an \code{AssertionError} containing $m$ and with a stack trace corresponding to the current execution state at the assertion.
\LMHash{}
It is a compile-time error if the type of $c$ may not be assigned to \code{bool}.
\rationale{
Why is this a statement, not a built in function call? Because it is handled magically so it has no effect and no overhead when assertions are disabled.
Also, in the absence of final methods, one could not prevent it being overridden (though there is no real harm in that).
It cannot be viewed as a function call that is being optimized away because the arguments might have side effects.
}
%If a lexically visible declaration named \code{assert} is in scope, an assert statement
%\code{\ASSERT{} (e); }
%is interpreted as an expression statement \code{(assert(e));} .
%\rationale{
%Since \ASSERT{} is a built-in identifier, one might define a function or method with this name.
%It is impossible to distinguish as \ASSERT{} statement from a method invocation in such a situation.
%One could choose to always interpret such code as an \ASSERT{} statement. Or we could choose to give priority to any lexically visible user defined function. The former can cause rather puzzling situations, e.g.,}
%\begin{dartCode}
% assert(bool b)\{print('My Personal Assertion \$b');\}
% assert\_puzzler() \{
% (assert(\TRUE{})); // prints true
% assert(\TRUE{}); // would do nothing
% (assert(\FALSE{})); // prints false
% assert(\FALSE{}); // would throw if asserts enabled, or do nothing otherwise
% \}
%\end{dartCode}
%\rationale{therefore, we opt for the second option. Alternately, one could insist that assert be a reserved word, which may have an undesirable effect with respect to compatibility of Javascript code ported to Dart.}
\section{Libraries and Scripts}
\LMLabel{librariesAndScripts}
\LMHash{}
A Dart program consists of one or more libraries, and may be built out of one or more {\em compilation units}.
A compilation unit may be a library or a part (\ref{parts}).
\LMHash{}
A library consists of (a possibly empty) set of imports, a set of exports, and a set of top-level declarations.
A top-level declaration is either a class (\ref{classes}), a type alias declaration (\ref{typedef}), a function (\ref{functions}) or a variable declaration (\ref{variables}).
The members of a library $L$ are those top level declarations given within $L$.
\begin{grammar}
<topLevelDefinition> ::= <classDefinition>
\alt <enumType>
\alt <typeAlias>
\alt \EXTERNAL{}? <functionSignature> `;'
\alt \EXTERNAL{}? <getterSignature> `;'
\alt \EXTERNAL{}? <setterSignature> `;'
\alt <functionSignature> <functionBody>
\alt <returnType>? \GET{} <identifier> <functionBody>
\alt <returnType>? \SET{} <identifier> <formalParameterList> <functionBody>
\alt (\FINAL{} | \CONST{}) <type> <staticFinalDeclarationList> `;'
\alt <variableDeclaration> `;'
<getOrSet> ::= \GET{}
\alt \SET{}
<libraryDefinition> ::= <scriptTag>? <libraryName>? <importOrExport>* <partDirective>*
\gnewline{} <topLevelDefinition>*
<scriptTag> ::= `#!' (\~{}<NEWLINE>)* <NEWLINE>
<libraryName> ::= <metadata> \LIBRARY{} <dottedIdentifierList> `;'
<importOrExport> ::= <libraryImport>
\alt <libraryExport>
<dottedIdentifierList> ::= <identifier> (`.' <identifier>)*
\end{grammar}
\LMHash{}
Libraries may be {\em explicitly named} or {\em implicitly named}.
An explicitly named library begins with the word \LIBRARY{} (possibly prefaced with any applicable metadata annotations), followed by a qualified identifier that gives the name of the library.
\commentary{
Technically, each dot and identifier is a separate token and so spaces between them are acceptable.
However, the actual library name is the concatenation of the simple identifiers and dots and contains no spaces.
}
\LMHash{}
An implicitly named library has the empty string as its name.
\rationale{
The name of a library is used to tie it to separately compiled parts of the library (called parts) and can be used for printing and, more generally, reflection.
The name may be relevant for further language evolution.
}
\commentary{
Libraries intended for widespread use should avoid name collisions.
Dart's \code{pub} package management system provides a mechanism for doing so.
Each pub package is guaranteed a unique name, effectively enforcing a global namespace.
}
\LMHash{}
A library may optionally begin with a {\em script tag}.
Script tags are intended for use with scripts (\ref{scripts}).
A script tag can be used to identify the interpreter of the script to whatever computing environment the script is embedded in.
The script tag must appear before any whitespace or comments.
A script tag begins with \syntax{`#!'} and ends at the end of the line.
Any characters that follow \syntax{`#!'} in the script tag are ignored by the Dart implementation.
\LMHash{}
Libraries are units of privacy.
A private declaration declared within a library $L$ can only be accessed by code within $L$.
Any attempt to access a private member declaration from outside $L$ will cause a method, getter or setter lookup failure.
\commentary{
Since top level privates are not imported, using the top level privates of another library is never possible.
}
\LMHash{}
The {\em public namespace} of library $L$ is the mapping that maps the simple name of each public top-level member $m$ of $L$ to $m$.
The scope of a library $L$ consists of the names introduced by all top-level declarations declared in $L$, and the names added by $L$'s imports (\ref{imports}).
\subsection{Imports}
\LMLabel{imports}
\LMHash{}
An {\em import} specifies a library to be used in the scope of another library.
\begin{grammar}
<libraryImport> ::= <metadata> <importSpecification>
<importSpecification> ::= \IMPORT{} <configurableUri> (\AS{} <identifier>)? <combinator>* `;'
\alt \IMPORT{} <uri> \DEFERRED{} \AS{} <identifier> <combinator>* `;'
<combinator> ::= \SHOW{} <identifierList>
\alt \HIDE{} <identifierList>
<identifierList> ::= <identifier> (, <identifier>)*
\end{grammar}
\LMHash{}
An import specifies a URI $x$ where the declaration of an imported library is to be found.
\LMHash{}
Imports may be {\em deferred} or {\em immediate}.
A deferred import is distinguished by the appearance of the built-in identifier \DEFERRED{} after the URI.
Any import that is not deferred is immediate.
\LMHash{}
It is a compile-time error if the specified URI of an immediate import does not refer to a library declaration.
The interpretation of URIs is described in section \ref{uris} below.
\LMHash{}
It is a compile-time error if the specified URI of a deferred import does not refer to a library declaration.
\rationale{
One cannot detect the problem at compile time because compilation often occurs during execution and one does not know what the URI refers to.
However the development environment should detect the problem.
}
\LMHash{}
The {\em current library} is the library currently being compiled.
The import modifies the namespace of the current library in a manner that is determined by the imported library and by the optional elements of the import.
\LMHash{}
An immediate import directive $I$ may optionally include a prefix clause of the form \code{\AS{} \id} used to prefix names imported by $I$.
A deferred import must include a prefix clause or a compile-time error occurs.
It is a compile-time error if a prefix used in a deferred import is used in another import clause.
\LMHash{}
An import directive $I$ may optionally include a namespace combinator clauses used to restrict the set of names imported by $I$.
Currently, two namespace combinators are supported: \HIDE{} and \SHOW{}.
\LMHash{}
Let $I$ be an import directive that refers to a URI via the string $s_1$.
Evaluation of $I$ proceeds as follows:
\LMHash{}
If $I$ is a deferred import, no evaluation takes place.
Instead, a mapping of the name of the prefix, $p$ to a {\em deferred prefix object} is added to the scope of the current library $L$.
The deferred prefix object has the following methods:
\begin{itemize}
\item \code{loadLibrary}.
This method returns a future $f$.
When called, the method causes an immediate import $I'$ to be executed at some future time, where $I'$ is derived from $I$ by eliding the word \DEFERRED{} and adding a \HIDE{} \code{loadLibrary} combinator clause.
When $I'$ executes without error, $f$ completes successfully.
If $I'$ executes without error, we say that the call to \code{loadLibrary} has succeeded, otherwise we say the call has failed.
\item For every top level function $f$ named \id{} in the imported library $B$, a corresponding method named \id{} with the same signature as $f$.
Calling the method results in a run-time error.
\item For every top level getter $g$ named \id{} in $B$, a corresponding getter named \id{} with the same signature as $g$.
Calling the method results in a run-time error.
\item For every top level setter $s$ named \id{} in $B$, a corresponding setter named \id{} with the same signature as $s$.
Calling the method results in a run-time error.
\item For every type $T$ named \id{} in $B$, a corresponding getter named \id{} with return type \code{Type}.
Calling the method results in a run-time error.
\end{itemize}
\rationale{
The purpose of adding members of $B$ to $p$ is to ensure that any errors raised when using $p$ are correct, and no spurious errors are generated.
In fact, at run time we cannot add these members until $B$ is loaded; but any such invocations will fail at run time as specified by virtue of being completely absent.
}
%But this is still a lie detectable by reflection. Probably revise so the type of p has these members but p does not.
The static type of the prefix object $p$ is a unique interface type that has those members whose names and signatures are listed above.
\LMHash{}
After a call succeeds, the name $p$ is mapped to a non-deferred prefix object as described below.
In addition, the prefix object also supports the \code{loadLibrary} method, and so it is possible to call \code{loadLibrary} again.
If a call fails, nothing happens, and one again has the option to call \code{loadLibrary} again.
Whether a repeated call to \code{loadLibrary} succeeds will vary as described below.
\LMHash{}
The effect of a repeated call to \code{$p$.loadLibrary} is as follows:
\begin{itemize}
\item
If another call to \code{$p$.loadLibrary} has already succeeded, the repeated call also succeeds.
Otherwise,
\item
If another call to \code{$p$.loadLibrary} has failed:
\begin{itemize}
\item
If the failure is due to a compilation error, the repeated call fails for the same reason.
\item
If the failure is due to other causes, the repeated call behaves as if no previous call had been made.
\end{itemize}
\end{itemize}
\commentary{
In other words, one can retry a deferred load after a network failure or because a file is absent, but once one finds some content and loads it, one can no longer reload.
We do not specify what value the future returned resolves to.
}
\LMHash{}
If $I$ is an immediate import then, first
\begin{itemize}
\item
If the URI that is the value of $s_1$ has not yet been accessed by an import or export (\ref{exports}) directive in the current isolate then the contents of the URI are compiled to yield a library $B$.
\commentary{
Because libraries may have mutually recursive imports, care must be taken to avoid an infinite regress.
}
\item Otherwise, the contents of the URI denoted by $s_1$ have been compiled into a library $B$ within the current isolate.
\end{itemize}
\LMHash{}
Let $NS_0$ be the exported namespace (\ref{exports}) of $B$.
Then, for each combinator clause $C_i, i \in 1 .. n$ in $I$:
\begin{itemize}
\item If $C_i$ is of the form
\code{\SHOW{} $\id_1, \ldots,\ \id_k$}
then let $NS_i = \SHOW{}([\id_1, \ldots,\ \id_k], NS_{i-1}$)
where $show(l,n)$ takes a list of identifiers $l$ and a namespace $n$, and produces a namespace that maps each name in $l$ to the same element that $n$ does.
Furthermore, for each name $x$ in $l$, if $n$ defines the name \code{$x$=} then the new namespace maps \code{$x$=} to the same element that $n$ does.
Otherwise the resulting mapping is undefined.
\item If $C_i$ is of the form
\code{\HIDE{} $\id_1, \ldots,\ \id_k$}
then let $NS_i = \HIDE{}([\id_1, \ldots,\ \id_k], NS_{i-1}$)
where $hide(l, n)$ takes a list of identifiers $l$ and a namespace $n$, and produces a namespace that is identical to $n$ except that for each name $k$ in $l$, $k$ and \code{$k$=} are undefined.
\end{itemize}
\LMHash{}
Next, if $I$ includes a prefix clause of the form \AS{} $p$, let $NS = NS_n \cup \{p: prefixObject(NS_n)\}$ where $prefixObject(NS_n)$ is a {\em prefix object} for the namespace $NS_n$, which is an object that has the following members:
\begin{itemize}
\item For every top level function $f$ named \id{} in $NS_n$, a corresponding method with the same name and signature as $f$ that forwards (\ref{functionDeclarations}) to $f$.
\item For every top level getter with the same name and signature as $g$ named \id{} in $NS_n$, a corresponding getter that forwards to $g$.
\item For every top level setter $s$ with the same name and signature as named \id{} in $NS_n$, a corresponding setter that forwards to $s$.
\item For every type $T$ named \id{} in $NS_n$, a corresponding getter named \id{} with return type \code{Type}, that, when invoked, returns the type object for $T$.
\end{itemize}
\LMHash{}
Otherwise, let $NS = NS_n$.
It is a compile-time error if the current library declares a top-level member named $p$.
The static type of the prefix object $p$ is a unique interface type that has those members whose names and signatures are listed above.
% What is the static type of a prefix object. Need to state that is a(n anonymous) type that has members with the same names as signatures as above.
% This is problematic, because it implies that p.T would be available even in a scope that declared p. We really need to think of p as a single object with properties p.T etc., except it isn't really that
% either. After all, p isn't actually available as a stand alone name.
\LMHash{}
Then, for each entry mapping key $k$ to declaration $d$ in $NS$, $d$ is made available in the top level scope of $L$ under the name $k$ unless either:
\begin{itemize}
\item
a top-level declaration with the name $k$ exists in $L$, OR
\item a prefix clause of the form \AS{} $k$ is used in $L$.
\end{itemize}
\rationale{
The greatly increases the chance that a member can be added to a library without breaking its importers.
}
\LMHash{}
A {\em system library} is a library that is part of the Dart implementation.
Any other library is a {\em non-system library}.
If a name $N$ is referenced by a library $L$
and $N$ would be introduced into the top level scope of $L$
by imports of two libraries, $L_1$ and $L_2$,
the exported namespace of $L_1$ binds $N$
to a declaration originating in a system library,
and the exported namespace of $L_2$ binds $N$ to a declaration
that does not originate in a system library,
then the import of $L_1$ is implicitly extended by a \code{\HIDE{} $N$} clause.
\rationale{
Whereas normal conflicts are resolved at deployment time, the functionality of \code{dart:} libraries is injected into an application at run time, and may vary over time as browsers are upgraded.
Thus, conflicts with \code{dart:} libraries can arise at run time, outside the developer's control.
To avoid breaking deployed applications in this way, conflicts with the \code{dart:} libraries are treated specially.
It is recommended that tools that deploy Dart code produce output in which all imports use show clauses to ensure that additions to the namespace of a library never impact deployed code.
}
\LMHash{}
If a name $N$ is referenced by a library $L$ and $N$ is introduced into the top level scope of $L$ by more than one import
and not all the imports denote the same declaration,
a compile-time error occurs.
\LMHash{}
We say that the namespace $NS$ {\em has been imported into} $L$.
\commentary{
It is not an error if $N$ is introduced by two or more imports but never referred to.
}
\rationale{
The policy above makes libraries more robust in the face of additions made to their imports.
A clear distinction needs to be made between this approach, and seemingly similar policies with respect to classes or interfaces.
The use of a class or interface, and of its members, is separate from its declaration.
The usage and declaration may occur in widely separated places in the code, and may in fact be authored by different people or organizations.
It is important that errors are given at the offending declaration so that the party that receives the error can respond to it a meaningful way.
In contrast a library comprises both imports and their usage; the library is under the control of a single party and so any problem stemming from the import can be resolved even if it is reported at the use site.
%On a related note, the provenance of the conflicting elements is not considered. An element that is imported via distinct paths may conflict with itself. This avoids variants of the well known "diamond" problem.
}
\LMHash{}
It is a compile-time warning to import two different libraries with the same name unless their name is the empty string.
\commentary{
A widely disseminated library should be given a name that will not conflict with other such libraries.
The preferred mechanism for this is using pub, the Dart package manager, which provides a global namespace for libraries, and conventions that leverage that namespace.
}
\commentary{
Note that no errors are raised if one hides or shows a name that is not in a namespace.
}
\rationale{
This prevents situations where removing a name from a library would cause breakage of a client library.
}
\LMHash{}
The dart core library \code{dart:core} is implicitly imported into every dart library other than itself via an import clause of the form
\code{\IMPORT{} `dart:core';}
unless the importing library explicitly imports \code{dart:core}.
\commentary{
Any import of \code{dart:core}, even if restricted via \SHOW{}, \HIDE{} or \AS{}, preempts the automatic import.
}
\rationale{
It would be nice if there was nothing special about \code{dart:core}.
However, its use is pervasive, which leads to the decision to import it automatically.
However, some library $L$ may wish to define entities with names used by \code{dart:core} (which it can easily do, as the names declared by a library take precedence).
Other libraries may wish to use $L$ and may want to use members of $L$ that conflict with the core library without having to use a prefix and without encountering errors.
The above rule makes this possible, essentially canceling \code{dart:core}'s special treatment by means of yet another special rule.
}
\subsection{Exports}
\LMLabel{exports}
\LMHash{}
A library $L$ exports a namespace (\ref{scoping}), meaning that the declarations in the namespace are made available to other libraries if they choose to import $L$ (\ref{imports}).
The namespace that $L$ exports is known as its {\em exported namespace}.
\begin{grammar}
<libraryExport> ::= <metadata> \EXPORT{} <configurableUri> <combinator>* `;'
\end{grammar}
\LMHash{}
An export specifies a URI $x$ where the declaration of an exported library is to be found.
It is a compile-time error if the specified URI does not refer to a library declaration.
\LMHash{}
We say that a name {\em is exported by a library} (or equivalently, that a library {\em exports a name}) if the name is in the library's exported namespace.
We say that a declaration {\em is exported by a library} (or equivalently, that a library {\em exports a declaration}) if the declaration is in the library's exported namespace.
\LMHash{}
A library always exports all names and all declarations in its public namespace.
In addition, a library may choose to re-export additional libraries via {\em export directives}, often referred to simply as {\em exports}.
\LMHash{}
Let $E$ be an export directive that refers to a URI via the string $s_1$.
Evaluation of $E$ proceeds as follows:
\LMHash{}
First,
\begin{itemize}
\item
If the URI that is the value of $s_1$ has not yet been accessed by an import or export directive in the current isolate then the contents of the URI are compiled to yield a library $B$.
\item Otherwise, the contents of the URI denoted by $s_1$ have been compiled into a library $B$ within the current isolate.
\end{itemize}
\LMHash{}
Let $NS_0$ be the exported namespace of $B$.
Then, for each combinator clause $C_i, i \in 1 .. n$ in $E$:
\begin{itemize}
\item If $C_i$ is of the form \code{\SHOW{} $\id_1, \ldots,\ \id_k$} then let
$NS_i = \SHOW{}([\id_1, \ldots,\ \id_k], NS_{i-1}$).
\item If $C_i$ is of the form \code{\HIDE{} $\id_1, \ldots,\ \id_k$}
then let $NS_i = \HIDE{}([\id_1, \ldots,\ \id_k], NS_{i-1}$).
\end{itemize}
\LMHash{}
For each
entry mapping key $k$ to declaration $d$ in $NS_n$ an entry mapping $k$ to $d$ is added to the exported namespace of $L$ unless a top-level declaration with the name $k$ exists in $L$.
\LMHash{}
If a name $N$ is not declared by a library $L$
and $N$ would be introduced into the exported namespace of $L$
by exports of two libraries, $L_1$ and $L_2$,
the exported namespace of $L_1$ binds $N$ to a declaration originating in a system library,
and the exported namespace of $L_2$ binds $N$ to a declaration
that does not originate in a system library,
then the export of $L_1$ is implicitly extended by a \code{\HIDE{} $N$} clause.
\rationale{
See the discussion in section \ref{imports} for the reasoning behind this rule.
}
\LMHash{}
We say that $L$ {\em re-exports library } $B$, and also that $L$ {\em re-exports namespace } $NS_n$.
When no confusion can arise, we may simply state that $L$ {\em re-exports }$B$, or that $L$ {\em re-exports }$NS_n$.
\LMHash{}
It is a compile-time error if a name $N$ is re-exported by a library $L$ and $N$ is introduced into the export namespace of $L$ by more than one export, unless all exports refer to same declaration for the name $N$.
It is a compile-time error to export two different libraries with the same name unless their name is the empty string.
\subsection{Parts}
\LMLabel{parts}
\LMHash{}
A library may be divided into {\em parts}, each of which can be stored in a separate location.
A library identifies its parts by listing them via \PART{} directives.
\LMHash{}
A {\em part directive} specifies a URI where a Dart compilation unit that should be incorporated into the current library may be found.
\begin{grammar}
<partDirective> ::= <metadata> \PART{} <uri> `;'
<partHeader> ::= <metadata> \PART{} \OF{} <identifier> (`.' <identifier>)* `;'
<partDeclaration> ::= <partHeader> <topLevelDefinition>* <EOF>
\end{grammar}
\LMHash{}
A {\em part header} begins with \PART{} \OF{} followed by the name of the library the part belongs to.
A part declaration consists of a part header followed by a sequence of top-level declarations.
\LMHash{}
Compiling a part directive of the form \code{\PART{} $s$;} causes the Dart system to attempt to compile the contents of the URI that is the value of $s$.
The top-level declarations at that URI are then compiled by the Dart compiler in the scope of the current library.
It is a compile-time error if the contents of the URI are not a valid part declaration.
It is a compile-time error if the referenced part declaration $p$ names a library other than the current library as the library to which $p$ belongs.
\LMHash{}
It is a compile-time error if a library contains
two part directives with the same URI.
\LMHash{}
We say that a library $L_1$ is {\em reachable from} a library $L$ if
any of the following is true (\ref{imports}, \ref{exports}):
\begin{itemize}
\item $L$ and $L_1$ is the same library.
\item $L$ imports or exports a library $L_2$, and $L_1$ is reachable from $L_2$.
\end{itemize}
\LMHash{}
Let $L$ be a library, let $u$ be a URI,
and let $L_1$ and $L_2$ be distinct libraries which are reachable from $L$.
It is a compile-time error if $L_1$ and $L_2$ both contain
a part directive with URI $u$.
\commentary{
In particular, it is an error to use the same part twice in the same program
(\ref{scripts}).
Note that a relative URI is interpreted as relative to the location of the
enclosing library (\ref{uris}), which means that $L_1$ and $L_2$ may both
have a part identified by \code{'myPart.dart'}, but they are not the same
URI unless $L_1$ and $L_2$ have the same location.
}
\subsection{Scripts}
\LMLabel{scripts}
\LMHash{}
A {\em script} is a library whose exported namespace (\ref{exports}) includes
a top-level function declaration named \code{main}
that has either zero, one or two required arguments.
A script $S$ is executed as follows:
\LMHash{}
First, $S$ is compiled as a library as specified above.
Then, the top-level function defined by \code{main}
in the exported namespace of $S$ is invoked (\ref{functionInvocation})
as follows:
If \code{main} can be be called with with two positional arguments,
it is invoked with the following two actual arguments:
\begin{enumerate}
\item An object whose run-time type implements \code{List<String>}.
\item An object specified when the current isolate $i$ was created,
for example through the invocation of \code{Isolate.spawnUri} that spawned $i$,
or the null object (\ref{null}) if no such object was supplied.
\end{enumerate}
If \code{main} cannot be called with two positional arguments,
but it can be called with one positional argument,
it is invoked with an object whose run-time type implements \code{List<String>}
as the only argument.
If \code{main} cannot be called with one or two positional arguments,
it is invoked with no arguments.
\commentary{
Note that if \code{main} requires more than two positional arguments,
the library is not considered a script.
}
\commentary{
A Dart program will typically be executed by executing a script.
}
\LMHash{}
It is a compile-time error if a library's export scope contains a declaration
named \code{main}, and the library is not a script.
\commentary{This restriction ensures that all top-level \code{main} declarations
introduce a script main-function, so there cannot be a top-level getter or field
named \code{main}, nor can it be a function that requires more than two
arguments. The restriction allows tools to fail early on invalid \code{main}
methods, without needing to know whether a library will be used as the entry
point of a Dart program. It is possible that this restriction will be removed
in the future.}
\subsection{URIs}
\LMLabel{uris}
\LMHash{}
URIs are specified by means of string literals:
\begin{grammar}
<uri> ::= <stringLiteral>
<configurableUri> ::= <uri> <configurationUri>*
<configurationUri> ::= \IF{} `(' <uriTest> `)' <uri>
<uriTest> ::= <dottedIdentifierList> (`==' <stringLiteral>)?
\end{grammar}
\LMHash{}
It is a compile-time error if the string literal $x$ that describes a URI contains a string interpolation.
\LMHash{}
It is a compile-time error if the string literal $x$ that is used in a {\em uriTest} is not a constant expression, or if $x$ involves string interpolation.
\LMHash{} A {\em configurable URI} $c$ of the form \code{\metavar{uri} $\metavar{configurationUri}_1$ \ldots $\metavar{configurationUri}_n$} {\em specifies a URI} as follows:
\begin{itemize}
\item{} Let $u$ be \metavar{uri}.
\item{} For each of the following configuration URIs of the form \code{\IF{} ($\metavar{test}_i$) $\metavar{uri}_i$}, in source order, do the following.
\begin{itemize}
\item{} If $\metavar{test}_i$ is \code{\metavar{ids}} with no \code{==} clause, it is
equivalent to \code{\metavar{ids} == "true"}.
\item{} If $\metavar{test}_i$ is \code{\metavar{ids} == \metavar{string}},
then create a string, \metavar{key}, from \metavar{ids}
by concatenating the identfiers and dots,
omitting any spaces between them that may occur in the source.
\item{} Look up \metavar{key} in the available compilation {\em environment}.
\commentary{
The compilation environment is provided by the platform.
It maps some string keys to string values,
and can be accessed programmatically using the
\code{const String.fromEnvironment} constructor.
Tools may choose to only make some parts of the compilation environment
available for choosing configuration URIs.
}
\item{} If the environment contains an entry for \metavar{key} and the
associated value is equal, as a constant string value, to the value of
the string literal \metavar{string},
then let $u$ be $\metavar{uri}_i$ and stop iterating the configuration URIs.
\item{} Otherwise proceed to the next configuration URI.
\end{itemize}
\item{} The URI specified by $c$ is $u$.
\end{itemize}
\LMHash{}
This specification does not discuss the interpretation of URIs, with the following exceptions.
\rationale{
The interpretation of URIs is mostly left to the surrounding computing environment.
For example, if Dart is running in a web browser, that browser will likely interpret some URIs.
While it might seem attractive to specify, say, that URIs are interpreted with respect to a standard such as IETF RFC 3986, in practice this will usually depend on the browser and cannot be relied upon.
}
\LMHash{}
A URI of the form \code{dart:$s$} is interpreted as a reference to a system library (\ref{imports}) $s$.
\LMHash{}
A URI of the form \code{package:$s$} is interpreted in an implementation specific manner.
\rationale{
The intent is that, during development, Dart programmers can rely on a package manager to find elements of their program.
}
\LMHash{}
Otherwise, any relative URI is interpreted as relative to the location of the current library.
All further interpretation of URIs is implementation dependent.
\commentary{
This means it is dependent on the embedder.
}
\section{Types}
\LMLabel{types}
\LMHash{}
Dart supports optional typing based on interface types.
\rationale{
The type system is unsound, due to the covariance of generic classes.
This is a deliberate choice (and undoubtedly controversial).
Experience has shown that sound type rules for generics fly in the face of programmer intuition.
It is easy for tools to provide a sound type analysis if they choose, which may be useful for tasks like refactoring.
}
\subsection{Static Types}
\LMLabel{staticTypes}
\LMHash{}
Type annotations are used in variable declarations (\ref{variables}) (including formal parameters (\ref{formalParameters})), in the return types of functions (\ref{functions}) and in the bounds of type variables.
Type annotations are used during static checking and when running programs.
\begin{grammar}
<type> ::= <typeName> <typeArguments>?
<typeName> ::= <qualified>
<typeArguments> ::= `<' <typeList> `>'
<typeList> ::= <type> (`,' <type>)*
\end{grammar}
\LMHash{}
A Dart implementation must provide a static checker that detects and reports exactly those situations this specification identifies as compile-time errors,
and only those situations.
However:
\begin{itemize}
\item Running the static checker on a program $P$ is not required for compiling and running $P$.
\item Running the static checker on a program $P$ must not prevent successful compilation of $P$ nor may it prevent the execution of $P$, regardless of whether any compile-time errors occur.
\end{itemize}
\commentary{
Nothing precludes additional tools that implement alternative static analyses (e.g., interpreting the existing type annotations in a sound manner such as either non-variant generics, or inferring declaration based variance from the actual declarations).
However, using these tools must not preclude successful compilation and execution of Dart code.
}
\LMHash{}
A type $T$ is {\em malformed} if{}f:
\begin{itemize}
\item
$T$ has the form \id{} or the form \code{\metavar{prefix}.\id},
and in the enclosing lexical scope,
the name \id{} (respectively \code{\metavar{prefix}.\id}) does not denote a type.
\item
$T$ denotes a type variable in the enclosing lexical scope,
but occurs in the signature or body of a static member.
\item $T$ is a parameterized type of the form \code{$G$<$S_1, \ldots,\ S_n$>},
and $G$ is malformed,
or $G$ is not a generic type,
or $G$ is a generic type, but it declares $n'$ type parameters and $n' \not= n$,
or $S_j$ is malformed for some $j \in 1 .. n$.
\item $T$ is a function type of the form
\code{$T_0$ \FUNCTION{}<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>}
\code{\quad($T_1\ x_1, \ldots,\ T_k\ x_k,\ $[$T_{k+1}\ x_{k+1}, \ldots,\ T_n\ x_n$])}
\noindent
or of the form
\code{$T_0$ \FUNCTION{}<$X_1\ \EXTENDS\ B_1, \ldots,\ X_m\ \EXTENDS\ B_m$>}
\code{\quad($T_1\ x_1, \ldots,\ T_k\ x_k,\ $\{$T_{k+1}\ x_{k+1}, \ldots,\ T_n\ x_n$\})}
\noindent
where each $x_j$ which is not a named parameter may be omitted,
and $T_j$ is malformed for some $j \in 0 .. n$,
or $B_j$ is malformed for some $j \in 1 .. m$.
\item
$T$ denotes declarations that were imported from multiple imports clauses.
\end{itemize}
\LMHash{}
Any use of a malformed type gives rise to a compile-time error.
A malformed type is then interpreted as \DYNAMIC{} by the static type checker unless explicitly specified otherwise.
\rationale{
This ensures that the developer is spared a series of cascading errors as the malformed type interacts with other types.
}
\LMHash{}
A type $T$ is {\em deferred} if{}f it is of the form $p.T$ where $p$ is a deferred prefix.
It is a compile-time error to use a deferred type in a type annotation, type test, type cast or as a type parameter.
However, all other compile-time errors must be issued under the assumption that all deferred libraries have successfully been loaded.
% Now, when passed to a generic, p.T also has to be treated as dynamic - otherwise we have to fail immediately. Where do we say that? And how does this fit with idea that as a type object it fails? Should we say that the accessor on p returns dynamic instead of failing? Do we distinguish its use in a constructor vs its use in an annotation? It's not that we evaluate type objects in constructor args - these cannot represent parameterized types.
\subsubsection{Type Promotion}
\LMLabel{typePromotion}
\LMHash{}
The static type system ascribes a static type to every expression.
In some cases, the type of a local variable (\commentary{which can be a formal parameter})
may be promoted from the declared type, based on control flow.
\LMHash{}
We say that a variable $v$ is known to have type $T$ whenever we allow the type of $v$ to be promoted.
The exact circumstances when type promotion is allowed are given in the relevant sections of the specification (\ref{logicalBooleanExpressions}, \ref{conditional} and \ref{if}).
\LMHash{}
Type promotion for a variable $v$ is allowed only when we can deduce that such promotion is valid based on an analysis of certain boolean expressions.
In such cases, we say that the boolean expression $b$ shows that $v$ has type $T$.
As a rule, for all variables $v$ and types $T$, a boolean expression does not show that $v$ has type $T$.
Those situations where an expression does show that a variable has a type are mentioned explicitly in the relevant sections of this specification (\ref{typeTest} and \ref{logicalBooleanExpressions}).
\subsection{Dynamic Type System}
\LMLabel{dynamicTypeSystem}
% \ref{classes} says that 'when a class name appears as a type,%
% that name denotes the interface of the class. So we can say
% that the dynamic type of an instance is a non-generic class or
% a generic instantiation of a generic class.
\LMHash{}
Let $o$ be an instance.
The {\em dynamic type} of $o$ is the class which is specified
for the situation where $o$ was obtained as a fresh instance
(\ref{redirectingFactoryConstructors},
\ref{lists}, \ref{maps}, \ref{new}, \ref{functionInvocation}).
\commentary{
In particular, the dynamic type of an instance never changes.
It is at times only specified that the given class implements
a certain type, e.g., for a list literal.
In these cases the dynamic type is implementation dependent,
except of course that said subtype requirement must be satisfied.
}
\LMHash{}
The dynamic types of a running Dart program are equivalent to
the static types with regard to subtyping.
\commentary{
Certain dynamic type checks are performed during execution
(\ref{variables},
\ref{redirectingGenerativeConstructors},
\ref{executionOfInitializerLists},
\ref{factories},
\ref{redirectingFactoryConstructors},
\ref{lists},
\ref{new},
\ref{bindingActualsToFormals},
\ref{ordinaryInvocation},
\ref{assignment},
\ref{typeCast},
\ref{localVariableDeclaration},
\ref{asynchronousFor-in},
\ref{return},
\ref{yieldEach},
\ref{assert}).
As specified in those locations,
these dynamic checks are based on the dynamic types of instances,
and the actual types of declarations
(\ref{actualTypeOfADeclaration}).
}
\LMHash{}
When types are reified as instances of the built-in class \code{Type},
those objects override the \code{==} operator
inherited from the \code{Object} class, so that
two \code{Type} objects are equal according to operator \syntax{`=='}
if{}f the corresponding types are subtypes of each other.
\commentary{
For example, the \code{Type} objects for the types
\DYNAMIC{} and \code{Object} are equal to each other
and hence \code{dynamic\,==\,Object} must evaluate to \TRUE.
No constraints are imposed on the built-in function \code{identical},
so \code{identical(dynamic, Object)} may be \TRUE{} or \FALSE.
Similarly, \code{Type} instances for distinct type alias declarations
declaring a name for the same function type are equal:
}
\begin{dartCode}
\TYPEDEF{} F = void Function<X>(X);
\TYPEDEF{} G = void Function<Y>(Y);
\\
\VOID{} main() \{
assert(F == G);
\}
\end{dartCode}
\subsection{Type Declarations}
\LMLabel{typeDeclarations}
\subsubsection{Typedef}
\LMLabel{typedef}
\LMHash{}
A {\em type alias} declares a name for a type expression.
\begin{grammar}
<typeAlias> ::= <metadata> \TYPEDEF{} <typeAliasBody>
<typeAliasBody> ::= <functionTypeAlias>
<functionTypeAlias> ::= <functionPrefix> <typeParameters>? <formalParameterList> `;'
<functionPrefix> ::= <returnType>? <identifier>
\end{grammar}
% TODO(eernst): Introduce new type aliases and new function type syntax, then
% include support for generic functions here.
\LMHash{}
The effect of a type alias of the form
\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ [T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}]$)}
\noindent
declared in a library $L$ is to introduce the name \id{} into the scope of $L$, bound to the function type
$(T_1, \ldots,\ T_n, [T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k} p_{n+k}]) \rightarrow T$.
The effect of a type alias of the form
\code{\TYPEDEF{} $T$ \id($T_1\ p_1, \ldots,\ T_n\ p_n,\ \{T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}\}$)}
\noindent
declared in a library $L$ is to introduce the name \id{} into the scope of $L$, bound to the function type
$(T_1, \ldots,\ T_n, \{T_{n+1}\ p_{n+1}, \ldots,\ T_{n+k}\ p_{n+k}\}) \rightarrow T$.
In either case, if{}f no return type is specified, it is taken to be \DYNAMIC{}.
Likewise, if a type annotation is omitted on a formal parameter, it is taken to be \DYNAMIC{}.
\LMHash{}
It is a compile-time error if any default values are specified in the signature of a function type alias.
%A typedef may only refer to itself via the bounds of its generic parameters.
Any self reference in a typedef, either directly, or recursively via another typedef, is a compile-time error.
%via a chain of references that does not include a class declaration.
\subsection{Interface Types}
\LMLabel{interfaceTypes}
\LMHash{}
The implicit interface of class $I$ is a direct supertype of the implicit interface of class $J$ if{}f:
\begin{itemize}
\item $I$ is \code{Object}, and $J$ has no \EXTENDS{} clause.
\item $I$ is listed in the \EXTENDS{} clause of $J$.
\item $I$ is listed in the \IMPLEMENTS{} clause of $J$.
\item $I$ is listed in the \WITH{} clause of $J$.
\item $J$ is a mixin application (\ref{mixinApplication}) of the mixin of $I$.
\end{itemize}
\LMHash{}
A type $T$ is more specific than a type $S$, written $T << S$, if one of the following conditions is met:
\begin{itemize}
\item $T$ is $S$.
\item $T$ is $\bot$.
\item $T$ is \code{Null} and $S$ is not $\bot$.
\item $S$ is \DYNAMIC{}.
\item $S$ is a direct supertype of $T$.
\item $T$ is a type parameter and $S$ is the upper bound of $T$.
\item $T$ is a type parameter and $S$ is \code{Object}.
\item $T$ is of the form \code{$I$<$T_1, \ldots,\ T_n$>} and $S$ is of the form \code{$I$<$S_1, \ldots,\ S_n$>} and:
$T_i << S_i, 1 \le i \le n$
\item $T$ and $S$ are both function types, and $T << S$ under the rules of section \ref{functionTypes}.
\item $T$ is a function type and $S$ is \FUNCTION{}.
\item $T << U$ and $U << S$.
\end{itemize}
\LMHash{}
$<<$ is a partial order on types.
$T$ is a subtype of $S$, written $T <: S$, if{}f $[\bot/\DYNAMIC{}]T << S$.
\rationale{
Note that $<:$ is not a partial order on types, it is only binary relation on types.
This is because $<:$ is not transitive.
If it was, the subtype rule would have a cycle.
For example:
\code{List $<:$ List<String>} and
\code{List<int> $<:$ List}, but
\code{List<int>} is not a subtype of \code{List<String>}.
Although $<:$ is not a partial order on types, it does contain a partial order, namely $<<$.
This means that, barring raw types, intuition about classical subtype rules does apply.
}
\commentary{
The \code{Null} type is more specific than all non-$\bot$ types, even though
it doesn't actually extend or implement those types.
The other types are effectively treated as if they are {\em nullable},
which makes the null object (\ref{null}) assignable to them.
}
\LMHash{}
$S$ is a supertype of $T$, written $S :> T$, if{}f $T$ is a subtype of $S$.
\commentary{
The supertypes of an interface are its direct supertypes and their supertypes.
}
\LMHash{}
An interface type $T$ may be assigned to a type $S$, written $T \Longleftrightarrow S$, if{}f either $T <: S$, $S <: T$.
\rationale{
This rule may surprise readers accustomed to conventional typechecking.
The intent of the $\Longleftrightarrow$ relation is not to ensure that an assignment is correct.
Instead, it aims to only flag assignments that are almost certain to be erroneous, without precluding assignments that may work.
For example, assigning a value of static type Object to a variable with static type String, while not guaranteed to be correct, might be fine if the run-time value happens to be a string.
}
\subsection{Function Types}
\LMLabel{functionTypes}
\LMHash{}
Function types come in two variants:
\begin{enumerate}
\item
The types of functions that only have positional parameters.
These have the general form
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_n,\ $[$T_{n+1}, \ldots,\ T_{n+k}$]) $ \rightarrow T$}.
\item
The types of functions with named parameters.
These have the general form
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_n,\ $\{$T_{x_1}\ x_1, \ldots,\ T_{x_k}\ x_k$\}) $ \rightarrow T$}.
\end{enumerate}
\commentary{
Note that the non-generic case is covered by using $s = 0$,
in which case the type parameter declarations are omitted (\ref{generics}).
}
\LMHash{}
Two function types are considered equal if consistent renaming of type
parameters can make them identical.
\commentary{
A common way to say this is that we do not distinguish function types which are alpha-equivalent.
For the subtyping rule below this means we can assume that a suitable renaming has already taken place.
In cases where this is not possible
because the number of type parameters in the two types differ or the bounds are different,
no subtype relationship exists.
}
\LMHash{}
%A function type $(T_1, \ldots, T_n, [T_{n+1} , \ldots, T_{n+k}]) \rightarrow T$ is a subtype of the
% the line below revises the rule to be more liberal
The function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_{k},\ $[$T_{k+1}, \ldots,\ T_{n+m}$]) $ \rightarrow T$}
\noindent
is a subtype of the function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($S_1, \ldots,\ S_{k+j},\ $[$S_{k+j+1}, \ldots,\ S_{n}$]) $ \rightarrow S$},
\noindent
if all of the following conditions are met,
assuming that $X_j$ is a subtype of $B_j$, for all $j \in 1 .. s$:
\begin{enumerate}
\item Either
\begin{itemize}
\item $S$ is \VOID{}, Or
\item $T \Longleftrightarrow S$.
\end{itemize}
\item $\forall i \in 1 .. n, T_i \Longleftrightarrow S_i$.
\end{enumerate}
\LMHash{}
A function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_n,\ $\{$T_{x_1}\ x_1, \ldots,\ T_{x_k}\ x_k$\}) $ \rightarrow T$}
\noindent
is a subtype of the function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($S_1, \ldots,\ S_n,\ $\{$S_{y_1}\ y_1, \ldots,\ S_{y_m}\ y_m$\}) $ \rightarrow S$},
\noindent
if all of the following conditions are met,
assuming that $X_j$ is a subtype of $B_j$, for all $j \in 1 .. s$:
\begin{enumerate}
\item Either
\begin{itemize}
\item $S$ is \VOID{}, Or
\item $T \Longleftrightarrow S$.
\end{itemize}
\item $\forall i \in 1 .. n, T_i \Longleftrightarrow S_i$.
\item $k \ge m$ and $y_i \in \{x_1, \ldots, x_k\}, i \in 1 .. m$.
%\{x_1, \ldots, x_k\}$ is a superset of $\{y_1, \ldots, y_m\}$.
\item For all $y_i \in \{y_1, \ldots, y_m\}, y_i = x_j \Rightarrow T_{x_j} \Longleftrightarrow S_{y_i}$
\end{enumerate}
%In addition, a function type $(T_1, \ldots, Tn, [T_{n+1} x_{n+1}, \ldots, T_{n+k} x_{n+k}]) \rightarrow T$ is a subtype of the function type $(T_1, \ldots, T_n, T_{n+1} , [T_{n+2} x_{n+2}, \ldots, T_{n+k} x_{n+k}]) \rightarrow T$.
%\rationale{This second rule is attractive to web developers, who are used to this sort of flexibility from Javascript. However, it may be costly to implement efficiently.}
%We write $(T_1, \ldots, T_n) \rightarrow T$ as a shorthand for the type $(T_1, \ldots, T_n, []) \rightarrow T$.
%The rules above need to be sanity checked, but the intent is that we view functions with rest parameters as having type $(T_1, ..., T_n, [\_{Tn+1}[] \_]) \rightarrow T$, where \_ is some magical identifier. Then the rules above may cover everything.
% This is wrong - from the outside, the type takes an unbounded sequence of types, not a list. This can be modeled as $(T_1, \ldots, T_n, [T_{n+1}, \_, \ldots, T_{n+k} \_]) \rightarrow T$ for some finite $k$.
\LMHash{}
In addition, the following subtype rules apply:
% NOTE(eernst): In Dart 1 we do not have transitivity of subtyping so we
% cannot use a rule about the empty list/set of optional parameters ('[]'
% or '{}') as an "intermediate step" in a subtype judgment. We keep them
% for now because they will be useful in Dart 2.
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_n,\ $[]) $ \rightarrow T \quad<:$}
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_n$)\ $\rightarrow T$}.
\vspace{2mm}
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_n,\ $\{\}) $ \rightarrow T \quad<:$}
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_n$)\ $\rightarrow T$}.
\vspace{2mm}
% NOTE(eernst): I think this rule is useless. We cannot use it (along with
% other rules) to prove (T1) -> S <: (T1, []) -> S <: (T1, [T2]) -> S,
% because it should not be provable (and it isn't) that we can accept two
% arguments statically, but at runtime we only accept one argument; similarly,
% we cannot prove (T1) -> S <: (T1, []) -> S <: ([T1]) -> S, because we
% would then allow invocation with no arguments where the run-time
% requirement is exactly one argument. So I believe that this rule is
% simply useless (it's not dangerous, it just doesn't allow us to prove
% anything). Hence, I'm commenting it out now.
%
% $(T_1, \ldots, T_n) \rightarrow T <: (T_1, \ldots, T_n, []) \rightarrow T$.
%
% Same for this rule:
%
% $(T_1, \ldots, T_n) \rightarrow T <: (T_1, \ldots, T_n, \{\}) \rightarrow T$.
\rationale{
The naive reader might conclude that, since it is not legal to declare a function with an empty optional parameter list, these rules are pointless.
However, they induce useful relationships between function types that declare no optional parameters and those that do.
}
\LMHash{}
A function type $T$ may be assigned to a function type $S$, written $T \Longleftrightarrow S$, if{}f $T <: S$.
\LMHash{}
A function is always an instance of some class that implements the class \FUNCTION{}.
All function types are subtypes of \FUNCTION{}.
%\commentary{Need to specify how a function values dynamic type is derived from its static signature.}
\LMHash{}
A function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_{k},\ $[$T_{k+1}, \ldots,\ T_{n+m}$]) $ \rightarrow T$}
\noindent
is more specific than the function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($S_1, \ldots,\ S_{k+j},\ $[$S_{k+j+1}, \ldots,\ S_{n}$]) $ \rightarrow S$},
\noindent
if all of the following conditions are met:
\begin{enumerate}
\item Either
\begin{itemize}
\item $S$ is \VOID{}, Or
\item $T << S$.
\end{itemize}
\item $\forall i \in 1 .. n, T_i << S_i$.
\end{enumerate}
\LMHash{}
A function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($T_1, \ldots,\ T_n,\ $\{$T_{x_1}\ x_1, \ldots,\ T_{x_k}\ x_k$\}) $ \rightarrow T$}
\noindent
is more specific than the function type
\code{<$X_1\ \EXTENDS\ B_1, \ldots,\ X_s\ \EXTENDS\ B_s$>}
\code{($S_1, \ldots,\ S_n,\ $\{$S_{y_1}\ y_1, \ldots,\ S_{y_m}\ y_m$\}) $ \rightarrow S$},
\noindent
if all of the following conditions are met:
\begin{enumerate}
\item Either
\begin{itemize}
\item $S$ is \VOID{}, Or
\item $T << S$.
\end{itemize}
\item $\forall i \in 1 .. n, T_i << S_i$.
\item $k \ge m$ and $y_i \in \{x_1, \ldots, x_k\}, i \in 1 .. m$.
%\{x_1, \ldots, x_k\}$ is a superset of $\{y_1, \ldots, y_m\}$.
\item For all $y_i \in \{y_1, \ldots, y_m\}, y_i = x_j \Rightarrow T_j << S_i$
\end{enumerate}
\LMHash{}
Furthermore, if $F$ is a function type, $F << \FUNCTION{}$.
\subsection{Type \DYNAMIC{}}
\LMLabel{typeDynamic}
\LMHash{}
The type \DYNAMIC{} is a static type which is a supertype of all other types,
just like \code{Object},
but it it differs from other types in that the static analysis
assumes that every member access has a corresponding member
with a signature that admits the given access.
\commentary{
For instance,
when the receiver in an ordinary method invocation has type \DYNAMIC{},
any method name can be invoked,
with any number of type arguments or none,
with any number of positional arguments,
and any set of named arguments,
of any type,
without error.
Note that the invocation will still cause a compile-time error
if one or more arguments or other subterms has an error.
}
\LMHash{}
% Inference is assumed to have taken place, so the type was not inferred.
If no static type annotation has been provided,
the type system considers declarations to have type \DYNAMIC{}.
%% TODO(eernst): Change when adding specification of instantiate-to-bound.
If a generic type is used but type arguments are not provided,
the type arguments default to type \DYNAMIC{}.
\commentary{
%% TODO(eernst): Amend when adding specification of instantiate-to-bound.
This means that given a generic declaration
\code{$G$<$P_1, \ldots,\ P_n$>$\ldots$},
where $P_i$ is a formal type parameter declaration, $i \in 1 .. n$,
the type $G$ is equivalent to
\code{$G$<$\DYNAMIC{}, \ldots,\ \DYNAMIC{}$>}.
}
\LMHash{}
The built-in type declaration \code{dynamic},
which is declared in the library \code{dart:core},
denotes the \DYNAMIC{} type.
When the name \DYNAMIC{} exported by \code{dart:core} is evaluated as an expression,
it evaluates to a \code{Type} object representing the \DYNAMIC{} type,
even though \DYNAMIC{} is not a class.
\commentary{
This \code{Type} object must compare equal to the corresponding \code{Type}
objects for \code{Object} and \VOID{}
(\ref{dynamicTypeSystem}).
}
\subsection{Type FutureOr}
\LMLabel{typeFutureOr}
%% TODO(eernst): We should make this a separate section, or change the title of this section.
\LMHash{}
The built-in type declaration \code{FutureOr},
which is declared in the library \code{dart:async},
defines a generic type with one type parameter (\ref{generics}).
\LMHash{}
The \code{FutureOr<$T$>} type is a non-class type with the following
type relations:
\begin{itemize}
\item{} $T$ <: \code{FutureOr<$T$>}.
\item{} \code{Future<$T$>} <: \code{FutureOr<$T$>}.
\item{} If $T$ <: $S$ and \code{Future<$T$>} <: $S$
then \code{FutureOr<$T$>} <: $S$.
\commentary{In particular, \code{FutureOr<$T$>} <: \code{Object}.}
\end{itemize}.
\commentary{
The last point guarantees that generic type \code{FutureOr} is
{\em covariant} in its type parameter, just like class types.
That is, if $S$ <: $T$ then \code{FutureOr<$S$>} <: \code{FutureOr<$T$>}.
}
\LMHash{}
If the type arguments passed to \code{FutureOr} would incur compile-time errors
if applied to a normal generic class with one type parameter,
the same compile-time errors are issued for \code{FutureOr}.
The name \code{FutureOr} as an expression
denotes a \code{Type} object representing the type \code{FutureOr<dynamic>}.
\rationale{
The \code{FutureOr<\metavar{type}>} type represents a case where a value can be
either an instance of the type \metavar{type}
or the type \code{Future<\metavar{type}>}.
Such cases occur naturally in asynchronous code.
Using \code{FutureOr} instead of \DYNAMIC{} allows some tools
to provide a more precise type analysis.
}
\LMHash{}
The type \code{FutureOr<$T$>} has an interface that is identical to that
of \code{Object}.
\commentary{
The only members that can be invoked on a value with static type
\code{FutureOr<$T$>} are members that are also on \code{Object}.
}
\rationale{
We only want to allow invocations of members that are inherited from
a common supertype of both $T$ and \code{Future<$T$>}.
In most cases the only common supertype is \code{Object}. The exceptions, like
\code{FutureOr<Future<Object\gtgt} which has \code{Future<Object>} as common
supertype, are few and not practically useful, so for now we choose to
only allow invocations of members inherited from \code{Object}.
}
\subsection{Type Void}
\LMLabel{typeVoid}
%% TODO(eernst): Adjust everything in this section when specifying generalized-void.
\LMHash{}
The special type \VOID{} may only be used as the return type of a function: it is a compile-time error to use \VOID{} in any other context.
\commentary{
For example, as a type argument, or as the type of a variable or parameter
Void is not an interface type.
The only subtype relations that pertain to void are therefore:
\begin{itemize}
\item[$\bullet$]
$\VOID{} <: \VOID{}$ (by reflexivity)
\item[$\bullet$]
$\bot <: \VOID{}$ (as bottom is a subtype of all types).
\item[$\bullet$]
$\VOID{} <: \DYNAMIC{}$ (as \DYNAMIC{} is a supertype of all types)
\end{itemize}
The analogous rules also hold for the $<<$ relation for similar reasons.
Hence, the static checker will issue errors if one attempts to access a member of the result of a void method invocation (even for members of the null object (\ref{null}), such as \code{==}).
Likewise, passing the result of a void method as a parameter or assigning it to a variable will raise an error unless the variable/formal parameter has type dynamic.
On the other hand, it is possible to return the result of a void method from within a void method.
One can also return the null object (\ref{null}); or a value of type \DYNAMIC{}.
Returning any other result will cause a compile-time error.
%% TODO(eernst): Correct this when integrating generalized-void.md.
A dynamic type error would arise if a non-null object was returned from a void method (since no object has run-time type \DYNAMIC{}).
}
\commentary{
The name \VOID{} does not denote a \code{Type} object.
}
\rationale{
It is syntacticly illegal to use \VOID{} as an expression, and it would make no sense to do so.
Type objects reify the run-time types of instances.
No instance ever has type \VOID{}.
}
\subsection{Parameterized Types}
\LMLabel{parameterizedTypes}
% TODO(eernst): We may want to add a new concept for the application of a
% generic function to actual type arguments (maybe it's an extra kind of
% 'parameterized type', but it differs from the generic class case because
% we _can_ have dynamic invocations of a generic function). But this does
% not arise as a stand-alone entity before we introduce generic tear-offs
% (\code{var f = foo<int>;}), or if we allow it to arise implicitly based
% on inference. That new concept should probably be added to this section.
\LMHash{}
A \emph{parameterized type} is a syntactic construct where the name of a generic type declaration is applied to a list of actual type arguments.
A \emph{generic instantiation} is the operation where a generic type is applied to actual type arguments.
\commentary{
So a parameterized type is the syntactic concept that corresponds to the semantic concept of a generic instantiation.
When using the former, we will often leave the latter implicit.
}
\LMHash{}
Let $T$ be a parameterized type \code{$G$<$S_1, \ldots,\ S_n$>}.
\LMHash{}
It is a compile-time error if $G$ is not a generic type,
or $G$ is a generic type, but the number of formal type parameters in the declaration of $G$ is not $n$.
Otherwise, let
$X_1, \ldots, X_n$
be the formal type parameters of $G$, and let
$B_1, \ldots, B_n$
be the corresponding upper bounds, using \DYNAMIC{} when no bound is declared.
\LMHash{}
$T$ is {\em malbounded} if{}f either
$S_i$ is malbounded for one or more $i \in 1 .. n$,
or $T$ is not well-bounded (\ref{superBoundedTypes}).
\LMHash{}
It is a compile-time error if $T$ is malbounded.
\LMHash{}
$T$ is evaluated as follows.
Let $t_i$ be the result of evaluating $S_i$, for $i \in 1 .. n$.
$T$ then evaluates to the generic instantiation where $G$ is applied to $t_1, \ldots, t_n$.
\LMHash{}
Let $T$ be a parameterized type of the form
\code{$G$<$A_1, \ldots,\ A_n$>}
and assume that $T$ is not malformed and not malbounded.
If $S$ is the static type of a member $m$ of $G$,
then the static type of the member $m$ of an expression of type
\code{$G$<$A_1, \ldots,\ A_n$>}
is
$[A_1/X_1, \ldots, A_n/X_n]S$,
where $X_1, \ldots, X_n$ are the formal type parameters of $G$.
%% TODO(eernst): This is the location where we can specify that each of the type arguments
%% of the receiver type \code{$G$<$A_1, \ldots,\ A_n$>} must be replaced by the bottom type
%% (`Null`, for now) in locations of the member type where it occurs contravariantly. For
%% instance, `c.f` should have static type `void Function(Null)` when `c` has static type
%% `C<T>` for any `T`, and we have `class C<X> { void Function(X) f; }`.
\subsubsection{Actual Type of Declaration}
\LMLabel{actualTypeOfADeclaration}
% NOTE(eernst): The actual type arguments in this section are dynamic entities,
% not syntax (the concept of an 'actual type' and an 'actual bound' is used to
% specify the dynamic semantics, including dynamic errors). So we use $t_i$
% to denote these type arguments, just like all those locations where the
% concept is used, rather than $A_i$ which is frequently used to denote the
% syntax of an actual type argument.
%
% The point is that $t_i$ will never contain a formal type parameter, so we
% need not worry about the need to iterate in the substitution that finds an
% actual bound. For instance, there is no problem determining the actual bound
% for \code{X} in an invocation of \code{void foo<X extends C<X>>() \{...\}}
% even if it is a recursive invocation on the form \code{foo<C<X>>()} in the
% body.
\LMHash{}
Let $T$ be the declared type of a declaration $d$,
as it appears in the program source.
Let $X_1, \ldots, X_n$ be the formal type parameters in scope at $d$.
In a context where the actual type arguments corresponding to
$X_1, \ldots, X_n$
are
$t_1, \ldots, t_n$,
the {\em actual type} of $d$ is
$[t_1/X_1, \ldots, t_n/X_n]T$.
\commentary{
In the non-generic case where $n = 0$ the actual type is equal to the declared type.
Note that
$X_1, \ldots, X_n$
may be declared by multiple entities, e.g.,
one or more enclosing generic functions and an enclosing generic class.
}
\LMHash{}
Let \code{$X$ \EXTENDS{} $B$} be a formal type parameter declaration.
Let
$X_1, \ldots, X_n$
be the formal type parameters in scope at the declaration of $X$.
In a context where the actual type arguments corresponding to
$X_1, \ldots, X_n$
are
$t_1, \ldots, t_n$,
the {\em actual bound} for $X$ is
$[t_1/X_1, \ldots, t_n/X_n]B$.
\commentary{
Note that there exists a $j$ such that $X = X_j$,
because each formal type parameter is in scope at its own declaration.
}
\subsubsection{Least Upper Bounds}
\LMLabel{leastUpperBounds}
% TODO(eernst): This section has been updated to take generic functions
% into account, but no other changes have been performed. Hence, we still
% need to update this section to use Dart 2 rules for LUB.
\LMHash{}
% does this diverge in some cases?
Given two interfaces $I$ and $J$,
let $S_I$ be the set of superinterfaces of $I$,
let $S_J$ be the set of superinterfaces of $J$
and let $S = (\{I\} \cup S_I) \cap (\{J\} \cup S_J)$.
Furthermore,
we define $S_n = \{T | T \in S \wedge depth(T) = n\}$ for any finite $n$
where $depth(T)$ is the number of steps in the longest inheritance path
from $T$ to \code{Object}.
%TODO(lrn): Specify that "inheritance path" is a path in the superinterface graph.
Let $q$ be the largest number such that $S_q$ has cardinality one,
which must exist because $S_0$ is $\{\code{Object}\}$.
The least upper bound of $I$ and $J$ is the sole element of $S_q$.
\LMHash{}
The least upper bound of \DYNAMIC{} and any type $T$ is \DYNAMIC{}.
The least upper bound of \VOID{} and any type $T \ne \DYNAMIC{}$ is \VOID{}.
The least upper bound of $\bot$ and any type $T$ is $T$.
Let $U$ be a type variable with upper bound $B$.
The least upper bound of $U$ and a type $T \ne \bot$ is the least upper bound of $B$ and $T$.
\LMHash{}
The least upper bound operation is commutative and idempotent,
but it is not associative.
% Function types
\LMHash{}
The least upper bound of a function type and an interface type $T$ is the least upper bound of \FUNCTION{} and $T$.
Let $F$ and $G$ be function types.
If $F$ and $G$ differ in their number of required parameters,
then the least upper bound of $F$ and $G$ is \FUNCTION{}.
Otherwise:
\begin{itemize}
\item If
\code{$F = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_r,\ $[$T_{r+1}, \ldots,\ T_n$]) $ \rightarrow T_0$} and
\code{$G = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($S_1, \ldots,\ S_r,\ $[$S_{r+1}, \ldots,\ S_k$]) $ \rightarrow S_0$}
\noindent
where $k \le n$ then the least upper bound of $F$ and $G$ is
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($L_1, \ldots,\ L_r,\ $[$L_{r+1}, \ldots,\ L_k$]) $ \rightarrow L_0$}
\noindent
where $L_i$ is the least upper bound of $T_i$ and $S_i, i \in 0 .. k$.
\item If
\code{$F = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_r,\ $[$T_{r+1}, \ldots,\ T_n$]) $ \rightarrow T_0$},
\code{$G = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($S_1, \ldots,\ S_r,\ $\{ \ldots{} \}) $ \rightarrow S_0$}
\noindent
then the least upper bound of $F$ and $G$ is
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($L_1, \ldots,\ L_r$) $ \rightarrow L_0$}
\noindent
where $L_i$ is the least upper bound of $T_i$ and $S_i, i \in 0 .. r$.
\item If
\code{$F = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($T_1, \ldots,\ T_r,\ $\{$T_{r+1}\ p_{r+1}, \ldots,\ T_f\ p_f$\}) $ \rightarrow T_0$},
\code{$G = $ <$X_1\ B_1, \ldots,\ X_s\ B_s$>($S_1, \ldots,\ S_r,\ $\{$S_{r+1}\ q_{r+1}, \ldots,\ S_g\ q_g$\}) $ \rightarrow S_0$}
then let
$\{x_m, \ldots, x_n\} = \{p_{r+1}, \ldots, p_f\} \cap \{q_{r+1}, \ldots, q_g\}$
and let $X_j$ be the least upper bound of the types of $x_j$ in $F$ and
$G, j \in m .. n$.
Then the least upper bound of $F$ and $G$ is
\code{<$X_1\ B_1, \ldots,\ X_s\ B_s$>($L_1, \ldots,\ L_r,\ $\{$X_m\ x_m, \ldots,\ X_n\ x_n$\}) $ \rightarrow L_0$}
where $L_i$ is the least upper bound of $T_i$ and $S_i, i \in 0 .. r$
\end{itemize}
\commentary{
Note that the non-generic case is covered by using $s = 0$,
in which case the type parameter declarations are omitted (\ref{generics}).
}
\section{Reference}
\LMLabel{reference}
\subsection{Lexical Rules}
\LMLabel{lexicalRules}
\LMHash{}
Dart source text is represented as a sequence of Unicode code points.
This sequence is first converted into a sequence of tokens according to the lexical rules given in this specification.
At any point in the tokenization process, the longest possible token is recognized.
\subsubsection{Reserved Words}
\LMLabel{reservedWords}
\LMHash{}
A {\em reserved word} may not be used as an identifier; it is a compile-time error if a reserved word is used where an identifier is expected.
\ASSERT{}, \BREAK{}, \CASE{}, \CATCH{}, \CLASS{}, \CONST{}, \CONTINUE{}, \DEFAULT{}, \DO{}, \ELSE{}, \ENUM{}, \EXTENDS{}, \FALSE{}, \FINAL{}, \FINALLY{}, \FOR{}, \IF{}, \IN{}, \IS{}, \NEW{}, \NULL{}, \RETHROW, \RETURN{}, \SUPER{}, \SWITCH{}, \THIS{}, \THROW{}, \TRUE{}, \TRY{}, \VAR{}, \VOID{}, \WHILE{}, \WITH{}.
\begin{grammar}
<LETTER> ::= `a' .. `z'
\alt `A' .. `Z'
<DIGIT> ::= `0' .. `9'
<WHITESPACE> ::= (`\\t' | ` ' | <NEWLINE>)+
\end{grammar}
\subsubsection{Comments}
\LMLabel{comments}
\LMHash{}
{\em Comments} are sections of program text that are used for documentation.
\begin{grammar}
<SINGLE\_LINE\_COMMENT> ::= `//' \~{}(<NEWLINE>)* (<NEWLINE>)?
<MULTI\_LINE\_COMMENT> ::= `/*' (<MULTI\_LINE\_COMMENT> | \~{} `*/')* `*/'
\end{grammar}
\LMHash{}
Dart supports both single-line and multi-line comments.
A {\em single line comment} begins with the token \code{//}.
Everything between \code{//} and the end of line must be ignored by the Dart compiler unless the comment is a documentation comment.
\LMHash{}
A {\em multi-line comment} begins with the token \code{/*} and ends with the token \code{*/}.
Everything between \code{/}* and \code{*}/ must be ignored by the Dart compiler unless the comment is a documentation comment.
Comments may nest.
\LMHash{}
{\em Documentation comments} are comments that begin with the tokens \code{///} or \code{/**}.
Documentation comments are intended to be processed by a tool that produces human readable documentation.
\LMHash{}
The scope of a documentation comment immediately preceding the declaration of a class $C$ is the instance scope of $C$.
\LMHash{}
The scope of a documentation comment immediately preceding the declaration of a function $f$ is the scope in force at the very beginning of the body of $f$.
\subsection{Operator Precedence}
\LMLabel{operatorPrecedence}
\LMHash{}
Operator precedence is given implicitly by the grammar.
\commentary{
The following non-normative table may be helpful
\newline
\begin{tabular}{| r | r | r | r |}
\hline
Description & Operator & Associativity & Precedence \\
\hline
Unary postfix & \code{$e$.}, \code{$e$?.}, \code{$e$++}, \code{$e$-{}-}, \code{$e1$[$e2$]},
\code{$e$()} & None & 16 \\
\hline
Unary prefix & \code{-$e$}, \code{!$e$}, \code{\~{}$e$}, \code{++$e$}, \code{-{}-$e$}, \code{\AWAIT{} $e$} & None & 15\\
\hline
Multiplicative & \code{*}, \code{/}, \code{\~{}/}, \code{\%} & Left & 14\\
\hline
Additive & \code{+}, \code{-} & Left & 13\\
\hline
Shift & \code{\ltlt}, \code{\gtgt}, \code{\gtgtgt} & Left & 12\\
\hline
Bitwise AND & \code{\&} & Left & 11\\
\hline
Bitwise XOR & \code{\^{}} & Left & 10\\
\hline
Bitwise Or & \code{|} & Left & 9\\
\hline
Relational & \code{<}, \code{>}, \code{<=}, \code{>=}, \AS{}, \IS{}, \code{\IS{}!} & None & 8\\
\hline
Equality & \code{==}, \code{!=} & None & 7\\
\hline
Logical AND & \code{\&\&} & Left & 6\\
\hline
Logical Or & \code{||} & Left & 5\\
\hline
If-null & \code{??} & Left & 4\\
\hline
Conditional & \code{$e1$\,?\,$e2$\,:\,$e3$} & Right & 3\\
\hline
Cascade & \code{..} & Left & 2\\
\hline
Assignment & \code{=}, \code{*=}, \code{/=}, \code{+=}, \code{-=}, \code{\&=}, \code{\^{}=}, etc. & Right & 1\\
\hline
\end{tabular}
}
\section*{Appendix: Integer Implementations}
\LMLabel{integerImplementations}
\commentary{
The \code{int} type represents integers.
The specification is written with 64-bit two's complement integers as the
intended implementation, but when Dart is compiled to JavaScript,
the implementation of \code{int} will instead use the JavaScript
number type.
This introduces a number of differencs:
\begin{itemize}
\item[$\bullet$]
Valid values of JavaScript \code{int} are any
IEEE-754 64-bit floating point number with no fractional part.
This includes positive and negative {\em infinity},
which can be reached by overflowing
(integer division by zero is still not allowed).
Otherwise valid integer literals (including any leading minus sign)
that represent invalid JavaScript \code{int} values
cannot be compiled to JavaScript.
Operations on integers may lose precision since 64-bit floating point numbers
are limited to 53 significant bits.
\item[$\bullet$]
JavaScript \code{int} instances also implement \code{double},
and integer-valued \code{double} instances also implement \code{int}.
The \code{int} and \code{double} class are still separate subclasses of the
class \code{num}, but {\em instances} of either class that represent an integer,
act as if they are actually instances of a common subclass implementing both
\code{int} and \code{double}. Fractional numbers only implement \code{double}.
\item[$\bullet$]
Bitwise operations on integers (and, or, xor, negate and shifts)
all truncate the operands to 32-bit values.
\item[$\bullet$]
The \code{identical} method cannot distinguish the values $0.0$ and $-0.0$,
and it cannot recognize any {\em NaN} value as identical to itself.
For efficiency, the \code{identical} operation uses the JavaScript \code{===}
operator.
\end{itemize}
}
\end{document}
[Text after \end{document} is ignored, hence we do not need "%"]
----------------------------------------------------------------------
* On Location Markers
This is a description of location markers, giving some information
about the underlying motivation and rationale, the actual
implementation, and the relevant tool support.
** What is a Location Marker?
In order to support more fine-grained update propagation from this
language specification to artifacts that depend on it, location
markers have been added. The idea is that each logical unit (section,
subsection, etc) and each paragraph containing normative text should
be addressable using these markers, such that source code (compilers
and other tools, tests, etc.) can contain location markers, and the
corresponding location in the spec may be looked up using standard
document viewer search features.
An SHA1 hash value of the text is associated with each location
marker, such that changes in the text will incur changes in this hash
value. Consequently, source code in tools/tests that depend on
specific parts of the spec may be flagged for revision by checking
whether these hash values have changed: If a given test T depends on
a paragraph with hash value V in the spec, and the search for V fails
in a new version of the spec, then that paragraph has changed and T
should be revisited and possible revised.
As a result, the search for parts of source code and similar artifacts
in likely need of updates because of spec changes can be performed
mechanically, which should help ensure that the conformance of all
artifacts depending on this spec is maintained more easily, and hence
more consistently. Note that it makes no difference whether the need
for an update has arisen in a very recent version of the spec or it
has existed for a long time, because the hash value just remains
different as long as the text is different from what it was when the
location marker was harvested from the spec.
** LaTeX Commands Supporting Location Markers
Concretely, this is based on the commands \LMHash and \LMLabel.
\LMHash{V} is used to add the text V in the margin, intended to mark
a paragraph of normative text with the SHA1 hash value of the text, V.
\LMLabel{L} has the effect of \label{L}, and moreover it shows the
text sec:L in the margin. In order to indicate a dependency on a
section or subsection an \LMLabel location marker is used, and in
order to indicate a dependency on a specific paragraph, the hash value
of that paragraph is used.
In this file, each normative paragraph has had the command \LMHash{}
added at the beginning, such that each of these paragraphs can be
decorated with their hash value. Similarly, all \section{}s,
\subsection{}s, \subsubsection{}s, and \paragraph{}s have had
their \label commands changed to \LMLabel, such that they are
decorated with logical names.
** Rationale
The design of location markers was proposed by Erik Ernst and
developed through discussions with several others, in particular Gilad
Bracha and Lars Bak. Some discussions along the way that gave rise to
the given design are outlined below.
The basic idea is that a hash value based on the actual text will
serve well to identify a piece of text, because it will change
whenever the text changes, and it remains the same if the text is
moved to a different location; in other words, it characterizes the
text itself, independently of the rest of the document. Hence:
- references to specific paragraphs in the spec are easy to create:
copy the marker and paste it into the source code (but see below
why this uses an extra indirection as far as possible)
- such references would be robust in the sense that they depend on
the actual text alone, i.e., they would not be invalidated by
updates to section numbers, relocation of the paragraph, or
updates to text in different paragraphs; as Lars mentioned, we
should use a "stripped" version of the text, removing comments,
normalizing white space, etc., which would make the refs even more
robust in case of "inessential" changes
- artifacts depending on a given part of the spec that was
changed could easily be pointed out: After an update to a
part of the spec, that artifact would hold a marker associated
with a hash value which does not any more occur in the spec,
maintainers of the artifact would then receive a notification
("test1773 depends on a part of the spec that was updated").
Nice tool support would show them the paragraph in the most recent
version of the spec as well as the old version that the artifact
used to depend on, and a comparison of the two would help
clarifying what needs fixing because of this change, if anything.
However, there is a conflict in this scenario: Lars pointed out that
it is very inconvenient to have to create a lot of revision control
commits (e.g., new versions of tests), just because a large number of
artifacts depend on a specific hash value that changed, if that change
has no real impact on each of those artifacts. The obvious solution
to this problem would be to use symbolic names and keep the actual
hash values out of the primary artifacts.
This approach has been used for \section{}s, \subsection{}s, etc., by
using their labels as location markers. For instance, dependency on
\subsubsection{New} would be marked as a dependency on 'sec:new',
which will (most likely) exist with the same label in the spec for a
long time. To detect a need for updates, the hash value associated
with \subsubsection{New} from the date of the latest check of this
kind to the dependent artifact should be compared with the current
hash value for the same \subsubsection{}: The artifact should be
revisited iff those hash values differ. As an easy approximation to
this scheme, the hash values for all location markers would be
computed for each spec update, and the location markers that have new
hash values should cause revisits to all artifacts depending on that
location marker.
The symbolic location markers on larger units like \section{}
etc. enable location marking in a hierarchical fashion: Dependencies
on a \subsubsection{} or on a \section{} can be chosen according to
the actual needs with each dependent artifact. In general, fine
granularity helps avoiding false positives, where an update somewhere
in a large unit will flag too many dependent artifacts for revisits.
In contrast, coarse granularity enables other artifacts to declare the
actual dependencies when small units would be impractical because the
artifact depends on so many of them. But there is a problem at the
bottom of this hierarchy, namely with paragraphs.
It would be very inconvenient to have to invent a logical name for
every paragraph. Similarly, using a simple paragraph numbering would
be unstable (add one new paragraph in the beginning of a section, and
all the rest have new numbers, creating a massive flood of false
update alerts, or, even worse, corrupting the declared dependencies in
artifacts because they point to the wrong paragraphs).
Hence, paragraphs have no other label than their actual hash value.
Artifacts that depend on very specific elements in the spec may
declare so by using an actual hash value for a given paragraph, and in
return they pay in terms of potential updates to the marker when that
paragraph changes, even in cases where the actual change makes no
difference for that particular artifact. This choice of granularity
vs. stability is up to the creator of each artifact.
** Maintenance of this document
The invariant that each normative paragraph is associated with a line
containing the text \LMHash{} should be maintained. Extra occurrences
of \LMHash{} can be added if needed, e.g., in order to make
individual \item{}s in itemized lists addressable. Each \LM.. command
must occur on a separate line. \LMHash{} must occur immediately
before the associated paragraph, and \LMLabel must occur immediately
after the associated \section{}, \subsection{} etc.
----------------------------------------------------------------------