From 1277f1812c8a24bf2d70e389290ee43b4d2b007d Mon Sep 17 00:00:00 2001 From: sgrekhov Date: Thu, 3 Apr 2025 11:45:23 +0300 Subject: [PATCH 1/7] #3128. Initial commit --- Tools/spec_coverage/README.md | 5 + Tools/spec_coverage/bin/main.dart | 42 + Tools/spec_coverage/config/config.json | 4 + Tools/spec_coverage/lib/co19.dart | 68 + Tools/spec_coverage/lib/config.dart | 8 + Tools/spec_coverage/lib/spec.dart | 37 + Tools/spec_coverage/lib/spec_parser.dart | 61 + Tools/spec_coverage/pubspec.yaml | 9 + .../spec_coverage/resources/dartLangSpec.tex | 23691 ++++++++++++++++ Tools/spec_coverage/resources/readme.txt | 5 + Tools/spec_coverage/resources/spec.txt | 22007 ++++++++++++++ 11 files changed, 45937 insertions(+) create mode 100644 Tools/spec_coverage/README.md create mode 100644 Tools/spec_coverage/bin/main.dart create mode 100644 Tools/spec_coverage/config/config.json create mode 100644 Tools/spec_coverage/lib/co19.dart create mode 100644 Tools/spec_coverage/lib/config.dart create mode 100644 Tools/spec_coverage/lib/spec.dart create mode 100644 Tools/spec_coverage/lib/spec_parser.dart create mode 100644 Tools/spec_coverage/pubspec.yaml create mode 100644 Tools/spec_coverage/resources/dartLangSpec.tex create mode 100644 Tools/spec_coverage/resources/readme.txt create mode 100644 Tools/spec_coverage/resources/spec.txt diff --git a/Tools/spec_coverage/README.md b/Tools/spec_coverage/README.md new file mode 100644 index 0000000000..7ca260f853 --- /dev/null +++ b/Tools/spec_coverage/README.md @@ -0,0 +1,5 @@ +Command-line application that shows Dart specification coverage by co19 tests. + +Usage: +`$ cd Tools/spec_coverage` +`$ dart bin/main.dart` diff --git a/Tools/spec_coverage/bin/main.dart b/Tools/spec_coverage/bin/main.dart new file mode 100644 index 0000000000..cfd36c89bc --- /dev/null +++ b/Tools/spec_coverage/bin/main.dart @@ -0,0 +1,42 @@ +import 'dart:convert' show jsonDecode; +import 'dart:io'; +import 'package:spec_coverage/co19.dart'; +import 'package:spec_coverage/config.dart'; +import 'package:spec_coverage/spec.dart'; + +main(List args) { + Config config = Config.fromJson(readConfig()); + Spec spec = Spec.fromTxt(config.specPath); + Co19 co19 = Co19(config.co19Dir); + findSpecChapters(co19.language.subDirs, spec.chapters); +} + +void findSpecChapters(List testDirs, List chapters) { + for (TestDir td in testDirs) { + bool found = false; + for(Chapter ch in chapters) { + if (td.name.toLowerCase() == ch.co19DirName.toLowerCase()) { + print("Found spec for ${td.path}"); + findSpecChapters(td.subDirs, ch.subChapters); + found = true; + break; + } + } + if (!found) { + print("Not found spec for ${td.path}. Chapters are:"); + for (Chapter ch in chapters) { + print(ch.co19DirName); + } + } + } +} + +Map readConfig() { + final configFile = File('config/config.json'); + if (configFile.existsSync()) { + final contents = configFile.readAsStringSync(); + return jsonDecode(contents); + } else { + throw Exception('Config file ${configFile.path} not found'); + } +} diff --git a/Tools/spec_coverage/config/config.json b/Tools/spec_coverage/config/config.json new file mode 100644 index 0000000000..68248e31ba --- /dev/null +++ b/Tools/spec_coverage/config/config.json @@ -0,0 +1,4 @@ +{ + "specPath": "resources/spec.txt", + "co19Dir": "../.." +} diff --git a/Tools/spec_coverage/lib/co19.dart b/Tools/spec_coverage/lib/co19.dart new file mode 100644 index 0000000000..2153115011 --- /dev/null +++ b/Tools/spec_coverage/lib/co19.dart @@ -0,0 +1,68 @@ +import 'dart:io'; + +class Co19 { + static const languageDirName = "Language"; + late final TestDir root; + late final TestDir language; + + Co19(String path) { + Directory dir = Directory(path); + if (!dir.existsSync()) { + throw Exception("Directory '$path' does not exists"); + } + root = TestDir(dir); + for (TestDir td in root.subDirs) { + if (td.name == languageDirName) { + language = td; + break; + } + } + } +} + +class TestDir { + final String path; + final List subDirs = []; + final List tests = []; + + TestDir(Directory root) : path = resolvePath(root.path) { + List entities = root.listSync(); + for (FileSystemEntity fse in entities) { + if (skip(fse)) { + continue; + } + FileStat fs = fse.statSync(); + if (fs.type == FileSystemEntityType.directory) { + subDirs.add(TestDir(Directory(fse.path))); + } else if (fs.type == FileSystemEntityType.file) { + tests.add(TestFile(fse.path)); + } + } + } + + static String resolvePath(String relativePath) { + String basePath = Directory.current.path; + Uri baseUri = Uri.directory(basePath); + Uri resolvedUri = baseUri.resolve(relativePath); + return resolvedUri.toFilePath(); + } + + String get name => _entityName(path); + + String _entityName(String p) => + p.substring(p.lastIndexOf(Platform.pathSeparator) + 1); + + bool skip(FileSystemEntity fse) { + // Skip directories like .git + if (_entityName(fse.path).startsWith(RegExp(r"\.[a-zA-Z]+"))) { + return true; + } + return false; + } +} + +class TestFile { + final String path; + + TestFile(this.path); +} diff --git a/Tools/spec_coverage/lib/config.dart b/Tools/spec_coverage/lib/config.dart new file mode 100644 index 0000000000..f5565e7fff --- /dev/null +++ b/Tools/spec_coverage/lib/config.dart @@ -0,0 +1,8 @@ +class Config { + final String co19Dir; + final String specPath; + + Config.fromJson(Map json) + : co19Dir = json["co19Dir"], + specPath = json["specPath"]; +} diff --git a/Tools/spec_coverage/lib/spec.dart b/Tools/spec_coverage/lib/spec.dart new file mode 100644 index 0000000000..e1e02d5ebe --- /dev/null +++ b/Tools/spec_coverage/lib/spec.dart @@ -0,0 +1,37 @@ +import 'dart:io'; + +import 'package:spec_coverage/spec_parser.dart'; + +class Spec { + late final List chapters; + + Spec.fromTxt(String path) { + File file = File(path); + List lines = file.readAsLinesSync(); + SpecParser sp = SpecParser(); + chapters = sp.parse(lines); + } +} + +class Chapter { + ChapterNumber number; + String header; + late String co19DirName; + List subChapters = []; + List lines = []; + + Chapter({required this.number, required this.header}) + : co19DirName = header.replaceAll(" ", "_"); + + @override + String toString() => "$number $header"; +} + +class ChapterNumber { + final List numbers; + + ChapterNumber(this.numbers); + + @override + String toString() => numbers.join("."); +} diff --git a/Tools/spec_coverage/lib/spec_parser.dart b/Tools/spec_coverage/lib/spec_parser.dart new file mode 100644 index 0000000000..402e9b0c09 --- /dev/null +++ b/Tools/spec_coverage/lib/spec_parser.dart @@ -0,0 +1,61 @@ +import 'spec.dart'; + +class SpecParser { + static const pchar = "§"; + int chapterCounter1 = 0; + int chapterCounter2 = 0; + int chapterCounter3 = 0; + + List parse(List lines) { + return _parseLevel(null, lines, 1); + } + + List _parseLevel(Chapter? ch, List lines, int level) { + final List parsed = []; + final List chLines = []; + + Pattern pattern = switch (level) { + 1 => RegExp("$pchar [a-zA-Z]{2,}"), + 2 => RegExp(" $pchar.$pchar [a-zA-Z]{2,}"), + 3 => RegExp(" $pchar.$pchar.$pchar [a-zA-Z]{2,}"), + _ => throw "Wrong level number $level", + }; + + while (lines.isNotEmpty) { + String line = lines.removeAt(0); + if (line.startsWith(pattern)) { + if (ch != null) { + if (level < 3) { + ch.subChapters = _parseLevel(ch, chLines, level + 1); + } + ch.lines = chLines; + chLines.clear(); + } + ChapterNumber cn = _getChapterNumber(line); + int start = cn.numbers.length == 1 ? 2 : 2 * cn.numbers.length + 1; + ch = Chapter(number: cn, header: line.substring(start).trim()); + parsed.add(ch); + } else if (ch != null) { + chLines.add(line); + } + } + return parsed; + } + + ChapterNumber _getChapterNumber(String line) { + if (line.startsWith(" $pchar.$pchar.$pchar")) { + return ChapterNumber([ + chapterCounter1, + chapterCounter2, + ++chapterCounter3, + ]); + } + if (line.startsWith(" $pchar.$pchar")) { + chapterCounter3 = 0; + return ChapterNumber([chapterCounter1, ++chapterCounter2]); + } + chapterCounter2 = 0; + chapterCounter3 = 0; + return ChapterNumber([++chapterCounter1]); + } +} diff --git a/Tools/spec_coverage/pubspec.yaml b/Tools/spec_coverage/pubspec.yaml new file mode 100644 index 0000000000..f76adf57d5 --- /dev/null +++ b/Tools/spec_coverage/pubspec.yaml @@ -0,0 +1,9 @@ +name: spec_coverage +description: "Dart specification coverage CLI tool" + +publish_to: 'none' + +version: 0.0.1 + +environment: + sdk: '^3.7.0' \ No newline at end of file diff --git a/Tools/spec_coverage/resources/dartLangSpec.tex b/Tools/spec_coverage/resources/dartLangSpec.tex new file mode 100644 index 0000000000..94a972ae89 --- /dev/null +++ b/Tools/spec_coverage/resources/dartLangSpec.tex @@ -0,0 +1,23691 @@ +\documentclass[makeidx]{article} +\usepackage{xspace} +\usepackage{epsfig} +\usepackage{xcolor} +\usepackage{syntax} +\usepackage[fleqn]{amsmath} +\usepackage{amssymb} +\usepackage{semantic} +\usepackage{dart} +\usepackage{hyperref} +\usepackage{lmodern} +\usepackage[T1]{fontenc} +\usepackage{makeidx} +\makeindex +\title{Dart Programming Language Specification\\ +{6th edition draft}\\ +{\large Version 2.13-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. Note that the versions specified +% below indicate the current tool chain version when those changes were made. +% In practice, new features have always been integrated into the language +% specification (this document) a while after the change was accepted into +% the language and implemented. As of September 2022, the upcoming version of +% the language which is being specified is indicated by a version number in +% parentheses after the tool chain version. +% +% Note that the version numbers used below (up to 2.15) were associated with +% the currently released language and tools at the time of the spec change, +% they were not aligned with the actual version of the language which is being +% specified in that version of this document. This is highly misleading, so we +% changed the subtitles to be a month rather than a version number. Similarly, +% the 'Version' specified on the front page has been changed to indicate the +% version of the language which will actually be specified by the next stable +% release of this document. +% +% Sep 2024 +% - Clarify the extension applicability rule to explicitly state that it +% is concerned with an instance member with the same basename, not a +% static member. +% +% Jun 2024 +% - Add missing references to section 'Type dynamic' at the points where the +% static analysis of Object member invocations is specified. +% +% Feb 2024 +% - Correct the rule about deriving a future type from a type (which is used +% by `flatten`). +% +% Dec 2023 +% - Allow `~/` on operands of type `double` in constant expressions, aligning +% the specification with already implemented behavior. +% - Broaden the grammar rule about `initializerExpression` to match the +% implemented behavior. Specify that an initializer expression can not be +% a function literal. +% - Specify in which situations it is an error to declare an initializing +% formal parameter. +% +% Nov 2023 +% - Specify that the dynamic error for calling a function in a deferred and +% not yet loaded library will occur before actual argument evaluation, not +% after. +% +% Oct 2023 +% - Introduce the rule that an `extension` declaration cannot have the name +% `type`. This is needed in order to disambiguate an `extension type` +% named `on`. +% +% Aug 2023 +% - Correct text about built-in identifier error and turn it into commentary +% (the normative text is in grammar rules using `typeIdentifier`), and +% correct the grammar for import prefixes to use `typeIdentifier`. +% +% Jul 2023 +% - Land the null-safety updates for sections about variables. +% - Change terminology: A 'static variable' is now a variable whose declaration +% includes `static` (which used to be called a 'class variable'); the old +% meaning of 'static variable' is now never used (we spell out every time +% that it is a 'library variable or a static variable', where the latter is +% the new meaning of that phrase). This avoids the confusion that came up +% just about every single time the phrase 'static variable' came up in a +% discussion. +% - Change terminology: The notion of 'mutable' and 'immutable' variables has +% been eliminated (it is spelled out each time which modifiers must be +% present or not present). The concept is confusing now where a variable can +% be late and final, and assignments to it are allowed by the static analysis. +% - Change the definition of the 'element type of a generator function', due to +% soundness issue with the current definition. +% +% Mar 2023 +% - Clarify how line breaks are handled in a multi-line string literal. Rename +% the lexical token NEWLINE to LINE\_BREAK (clarifying that it is not `\n`). +% - Clean up grammar rules (avoid `T?` as a superclass/etc., which is an +% error anyway; change extension names to `typeIdentifier`, avoiding +% built-in identifiers). +% +% Feb 2023 +% - Change the specification of constant expressions of the form `e1 == e2` +% to use primitive equality. +% +% Dec 2022 +% - Change the definition of the type function 'flatten' to resolve soundness +% issue, cf. SDK issue #49396. +% - Introducing null-safety related changes to the sections about variables +% and local variables. +% - Change 'primitive operator ==' to 'primitive equality', and include +% constraints on `hashCode` corresponding to the ones we have on `==`. +% +% 2.15 +% - Allow generic instantiation of expressions with a generic function type +% (until now, it was an error unless the expression denoted a declaration). +% - Allow generic instantiation of the `call` method of a function object. +% - Clarify that `TypeLiteral.extensionMethod()` is an error, in line with the +% error for `int.toString()`. +% - Add support for function closurization for callable objects, in the sense +% that `o` is desugared as `o.call` when the context type is a function type. +% - Clarify the treatment of `covariant` parameters in the interface of a class +% that inherits an implementation where those parameters are not covariant. +% - Adjust and clarify simple string interpolation (to allow `'$this'`, which +% is already implemented and useful). +% - Add several lexical rules about identifiers, clarifying different kinds. +% - Clarify the conflicts between extension members and `Object` instance +% members. +% - Correct to include metadata. +% - Clarify the section about assignable expressions. +% +% 2.14 +% - Add constraint on type of parameter which is covariant-by-declaration in +% the case where the method is inherited (that case was omitted by mistake). +% - Clarify symbol equality and identity. +% +% 2.12 - 2.13 (there was no 2.11) +% - Revert the CL where certain null safety features were removed (to enable +% publishing a stable version of the specification). +% - Add rule that a top-level pair of declarations with the same basename +% is a compile-time error except when it is a getter/setter pair. +% - Change grammar to enable non-function type aliases. Correct rule for +% invoking `F.staticMethod()` where `F` is a type alias. +% - Add missing error for cyclic redirecting generative constructor. +% +% 2.8 - 2.10 +% - Change several warnings to compile-time errors, matching the actual +% behavior of tools. +% - Eliminate error for library name conflicts in imports and exports. +% - Clarify the specification of initializing formals. Fix error: Add +% missing `?` at the end for function typed initializing formal. +% - Adjust specification of JS number semantics. +% - Revise and clarify the sections Imports and Exports. +% - Bug fix: Change to omit the single identifier, then add it +% back when is used, as resp. . +% - Clarify that a function-type bounded receiver has a `.call` method. +% - Merge the `static' and `instance' scope of a class, yielding a single +% `class' scope. +% - Add specification of `>>` in JavaScript compiled code, in appendix. +% - Integrate the specification of extension methods into this document. +% - Specify identifier references denoting extension members. +% - Remove a few null safety features, to enable publishing a stable +% version of the specification which is purely about Dart 2.10. +% - Reorganize specification of type aliases to be in section `Type Aliases' +% (this used to be both there, and in 'Generics'). +% - Clarify the cyclicity error for type aliases ("F is not allowed to depend +% on itself). +% - Add the error for a type alias $F$ used in an instance creation etc., when +% $F$ expands to a type variable. +% - Correct lexical lookup rules to include implicit extension method +% invocation. +% +% 2.7 +% - Rename non-terminals `<...Definition>` to `<...Declaration>` (e.g., it is +% 'class declaration' everywhere, so `` is inconsistent). +% - Clarify that and are the +% start symbols of the grammar. +% - Clarify the notion of being `noSuchMethod forwarded': `m` is indeed +% noSuchMethod forwarded if an implementation of `m` is inherited, but +% it does not have the required signature. +% - Clarify static checks on `yield` and `yield*` to explicitly ensure that +% assignability is enforced per element. +% - Update whitelist for expressions of type void to include `await e`, +% consistent with decision in SDK issue #33415. +% - Re-adjust `yield*` rules: Per-element type checks are not supported, +% the given Iterable/Stream must have a safe element type. +% - Clarify that an expression of type `X extends T` can be invoked when +% `T` is a function type, plus other similar cases. +% - Specify actual type arguments passed to a generic function which is invoked +% with no type arguments (so it must be a dynamic invocation). +% +% 2.6 +% - Specify static analysis of a "callable object" invocation (where +% the callee is an instance of a class that has a `call` method). +% - Specify that string literals cannot use string +% interpolation; specify that it is a dynamic error for `loadLibrary` +% to load a different library than the one which was used for +% compile-time checks. +% - Specify that a constant expression `e.length` can only invoke an instance +% getter (in particular, it cannot execute/tear-off an extension member); +% similar changes were made for several operators. +% - Specify the type arguments of the fields of an `Invocation` received by +% `noSuchMethod`, when invoked in response to a failed instance member +% invocation. +% +% 2.4 +% - Clarify the section `Exports'. +% - Update grammar rules for , to support `static late final` +% variables with no initializer; for several top-level declarations, +% to correct the existence and placement of ; for +% , to simplify the grammar (preserving the +% derivable terms); for , to allow top-level final +% and const variables with no type, and to allow `late final` top-level +% variables, to allow `late` on a top-level variable declaration; and +% adding to allow `required` parameters. +% - Make lexical identifier lookups use the rules for 'Identifier Reference' +% consistently; that is, always look up `id` as well as `id=`, and commit +% to the kind of declaration found by that lookup. +% - Specify the signature of the `call` method of a function object. +% - Add the rule that it is an error for a type variable of a class to occur +% in a non-covariant position in a superinterface. +% - Correct several grammar rules, including: added (to +% avoid semicolon in ), adjusted . +% - Revise section on cascades. Now uses compositional grammar, and +% specifies static type, compile-time errors, and includes `?..`. +% - Correct the grammar and lexical rules for string literals. +% - Change specification of `await` to be type-safe, avoiding cases like: +% FutureOr> ffs = Future.value(s); +% Future fs = await ffs; +% +% 2.3 +% - Add requirement that the iterator of a for-in statement must have +% type `Iterator`. +% - Clarify which constructors are covered by the section 'Constant +% Constructors' and removed confusing redundancy in definiton of +% potentially constant expressions. +% - Integrate the feature specification of collection literal elements +% (aka UI-as-code). +% +% 2.2 +% - Specify whether the values of literal expressions override Object.==. +% - Allow Type objects as case expressions and const map keys. +% - Introduce set literals. +% - Specify that a getter/setter and a method with the same basename is +% an error, also in the case where a class obtains both from its +% superinterfaces. +% - Specify the Dart 2.0 rule that you cannot implement, extend or mix-in +% Function. +% - Generalize specification of type aliases such that they can denote any +% type, not just function types. +% - Clarify that 'Constant Constructors' is concerned with non-redirecting +% generative constructors only. +% +% 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 superinvocations, adjust +% specification of superinvocations accordingly. +% - Specify that it is a dynamic error to initialize a non-static variable +% with an object 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` 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. +% - Specify that bound satisfaction in generic type alias type parameters +% must imply bound satisfaction everywhere in the body. +% - Specify that super-bounded generic type alias applications must trigger +% a well-boundedness check on all types occurring in the denoted type. +% - Corrected corner case of rules for generation of noSuchMethod forwarders. +% - Integrate feature specification on parameters that are +% covariant-by-declaration. +% - Integrate feature specification on parameters that are +% covariant-by-class. +% - Correct section 'Type of a function', allowing for adjustments needed +% for rules related to covariant parameters. +% - Specified the dynamic type of function objects in several contexts, such +% that the special treatment of covariant parameters can be mentioned. +% - Specified what it means for an override relation to be correct, thus +% adding the parts that are not captured by a function type subtype check. +% - Introduced the notion of member signatures, specified that they are the +% kind of entity that a class interface contains. +% - Corrected super-boundedness check to take variance into account at the +% top level. +% +% 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 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. +% - Integrate subtyping.md. This introduces the Dart 2 rules for subtyping, +% which in particular means that the notion of being a more specific type +% is eliminated, and function types are made contravariant in their +% parameter types. +% - Integrate instantiation to bound. This introduces the notions of raw +% types, the raw-depends relation, and simple bounds; and it specifies +% the algorithm which is used to expand a raw type (e.g., `C`) to a +% parameterized type (e.g., `C`). +% - Integrate invalid_returns.md. This replaces the rules about when it is +% an error to have `return;` or `return e;` in a function. +% - Integrate generalized-void.md. Introduces syntactic support for using +% `void` in many new locations, including variable type annotations and +% actual type arguments; also adds errors for using values of type `void`. +% - Integrate implicit_creation.md, specifying how some constant expressions +% can be written without `const`, and all occurrences of `new` can be +% omitted. +% +% 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. + + +\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. +% 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.% +} +\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 `\lit{::=}'. +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}\color{commentaryColor} + ::= + \alt + \alt + \alt * + \alt + + \alt ? + \alt ( ) + \alt \gtilde + \alt `aTerminal' + \alt +\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 \Index{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 \Index{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 \Index{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 \DefineSymbol{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. + +\BlindDefineSymbol{j, y_j, x_j}% +\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 \DefineSymbol{E} again a composite syntactic entity. +The notation +\IndexCustom{$[x_1/y_1, \ldots, x_n/y_n]E$}{[x1/y1, ..., xn/yn]E@$[x/y\ldots]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 \Index{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 \code{[\List{o}{1}{n}]} +(respectively \code{\{$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{}% +\BlindDefineSymbol{x, op, y}% +The specifications of operators often involve statements such as +\code{$x$ \metavar{op} $y$} is equivalent to the method invocation +\IndexCustom{\rm\code{$x$.\metavar{op}($y$)}}{% + x.op(y)@\code{$x$.\metavar{op}($y$)}}. +Such specifications should be understood as a shorthand for: +\begin{itemize} +\item + $x$ $op$ $y$ is equivalent to the method invocation + \code{$x$.\metavar{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 +{\rm\code{$x$.\metavar{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 +\IndexCustom{fresh variable}{variable!fresh}, +it means a local variable with a name that doesn't occur anywhere +in the current program. +When the specification introduces a fresh variable bound to an object, +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, respectively, the root of the class hierarchy and +the reification of run-time types. +% +It would be possible to declare, e.g., +a local variable named \code{Object}, +so it is generally incorrect to assume that +the name \code{Object} will actually resolve to said core class. +However, we will generally omit mentioning this, for brevity.% +} + +%% TODO(eernst): We need to get rid of the concept of `is equivalent to`, +%% cf. language issue https://github.com/dart-lang/language/issues/227. +%% In this CL the phrase `treated as` has been introduced in a few places, +%% and the above-mentioned issue 227 will give rise to a complete revision +%% of this aspect of this document. In particular, the next paragraph will +%% be deleted. + +\LMHash{}% +When the specification says that one piece of syntax \Index{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. + +\LMHash{}% +\BlindDefineSymbol{s, s'}% +When the specification says that one piece of syntax $s$ is +\Index{treated as} +another piece of syntax $s'$, +it means that the static analysis of $s$ is the static analysis of $s'$ +(\commentary{in particular, exactly the same compile-time errors occur}). +Moreover, if $s$ has no compile-time errors then +the behavior of $s$ at run time is exactly the behavior of $s'$. + +\rationale{% +Error \emph{messages}, if any, should always refer to the original syntax $s$.% +} + +\commentary{% +In short, whenever $s$ is treated as $s'$, +the reader should immediately switch to the section about $s'$ +in order to get any further information about +the static analysis and dynamic semantics of $s$.% +} + +\rationale{% +The notion of being `treated as' is similar to the notion of syntactic sugar: +``$s$ is treated as $s'$'' +could as well have been worded +``$s$ is desugared into $s'$''. +Of course, it should then actually be called ``semantic sugar'', +because the applicability of the transformation and the construction of $s'$ +may rely on information from static analysis. + +The point is that we only specify the static analysis and dynamic semantics +of a core language which is a subset of Dart +(just slightly smaller than Dart), +and desugaring transforms any given Dart program to +a program in that core language. +This helps keeping the language specification consistent and comprehensible, +because it shows directly +that some language features are introducing essential semantics, +and others are better described as mere abbreviations of existing constructs.% +} + +\LMHash{}% +The specification uses one syntactic construct, the +\IndexCustom{\LET{} expression}{let expression@\LET{} expression}, +which is not derivable in the grammar +(\commentary{that is, no Dart source code contains such an expression}). +This expression is helpful in specifying certain syntactic forms +that are treated as other syntactic forms, +because it allows for introducing and initializing one or more fresh variables, +and using them in an expression. + +\commentary{% +That is, a \LET{} expression is only introduced as a tool +to define the evaluation semantics of an expression +in terms of other expressions containing \LET{} expressions.% +} + +\LMHash{}% +The syntax of a \LET{} expression is as follows: + +\begin{grammar} + ::= \LET{} \IN{} +\end{grammar} + +\LMHash{}% +\BlindDefineSymbol{e_{\metavar{let}}, e_j, v_j, k}% +Let $e_{\metavar{let}}$ be a \LET{} expression of the form +\LetMany{$v_1$}{$e_1$}{$v_k$}{$e_k$}{$e$}. +It is tacitly assumed that $v_j$ is a fresh variable, $j \in 1 .. k$, +unless something is stated to the contrary. + +\LMHash{}% +$e_{\metavar{let}}$ contains $k$ nested scopes, \DefineSymbol{\List{S}{1}{k}}. +The enclosing scope for $S_1$ is the current scope for $e_{\metavar{let}}$, +and the enclosing scope for $S_j$ is $S_{j-1}$, $j \in 2 .. k$. +The current scope of $e_1$ is the current scope of $e_{\metavar{let}}$, +the current scope of $e_j$ is $S_{j-1}$, $j \in 2 .. k$, +and the current scope of $e$ is $S_k$. +For $j \in 1 .. k$, $v_j$ introduces a final, local variable into $S_j$, +with the static type of $e_j$ as its declared type. + +\commentary{% +Type inference of $e_j$ and the context type used for inference of $e_j$ +are not relevant. +It is generally assumed that type inference has occurred already +(\ref{overview}).% +} + +\LMHash{}% +Evaluation of $e_{\metavar{let}}$ proceeds by +evaluating $e_j$ to an object $o_j$ and binding $v_j$ to $o_j$, +where $j \in 1 .. k$, in that order. +Finally, $e$ is evaluated to an object $o$ and then +$e_{\metavar{let}}$ evaluates to $o$. + +\LMHash{}% +The right margin of each page in this document is used to indicate +referenced entities. + +\LMHash{}% +The document contains an index at the end. +Each entry in the index refers to a page number, $p$. +On page $p$ there is a `$\diamond$' in the margin +at the definition of the given indexed phrase, +and the phrase itself is shown using \emph{this typeface}. +We have hereby introduced the +\Index{index marker $\diamond$} +itself. + +\LMHash{}% +The right margin also contains symbols. +Whenever a symbol +\BlindDefineSymbol{\textcolor{commentaryColor}{C}}% +\BlindDefineSymbol{\textcolor{commentaryColor}{x_j}}% +(\commentary{say, $C$ or $x_j$}) +is introduced and used in more than a few lines of text, +it is shown in the margin. + +\commentary{% +The point is that it is easy to find the definition of a symbol +by scanning back in the text until that symbol occurs in the margin. +To avoid useless verbosity, some symbols are not mentioned in the margin. +For instance, we may introduce \List{e}{1}{k}, +but only show $e_j$ and $k$ in the margin. + +Note that it may be necessary to look at a few lines of text +above the `$\diamond$' or symbol, +because the margin markers can be pushed down one line +when there is more than one marker for a single line.% +} + + +\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 \NoIndex{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 \IndexCustom{compile-time namespace}{namespace!compile-time} +is a partial function that maps names to namespace values. +Compile-time namespaces are used much more frequently than run-time namespaces +(\commentary{defined later in this section}), +so when the word \Index{namespace} is used alone, +it means compile-time namespace. +A \Index{name} is a lexical token which is an \synt{IDENTIFIER}, +an \synt{IDENTIFIER} followed by \lit{=}, or +an \synt{operator}, +or \code{unary-}; +and a \Index{namespace value} is +a declaration, a namespace, or the special value \ConflictValue{} +(\ref{conflictMergingOfNamespaces}). + +\LMHash{}% +If $\Namespace{}{n} = V$ then we say that \NamespaceName{} +\IndexCustom{maps}{namespace!maps a key to a value} +the +\IndexCustom{key}{namespace!key} +$n$ to the +\IndexCustom{value}{namespace!value} +$V$, +and that \NamespaceName{} +\IndexCustom{has the binding}{namespace!has a binding} +$n\mapsto{}V$. +\commentary{% +The fact that \NamespaceName{} is a partial function just means that +each name is mapped to at most one namespace value. +That is, if \NamespaceName{} has the bindings +$n\mapsto{}V_1$ and $n\mapsto{}V_2$ +then $V_1 = V_2$.% +} + +\LMHash{}% +Let \NamespaceName{} be a namespace. +We say that a name $n$ \Index{is in} \NamespaceName{} +if $n$ is a key of \NamespaceName. +We say a declaration $d$ \NoIndex{is in} \NamespaceName{} +if a key of \NamespaceName{} is mapped to $d$. + +\LMHash{}% +A scope $S_0$ has an associated namespace \NamespaceName{0}. +The bindings of \NamespaceName{0} is specified in this document by saying that +a given declaration \BlindDefineSymbol{D, n}$D$ named $n$ +\IndexCustom{introduces}{declaration!introduces an entity into a scope} +a specific entity \DefineSymbol{V} into $S_0$, +which means that the binding $n\mapsto{}V$ is added to \NamespaceName{0}. + +\commentary{% +In some cases, the name of the declaration differs from +the identifier that occurs in the declaration syntax used to declare it. +Setters have names that are distinct from the corresponding getters +because they always have an \lit{=} automatically added at the end, +and the unary minus operator has the special name \code{unary-}.% +} + +\commentary{% +It is typically the case that $V$ is the declaration $D$ itself, +but there are exceptions. +For example, +a variable declaration introduces an implicitly induced getter declaration, +and in some cases also an implicitly induced setter declaration into the +given scope.% +} + +\commentary{% +Note that labels (\ref{labels}) are not included in the namespace of a scope. +They are resolved lexically rather then being looked up in a namespace.% +} + +\LMHash{}% +It is a compile-time error if there is more than one entity with the same name +declared in the same scope. + +\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 +which is declared in the same library.% +} + +\LMHash{}% +We introduce the notion of a +\Index{run-time namespace}. +This is a partial function from names to run-time entities, +in particular storage locations and functions. +Each run-time namespace corresponds to a namespace with the same keys, +but with values that correspond to the semantics of the namespace values. + +\rationale{% +A namespace typically maps a name to a declaration, +and it can be used statically to figure out what that name refers to. +For example, +a variable is associated with an actual storage location at run time. +We introduce the notion of a run-time namespace based on a namespace, +such that the dynamic semantics can access run-time entities +like that storage location. +The same code may be executed multiple times with the same run-time namespace, +or with different run-time namespaces for each execution. +E.g., local variables declared inside a function +are specific to each invocation of the function, +and instance variables are specific to an object.% +} + +\LMHash{}% +Dart is lexically scoped. +Scopes may nest. +A name or declaration $d$ is \Index{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 \Index{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$ \Index{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 \Index{privacy}: public and private. +A declaration is \IndexCustom{private}{private!declaration} +if{}f its name is private, +otherwise it is \IndexCustom{public}{public!declaration}. +A name $q$ is \IndexCustom{private}{private!name} +if{}f any one of the identifiers that comprise $q$ is private, +otherwise it is \IndexCustom{public}{public!name}. +An identifier is \IndexCustom{private}{private!identifier} +if{}f it begins with an underscore (the \_ character) +otherwise it is \IndexCustom{public}{public!identifier}. + +\LMHash{}% +A declaration $m$ is \Index{accessible to a 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.% +} + +\rationale{% +Privacy applies only to declarations within a library, +not to the library declaration as a whole. +This is because libraries do not reference each other by name, +and so the idea of a private library is meaningless +(\ref{imports}). +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. + +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 \Index{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{}% +\IndexCustom{Compile-time errors}{compile-time error} +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 a \Index{runtime}, +a program that interfaces between the engine and +the surrounding computing environment. +The runtime may be, for instance, a C++ program on the server. +When an isolate fails with a compile-time error as described above, +control returns to the runtime, +along with an exception describing the problem. +This is necessary so that the runtime can clean up resources etc. +It is then the runtime's decision whether to terminate the isolate or not.% +} + +\LMHash{}% +\IndexCustom{Static warnings}{static warning} +are situations that do not preclude execution, +but which are unlikely to be intended, +and likely to cause bugs or inconveniences. +A Dart compiler is free to report some, all, +or none of the specified static warnings before the associated code is executed. +A Dart compiler may also choose to report additional warnings +not defined by this specification. + +\LMHash{}% +When this specification says that a \Index{dynamic error} occurs, +it means that a corresponding error object is thrown. +When it says that a \Index{dynamic type error} occurs, +it represents a failed type check at run time, +and the object which is thrown implements \code{TypeError}. + +\LMHash{}% +Whenever we say that an exception $ex$ is +\IndexCustom{thrown}{throwing an exception}, +it acts like an expression had thrown (\ref{statementCompletion}) +with $ex$ as exception object and with a stack trace +corresponding to the current system state. +When we say that a $C$ \IndexCustom{is thrown}{throwing a class}, +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} + ::= \LATE? \FINAL{} ? + \alt \CONST{} ? + \alt \LATE? + + ::= \VAR{} + \alt + + ::= \gnewline{} + (`=' )? (`,' )* + + ::= (`=' )? + + ::= + (`,' )* +\end{grammar} + +\LMHash{}% +An \synt{initializedVariableDeclaration} +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 initialization, type, and modifiers. + +\commentary{% +For example, +\code{\VAR{} x, y;} +is equivalent to +\code{\VAR{} x; \VAR{} y;} +and +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s1, s2 = "foo";} +is equivalent to having both +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s1;} +and +\code{\STATIC\,\,\LATE\,\,\FINAL{} String s2 = "foo";}.% +} + +\LMHash{}% +It is possible for a variable declaration to include the modifier \COVARIANT. +The effect of doing this with an instance variable is described elsewhere +(\ref{instanceVariables}). +It is a \Error{compile-time error} for the declaration of a variable +which is not an instance variable to include the modifier \COVARIANT. + +\commentary{% +A formal parameter declaration induces a local variable into a scope, +but formal parameter declarations are not variable declarations +and do not give rise to the above error. +The effect of having the modifier \COVARIANT{} on a formal parameter +is described elsewhere +(\ref{covariantParameters}).% +} + +\LMHash{}% +In a variable declaration of one of the forms +\code{$N$\,\,\id;} +or +\code{$N$\,\,\id{} = $e$;} +where $N$ is derived from +\syntax{ } and \id{} is an identifier, +we say that \id{} is a \Index{declaring occurrence} of the identifier. +For every identifier which is not a declaring occurrence, +we say that it is a \Index{referencing occurrence}. +We also abbreviate that to say that an identifier is +a \Index{declaring identifier} respectively an \Index{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 specific declaration named $\id'$ at compile-time, +but in this situation $\id'$ is still a referencing identifier.% +} + +\LMHash{}% +For brevity, we will refer to a variable using its name, +even though the name of a variable and the variable itself +are very different concepts. + +\commentary{% +So we will talk about ``the variable \id{}'', +rather than introducing ``the variable $v$ named \id{}''\!, +in order to be able to say ``the variable $v$'' later on. +This should not create any ambiguities, +\emph{because} the concept of a name and the concept of a variable +are so different.% +} + +\LMHash{}% +An \Index{initializing variable declaration} +is a variable declaration whose declaring identifier is +immediately followed by `\code{=}' and an \Index{initializing expression}. + +\LMHash{}% +A variable declared at the top-level of a library is referred to as either a +\IndexCustom{library variable}{variable!library} or a +\IndexCustom{top-level variable}{variable!top-level}. +It is a \Error{compile-time error} if a library variable declaration +has the modifier \STATIC. + +\LMHash{}% +A \IndexCustom{static variable}{variable!static} +is a variable whose declaration is +immediately nested inside a \CLASS, \MIXIN, \ENUM, or \EXTENSION{} declaration +and includes the modifier \STATIC. + +\LMHash{}% +A \Error{compile-time error} occurs if a static or library variable has +no initializing expression and a type which is not nullable +(\ref{typeNullability}), +unless the variable declaration has +the modifier \LATE{} or the modifier \EXTERNAL. + +\LMHash{}% +A \IndexCustom{non-local variable}{variable!non-local} +is a library variable, a static variable, or an instance variable. +\commentary{% +That is, any kind of variable which is not a local variable.% +} + +\LMHash{}% +A \IndexCustom{constant variable}{variable!constant} +is a variable whose declaration includes the modifier \CONST. +A constant variable must be initialized to a constant expression +(\ref{constants}), +or a \Error{compile-time error} occurs. + +\commentary{% +An initializing expression $e$ of a constant variable declaration +occurs in a constant context +(\ref{constantContexts}). +This means that \CONST{} modifiers in $e$ need not be specified explicitly.% +} + +\rationale{% +It is grammatically impossible for a constant variable declaration +to have the modifier \LATE. +However, even if it had been grammatically possible, +a \LATE{} constant variable would still have to be a compile-time error, +because being a compile-time constant is inherently incompatible +with being computed late. + +Similarly, an instance variable cannot be constant +(\ref{instanceVariables}).% +} + + +\subsection{Implicitly Induced Getters and Setters} +\LMLabel{implicitlyInducedGettersAndSetters} + +%% TODO(eernst): When inference is specified, we should be able to conclude +%% that the cases with no declared type do not exist after type inference +%% (for instance `var x;` or `var x = e;`), and then we can replace all rules +%% about such cases by commentary saying that they may exist in the input, +%% but they are gone after type inference. +%% +%% At this time we rely on the assumption that type inference has already +%% occurred, which means that we can refer to the declared type of a variable +%% without mentioning type inference. + +\LMHash{}% +The following rules on implicitly induced getters and setters +apply to all non-local variable declarations. +\commentary{% +Local variable declarations +(\ref{localVariableDeclaration}) +do not induce getters or setters.% +} + +\LMHash{}% +\Case{Getter: Variable with declared type} +Consider a variable declaration of one of the forms + +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL?\,\,$T$\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\CONST\,\,$T$\,\,\id{} = $e$;} +\end{itemize} + +\noindent +where $T$ is a type, \id{} is an identifier, +and \lit{?} indicates that the given modifier may be present or absent. +Each of these declarations implicitly induces a getter +(\ref{getters}) +with the header \code{$T$\,\,\GET\,\,\id}, +whose invocation evaluates as described below +(\ref{evaluationOfImplicitVariableGetters}). +In these cases the declared type of \id{} is $T$. +\EndCase + +\LMHash{}% +\Case{Getter: Variable with no declared type} +A variable declaration of one of the forms + +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,\FINAL\,\,\id{} = $e$;} +\item \code{\STATIC?\,\,\CONST\,\,\id{} = $e$;} +\end{itemize} + +\noindent +implicitly induces a getter with the header that +contains \STATIC{} if{}f the declaration contains \STATIC{} and is followed by +\code{$T$\,\,\GET\,\,\id}, +where $T$ is obtained from type inference +in the case where $e$ exists, +and $T$ is \DYNAMIC{} otherwise. +The invocation of this getter evaluates as described below +(\ref{evaluationOfImplicitVariableGetters}). +In these cases, the declared type of \id{} is $T$. +\EndCase + +\LMHash{}% +\Case{Setter: Mutable variable with declared type} +A variable declaration of one of the forms + +\begin{itemize} +\item \code{\STATIC?\,\,\LATE?\,\,$T$\,\,\id;} +\item \code{\STATIC?\,\,\LATE?\,\,$T$\,\,\id{} = $e$;} +\end{itemize} + +\noindent +implicitly induces a setter (\ref{setters}) with the header +\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\LMHash{}% +\Case{Setter: Mutable variable with no declared type, with initialization} +A variable declaration of the form +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id{} = $e$;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\commentary{% +Type inference could have provided a type different from \DYNAMIC{} +(\ref{overview}).% +} +\EndCase + +\LMHash{}% +\Case{Setter: Mutable variable with no declared type, no initialization} +A variable declaration of the form +\code{\STATIC?\,\,\LATE?\,\,\VAR\,\,\id;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}, +whose execution sets the value of \id{} to the incoming argument $x$. + +\commentary{% +Type inference has not yet been specified in this document +(\ref{overview}). +Note that type inference could change, e.g., +\code{\VAR\,\,x;} to \code{$T$\,\,x;}, +which would take us to an earlier case.% +} +\EndCase + +\LMHash{}% +\Case{Setter: Late-final variable with declared type} +A variable declaration of the form +\code{\STATIC?\,\,\LATE\,\,\FINAL\,\,$T$\,\,\id;} +implicitly induces a setter (\ref{setters}) with the header +\code{\VOID\,\,\SET\,\,\id($T$\,\,$x$)}. +If this setter is executed +in a situation where the variable \id{} has not been bound, +it will bind \id{} to the object that $x$ is bound to. +If this setter is executed +in a situation where the variable \id{} has been bound to an object, +a dynamic error occurs. +\EndCase + +\LMHash{}% +\Case{Setter: Late-final variable with no declared type, no initialization} +A variable declaration of the form +\code{\STATIC?\,\,\LATE\,\,\FINAL\,\,\id;} +implicitly induces a setter with the header +\code{\VOID\,\,\SET\,\,\id(\DYNAMIC\,\,$x$)}. +An execution of said setter +in a situation where the variable \id{} has not been bound +will bind \id{} to the object that the argument $x$ is bound to. +An execution of the setter +in a situation where the variable \id{} has been bound to an object +will incur a dynamic error. +\EndCase + +\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 library scope of the enclosing library. +A static variable introduces a static getter into +the body scope of the immediately enclosing +class, mixin, enum, or extension declaration. +An instance variable introduces an instance getter into +the body scope of the immediately enclosing +class, mixin, or enum declaration +(\commentary{an extension cannot declare instance variables}). + +\LMHash{}% +A non-local variable introduces a setter if{}f +it does not have the modifier \FINAL{} or the modifier \CONST{}, +or it is \LATE{} and \FINAL, but does not have an initializing expression. + +\LMHash{}% +A library variable which introduces a setter will introduce +a library setter into the enclosing library scope. +A static variable which introduces a setter will introduce +a static setter into the body scope of the immediately enclosing +class, mixin, enum, or extension declaration. +An instance variable that introduces a setter will introduce +an instance setter into the body scope of the immediately enclosing +class, mixin, or enum declaration +(\commentary{an extension cannot declare instance variables}). + +\LMHash{}% +Let \id{} be a variable declared by a variable declaration +that has an initializing expression $e$. +It is a \Error{compile-time error} if the static type of $e$ +is not assignable to the declared type of \id. +It is a \Error{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 non-late static variable declaration $D$ named \id{} +that has the modifier \FINAL{} or the modifier \CONST{} +does not induce a setter. +However, an assignment to \id{} at a location where $D$ is in scope +is not necessarily a compile-time error. +For example, a setter named \code{\id=} could be found by lexical lookup +(\ref{lexicalLookup}). + +Similarly, a non-late final instance variable \id{} does not induce a setter, +but an assignment could be an invocation of +a setter which is provided in some other way. +For example, it could be that lexical lookup yields nothing, +and the location of the assignment has access to \THIS, +and the interface of an enclosing class has a setter named \code{\id=} +(in this case both the getter and setter are inherited).% +} + +\LMHash{}% +Consider a variable \id{} +whose declaration does not have the modifier \LATE. +Assume that \id{} does not have an initializing expression, +and it is not initialized by an initializing formal +(\ref{generativeConstructors}), +nor by an element in a constructor initializer list +(\ref{initializerLists}). +The initial value of \id{} is then the null object +(\ref{null}). + +\commentary{% +Note that there are many situations where such a variable declaration +is a compile-time error, +in which case the initial value is of course irrelevant.% +} + +\LMHash{}% +Otherwise, variable initialization proceeds as follows: + +\LMHash{}% +A declaration of a static or library variable +with an initializing expression is 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{}% +\BlindDefineSymbol{\id, o}% +Initialization of an instance variable \id{} +with an initializing expression $e$ +proceeds as follows: +$e$ is evaluated to an object $o$ +and the variable \id{} 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{}% +% This error can occur due to an implicit downcast from \DYNAMIC. +It is a dynamic type error if the dynamic type of $o$ is not +a subtype of the actual type of the variable \id{} +(\ref{actualTypes}). + + +\subsection{Evaluation of Implicit Variable Getters} +\LMLabel{evaluationOfImplicitVariableGetters} + +\LMHash{}% +We introduce two specific kinds of getters in order to specify +the behavior of various kinds of variables +without duplicating the specification of their common behaviors. + +\LMHash{}% +A +\IndexCustom{late-initialized getter}{getter!late-initialized} +is a getter $g$ which is implicitly induced by a non-local variable $v$ +that has an initializing expression $e$. +\commentary{% +It is described below which declarations induce a late-initialized getter.% +} +An invocation of $g$ proceeds as follows: + +\LMHash{}% +If the variable $v$ has not been bound to an object then +$e$ is evaluated to an object $o$. +If $v$ has now been bound to an object, and $v$ is final, +a dynamic error occurs. % Implementations throw a 'LateInitializationError'. +Otherwise, $v$ is bound to $o$, +and the evaluation of $g$ completes returning $o$. +If the evaluation of $e$ throws then +the invocation of $g$ completes throwing the same object and stack trace, +and does not change the binding of $v$. + +\LMHash{}% +An invocation of $g$ in a situation where $v$ has been bound to an object $o'$ +completes immediately, returning $o'$. + +\commentary{% +Consider a non-local variable declaration of the form +\code{\LATE\,\,\VAR\,\,x = $e$;}, +whose implicitly induced getter is late-initialized. +Perhaps surprisingly, +if the variable \code{x} has been bound to an object +when its getter is invoked for the first time, +$e$ will never be executed. +In other words, the initializing expression can be pre-empted by an assignment.% +} + +\commentary{% +Also note that an initializing expression can have side effects +that are significant during initialization. +For example:% +} + +\begin{dartCode} +bool b = \TRUE; +int i = (() => (b = !b) ? (i = 10) : i + 1)(); +\\ +\VOID{} main() \{ + print(i); // '11'. +\} +\end{dartCode} + +\commentary{% +In this example, \code{main} invokes +the implicitly induced getter named \code{i}, +and the variable \code{i} has not been bound at this point. +Hence, evaluation of the initializing expression proceeds. +This causes \code{b} to be toggled to \FALSE, +which again causes \code{i + 1} to be evaluated. +This causes the getter \code{i} to be invoked again, +and it is still true that the variable has not been bound, +so the initializing expression is evaluated again. +This toggles \code{b} to \TRUE, +which causes \code{i = 10} to be evaluated, +which causes the implicitly induced setter named \code{i=} to be invoked, +and the most recent invocation of the getter \code{i} +returns 10. +This makes \code{i + 1} evaluate to 11, +and the variable is then bound to 11. +Finally, the invocation of the getter \code{i} in \code{main} +completes returning 11.% +} + +\commentary{% +This is a change from the semantics of older versions of Dart: +Throwing an exception during initializer evaluation no longer sets the +variable to \code{null}, +and reading the variable during initializer evaluation +no longer causes a dynamic error.% +} + +\LMHash{}% +A +\IndexCustom{late-uninitialized getter}{getter!late-uninitialized} +is a getter $g$ which is implicitly induced by a non-local variable $v$ +that does not have an initializing expression. +\commentary{% +Again, only \emph{some} non-local variables without an initializing expression +induce a late-uninitialized getter, as specified below.% +} +An invocation of $g$ proceeds as follows: +If the variable $v$ has not been bound to an object then a dynamic error occurs. +If $v$ has been bound to an object $o'$ then +the invocation of $g$ completes immediately, returning $o'$. + +\LMHash{}% +\BlindDefineSymbol{d, \id}% +Let $d$ be the declaration of a non-local variable named \id. +For brevity, we will refer to it below as +`the variable \id' or `the variable $d$', or just as `\id' or `$d$'. +Execution of the implicitly induced getter of \id{} proceeds as follows: + +\LMHash{}% +\Case{Non-late instance variable} +If $d$ declares an instance variable which does not have the modifier \LATE, +then the invocation of the implicit getter of \id{} evaluates to +the object that \id{} is bound to. + +\commentary{% +It is not possible to invoke an instance getter on an object +before the object has been initialized. +Hence, a non-late instance variable is always bound +when the instance getter is invoked.% +} +\EndCase + +\LMHash{}% +\Case{Late, initialized instance variable} +If $d$ declares an instance variable \id{} which has the modifier \LATE{} +and an initializing expression, +the implicitly induced getter of \id{} is a +late-initialized getter. +This determines the semantics of an invocation. +\EndCase + +\LMHash{}% +\Case{Late, uninitialized instance variable} +If $d$ declares an instance variable \id{} which has the modifier \LATE{} +and does not have an initializing expression, +the implicitly induced getter of \id{} is a +late-uninitialized getter. +This determines the semantics of an invocation. + +\commentary{% +In this case it is possible for \id{} to be unbound, +but there are also several ways to bind \id{} to an object: +A constructor can have an initializing formal +(\ref{generativeConstructors}) +or an initializer list entry +(\ref{initializerLists}) +that will initialize \id{}, +and the implicitly induced setter named \code{\id=} could +have been invoked and completed normally.% +} +\EndCase + +\LMHash{}% +\Case{Static or library variable} +If $d$ declares a static or library variable, +the implicitly induced getter of \id{} executes as follows: + +\begin{itemize} +\item \emph{Non-constant variable with an initializer.} + In the case where $d$ has an initializing expression and is not constant, + the implicitly induced getter of \id{} is a late-initialized getter. + This determines the semantics of an invocation. + \commentary{% + Note that these static or library variables can be \emph{implicitly} + late-initialized, in the sense that they do not have + the modifier \LATE.% + } +\item \emph{Constant variable.} + If $d$ declares a constant variable with the initializing expression $e$, + the result of executing the implicitly induced 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 \emph{Variable without an initializer.} + If $d$ declares a variable \id{} without an initializing expression + and does not have the modifier \LATE, + an invocation of the implicitly induced getter of \id{} evaluates to + the object that \id{} is bound to. + + \commentary{% + The variable is always bound to an object in this case. + This may be the null object, + which is the initial value of some variable declarations + covered by this case.% + } + + If $d$ declares a variable \id{} without an initializing expression + and has the modifier \LATE, + the implicitly induced getter is a late-uninitialized getter. + This determines the semantics of an invocation. +\end{itemize} + +% Reduce whitespace after itemized list: This is just an end symbol. +\vspace{-\baselineskip}\EndCase + + +\section{Functions} +\LMLabel{functions} + +\LMHash{}% +Functions abstract over executable actions. + +\begin{grammar} + ::= \gnewline{} + ? + + ::= ? + + ::= \ASYNC? `=>' `;' + \alt (\ASYNC{} `*'? | \SYNC{} `*')? + + ::= `{' `}' +\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{}% +A function is \IndexCustom{asynchronous}{function!asynchronous} +if its body is marked with the \ASYNC{} or \code{\ASYNC*} modifier. +Otherwise the function is \IndexCustom{synchronous}{function!synchronous}. +A function is a \IndexCustom{generator}{function!generator} +if its body is marked with the \code{\SYNC*} or \code{\ASYNC*} modifier. +Further details about these concepts are given below. + +\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 \emph{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{}% +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*}. + % + Unless it is statically known that the body of the function + cannot complete normally + (\commentary{that is, it cannot reach the end and ``fall through''}, + cf.~\ref{statementCompletion}), + it is a compile-time error if + the addition of \code{\RETURN;} at the end of the body + would be a compile-time error. + \commentary{% + For instance, it is an error if + the return type of a synchronous function is \code{int}, + and the body may complete normally. + The precise rules are given in section~\ref{return}.% + } + + \commentary{% + Because Dart supports dynamic function invocations, + we cannot guarantee that a function that does not return an object + will not be used in the context of an expression. + Therefore, every function must either throw or return an object. + 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. + Generators are not allowed to explicitly return anything, + objects are added to the generated stream or iterable using + \YIELD{} or \YIELD*.% + } + Let $T$ be the declared return type of the function that has this body. + It is a compile-time error if one of the following conditions hold: + \begin{itemize} + \item The function is synchronous, $T$ is not \VOID, + and it would have been a compile-time error + to declare the function with the body + \code{\{ \RETURN{} $e$; \}} + rather than \code{=> $e$}. + \commentary{% + In particular, $e$ can have \emph{any} type when the return type is \VOID.% + } + \rationale{% + This enables concise declarations of \VOID{} functions. + It is reasonably easy to understand such a function, + because the return type is textually near to the returned expression $e$. + In contrast, \code{\RETURN{} $e$;} in a block body is only allowed + for an $e$ with one of a few specific static types, + because it is less likely that the developer understands + that the returned object will not be used + (\ref{return}).% + } + \item The function is asynchronous, \flatten{T} is not \VOID, + and it would have been a compile-time error + to declare the function with the body + \code{\ASYNC{} \{ \RETURN{} $e$; \}} + rather than \code{\ASYNC{} => $e$}. + \commentary{% + In particular, $e$ can have \emph{any} type + when the flattened return type is \VOID,% + } + \rationale{% + and the rationale is similar to the synchronous case.% + } + \end{itemize} +\end{itemize} + +\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$. +It is a compile-time error if the declared return type of +a function marked \code{\SYNC*} or \code{\ASYNC*} is \VOID. + +\LMHash{}% +We define the +\Index{union-free type derived from} +a type $T$ as follows: +If $T$ is of the form \code{$S$?}\ or the form \code{FutureOr<$S$>} +then the union-free type derived from $T$ is +the union-free type derived from $S$. +Otherwise, the union-free type derived from $T$ is $T$. +\commentary{% +For example, the union-free type derived from +\code{FutureOr?} is \code{int}.% +} + +\LMHash{}% +We define the +\IndexCustom{element type of a generator function}{% + function!generator!element type} +$f$ as follows: +% +Let $S$ be the union-free type derived from the declared return type of $f$. +% +If $f$ is a synchronous generator and +$S$ implements \code{Iterable<$U$>} for some $U$ +(\ref{interfaceSuperinterfaces}) +then the element type of $f$ is $U$. +% +If $f$ is an asynchronous generator and +$S$ implements \code{Stream<$U$>} for some $U$ +then the element type of $f$ is $U$. +% +Otherwise, if $f$ is a generator (synchronous or asynchronous) +and $S$ is a supertype of \code{Object} +(\commentary{which includes \code{Object} itself}) +then the element type of $f$ is \DYNAMIC. +\commentary{No further cases are possible.} + + +\subsection{Function Declarations} +\LMLabel{functionDeclarations} + +\LMHash{}% +A \Index{function declaration} is a function that +is neither a member of a class nor a function literal. +Function declarations include exactly the following: +\IndexCustom{library functions}{function!library}, +which are function declarations +%(including getters and setters) +at the top level of a library, and +\IndexCustom{local functions}{function!local}, +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$ \Index{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 +\Index{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 +\Index{formal type parameter list} (\ref{functions}), +in which case we say that it is a +\IndexCustom{generic function}{function!generic}. +A \IndexCustom{non-generic function}{function!non-generic} +is a function which is not generic. + +\LMHash{}% +The \Index{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 +\IndexCustom{type parameter scope}{scope!type parameter}. +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 + +\noindent +\code{class C{}> \{ \ldots\ \}}, + +\noindent +and the formal type parameters are in scope for each other, +allowing dependencies like +\code{class D \{ \ldots\ \}}.% +} + +\LMHash{}% +The formal parameter list of a function declaration introduces +a new scope known as the function's +\IndexCustom{formal parameter scope}{scope!formal parameter}. +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 +\IndexCustom{body scope}{scope!function body}. +The body scope of a function $f$ is enclosed in the scope introduced by +the formal parameter scope of $f$. + +\LMHash{}% +It is a compile-time error if a formal parameter +is declared as a constant variable (\ref{variables}). + +\begin{grammar} + ::= `(' `)' + \alt `(' `,'? `)' + \alt `(' `,' `)' + \alt `(' `)' + + ::= \gnewline{} + (`,' )* + + ::= + \alt + + ::= \gnewline{} + `[' (`,' )* `,'? `]' + + ::= \gnewline{} + `{' (`,' )* `,'? `}' +\end{grammar} + +\LMHash{}% +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 \Index{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. +\item + As an initializing formal, which is only valid as a parameter to + a generative constructor (\ref{generativeConstructors}). +\item + Via an ordinary variable declaration (\ref{variables}). +\end{itemize} + +\begin{grammar} + ::= \gnewline{} + + + ::= + \alt + \alt + + ::= \gnewline{} + \COVARIANT? ? `?'? + + ::= + \alt \COVARIANT? + + ::= \COVARIANT? + + ::= \gnewline{} + ? \THIS{} `.' ( `?'?)? +\end{grammar} + +\LMHash{}% +It is a compile-time error if a formal parameter has the modifier \CONST{} +or the modifier \LATE. +It is a compile-time error if \VAR{} occurs as +the first token of a \synt{fieldFormalParameter}. + +\LMHash{}% +It is a compile-time error if a parameter derived from +\synt{fieldFormalParameter} occurs as a parameter of a function +which is not a non-redirecting generative constructor. + +\commentary{% +A \synt{fieldFormalParameter} declares an initializing formal, +which is described elsewhere +(\ref{generativeConstructors}).% +} + +\LMHash{}% +It is possible to include the modifier \COVARIANT{} +in some forms of parameter declarations. +The effect of doing this is described in a separate section +(\ref{covariantParameters}). + +\commentary{% +Note that the non-terminal \synt{normalFormalParameter} is also used +in the grammar rules for optional parameters, +which means that such parameters can also be covariant.% +} + +\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} + ::= (`=' )? + + ::= \gnewline{} + \REQUIRED? + \gnewline{} ((`=' | `:') )? +\end{grammar} + +The form \syntax{ `:' } +is equivalent to the form +\syntax{ `=' }. +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.% +} + + +\subsubsection{Covariant Parameters} +\LMLabel{covariantParameters} + +\LMHash{}% +Dart allows formal parameters of instance methods, +including setters and operators, +to be declared \COVARIANT. + +\commentary{% +The syntax for doing this is specified in an earlier section +(\ref{requiredFormals}).% +} + +\LMHash{}% +It is a compile-time error if the modifier \COVARIANT{} occurs +in the declaration of a formal parameter of a function +which is not an instance method, an instance setter, or an operator. + +\commentary{% +As specified below, a parameter can also be covariant for other reasons. +The overall effect of having a covariant parameter $p$ +in the signature of a given method $m$ +is to allow the type of $p$ to be overridden covariantly, +which means that the type required at run time for a given actual argument +may be a proper subtype of the type which is known at compile time +at the call site.% +} + +\rationale{% +This mechanism allows developers to explicitly request that +a compile-time guarantee which is otherwise supported +(namely: that an actual argument whose static type satisfies the requirement +will also do so at run time) +is replaced by dynamic type checks. +In return for accepting these dynamic type checks, +developers can use covariant parameters to express software designs +where the dynamic type checks are known (or at least trusted) to succeed, +based on reasoning that the static type analysis does not capture.% +} + +\LMHash{}% +\BlindDefineSymbol{m, X_j, s}% +Let $m$ be a method signature with formal type parameters +\List{X}{1}{s}, +positional formal parameters \List{p}{1}{n}, +\BlindDefineSymbol{p_j, n, q_j, k}% +and named formal parameters \List{q}{1}{k}. +\BlindDefineSymbol{m', X'_j}% +Let $m'$ be a method signature with formal type parameters +\List{X'\!}{1}{s}, +positional formal parameters \List{p'\!}{1}{n'}, +\BlindDefineSymbol{p'_j, n', q'_j, k'}% +and named formal parameters \List{q'\!}{1}{k'}. +% +Assume that $j \in 1 .. n'$, and $j \leq n$; +we say that $p'_j$ is the parameter in $m'$ that +\IndexCustom{corresponds}{parameter corresponds to parameter} +to the formal parameter $p_j$ in $m$. +Assume that $j \in 1 .. k'$ and $l \in 1 .. k$; +we say that $q'_j$ is the parameter in $m'$ that +\NoIndex{corresponds} to the formal parameter +$q_l$ in $m$ if $q'_j = q_l$. +% +Similarly, we say that the formal type parameter +$X'_j$ from $m'$ +\NoIndex{corresponds} to the formal type parameter +$X_j$ from $m$, for all $j \in 1 .. s$. + +\commentary{% +This includes the case where $m$ respectively $m'$ has +optional positional parameters, +in which case $k = 0$ respectively $k' = 0$ must hold, +but we can have $n \not= n'$. +The case where the numbers of formal type parameters differ is not relevant.% +} + +% Being covariant is a property of a parameter of the interface of a class; +% this means that we only talk about the originating keyword \COVARIANT{} +% and the class that contains the relevant declaration when we detect for +% the first time that a given parameter is covariant. From that point and on +% it is "carried" along the subtype links associated with class interfaces, +% such that we can get it inductively from an indirect superinterface just +% by checking whether the direct superinterfaces "have" a method signature +% with the relevant name and a corresponding parameter, and then checking +% that parameter. The same approach is applicable for covariant-by-class. + +\LMHash{}% +\BlindDefineSymbol{C, m, p}% +Let $C$ be a class that declares +a method $m$ which has +a parameter $p$ whose declaration has the modifier \COVARIANT; +in this case we say that the parameter $p$ is +\IndexCustom{covariant-by-declaration}{parameter!covariant-by-declaration}. +% +In this case the interface of $C$ has the method signature $m$, +and that signature has the parameter $p$; +we also say that the parameter $p$ in this method signature is +\NoIndex{covariant-by-declaration}. +% +Finally, the parameter $p$ of the method signature $m$ +of the interface of a class $C$ is +\NoIndex{covariant-by-declaration} +if a direct superinterface of $C$ +has an accessible method signature $m'$ with the same name as $m$, +which has a parameter $p'$ that corresponds to $p$, +such that $p'$ is covariant-by-declaration. + +\LMHash{}% +Assume that \BlindDefineSymbol{C, X_j, B_j, s}$C$ is a generic class +with formal type parameter declarations +\code{$X_1\ \EXTENDS\ B_1 \ldots,\ X_s\ \EXTENDS\ B_s$}, +\BlindDefineSymbol{m, p, T}% +let $m$ be a declaration of an instance method in $C$ +(which can be a method, a setter, or an operator), +let $p$ be a parameter declared by $m$, and +let $T$ be the declared type of $p$. +% +The parameter $p$ is +\IndexCustom{covariant-by-class}{parameter!covariant-by-class} +if, for any $j \in 1 .. s$, +$X_j$ occurs in a covariant or an invariant position in $T$. +% +In this case the interface of $C$ also has the method signature $m$, +and that signature has the parameter $p$; +we also say that the parameter $p$ in this method signature is +\NoIndex{covariant-by-class}. +Finally, the parameter $p$ of the method signature $m$ +of the interface of the class $C$ is +\NoIndex{covariant-by-class} +if a direct superinterface of $C$ +has an accessible method signature $m'$ with the same name as $m$, +which has a parameter $p'$ that corresponds to $p$, +such that $p'$ is covariant-by-class. + +\LMHash{}% +A formal parameter $p$ is +\IndexCustom{covariant}{parameter!covariant} +if $p$ is covariant-by-declaration or $p$ is covariant-by-class. + +\commentary{% +It is possible for a parameter to be simultaneously +covariant-by-declaration and covariant-by-class. +Note that a parameter may be +covariant-by-declaration or covariant-by-class +based on a declaration in any direct or indirect superinterface, +including any superclass: +The definitions above propagate these properties +to an interface from each of its direct superinterfaces, +but they will in turn receive the property from their direct superinterfaces, +and so on.% +} + + +\subsection{Type of a Function} +\LMLabel{typeOfAFunction} + +\LMHash{}% +This section specifies the static type which is ascribed to +the function denoted by a function declaration, +and the dynamic type of the corresponding function object. + +\LMHash{}% +In this specification, +the notation used to denote the type of a function, +that is, a \Index{function type}, +follows the syntax of the language, +except that \EXTENDS{} is abbreviated to +\FunctionTypeExtends. +This means that every function type is of one of the forms +\FunctionTypePositionalStd{T_0} +\FunctionTypeNamedStd{T_0} + +\noindent +where $T_0$ is the return type, +$X_j$ are the formal type parameters with bounds $B_j$, $j \in 1 .. s$, +$T_j$ are the formal parameter types for $j \in 1 .. n + k$, +and $x_{n+j}$ are the names of named parameters for $j \in 1 .. k$. +Non-generic function types are covered by the case $s = 0$, +where the type parameter declaration list +\code{<\ldots{}>} +as a whole is omitted. +% +Similarly, the optional brackets \code{[]} and \code{\{\}} are omitted +when there are no optional parameters. + +% We promise that the two forms always get the same treatment for k=0. +\commentary{% +Both forms with optionals cover function types with no optionals when $k = 0$, +and every rule in this specification is such that +any of the two forms may be used without ambiguity +to determine the treatment of function types with no optionals.% +} + +\LMHash{}% +If a function declaration does not declare a return type explicitly, +its return type is \DYNAMIC{} (\ref{typeDynamic}), +unless it is a constructor, +in which case it is not considered to have a return type, +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 for each type parameter the upper bound, +which is considered to be the built-in class \code{Object} +if no bound is specified. +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 formal type parameter names in function types +because they are needed in order to express such things as relations among +different type parameters, F-bounds, and the types of formal parameters. +However, we do not wish to distinguish between 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 \DefineSymbol{s} of formal type parameters is zero then +the type parameter list in the function type is omitted. + +\LMHash{}% +Let $F$ be a function with +type parameters \TypeParametersStd, +required formal parameter types \List{T}{1}{n}, +return type $T_0$, +and no optional parameters. +Then the static type of $F$ is +\FunctionTypeAllRequiredStd{T_0}. + +\LMHash{}% +Let $F$ be a function with +type parameters \TypeParametersStd, +required formal parameter types \List{T}{1}{n}, +return type $T_0$ +and positional optional parameter types \List{T}{n+1}{n+k}. +Then the static type of $F$ is +\FunctionTypePositionalStd{T_0}. + +\LMHash{}% +Let $F$ be a function with +type parameters \TypeParametersStd, +required formal parameter types \List{T}{1}{n}, +return type $T_0$, +and named parameters \PairList{T}{x}{n+1}{n+k}, +where $x_{n+j}$, $j \in 1 .. k$ may or may not have a default value. +Then the static type of $F$ is +\FunctionTypeNamedStd{T_0}. + +\LMHash{}% +Let $T$ be the static type of a function declaration $F$. +Let $u$ be the run-time type of a function object $o$ obtained by +function closurization +(\ref{functionClosurization}) +or instance method closurization +(\ref{instanceMethodClosurization}) +applied to $F$, +and let $t$ be the actual type corresponding to $T$ +at the occasion where $o$ was created +(\ref{actualTypes}). +\commentary{% +$T$ may contain free type variables, but $t$ contains their actual values.% +} +The following must then hold: +$u$ is a class that implements the built-in class \FUNCTION; +$u$ is a subtype of $t$; +and $u$ is not a subtype of any function type which is a proper subtype of $t$. +\commentary{% +If we had omitted the last requirement then +\code{f \IS{} int\,\FUNCTION([int])} +could evaluate to \TRUE{} with the declaration +\code{\VOID{} f()\,\{\}}, +which is obviously not the intention.% +} + +\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, e.g., +one cannot assume that any two distinct function objects +will necessarily have the same run-time type.% +} + + +\subsection{External Functions} +\LMLabel{externalFunctions} + +\LMHash{}% +An \IndexCustom{external function}{function!external} +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 \emph{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{}% +An implementation specific compile-time error can be raised +at an \EXTERNAL{} function declaration. + +\commentary{% +Such errors are intended to indicate that +every invocation of that function would throw, e.g., +because it is known that it will not be connected to a body.% +} + +\LMHash{}% +The actual syntax is given in +sections \ref{classes} and \ref{librariesAndScripts} below. + + +\section{Classes} +\LMLabel{classes} + +\LMHash{}% +A \Index{class} defines the form and behavior of a set of objects which are its +\IndexCustom{instances}{instance}. +Classes may be defined by class declarations as described below, +or via mixin applications (\ref{mixinApplication}). + +\begin{grammar} + ::= + \ABSTRACT? \CLASS{} ? + \gnewline{} ? ? + \gnewline{} `{' ( )* `}' + \alt \ABSTRACT? \CLASS{} + + ::= (`,' )* + + ::= `;' + \alt + + ::= ? + \alt + \alt \STATIC? + \alt \STATIC? + \alt \STATIC? + \alt + + ::= \EXTERNAL{} + \alt \EXTERNAL{} + \alt \EXTERNAL{} + \alt (\EXTERNAL{} \STATIC?)? + \alt (\EXTERNAL{} \STATIC?)? + \alt (\EXTERNAL{} \STATIC?)? + \alt \EXTERNAL? + \alt \STATIC{} \CONST{} ? + \alt \STATIC{} \FINAL{} ? + \alt \STATIC{} \LATE{} \FINAL{} ? + \alt \STATIC{} \LATE? + \alt \COVARIANT{} \LATE{} \FINAL{} ? + \alt \COVARIANT{} \LATE? + \alt \LATE? \FINAL{} ? + \alt \LATE? + \alt + \alt ( | )? + \alt ( | )? + + ::= \gnewline{} + (`,' )* + + ::= `=' +\end{grammar} + +\LMHash{}% +It is possible to include the modifier \COVARIANT{} +in some forms of declarations. +The effect of doing this is described elsewhere +(\ref{covariantParameters}). + +\LMHash{}% +A class has constructors, instance members and static members. +The \IndexCustom{instance members}{members!instance} of a class +are its instance methods, getters, setters and instance variables. +The \IndexCustom{static members}{members!static} of a class +are its static methods, getters, setters, and variables. +The \IndexCustom{members}{members} of a class +are its static and instance members. + +\LMHash{}% +A class declaration introduces two scopes: +\begin{itemize} +\item + A \IndexCustom{type-parameter scope}{scope!type parameter}, + which is empty if the class is not generic (\ref{generics}). + The enclosing scope of the type-parameter scope of a class declaration is + the library scope of the current library. +\item + A \IndexCustom{body scope}{scope!class body}. + The enclosing scope of the body scope of a class declaration is + the type parameter scope of the class declaration. +\end{itemize} + +\LMHash{}% +The current scope of an instance member declaration, +a static member declaration, +or a constructor declaration is +the body scope of the class in which it is declared. + +\LMHash{}% +The current instance +(\commentary{and hence its members}) +can only be accessed at specific locations in a class: +We say that a location $\ell$ +\IndexCustom{has access to \THIS}{has access to this@has access to \THIS} +if{}f $\ell$ is inside the body of a declaration of +an instance member or a generative constructor, +or in the initializing expression of a \LATE{} instance variable declaration. + +\commentary{% +Note that an initializing expression for a non-\LATE{} instance variable +does not have access to \THIS, +and neither does any part of a declaration marked \STATIC.% +} + +\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 \IndexCustom{abstract class declaration}{class declaration!abstract} +is a class declaration that is explicitly declared +with the \ABSTRACT{} modifier. +A \IndexCustom{concrete class declaration}{class declaration!concrete} +is a class declaration that is not abstract. +An \IndexCustom{abstract class}{class!abstract} is a class +whose declaration is abstract, and +a \IndexCustom{concrete class}{class!concrete} is a class +whose declaration is concrete. + +\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.% +} + +\commentary{% +The interface of a class $C$ is +an implicit interface that declares instance member signatures +that correspond to the instance members declared by $C$, +and whose direct superinterfaces are +the direct superinterfaces of $C$ +(\ref{interfaces}, \ref{superinterfaces}).% +} + +\LMHash{}% +When a class name appears as a type, +that name denotes the interface of the class. + +\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$, +or if $G$ has a member whose basename is $X$, +or if $G$ has a constructor named \code{$G$.$X$}. + +\commentary{% +Here are simple examples, that illustrate the difference between +``has a member'' and ``declares a member''. +For example, \code{B} \IndexCustom{declares}{declares member} +one member named \code{f}, +but it \IndexCustom{has}{has member} 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} + // \comment{with instance getter \& setter} +\\ + // \comment{compile-time error: static method conflicts with instance method} + \STATIC{} f(x) => 3; +\} +\end{dartCode} + + +\subsection{Fully Implementing an Interface} +\LMLabel{fullyImplementingAnInterface} + +% Note that rules here and in \ref{instanceMethods} overlap, but they are +% both needed: This section is concerned with concrete methods, including +% inherited ones, and \ref{instanceMethods} is concerned with instance +% members declared in $C$, including both concrete and abstract ones. + +\LMHash{}% +% The use of `concrete member' below may seem redundant, because a class +% does not inherit abstract members from its superclass, but this +% underscores the fact that even when an abstract declaration of $m$ is +% declared in $C$, $C$ does not "have" an $m$ which will suffice here. +A concrete class must fully implement its interface. +\BlindDefineSymbol{C, I, m}% +Let $C$ be a concrete class declared in library $L$, with interface $I$. +Assume that $I$ has a member signature $m$ which is accessible to $L$. +It is a compile-time error if $C$ does not have +a concrete member with the same name as $m$ and accessible to $L$, +unless $C$ has a non-trivial \code{noSuchMethod} +(\ref{theMethodNoSuchMethod}). + +\LMHash{}% +Each concrete member must have a suitable signature: +Assume that $C$ has a concrete member with +the same name as $m$ and accessible to $L$, +and let \DefineSymbol{m''} be its member signature. +\commentary{% +The concrete member may be declared in $C$ or inherited from a superclass.% +} +Let \DefineSymbol{m'} be the member signature which is obtained from $m''$ +by adding, if not present already, the modifier \COVARIANT{} +(\ref{covariantParameters}) +to each parameter $p$ in $m''$ where +the corresponding parameter in $m$ has the modifier \COVARIANT. +It is a compile-time error if $m'$ is not a correct override of $m$ +(\ref{correctMemberOverrides}), +unless that concrete member is a \code{noSuchMethod} forwarder +(\ref{theMethodNoSuchMethod}). + +\commentary{% +Consider a concrete class \code{C}, +and assume that \code{C} declares or inherits +a member implementation with the same name +for every member signature in its interface. +It is still an error if one or more of those member implementations +has parameters or types such that they do not satisfy +the corresponding member signature in the interface. +For this check, any missing \COVARIANT{} modifiers are implicitly added +to the signature of an inherited member (this is how we get $m'$ from $m''$). +When the modifier \COVARIANT{} is added to one or more parameters +(which will only happen when the concrete member is inherited), +an implementation may choose to implicitly induce a forwarding method +with the same signature as $m'$, +in order to perform the required dynamic type check, +and then invoke the inherited method.% +} + +\LMHash{}% +It is an implementation specific choice whether or not +an implicitly induced forwarding method is used +when the modifier \COVARIANT{} is added to +one or more parameters in $m'$. + +\commentary{% +This is true in spite of the fact that such forwarding methods can be observed. +E.g., we can compare +the run-time type of a tearoff of the method from +a receiver of type \code{C} +to the run-time type of a tearoff of the super-method from +a location in the body of \code{C}.% +} + +\LMHash{}% +With or without a forwarding method, +the member signature in the interface of $C$ is $m$. + +\commentary{% +The forwarding method does not change the interface of \code{C}, +it is an implementation detail. +In particular, this holds even in the case where +an explicit declaration of the forwarding method would have +changed the interface of \code{C}, because $m'$ is a subtype of $m$. + +When a class has a non-trivial \code{noSuchMethod}, +the class may leave some members unimplemented, +and the class is allowed to have a \code{noSuchMethod} forwarder +which does not satisfy the class interface +(in which case it will be overridden by another \code{noSuchMethod} forwarder). + +Here is an example:% +} + +\begin{dartCode} +\CLASS\ B \{ + \VOID\ m(int i) \{\} // \comment{Signature $m''$: \VOID\ m(int).} +\} +\\ +\ABSTRACT\ \CLASS\ I \{ + \VOID\ m(\COVARIANT\ num n); // \comment{Signature: \VOID\ m(\COVARIANT\ num).} +\} +\\ +\CLASS\ C \EXTENDS\ B \IMPLEMENTS\ I \{ + // \comment{Signature $m$: \VOID\ m(\COVARIANT\ num).} + // + // \comment{To check that this class fully implements its interface,} + // \comment{check that $m'$, that is, \VOID\ m(\COVARIANT\ int),} + // \comment{correctly overrides $m$: OK!} +\} +\end{dartCode} + +\LMHash{}% +Parameters that are covariant-by-declaration +must also satisfy the following constraint: +Assume that the parameter $p$ of $m'$ has the modifier \COVARIANT. +Assume that a direct or indirect superinterface of $C$ has +a method signature $m_s$ with the same name as $m'$ and accessible to $L$, +such that $m_s$ has a parameter $p_s$ that corresponds to $p$. +In this situation, a compile-time error occurs +if the type of $p$ is not a subtype and not a supertype of the type of $p_s$. + +\commentary{% +This ensures that an inherited method satisfies the same constraint +for each formal parameter which is covariant-by-declaration +as the constraint which is specified for a declaration in $C$ +(\ref{instanceMethods}).% +} + + +\subsection{Instance Methods} +\LMLabel{instanceMethods} + +\LMHash{}% +\IndexCustom{Instance methods}{method!instance} +are functions (\ref{functions}) +whose declarations are immediately contained within a class declaration +and that are not declared \STATIC. +The \Index{instance methods of a class} $C$ are +the instance methods declared by $C$ +and the instance methods inherited by $C$ from its superclass +(\ref{inheritanceAndOverriding}). + +\LMHash{}% +\BlindDefineSymbol{C, D, m}% +Consider a class $C$ +and an instance member declaration $D$ in $C$, with member signature $m$ +(\ref{interfaces}). +It is a compile-time error if $D$ overrides a declaration +% Note that $m'$ is accessible, due to the definition of `overrides'. +with member signature $m'$ +from a direct superinterface of $C$ +(\ref{interfaceInheritanceAndOverriding}), +unless $m$ is a correct member override of $m'$ +(\ref{correctMemberOverrides}). + +\commentary{% +This is not the only kind of conflict that may exist: +An instance member declaration $D$ may conflict with another declaration $D'$, +even in the case where they do not have the same name +or they are not the same kind of declaration. +E.g., $D$ could be an instance getter and $D'$ a static setter +(\ref{classMemberConflicts}).% +} + +\LMHash{}% +For each parameter $p$ of $m$ where \COVARIANT{} is present, +it is a compile-time error if there exists +a direct or indirect superinterface of $C$ which has +an accessible method signature $m''$ with the same name as $m$, +such that $m''$ has a parameter $p''$ that corresponds to $p$ +(\ref{covariantParameters}), +unless the type of $p$ is a subtype or a supertype of the type of $p''$. + +\commentary{% +This means that +a parameter which is covariant-by-declaration can have a type +which is a supertype or a subtype of the type of +a corresponding parameter in a superinterface, +but the two types cannot be unrelated. +Note that this requirement must be satisfied +for each direct or indirect superinterface separately, +because that relationship is not transitive.% +} + +\rationale{% +The superinterface may be the statically known type of the receiver, +so this means that we relax the potential typing relationship +between the statically known type of a parameter and the +type which is actually required at run time +to the subtype-or-supertype relationship, +rather than the strict supertype relationship +which applies to a parameter which is not covariant. +It should be noted that it is not statically known +at the call site whether any given parameter is covariant, +because the covariance could be introduced in +a proper subtype of the statically known type of the receiver. +We chose to give priority to flexibility rather than safety here, +because the whole point of covariant parameters is that developers +can make the choice to increase the flexibility +in a trade-off where some static type safety is lost.% +} + + +\subsubsection{Operators} +\LMLabel{operators} + +\LMHash{}% +\IndexCustom{Operators}{operators} are instance methods with special names, +except for operator \lit{[]} which is an instance getter +and operator \lit{[]=} which is an instance setter. + +\begin{grammar} + ::= \gnewline{} + ? \OPERATOR{} + + ::= `~' + \alt + \alt `[]' + \alt `[]=' + + ::= + \alt + \alt + \alt + \alt `==' + \alt +\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: +\lit{<}, +\lit{>}, +\lit{<=}, +\lit{>=}, +\lit{==}, +\lit{-}, +\lit{+}, +\lit{/}, +\lit{\gtilde/}, +\lit{*}, +\lit{\%}, +\lit{|}, +\lit{\^}, +\lit{\&}, +\lit{\ltlt}, +\lit{\gtgtgt}, +\lit{\gtgt}, +\lit{[]=}, +\lit{[]}, +\lit{\gtilde}. + +\LMHash{}% +It is a compile-time error if the arity of the user-declared operator +\lit{[]=} is not 2. +It is a compile-time error if the arity of a user-declared operator +with one of the names: +\lit{<}, +\lit{>}, +\lit{<=}, +\lit{>=}, +\lit{==}, +\lit{-}, +\lit{+}, +\lit{\gtilde/}, +\lit{/}, +\lit{*}, +\lit{\%}, +\lit{|}, +\lit{\^}, +\lit{\&}, +\lit{\ltlt}, +\lit{\gtgtgt}, +\lit{\gtgt}, +\lit{[]} +is not 1. +It is a compile-time error if the arity of the user-declared operator +\lit{-} +is not 0 or 1. + +\commentary{% +The \lit{-} 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 \lit{-} 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 +\lit{\gtilde} +is not 0. + +\LMHash{}% +It is a compile-time error to declare an optional parameter in an operator. + +\LMHash{}% +It is a compile-time error if a user-declared operator \lit{[]=} +declares a return type other than \VOID. + +\commentary{% +If no return type is specified for a user-declared operator +\lit{[]=}, +its return type is \VOID{} (\ref{typeOfAFunction}).% +} + +\rationale{% +The return type is \VOID{} because +a return statement in an implementation of operator +\lit{[]=} +does not return an object. +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 object $o$. +$e$ will then evaluate to $o$, +and even if the executed body of operator +\lit{[]=} +completes with an object $o'$, +that is, if $o'$ is returned it is simply ignored. +The rationale for this behavior is that +assignments should be guaranteed to evaluate to the assigned object.% +} + + +\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 \CALL, because we would have a +% compile-time error invoking \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$ \Index{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{}% +\BlindDefineSymbol{C, L, m}% +Let $C$ be a concrete class, +let $L$ be the library that contains the declaration of $C$, +and let $m$ be a name. +Then $m$ is \Index{noSuchMethod forwarded} in $C$ if{}f +one of the following is true: + +\begin{itemize} +\item \textbf{Requested in program:} + $C$ has a non-trivial \code{noSuchMethod}, + the interface of $C$ contains a member signature $S$ named $m$, + and $C$ has no concrete member named $m$ and accessible to $L$ + that correctly overrides $S$ + (\commentary{% + that is, no member named $m$ is declared or inherited by $C$, + or one is inherited, but it does not have the required signature% + }). + In this case we also say that $S$ is noSuchMethod forwarded. +\item + \textbf{Forced by privacy:} + There exists a direct or indirect superinterface + $D$ of $C$ which is declared in a library $L_2$ different from $L$, + the interface of $D$ contains a member signature $S$ named $m$, + $m$ is a private name, + and no superclass of $C$ has + a concrete member named $m$ accessible to $L_2$ + that correctly overrides $S$. + In this case we also say that $S$ is noSuchMethod forwarded. +\end{itemize} + +\LMHash{}% +For a concrete class $C$, a +\Index{noSuchMethod forwarder} +is implicitly induced for each member signature +which is noSuchMethod forwarded. + +\LMHash{}% +It is a compile-time error if the name $m$ is noSuchMethod forwarded +in a concrete class $C$, +and a superclass of $C$ has an accessible concrete declaration of $m$ +which is not a noSuchMethod forwarder. + +\LMHash{}% +%% TODO(eernst): We used to say `the interface of $C$ or $D$'; but we +%% need to change `accessible' to a scheme similar to name-merging everywhere +%% in order to be able to say this precisely. +A noSuchMethod forwarder is a concrete member of $C$ +with the signature taken from the interface of $C$, +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{instanceMethodClosurization}) +using a property extraction +(\ref{propertyExtraction}). + +\commentary{% +The error concerned with an implictly induced forwarder +that would override a human-written declaration +can only occur 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: noSuchMethod forwarder cannot 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.% +} + +\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 or another noSuchMethod forwarder 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{}% +\BlindDefineSymbol{C, m, X_j, r}% +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 +\BlindDefineSymbol{a_j, k, x_j, n}% +\code{$a_1,\ \ldots,\ a_k$} +(\commentary{some of which may be optional when $n = 0$}), +and named formal parameters with names +\code{$x_1,\ \ldots,\ x_n$} +(\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 $n = 0$.% +} + +\LMHash{}% +The execution of the body of $m$ creates +an instance \DefineSymbol{im} of the predefined class \code{Invocation} +such that: + +\begin{itemize} +\item \code{$im$.isMethod} evaluates to \TRUE{} if{}f $m$ is a method. +\item \code{$im$.isGetter} evaluates to \TRUE{} if{}f $m$ is a getter. +\item \code{$im$.isSetter} evaluates to \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 + whose dynamic type implements \code{List}, + containing the same objects as the list resulting from evaluation of + \code{[$a_1, \ldots,\ a_k$]}. +\item \code{$im$.namedArguments} evaluates to an unmodifiable map + whose dynamic type implements \code{Map}, + with the same keys and values as the map resulting from evaluation of + + \code{\{$\#x_1$: $x_1, \ldots,\ \#x_m$: $x_m$\}}. +\item \code{$im$.typeArguments} evaluates to an unmodifiable list + whose dynamic type implements \code{List}, + containing the same objects as the list resulting from evaluation of + \code{[$X_1, \ldots,\ X_r$]}. +\end{itemize} + +\LMHash{}% +Next, \code{noSuchMethod} is invoked with $im$ 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} + + +\subsubsection{The Operator `==' and Primitive Equality} +\LMLabel{theOperatorEqualsEquals} + +\LMHash{}% +The operator \lit{==} is used implicitly in certain situations, +and in particular constant expressions +(\ref{constants}) +give rise to constraints on that operator. +The situation is similar with the getter \code{hashCode}. +In order to specify these constraints just once we introduce the notion of +\Index{primitive equality}. + +\rationale{% +Certain constant expressions are known to have a value +whose equality is primitive. +This is useful to know because it allows +the value of equality expressions +and the value of invocations of \code{hashCode} +to be computed at compile-time. +In particular, this can be used to build +constant collections at compile-time, +and it can be used to check that +all elements in a constant set are distinct, +and all keys in a constant map are distinct.% +} + +\begin{itemize} +\item The null object has primitive equality + (\ref{null}). +\item Every instance of type \code{bool}, \code{int}, and \code{String} + has primitive equality. +\item Every instance of type \code{Symbol} + which was originally obtained by evaluation of a literal symbol or + a constant invocation of a constructor of the \code{Symbol} class + has primitive equality. +\item + %% TODO(eernst): With Dart 2.15, we need to mention `List` here, + %% unless 'constant type literal' includes that case. + Every instance of type \code{Type} + which was originally obtained by evaluating a constant type literal + (\ref{dynamicTypeSystem}) + has primitive equality. +\item + Let $o$ be an object obtained by evaluation of a constant list literal + (\ref{lists}), + a constant map literal + (\ref{maps}), or + a constant set literal + (\ref{sets}), + then $o$ has primitive equality. +\item + %% TODO(eernst): With Dart 2.15, consider `f`. + A function object obtained by function closurization of + a static method or a top-level function + (\ref{functionClosurization}) + as the value of a constant expression + has primitive equality. +\item + An instance $o$ has primitive equality + if the dynamic type of $o$ is a class $C$, + and $C$ has primitive equality. +\item + The class \code{Object} has primitive equality. +\item + A class $C$ has primitive equality + if it does not have an implementation of the operator \lit{==} + that overrides the one inherited from \code{Object}, + and it does not have an implementation of the getter \code{hashCode} + that overrides the one inherited from \code{Object}. +\end{itemize} + +\LMHash{}% +When we say that a given instance or class +\IndexCustom{does not have primitive equality}{% + primitive equality!does not have}, +it means that it is not true that said instance or class +has primitive equality. + + +\subsection{Getters} +\LMLabel{getters} + +\LMHash{}% +Getters are functions (\ref{functions}) that are used +to retrieve the values of object properties. + +\begin{grammar} + ::= ? \GET{} +\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. + +\LMHash{}% +The \Index{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 \Index{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. +The rules for when a getter correctly overrides another member +are given elsewhere +(\ref{correctMemberOverrides}).% +} + + +\subsection{Setters} +\LMLabel{setters} + +\LMHash{}% +Setters are functions (\ref{functions}) that are used to set +the values of object properties. + +\begin{grammar} + ::= ? \SET{} +\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. + +\commentary{% +Hence, a setter name can never conflict with, override or be overridden by +a getter or method.% +} + +\LMHash{}% +The \Index{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 \Index{static setters of a class} $C$ are +those static setters declared by $C$, +either implicitly or explicitly. + +\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 error if a setter declares a return type other than \VOID. +It is a compile-time error if a class has +a setter named \code{$v$=} with argument type $T$ and +a getter named $v$ with return type $S$, +and $S$ may not be assigned to $T$. + +\commentary{% +The rules for when a setter correctly overrides another member +are given elsewhere +(\ref{correctMemberOverrides}). +A setter declaration may conflict with other declarations as well +(\ref{classMemberConflicts}).% +} + + +\subsection{Abstract Instance Members} +\LMLabel{abstractInstanceMembers} + +\LMHash{}% +An \IndexCustom{abstract method}{method!abstract} +(respectively, +\IndexCustom{abstract getter}{getter!abstract} or +\IndexCustom{abstract setter}{setter!abstract}) +is an instance method, getter or setter that is not declared \EXTERNAL{} +and does not provide an implementation. +A \IndexCustom{concrete method}{method!concrete} +(respectively, +\IndexCustom{concrete getter}{getter!concrete} or +\IndexCustom{concrete setter}{setter!concrete}) +is an instance method, getter or setter that is not abstract. + +\rationale{% +Abstract instance members are useful because of their interplay with classes. +Every Dart class induces an implicit interface, +and Dart does not support specifying interfaces explicitly. +Using an abstract class instead of a traditional 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.% +} + +\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 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.% +} + +\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{}% +\IndexCustom{Instance variables}{variables!instance} +are variables whose declarations +are immediately contained within a class declaration +and that are not declared \STATIC. +The \Index{instance variables of a class} $C$ are +the 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 variable. +An instance getter for it can always be defined manually if desired.% +} + +\LMHash{}% +It is possible for the declaration of an instance variable +to include the modifier \COVARIANT{} +(\ref{variables}). +The effect of this is that the formal parameter of +the corresponding implicitly induced setter +is considered to be covariant-by-declaration +(\ref{covariantParameters}). + +\commentary{% +The modifier \COVARIANT{} on an instance variable has no other effects. +In particular, the return type of the implicitly induced getter +can already be overridden covariantly without \COVARIANT, +and it can never be overridden to a supertype or an unrelated type, +regardless of whether the modifier \COVARIANT{} is present.% +} + + +\subsection{Constructors} +\LMLabel{constructors} + +\LMHash{}% +A \Index{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 \Index{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 +\IndexCustom{function type of a constructor}{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 body scope of $C$, where $X_1, \ldots, X_m$ are in scope.% +} + +\commentary{% +A constructor declaration may conflict with static member declarations +(\ref{classMemberConflicts}).% +} + +\commentary{% +A constructor declaration does not introduce a name into a scope. +If a function expression invocation +(\ref{functionExpressionInvocation}) +or an instance creation +(\ref{instanceCreation}) +denotes a constructor as +$C$, \code{$prefix$.$C$}, \code{$C$.\id}, or \code{\metavar{prefix}.$C$.\id}, +resolution relies on the library scope to determine the class +(possibly via an import prefix). +The class declaration is then directly checked for +whether it has a constructor named $C$ respectively \code{$C$.\id}. +It is not possible for an identifier to directly refer to a constructor, +since the constructor is not in any scope used for resolving identifiers.% +} + +\LMHash{}% +If{}f no constructor is specified for a class $C$, +it implicitly has a default constructor \code{C():\ \SUPER()\ \{\}}, +unless $C$ is the built-in class \code{Object}. +%% TODO(eernst): With null safety, add `or \code{Null}`. + + +\subsubsection{Generative Constructors} +\LMLabel{generativeConstructors} + +\LMHash{}% +A \IndexCustom{generative constructor}{constructor!generative} +declaration consists of a constructor name, a formal parameter list +(\ref{formalParameters}), +and either a redirect clause or an initializer list and an optional body. + +\begin{grammar} + ::= + + ::= (`.' )? +\end{grammar} + +\commentary{% +See \synt{declaration} and \synt{methodSignature} for grammar rules +introducing a redirection or an initializer list and a body.% +} + +%% TODO(eernst): Add `\Error{...}` below when that command is added. +\LMHash{}% +A compile-time error occurs if a generative constructor declaration +has a body of the form `\code{=>\,\,$e$;}'. + +\commentary{% +In other function declarations, +this kind of body is taken to imply that the value of $e$ is returned, +but generative constructors do not return anything.% +} + +\LMHash{}% +If a formal parameter declaration $p$ is derived from +\synt{fieldFormalParameter}, +it declares an \Index{initializing formal parameter}. +A term of the form \code{\THIS.\id} is contained in $p$, +and \id{} is the \NoIndex{name} of $p$. +It is a compile-time error if \id{} is not also the name of +an instance variable of the immediately enclosing class or enum. + +\LMHash{}% +It is a compile-time error for an initializing formal parameter +to occur in any function which is not a generative constructor. +Also, it is a compile-time error for an initializing formal parameter +to occur in a redirecting or external constructor. +\commentary{In particuar, there is always an enclosing class or enum.} + +\LMHash{}% +Assume that $p$ is a declaration of an initializing formal parameter named \id. +Let $T_{id}$ be the type of the instance variable named \id{} in +the immediately enclosing class or enum. +If $p$ has a type annotation $T$ then the declared type of $p$ is $T$. +Otherwise, the declared type of $p$ is $T_{id}$. +It is a compile-time error if the declared type of $p$ +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 +\IndexCustom{formal parameter initializer scope}{% + scope!formal parameter initializer}, +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, +% This can occur due to a failing implicit cast. +unless the assigned object has a dynamic type +which is not a subtype of the declared type of the instance variable \id, +in which case a dynamic 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 \Index{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 +\IndexCustom{redirecting}{constructor!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} + ::= `:' \THIS{} (`.' )? +\end{grammar} + +\def\ConstMetavar{\mbox{\CONST?}} + +\LMHash{}% +\BlindDefineSymbol{C, X_j, B_j, m}% +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, +\BlindDefineSymbol{\ConstMetavar}% +$\ConstMetavar$ stands for either \CONST{} or nothing, +$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$, +\BlindDefineSymbol{N, \id}% +and \id{} is an identifier. +Consider a declaration of a redirecting generative constructor +of one of the forms + +\noindent +\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 +\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 + +\noindent +\code{$\THIS{}$($e_1 \ldots,\ e_p,\ x_1$:\ $e_{p+1}, \ldots,\ x_q$:\ $e_{p+q}$)} + +\noindent +\code{$\THIS.\id$($e_1 \ldots,\ e_p,\ x_1$:\ $e_{p+1}, \ldots,\ x_q$:\ $e_{p+q}$)}. + +\LMHash{}% +The +\IndexCustom{redirectee constructor}{constructor!redirectee} +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{}% +A redirecting generative constructor $q'$ is \Index{redirection-reachable} +from a redirecting generative 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 generative constructor +is redirection-reachable from itself. + +\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{}% +% This error can occur due to a failed implicit cast. +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{actualTypes}) +of the corresponding formal parameter in the declaration of $k$. +% This error can occur due to a failed implicit cast. +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{actualTypes}) +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 \Index{initializers}. + +\commentary{% +There are three kinds of initializers. +\begin{itemize} +\item[$\bullet$] A \emph{superinitializer} identifies a + \emph{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 \emph{instance variable initializer} + assigns an object to an individual instance variable. +\item[$\bullet$] An assertion. +\end{itemize}% +} + +\begin{grammar} + ::= `:' (`,' )* + + ::= \SUPER{} + \alt \SUPER{} `.' + \alt + \alt + + ::= \gnewline{} + (\THIS{} `.')? `=' + + ::= \gnewline{} + + \alt + \alt + \alt +\end{grammar} + +%% TODO(eernst): When #54262 is resolved, delete the next paragraph. +%% If is changed such that it derives , +%% the following error will simply be a property of the grammar rule +%% because will _not_ derive . +\LMHash{}% +As a special disambiguation rule, +an \synt{initializerExpression} can not derive a \synt{functionExpression}. + +\rationale{% +This resolves a near-ambiguity: +In \code{A()\,:\,\,x\,\,=\,\,()\,\,\{\,\ldots\,\}}, +\code{x} could be initialized to the empty record, +and the block could be the body of the constructor. +Alternatively, \code{x} could be initialized to a function object, +and the constructor would then not have a body. +It would only be known which case we have when we encounter +(or do not encounter) +a semicolon at the very end. +That was considered unreadable. +Hence, parsers can commit to not parsing a function expression +in this situation. +Note that it is still possible for \synt{initializerExpression} to derive +a term that contains a function expression as a subterm, e.g., +\code{A()\,:\,\,x\,\,=\,\,(()\,\,\{\,\ldots\,\});}.% +} + +\LMHash{}% +An initializer of the form \code{$v$ = $e$} is equivalent to +an initializer of the form \code{\THIS.$v$ = $e$}, +and both forms are called \Index{instance variable initializers}. +It is a compile-time error if the enclosing class +does not declare an instance variable named $v$. +It is a compile-time error unless the static type of $e$ +is assignable to the declared type of $v$. + +\LMHash{}% +Consider a \Index{superinitializer} $s$ of the form + +\noindent +\code{\SUPER($a_1, \ldots,\ a_n,\ x_{n+1}:\ a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)} +respectively + +\noindent +\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 \DefineSymbol{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 \DefineSymbol{f} be a final instance variable declared in +the immediately enclosing class or enum. +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{}% +\BlindDefineSymbol{k, T, i}% +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 or enum bound to +a set of actual type arguments of $T$, \DefineSymbol{\List{t}{1}{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 + +\noindent +\code{\THIS.$g$($a_1, \ldots,\ a_n,\ x_{n+1}$:\ $a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)} + +where \DefineSymbol{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 or enum bound to +\List{t}{1}{m}. + +\LMHash{}% +Otherwise, $k$ is not redirecting. +Execution then proceeds as follows: + +\LMHash{}% +The instance variable declarations of the immediately enclosing class or enum +are visited in the order they appear in the program text. +For each such declaration $d$, if $d$ has the form +\code{\synt{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 or enum +is not yet bound to an object, +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 +\DefineSymbol{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$. +% This error can occur due to an implicit cast. +It is a dynamic type error if the dynamic type of $o$ is not +a subtype of the actual type +(\ref{actualTypes}) +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 \DefineSymbol{s} of the form + +\noindent +\code{\SUPER($a_1, \ldots,\ a_n,\ x_{n+1}:\ a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)} +respectively + +\noindent +\code{\SUPER.\id($a_1, \ldots,\ a_n,\ x_{n+1}$:\ $a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)}. + +\LMHash{}% +\BlindDefineSymbol{C, S, u_j, p}% +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 the actual bindings \List{t}{1}{m} +of the formal type parameters of $C$ +in the superclass as specified in the header of $C$. +Let \DefineSymbol{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 \IndexCustom{factory}{constructor!factory} +is a constructor prefaced by the built-in identifier +(\ref{identifierReference}) +\FACTORY. + +\begin{grammar} + ::= \gnewline{} + \CONST? \FACTORY{} +\end{grammar} + +\LMHash{}% +The 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 +%% TODO(eernst): Come Dart 3.0, add 'mixin'. +the immediately enclosing class or enum. + +\LMHash{}% +% This error can occur due to an implicit cast. +It is a dynamic type error if a factory returns a non-null object +whose type is not a subtype of its actual +(\ref{actualTypes}) +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 \IndexCustom{redirecting factory constructor}{constructor!redirecting factory} +specifies a call to a constructor of another class that is to be used +whenever the redirecting constructor is called. + +\begin{grammar} + ::= \gnewline{} + \CONST? \FACTORY{} `=' \gnewline{} + + + ::= + \alt + \alt (`.' )? +\end{grammar} + +Assume that +\BlindDefineSymbol{C, X_j, B_j, m}% +\code{$C$<$X_1\ \EXTENDS\ B_1 \ldots,\ X_m\ \EXTENDS\ B_m$>} +is the name and formal type parameters of the enclosing class, +\BlindDefineSymbol{\ConstMetavar, N}% +$\ConstMetavar$ is \CONST{} or empty, +$N$ is $C$ or $C.\id_0$ for some identifier $\id_0$, +and \DefineSymbol{\id} is an identifier, +then consider a declaration of a redirecting factory constructor +\DefineSymbol{k} of one of the forms + +\begin{normativeDartCode} +$\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{normativeDartCode} + +\noindent +\BlindDefineSymbol{R, T}% +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 +\IndexCustom{redirectee constructor}{constructor!redirectee} +for this declaration is the constructor \DefineSymbol{k'} denoted by $R$. + +\LMHash{}% +A redirecting factory constructor $q'$ is \Index{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. + +\rationale{% +Default values specified in $k$ would be ignored, +since it is the \emph{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 \DefineSymbol{\List{T}{1}{m}} be the actual type arguments passed to $k'$ +in the declaration of $k$. +Let \DefineSymbol{\List{X}{1}{m}} be the formal type parameters declared by +the class that contains the declaration of $k'$. +Let \DefineSymbol{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 +%% TODO(eernst): Come Dart 3.0, add 'mixin'. +the interface of the class or enum that immediately encloses $k$.% +} + +\LMHash{}% +For the dynamic semantics, +assume that \DefineSymbol{k} is a redirecting factory constructor +and \DefineSymbol{k'} is the redirectee of $k$. + +\LMHash{}% +% This error can occur due to an implicit cast. +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{actualTypes}) +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 \IndexCustom{constant constructor}{constructor!constant} +may be used to create compile-time constant (\ref{constants}) objects. +A constant constructor is prefixed by the reserved word \CONST. + +\begin{grammar} + ::= \gnewline{} + \CONST{} +\end{grammar} + +\commentary{% +Constant constructors have stronger constraints than other constructors. +For instance, all the work of a non-redirecting generative constant constructor +must be done in its initializers +and in the initializing expressions of +the instance variables of the enclosing class +(and the latter may already have happened earlier, +because those initializing expressions must be constant).% +} + +\LMHash{}% +Constant redirecting generative and factory constructors are specified elsewhere +(p.\,\pageref{redirectingGenerativeConstructors}, +p.\,\pageref{redirectingFactoryConstructors}). +This section is henceforth concerned with +non-redirecting generative constant constructors. + +\LMHash{}% +It is a compile-time error if a non-redirecting generative constant constructor +is declared by a class that has a instance variable which is not final. + +\commentary{% +The above refers to both locally declared and inherited instance variables.% +} + +\LMHash{}% +If a non-redirecting generative constant constructor \DefineSymbol{k} +is declared by a class $C$, +it is a compile-time error +for an instance variable declared in $C$ +to have an initializing expression that is not a constant expression. + +\commentary{% +A superclass of $C$ cannot have such an initializing expression $e$ either. +If it has a non-redirecting generative constant constructor +then $e$ is an error, +and if it does not have such a constructor +then the (implicit or explicit) superinitializer in $k$ is an error.% +} + +\LMHash{}% +The superinitializer that appears, explicitly or implicitly, +in the initializer list of a constant constructor +must specify a generative 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 +(\ref{constants}), +or a compile-time error occurs. + +\LMHash{}% +When a constant constructor \DefineSymbol{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.% +} + + +\subsection{Static Methods} +\LMLabel{staticMethods} + +\LMHash{}% +\IndexCustom{Static methods}{method!static} +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$. + +\rationale{% +Inheritance of static methods has little utility in Dart. +Static methods cannot be overridden. +Any required static method 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} + ::= \EXTENDS{} ? + \alt + + ::= \WITH{} +\end{grammar} + +\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 that does not denote a class (\ref{typedef}), +an enumerated type (\ref{enums}), +a deferred type (\ref{staticTypes}), type \DYNAMIC{} (\ref{typeDynamic}), +or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). + +\commentary{% +Note that \VOID{} is a reserved word, +which implies that the same restrictions apply for the type \VOID, +and similar restrictions are specified for other types like +\code{Null} (\ref{null}) and +\code{String} (\ref{strings}).% +} + +\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 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 a \Index{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$ \Index{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{$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.% +} + +\commentary{% +Whether an override is legal or not is specified relative to +all direct superinterfaces, not just the interface of the superclass, +and that is described elsewhere +(\ref{instanceMethods}). +Static members never override anything, +but they may participate in some conflicts +involving declarations in superinterfaces +(\ref{classMemberConflicts}).% +} + +\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}). + A non-local variable $f$ introduces a getter $f$, + and a non-local variable $f$ + also introduces a setter + if it is not final and not constant, + or it is late and final and has no initializing expression + \code{$f$=} (\ref{instanceVariables}, \ref{variables}). + When we speak of members here, we mean + accessible instance, static, or library 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 basename + (\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} + If two members override each other, + it is an error unless it is a correct override + (\ref{correctMemberOverrides}). +\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 does not implement some member + of its interface, and there is no non-trivial \code{noSuchMethod} + (\ref{classes}). +\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 superinvocation (\ref{superInvocations}). +\item If a class defines an instance member named $m$, + and any of its superinterfaces have a member signature named $m$, + the interface of the class contains the $m$ from the class itself. +\item An interface inherits all members of its superinterfaces + that are not overridden and not members of multiple superinterfaces. +\item If multiple superinterfaces of an interface + define a member with the same name as $m$, + then at most one member is inherited. + That member (if it exists) is the one whose type is a subtype + of all the others. + If there is no such member, 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 non-trivial \code{noSuchMethod} + (\ref{theMethodNoSuchMethod}). +\item The identifier of a named constructor cannot be the same as + the basename of a static member declared in the same class + (\ref{classMemberConflicts}). +\end{enumerate}% +} + + +\subsection{Superinterfaces} +\LMLabel{superinterfaces} + +\LMHash{}% +A class has a set of \Index{direct superinterfaces}. +This set contains the interface of its superclass +and the interfaces of the classes specified in +the \IMPLEMENTS{} clause of the class. + +\begin{grammar} + ::= \IMPLEMENTS{} +\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 that does not denote a class (\ref{typedef}), +an enumerated type (\ref{enums}), +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 +%% TODO(eernst): Refer to nnbd notion of 'same type'. +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$. + +\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 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 a class $C$ has two superinterfaces +that are different instantiations of the same generic class. +\commentary{% +For example, a class can not have +both \code{List<\VOID>} and \code{List<\DYNAMIC>} as superinterfaces, +directly or indirectly.% +} + +\LMHash{}% +When a generic class $C$ declares a type parameter $X$, +it is a compile-time error if $X$ occurs in a non-covariant position +% Could say `a direct superinterface', but it is easy to see that it is +% enough to check direct superinterfaces, and it is then true +% for indirect ones as well. +in a type which specifies a superinterface of $C$. +\commentary{% +For example, the class can not have +\code{List<\VOID{} \FUNCTION($X$)>} +in its \EXTENDS{} or \IMPLEMENTS{} clause.% +} + +\LMHash{}% +It is a compile-time error if the interface of a class $C$ is +a superinterface of itself. + +\commentary{% +A class does not inherit members from its superinterfaces. +However, its implicit interface does.% +} + + +\subsection{Class Member Conflicts} +\LMLabel{classMemberConflicts} + +\LMHash{}% +Some pairs of class, mixin, enum, and extension 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 \Index{basename} of a getter or method named $n$ is $n$; +the basename of a setter named \code{$n$=} is $n$. +The basename of an operator named $n$ is $n$, +except for operator \code{[]=} whose basename is \code{[]}. + +\LMHash{}% +Let \DefineSymbol{C} be a class. +It is a compile-time error if $C$ +declares a constructor named \code{$C$.$n$} and +a static member with basename $n$. +It is a compile-time error if $C$ +declares a static member with basename $n$ and +the interface of $C$ has an instance member with basename $n$. +It is a compile-time error if the interface of $C$ +has an instance method named $n$ and an instance setter with basename $n$. +It is a compile-time error if $C$ declares a static method named $n$ +and a static setter with basename $n$. + +\LMHash{}% +When \DefineSymbol{C} is a mixin or an extension, +the compile-time errors occur according to the same rules. +\commentary{% +This is redundant in some cases. +For instance, it is already an error for a mixin to declare a constructor. +But useful cases exist as well, e.g., a conflict between a static member +and an instance member.% +} + +\LMHash{}% +These errors occur when the getters or setters are defined explicitly +as well as when they are induced by variable declarations. + +\commentary{% +Note that other errors which are similar in nature are covered elsewhere. +For instance, if $C$ is a class that has two superinterfaces $I_1$ and $I_2$, +where $I_1$ has a method named $m$ +and $I_2$ has a getter named $m$, +then it is an error because the computation of the interface of $C$ +includes a computation of the combined member signature +(\ref{combinedMemberSignatures}) +of that getter and that method, +and it is an error for a combined member signature +to include a getter and a non-getter.% +} + + +\section{Interfaces} +\LMLabel{interfaces} + +\LMHash{}% +This section introduces the notion of interfaces. +We define the notion of member signatures first, +because that concept is needed in the definition of interfaces. + +% We need a separate concept of instance member signatures, +% such that we can obtain a clean treatment of how to compute +% the interface of a class and the common interface of a set +% of superinterfaces, e.g., the superinterfaces of a class or +% the common interface represented by an `on` clause in a +% `mixin`. For instance, we do not want to specify each time +% we check for conflicts that the body doesn't matter, or +% that the metadata doesn't matter, the interface of a class +% should simply never contain a body of any member in the +% first place. Also the clear separation of a syntactic +% declaration and a member signature provides a well-defined +% occasion to introduce transformations, e.g., to replace +% some parameter types by others, which is needed for the +% specification of a correct override relation. + +\LMHash{}% +A \Index{member signature} $s$ +can be derived from a class instance member declaration $D$. +It contains the same information as $D$, +except that $s$ omits the body, if any; +it contains the return type and parameter types +even if they are implicit in $D$; +it omits the names of positional parameters; +it omits the modifier \FINAL{} from each parameter, if any; +it omits metadata +(\ref{metadata}); +and it omits information about whether the member is +\EXTERNAL, \ASYNC, \ASYNC*, or \SYNC*. +It makes no difference whether $D$ is given as explicit syntax +or it is induced implicitly, e.g., by a variable declaration. +Finally, if $s$ has formal parameters, +each of them has the modifier \COVARIANT{} +(\ref{requiredFormals}) +if and only if that parameter is covariant-by-declaration +(\ref{covariantParameters}). + +\LMHash{}% +We use a syntax similar to that of an abstract member declaration +to specify member signatures. +The difference is that the names of positional parameters are omitted. +This syntax is only used for the purposes of specification. + +\rationale{% +Member signatures are synthetic entities, that is, +they are not supported as concrete syntax in a Dart program, +they are computed entities used during static analysis. +However, it is useful to be able to indicate the +properties of a member signature in this specification +via a syntactic representation. +A member signature makes it explicit +whether a parameter is covariant-by-declaration, +but it remains implicit whether it is covariant-by-class +(\ref{covariantParameters}). +The reason for this is that the rule for determining whether +a given override relation is correct +(\ref{correctMemberOverrides}) +depends on the former and not on the latter.% +} + +\LMHash{}% +Let \DefineSymbol{m} be a method signature of the form + +\noindent +\code{$T_0$ \id<\TypeParametersStd>(} + +\noindent +\code{\qquad\qquad\List{\COVARIANT?\ T}{1}{n},} + +\noindent +\code{\qquad\qquad[\PairList{\COVARIANT?\ T}{= d}{n+1}{n+k}])}. + +\noindent +The \IndexCustom{function type of}{method signature!function type} +$m$ is then + +\noindent +\FunctionTypePositionalStd{T_0}. + +\LMHash{}% +Let \DefineSymbol{m} be a method signature of the form + +\noindent +\code{$T_0$ \id<\TypeParametersStd>(} + +\noindent +\code{\qquad\qquad\List{\COVARIANT?\ T}{1}{n},} + +\noindent +\code{\qquad\qquad\{\TripleList{\COVARIANT?\ T}{x}{= d}{n+1}{n+k}\})}. + +\noindent +The \NoIndex{function type of} $m$ is then + +\noindent +\FunctionTypeNamedStd{T_0}. + +\LMHash{}% +Let \DefineSymbol{m} be a setter signature of the form +\code{\VOID\ \SET\ \id(\COVARIANT?\ $T$ $p$)}. +The \NoIndex{function type of} $m$ is then +\FunctionTypeSimple{\VOID}{$T$}. + +\LMHash{}% +The function type of a member signature remains unchanged if +some or all default values are omitted. + +\commentary{% +We do not specify the function type of a getter signature. +For such signatures we will instead directly refer to the return type.% +} + +\LMHash{}% +An \Index{interface} is a synthetic entity that defines +how one may interact with an object. +An interface has method, getter and setter signatures, +and a set of superinterfaces, +which are again interfaces. +Each interface is the implicit interface of a class, +in which case we call it a +\IndexCustom{class interface}{interface!class}, +or a combination of several other interfaces, +in which case we call it a +\IndexCustom{combined interface}{interface!combined}. + +\LMHash{}% +Let $C$ be a class. +The \Index{class interface} $I$ of $C$ is the interface that declares +a member signature derived from +each instance member declared by $C$. +The \Index{direct superinterfaces} of $I$ are the direct superinterfaces of $C$ +(\ref{superinterfaces}). + +\commentary{% +We say that the class interface `declares' these member signatures, +such that we can say that an interface `declares' or `has' a member, +just like we do for classes. +Note that a member signature $s$ of the interface of class $C$ +may have a parameter $p$ with modifier \COVARIANT, +even though $s$ was derived from a declaration $D$ in $C$ +and the parameter corresponding to $p$ in $D$ does not +have that modifier. +This is because $p$ may have ``inherited'' +the property of being covariant-by-declaration +from one of its superinterfaces +(\ref{covariantParameters}).% +} + +\LMHash{}% +For the purpose of performing static checks on ordinary method invocations +(\ref{ordinaryInvocation}) +and property extractions +(\ref{propertyExtraction}), +any type $T$ which is $T_0$ bounded +(\ref{bindingActualsToFormals}), +where $T_0$ is a class with interface $I$, +is also considered to have interface $I$. +Similarly, when $T$ is $T_0$ bounded where $T_0$ is a function type, +$T$ is considered to have a method named \CALL{} with signature $m$, +such that the function type of $m$ is $T_0$. + +\LMHash{}% +\BlindDefineSymbol{I, \List{I}{1}{k}}% +The \Index{combined interface} $I$ of a list of interfaces \List{I}{1}{k} +is the interface that declares the set of member signatures $M$, +where $M$ is determined as specified below. +The \Index{direct superinterfaces} of $I$ is the set \List{I}{1}{k}. + +\LMHash{}% +Let $M_0$ be the set of all member signatures declared by \List{I}{1}{k}. +\DefineSymbol{M} is then the smallest set satisfying the following: + +\begin{itemize} +\item For each name \id{} and library $L$ such that $M_0$ contains + a member signature named \id{} which is accessible to $L$, + let $m$ be the combined member signature named \id{} + from \List{I}{1}{k} with respect to $L$. + It is a compile-time error + if the computation of this combined member signature failed. + Otherwise, $M$ contains $m$. +\end{itemize} + +\rationale{% +Interfaces must be able to contain inaccessible member signatures, +because they may be accessible from the interfaces associated with +declarations of subtypes.% +} + +\commentary{% +For instance, class $C$ in library $L$ may declare a private member named +\code{\_foo}, +a class $D$ in a different library $L_2$ may extend $C$, +and a class $E$ in library $L$ may extend $D$; +$E$ may then declare a member that overrides \code{\_foo} from $C$, +and that override relation must be checked based on the interface of $D$. +So we cannot allow the interface of $D$ +to ``forget'' inaccessible members like \code{\_foo}. + +For conflicts the situation is even more demanding: +Classes $C_1$ and $C_2$ in library $L$ may declare private members +\code{String \_foo(int i)} and \code{int get \_foo}, +and a subtype $D_{12}$ in a different library $L_2$ may have +an \IMPLEMENTS{} clause listing both $C_1$ and $C_2$. +In that case we must report a conflict even though the conflicting +declarations are not accessible to $L_2$, +because those member signatures are then noSuchMethod forwarded +(\ref{theMethodNoSuchMethod}), +and an invocation of \code{\_foo} on an instance of $D$ in $L$ +must return an `int` according to the first member signature, +and it must return a function object according to the second one, +and an invocation of \code{\_foo(42)} +must return a \code{String} with the first member signature, and it must fail +(at compile time or, for a dynamic invocation, run time) with the second.% +} + +\rationale{% +It may not be possible to satisfy such constraints simultaneously, +and it will inevitably be a complex semantics, +so we have chosen to make it an error. +It is unfortunate that the addition of a private declaration +in one library may break existing code in a different library. +But it should be noted that the conflicts can be detected locally +in the library where the private declarations exist, +because they only arise for private members with +the same name and incompatible signatures. +Renaming that private member to anything not used in that library +will eliminate the conflict and will not break any clients.% +} + + +\subsection{Combined Member Signatures} +\LMLabel{combinedMemberSignatures} + +\LMHash{}% +This section specifies how to compute a member signature which will +appropriately stand for a prioritized set of several member signatures, +taken from a given list of interfaces. + +\commentary{% +In general, a combined member signature has a type which is +a subtype of all the types given for that member. +This is needed in order to ensure that the type of +a member \id{} of a class $C$ is well-defined, +even in the case where $C$ inherits +several different declarations of \id{} +and does not override \id. +In case of failure, it serves to specify the situations +where a developer must add a declaration in order to resolve an ambiguity. +The member signatures are prioritized in the sense that we will select +a member signature from the interface with the lowest possible index +in the case where several member signatures are equally suitable +to be chosen as the combined member signature. +That is, ``the first interface wins''.% +} + +\LMHash{}% +For the purposes of computing a combined member signature, +we need a special notion of +\IndexCustom{equality}{member signature equality} +of member signatures. +Two member signatures $m_1$ and $m_2$ are equal +if{}f they have the same name, +are accessible to the same set of libraries, +have the same same return type (for getters), +or the same function type and the same occurrences of \COVARIANT{} +(for methods and setters). + +\commentary{% +In particular, private methods from different libraries are never equal. +Top types differ as well. +For instance, +\FunctionTypeSimple{\DYNAMIC}{} and \FunctionTypeSimple{\code{Object}}{} +are not equal, even though they are subtypes of each other. +We need this distinction because management of top type discrepancies is +one of the purposes of computing a combined interface.% +} + +\LMHash{}% +\BlindDefineSymbol{\id, L, I_j, k}% +Now we define combined member signatures. +Let \id{} be an identifier, $L$ a library, +\List{I}{1}{k} a list of interfaces, +and \DefineSymbol{M_0} the set of +all member signatures from \List{I}{1}{k} named \id{} +and accessible to $L$. +The +\IndexCustom{combined member signature + named \id{} from \List{I}{1}{k} with respect to $L$}{% + combined member signature} +is the member signature which is obtained as follows: + +\LMHash{}% +If $M_0$ is empty, computation of the combined member signature failed. + +\LMHash{}% +If $M_0$ contains exactly one member signature $m'$, +the combined member signature is $m'$. + +\LMHash{}% +Otherwise, $M_0$ contains more than one member signature +\DefineSymbol{\List{m}{1}{q}}. + +\LMHash{}% +\Case{Failing mixtures} +If $M_0$ contains at least one getter signature +and at least one non-getter signature, +the computation of the combined member signature failed. +\EndCase + +\LMHash{}% +\Case{Getters} +If $M_0$ contains getter signatures only, +the computation of the combined member signature proceeds as described below +for methods and setters, +except that it uses the return type of the getter signature +where methods and setters use the function type of the member signature. +\EndCase + +\LMHash{}% +\Case{Methods and setters} +In this case $M_0$ consists of setter signatures only, +or method signatures only, +because the name \id{} in the former case always ends in \lit{=}, +which is never true in the latter case. + +\LMHash{}% +\BlindDefineSymbol{N}% +Determine whether there exists a non-empty set $N \subseteq 1 .. q$ such that +for each $i \in N$, +the function type of $m_i$ is a subtype of +the function type of $m_j$ for each $j \in 1 .. q$. +% +If no such set exists, the computation of the combined member signature failed. +\commentary{% +A useful intuition about this situation is that +the given member signatures do not agree on +which type is suitable for the member named \id. +Otherwise we have a set of member signatures which are ``most specific'' +in the sense that their function types are subtypes of them all.% +} + +{ % Scope for N_min, M_min, N_firstMin. + +\def\Nall{\ensuremath{N_{\mbox{\scriptsize{}all}}}} +\def\Mall{\ensuremath{M_{\mbox{\scriptsize{}all}}}} +\def\MallFirst{\ensuremath{M_{\mbox{\scriptsize{}first}}}} + +\LMHash{}% +Otherwise, when a set $N$ as specified above exists, +let \Nall{} be the greatest set satisfying the requirement on $N$, +\BlindDefineSymbol{\Mall}% +and let $\Mall{} = \{ m_i\;|\;i \in \Nall\}$. +\commentary{% +That is, \Mall{} contains all member signatures named \id{} +with the most specific type. +Dart subtyping is a partial pre-order, +which ensures that such a greatest set of least elements exists, +if any non-empty set of least elements exist. +We can have several such signatures because member signatures +can be such that they are not equal, +and yet their function types are subtypes of each other. +We need to compute one member signature from \Mall, +and we do that by using the ordering of the given interfaces.% +} + +\LMHash{}% +\BlindDefineSymbol{\MallFirst}% +Let $j \in 1 .. k$ be the smallest number such that +$\MallFirst{} = \Mall{} \cap I_j$ is non-empty. +Let $m_i$ be the single element that \MallFirst{} contains. +\commentary{% +This set contains exactly one element because it is non-empty +and no interface contains more than one member signature named \id. +In other words, we choose $m_i$ as the member signature from +the first possible interface +among the most specific member signatures \Mall.% +} +} + +\LMHash{}% +The combined member signature is then $m'$, +which is obtained from $m_i$ by adding the modifier \COVARIANT{} +to each parameter $p$ (if it is not already present) +when there exists a $j \in 1 .. q$ +such that the parameter corresponding to $p$ +(\ref{covariantParameters}) +has the modifier \COVARIANT. +\commentary{% +In other words, +each parameter in the combined member signature is marked covariant +if any of the corresponding parameters are marked covariant, +not just among the most specific signatures, +but among \emph{all} signatures named \id{} (which are accessible to $L$) +in the given list of interfaces.% +} +\EndCase + + +\subsection{Superinterfaces} +\LMLabel{interfaceSuperinterfaces} + +\LMHash{}% +An interface has a set of direct superinterfaces +(\ref{interfaces}). +An interface $J$ is a \Index{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$. + +\LMHash{}% +When we say that a type $S$ +\IndexCustom{implements}{type!implements a type} +another type $T$, +this means that $T$ is a superinterface of $S$, +or $S$ is $S_0$ bounded for some type $S_0$ +(\ref{bindingActualsToFormals}), +and $T$ is a superinterface of $S_0$. +Assume that $G$ is a raw type +(\ref{instantiationToBound}) +whose declaration declares $s$ type parameters. +When we say that a type $S$ +\IndexCustom{implements}{type!implements a raw type} +$G$, +this means that there exist types \List{U}{1}{s} +such that $S$ implements \code{$G$<\List{U}{1}{s}>}. + +\commentary{% +Note that this is not the same as being a subtype. +For instance, \code{List} implements \code{Iterable}, +but it does not implement \code{Iterable}. +Similarly, \code{List} implements \code{Iterable}. +Also, note that when $S$ implements $T$ +where $T$ is not a subtype of \code{Null}, +$S$ cannot be a subtype of \code{Null}.% +} + +\LMHash{}% +Assume that $S$ is a type and $G$ is a raw type such that $S$ implements $G$. +Then there exist unique types \List{U}{1}{s} such that +$S$ implements \code{$G$<\List{U}{1}{s}>}. +We then say that \List{U}{1}{s} are the +\IndexCustom{actual type arguments of $S$ at $G$}{% + type arguments!of a type at a raw type}, +and we say that $U_j$ is the +\IndexCustom{$j$th actual type argument of $S$ at $G$}{% + type arguments!of a type at a raw type, $j$th}, +for any $j \in 1 .. s$. + +\commentary{% +For instance, the type argument of \code{List} at \code{Iterable} +is \code{int}. +This concept is particularly useful when +the chain of direct superinterfaces from $S$ to $G$ +does not just pass all type arguments on unchanged, e.g., +with a declaration like +\code{\CLASS\,\,C\,\,\EXTENDS\,\,B,\,Y,\,X> \{\}}.% +} + + +\subsubsection{Inheritance and Overriding} +\LMLabel{interfaceInheritanceAndOverriding} + +\LMHash{}% +\BlindDefineSymbol{J, K}% +Let $J$ be an interface and $K$ be a library. +We define $\inherited{J, K}$ to be the set of member signatures +\DefineSymbol{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 signature $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 member signatures \DefineSymbol{m'} +such that all of the following hold: +\begin{itemize} +\item $J$ is the interface of a class $C$. +\item $C$ declares a member signature $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 signature $m'$ or + \item $m'$ is a member of $inherited(A, K)$. + \end{itemize} +\end{itemize} + +\LMHash{}% +Let $I$ be the interface of a class $C$ declared in library $L$. +$I$ \Index{inherits} all members of $\inherited{I, L}$ +and $I$ \Index{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} hold for overriding between interfaces as well. + +\LMHash{}% +If the above rule would cause multiple member signatures +with the same name \id{} to be inherited then +exactly one member is inherited, namely +the combined member signature named \id, +from the direct superinterfaces +% This is well-defined because $I$ is a class interface. +in the textual order that they are declared, +with respect to $L$ +(\ref{combinedMemberSignatures}). +It is a compile-time error +if the computation of said combined member signature fails. + + +\subsubsection{Correct Member Overrides} +\LMLabel{correctMemberOverrides} + +\LMHash{}% +\BlindDefineSymbol{m, m', \id}% +Let $m$ and $m'$ be member signatures with the same name \id. +Then $m$ is a \Index{correct override} of $m'$ +if{}f the following criteria are all satisfied: + +\begin{itemize} +\item + $m$ and $m'$ are both methods, both getters, or both setters. +\item + If $m$ and $m'$ are both getters: + The return type of $m$ must be a subtype of the return type of $m'$. +\item + If $m$ and $m'$ are both methods or both setters: + Let $F$ be the function type of $m$ + except that the parameter type is the built-in class \code{Object} + for each parameter of $m$ which is covariant-by-declaration + (\ref{covariantParameters}). + Let $F'$ be the function type of $m'$. + $F$ must then be a subtype of $F'$. + + \commentary{% + The subtype requirement ensures that argument list shapes + that are admissible for an invocation of a method with signature $m'$ + are also admissible for an invocation of a method with signature $m$. + For instance, $m'$ may accept 2 or 3 positional arguments, + and $m$ may accept 1, 2, 3, or 4 positional arguments, but not vice versa. + This is a built-in property of the function type subtype rules. + } +\item + %% TODO(eernst): Come nnbd, this warning is removed. + If $m$ and $m'$ are both methods, + $p$ is an optional parameter of $m$, + $p'$ is the parameter of $m'$ corresponding to $p$, + $p$ has default value $d$ and $p'$ has default value $d'$, + then $d$ and $d'$ must be identical, + or a static warning occurs. +\end{itemize} + +\commentary{% +Note that a parameter which is covariant-by-declaration +must have a type which satisfies one more requirement, +relative to the corresponding parameters in all superinterfaces, +both direct and indirect +(\ref{instanceMethods}). +We cannot make that requirement a part of the notion of correct overrides, +because correct overrides are only concerned with +the relation to a single superinterface.% +} + + +\section{Mixins} +\LMLabel{mixins} + +\LMHash{}% +A mixin describes the difference between a class and its superclass. +A mixin is either derived from an existing class declaration +or introduced by a mixin declaration. +It is a compile-time error to derive a mixin from +a class that declares a generative constructor, +or from a class that has a superclass other than \code{Object}. + +\LMHash{}% +Mixin application occurs when one or more mixins are mixed into +a class declaration via its \WITH{} clause (\ref{mixinApplication}). +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 the following section. + + +\subsection{Mixin Classes} +\LMLabel{mixinClasses} + +\begin{grammar} + ::= \gnewline{} + ? `=' `;' + + ::= ? +\end{grammar} + +\LMHash{}% +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 function type (\ref{functionTypes}), +a type alias that does not denote a class (\ref{typedef}), +an enumerated type (\ref{enums}), +a deferred type (\ref{staticTypes}), +type \DYNAMIC{} (\ref{typeDynamic}), +type \VOID{} (\ref{typeVoid}), +or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). +If $T$ is a type in a \WITH{} clause, \IndexCustom{the mixin of}{type!mixin of} +$T$ is either the mixin derived from $T$ if $T$ denotes a class, +or the mixin introduced by $T$ if $T$ denotes a mixin declaration. + +\LMHash{}% +Let $D$ be a mixin application class declaration of the form + +\begin{normativeDartCode} +\ABSTRACT? \CLASS{} $N$ = $S$ \WITH{} $M_1$, \ldots, $M_n$ \IMPLEMENTS{} $I_1$, \ldots, $I_k$; +\end{normativeDartCode} + +\LMHash{}% +It is a compile-time error if $S$ is an enumerated type (\ref{enums}). +It is a compile-time error if any of $M_1, \ldots, M_k$ is an enumerated type +(\ref{enums}). + +\LMHash{}% +The effect of $D$ in library $L$ is to introduce the name $N$ into +the scope of $L$, bound to the class (\ref{classes}) defined by the clause +\code{$S$ \WITH{} $M_1$, \ldots, $M_n$} +with name $N$, as described below. +If $k > 0$ then the class also implements $I_1$, \ldots, $I_k$. +If{}f the class declaration is prefixed by the built-in identifier \ABSTRACT, +the class being defined is made an abstract class. + +\LMHash{}% +A clause of the form \code{$S$ \WITH{} $M_1$, \ldots, $M_n$} +with name $N$ defines a class as follows: + +\LMHash{}% +If there is only one mixin ($n = 1$), then \code{$S$ \WITH{} $M_1$} +defines the class yielded by the mixin application (\ref{mixinApplication}) +of the mixin of $M_1$ (\ref{mixinDeclaration}) to the class denoted by +$S$ with name $N$. + +\LMHash{}% +If there is more than one mixin ($n > 1$), then +let $X$ be the class defined by \code{$S$ \WITH{} $M_1$, \ldots, $M_{n-1}$} +with name $F$, where $F$ is a fresh name, and make $X$ abstract. +Then \code{$S$ \WITH{} $M_1$, \ldots, $M_n$} defines the class yielded +by the mixin application of the mixin of $M_n$ to the class $X$ with name $N$. + +\LMHash{}% +In either case, let $K$ be a class declaration with +the same constructors, superclass, interfaces and instance members as +the defined class. +It is a compile-time error if the declaration of $K$ would cause +a compile-time error. +% TODO(eernst): Not completely! +% We do not want super-invocations on covariant implementations +% to be compile-time errors. + +\commentary{% +It is an error, for example, if $M$ contains a member declaration $d$ +which overrides a member signature $m$ in the interface of $S$, +but which is not a correct override of $m$ +(\ref{correctMemberOverrides}).% +} + +\subsection{Mixin Declaration} +\LMLabel{mixinDeclaration} + +\LMHash{}% +A mixin defines zero or more +\IndexCustom{mixin member declarations}{mixin!member declaration}, +zero or more +\IndexCustom{required superinterfaces}{mixin!required superinterface}, +one +\IndexCustom{combined superinterface}{mixin!combined superinterface}, +and zero or more +\IndexCustom{implemented interfaces}{mixin!implemented interface}. + +\LMHash{}% +The mixin derived from a class declaration: + +\begin{normativeDartCode} +\ABSTRACT? \CLASS{} $X$ \IMPLEMENTS{} $I_1$, \ldots, $I_k$ \{ + \metavar{members} +\} +\end{normativeDartCode} + +has \code{Object} as required superinterface +and combined superinterface, +$I_1$, \ldots, $I_k$ as implemented interfaces, +and the instance members of \metavar{members} as mixin member declarations. +If $X$ is generic, so is the mixin. + +\LMHash{}% +A mixin declaration introduces a mixin and provides a scope +for static member declarations. + +\begin{grammar} + ::= \MIXIN{} ? + \gnewline{} (\ON{} )? ? + \gnewline{} `\{' ( )* `\}' +\end{grammar} + +\LMHash{}% +It is a compile-time error to declare a constructor in a mixin-declaration. + +\LMHash{}% +A mixin declaration with no \code{\ON} clause is equivalent +to one with the clause \code{\ON{} Object}. + +\LMHash{}% +Let $M$ be a \MIXIN{} declaration of the form + +\begin{normativeDartCode} +\MIXIN{} $N$<\TypeParametersStd> \ON{} \List{T}{1}{n} + \IMPLEMENTS{} \List{I}{1}{k} \{ + \metavar{members} +\} +\end{normativeDartCode} + +\LMHash{}% +It is a compile-time error if any of the types $T_1$ through $T_n$ +or $I_1$ through $I_k$ is +a type variable (\ref{generics}), +a function type (\ref{functionTypes}), +a type alias not denoting a class (\ref{typedef}), +an enumerated type (\ref{enums}), +a deferred type (\ref{staticTypes}), +type \DYNAMIC{} (\ref{typeDynamic}), +type \VOID{} (\ref{typeVoid}), +or type \code{FutureOr<$T$>} for any $T$ (\ref{typeFutureOr}). + +\LMHash{}% +Let $M_S$ be the interface declared by the class declaration + +\begin{normativeDartCode} +\ABSTRACT{} \CLASS{} $M_{super}$<$P_1$, \ldots, $P_m$> \IMPLEMENTS{} $T_1$, $\dots{}$, $T_n$ \{\} +\end{normativeDartCode} + +\noindent +where $M_{super}$ is a fresh name. +It is a compile-time error for the mixin declaration if the $M_S$ +class declaration would cause a compile-time error, +\commentary{% +that is, if any member is declared by more than one declared superinterface, +and there is not a most specific signature for that member among the super +interfaces% +}. +The interface $M_S$ is called the +\Index{superinvocation interface} of the mixin declaration $M$. +\commentary{% +If the mixin declaration $M$ has only one declared superinterface, $T_1$, +then the superinvocation interface $M_{super}$ has exactly the same members +as the interface $T_1$.% +} + +\LMHash{}% +Let $M_I$ be the interface that would be defined by the class declaration + +\begin{normativeDartCode} +\ABSTRACT{} \CLASS{} $N$<\TypeParametersStd> + \IMPLEMENTS{} \List{T}{1}{n}, \List{I}{1}{k} \{ + $\metavar{members}'$ +\} +\end{normativeDartCode} + +where $\metavar{members}'$ are the member declarations of +the mixin declaration $M$ except that all superinvocations are treated +as if \SUPER{} was a valid expression with static type $M_S$. +It is a compile-time error for the mixin $M$ if this $N$ class +declaration would cause a compile-time error, \commentary{that is, if the +required superinterfaces, the implemented interfaces and the declarations do not +define a consistent interface, if any member declaration contains a +compile-time error other than a super-invocation, or if a super-invocation +is not valid against the interface $M_S$}. +The interface introduced by the mixin declaration $M$ has the same member +signatures and superinterfaces as $M_I$. + +\LMHash{}% +The mixin declaration $M$ introduces a mixin +with the \NoIndex{required superinterface}s $T_1$, \ldots, $T_n$, +the \NoIndex{combined superinterface} $M_S$, +\NoIndex{implemented interface}s $I_1$, \ldots, $I_k$ +and the instance members declared in $M$ as \Index{mixin member declarations}. + + +\subsection{Mixin Application} +\LMLabel{mixinApplication} + +\LMHash{}% +A mixin may be applied to a superclass, yielding a new class. + +\LMHash{}% +Let $S$ be a class, +$M$ be a mixin with \NoIndex{required superinterface}s $T_1$, \ldots, $T_n$, +\NoIndex{combined superinterface} $M_S$, +\NoIndex{implemented interfaces} $I_1$, \ldots, $I_k$ and +\metavar{members} as \NoIndex{mixin member declarations}, +and let $N$ be a name. + +\LMHash{}% +It is a compile-time error to apply $M$ to $S$ if $S$ does not implement, +directly or indirectly, all of $T_1$, \ldots, $T_n$. +It is a compile-time error if any of \metavar{members} contains a +super-invocation of a member $m$ \commentary{(for example \code{super.foo}, +\code{super + 2}, or \code{super[1] = 2})}, and $S$ does not have a concrete +implementation of $m$ which is a valid override of the member $m$ in +the interface $M_S$. \rationale{We treat super-invocations in mixins as +interface invocations on the combined superinterface, so we require the +superclass of a mixin application to have valid implementations of those +interface members that are actually super-invoked.} + +\LMHash{}% +The mixin application of $M$ to $S$ with name $N$ introduces a new +class, $C$, with name $N$, superclass $S$, +implemented interface $M$ +and \metavar{members} as instance members. +The class $C$ has no static members. +If $S$ declares any generative constructors, then the application +introduces generative constructors on $C$ as follows: + +\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$} giving rise +to the mixin application.} + +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{normativeDartCode} +$C_q$($T_{1}$ $a_{1}$, \ldots, $T_{k}$ $a_{k}$): $\SUPER_q$($a_{1}$, $\ldots$, $a_{k}$); +\end{normativeDartCode} + +\noindent +where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$, +which denote the superclass, by $N$, 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 $C$ does not declare any +instance variables, $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{normativeDartCode} +$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{normativeDartCode} + +\noindent +where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$, +which denote the superclass, by $N$, +$\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 $MC$ does not declare any +instance variables, $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{normativeDartCode} +$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{normativeDartCode} + +\noindent +where $C_q$ is obtained from $S_q$ by replacing occurrences of $S_N$ +which denote the superclass by $N$, +$\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. + + +\section{Extensions} +\LMLabel{extensions} + +\LMHash{}% +This section specifies extensions. +This mechanism supports the declaration of functions +that are similar to instance methods in use, +but similar to non-method functions in that +they are declared outside the target class, +and they are resolved statically. +The resolution is based on whether the relevant extension is in scope, +and whether the invocation satisfies several other requirements. + +\begin{grammar} + ::= \gnewline{} + \EXTENSION{} ? ? \ON{} + \gnewline{} `\{' ( )* `\}' +\end{grammar} + +\LMHash{}% +A declaration derived from \synt{extensionDeclaration} is known as an +\IndexCustom{extension declaration}{extension!declaration}. +It introduces an +\Index{extension} +with the given \synt{identifier}, if present, +into the namespace of the enclosing library +(\commentary{and hence into the library scope}), +and provides a scope for the declaration of +extension members. +Additionally, the extension is introduced into the library namespace +with a fresh, private name. +The former is known as the +\IndexCustom{declared name}{extension!declared name} +of the extension, +and the latter is known as the +\IndexCustom{fresh name}{extension!fresh name} +of the extension. + +\commentary{% +A fresh name is also introduced into +the library namespace of the current library +for each imported extension, +even when it is imported with a prefix +(\ref{theImportedNamespace}). +% +The declared name of an extension $E$ is +introduced into the library scope of the current library +following the same rules as the names of +other locally declared or imported declarations like classes. +% +A fresh name of $E$ is introduced in these cases, +but also in one additional case: +when there is a name clash on the declared name of $E$.% +} + +\commentary{% +The fresh name makes it possible for an extension to be used +in an implicit invocation +(\ref{implicitExtensionInvocations}), +even in the case where the declared name +or an import prefix that provides access to the declared name +is shadowed by a declaration in an intermediate scope, +or conflicted by a name clash.% +} + +\rationale{% +The fact that an extension can be used implicitly even in the case where +it does not have a declared name or the declared name is shadowed or conflicted +reflects the fact that the primary intended usage is implicit invocation. +Even though a developer cannot know (and hence cannot use) the fresh name +of a given extension, an implicit invocation can use it.% +} + +\LMHash{}% +It is a compile-time error if the current library has +a deferred import of a library $L'$ +such that the imported namespace from $L'$ contains +a name denoting an extension. + +\commentary{% +This implies that the import must use \HIDE{} or \SHOW{} to eliminate +the names of extensions from the deferred import.% +} + +\rationale{% +This restriction ensures that no extensions are introduced +using deferred imports, +which allows us to introduce a semantics for such extensions in the future +without affecting existing code.% +} + +\LMHash{}% +The \synt{type} in an extension declaration +is known as the extension's +\IndexCustom{\ON{} type}{extension!\ON{} type}. +The \ON{} type can be any valid type, including a type variable. + +\commentary{% +The basic intuition is that an extension \code{E} may have +an \ON{} type $T$ (specifying the type of receiver) and a set of members. +If $e$ is an expression whose static type is $T$ +and \code{foo()} is a member declared by \code{E}, +\code{$e$.foo()} may invoke said member with the value of $e$ bound to \THIS. +An explicitly resolved form \code{E($e$).foo()} is available, +such that \code{E.foo} can be invoked even in the case +where \code{$e$.foo()} would invoke some other function +because some other extension is more specific. +Details of these concepts, rules, and mechanisms are given +in this section and its subsections.% +} + +\LMHash{}% +The declared name of an extension does not denote a type, +but it can be used to denote the extension itself +(\commentary{% +e.g., in order to access static members of the extension, +or in order to resolve an invocation explicitly% +}). + +\LMHash{}% +An extension declaration introduces two scopes: +\begin{itemize} +\item + A \IndexCustom{type-parameter scope}{scope!type parameter}, + which is empty if the extension is not generic (\ref{generics}). + The enclosing scope of the type-parameter scope of an extension declaration is + the library scope of the current library. + The type parameter scope is the current scope for + the type parameters and for the extension's \ON{} \synt{type}. +\item + A \IndexCustom{body scope}{scope!extension body}. + The enclosing scope of the body scope of an extension declaration is + the type parameter scope of the extension declaration. + The current scope for an extension member declaration is + the body scope of the enclosing extension declaration. +\end{itemize} + +\LMHash{}% +\BlindDefineSymbol{D, \code{E}}% +Let $D$ be an extension declaration with declared name \code{E}. +A member declaration in $D$ with the modifier \STATIC{} is designated as a +\IndexCustom{static member}{extension!static member} +declaration. +% +A member declaration in $D$ without the modifier \STATIC{} is designated as an +\IndexCustom{instance member}{extension!instance member} +declaration. +% +Member naming conflict errors may occur in $D$ +in situations that also occur in classes and mixins +(\ref{classMemberConflicts}). +Moreover, a compile-time error occurs in the following situations: + +\begin{itemize} +\item $D$ declares a member whose basename is \code{E}. +\item $D$ declares a type parameter named \code{E}. +\item $D$ declares a member whose basename is the name of a type parameter + of $D$. +\item $D$ declares an instance member or a static member whose basename is + \code{hashCode}, \code{noSuchMethod}, \code{runtimeType}, \code{toString}, + or \lit{==}. + \commentary{% + That is, a member whose basename is also the name of + an instance member that every object has.% + } +\item $D$ declares a constructor. +\item $D$ declares an instance variable. +\item $D$ declares an abstract member. +\item $D$ declares a method with a formal parameter + with the modifier \COVARIANT. +\end{itemize} + +\rationale{% +Abstract members are not allowed because there is +no support for providing an implementation. +% +Constructors are not allowed since the extension +does not introduce any type that can be constructed. +% +Instance variables are not allowed because no memory is allocated +for each object accessed as \THIS{} in the members. +Developers can emulate per-\THIS{} state if needed, +e.g., using an \code{Expando}. +% +Members with the same basename as members of \code{Object} +are not allowed because they could only be invoked using explicit resolution, +as in \code{E(e).toString(14)}, +which would be confusing and error-prone.% +} + + +\subsection{Explicit Invocation of an Instance Member of an Extension} +\LMLabel{explicitExtensionInvocations} + +\LMHash{}% +Let \DefineSymbol{E} be a simple or qualified identifier +that denotes an extension. +An \IndexCustom{extension application}{extension!application} +is then an expression of the form +\syntax{$E$ ? `(' `)'}. +An extension member with a name accessible to the current library +can be invoked explicitly on a particular object +by performing a member invocation +(\ref{memberInvocations}) +where the receiver is an extension application. + +\commentary{% +Type inference is not yet specified in this document, +and is assumed to have taken place already +(\ref{overview}), +but the following describes the intended treatment. +This section and its subsections have similar commentary about type inference +below, marked 'With type inference: \ldots'. + +Let $E$ be a simple or qualified identifier denoting +an extension named \code{E} and declared as follows:% +} + +\begin{dartCode} +\EXTENSION{} E<\TypeParametersStd> on $T$ \{\,\ldots\,\} +\end{dartCode} + +\noindent +\commentary{% +Type inference for an extension application +of the form \code{$E$($e$)} +is done exactly the same as it would be for +the same syntax considered as a constructor invocation +where $E$ is assumed to denote the following class, +and the context type is empty (implying no requirements):% +} + +\begin{dartCode} +\CLASS{} E<\TypeParametersStd> \{ + final $T$ target; + E(this.target); +\} +\end{dartCode} + +\noindent +\commentary{% +This will infer type arguments for \code{$E$($e$)}, and it will +introduce a context type for the expression $e$. +For example, if $E$ is declared as +\code{\EXTENSION{} E on Set \{\,\ldots\,\}} +then \code{E(\{\})} will provide the expression \code{\{\}} with +a context type that makes it a set literal.% +} + +\LMHash{}% +\BlindDefineSymbol{a, E, T_j, e}% +Let $a$ be an extension application of the form +\code{$E$<\List{T}{1}{s}>($e$)}, +where $E$ denotes an extension declared as + +\noindent +\BlindDefineSymbol{X_j, B_j, s, T}% +\EXTENSION{} E<\TypeParametersStd> \ON{} $T$ \{\,\ldots\,\}. + +\LMHash{}% +We define the +\IndexCustom{instantiated \ON{} type}{extension!instantiated \ON{} type} +of $a$ as $[T_1/X_1, \ldots, T_s/X_s]T$. +We define the +\IndexCustom{instantiation-to-bound \ON{} type}{% + extension!instantiation-to-bound \ON{} type} +of $a$ as $[U_1/X_1, \ldots, U_s/X_s]T$, +where \List{U}{1}{s} is the result of instantiation to bound +on the type parameters of $E$ +(\ref{instantiationToBound}). +% +A compile-time error occurs unless +\SubtypeNE{T_j}{[T_1/X_1, \ldots, T_s/X_s]B_j}, +$j \in 1 .. s$ +(\commentary{that is, the bounds cannot be violated}). +% +A compile-time error occurs unless the static type of $e$ is assignable to +the instantiated \ON{} type of $a$. +\commentary{% +Note that a compile-time error occurs as well +if the static type of $e$ is \VOID{} +(\ref{typeVoid}).% +} + +\LMHash{}% +It is a compile-time error if an extension application occurs +in a location where it is \emph{not} the syntactic receiver of +a simple or composite member invocation +(\ref{memberInvocations}). + +\commentary{% +That is, the only valid use of an extension application is +to invoke or tear off members on it. +This is similar to how prefix names can also only be used as +member invocation targets, +except that extensions can also declare operators. +For instance, \code{$E$($e$) + 1} can be a valid invocation of +an operator \lit{+} declared in an extension $E$.% +} + +\LMHash{}% +An extension application does not have a type. + +\commentary{% +This is consistent with the fact that any use of an extension application +where a type is needed is a compile-time error.% +} + +\LMHash{}% +\BlindDefineSymbol{i, r}% +Let $i$ be a simple member invocation +(\ref{memberInvocations}) +whose receiver $r$ is an extension application of the form +\BlindDefineSymbol{E, T_j, k, e}% +\code{$E$<\List{T}{1}{k}>($e$)} +(\commentary{which is \code{$E$($e$)} when $k$ is zero}) +whose corresponding member name is \DefineSymbol{n}, +and assume that $r$ has no compile-time errors. +A compile-time error occurs unless the extension denoted by $E$ +declares a member named $n$. +Otherwise let \DefineSymbol{\List{X}{1}{k}} be +the type parameters of said extension. +Let \DefineSymbol{s} be the member signature of the member $n$ declared by $E$. +Exactly the same compile-time errors occur for $i$ as +the ones that would occur for a member invocation $i_1$ +which is obtained from $i$ by replacing $r$ by +a variable whose type is +a class $C$ declared in the same scope as $E$ +that declares a member $n$ with member signature +$s_1 = [T_1/X_1, \ldots, T_k/X_k]s$: + +\begin{normativeDartCode} +\ABSTRACT{} \CLASS{} $C$ \{ + $D$ // \comment{Member declaration with signature $s_1$.} +\} +\end{normativeDartCode} + +\LMHash{}% +The member signature $s_1$ is called the +\IndexCustom{invocation member signature}{% + extension!invocation member signature} +of $i$. +The static type of $i$ is the return type of +the invocation member signature of $i$. +\commentary{For example:} + +\begin{dartCode} +\EXTENSION{} E \ON{} List \{ + List{}> split(int at) => + [this.sublist(0, at), this.sublist(at)]; +\} +\\ +\VOID{} main() \{ + List xs = [1, 2, 3]; + \VAR{} ys = E(xs).split(1); // \comment{(*)} +\} +\\ +\ABSTRACT{} \CLASS{} C \{ + // \comment{Declaration with invocation member signature for (*).} + List{}> split(int at); +\} +\end{dartCode} + +\commentary{% +With type inference: +In the case where the invocation member signature $s_1$ is generic, +type inference occurs on $i$ in the same way as it +would occur for an invocation of a function whose type is the +function type of $s_1$.% +} + +\LMHash{}% +\BlindDefineSymbol{i, r}% +For the dynamic semantics, +let $i$ be a simple, unconditional member invocation +whose receiver $r$ is an extension application of the form +\BlindDefineSymbol{E, T_j, k, e}% +\code{$E$<\List{T}{1}{k}>($e$)} +where the type parameters of $E$ are \DefineSymbol{\List{X}{1}{k}} +and the actual values of \List{T}{1}{k} are \DefineSymbol{\List{t}{1}{k}} +(\ref{actualTypes}), +\BlindDefineSymbol{n, m}% +and whose corresponding member name is $n$. +Let $m$ be the member of $E$ that has the name $n$. +Evaluation of $i$ proceeds by evaluating +$e$ to an object $o$, +evaluating and binding the actual arguments to the formal parameters +(\ref{bindingActualsToFormals}), +and finally executing $m$ +in a binding environment where \List{X}{1}{k} are bound to \List{t}{1}{k}, +\THIS{} is bound to $o$, +and each formal parameter is bound to the corresponding actual argument. +The value of $i$ is the value returned by the invocation of $m$. + +\LMHash{}% +When $i$ is a conditional or composite member invocation, +the static analysis and dynamic semantics is determined by +member invocation desugaring +(\ref{memberInvocations}). + +\rationale{% +Note that a cascade (\ref{cascades}) +whose receiver is an extension application $a$ is a compile-time error. +This is so because it implies that $a$ denotes an object, which is not true, +and also because it would force each \synt{cascadeSection} +to invoke a member of the same extension, +which is unlikely to be desirable.% +} + + +\subsection{Implicit Invocation of an Instance Member of an Extension} +\LMLabel{implicitExtensionInvocations} + +\LMHash{}% +Instance members of an extension can be invoked or closurized implicitly +(\commentary{without mentioning the name of the extension}), +as if they were instance members of the receiver of +the given member invocation. + +\commentary{% +For instance, if \code{E<$T_1, T_2$>($e_1$).m<$T_3$>($e_2$)} is +a correct explicit invocation of the instance member \code{m} of +an extension \code{E}, +then \code{$e_1$.m<$T_3$>($e_2$)} may be +a correct implicit invocation with the same meaning. +In other words, +the receiver $r$ of a member invocation can be implicitly replaced by +an extension application with receiver $r$, +if a number of requirements that are detailed below are satisfied.% +} + +\rationale{% +Implicit invocation is intended as the primary way to use extensions, +with explicit invocation as a fallback +in case the implicit invocation is an error, or +the implicit invocation resolves to an instance member of +a different extension than the intended one.% +} + +\LMHash{}% +\BlindDefineSymbol{i, r, m}% +An implicit extension member invocation occurs +for a member invocation $i$ +(\ref{memberInvocations}) +with receiver $r$ and corresponding member name $m$ if{}f +(1) $r$ is not a type literal, +(2) the interface of the static type of $r$ does not have a member +whose basename is the basename of $m$, +and (3) there exists a unique most specific +(\ref{extensionSpecificity}) +extension denoted by $E$ which is accessible +(\ref{extensionAccessibility}) +and applicable +(\ref{extensionApplicability}) +to $i$. + +\LMHash{}% +In the case where no compile-time error occurs, +$i$ is treated as $i'$, which is obtained from $i$ by +replacing the leading $r$ by \code{$E$($r$)}. + +\commentary{% +With type inference: +When $E$ is generic, +type inference applied to \code{$E$($r$)} may provide actual type arguments, +yielding an $i'$ of the form \code{$E$<\List{T}{1}{k}>($r$)}. +If this type inference step fails then $E$ is not applicable +(\ref{extensionApplicability}).% +} + +\commentary{% +Implicit invocation of an instance member of an extension +in a cascade is also possible, +because a cascade is desugared to an expression that contains +one or more member invocations.% +} + + +\subsubsection{Accessibility of an Extension} +\LMLabel{extensionAccessibility} + +\LMHash{}% +An extension $E$ is +\IndexCustom{accessible}{extension!accessibility} +in a given scope $S$ +if there exists a name $n$ such that a lexical lookup for $n$ from $S$ +(\ref{lexicalLookup}) +yields $E$. + +\commentary{% +The name $n$ can be the declared name of $E$ or the fresh name of $E$, +but since the fresh name is always in scope +whenever the declared name is in scope, +it is sufficient to consider the fresh name. +% +When the fresh name of $E$ is in the library scope, +it is available in \emph{any} scope, +because the name is fresh and hence it cannot be shadowed +by any declaration in any intermediate scope. +% +This implies that if $E$ is accessible anywhere in a given library $L$ +then it is accessible everywhere in $L$.% +} + + +\subsubsection{Applicability of an Extension} +\LMLabel{extensionApplicability} + +\LMHash{}% +\BlindDefineSymbol{E, e, r, S, m}% +Let $E$ be an extension. +Let $e$ be a member invocation +(\ref{memberInvocations}) +with a receiver $r$ with static type $S$ +and with a corresponding member name whose basename is $m$. +We say that $E$ is +\IndexCustom{applicable}{extension!is applicable} +to $e$ if the following conditions are all satisfied: + +\begin{itemize} +\item + $r$ is not a type literal. + + \commentary{% + This means that the invocation is an instance member invocation, + in the sense that $r$ denotes an object, + so it may invoke an instance member or be an error, + but it cannot be a static member access. + Note that $r$ also does not denote a prefix or an extension, + and it is not an extension application, + because they do not have a type.% + } +\item + The type $S$ does not have an instance member with the basename $m$, + and $S$ is neither \DYNAMIC{} nor \code{Never}. + + \commentary{% + \DYNAMIC{} and \code{Never} are considered to have all members. + Also, it is an error to access a member on a receiver of type \VOID{} + (\ref{typeVoid}), + so extensions are never applicable to receivers of + any of the types \DYNAMIC, \code{Never}, or \VOID.% + } + + For the purpose of determining extension applicability, + function types and the type \code{Function} + are considered to have a member named \CALL. + + \commentary{% + Hence, extensions are never applicable to functions + when the basename of the member is \CALL. + % + Instance members declared by the built-in class \code{Object} + exist on all types, + so no extension is ever applicable for members with such names.% + } +\item + Consider an extension application $a$ of the form \code{$E$($v$)}, + where $v$ is a fresh variable with static type $S$. + It is required that an occurrence of $a$ + in the scope which is the current scope for $e$ + is not a compile-time error. + + \commentary{% + In other words, $S$ must match the \ON{} type of $E$. + With type inference, inferred actual type arguments may be added, + yielding \code{$E$<\List{S}{1}{k}>($v$)}, + which is then required to not be an error. + If this inference step fails it is not an error, + it just means that $E$ is not applicable to $e$.% + } +\item + The extension $E$ declares an instance member with basename $m$. +\end{itemize} + +\commentary{% +With type inference: +The context type of the invocation does not affect +whether the extension is applicable, +and neither the context type nor the method invocation affects +the type inference of $r$, +but if the extension method itself is generic, +the context type may affect the member invocation.% +} + + +\subsubsection{Specificity of an Extension} +\LMLabel{extensionSpecificity} + +\LMHash{}% +\BlindDefineSymbol{E_j, k}% +When \List{E}{1}{k}, $k > 1$, are extensions +which are accessible and applicable to a member invocation $e$ +(\ref{memberInvocations}), +we define the notion of +\IndexCustom{specificity}{extension!specificity}, +which is a partial order on \List{E}{1}{k}. + +\commentary{% +Specificity is used to determine which extension method to execute +in the situation where more than one choice is possible.% +} + +\LMHash{}% +\BlindDefineSymbol{e, r, m}% +Let $e$ be a member invocation with receiver $r$ +and correspsonding member name $m$, +\BlindDefineSymbol{E_1, E_2}% +and let $E_1$ and $E_2$ denote two distinct +accessible and applicable extensions for $e$. +\BlindDefineSymbol{T_j, S_j}% +Let $T_j$ be the instantiated \ON{} type of $e$ with respect to $E_j$, +and $S_j$ be the instantiation-to-bound \ON{} type of $e$ with respect to $E_j$, +for $j \in 1 .. 2$ +(\ref{explicitExtensionInvocations}). +Then $E_1$ is more specific than $E_2$ with respect to $e$ +if at least one of the following conditions is satisfied: + +\begin{itemize} +\item + $E_1$ is not declared in a system library, + but $E_2$ is declared in a system library. +\item + $E_1$ and $E_2$ are both declared in a system library, + or neither of them is declared in a system library, and + \begin{itemize} + \item \SubtypeNE{T_1}{T_2}, but not \SubtypeNE{T_2}{T_1}, or + \item \SubtypeNE{T_1}{T_2}, \SubtypeNE{T_2}{T_1}, and + \SubtypeNE{S_1}{S_2}, but not \SubtypeNE{S_2}{S_1}. + \end{itemize} + + \commentary{% + In other words, the instantiated \ON{} type determines the specificity, + and the instantiation-to-bound \ON{} type is used as a tie breaker + in the case where subtyping does not distinguish between the former.% + } +\end{itemize} + +\commentary{% +The following examples illustrate implicit extension resolution +when multiple applicable extensions are available.% +} + +\begin{dartCode} +\EXTENSION{} ExtendIterable \ON{} Iterable \{ + \VOID{} myForEach(void \FUNCTION(T) f) \{ + \FOR{} (\VAR{} x \IN{} \THIS) f(x); + \} +\} +\EXTENSION{} ExtendList \ON{} List \{ + \VOID{} myForEach(\VOID{} \FUNCTION(T) f) \{ + \FOR{} (int i = 0; i < length; i++) f(\THIS[i]); + \} +\} +\\ +\VOID{} main() \{ + List x = [1]; + x.myForEach(print); +\} +\end{dartCode} + +\commentary{% +Here both of the extensions apply, +but \code{ExtendList} is more specific than \code{ExtendIterable} because +\SubtypeNE{\code{List}}{\code{Iterable}}.% +} + +\begin{dartCode} +\EXTENSION{} BestCom \ON{} Iterable \{ T best() \{...\}\} +\EXTENSION{} BestList \ON{} List \{ T best() \{...\}\} +\EXTENSION{} BestSpec \ON{} List \{ num best() \{...\}\} +\\ +\VOID{} main() \{ + List x = ...; + \VAR{} v = x.best(); + List y = ...; + \VAR{} w = y.best(); +\} +\end{dartCode} + +\commentary{% +Here all three extensions apply to both invocations. +For \code{x.best()}, \code{BestList} is most specific, +because \code{List} is a proper subtype of both +\code{Iterable} and \code{List}. +Hence, the type of \code{x.best()} is \code{int}. + +For \code{y.best()}, \code{BestSpec} is most specific. +The instantiated \ON{} types that are compared are +\code{Iterable} for \code{BestCom} and +\code{List} for the two other extensions. +Using the instantiation-to-bound \ON{} types as a tie breaker, +we find that \code{List} is less precise than \code{List}, +so \code{BestSpec} is selected. +Hence, the type of \code{y.best()} is \code{num}.% +} + +\rationale{% +In general, the definition of specificity aims to select +the extension which has more precise type information available. +This does not necessarily yield the most precise type of the result +(for instance, \code{BestSpec.best} could have returned \code{Object}), +but it is also important that the rule is simple. + +In practice, we expect unintended extension member name conflicts to be rare. +If the same author is providing more specialized versions of +an extension for subtypes, +the choice of an extension which has the most precise types available +is likely to be a rather unsurprising and useful behavior.% +} + + +\subsection{Static analysis of Members of an Extension} +\LMLabel{staticAnalysisOfMembersOfAnExtension} + +\LMHash{}% +Static analysis of the member declarations in an extension $E$ +relies on the scopes of the extension +(\ref{extensions}) +and follows the normal rules except for the following: + +\LMHash{}% +When static analysis is performed on the body of an instance member +of an extension $E$ with \ON{} type $T_{on}$, +the static type of \THIS{} is $T_{on}$. + +\LMHash{}% +A compile-time error occurs if the body of an extension member +contains \SUPER. + +\commentary{% +A lexical lookup in an extension $E$ may yield +a declaration of an instance method declared in $E$. +As specified elsewhere +(\ref{lexicalLookup}), +this implies that extension instance members +will shadow class instance members +when called from another instance member inside the same extension +using an unqualified function invocation +(that is, invoking it as \code{m()} and not \code{\THIS.m()}, +\ref{unqualifiedInvocation}). +% +This is the only situation where implicit invocation of +an extension member with basename \id{} +can succeed even if the interface of the receiver has +a member with basename \id. +% +On the other hand, it is consistent with the general property of Dart that +lexically enclosing declarations shadow other declarations, e.g., +an inherited declaration can be shadowed by a global declaration. +Here is an example:% +} + +\begin{dartCode} +\EXTENSION{} MyUnaryNumber \ON{} List \{ + bool get isEven => length.isEven; + bool get isOdd => !isEven; + static bool isListEven(List list) => list.isEven; + List get first => []; + List get smallest => first; +\} +\end{dartCode} + +\commentary{% +With \code{list.isEven}, +\code{isEven} resolves to the declaration in \code{MyUnaryNumber}, +given that \code{List} does not have a member with basename \code{isEven}, +and unless there are any other extensions creating a conflict. + +The use of \code{length} in the declaration of \code{isEven} +is not defined in the current lexical scope, +so it is treated as \code{\THIS.length}, +because the interface of the \ON{} type \code{List} has +a \code{length} getter. + +The use of \code{isEven} in \code{isOdd} resolves lexically to +the \code{isEven} getter above it, +so it is treated as \code{MyUnaryNumber(this).isEven}, +even if there are other extensions in scope +which define an \code{isEven} on \code{List}. + +The use of \code{first} in \code{smallest} resolves lexically to +the \code{first} getter above it, +even though there is a member with the same basename in +the interface of \THIS. +The getter \code{first} cannot be called +in an implicit invocation from anywhere outside of \code{MyUnaryNumber}. +This is the exceptional case mentioned above, +where a member of an extension shadows +a regular instance member on \THIS. +In practice, extensions will very rarely introduce members +with the same basename as a member of its \ON{} type's interface. + +An unqualified identifier \code{id} which is not in scope +is treated as \code{\THIS.id} inside instance members as usual +(\ref{lexicalLookup}). +If \code{id} is not declared by the static type of \THIS{} +(the \ON{} type) +then it may be an error, +or it may be resolved using a different extension.% +} + + +\subsection{Extension Method Closurization} +\LMLabel{extensionMethodClosurization} + +\LMHash{}% +An extension instance method is subject to closurization +in a similar manner as class instance methods +(\ref{superGetterAccessAndMethodClosurization}). + +\LMHash{}% +\BlindDefineSymbol{a, E, S_j, e_1}% +Let $a$ be an extension application +(\ref{explicitExtensionInvocations}) +of the form \code{$E$<\List{S}{1}{m}>($e_1$)}. +\BlindDefineSymbol{Y_j, m}% +Let \List{Y}{1}{m} be the formal type parameters +of the extension $E$. +% +\BlindDefineSymbol{e, \id}% +An expression $e$ of the form \code{$a$.\id} +where \id{} is an identifier is then known as an +\IndexCustom{extension property extraction}{% + extension!property extraction}. +It is a compile-time error unless $E$ declares an instance member named \id. +If said instance member is a method then +$e$ has the static type $[S_1/Y_1, \ldots, S_m/Y_m]F$, +where $F$ is the function type of said method declaration. + +\commentary{% +If \id{} is a getter then $e$ is a getter invocation, +which is specified elsewhere +(\ref{explicitExtensionInvocations}).% +} + +\LMHash{}% +If \id{} is a method then $e$ is known as an +\IndexCustom{instance method closurization}{% + extension!instance method closurization} +of \id{} on $a$, +and evaluation of $e$ +(\commentary{which is \code{$E$<\List{S}{1}{m}>($e_1$).\id}}) +proceeds as follows: + +\LMHash{}% +Evaluate $e_1$ to an object $o$. +Let $u$ be a fresh final variable bound to $o$. +Then $e$ evaluates to a function object which is equivalent to: +\begin{itemize} +\item +\begin{normativeDartCode} +<\TypeParameters{X}{B'}{s}> +($\PairList{T}{p}{1}{n},\ $\{$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$\}) => +\quad$E$<\List{S}{1}{m}>($u$) +\quad.\id<\List{X}{1}{s}>($\List{p}{1}{n},\ p_{n+1}$: $p_{n+1}, \ldots,\ p_{n+k}$: $p_{n+k}$); +\end{normativeDartCode} +where \id{} declares type parameters +\TypeParametersStd, +required parameters \List{p}{1}{n}, +and named parameters \List{p}{n+1}{n+k} with defaults \List{d}{1}{k}, +using \code{null} for parameters whose default value is not specified. +\item +\begin{normativeDartCode} +<\TypeParameters{X}{B'}{s}> +($\PairList{T}{p}{1}{n},\ $[$T_{n+1}\ p_{n+1} = d_1, \ldots,\ T_{n+k}\ p_{n+k} = d_k$]) => +\quad$E$<\List{S}{1}{m}>($u$).\id<\List{X}{1}{s}>(\List{p}{1}{n+k}); +\end{normativeDartCode} +where \id{} declares type parameters +\TypeParametersStd, +required parameters \List{p}{1}{n}, +and optional positional parameters +\List{p}{n+1}{n+k} with defaults \List{d}{1}{k}, +using \code{null} for parameters whose default value is not specified. +\end{itemize} + +\LMHash{}% +In the function literals above, +$B'_j = [S_1/Y_1, \ldots, S_m/Y_m]B_j, j \in 1 .. s$, +and $T_j = [S_1/Y_1, \ldots, S_m/Y_m]T'_j, j \in 1 .. n+k$, +where $T'_j$ is the type of the corresponding parameter in +the declaration of \id. +Capture of type variables in \List{S}{1}{m} must be avoided, +so $X_j$ must be renamed if \List{S}{1}{m} contains any occurrences of $X_j$, +for all $j \in 1 .. s$. + +\commentary{% +In other words, the closurization is the value of +a function literal whose signature is the same as that of \id, +except that the actual type arguments are substituted for +the formal type parameters of $E$, +and then it simply forwards the invocation +to \id{} with the captured object $u$ as the receiver.% +} + +\commentary{% +Two extension instance method closurizations are never equal +unless they are identical. +Note that this differs from closurizations of class instance methods, +which are equal when they tear off the same method of the same receiver.% +} + +\rationale{% +The reason for this difference is that even if $o_1$ and $o_2$ +are instance method closurizations of the same extension $E$ +applied to the same receiver $o$, +they may have different actual type arguments passed to $E$, +because those type arguments are determined by the call site +(and with inference: by the static type of the expression yielding $o$), +and not just by the properties of $o$ and the torn-off method.% +} + +\commentary{% +Note that an instance method closurization on an extension is not +a constant expression, +even in the case where the receiver is a constant expression. +This is because it creates a new function object each time it is evaluated.% +} + +\LMHash{}% +Extension method closurization can occur for an implicit invocation +of an extension instance member. + +\commentary{% +This is a consequence of the fact that the implicit invocation is +treated as the corresponding explicit invocation +(\ref{implicitExtensionInvocations}). +For instance, +\code{$e$.\id} may be implicitly transformed into +\code{$E$<$T_1, T_2$>($e$).\id}, +which is then handled as specified above.% +} + +\LMHash{}% +Extension method closurizations are subject to generic function instantiation +(\ref{genericFunctionInstantiation}). +\commentary{For example:} + +\begin{dartCode} +\EXTENSION{} \ON{} int \{ + Set asSet() => \{if (\THIS{} \IS T) \THIS{} \AS{} T\}; +\} +\\ +\VOID{} main() \{ + Set Function() f = 1.asSet; + print(f()); // \comment{Prints '\{\}'.} +\} +\end{dartCode} + +\commentary{% +In this example \code{\{\}} is printed, +because the function object obtained by extension method closurization +was subject to a generic function instantiation +which gave \code{T} the value \code{double}, +which makes `\code{\THIS\,\,\IS\,\,T}' evaluate to false.% +} + + +\subsection{The \CALL{} Member of an Extension} +\LMLabel{theCallMemberOfAnExtension} + +\LMHash{}% +An extension can provide a \CALL{} method which is invoked implicitly, +similarly to a function expression invocation +(\ref{functionExpressionInvocation}). + +\commentary{% +E.g., \code{$e$()} is treated as \code{$e$.call()} +when the static type of $e$ is a non-function that has a method named \CALL. +Here is an example where the \CALL{} method comes from an extension:% +} + +\begin{dartCode} +\EXTENSION{} $E$ \ON{} int \{ + Iterable call(int to) => + Iterable.generate(to - this + 1, (i) => this + i); +\} +\\ +\VOID{} main() \{ + \FOR{} (\VAR{} i \IN{} 1(3)) print(i); // \comment{Prints 1, 2, 3.} + \FOR{} (\VAR{} i \IN{} $E$(4)(5)) print(i); // \comment{Prints 4, 5.} +\} +\end{dartCode} + +\rationale{% +This may look somewhat surprising, +though similar to an approach using \code{\OPERATOR []}: +\code{\FOR{} (\VAR{} i \IN{} 1[3])\,\,\{\,...\,\}}. +We expect developers to use this power responsibly.% +} + +\LMHash{}% +\BlindDefineSymbol{a, i}% +Let $a$ be an extension application +(\ref{explicitExtensionInvocations}), +and $i$ an expression of the form + +\noindent +\code{$a$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$:\ $a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)} + +\noindent +(\commentary{where the type argument list is omitted when $r$ is zero}). +$i$ is then treated as +(\ref{notation}) + +\noindent +\code{$a$.\CALL<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$:\ $a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)}. + +\commentary{% +In other words, an invocation of an extension application +is immediately treated as an invocation of an extension method named \CALL.% +} + +\LMHash{}% +\BlindDefineSymbol{e, S, i}% +Let $e$ be an expression with static type $S$ +which is not a property extraction expression +(\ref{propertyExtraction}), +and let $i$ be an expression of the form + +\noindent +\code{$e$<$A_1, \ldots,\ A_r$>($a_1, \ldots,\ a_n,\ x_{n+1}$:\ $a_{n+1}, \ldots,\ x_{n+k}$:\ $a_{n+k}$)} + +\noindent +(\commentary{where the type argument list is again omitted when $r$ is zero}). +If $S$ is \DYNAMIC, \FUNCTION, or a function type, +or the interface of $S$ has a method named \CALL, +$i$ is specified elsewhere +(\ref{functionExpressionInvocation}). +Otherwise, if $S$ has a non-method instance member with basename \CALL{} +then $i$ is a compile-time error. +Otherwise, $i$ is treated as the expression $i'$ which is + +\noindent +\code{$e$.\CALL<$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 $i'$ can be an implicit invocation of +an extension method named \CALL, +and it can be an error. +In the latter case, error messages should be worded in terms of $i$, +not $i'$.% +} + +\LMHash{}% +It is a compile-time error unless $i'$ is an implicit invocation of +an extension instance method named \CALL. + +\commentary{% +In particular, $i'$ cannot be an invocation of an extension getter +whose return type is a function type, \FUNCTION, or \DYNAMIC.% +} + +\commentary{% +Note that there is no support for an implicit property extraction +which tears off an extension method named \CALL. +For instance, assuming the extension $E$ declared in the previous example:% +} + +\begin{dartCode} +Iterable \FUNCTION(int) from2 = 2; // \comment{Error.} +\end{dartCode} + +\rationale{% +The implicit property extraction could be allowed, +but it would come at a readability cost. +A type like \code{int} is well known as being non-callable, +and an implicit \code{.call} tear-off would have no visible syntax. +In an implicit \CALL{} invocation, the arguments are visible to a reader, +but for an implicit tear-off of a \CALL{} function, +there is no visible syntax at all.% +} + +\commentary{% +If desired, the property extraction can be expressed explicitly +using \code{2.\CALL}.% +} + + +\section{Enums} +\LMLabel{enums} + +\LMHash{}% +An \Index{enumerated type}, or \Index{enum}, is used to represent +a fixed number of constant values. + +\begin{grammar} + ::= \ENUM{} + \gnewline{} `{' (`,' )* (`,')? `}' + + ::= +\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{normativeDartCode} +$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{normativeDartCode} + +\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 declaration of a class (\ref{classes}), +mixin (\ref{mixins}), +extension (\ref{extensions}), +type alias (\ref{typedef}), +or function (\ref{functions}) $G$ may be \Index{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 \IndexCustom{generic class declaration}{class declaration!generic} +introduces a generic class into the library scope of the current library. +A \IndexCustom{generic class}{class!generic} +is a mapping that accepts a list of actual type arguments +and maps them to a class. +Consider a generic class declaration $G$ named $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}). + +\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 $G$ by replacing +each occurrence of $X_j$ by $T_j$. + +\commentary{% +Other properties of $C'$ such as the subtype relationships +are specified elsewhere +(\ref{subtypes}).% +} + +\commentary{% +Generic type aliases are specified elsewhere +(\ref{typedef}).% +} + +\LMHash{}% +A \IndexCustom{generic type}{type!generic} 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 \IndexCustom{generic function declaration}{function declaration!generic} +introduces a generic function (\ref{formalParameters}) into the current scope. + +\LMHash{}% +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$. +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} + ::= (\EXTENDS{} )? + + ::= `<' (`,' )* `>' +\end{grammar} + +\LMHash{}% +A type parameter $T$ may be suffixed with an \EXTENDS{} clause +that specifies the \Index{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$. + +\commentary{% +However, a type parameter of a generic class +is considered to be a malformed type +when referenced by a static member +(\ref{staticTypes}). +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. +This enables typechecking code such as:% +} + +\begin{dartCode} +\CLASS{} Ordered \{ + operator >(T x); +\} + +\CLASS{} Sorter 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.% +} + + +\subsection{Variance} +\LMLabel{variance} + +\LMHash{}% +We say that a type $S$ \Index{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$ \Index{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$ \Index{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 in a \Index{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 generic 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 generic 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 in a \Index{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 generic 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 generic 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 in an \Index{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 generic 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 generic 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 +\IndexCustom{the formal type parameter $X_j$ is invariant}{% + type parameter!invariant} +if{}f $X_j$ occurs invariantly in $T$, $X_j$ +\IndexCustom{is covariant}{type parameter!covariant} +if{}f $X_j$ occurs covariantly in $T$, and $X_j$ +\IndexCustom{is contravariant}{type parameter!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 \Index{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{}>}.% +} + +% 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 \Index{regular-bounded}. + +\commentary{% +In particular, every non-generic class and every function type +is a regular-bounded type.% +} + +\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 generic 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 \Index{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 regular-bounded types are those types +that do not violate their type parameter bounds.% +} + +\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 generic type alias. +$T$ is \Index{super-bounded} if{}f the following conditions are both true: + +\begin{itemize} +\item + $T$ is not regular-bounded. +\item + Let $T'$ be the result of replacing every occurrence in $T$ + of a top type in a covariant position by \code{Null}, + and every occurrence in $T$ + of \code{Null} in a contravariant position by \code{Object}. + It is then required that $T'$ is regular-bounded. + % + Moreover, if $G$ denotes a generic type alias with body $U$, + it is required that every type that occurs as a subterm of + $[S_1/X_1, \ldots,\ S_n/X_n]U$ + is well-bounded (defined below). +\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 \Index{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 of a class + (\ref{superclasses}), + or it occurs as an element in the type list of an \IMPLEMENTS{} clause + %% TODO(eernst): Come extension types, add ref. Maybe mixin class? + (\ref{superinterfaces}, \ref{enums}, \ref{mixins}), + or a \WITH{} clause + (\ref{classes}, \ref{enums}), + or it occurs as an element in the type list of an \ON{} clause of a mixin + (\ref{mixins}). +\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 x; +\} +\\ +A 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.% +} + +\commentary{% +For example, consider the following class:% +} + +\begin{dartCode} +\CLASS{} C$\!$> \{ + X next; +\} +\end{dartCode} + +\commentary{% +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').% +} + +\rationale{% +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$\!$>$\!$>$\!$>}. +% +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} and +\code{C{}>{}>} +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{}>} +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{}>} then already +\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.% +} + + +\subsection{Instantiation to Bound} +\LMLabel{instantiationToBound} + +\LMHash{}% +This section describes how to compute type arguments +that are omitted from a type, +or from an invocation of a generic function. + +\commentary{% +%% TODO(eernst): When we add a specification of type inference, we will adjust +%% the specification of i2b such that it allows for taking initial values for +%% the actual type arguments (that is, $U_{j,0}$ is given "from the caller" for +%% some $j$; probably "the caller" will always be type inference), and all other +%% parts of the algorithm remain unchanged. +%% I think it will be more confusing than helpful to start writing this now, +%% and it will be a small adjustment when we add a spec of type inference. So +%% at this point we just specify i2b as a stand-alone algorithm. +Note that type inference is assumed to have taken place already +(\ref{overview}), +so type arguments are not considered to be omitted if they are inferred. +This means that instantiation to bound is a backup mechanism, +which will be used when no information is available for inference.% +} + +\LMHash{}% +Consider the situation where a term $t$ of the form \synt{typeName} +denotes a generic type declaration, +and it is used as a type or as an expression in the enclosing program. +\commentary{% +This implies that type arguments are accepted, but not provided.% +} +We use the phrase +\Index{raw type} respectively \Index{raw type expression} +to identify such terms. +In the following we only mention raw types, +but everything said about raw types +applies to raw type expressions in the obvious manner. + +\commentary{% +For instance, with the declaration \code{Type listType() => List;}, +evaluation of the raw type expression \code{List} in the body yields +an instance of class \code{Type} reifying \code{List}, +because \code{List} is subject to instantiation to bound. +Note that \code{List} is not syntactically an expression, +but it is still possible to get access to +a \code{Type} instance reifying \code{List} +without instantiation to bound, +because it can be the value of a type variable.% +} + +\rationale{% +We can unambiguously define raw types to denote +the result of applying the generic type +to a list of implicitly provided actual type arguments, +and instantiation to bound is a mechanism which does just that. +This is because Dart does not, and will not, support higher-kinded types; +for example, the value of a type variable $X$ will be a type, +it cannot be the generic class \code{List} as such, +and it cannot be applied to type arguments, e.g., \code{$X$}.% +} + +\rationale{% +In the typical case where only covariance is encountered, +instantiation to bound will yield a \emph{supertype} of +all the regular-bounded types that can be expressed. +This allows developers to consider a raw type as a type +which is used to specify that +``the actual type arguments do not matter''$\!$.% +} +\commentary{% +For example, assuming the declaration +\code{\CLASS{} C \{\ldots\}}, +instantiation to bound on \code{C} yields \code{C}, +and this means that \code{C x;} can be used to declare a variable \code{x} +whose value can be a \code{C<$T$>} for \emph{all possible} values of $T$.% +} + +\rationale{% +Conversely, consider the situation where +a generic type alias denotes a function type, +and it has one type parameter which is contravariant. +Instantiation to bound on that type alias will then yield a \emph{subtype} of +all the regular-bounded types that can be expressed +by varying that type argument. +This allows developers to consider such a type alias used as a raw type +as a function type which allows the function to be passed to clients +``where it does not matter which values +for the type argument the client expects''$\!$.% +} +\commentary{% +E.g., with +\code{\TYPEDEF{} F = \FUNCTION(X);} +instantiation to bound on \code{F} yields \code{F}, +and this means that \code{F f;} can be used to declare a variable \code{f} +whose value will be a function that can be passed to clients expecting +an \code{F<$T$>} for \emph{all possible} values of $T$.% +} + + +\subsubsection{Auxiliary Concepts for Instantiation to Bound} +\LMLabel{auxiliaryConceptsForInstantiationToBound} + +\LMHash{}% +Before we specify instantiation to bound +we need to define two auxiliary concepts. +Let $T$ be a raw type. +A type $S$ then +\IndexCustom{raw-depends on}{raw-depends on!type} +$T$ if one or more of the following conditions hold: + +\begin{itemize} +\item + $S$ is of the form \synt{typeName}, and $S$ is $T$. + \commentary{% + Note that this case is not applicable + if $S$ is a subterm of a term of the form + \syntax{$S$ }, + that is, + if $S$ receives any type arguments. + Also note that $S$ cannot be a type variable, + because then `$S$ is $T$' cannot hold. + See the discussion below and the reference to~\ref{subtypeRules} + for more details about why this is so.% + } +\item + $S$ is of the form \syntax{ }, + and one of the type arguments raw-depends on $T$. +\item + $S$ is of the form \syntax{ ?}\ where + \synt{typeName} denotes a type alias $F$, + and the body of $F$ raw-depends on $T$. +\item + $S$ is of the form + \syntax{? \FUNCTION{} ? } and + \syntax{?}\ raw-depends on $T$, + or a bound in \syntax{?}\ raw-depends on $T$, + or a type in \synt{parameterTypeList} raw-depends on $T$. +\end{itemize} + +\commentary{% +Meta-variables +(\ref{metaVariables}) +like $S$ and $T$ are understood to denote types, +and they are considered to be equal (as in `$S$ is $T$') +in the same sense as in the section about subtype rules +(\ref{subtypeRules}). +% +In particular, +even though two identical pieces of syntax may denote two distinct types, +and two different pieces of syntax may denote the same type, +the property of interest here is whether they denote the same type +and not whether they are spelled identically. + +The intuition behind the situation where a type raw-depends on another type is +that we need to compute any missing type arguments for the latter +in order to be able to tell what the former means. + +In the rule about type aliases, $F$ may or may not be generic, +and type arguments may or may not be present. +However, there is no need to consider the result of substituting +actual type arguments for formal type parameters in the body of $F$ +(or even the correctness of passing those type arguments to $F$), +because we only need to inspect +all types of the form \synt{typeName} in its body, +and they are not affected by such a substitution. +In other words, raw-dependency is a relation +which is simple and cheap to compute.% +} + +\LMHash{}% +Let $G$ be a generic class or a generic type alias +with $k$ formal type parameter declarations +containing formal type parameters \List{X}{1}{k} and bounds \List{B}{1}{k}. +For any $j \in 1 .. k$, +we say that the formal type parameter $X_j$ has a \Index{simple bound} +when one of the following requirements is satisfied: + +\begin{itemize} +\item $B_j$ is omitted. + +\item $B_j$ is included, but does not contain any of \List{X}{1}{k}. + If $B_j$ raw-depends on a raw type $T$ + then every type parameter of $T$ must have a simple bound. +\end{itemize} + +\LMHash{}% +The notion of a simple bound must be interpreted inductively rather than +coinductively, i.e., if a bound $B_j$ of a generic class or +generic type alias $G$ is reached during an investigation of whether +$B_j$ is a simple bound, the answer is no. + +\commentary{% +For example, with +\code{\CLASS{} C \{\}}, +the type parameter \code{X} does not have a simple bound: +A raw \code{C} is used as a bound for \code{X}, +so \code{C} must have simple bounds, +but one of the bounds of \code{C} is the bound of \code{X}, +and that bound is \code{C}, so \code{C} must have simple bounds: +That was a cycle, so the answer is ``no'', +\code{C} does not have simple bounds.% +} + +\LMHash{}% +Let $G$ be a generic class or a generic type alias. +We say that $G$ +\IndexCustom{has simple bounds}{type!generic, has simple bounds} +if{}f every type parameter of $G$ has simple bounds. + +\commentary{% +We can now specify in which sense instantiation to bound requires +the involved types to be "simple enough". +We impose the following constraint on all type parameter bounds, +because all type parameters may be subject to instantiation to bound.% +} + +\LMHash{}% +It is a compile-time error +if a formal type parameter bound $B$ contains a raw type $T$, +unless $T$ has simple bounds. + +\commentary{% +So type arguments on bounds can only be omitted +if they themselves have simple bounds. +In particular, +\code{\CLASS{} C \{\}} +is a compile-time error, +because the bound \code{C} is raw, +and the formal type parameter \code{X} +that corresponds to the omitted type argument +does not have a simple bound.% +} + +\LMHash{}% +Let $T$ be a type of the form \synt{typeName} +which denotes a generic class or a generic type alias +(\commentary{so $T$ is raw}). +Then $T$ is equivalent to the parameterized type which is +the result obtained by applying instantiation to bound to $T$. +It is a compile-time error if the instantiation to bound fails. + +\commentary{% +This rule is applicable for all occurrences of raw types, +e.g., when it occurs as a type annotation of a variable or a parameter, +as a return type of a function, +as a type which is tested in a type test, +as the type in an \synt{onPart}, +etc.% +} + + +\subsubsection{The Instantiation to Bound Algorithm} +\LMLabel{theInstantiationToBoundAlgorithm} + +\LMHash{}% +We now specify how the +\Index{instantiation to bound} +algorithm proceeds. +Let $T$ be a raw type. +Let \List{X}{1}{k} be the formal type parameters in the declaration of $G$, +and let \List{B}{1}{k} be their bounds. +For each $i \in 1 .. k$, +let $S_i$ denote the result of instantiation to bound on $B_i$; +in the case where the $i$th bound is omitted, let $S_i$ be \DYNAMIC. + +\commentary{% +If $B_i$ for some $i$ is raw (in general: if it raw-depends on some type $U$) +then all its (respectively $U$'s) omitted type arguments have simple bounds. +This limits the complexity of instantiation to bound for $B_i$, +and in particular it cannot involve a dependency cycle +where we need the result from instantiation to bound for $G$ +in order to compute the instantiation to bound for $G$.% +} + +\LMHash{}% +Let $U_{i,0}$ be $S_i$, for all $i \in 1 .. k$. +\commentary{% +This is the "current value" of the bound for type variable $i$, at step 0; +in general we will consider the current step, $m$, and use data for that step, +e.g., the bound $U_{i,m}$, to compute the data for step $m + 1$.% +} + +{ %% Scope for definitions of relations used during i2b + +\def\Depends{\ensuremath{\rightarrow_m}} +\def\TransitivelyDepends{\ensuremath{\rightarrow^{+}_m}} + +\LMHash{}% +Let \Depends{} be a relation among the type variables +\List{X}{1}{k} such that +$X_p \Depends X_q$ iff $X_q$ occurs in $U_{p,m}$. +\commentary{% +So each type variable is related to, that is, depends on, +every type variable in its bound, which might include itself.% +} +Let \TransitivelyDepends{} be the transitive +(\commentary{but not reflexive}) +closure of \Depends. +For each $m$, let $U_{i,m+1}$, for $i \in 1 .. k$, +be determined by the following iterative process, where $V_m$ denotes +\code{$G$<$U_{1,m},\ \ldots,\ U_{k,m}$>}: + +\begin{itemize} +\item[1.] + If there exists a $j \in 1 .. k$ such that + $X_j \TransitivelyDepends X_j$ + (\commentary{that is, if the dependency graph has a cycle}) + let \List{M}{1}{p} be the strongly connected components (SCCs) + with respect to \Depends. + \commentary{% + That is, the maximal subsets of \List{X}{1}{k} + where every pair of variables in each subset + are related in both directions by \TransitivelyDepends; + note that the SCCs are pairwise disjoint; + also, they are uniquely defined up to reordering, + and the order does not matter for this algorithm.% + } + Let $M$ be the union of \List{M}{1}{p} + (\commentary{that is, all variables that participate in a dependency cycle}). + Let $i \in 1 .. k$. + If $X_i$ does not belong to $M$ then $U_{i,m+1}$ is $U_{i,m}$. + Otherwise there exists a $q$ such that $X_i \in M_q$; + $U_{i,m+1}$ is then obtained from $U_{i,m}$ + by substituting \DYNAMIC{} for every occurrence of a variable in $M_q$ + that is in a position in $V_m$ which is not contravariant, + and substituting \code{Null} for every occurrence of a variable in $M_q$ + which is in a contravariant position in $V_m$. + +\item[2.] + Otherwise (\commentary{when there are no dependency cycles}), + let $j$ be the lowest number such that $X_j$ occurs in $U_{p,m}$ for some $p$ + and $X_j \not\rightarrow_m X_q$ for all $q$ in $1 .. k$ + (\commentary{% + that is, the bound of $X_j$ does not contain any type variables, + but $X_j$ occurs in the bound of some other type variable% + }). + Then, for all $i \in 1 .. k$, + $U_{i,m+1}$ is obtained from $U_{i,m}$ + by substituting $U_{j,m}$ for every occurrence of $X_j$ + that is in a position in $V_m$ which is not contravariant, + and substituting \code{Null} for every occurrence of $X_j$ + which is in a contravariant position in $V_m$. + +\item[3.] + Otherwise (\commentary{when there are no dependencies at all}), + terminate with the result \code{<$U_{1,m},\ \ldots,\ U_{k,m}$>}. +\end{itemize} + +\commentary{% +This process will always terminate, because the total number of +occurrences of type variables from $\{\,\List{X}{1}{k}\,\}$ in +the current bounds is strictly decreasing with each step, and we terminate +when that number reaches zero.% +} + +\rationale{% +It may seem somewhat arbitrary to treat unused and invariant parameters +in the same way as covariant parameters, +in particular because invariant parameters fail to satisfy the expectation that +a raw type denotes a supertype of all the expressible regular-bounded types. + +We could easily have made every instantiation to bound an error +when applied to a type where invariance occurs anywhere +during the run of the algorithm. +However, there are a number of cases where this choice produces a usable type, +and we decided that it is not helpful to outlaw such cases.% +} + +\begin{dartCode} +\TYPEDEF{} Inv = X \FUNCTION(X); +\CLASS{} B{}> \{\} +\\ +B b; // \comment{The raw B means} B{}>. +\end{dartCode} + +\commentary{% +For example, the value of \code{b} can have dynamic type +\code{B}. +However, the type arguments have to be chosen carefully, +or the result will not be a subtype of \code{B}. +For instance, \code{b} cannot have dynamic type +\code{B{}>}, +because \code{Inv} is not a subtype of \code{Inv}.% +} + +\LMHash{}% +A raw type $T$ is a compile-time error if instantiation to bound on $T$ +yields a type which is not well-bounded +(\ref{superBoundedTypes}). + +\commentary{% +This kind of error can occur, as demonstrated by the following example:% +} + +\begin{dartCode} +\CLASS{} C{}> \{\} +\TYPEDEF{} F{}> = X \FUNCTION(X); +\\ +F f; // \comment{Compile-time error.} +\end{dartCode} + +\commentary{% +With these declarations, +the raw \code{F} which is used as a type annotation is a compile-time error: +The algorithm yields \code{F{}>}, +and that is neither a regular-bounded nor a super-bounded type. +% +The resulting type can be specified explicitly as +\code{C<\DYNAMIC{}> \FUNCTION(C<\DYNAMIC{}>)}. +That type exists, +we just cannot express it by passing a type argument to \code{F}, +so we make it an error rather than allowing it implicitly.% +} + +\rationale{% +The core reason why it makes sense to make such a raw type an error +is that there is no subtype relationship +between the relevant parameterized types.% +} +\commentary{% +For instance, \code{F} and \code{F} are unrelated, +even when \SubtypeNE{\code{T1}}{\code{T2}} or vice versa. +In fact, there is no type \code{T} whatsoever +such that a variable with declared type \code{F} +could be assigned to a variable of type +\code{C<\DYNAMIC{}> \FUNCTION(C<\DYNAMIC{}>)}. +% +So the raw \code{F}, if permitted, +would not be ``a supertype of \code{F} for all possible \code{T}'', +it would be a type which is unrelated to \code{F} +for \emph{every single} \code{T} that satisfies the bound of \code{F}. +This is so useless that we made it an error.% +} + +\LMHash{}% +When instantiation to bound is applied to a type, it proceeds recursively: +For a parameterized type \code{$G$<\List{T}{1}{k}>} +it is applied to \List{T}{1}{k}. +For a function type +\FunctionTypePositionalStd{T_0} + +\noindent +and a function type +\FunctionTypeNamedStd{T_0} +it is applied to \List{T}{0}{n+k}. + +\commentary{% +This means that instantiation to bound has no effect on +a type that does not contain any raw types. +Conversely, instantiation to bound acts on types which are syntactic subterms, +also when they are deeply nested.% +} + +\LMHash{}% +\IndexCustom{Instantiation to bound on a generic function $f$}{% + generic function!instantiation to bound} +also uses the algorithm described above, +taking the formal parameters \List{X}{1}{k} from the declaration of $f$, +with bounds \List{B}{1}{k}, and, +for each $i \in 1 .. k$, +letting $S_i$ denote the result of instantiation to bound on $B_i$, +and letting $S_i$ be \DYNAMIC{} when the $i$th bound is omitted. + +\LMHash{}% +Let $f$ be a generic function declaration. +If instantiation to bound on $f$ yields +a list of type arguments \List{T}{1}{k} such that, +for some $j \in 1..k$, +$T_j$ is or contains a type which is not well-bounded, +or if \List{T}{1}{k} does not satisfy the bounds +on the formal type parameters of $f$, +then we say that +\IndexCustom{$f$ does not have default type arguments}{% + generic function!does not have default type arguments}. + + +\section{Metadata} +\LMLabel{metadata} + +\LMHash{}% +Dart supports metadata which is used to attach +user defined annotations to program structures. + +\begin{grammar} + ::= (`@' )* + + ::= \gnewline{} + | | +\end{grammar} + +\LMHash{}% +Metadata consists of a series of annotations, +each of which begin with the character \lit{@}, +followed by a constant expression $e$ derivable from +\synt{metadatum}. +It is a compile-time error if $e$ is not one of the following: +\begin{itemize} +\item A reference to a constant variable. +\item A call to a constant constructor. +\end{itemize} + +\commentary{% +The expression $e$ occurs in a constant context +(\ref{constantContexts}), +which means that \CONST{} modifiers need not be specified explicitly.% +} + +\LMHash{}% +Metadata that occurs as the first element of +the right hand side of a grammar rule +is associated with the abstract syntax tree for the non-terminal +on the left hand side of said grammar rule +\commentary{(that is, it is associated with its parent)}. +Otherwise, metadata is associated with the abstract syntax tree +of the program construct $p$ that immediately follows the metadata +in the grammar rule. + +\rationale{% +These rules are intended to ensure a minimal level of consistency +in the association that binds each metadatum to a program construct. +The structure of the abstract syntax tree is implementation specific, +and it is not even guaranteed that a tool will use anything +which is known as an abstract syntax tree. +In that case the phrase `abstract syntax tree' should be interpreted as +the program representation entities which are actually used. + +This implies that the fine details of the association between metadata +and an abstract syntax tree node is also implementation specific. +In particular, an implementation can choose to associate a given metadatum +with more than one abstract syntax tree node.% +} + +\LMHash{}% +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. +In this case the binding of each metadatum to an abstract syntax tree node +is determined by the given static analysis tool, +which is of course not subject to any constraints in this document. +Surely it will still be useful to strive for consistency among all tools +with respect to the binding from metadata to abstract syntax tree nodes.% +} + +\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 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{}% +An \Index{expression} is a fragment of Dart code +that can be evaluated at run time. + +\LMHash{}% +Every expression has an associated static type (\ref{staticTypes}) and +may have an associated static context type +%% TODO(eernst): This ref is undefined until CL 92782 is landed. +%% (\ref{contextTypes}), +which may affect the static type and evaluation of the expression. +Every object has an associated dynamic type (\ref{dynamicTypeSystem}). + +%% TODO(eernst): should derive as well, +%% the fact that it is currently derived from induces a genuine +%% and serious source of ambiguity, which makes it difficult to parse Dart +%% using anything other than a modified recursive descent parser. + +\begin{grammar} + ::= + \alt + \alt + \alt + + ::= \gnewline{} + + \alt + \alt + + ::= (`,' )* + + ::= + \alt \SUPER{} + \alt \SUPER{} + \alt + \alt + \alt + \alt + \alt + \alt + \alt `(' `)' + + ::= + \alt + \alt + \alt + \alt + \alt + \alt +\end{grammar} + +\LMHash{}% +An expression $e$ may always be enclosed in parentheses, +but this never has any semantic effect on $e$. + +\commentary{% +However, it may have an effect on the surrounding expression. +For instance, given a class \code{C} with a static method +\code{m() => 42}, \code{C.m()} returns 42, +but \code{(C).m()} is a compile-time error. +% +The point is that the meaning of \code{C.m()} +is specified in terms of several parts, +rather than being specified in a strictly compositional manner. +Concretely, the meaning of \code{C} and \code{(C)} as expressions is the same, +but the meaning of \code{C.m()} is not defined in terms of +the meaning of \code{C} as an expression, +and it differs from the meaning of \code{(C).m()}.% +% A strictly compositional evaluation would always evaluate every subexpression +% using the same rules (`evaluation` is always the same thing), and then it +% would combine the evaluation results into the result of the whole expression. +% We won't expand on that here, and in particular we won't discuss whether +% compositional evaluation is even meaningful in the context of side-effects. +% But it's still useful to keep in mind that we have these "highly +% non-compositional" elements in the semantics, such as static method +% lookups. +} + + +\subsection{Expression Evaluation} +\LMLabel{expressionEvaluation} + +\LMHash{}% +Evaluation of an expression either +\IndexCustom{produces an object}{expression!produces an object} +or it +\IndexCustom{throws}{expression!throws} +an exception object and an associated stack trace. +In the former case, we also say that the expression +\NoIndex{evaluates to an object}. + +\LMHash{}% +If evaluation of one expression, $e$, +is defined in terms of evaluation of another expression $e_1$, +typically a subexpression of $e$, +and the evaluation of $e_1$ throws an exception and a stack trace, +the evaluation of $e$ stops at that point +and throws the same exception object and stack trace. + + +\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 'constant' in Dart are associated with compile time. +A potentially constant expression is an expression that will generally yield +a constant value when the values of certain parameters are given. +The constant expressions is a subset of the potentially constant expressions +that \emph{can} be evaluated 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{Object}, \code{bool}, \code{int}, \code{double}, +\code{String}, \code{Type}, \code{Symbol}, or \code{Null}.% +} + +\LMHash{}% +The \IndexCustom{potentially constant expressions}{% + potentially constant expression} +and \IndexCustom{constant expressions}{constant expression} +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 an instance of type \code{int} or \code{double}. + % A too-large integer literal does not evaluate to an object. + +\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 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 + Let $e$ be 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. + If $e$ is not subject to generic function instantiation + (\ref{genericFunctionInstantiation}) + then $e$ is a potentially constant and constant expression. + If generic function instantiation does apply to $e$ + and the provided actual type arguments are \List{T}{1}{s} + then $e$ is a potentially constant and constant expression + if{}f each $T_j, j \in 1 .. s$, is a constant type expression + (\ref{constants}). + +\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. + It is further a constant expression if the invocation evaluates to an object. + % \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 an object. + +\item + A constant set literal (\ref{sets}), + \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 set literal evaluates to an object. + +\item + A constant map literal (\ref{maps}), + \code{\CONST{} <$K$, $V$>\{$k_1$: $v_1$, \ldots, $k_n$: $v_n$\}}, or + \code{<$K$, $V$>\{$k_1$: $v_1$, \ldots, $k_n$: $v_n$\}} + that occurs in a constant context, + is a potentially constant expression. + It is further a constant expression + if the map literal evaluates to an object. + +\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 an instance of \code{double} + or an instance that that has primitive equality + (\ref{theOperatorEqualsEquals}), + or $e_2$ evaluates to the null object + (\ref{null}). + +\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 + an instance 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 an instance 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 an instance of type \code{bool}. + \end{enumerate} + +\item + An expression of the form \code{\gtilde$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 an instance of type \code{int} + such that \gtilde{} denotes an instance operator invocation. + +\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 instances of \code{int}, + or both to instances of \code{bool}, + such that the operator symbol + \lit{\&}, \lit{|}, respectively \lit{\^} + denotes an instance operator invocation. + +\item An expression of one of the forms + \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 + both evaluate to an instance of \code{int}, + such that the operator symbol + \lit{\gtgt}, \lit{\gtgtgt}, respectively \lit{\ltlt} + denotes an instance operator invocation. + +\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 an instance of \code{int} or \code{double}, + or both evaluate to an instance of \code{String}, + such that \lit{+} denotes an instance operator invocation. + +\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 an instance of type \code{int} or \code{double}, + such that \lit{-} denotes an instance operator invocation. + +\item An expression of the form \code{$e_1$\,-\,$e_2$}, \code{$e_1$\,*\,$e_2$}, + \code{$e_1$\,/\,$e_2$},\code{$e_1$\,\gtilde/\,$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 instances of \code{int} or \code{double}, + such that the given operator symbol denotes + an invocation of an instance operator. + +\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 an object which is not the null object, or + \item $e_1$ evaluates to the null object, 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 an instance of \code{String}, + such that \code{length} denotes an instance getter invocation. + +\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 $e$ evaluates to an object which is not the null object + and not of type $T$.% + } + +\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. + +\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{}% +A +\Index{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 of 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 + %% TODO(eernst): This does not allow for type variables introduced by + %% the type itself. `Function(X)` could be a constant type expression, + %% but that is not covered by the current rules: `X` is a type variable, + %% and they are never allowed. + 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. + +\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} + + +\subsubsection{Further Remarks on Constants and Potential Constants} +\LMLabel{furtherCommentsOnConstantsAndPotentiallyConstants} + +\rationale{% +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.% +} + +\commentary{% +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 \gtilde/ 0; +\FINAL{} y = 1 \gtilde/ 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 of \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: +First, it is constant so we \emph{can} evaluate it at compile time. +Second, it seems more useful to give +the error stemming from the evaluation explicitly.% +} + +\rationale{% +One might reasonably ask why +$e_1$\,?\,\,$e_2$\,:\,$e_3$ and $e_1$\,??\,\,$e_2$ +have constant forms. +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, +e.g., in constant constructor initializers such as +\code{\CONST{} C(foo):\ \THIS.foo = foo ??\ someDefaultValue;}% +} + +\commentary{% +The difference between +a potentially constant expression and a constant expression +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 +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. +For instance:% +} + +\begin{dartCode} +\CLASS{} C \{ + \FINAL{} x, y, 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, +for an invocation of this constructor in a constant expression. +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 that 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 rules on constant constructors +(\ref{constantConstructors}), +combined with the rules for evaluating constant objects (\ref{const}).% +} + + +\subsubsection{Constant Contexts} +\LMLabel{constantContexts} + +\LMHash{}% +Let $e$ be an expression; $e$ occurs in a +\Index{constant context} +if{}f one of the following applies: + +% We avoid the circularity "constant context depends on constant list literal, +% etc., which depends on constant context" by mentioning the \CONST{} modifier +% explicitly here. So 'constant context' is consistently a lower-level concept +% based on syntax, and `constant X expressions' (like `constant list literal') +% are built on top of this. + +\begin{itemize} +\item $e$ is an element of a list or set literal whose first token is \CONST, + or $e$ is a key or a value of an entry + of a map literal whose first token is \CONST. +\item $e$ occurs as \code{@$e$} in a construct derived from \synt{metadata}. +\item $e$ is an actual argument in an expression derived from + \synt{constObjectExpression}. +\item $e$ is the initializing expression of a constant variable declaration + (\ref{variables}). +\item $e$ is a switch case expression + (\ref{switch}). +\item $e$ is an immediate subexpression of + an expression $e_0$ which occurs in a constant context, + where $e_0$ is + %% May be added later: + %% not a \THROW{} expression (\ref{throw}) and + not a function literal + (\ref{functionExpressions}). +\end{itemize} + +\rationale{% +A constant context is introduced in situations where +an expression is required to be constant. +This is used to allow the \CONST{} modifier to be omitted +in cases where it does not contribute any new information.% +} + + +\subsection{Null} +\LMLabel{null} + +\LMHash{}% +The reserved word \NULL{} evaluates to the \Index{null object}. + +\begin{grammar} + ::= \NULL{} +\end{grammar} + +\LMHash{}% +The null object is the sole instance of the built-in class \code{Null}. +% The following can be a consequence of the declaration of `Null`, +% but we don't spell that out, we just require that it is an error. +Attempting to instantiate \code{Null} causes a compile-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{% +The null object has primitive equality +(\ref{theOperatorEqualsEquals}).% +} + +\LMHash{}% +The static type of \NULL{} is the \code{Null} type. + + +\subsection{Numbers} +\LMLabel{numbers} + +\LMHash{}% +A \IndexCustom{numeric literal}{literal!numeric} +is either a decimal or hexadecimal numeral representing an integer value, +or a decimal double representation. + +\begin{grammar} + ::= + \alt + + ::= + (`.' +)? ? + \alt `.' + ? + + ::= (`e' | `E') (`+' | `-')? + + + ::= `0x' + + \alt `0X' + + + ::= `a' .. `f' + \alt `A' .. `F' + \alt +\end{grammar} + +\LMHash{}% +A numeric literal starting with `0x' or `0X' +is a \IndexCustom{hexadecimal integer literal}{literal!hexadecimal integer}. +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 +\IndexCustom{decimal integer literal}{literal!decimal integer}. +It has the numeric integer value of the decimal numeral. + +\LMHash{}% +An \IndexCustom{integer literal}{literal!integer} +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 +\IndexCustom{double literal}{literal!double}. +\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 \emph{precisely} by 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 \lit{==} operator inherited from the \code{Object} class. + + +\subsection{Booleans} +\LMLabel{booleans} + +\LMHash{}% +The reserved words \TRUE{} and \FALSE{} evaluate to objects +\IndexCustom{true}{true, the object} and +\IndexCustom{false}{false, the object} +that represent the boolean values true and false respectively. +They are the \IndexCustom{boolean literals}{literal!boolean}. + +\begin{grammar} + ::= \TRUE{} + \alt \FALSE{} +\end{grammar} + +\LMHash{}% +Both \NoIndex{true} and \NoIndex{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}. + +\commentary{% +The \TRUE{} and \FALSE{} objects have primitive equality +(\ref{theOperatorEqualsEquals}).% +} + +\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 \Index{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} + ::= ( | )+ +\end{grammar} + +\LMHash{}% +A string can be a sequence of single line strings and multiline strings. + +\begin{grammar} + ::= + \alt + \alt \gnewline{} + ( )* \gnewline{} + + \alt + \alt \gnewline{} + ( )* \gnewline{} + + + ::= + `r' `\sq' (\gtilde(`\sq' | `\\r' | `\\n'))* `\sq' + \alt `r' `"' (\gtilde(`"' | `\\r' | `\\n'))* `"' + + ::= \gtilde(`\\' | `\sq' | `"' | `$' | `\\r' | `\\n') + \alt + \alt `\\' \gtilde(`n' | `r' | `b' | `t' | `v' | `x' | `u' | `\\r' | `\\n') + \alt + + ::= | `"' + + ::= \gnewline{} + `\sq' * `\sq' + + ::= \gnewline{} + `\sq' * `${' + + ::= \gnewline{} + `}' * `${' + + ::= \gnewline{} + `}' * `\sq' + + ::= | `\sq' + + ::= \gnewline{} + `"' * `"' + + ::= \gnewline{} + `"' * `${' + + ::= \gnewline{} + `}' * `${' + + ::= \gnewline{} + `}' * `"' +\end{grammar} + +\LMHash{}% +A single line string is delimited by +either matching single quotes or matching double quotes. + +\commentary{% +Hence, \code{'abc'} and \code{"abc"} are both legal strings, +as are \code{'He said "To be or not to be" did he not?'} and +\code{"He said 'To be or not to be' didn't he?"}. +However, \code{"This'} is not a valid string, nor is \code{'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 would print `\code{A simple sum: 2 + 2 = 22}' rather than +`\code{A simple sum: 2 + 2 = 4}'. +However, for efficiency reasons, +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} + +\LMHash{}% +An auxiliary +\Index{string interpolation state stack} +is maintained outside the parser, +in order to ensure that string interpolations are matched up correctly. + +\commentary{% +This is necessary because the expression of a non-simple string interpolation +may itself contain string literals +with their own non-simple string interpolations.% +} + +\LMHash{}% +For rules with names \synt{\ldots\_BEGIN\_MID}, +a marker is pushed on the auxiliary stack to indicate that +a string interpolation of the given kind has started, +where the kind is \lit{\sq}, \lit{"}, \lit{\sqsqsq}, or \lit{"""}. +For rules with names \synt{\ldots\_MID\_MID}, +only the rule with the kind on the top of the auxiliary stack can be used. +For rules with names \synt{\ldots\_MID\_END}, +only the rule with the kind on the top of the auxiliary stack can be used, +and the marker is then popped. + +\begin{grammar} + ::= + \alt + \alt \gnewline{} + ( )* \gnewline{} + + \alt + \alt \gnewline{} + ( )* \gnewline{} + + + ::= `r' `\sqsqsq' .*? `\sqsqsq' + \alt `r' `"""' .*? `"""' + + ::= | `\sq' | `\sqsq' + + ::= \gnewline{} + ( | `"' | `\\r' | `\\n') + + ::= \gnewline{} + `\sqsqsq' * `\sqsqsq' + + ::= \gnewline{} + `\sqsqsq' * `${' + + ::= \gnewline{} + `}' * `${' + + ::= \gnewline{} + `}' * `\sqsqsq' + + ::= | `"' | `""' + + ::= \gnewline{} + ( | `\sq' | `\\r' | `\\n') + + ::= \gnewline{} + `"""' * `"""' + + ::= \gnewline{} + `"""' * `${' + + ::= \gnewline{} + `}' * `${' + + ::= \gnewline{} + `}' * `"""' + + ::= `\\n' | `\\r' | `\\f' | `\\b' | `\\t' | `\\v' + \alt `\\x' + \alt `\\u' + \alt `\\u{' `}' + + ::= \gnewline{} + ? ? + \gnewline{} ? ? ? +\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 \synt{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.% +} + +\LMHash{}% +In the rule for \synt{RAW\_MULTI\_LINE\_STRING}, +the two occurrences of \lit{.*?} +denote a non-greedy token recognition step: +It terminates as soon as the lookahead is the specified next token +(\commentary{that is, \lit{\sqsqsq}or \lit{"""}}). + +\commentary{% +Note that multi-line string interpolation relies on +the auxiliary string interpolation state stack, +just like single-line string interpolation.% +} + +\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' $_1$ $_2$}, equivalent to + + \syntax{`\\u{' $_1$ $_2$ `}'}. +\item + \syntax{`\\u' $_1$ $_2$ $_3$ $_4$}, + equivalent to + + \noindent + \syntax{`\\u{' $_1$ $_2$ $_3$ $_4$ `}'}. +\item + \syntax{`\\u{' `}'} is + the Unicode code point represented by the + \syntax{}. + It is a compile-time error if the value of the + \syntax{} + is not a valid Unicode code point. + \commentary{For example,} + {\color{commentaryColor}{\syntax{`\\u{0A}'}}\color{normativeColor}} + \commentary{is the code point U+000A.} +\item + \lit{\$} indicating the beginning of an interpolated expression. +\item + { % We need a definition for $k$ in order to be able to use it in \syntax. + \def\k{$k$} + 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 \lit{r}, +indicating that it is a \Index{raw string}, +in which case no escapes or interpolations are recognized. + +\LMHash{}% +Line breaks in a multiline string are represented by +the \synt{LINE\_BREAK} production. +A line break introduces a single newline character (U+000A) +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} + ::= `\\n' + \alt `\\r\\n' + \alt `\\r' +\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 \lit{==} 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 objects are converted into strings and +concatenated with the enclosing string. +This process is known as \Index{string interpolation}. + +\begin{grammar} + ::= + \alt `${' `}' + + ::= \gnewline{} + `$' ( | | \THIS) +\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 \lit{\$} character in a string signifies +the beginning of an interpolated expression. +The \lit{\$} sign may be followed by either: +\begin{itemize} +\item A single identifier \id{} that does not contain the \lit{\$} character + (but it can be a built-in identifier), + or the reserved word \THIS. +\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$) +into 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 object. +\item If $r_i$ is the null object, a dynamic error occurs. +\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 \IndexCustom{symbol literal}{literal!symbol} +denotes a name that would be either +a valid declaration name, a valid library name, or \VOID. + +\begin{grammar} + ::= + `#' ( (`.' )* | | \VOID) +\end{grammar} + +\LMHash{}% +The static type of a symbol literal is \code{Symbol}. + +\LMHash{}% +Let \id{} be an identifier that does not begin with an underscore +(`\code{\_}'). +The symbol literal \code{\#\id} +evaluates to an instance of \code{Symbol} +representing the identifier \id. + +\LMHash{}% +A symbol literal \code{\#$\id_1$.$\id_2$.$\cdots$.$\id_n$} +where \List{\id}{1}{n} are identifiers +evaluates to an instance of \code{Symbol} +representing that particular sequence of identifiers. +\commentary{% +This kind of symbol literal denotes the name of a library declaration, +as specified in a \synt{libraryName}. +Library names are not subject to library privacy, even +if some of its identifiers begin with an underscore.% +} + +\LMHash{}% +A symbol literal \code{\#\metavar{op}} +where \metavar{op} is derived from \synt{operator} +evaluates to an instance of \code{Symbol} +representing that particular operator name. + +\LMHash{}% +The symbol literal \code{\#void} +evaluates to an instance of \code{Symbol} +representing the reserved word \VOID. + +\LMHash{}% +For the value $o$ of a symbol literal representing a source code term +as specified in the previous paragraphs, we say that $o$ is a +\IndexCustom{non-private symbol based on}{symbol!non-private, based on} +the string whose contents is the characters of that term, without whitespace. + +\commentary{% +Note that this does not apply for private symbols, +which are discussed below. +A private symbol is not based on any string.% +} + +\LMHash{}% +If $o$ is the value of an invocation of the \code{Symbol} constructor +of the form +\code{Symbol($e$)}, \code{\NEW\,\,Symbol($e$)}, +or \code{\CONST\,\,Symbol($e$)}, +where $e$ is an expression +(\commentary{constant if necessary}) +that evaluates to a string $s$, +we say that $o$ is a \NoIndex{non-private symbol based on} $s$. + +\commentary{% +Note that \code{Symbol('\_foo')} is a non-private symbol, +and it is distinct from \code{\#\_foo}, as described below.% +} + +\LMHash{}% +Assume that $i \in 1,2$, +and that $o_i$ is the value of a constant expression +which is a symbol based on the string $s_i$. +If \code{$s_1$\,==\,$s_2$} then $o_1$ and $o_2$ is the same object. +\commentary{That is, symbol instances are canonicalized.} + +\LMHash{}% +If $o_1$ and $o_2$ are non-private symbols +(\commentary{not necessarily constant}) +based on strings $s_1$ and $s_2$ +then $o_1$ and $o_2$ are equal according to operator \lit{==} +if and only if \code{$s_1$ == $s_2$} +(\ref{equality}). + +\LMHash{}% +A symbol literal \code{\#\_\id} where \code{\_\id} is an identifier +evaluates to an instance of \code{Symbol} +representing the private identifier \code{\_\id} of the enclosing library. +All occurrences of \code{\#\_\id} \emph{in the same library} evaluate to +the same object, +and no other symbol literal or \code{Symbol} constructor invocation +evaluates to the same object, +nor to a \code{Symbol} instance that is equal to that object +according to the \lit{==} operator. + +\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.% +} + + +\subsection{Collection Literals} +\LMLabel{collectionLiterals} + +\LMHash{}% +This section specifies several literal expressions denoting collections. +Some syntactic forms may denote more than one kind of collection, +in which case a disambiguation step is performed +in order to determine the kind +(\ref{setAndMapLiteralDisambiguation}). + +\LMHash{}% +The subsections of this section are concerned with mechanisms that are +common to all kinds of collection literals +(\ref{collectionLiteralTypePromotion}, +\ref{collectionLiteralElementEvaluation}), +followed by a specification of list literals +(\ref{listLiteralInference}, \ref{lists}), +followed by a specification of how to disambiguate and infer types +for sets and maps +(\ref{setAndMapLiteralDisambiguation}, \ref{setAndMapLiteralInference}), +and finally a specification of sets +(\ref{sets}) +and maps +(\ref{maps}). + +\begin{grammar} + ::= \CONST? ? `[' ? `]' + + ::= \CONST? ? `{' ? `}' + + ::= (`,' )* `,'? + + ::= + \alt + \alt + \alt + \alt + + ::= + + ::= `:' + + ::= (`...' | `...?') + + ::= \IF{} `(' `)' (\ELSE{} )? + + ::= \AWAIT? \FOR{} `(' `)' +\end{grammar} + +\LMHash{}% +Syntactically, a \Index{collection literal} can be +a \synt{listLiteral} or a \synt{setOrMapLiteral}. +The contents of the collection is specified as a sequence of +\IndexCustom{collection literal elements}{collection literal!elements}, +in short \Index{elements}. +Each element may be a declarative specification of a single entity, +such as an \synt{expressionElement} or a \synt{mapElement}, +it may specify a collection which is to be included, +of the form \synt{spreadElement}, +or it may be a computational element specifying +how to obtain zero or more entities, +of the form \synt{ifElement} or \synt{forElement}. + +\commentary{% +Terms derived from \synt{element}, +and the ability to build collections from them, +is also known as +\Index{UI-as-code}.% +} + +\LMHash{}% +The \Index{leaf elements} of an element $\ell$ derived from +\synt{expressionElement} or \synt{mapElement} +is $\{\ell\}$. +The leaf elements of an element of the form +\code{\IF\,($e$)\,$\ell$} or +\code{\FOR\,(\metavar{forLoopParts})\,$\ell$} +is the leaf elements of $\ell$. +The leaf elements of an element of the form +\code{\IF\,($e$)\,$\ell_1$\,\ELSE\,$\ell_2$} +is the union of the leaf elements of $\ell_1$ and $\ell_2$. +The leaf elements of a \synt{spreadElement} is the empty set. + +\commentary{% +The leaf elements of a collection literal is always +a set of expression elements and/or map elements.% +} + +\LMHash{}% +In order to allow collection literals to occur as constant expressions, +we specify what it means for an element $\ell$ +to be +\IndexCustom{constant}{collection literal element!constant} +or +\IndexCustom{potentially constant}{% + collection literal element!potentially constant}: + +\begin{itemize} +\item + When $\ell$ is an \synt{expressionElement} of the form $e$: + + $\ell$ is a potentially constant element + if $e$ is a potentially constant expression, + and $\ell$ is a constant element + if $e$ is a constant expression. +\item + When $\ell$ is a \synt{mapElement} + of the form `\code{$e_1$:\,$e_2$}': + + $\ell$ is a potentially constant element + if both $e_1$ and $e_2$ are potentially constant expressions, + and it is a constant element if they are constant expressions. +\item + When $\ell$ is a \synt{spreadElement} + of the form `\code{...$e$}' or `\code{...?$e$}': + + $\ell$ is a potentially constant element + if $e$ is a potentially constant expression. + + $\ell$ is a constant element + if $e$ is a constant expression that evaluates + to a \code{List}, \code{Set}, or \code{Map} instance + originally created by a list, set, or map literal. + + Moreover, $\ell$ is a constant element if it is `\code{...?$e$}', + where $e$ is a constant expression that evaluates + to the null object. +\item + When $\ell$ is an \synt{ifElement} + of the form + \code{\IF\,\,($b$)\,\,$\ell_1$} + or the form + \code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$}: + + $\ell$ is a potentially constant element + if $b$ is a potentially constant expression, + $\ell_1$ is potentially constant, + and so is $\ell_2$, if present. + + $\ell$ is a constant element if $b$ is a constant expression + and: + + \begin{itemize} + \item + $\ell$ is \code{\IF\,\,($b$)\,\,$\ell_1$} and + either $b$ evaluates to \TRUE{} and $\ell_1$ is constant, + or $b$ evaluates to \FALSE{} and $\ell_1$ is potentially constant. + \item + $\ell$ is \code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$} and + either $b$ evaluates to \TRUE, + $\ell_1$ is constant, + and $\ell_2$ is potentially constant; + or $b$ evaluates to \FALSE, + $\ell_1$ is potentially constant, + and $\ell_2$ is constant. + \end{itemize} +\end{itemize} + +\commentary{% +A \synt{forElement} can never occur in a constant collection literal.% +} + +%% TODO(eernst): We may change this text to commentary or delete it, +%% it consists of descriptions of errors, but they are already covered +%% elsewhere. +%% +%% Compile-time errors. +%% +%% The following compile-time errors are specified in the feature +%% specification, but they are already implied by the errors specified +%% elsewhere. +%% +%% - "A non-null-aware spread element has static type \code{Null}". +%% For a list literal: listLiteralInference makes this an error by case +%% analysis on 'Spread element'. +%% Set/map literal: setAndMapLiteralInference, ditto. +%% +%% - "A spread element in a list or set literal has a static type that is +%% not \DYNAMIC{} and not a subtype of \code{Iterable}". +%% List literal: case analysis on 'Spread element'. +%% Set literal: case analysis on 'Spread element': only succeeds if +%% $S$ implements `Map` (and not `Iterable`), so it has a key/value +%% type and no element type, which is an error (\ref{sets}). +%% +%% - "A spread element in a list or set has a static type that +%% implements \code{Iterable<$T$>} for some $T$ and +%% $T$ is not assignable to the element type of the list." +%% List literal: cf. 'Spread element' this implies that the spread element +%% has element type $T$, and non-assignability is an error, \ref{lists}. +%% Set literal: cf. 'Spread element' for sets/maps: ditto. +%% +%% - "A spread element in a map literal has a static type that is +%% not \DYNAMIC{} and not a subtype of \code{Map}". +%% Set/map 'Spread element' case analysis then implies that it implements +%% `Iterable` and not `Map`, in which case it has no key/value type pair, +%% which is an error, \ref{maps}. +%% +%% - "If a map spread element's static type implements \code{Map<$K$, $V$>} +%% for some $K$ and $V$ and $K$ is not assignable to the key type of the +%% map or $V$ is not assignable to the value type of the map". +%% This is an error, \ref{maps}. +%% +%% - "The variable in a \synt{forElement} (\commentary{either a for-in +%% element or C-style}) is declared outside of the element to be final or +%% to not have a setter". +%% This error is specified in \ref{listLiteralInference} and +%% \ref{setAndMapLiteralInference}. +%% +%% - "The type of the iterator expression in a synchronous for-in element +%% may not be assigned to \code{Iterable<$T$>} for any type $T$. +%% Otherwise, the \Index{iterable type} of the iterator is $T$". +%% Covered by the same text as the previous error. +%% +%% - "The iterable type of the iterator in a synchronous for-in element +%% may not be assigned to the for-in variable's type." +%% Covered by the same text again. +%% +%% - "The type of the stream expression in an asynchronous \AWAIT{} for-in +%% element may not be assigned to \code{Stream<$T$>} for any type $T$. +%% Otherwise, the \Index{stream type} of the stream is $T$". +%% Same text again (the `forElement` text includes both await for and for). +%% +%% - "The stream type of the iterator in an asynchronous \AWAIT{} for-in element +%% may not be assigned to the for-in variable's type". +%% Same text again. +%% +%% - "\AWAIT{} \FOR{} is used when the function immediately enclosing the +%% collection literal is not asynchronous". +%% Same text again. +%% +%% - "\AWAIT{} is used before a C-style \synt{forElement}. +%% \AWAIT{} can only be used with for-in loops". +%% Same text again. +%% +%% - "The type of the condition expression (\commentary{the second clause}) +%% in a C-style \FOR{} element may not be assigned to \code{bool}". +%% Same text again. + + +\subsubsection{Type Promotion} +\LMLabel{collectionLiteralTypePromotion} + +\LMHash{}% +An \synt{ifElement} interacts with type promotion +in the same way that \IF{} statements do. +Let $\ell$ be an \synt{ifElement} of the form +\code{\IF\,\,($b$)\,\,$\ell_1$} or +\code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$}. +If $b$ shows that a local variable $v$ has type $T$, then +the type of $v$ is known to be $T$ in $\ell_1$, +unless any of the following are true: + +\begin{itemize} +\item $v$ is potentially mutated in $\ell_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 $\ell_1$ and + $v$ is potentially mutated anywhere in the scope of $v$. +\end{itemize} + +%% TODO(eernst): Come nnbd, update this. +\commentary{% +Type promotion will likely get more sophisticated in a future version of Dart. +When that happens, +\synt{ifElement}s will continue to match \IF{} statements +(\ref{if}).% +} + + +\subsubsection{Collection Literal Element Evaluation} +\LMLabel{collectionLiteralElementEvaluation} + +\LMHash{}% +The evaluation of a sequence of collection literal elements +(\ref{collectionLiterals}) +yields a +\IndexCustom{collection literal object sequence}{% + collection literal!object sequence}, +also called an \NoIndex{object sequence} when no ambiguity can arise. + +\LMHash{}% +We use the notation +% `\LiteralSequence` cannot be used after `@`, so we use an approximation. +\IndexCustom{\LiteralSequence{\ldots}}{[[...]]@% + \ensuremath{[\hspace{-0.6mm}[\ldots]\hspace{-0.6mm}]}} +to denote an object sequence with explicitly listed elements, +and we use `$+$' to compute the concatenation of object sequences +(\commentary{as in $s_1 + s_2$}), +which is an operation that will succeed and has no side-effects. +Each element in the sequence is an object $o$ or a pair $o_1: o_2$. +There is no notion of an element type for an object sequence, +and hence no notion of dynamic errors arising from +a type mismatch during concatenation. + +\commentary{% +Object sequences can safely be treated as a low-level mechanism +which may omit otherwise required actions like dynamic type checks +because every access to an object sequence occurs +in code created by language defined desugaring +on statically checked constructs. +It is left unspecified how an object sequence is implemented, +it is only required that it contains the indicated objects or pairs +in the given order. +For each kind of collection, +the sequence is used in the given order to populate the collection, +in a manner which is specific to the kind, +and which is specified separately +(\ref{lists}, \ref{sets}, \ref{maps}).% + +There may be an actual data structure +representing the object sequence at run time, +but the object sequence could also be eliminated, e.g., +because each element is inserted directly into the target collection +as soon as it has been computed. +Note that each object sequence will exclusively contain objects, +or it will exclusively contain pairs, +because any attempt to create a mixed sequence would cause +an error at compile time or at run time +(the latter may occur for a spread element with static type \DYNAMIC{}).% +} + +\LMHash{}% +Assume that a literal collection \metavar{target} is given, +and the object sequence obtained as described below will be used +to populate \metavar{target}. +Let $T_{\metavar{target}}$ denote the dynamic type of \metavar{target}. + +\commentary{% +Access to the type of \metavar{target} is needed below +in order to raise dynamic errors at specific points during +the evaluation of an object sequence. +Note that the dynamic type of \metavar{target} is statically known, +except for the binding of any type variables in its \synt{typeArguments}. +This implies that some questions can be answered at compile-time, e.g., +whether or not \code{Iterable} occurs as a superinterface of +$T_{\metavar{target}}$. +In any case, $T_{\metavar{target}}$ is guaranteed to implement +\code{Iterable} (when \metavar{target} is a list or a set) +or \code{Map} (when \metavar{target} is a map), +but never both.% +} + +\LMHash{}% +Assume that a location in code and a dynamic context is given, +such that ordinary expression evaluation is possible. +\IndexCustom{Evaluation of a collection literal element sequence}{% + collection literal element!evaluation of sequence} +at that location and in that context is specified as follows: + +\LMHash{}% +Let $s_{\metavar{syntax}}$ of the form \List{\ell}{1}{k} be +a sequence of collection literal elements. +The sequence of objects $s_{\metavar{object}}$ +obtained by evaluating $s_{\metavar{syntax}}$ +is the concatenation of the sequences of objects +obtained by evaluating each element $\ell_j$, $j \in 1 .. k$: +$s_{\metavar{object}}=\EvaluateElement{\ell_1}+\ldots+\EvaluateElement{\ell_k}$, +where \EvaluateElement{\ell_j} denotes the object sequence yielded by +evaluation of a single collection literal element $\ell_j$. + +\LMHash{}% +When a pseudo-statement of the form +\code{$s := s + \EvaluateElement{\ell}$;} +is used in normative code below, +it denotes the extension of $s$ with the object sequence +yielded by evaluation of $\ell$, +but it also denotes the specification of actions taken to produce +said object sequence, +and to produce the side effects associated with this computation, +as implied by evaluation of expressions and execution of statements +as specified below for the evaluation of \EvaluateElement{\ell}. + +\LMHash{}% +When a pseudo-statement of the form +\code{$\EvaluateElement{\ell} := s$;} +occurs in normative code below, +it occurs at a point where the computation is complete +and it specifies that the value of \EvaluateElement{\ell} is $s$. +\IndexCustom{Evaluation of a collection literal element $\ell$}{% + collection literal element!evaluation} +in the given context +to an object sequence +\IndexCustom{\EvaluateElement{\ell}}{% + evaluateElement(l)@\emph{evaluateElement}\code{($\ell$)}} +is then specified as follows: + +\LMHash{}% +\Case{Expression element} +In this case $\ell$ is an expression $e$; +$e$ is evaluated to an object $o$ +and $\EvaluateElement{\ell} := \LiteralSequence{o}$. +\EndCase + +\LMHash{}% +\Case{Map element} +In this case $\ell$ is pair of expressions +\code{$e_1$:$e_2$}; +first $e_1$ is evaluated to an object $o_1$, +then $e_2$ is evaluated to an object $o_2$, +and $\EvaluateElement{\ell} := \LiteralSequence{o_1:o_2}$. +\EndCase + +\LMHash{}% +\Case{Spread element} +The element $\ell$ is of the form `\code{...$e$}' or `\code{...?$e$}'. +Evaluate $e$ to an object $o_{\metavar{spread}}$. +\begin{enumerate} +\item + When $\ell$ is `\code{...$e$}': + %% TODO(eernst): Come NNBD, this error cannot occur any more: delete. + If $o_{\metavar{spread}}$ is the null object then a dynamic error occurs. + Otherwise evaluation proceeds with step 2. + + When $\ell$ is `\code{...?$e$}': + If $o_{\metavar{spread}}$ is the null object then + $\EvaluateElement{\ell} := \LiteralSequence{}$. + Otherwise evaluation proceeds with step 2. +\item + Let $T_{\metavar{spread}}$ be the dynamic type of $o_{\metavar{spread}}$. + Let $S$ be the static type of $e$. + When $S$ is not a top type + (\ref{superBoundedTypes}), + let $S_{\metavar{spread}}$ be $S$. + When $S$ is a top type: + If \metavar{target} is a list or a set then + let $S_{\metavar{spread}}$ be \code{Iterable<\DYNAMIC>}; + otherwise + (\commentary{where \metavar{target} is a map}), + let $S_{\metavar{spread}}$ be \code{Map<\DYNAMIC,\,\,\DYNAMIC>}. + + \begin{itemize} + \item + When \metavar{target} is a list or a set + and $T_{\metavar{spread}}$ implements + (\ref{interfaceSuperinterfaces}) + \code{Iterable}, + the following code is executed in the context where $\ell$ occurs, + where \code{spread}, $s$, \code{v}, and \code{value} are fresh variables, + and \code{Value} is a fresh type variable bound to the + actual type argument of $T_{\metavar{target}}$ at \code{Iterable} + (\ref{interfaceSuperinterfaces}): + + \vspace{-2ex}\begin{minipage}[t]{\textwidth} +\begin{normativeDartCode} +$S_{\metavar{spread}}$ spread = $o_{\metavar{spread}}$; +\VAR{} $s$ = \LiteralSequence; +\FOR{} (\VAR{} v \IN{} spread) \{ + Value value = v; + $s := s + \LiteralSequence{\code{value}}$; +\} +$\EvaluateElement{\ell} := s$; +\end{normativeDartCode} + \end{minipage} + + \commentary{% + The code makes use of a pseudo-variable $s$ denoting an object sequence. + We do not specify the type of $s$, + this variable is only used to indicate the required + semantic actions taken to gather the resulting object sequence. + In the case where the implementation does not have + a representation of $s$ at all, + the action may be to extend \metavar{target} immediately. + A similar approach is used in subsequent cases.% + } + \item + When \metavar{target} is a map and $T_{\metavar{spread}}$ implements + \code{Map}, + the following code is executed in the context where $\ell$ occurs, + where \code{spread}, $s$, \code{v}, \code{key}, and \code{value} + are fresh variables, + and \code{Key} and \code{Value} are fresh type variables bound to the + first respectively second actual type argument + of $T_{\metavar{target}}$ at \code{Map}: + + \vspace{-2ex}\begin{minipage}[t]{\textwidth} +\begin{normativeDartCode} +$S_{\metavar{spread}}$ spread = $o_{\metavar{spread}}$; +\VAR{} $s$ = \LiteralSequence; +\FOR{} (\VAR{} v \IN{} spread) \{ + Key key = v.key; + Value value = v.value; + $s := s + \LiteralSequence{\code{key}:\,\code{value}}$; +\} +$\EvaluateElement{\ell} := s$; +\end{normativeDartCode} + \end{minipage} + + % Will not change with nnbd: `spread` type arguments could be \DYNAMIC. + It is allowed for an implementation to delay the dynamic errors + that occur if the given \code{key} does not have the type \code{Key}, + or the given \code{value} does not have the type \code{Value}, + but it cannot occur after the pair has been appended to $s$. + \item + Otherwise, a dynamic error occurs. + + \commentary{% + This occurs when the target is an iterable respectively a map, + and the spread is not, which is possible for + a spread whose static type is \DYNAMIC.% + } + \end{itemize} +\end{enumerate} + +\rationale{% +This may not be the most efficient way to traverse the items in a collection, +and implementations may of course use any other approach +with the same observable behavior. +However, in order to give implementations more room to optimize +we also allow the following.% +} + +\LMHash{}% +If $o_{\metavar{spread}}$ is an object whose dynamic type implements +(\ref{interfaceSuperinterfaces}) +\code{List}, \code{Queue}, or \code{Set}, +an implementation may choose to call \code{length} on the object. +If $o_{\metavar{spread}}$ is an object +whose dynamic type implements \code{List}, +an implementation may choose to call operator \lit{[]} +in order to access elements from the list. +If it does so, it will only pass indices +that are non-negative and less than the value returned by \code{length}. + +\rationale{% +This may allow for more efficient code for +allocating the collection and accessing its parts. +The given classes are expected to have +an efficient and side-effect free implementation +of \code{length} and operator \lit{[]}. +A Dart implementation may detect whether these options apply +at compile time based on the static type of $e$, +or at runtime based on the actual value.% +} +\EndCase + +\LMHash{}% +\Case{If element} +When $\ell$ is an \synt{ifElement} of the form +\code{\IF\,\,($b$)\,\,$\ell_1$} or +\code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$}, +the condition $b$ is evaluated to a value $o_b$. +If $o_b$ is \TRUE{} then +$\EvaluateElement{\ell} := \EvaluateElement{\ell_1}$. +If $o_b$ is \FALSE{} and $\ell_2$ is present then +$\EvaluateElement{\ell} := \EvaluateElement{\ell_2}$, +and if $\ell_2$ is not present then +$\EvaluateElement{\ell} := \LiteralSequence{}$. +% $o_b$ can have type \DYNAMIC. +If $o_b$ is neither \TRUE{} nor \FALSE{} then a dynamic error occurs. +\EndCase + +\LMHash{}% +\Case{For element} +Let $P$ be derived from \syntax{} and +let $\ell$ be a \synt{forElement} of the form +\code{\AWAIT?\,\,\FOR\,\,($P$)\,\,$\ell_1$}, +where `\AWAIT?' indicates that \AWAIT{} may be present or absent. +To evaluate $\ell$, +the following code is executed in the context where $\ell$ occurs, +where \AWAIT{} is present if and only if it is present in $\ell$: + +\vspace{-2ex}\begin{minipage}[t]{\textwidth} +\begin{normativeDartCode} +\VAR{} $s$ = \LiteralSequence; +\AWAIT? \FOR{} ($P$) \{ + $s := s + \EvaluateElement{\ell_1}$; +\} +$\EvaluateElement{\ell} := s$; +\end{normativeDartCode} +\end{minipage} +\EndCase + + +\subsubsection{List Literal Inference} +\LMLabel{listLiteralInference} + +\LMHash{}% +This section specifies how a list literal \metavar{list} is traversed and an +\IndexCustom{inferred element type}{list literal!element type} +for \metavar{list} is determined. +We specify first how to infer the element type of a single element, +then how to use that result to infer +the element type of \metavar{list} as a whole. + +\LMHash{}% +The context type $P$ +(\ref{setAndMapLiteralDisambiguation}) +for each element of \metavar{list} is +obtained from the context type of \metavar{list}. +If downwards inference constrains the type of \metavar{list} +to \code{List<$P_e$>} or \code{Iterable<$P_e$>} for some $P_e$ +then $P$ is $P_e$. +Otherwise, $P$ is \FreeContext{} +(\ref{setAndMapLiteralDisambiguation}). + +\LMHash{}% +Let $\ell$ be a term derived from \synt{element}. +Inference of the element type of $\ell$ with context type $P$ +proceeds as follows, +where the context type for inference of an element type is always $P$, +unless anything is said to the contrary: + +\LMHash{}% +\Case{Expression element} +In this case $\ell$ is an expression $e$. +The inferred element type of $\ell$ is +% The type of $e$ is not an element type, so we mention $P$. +the inferred type of $e$ in context $P$. +\EndCase + +\LMHash{}% +\Case{Map element} +% We cannot really tell whether this or the error in \ref{lists} arises first +% (say, when the list literal has an explicit type argument, it is not +% guaranteed that the implementation performs type inference on it at all). +% So we _must_ specify the error in \ref{lists}, and this location should +% then be a commentary, because we already have the error elsewhere. +\commentary{% +This cannot occur: +it is a compile-time error +when a leaf element of a list literal is a map element +(\ref{lists}).% +} +\EndCase + +\LMHash{}% +\Case{Spread element} +Let $e$ be the expression of $\ell$. +If $\ell$ is `\code{...$e$}', +let $S$ be the inferred type of $e$ in context \code{Iterable<$P$>}. +Otherwise +(\commentary{when $\ell$ is `\code{...?$e$}'}), +%% TODO(eernst): Come NNBD, add a \ref{} to the specification of +%% 'the non-nullable type of'. +let $S$ be the non-nullable type of +%% TODO(eernst): Clarify whether inference will indeed have that context; +%% it is clear that we need to eliminate `Null` from $S$, and also that $e$ +%% is allowed to have a potentially nullable type, and it seems inconvenient +%% if we use `Iterable<$P$>` as context type and fail in the case where $e$, +%% say, has type `List<$U$>?` for some $U$. +the inferred type of $e$ in context \code{Iterable<$P$>?}. + +\begin{itemize} +\item + If $S$ implements \code{Iterable}, + the inferred element type of $\ell$ is + the type argument of $S$ at \code{Iterable}. +\item + If $S$ is \DYNAMIC, + the inferred element type of $\ell$ is \DYNAMIC. +\item + If $S$ is \code{Null} and the spread operator is \lit{...?}, + the inferred element type of $\ell$ is \code{Null}. +\item + Otherwise, a compile-time error occurs. +\end{itemize} +\vspace{-5mm} +\EndCase + +\LMHash{}% +\Case{If element} +In this case $\ell$ is of the form +\code{\IF\,\,($b$)\,\,$\ell_1$} or +\code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$}. +The condition $b$ is always inferred with a context type of \code{bool}. + +Assume that `\code{\ELSE\,\,$\ell_2$}' is not present. +Then, if the inferred element type of $\ell_1$ is $S$, +the inferred element type of $\ell$ is $S$. + +Otherwise, `\code{\ELSE\,\,$\ell_2$}' is present. +If the inferred element type of $\ell_1$ is $S_1$ and +the inferred element type of $\ell_2$ is $S_2$, +the inferred element type of $\ell$ is +the least upper bound of $S_1$ and $S_2$. +\EndCase + +\LMHash{}% +\Case{For element} +In this case $\ell$ is of the form +\code{\AWAIT?\,\,\FOR\,\,($P$)\,\,$\ell_1$} +where $P$ is derived from \synt{forLoopParts} and +`\AWAIT?' indicates that \AWAIT{} may be present or absent. + +The same compile-time errors occur for $\ell$ as +the errors that would occur with the corresponding \FOR{} statement +\code{\AWAIT?\,\,\FOR\,\,($P$)\,\,\{\}}, +located in the same scope as $\ell$. +Moreover, the errors and type analysis of $\ell$ is performed +as if it occurred in the body scope of said \FOR{} statement. +\commentary{% +For instance, if $P$ is of the form +\code{\VAR\,\,v\,\,\IN\,\,$e_1$} +then the variable \code{v} is in scope for $\ell$.% +} + +Inference for the parts +(\commentary{% +such as the iterable expression of a for-in, +or the \synt{forInitializerStatement} of a for loop% +}) +is done as for the corresponding \FOR{} statement, +including \AWAIT{} if and only if the element includes \AWAIT. +Then, if the inferred element type of $\ell_1$ is $S$, +the inferred element type of $\ell$ is $S$. + +\commentary{% +In other words, inference flows upwards from the body element.% +} +\vspace{3mm} +\EndCase + +\LMHash{}% +Finally, we define +\IndexCustom{type inference on a list literal}{% + type inference!list literal} +as a whole. +Assume that \metavar{list} is derived from \synt{listLiteral} +and contains the elements \List{\ell}{1}{n}, +and the context type for \metavar{list} is $P$. + +\begin{itemize} +\item + If $P$ is \FreeContext{} then + the inferred element type for \metavar{list} is $T$, + where $T$ is the least upper bound of + the inferred element types of \List{\ell}{1}{n}. + +\item + %% TODO(eernst): Feature spec says $P$, but how do we know $P$ is a type? + Otherwise, + the inferred element type for \metavar{list} is $T$, + where $T$ is determined by downwards inference. +\end{itemize} + +\LMHash{}% +In both cases, the static type of \metavar{list} is \code{List<$T$>}. + + +\subsubsection{Lists} +\LMLabel{lists} + +\LMHash{}% +A \IndexCustom{list literal}{literal!list} +denotes a list object, which is an integer indexed collection of objects. +The grammar rule for \synt{listLiteral} is specified elsewhere +(\ref{collectionLiterals}). + +\LMHash{}% +When a given list literal $e$ has no type arguments, +the type argument $T$ is selected as specified elsewhere +(\ref{listLiteralInference}), +and $e$ is henceforth treated as +(\ref{notation}) +\code{<$T$>$e$}. + +\commentary{% +The static type of a list literal of the form \code{<$T$>$e$} +is \code{List<$T$>} +(\ref{listLiteralInference}).% +} + +\LMHash{}% +Let $e$ be a list literal of the form +\code{<$T$>[\List{\ell}{1}{m}]}. +It is a compile-time error if a leaf element of $e$ is a +\synt{mapElement}. +It is a compile-time error if, for some $j \in 1 .. m$, +$\ell_j$ does not have an element type, +or the element type of $\ell_j$ may not be assigned to $T$. + +\LMHash{}% +A list may contain zero or more objects. +The number of objects 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 dynamic error to attempt to access a list +using an index that is not a member of its set of indices. + +\rationale{% +The system libraries define many members for the type \code{List}, +but we specify only the minimal set of requirements +which are used by the language itself.% +} + +\LMHash{}% +If a list literal $e$ begins with the reserved word \CONST{} +or $e$ occurs in a constant context +(\ref{constantContexts}), +it is a +\IndexCustom{constant list literal}{literal!list!constant}, +which is a constant expression +(\ref{constants}) +and therefore evaluated at compile time. +Otherwise, it is a +\IndexCustom{run-time list literal}{literal!list!run-time} +and it is evaluated at run time. +Only run-time list literals can be mutated +after they are created. +% This error can occur because being constant is a dynamic property. +Attempting to mutate a constant list literal will result in a dynamic error. + +\commentary{% +% The following is true either directly or indirectly: There is a \CONST{} +% modifier on the list literal, or the list literal as a whole occurs +% in a constant context. +Note that the collection literal elements of a constant list literal +occur in a constant context +(\ref{constantContexts}), +which means that \CONST{} modifiers need not be specified explicitly.% +} + +\LMHash{}% +It is a compile-time error +if an element of a constant list literal is not constant. +It is a compile-time error if the type argument of a constant list literal +(\commentary{no matter whether it is explicit or inferred}) +is not a constant type expression +(\ref{constants}). + +\rationale{% +The binding of a formal type parameter of an enclosing class or function +is not known at compile time, +so we cannot use such type parameters inside constant expressions.% +} + +\LMHash{}% +The value of a constant list literal +\code{\CONST?\,\,<$T$>[\List{\ell}{1}{m}]} +is an object $o$ whose class implements the built-in class +\code{List<$t$>} +where $t$ is the actual value of $T$ +(\ref{actualTypes}), +and whose contents is the object sequence \List{o}{1}{n} obtained by +evaluation of \List{\ell}{1}{m} +(\ref{collectionLiteralElementEvaluation}). +The $i$th object of $o$ (at index $i - 1$) is then $o_i$. + +\LMHash{}% +Let \code{\CONST?\,\,<$T_1$>[$\ell_{11}, \ldots, \ell_{1m_1}$]} +and \code{\CONST?\,\,<$T_2$>[$\ell_{21}, \ldots, \ell_{2m_2}$]} +be two constant list literals. +Let $o_1$ with contents $o_{11}, \ldots, o_{1n}$ and actual type argument $t_1$ +respectively +$o_2$ with contents $o_{21}, \ldots, o_{2n}$ and actual type argument $t_2$ +be the result of evaluating them. +Then \code{identical($o_1$, $o_2$)} evaluates to \TRUE{} if{}f +\code{$t_1$ == $t_2$} and \code{identical($o_{1i}$, $o_{2i}$)} +evaluates to \TRUE{} for all $i \in 1 .. n$. + +\commentary{% +In other words, constant list literals are canonicalized. +There is no need to consider canonicalization +for other instances of type \code{List}, +because such instances cannot be +the result of evaluating a constant expression.% +} + +\LMHash{}% +A run-time list literal +\code{<$T$>[\List{\ell}{1}{m}]} +is evaluated as follows: +\begin{itemize} +\item + The elements \List{\ell}{1}{m} are evaluated + (\ref{collectionLiteralElementEvaluation}), + to an object sequence \LiteralSequence{\List{o}{1}{n}}. +\item + A fresh instance (\ref{generativeConstructors}) $o$, of size $n$, + whose class implements the built-in class \code{List<$t$>} + is allocated, + where $t$ is the actual value of $T$ + (\ref{actualTypes}). +\item + The operator \lit{[]=} is invoked on $o$ with + first argument $i$ and second argument + $o_{i+1}, 0 \le i < n$. +\item + The result of the evaluation is $o$. +\end{itemize} + +\LMHash{}% +The objects created by list literals do not override +the \lit{==} 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 as follows (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}$.% +} + + +\subsubsection{Set and Map Literal Disambiguation} +\LMLabel{setAndMapLiteralDisambiguation} + +\LMHash{}% +Some terms like \code{\{\}} and \code{\{\,...\id\,\}} are ambiguous: +they may be either a set literal or a map literal. +This ambiguity is eliminated in two steps. +The first step uses only the syntax and context type, +%% TODO(eernst): Enable this reference when 'context type' gets defined. +%% (\ref{contextType}) +and is described in this section. +The second step uses expression types and is described next +(\ref{setAndMapLiteralInference}). + +\LMHash{}% +Let $e$ be a \synt{setOrMapLiteral} +with leaf elements $\cal L$ and context type $C$. +If $C$ is \FreeContext{} then let $S$ be undefined. +%% TODO(eernst): Define `greatest closure' of a context type +%% when we define `context type'. +Otherwise let $S$ be the greatest closure of \futureOrBase{C} +(\ref{typeFutureOr}). + +%% TODO(eernst): Delete when `context type', `greatest closure' are defined. +\commentary{% +A future version of this document will specify context types. +The basic intuition is that a +\Index{context type} +is the type declared for a +receiving entity such as +a formal parameter $p$ or a declared variable $v$. +That type will be the context type for +an actual argument passed to $p$, +respectively an initializing expression for $v$. +In some situations the context has no constraints, +e.g., when a variable is declared with \VAR{} rather than a type annotation. +This gives rise to an +\IndexCustom{unconstrained context type}{context type!unconstrained}, +\IndexCustom{\rm\FreeContext}{[]@\FreeContext}, +which may also occur in a composite term, e.g., \code{List<\FreeContext>}. +%% TODO(eernst): Clarify why we do not just use i2b, rather than +%% introducing the notion of a greatest (and least) closure. +The greatest closure of a context type $C$ is +approximately the least common supertype of all types +obtainable by replacing \FreeContext{} by a type.% +} + +\LMHash{}% +The disambiguation step of this section is +the first applicable entry in the following list: + +\begin{itemize} +\item When $e$ has type arguments \List{T}{1}{k}, $k > 0$: + If $k = 1$ then $e$ is a set literal with static type + \code{Set<$T_1$>}. + If $k = 2$ then $e$ is a map literal with static type + \code{Map<$T_1$,\,\,$T_2$>}. + Otherwise a compile-time error occurs. +\item + When $S$ implements + (\ref{interfaceSuperinterfaces}) + \code{Iterable} but not \code{Map}, + $e$ is a set literal. + When $S$ implements \code{Map} but not \code{Iterable}, + $e$ is a map literal. +\item + When ${\cal L} \not= \emptyset$ (\commentary{that is, $e$ has leaf elements}): + If $\cal L$ contains a \synt{mapElement} + as well as an \synt{expressionElement}, + a compile-time error occurs. + Otherwise, if $\cal L$ contains an \synt{expressionElement}, + $e$ is a set literal. + Otherwise $\cal L$ contains a \synt{mapElement}, and $e$ is a map literal. +\item + When $e$ is of the form \code{\{\}} and $S$ is undefined, + $e$ is a map literal. + \rationale{% + There is no deeper reason for this choice, + but the fact that \code{\{\}} is a map by default + was useful when set literals were introduced, + because it would be a breaking change to make it a set.% + } +\item + Otherwise, $e$ is still ambiguous. + \commentary{% + In this case $e$ is non-empty, but contains only spreads + wrapped zero or more times in \synt{ifElement}s or \synt{forElement}s. + Disambiguation will then occur during inference + (\ref{setAndMapLiteralInference}).% + } +\end{itemize} + +\commentary{% +When this step does not determine a static type, +it will be determined by type inference +(\ref{setAndMapLiteralInference}).% +} + +\LMHash{}% +If this process successfully disambiguates the literal +then we say that $e$ is +\IndexCustom{unambiguously a set}{set!unambiguously} +or +\IndexCustom{unambiguously a map}{map!unambiguously}, +as appropriate. + + +\subsubsection{Set and Map Literal Inference} +\LMLabel{setAndMapLiteralInference} + +\LMHash{}% +This section specifies how a \synt{setOrMapLiteral} $e$ is traversed +and an associated +\IndexCustom{inferred element type}{set or map literal!element type} +and/or an associated +\IndexCustom{inferred key and value type pair}{% + set or map literal!key and value type pair} +is determined. + +\commentary{% +If $e$ has an element type then it may be a set, +and if it has a key and value type pair then it may be a map. +% +However, if the literal $e$ contains a spread element of type \DYNAMIC, +that element cannot be used to determine whether $e$ is a set or a map. +The ambiguity is represented as having \emph{both} +an element type and a key and value type pair. + +It is an error if the ambiguity is not resolved by some other elements, +but if it is resolved then the dynamic spread element is required +to evaluate to a suitable instance +(implementing \code{Iterable} when $e$ is a set, +and implementing \code{Map} when $e$ is a map), +which means that it is a dynamic error if there is a mismatch. +In other situations it is a compile-time error to have both +an element type and a key and value type pair, +because $e$ must be both a set and a map. +Here is an example:% +} + +\begin{dartCode} +\DYNAMIC{} x = \{\}; +Iterable l = []; +Map m = \{\}; +\\ +\VOID{} main() \{ + \VAR v1 = \{...x\}; // \comment{Compile-time error: ambiguous} + \VAR v2 = \{...x, ...l\}; // \comment{A set, dynamic error when `x` is evaluated} + \VAR v3 = \{...x, ...m\}; // \comment{A map, no dynamic errors} + \VAR v4 = \{...l, ...m\}; // \comment{Compile-time error: must be set and map} +\} +\end{dartCode} + +\LMHash{}% +Let \metavar{collection} be a collection literal +derived from \synt{setOrMapLiteral}. +The inferred type of an \synt{element} is an element type $T$, +a pair of a key and value type $(K, V)$, or both. +It is computed relative to a context type $P$ +(\ref{setAndMapLiteralDisambiguation}), +which is determined as follows: + +\begin{itemize} +\item + If \metavar{collection} is unambiguously a set + (\ref{setAndMapLiteralDisambiguation}) + then $P$ is \code{Set<$P_e$>}, + %% TODO(eernst): Add reference when we specify inference. + where $P_e$ is determined by downwards inference, + and may be \FreeContext{} + %% TODO(eernst): Correct this reference when we specify context types. + (\ref{setAndMapLiteralDisambiguation}) + if downwards inference does not constrain it. + + %% TODO(eernst): Remove this when we specify inference. + \commentary{% + A future version of this document will specify inference, + the notion of downwards inference, + and constraining. + The brief intuition is that inference selects values for + type parameters in generic constructs + where no type arguments have been provided, + aiming at a type which matches a given context type; + downwards inference does this by passing information + from a given expression into its subexpressions, + and upwards inference propagates information in the opposite direction. + Constraints are expressed in terms of context types; + being unconstrained means having \FreeContext{} as the context type. + Having a context type that \emph{contains} + one or more occurrences of \FreeContext{} + provides a partial constraint on the inferred type.% + } +\item + If \metavar{collection} is unambiguously a map + then $P$ is \code{Map<$P_k$,\,\,$P_v$>} + where $P_k$ and $P_v$ are determined by downwards inference, + and may be \FreeContext{} + if the downwards context does not constrain one or both. +\item + Otherwise, \metavar{collection} is ambiguous, + and the downwards context for the elements of \metavar{collection} + is \FreeContext. +\end{itemize} + +\LMHash{}% +We say that a collection literal element +\IndexCustom{can be a set}{collection literal element!can be a set} +if it has an element type; +it +\IndexCustom{can be a map}{collection literal element!can be a map} +if it has a key and value type pair; +it +\IndexCustom{must be a set}{collection literal element!must be a set} +if it can be a set and has and no key and value type pair; +and it +\IndexCustom{must be a map}{collection literal element!must be a map} +if can be a map and has no element type. + +\LMHash{}% +Let $\ell$ be a term derived from \synt{element}. +\IndexCustom{Inference of the type of}{% + type inference!collection literal element} +$\ell$ with context type $P$ then proceeds +as follows: + +\LMHash{}% +\Case{Expression element} +In this case $\ell$ is an expression $e$. +% +If $P$ is \FreeContext, +the inferred element type of $\ell$ is +the inferred type of $e$ in context \FreeContext. +% +If $P$ is \code{Set<$P_e$>}, +the inferred element type of $\ell$ is +the inferred type of $e$ in context $P_e$. +\EndCase + +\LMHash{}% +\Case{Map element} +In this case $\ell$ is a pair of expressions \code{$e_k$:\,$e_v$}. +% +If $P$ is \FreeContext, +the inferred key and value type pair of $\ell$ is $(K, V)$, +where $K$ and $V$ is +the inferred type of $e_k$ respectively $e_v$, +in context \FreeContext. +% +If $P$ is \code{Map<$P_k$,\,\,$P_v$>}, +the inferred key and value type pair of $\ell$ is $(K, V)$, +where $K$ is +the inferred type of $e_k$ in context $P_k$, and +the $V$ is +the inferred type of $e_v$ in context $P_v$. +\EndCase + +\LMHash{}% +\Case{Spread element} +In this case $\ell$ is of the form +`\code{...$e$}' or `\code{...?$e$}'. +If $P$ is \FreeContext{} then let $S$ be +the inferred type of $e$ in context \FreeContext. +Then: + +\begin{itemize} +\item + If $S$ implements \code{Iterable}, + the inferred element type of $\ell$ is + the type argument of $S$ at \code{Iterable}. + + \commentary{% + This is the result of constraint matching for $X$ + using the constraint $S\,\,<:\,\,\code{Iterable<$X$>}$. + Note that when $S$ implements a class like \code{Map} or \code{Iterable}, + it cannot be a subtype of \code{Null} + (\ref{interfaceSuperinterfaces}).% + } +\item + If $S$ implements \code{Map}, + the inferred key and value type pair of $\ell$ is $(K, V)$, + where $K$ is the first and $V$ the second type argument + of $S$ at \code{Map}. + + \commentary{% + This is the result of constraint matching for $X$ and $Y$ using + the constraint $S\,\,<:\,\,\code{Map<$X$,\,\,$Y$>}$.% + + Note that this case and the previous case + can match on the same element simultaneously + when $S$ implements both \code{Iterable} and \code{Map}. + The same situation arises several times below. + In such cases we rely on other elements to disambiguate.% + } +\item + If $S$ is \DYNAMIC{} then + the inferred element type of $\ell$ is \DYNAMIC, + and the inferred key and value type pair of $\ell$ is + $(\DYNAMIC, \DYNAMIC)$. + + \commentary{% + We produce both an element type and a key and value type pair here, + and rely on other elements to disambiguate.% + } +\item + If $S$ is \code{Null} and the spread operator is \lit{...?} then + the inferred element type of $\ell$ is \code{Null}, + and the inferred key and value type pair $(\code{Null}, \code{Null})$. +\item + Otherwise, a compile-time error occurs. +\end{itemize} + +\noindent +%% TODO(eernst): Clarify why we shouldn't be able to use a context type of +%% `Iterable<$P_e$>` in the same way: infer $e$ in context `Iterable<$P_e$>` +%% as well. +Otherwise, if $P$ is \code{Set<$P_e$>} then let $S$ be +the inferred type of $e$ in context \code{Iterable<$P_e$>}, and then: + +\begin{itemize} +\item + If $S$ implements \code{Iterable}, + the inferred element type of $\ell$ is + the type argument of $S$ at \code{Iterable}. + \commentary{% + This is the result of constraint matching for $X$ using + the constraint $S <: \code{Iterable<$X$>}$.% + } +\item + If $S$ is \DYNAMIC, + the inferred element type of $\ell$ is \DYNAMIC. +\item + If $S$ is \code{Null} and the spread operator is \lit{...?}, + the inferred element type of $\ell$ is \code{Null}. +\item + Otherwise, a compile-time error occurs. +\end{itemize} + +\noindent +Otherwise, if $P$ is \code{Map<$P_k$,\,\,$P_v$>} then let $S$ be +the inferred type of $e$ in context $P$, and then: + +\begin{itemize} +\item + If $S$ implements \code{Map}, + the inferred key and value type pair of $\ell$ is $(K, V)$, + where $K$ is the first and $V$ the second type argument of + $S$ at \code{Map}. + \commentary{% + This is the result of constraint matching for $X$ and $Y$ using + the constraint \code{$S$ <: Map<$X$,\,\,$Y$>}.% + } +\item + If $S$ is \DYNAMIC, + the inferred key and value type pair of $\ell$ is + + \noindent + $(\DYNAMIC, \DYNAMIC)$. +\item + If $S$ is \code{Null} and the spread operator is \lit{...?}, + the inferred key and value type pair $(\code{Null}, \code{Null})$. +\item + Otherwise, a compile-time error occurs. +\end{itemize} +\vspace{-5mm} +\EndCase + +\LMHash{}% +\Case{If element} +In this case $\ell$ is of the form +\code{\IF\,\,($b$)\,\,$\ell_1$} or +\code{\IF\,\,($b$)\,\,$\ell_1$\,\,\ELSE\,\,$\ell_2$}. +The condition $b$ is always inferred with a context type of \code{bool}. + +Assume that `\code{\ELSE\,\,$\ell_2$}' is not present. Then: +\begin{itemize} +\item + If the inferred element type of $\ell_1$ is $S$, + the inferred element type of $\ell$ is $S$. +\item + If the inferred key and value type pair of $\ell_1$ is $(K, V)$, + the inferred key and value type pair of $\ell$ is $(K, V)$. +\end{itemize} + +Otherwise, `\code{\ELSE\,\,$\ell_2$}' is present. +It is a compile error if $\ell_1$ must be a set and $\ell_2$ must be a map, +or vice versa. + +\commentary{% +This means that one cannot spread a map on one branch and a set on the other. +Since \DYNAMIC{} provides both an element type and a key and value type pair, +a \DYNAMIC{} spread in either branch does not cause the error to occur.% +} + +Then: + +\begin{itemize} +\item + If the inferred element type of $\ell_1$ is $S_1$ and + the inferred element type of $\ell_2$ is $S_2$, + the inferred element type of $\ell$ is + the least upper bound of $S_1$ and $S_2$. +\item + If the inferred key and value type pair of $e_1$ is + $(K_1, V_1)$ + and the inferred key and value type pair of $e_2$ is + $(K_2, V_2)$, + the inferred key and value type pair of $\ell$ is + $(K, V)$, + where $K$ is the least upper bound of $K_1$ and $K_2$, and + and $V$ is the least upper bound of $V_1$ and $V_2$. +\end{itemize} +\vspace{-5mm} +\EndCase + +\LMHash{}% +\Case{For element} +In this case $\ell$ is of the form +\code{\AWAIT?\,\,\FOR\,\,($P$)\,\,$\ell_1$} +where $P$ is derived from \synt{forLoopParts} and +`\AWAIT?' indicates that \AWAIT{} may be present or absent. + +The same compile-time errors occur for $\ell$ as +the errors that would occur with the corresponding \FOR{} statement +\code{\AWAIT?\,\,\FOR\,\,($P$)\,\,\{\}}, +located in the same scope as $\ell$. +Moreover, the errors and type analysis of $\ell$ is performed +as if it occurred in the body scope of said \FOR{} statement. + +\commentary{% +For instance, if $P$ is of the form +\code{\VAR\,\,v\,\,\IN\,\,$e_1$} +then the variable \code{v} is in scope for $\ell$.% +} + +Inference for the parts +(\commentary{% +such as the iterable expression of a for-in, +or the \synt{forInitializerStatement} of a for loop% +}) +is done as for the corresponding \FOR{} statement, +including \AWAIT{} if and only if the element includes \AWAIT. + +\begin{itemize} +\item + If the inferred element type of $\ell_1$ is $S$ then + the inferred element type of $\ell$ is $S$. +\item + If the inferred key and value type pair of $e_1$ is $(K, V)$, + the inferred key and value type pair of $\ell$ is $(K, V)$. +\end{itemize} + +\commentary{% +In other words, inference flows upwards from the body element.% +} +\vspace{3mm} +\EndCase + +\LMHash{}% +Finally, we define +\IndexCustom{type inference on a set or map literal}{% + type inference!set or map literal} +as a whole. +Assume that \metavar{collection} is derived from \synt{setOrMapLiteral}, +and the context type for \metavar{collection} is $P$. + +\begin{itemize} +\item + If \metavar{collection} is unambiguously a set: + + \begin{itemize} + \item + If $P$ is \FreeContext{} then + the static type of \metavar{collection} is \code{Set<$T$>} + where $T$ is the least upper bound of + the inferred element types of the elements. + \item + %% TODO(eernst): Feature spec says $P$, but how do we know $P$ is a type? + Otherwise, the static type of \metavar{collection} is $T$ + where $T$ is determined by downwards inference. + + \commentary{% + Note that the inference will never produce a key and value type pair + with the given context type.% + } + \end{itemize} + + The static type of \metavar{collection} is then \code{Set<$T$>}. +\item + If \metavar{collection} is unambiguously a map + where $P$ is \code{Map<$P_k$,\,\,$P_v$>} or $P$ is \FreeContext{} + and the inferred key and value type pairs are + \KeyValueTypeList{K}{V}{1}{n}: + + If $P_k$ is \FreeContext{} or $P$ is \FreeContext, + the static key type of \metavar{collection} is $K$ + where $K$ is the least upper bound of \List{K}{1}{n}. + Otherwise the static key type of \metavar{collection} is $K$ + where $K$ is determined by downwards inference. + + If $P_v$ is \FreeContext{} or $P$ is \FreeContext, + the static value type of \metavar{collection} is $V$ + where $V$ is the least upper bound of \List{V}{1}{n}. + Otherwise the static value type of \metavar{collection} is $V$ + where $V$ is determined by downwards inference. + + \commentary{% + Note that inference will never produce a element type here + given this downwards context.% + } + + The static type of \metavar{collection} is then \code{Map<$K$,\,\,$V$>}. +\item + Otherwise, \metavar{collection} is still ambiguous, + the downwards context for the elements of \metavar{collection} + is \FreeContext, + and the disambiguation is done using + the immediate elements of \metavar{collection} as follows: + + \begin{itemize} + \item + If all elements can be a set, + and at least one element must be a set, + then \metavar{collection} is a set literal with + static type \code{Set<$T$>} where $T$ is + the least upper bound of the element types of the elements. + \item + If all elements can be a map, + and at least one element must be a map, then $e$ is + a map literal with static type \code{Map<$K$,\,\,$V$>} where $K$ is + the least upper bound of the key types of the elements and $V$ is + the least upper bound of the value types. + \item + Otherwise, a compile-time error occurs. + \commentary{In this case the literal cannot be disambiguated.} + \end{itemize} +\end{itemize} + +\commentary{% +This last error can occur if the literal \emph{must} be both a set and a map. +Here is an example:% +} + +\begin{dartCode} +\VAR{} iterable = [1, 2]; +\VAR{} map = \{1: 2\}; +\VAR{} ambiguous = \{...iterable, ...map\}; // \comment{Compile-time error} +\end{dartCode} + +\commentary{% +\noindent +Or, if there is nothing indicates that it is \emph{either} a set or a map:% +} + +\begin{dartCode} +\DYNAMIC{} dyn; +\VAR{} ambiguous = \{...dyn\}; // \comment{Compile-time error} +\end{dartCode} + + +\subsubsection{Sets} +\LMLabel{sets} + +\LMHash{}% +A \IndexCustom{set literal}{literal!set} denotes a set object. +The grammar rule for \synt{setOrMapLiteral} which covers +set literals as well as map literals occurs elsewhere +(\ref{collectionLiterals}). +A set literal consists of zero or more collection literal elements +(\ref{collectionLiterals}). +A term derived from \synt{setOrMapLiteral} +may be a set literal or a map literal, +and it is determined via a disambiguation step +whether it is a set literal or a map literal +(\ref{setAndMapLiteralDisambiguation}, \ref{setAndMapLiteralInference}). + +\LMHash{}% +When a given set literal $e$ has no type arguments, +the type argument $T$ is selected as specified elsewhere +(\ref{setAndMapLiteralInference}), +and $e$ is henceforth treated as +(\ref{notation}) +\code{<$T$>$e$}. + +\commentary{% +The static type of a set literal of the form \code{<$T$>$e$} +is \code{Set<$T$>} +(\ref{setAndMapLiteralInference}).% +} + +\LMHash{}% +Let $e$ be a set literal of the form +\code{<$T$>\{\List{\ell}{1}{m}\}}. +It is a compile-time error if a leaf element of $e$ is a +\synt{mapElement}. +It is a compile-time error if, for some $j \in 1 .. m$, +$\ell_j$ does not have an element type, +or the element type of $\ell_j$ may not be assigned to $T$. + +\LMHash{}% +A set may contain zero or more objects. +Sets have a method which can be used to insert objects; +this will incur a dynamic error if the set is not modifiable. +Otherwise, when inserting an object $o_{\metavar{new}}$ into a set $s$, +if an object $o_{\metavar{old}}$ exists in $s$ such that +\code{$o_{\metavar{old}}$ == $o_{\metavar{new}}$} evaluates to \TRUE{} +then the insertion makes no changes to $s$; +if no such object exists, +$o_{\metavar{new}}$ is added to $s$; +in both cases the insertion completes successfully. + +\LMHash{}% +A set is ordered: iteration over the elements of a set +occurs in the order the elements were added to the set. + +\commentary{% +The system libraries define many members for the type \code{Set}, +but we specify only the minimal set of requirements +which are used by the language itself.% + +Note that an implementation may require +consistent definitions of several members +of a class implementing \code{Set} in order to work correctly. +For instance, there may be a getter \code{hashCode} which is required +to have a behavior which is in some sense consistent with operator \lit{==}. +Such constraints are documented in the system libraries.% +} + +\LMHash{}% +If a set literal $e$ begins with the reserved word \CONST{} +or $e$ occurs in a constant context +(\ref{constantContexts}), +it is a +\IndexCustom{constant set literal}{literal!set!constant} +which is a constant expression +(\ref{constants}) +and therefore evaluated at compile time. +Otherwise, it is a +\IndexCustom{run-time set literal}{literal!set!run-time} +and it is evaluated at run time. +Only run-time set literals can be mutated after they are created. +% This error can occur because being constant is a dynamic property, here. +Attempting to mutate a constant set literal will result in a dynamic error. + +\commentary{% +% The following is true either directly or indirectly: There is a \CONST{} +% modifier on the literal set, or we use the "immediate subexpression" rule +% about constant contexts. +Note that the element expressions of a constant set literal +occur in a constant context +(\ref{constantContexts}), +which means that \CONST{} modifiers need not be specified explicitly.% +} + +\LMHash{}% +It is a compile-time error if +a collection literal element in a constant set literal +is not a constant expression. +It is a compile-time error if +an element in a constant set literal +does not have primitive equality +(\ref{theOperatorEqualsEquals}). +It is a compile-time error if two elements of a constant set literal are equal +according to their \lit{==} operator +(\ref{equality}). +It is a compile-time error if the type argument of a constant set literal +(\commentary{no matter whether it is explicit or inferred}) +is not a constant type expression +(\ref{constants}). + +\rationale{% +The binding of a formal type parameter of an enclosing class or function +is not known at compile time, +so we cannot use such type parameters inside constant expressions.% +} + +\LMHash{}% +The value of a constant set literal +\code{\CONST?\,\,<$T$>\{\List{\ell}{1}{m}\}} +is an object $o$ whose class implements the built-in class +\code{Set<$t$>} +where $t$ is the actual value of $T$ +(\ref{actualTypes}), +and whose contents is the set of objects in +the object sequence \List{o}{1}{n} obtained by +evaluation of \List{\ell}{1}{m} +(\ref{collectionLiteralElementEvaluation}). +The elements of $o$ occur in the same order as +the objects in said object sequence +(\commentary{which can be observed by iteration}). + +\LMHash{}% +Let \code{\CONST?\,\,<$T_1$>\{\,$\ell_{11}, \ldots, \ell_{1m_1}$\,\}} +and \code{\CONST?\,\,<$T_2$>\{\,$\ell_{21}, \ldots, \ell_{2m_2}$\,\}} +be two constant set literals. +Let $o_1$ with contents $o_{11}, \ldots, o_{1n}$ and actual type argument $t_1$ +respectively +$o_2$ with contents $o_{21}, \ldots, o_{2n}$ and actual type argument $t_2$ +be the result of evaluating them. +Then \code{identical($o_1$, $o_2$)} evaluates to \TRUE{} if{}f +%% TODO(eernst): Refer to nnbd notion of 'same type'. +\code{$t_1$ == $t_2$} and \code{identical($o_{1i}$, $o_{2i}$)} +evaluates to \TRUE{} for all $i \in 1 .. n$. + +\commentary{% +In other words, constant set literals are canonicalized if they have +the same type argument and the same values in the same order. +Two constant set literals are never identical +if they have a different number of elements. +There is no need to consider canonicalization +for other instances of type \code{Set}, +because such instances cannot be +the result of evaluating a constant expression.% +} + +\LMHash{}% +A run-time set literal \code{<$T$>\{\List{\ell}{1}{n}\}} +is evaluated as follows: +\begin{itemize} +\item + The elements \List{\ell}{1}{m} are evaluated + (\ref{collectionLiteralElementEvaluation}), + to an object sequence \LiteralSequence{\List{o}{1}{n}}. +\item + A fresh object (\ref{generativeConstructors}) $o$ + implementing the built-in class \code{Set<$t$>} is created, + where $t$ is the actual value of $T$ + (\ref{actualTypes}). +\item + For each object $o_j$ in \List{o}{1}{n}, in order, + $o_j$ is inserted into $o$. + \commentary{% + Note that this leaves $o$ unchanged when $o$ already contains + and object $o$ which is equal to $o_j$ according to operator \lit{==}.% + } +\item + The result of the evaluation is $o$. +\end{itemize} + +\LMHash{}% +The objects created by set literals do not override +the \lit{==} operator inherited from the \code{Object} class. + + +\subsubsection{Maps} +\LMLabel{maps} + +\LMHash{}% +A \IndexCustom{map literal}{literal!map} denotes a map object, +which is a mapping from keys to values. +The grammar rule for \synt{setOrMapLiteral} which covers both +map literals and set literals occurs elsewhere +(\ref{collectionLiterals}). +A map literal consists of zero or more collection literal elements +(\ref{collectionLiterals}). +A term derived from \synt{setOrMapLiteral} +may be a set literal or a map literal, +and it is determined via a disambiguation step +whether it is a set literal or a map literal +(\ref{setAndMapLiteralDisambiguation}, \ref{setAndMapLiteralInference}). + +\LMHash{}% +When a given map literal $e$ has no type arguments, +the type arguments $K$ and $V$ are selected as specified elsewhere +(\ref{setAndMapLiteralInference}), +and $e$ is henceforth treated as +(\ref{notation}) +\code{<$K$,\,$V$>$e$}. + +\commentary{% +The static type of a map literal of the form \code{<$K$,\,$V$>$e$} +is \code{Map<$K$,\,$V$>} +(\ref{setAndMapLiteralInference}).% +} + +\LMHash{}% +Let $e$ be a map literal of the form +\code{<$K$,\,$V$>\{\List{\ell}{1}{m}\}}. +It is a compile-time error if a leaf element of $e$ is an +\synt{expressionElement}. +It is a compile-time error if, for some $j \in 1 .. m$, +$\ell_j$ does not have a key and value type pair; +or the key and value type pair of $\ell_j$ is $(K_j, V_j)$, +and $K_j$ may not be assigned to $K$ or +$V_j$ may not be assigned to $V$. + +\LMHash{}% +A map object consists of zero or more map entries. +Each entry has a \Index{key} and a \Index{value}, +and we say that the map +\IndexCustom{binds}{map!binds} or +\IndexCustom{maps}{map!maps} +the key to the value. +A key and value pair is +added to a map using operator \lit{[]=}, +and the value for a given key is retrieved from a map using operator \lit{[]}. +The keys of a map are treated similarly to a set +(\ref{sets}): +When binding a key $k_{\metavar{new}}$ to a value $v$ in a map $m$ +(\commentary{as in \code{$m$[$k_{\metavar{new}}$]\,=\,$v$}}), +if $m$ already has a key $k_{\metavar{old}}$ such that +\code{$k_{\metavar{old}}$ == $k_{\metavar{new}}$} evaluates to \TRUE, +$m$ will bind $k_{\metavar{old}}$ to $v$; +otherwise +(\commentary{when no such key $k_{\metavar{old}}$ exists}), +a binding from $k_{\metavar{new}}$ to $v$ is added to $m$. + +\LMHash{}% +A map is ordered: iteration over the keys, values, or key/value pairs +occurs in the order in which the keys were added to the set. + +\commentary{% +The system libraries support many operations on an instance +whose type implements \code{Map}, +but we specify only the minimal set of requirements +which are used by the language itself. + +Note that an implementation may require +consistent definitions of several members +of a class implementing \code{Map} in order to work correctly. +For instance, there may be a getter \code{hashCode} which is required +to have a behavior which is in some sense consistent with operator \lit{==}. +Such constraints are documented in the system libraries.% +} + +\LMHash{}% +If a map literal $e$ begins with the reserved word \CONST, +or if $e$ occurs in a constant context +(\ref{constantContexts}), +it is a +\IndexCustom{constant map literal}{literal!map!constant} +which is a constant expression +(\ref{constants}) +and therefore evaluated at compile time. +Otherwise, it is a +\IndexCustom{run-time map literal}{literal!map!run-time} +and it is evaluated at run time. +Only run-time map literals can be mutated after they are created. +% This error can occur because being constant is a dynamic property, here. +Attempting to mutate a constant map literal will result in a dynamic error. + +\commentary{% +% The following is true either directly or indirectly: There is a \CONST{} +% modifier on the literal map, or we use the "immediate subexpression" rule +% about constant contexts. +Note that the key and value expressions of a constant map literal +occur in a constant context +(\ref{constantContexts}), +which means that \CONST{} modifiers need not be specified explicitly.% +} + +\LMHash{}% +It is a compile-time error +if a collection literal element in a constant map literal is not constant. +It is a compile-time error if +a key in a constant map literal +does not have primitive equality +(\ref{theOperatorEqualsEquals}). +It is a compile-time error if two keys of a constant map literal are equal +according to their \lit{==} operator +(\ref{equality}). +It is a compile-time error if a type argument of a constant map literal +(\commentary{no matter whether it is explicit or inferred}) +is not a constant type expression +(\ref{constants}). + +\rationale{% +The binding of a formal type parameter of an enclosing class or function +is not known at compile time, +so we cannot use such type parameters inside constant expressions.% +} + +\LMHash{}% +The value of a constant map literal +\code{\CONST?\,\,<$T_1$,\,$T_2$>\{\List{\ell}{1}{m}\}} +is an object $o$ whose class implements the built-in class +\code{Map<$t_1$,\,\,$t_2$>}, +where $t_1$ and $t_2$ is the actual value of $T_1$ respectively $T_2$ +(\ref{actualTypes}). +The key and value pairs of $o$ is +the pairs of the object sequence \KeyValueList{k}{v}{1}{n} obtained by +evaluation of \List{\ell}{1}{m} +(\ref{collectionLiteralElementEvaluation}), +in that order. + +\LMHash{}% +Let \code{\CONST?\,\,<$U_1$,\,$V_1$>\{\List{\ell}{1}{m_1}\}} +and \code{\CONST?\,\,<$U_2$,\,$V_2$>\{\List{\ell}{1}{m_2}\}} +be two constant map literals. +Let $o_1$ with contents \KeyValueList{k_1}{v_1}{1}{n} +and actual type arguments $u_1$, $v_1$ +respectively +$o_2$ with contents \KeyValueList{k_2}{v_2}{1}{n} +and actual type argument $u_2$, $v_2$ +be the result of evaluating them. +Then \code{identical($o_1$, $o_2$)} evaluates to \TRUE{} if{}f +\code{$u_1$ == $u_2$}, \code{$v_1$ == $v_2$}, +\code{identical($k_{1i}$, $k_{2i}$)}, and +\code{identical($v_{1i}$, $v_{2i}$)} +for all $i \in 1 .. n$. + +\commentary{% +In other words, constant map literals are canonicalized. +There is no need to consider canonicalization +for other instances of type \code{Map}, +because such instances cannot be +the result of evaluating a constant expression.% +} + +\LMHash{}% +A run-time map literal +\code{<$T_1, T_2$>\{\List{\ell}{1}{m}\}} +is evaluated as follows: +\begin{itemize} +\item + The elements \List{\ell}{1}{m} are evaluated + (\ref{collectionLiteralElementEvaluation}), + to an object sequence \LiteralSequence{\KeyValueList{k}{v}{1}{n}}. +\item + A fresh instance (\ref{generativeConstructors}) $o$ + whose class implements the built-in class \code{Map<$t_1$,\,\,$t_2$>} + is allocated, + where $t_1$ and $t_2$ are the actual values of $T_1$ respectively $T_2$ + (\ref{actualTypes}). +\item + The operator \lit{[]=} is invoked on $o$ + with first argument $k_i$ and second argument $v_i$, + for each $i \in 1 .. n$, in that order. +\item + The result of the evaluation is $o$. +\end{itemize} + +\LMHash{}% +The objects created by map literals do not override +the \lit{==} operator inherited from the \code{Object} class. + + +\subsection{Throw} +\LMLabel{throw} + +\LMHash{}% +The \Index{throw expression} is used to throw an exception. + +\begin{grammar} + ::= \THROW{} + + ::= \THROW{} +\end{grammar} + +\LMHash{}% +Evaluation of a throw expression of the form +\code{\THROW{} $e$;} +proceeds as follows: + +\LMHash{}% +The expression $e$ is evaluated to an object $v$ +(\ref{expressionEvaluation}). + +\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{expressionEvaluation}). + +\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 \code{stackTrace} getter inherited from \code{Error}. + +\commentary{% +If the same \code{Error} object is thrown more than once, +its \code{stackTrace} getter will return the stack trace from +the \emph{first} time it was thrown.% +} + +\LMHash{}% +The static type of a throw expression is $\bot$. + + +\subsection{Function Expressions} +\LMLabel{functionExpressions} + +\LMHash{}% +A \IndexCustom{function literal}{literal!function} +is an anonymous declaration and an expression +that encapsulates an executable unit of code. + +%% TODO(eernst): This is highly ambiguous because derives +%% . Dart.g derives from +%% but only allows the block in , which +%% is derived from . It has +%% as well, allowing for an `=>` function literal in a cascade assignment. +%% However, we need to assess the breakage very carefully before adopting +%% that approach, because it prevents function literals from being parsed +%% as conditionalExpression, ifNullExpression, ... postfixExpression. +\begin{grammar} + ::= + + ::= \ASYNC? `=>' + \alt (\ASYNC{} `*'? | \SYNC{} `*')? +\end{grammar} + +\LMHash{}% +The grammar does not allow a function literal to declare a return type, +but it is possible for a function literal to have a +\IndexCustom{declared return type}{literal!function!declared return type}, +because it can be obtained by means of type inference. +Such a return type is included +when we refer to the declared return type of a function. + +\commentary{% +Type inference will be specified in a future version of this document. +Currently we consider type inference to be a phase that has completed, +and this document specifies the meaning of Dart programs +where inferred types have already been added.% +} + +\LMHash{}% +We say that a type $T$ +\IndexCustom{derives a future type}{type!derives a future type} +$F$ in the following cases, using the first applicable case: + +%% TODO(eernst): Note that `X extends X?` can create an infinite loop. +%% We will probably make that kind of bound an error. +\begin{itemize} +\item + %% TODO(eernst): Come mixin classes and extension types: add them. + If $T$ is a type which is introduced by + a class, mixin, or enum declaration, + and if $T$ or a direct or indirect superinterface + (\ref{interfaceSuperinterfaces}) + of $T$ is \code{Future<$U$>} for some $U$, + then $T$ derives the future type \code{Future<$U$>}. +\item + If $T$ is the type \code{FutureOr<$U$>} for some $U$, + then $T$ derives the future type \code{FutureOr<$U$>}. +\item + If $T$ is \code{$S$?} for some $S$, and + $S$ derives the future type $F$, + then $T$ derives the future type \code{$F$?}. +\item + If $T$ is a type variable with bound $B$, and + $B$ derives the future type $F$, + then $T$ derives the future type $F$. +\item + \commentary{% + There is no rule for the case where $T$ is of the form \code{$X$\,\&\,$S$} + because this will never occur + (this concept is only used in \flattenName, which is defined below).% + } +\end{itemize} + +\LMHash{}% +When none of these cases are applicable, +we say that $T$ does not derive a future type. + +\commentary{% +Note that if $T$ derives a future type $F$ then \SubtypeNE{T}{F}, +and $F$ is always of the form \code{$G$<...>} or \code{$G$<...>?}, +where $G$ is \code{Future} or \code{FutureOr}. The proof is by induction on the +structure of $T$: + +\begin{itemize} +\item + %% TODO(eernst): Come mixin classes and extension types: add them. + If $T$ is a type which is introduced by + a class, mixin, or enum declaration, + and if $T$ or a direct or indirect superinterface + (\ref{interfaceSuperinterfaces}) + of $T$ is \code{Future<$U$>} for some $U$, then, letting + \code{$G =$ Future} and \code{$F = G$<$U$>}, $T <: F$. +\item + If $T$ is the type \code{FutureOr<$U$>} for some $U$, then by reflexivity, + \code{$T <:$ FutureOr<$U$>}. Letting \code{$G =$ FutureOr} and + \code{$F = G$<$U$>}, it follows that $T <: F$. +\item + If $T$ is \code{$S$?} for some $S$, and + $S$ derives the future type $F'$, + then by the induction hypothesis, \code{$S <: F'$}, where $F'$ is of the form + \code{$G'$<$U$>} or \code{$G'$<$U$>?} and $G'$ is \code{Future} or + \code{FutureOr}. Therefore, \code{$S$? $<: F'$?}, and by substitution, + \code{$T <: F'$?}. Since \code{$T$?? $= T$?} for all $T$, it follows that + \code{$T <: G'$<$U$>?}. So, letting $G = G'$ and \code{$F = G$<$U$>?}, + it follows that $T <: F$. +\item + If $T$ is a type variable with bound $B$, and + $B$ derives the future type $F$, + then by the induction hypothesis, \code{$B <: F'$}, where $F'$ is of the form + \code{$G'$<$U$>} or \code{$G'$<$U$>?} and $G'$ is \code{Future} or + \code{FutureOr}. Also, since $B$ is the bound of $T$, $T <: B$, so by + transitivity, $T <: F'$. Therefore, letting $G = G'$ and $F = F'$, it + follows that $T <: F$. +\end{itemize} + +Also note that 'derives' in this context refers to the computation +where a type $T$ is given, the supertypes of $T$ are searched, +and a type $F$ of one of those forms is selected. +There is no connection to the notion of a 'derived class' meaning 'subclass' +that some programming language communities use.% +} + +\LMHash{}% +We define the auxiliary function +\IndexCustom{\flatten{T}}{flatten(t)@\emph{flatten}$(T)$} +as follows, using the first applicable case: + +\begin{itemize} +\item If $T$ is \code{$X$\,\&\,$S$} + for some type variable $X$ and type $S$ then + \begin{itemize} + \item if $S$ derives a future type $U$ + then \DefEquals{\flatten{T}}{\code{\flatten{U}}}. + \item otherwise, + \DefEquals{\flatten{T}}{\code{\flatten{X}}}. + \end{itemize} + +\item If $T$ derives a future type \code{Future<$S$>} + or \code{FutureOr<$S$>} + then \DefEquals{\flatten{T}}{S}. + +\item If $T$ derives a future type \code{Future<$S$>?}\ or + \code{FutureOr<$S$>?}\ then \DefEquals{\flatten{T}}{\code{$S$?}}. + +\item Otherwise, \DefEquals{\flatten{T}}{T}. +\end{itemize} + +\rationale{% +This definition guarantees that for any type $T$, +\code{$T <:$ FutureOr<$\flatten{T}$>}. The proof is by induction on the +structure of $T$: + +\begin{itemize} +\item If $T$ is \code{$X$\,\&\,$S$} then + \begin{itemize} + \item if $S$ derives a future type $U$, + then \code{$T <: S$} and \code{$S <: U$}, so \code{$T <: U$}. + By the induction hypothesis, \code{$U <:$ FutureOr<$\flatten{U}$>}. + Since \code{$\flatten{T} = \flatten{U}$} in this case, it follows that + \code{$U <:$ FutureOr<$\flatten{T}$>}, and so + \code{$T <:$ FutureOr<$\flatten{T}$>}. + \item otherwise, \code{$T <: X$}. + By the induction hypothesis, \code{$X <:$ FutureOr<$\flatten{X}$>}. + Since \code{$\flatten{T} = \flatten{X}$} in this case, it follows that + \code{$U <:$ FutureOr<$\flatten{T}$>}, and so + \code{$T <:$ FutureOr<$\flatten{T}$>}. + \end{itemize} + +\item If $T$ derives a future type \code{Future<$S$>} + or \code{FutureOr<$S$>}, then, since \code{Future<$S$> $<:$ FutureOr<$S$>}, + it follows that \code{$T <:$ FutureOr<$S$>}. Since \code{$\flatten{T} = S$} + in this case, it follows that \code{$T <:$ FutureOr<$\flatten{T}$>}. + +\item If $T$ derives a future type \code{Future<$S$>?} or + \code{FutureOr<$S$>?}, then, since \code{Future<$S$>? $<:$ FutureOr<$S$>?}, + it follows that \code{$T <:$ FutureOr<$S$>?}. + \code{FutureOr<$S$>? $<:$ FutureOr<$S$?>} for any type $S$ (this can be shown + using the union type subtype rules and from + \code{Future<$S$> $<:$ Future<$S$?>} by covariance), so by transivitity, + \code{$T <:$ FutureOr<$S$?>}. Since \code{$\flatten{T} = S$?} in this case, + it follows that \code{$T <:$ FutureOr<$\flatten{T}$>}. + +\item Otherwise, \code{$\flatten{T} = T$}, so + \code{FutureOr<$\flatten{T}$> $=$ FutureOr<$T$>}. Since + \code{$T <:$ FutureOr<$T$>}, it follows that + \code{$T <:$ FutureOr<$\flatten{T}$>}. +\end{itemize} +} + +\LMHash{}% +\Case{Positional, arrow} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +\FunctionTypePositionalStd{T_0}, + +\noindent +%% TODO[inference]: The static type of the function literal may be inferred. +where $T_0$ is the static type of $e$. +\EndCase + +\LMHash{}% +\Case{Positional, arrow, future} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +\FunctionTypePositionalStdCr{\code{Future<\flatten{T_0}>}}, + +\noindent +where $T_0$ is the static type of $e$. +\EndCase + +\LMHash{}% +\Case{Named, arrow} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +\FunctionTypeNamedStd{T_0}, + +\noindent +where $T_0$ is the static type of $e$. +\EndCase + +\LMHash{}% +\Case{Named, arrow, future} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +\FunctionTypeNamedStdCr{\code{Future<\flatten{T_0}>}}, + +\noindent +where $T_0$ is the static type of $e$. +\EndCase + +\LMHash{}% +\Case{Positional, block} +The static type of a function literal of the form + +\noindent +\code{<\TypeParameters{X}{B}{S}>} + +\noindent +\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 +\FunctionTypePositionalStdCr{\DYNAMIC} +\EndCase + +\LMHash{}% +\Case{Positional, block, future} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypePositionalStdCr{\code{Future}}. +\EndCase + +\LMHash{}% +\Case{Positional, block, stream} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypePositionalStdCr{\code{Stream}}. +\EndCase + +\LMHash{}% +\Case{Positional, block, iterable} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypePositionalStdCr{\code{Iterable}}. +\EndCase + +\LMHash{}% +\Case{Named, block} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypePositionalStdCr{\DYNAMIC}. +\EndCase + +\LMHash{}% +\Case{Named, block, future} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypeNamedStdCr{\code{Future}}. +\EndCase + +\LMHash{}% +\Case{Named, block, stream} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypeNamedStdCr{\code{Stream}}. +\EndCase + +\LMHash{}% +\Case{Named, block, iterable} +The static type of a function literal of the form + +\noindent +\code{<\TypeParametersStd>} + +\noindent +\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 +%% TODO(eernst): Adjust to take type inference into account. +\FunctionTypeNamedStdCr{\code{Iterable}}. +\EndCase + +\LMHash{}% +In all of the above cases, +the type argument lists are omitted when $m=0$, +and whenever $T_i$ is not specified, $i \in 1 .. n+k$, +it is considered to have been specified as \DYNAMIC. + +\LMHash{}% +Evaluation of a function literal yields a function object $o$. + +\commentary{% +The run-time type of $o$ is specified based on +the static type $T$ of the function literal +and the binding of type variables occurring in $T$ +at the occasion where the evaluation occurred +(\ref{typeOfAFunction}).% +} + + +\subsection{This} +\LMLabel{this} + +\LMHash{}% +The reserved word \THIS{} denotes +the target of the current instance member invocation. + +\begin{grammar} + ::= \THIS{} +\end{grammar} + +\LMHash{}% +The static type of \THIS{} is the interface of the +immediately enclosing class, enum, or mixin, if any. +The static type of \THIS{} is +the \ON{} type of the enclosing extension, if any +(\ref{extensions}). + +\commentary{% +If none of those declarations exist, +an occurrence of \THIS{} is a compile-time error +(\ref{classes}).% +} + +\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 initializing expression of a non-late 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.% +} + +\LMHash{}% +It is a compile-time error if +the type $T$ in an instance creation expression of one of the forms + +\noindent +\code{\NEW{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, + +\noindent +\code{\NEW{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, + +\noindent +\code{\CONST{} $T$.\id($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)}, + +\noindent +\code{\CONST{} $T$($a_1, \ldots,\ a_n,\ x_{n+1}$: $a_{n+1}, \ldots,\ x_{n+k}$: $a_{n+k}$)} + +\noindent +is an enumerated type (\ref{enums}). + + +\subsubsection{New} +\LMLabel{new} + +\LMHash{}% +The \Index{new expression} invokes a constructor (\ref{constructors}). + +\begin{grammar} + ::= \NEW{} +\end{grammar} + +\LMHash{}% +Let $e$ be a new expression of the form + +\noindent +\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 + +\noindent +\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()} is an error if \code{F} is a type alias +that does not denote a class.% +} + +\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 + +\noindent +\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 + +\noindent +\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$.} +% This error can occur due to an implicit cast. +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} +% This error can occur because being-loaded is a dynamic property. +If $T$ is a deferred type with prefix $p$, +then if $p$ has not been successfully loaded, +a dynamic error occurs. +\EndCase + +\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{statementCompletion}), +$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{expressionEvaluation}). +\EndCase + +\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.% +} +\EndCase + +\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 an object +(\ref{statementCompletion}) +then $e$ evaluates to the returned object. +Otherwise, if the execution completes normally or returns with no object, +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{expressionEvaluation}). + +\rationale{% +A factory constructor can be declared in an abstract class and used safely, +as it will either produce a valid instance or throw.% +} +\EndCase + + +\subsubsection{Const} +\LMLabel{const} + +\LMHash{}% +A \Index{constant object expression} invokes a constant constructor +(\ref{constantConstructors}). + +\begin{grammar} + ::= \CONST{} +\end{grammar} + +\LMHash{}% +Let $e$ be a constant object expression of the form + +\noindent +\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 + +\noindent +\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$ is not a constant type expression 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'$: + +\noindent +\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 method call, +invoking one of the static methods \code{spawnUri} or \code{spawn} defined in +the \code{Isolate} class in the library \code{dart:isolate}. +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. +% This error can occur because memory usage is a dynamic property. +It is possible for a running isolate to exhaust its memory or stack, +resulting in a dynamic 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 runtime.% +} + + +\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 an object $v$ +(\ref{statementCompletion}), +the invocation evaluates to $v$. +If the execution completes normally or it returns without an object, +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{expressionEvaluation}). + +\commentary{% +A complete function body can never break or continue +(\ref{statementCompletion}) +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 an object is treated +the same as returning with 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 an object, 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 the actual type +(\ref{actualTypes}) +corresponding to the element type of $f$ +(\ref{functions}). + +\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{statementCompletion}), +\begin{itemize} +\item If it returns without an object or it completes normally + (\ref{statementCompletion}), + $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} + +\LMHash{}% +Each iterator starts a separate computation. +If the \code{\SYNC*} function is impure, +the sequence of objects 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}, +where $T$ is the actual type +(\ref{actualTypes}) +corresponding to the future value type of $f$. +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{statementCompletion}). +If execution of the body returns an object, $o$ is completed with that object. +If it completes normally or returns without an object, +$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 +\emph{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 the actual type +(\ref{actualTypes}) +corresponding to the element type of $f$ +(\ref{functions}). +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 without an object + (\ref{statementCompletion}), + 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 with an object +(\ref{statementCompletion}). +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.% +} + + +\subsubsection{Actual Argument Lists} +\LMLabel{actualArgumentLists} + +\LMHash{}% +Actual argument lists have the following syntax: + +\begin{grammar} + ::= `(' ( `,'?)? `)' + + ::= (`,' )* + \alt (`,' )* + + ::=