Version 2.12.0-13.0.dev

Merge commit 'e8c4cc60d6376c94d48ace4cf5bb00caccbc11c7' into 'dev'
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index f30ff8e..3fdeadb 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -11,6 +11,14 @@
   is now `FunctionTypeAliasElement`, not its function element.
 * Removed deprecated `GenericTypeAliasElement`.
 
+## 0.40.6
+* The non_nullable feature is released in 2.12 language version.
+* Updated the current language version to 2.12.
+* Changed the default language version when the package does not specify one.
+  Instead of the latest known language version, the language version of the
+  SDK (against which analysis is done, not necessary the same as used to run
+  the analyzer) is used.
+
 ## 0.40.5
 * Deprecated `GenericTypeAliasElement`. Use `FunctionTypeAliasElement`.
 * Read imports, exports, and parts on demand in `AnalysisDriver`.
diff --git a/pkg/dartdev/lib/src/analytics.dart b/pkg/dartdev/lib/src/analytics.dart
index c42129d..9f3095f 100644
--- a/pkg/dartdev/lib/src/analytics.dart
+++ b/pkg/dartdev/lib/src/analytics.dart
@@ -54,39 +54,46 @@
   if (Platform.environment['_DARTDEV_LOG_ANALYTICS'] != null) {
     // Used for testing what analytics messages are sent.
     _instance = _LoggingAnalytics();
-  } else if (disableAnalytics) {
+    return _instance;
+  }
+
+  if (disableAnalytics) {
     // Dartdev tests pass a hidden 'disable-dartdev-analytics' flag which is
     // handled here.
     // Also, stdout.hasTerminal is checked, if there is no terminal we infer that
     // a machine is running dartdev so we return analytics shouldn't be set.
     _instance = DisabledAnalytics(_trackingId, _appName);
-  } else {
-    var settingsDir = getDartStorageDirectory();
-    if (settingsDir == null) {
-      // Some systems don't support user home directories; for those, fail
+    return _instance;
+  }
+
+  var settingsDir = getDartStorageDirectory();
+  if (settingsDir == null) {
+    // Some systems don't support user home directories; for those, fail
+    // gracefully by returning a disabled analytics object.
+    _instance = DisabledAnalytics(_trackingId, _appName);
+    return _instance;
+  }
+
+  if (!settingsDir.existsSync()) {
+    try {
+      settingsDir.createSync();
+    } catch (e) {
+      // If we can't create the directory for the analytics settings, fail
       // gracefully by returning a disabled analytics object.
       _instance = DisabledAnalytics(_trackingId, _appName);
-    } else if (!settingsDir.existsSync()) {
-      try {
-        settingsDir.createSync();
-      } catch (e) {
-        // If we can't create the directory for the analytics settings, fail
-        // gracefully by returning a disabled analytics object.
-        _instance = DisabledAnalytics(_trackingId, _appName);
-      }
-    } else {
-      var readmeFile =
-          File('${settingsDir.absolute.path}${path.separator}$_readmeFileName');
-      if (!readmeFile.existsSync()) {
-        readmeFile.createSync();
-        readmeFile.writeAsStringSync(_readmeFileContents);
-      }
-
-      var settingsFile = File(path.join(settingsDir.path, _settingsFileName));
-      _instance = DartdevAnalytics(_trackingId, settingsFile, _appName);
+      return _instance;
     }
   }
 
+  var readmeFile =
+      File('${settingsDir.absolute.path}${path.separator}$_readmeFileName');
+  if (!readmeFile.existsSync()) {
+    readmeFile.createSync();
+    readmeFile.writeAsStringSync(_readmeFileContents);
+  }
+
+  var settingsFile = File(path.join(settingsDir.path, _settingsFileName));
+  _instance = DartdevAnalytics(_trackingId, settingsFile, _appName);
   return _instance;
 }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 8c009af..a10bff9 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3002,12 +3002,49 @@
     // size on expression evaluation is better.
     // Issue: https://github.com/dart-lang/sdk/issues/43288
     var fun = _emitFunction(functionNode, name);
-    var items = _typeTable?.discharge();
-    var body = js_ast.Block([...?items, ...fun.body.statements]);
 
+    var types = _typeTable.discharge();
+    var constants = _dischargeConstTable();
+
+    var body = js_ast.Block([...?types, ...?constants, ...fun.body.statements]);
     return js_ast.Fun(fun.params, body);
   }
 
+  /// Emit all collected const symbols
+  ///
+  /// This is similar to how constants are emitted during
+  /// initial compilation in emitModule
+  ///
+  /// TODO: unify the code with emitModule.
+  List<js_ast.Statement> _dischargeConstTable() {
+    var items = <js_ast.Statement>[];
+
+    if (_constLazyAccessors.isNotEmpty) {
+      var constTableBody = runtimeStatement(
+          'defineLazy(#, { # }, false)', [_constTable, _constLazyAccessors]);
+      items.add(constTableBody);
+      _constLazyAccessors.clear();
+    }
+
+    _copyAndFlattenBlocks(items, moduleItems);
+    moduleItems.clear();
+    return items;
+  }
+
+  /// Flattens blocks in [items] to a single list.
+  ///
+  /// This will not flatten blocks that are marked as being scopes.
+  void _copyAndFlattenBlocks(
+      List<js_ast.Statement> result, Iterable<js_ast.ModuleItem> items) {
+    for (var item in items) {
+      if (item is js_ast.Block && !item.isScope) {
+        _copyAndFlattenBlocks(result, item.statements);
+      } else {
+        result.add(item as js_ast.Statement);
+      }
+    }
+  }
+
   js_ast.Fun _emitFunction(FunctionNode f, String name) {
     // normal function (sync), vs (sync*, async, async*)
     var isSync = f.asyncMarker == AsyncMarker.Sync;
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 49a1d1c..ff0b230 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -409,6 +409,28 @@
           ))
           ''');
     });
+
+    test('function', () async {
+      await driver.check(
+          scope: <String, String>{'x': '1', 'y': '2', 'z': '3'},
+          expression: 'main',
+          expectedResult: '''
+          (function(x, y, z) {
+            var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
+            dart.defineLazy(CT, {
+              get C0() {
+                return C0 = dart.fn(foo.main, VoidTodynamic());
+              }
+            }, false);
+            var C0;
+            return C0 || CT.C0;
+          }(
+            1,
+            2,
+            3
+          ))
+          ''');
+    });
   });
 
   group('Expression compiler tests in method:', () {
@@ -1313,7 +1335,16 @@
           expression: 'const MyClass(1)',
           expectedResult: '''
           (function(p) {
-            return C0 || CT.C0;
+             dart.defineLazy(CT, {
+               get C0() {
+                 return C0 = dart.const({
+                   __proto__: foo.MyClass.prototype,
+                   [_t]: 1
+                 });
+               }
+             }, false);
+             var C0;
+             return C0 || CT.C0;
           }(
             1
           ))
@@ -1353,6 +1384,15 @@
           expression: "const Key('t')",
           expectedResult: '''
           (function(p) {
+            dart.defineLazy(CT, {
+              get C0() {
+                return C0 = dart.const({
+                  __proto__: foo.ValueKey.prototype,
+                  [value]: "t"
+                  });
+                }
+            }, false);
+            var C0;
             return C0 || CT.C0;
           }(
             1
diff --git a/pkg/nnbd_migration/test/abstract_context.dart b/pkg/nnbd_migration/test/abstract_context.dart
index 05e8c96..367bb3a 100644
--- a/pkg/nnbd_migration/test/abstract_context.dart
+++ b/pkg/nnbd_migration/test/abstract_context.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:convert';
+
 import 'package:analyzer/dart/analysis/analysis_context.dart';
 import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
 import 'package:analyzer/dart/analysis/session.dart';
@@ -23,7 +25,19 @@
   AnalysisContextCollection _analysisContextCollection;
   AnalysisDriver _driver;
 
-  AnalysisDriver get driver => _driver;
+  final Set<String> knownPackages = {};
+
+  /// Whether the test should perform analysis with NNBD enabled.
+  ///
+  /// `false` by default.  May be overridden in derived test classes.
+  bool get analyzeWithNnbd => false;
+
+  AnalysisDriver get driver {
+    if (_driver == null) {
+      _createAnalysisContexts();
+    }
+    return _driver;
+  }
 
   String get homePath => '/home';
 
@@ -49,7 +63,7 @@
   /// package.
   File addPackageFile(String packageName, String pathInLib, String content) {
     var packagePath = '/.pub-cache/$packageName';
-    _addTestPackageDependency(packageName, packagePath);
+    knownPackages.add(packageName);
     return newFile('$packagePath/lib/$pathInLib', content: content);
   }
 
@@ -91,22 +105,13 @@
 ''');
   }
 
-  /// Create all analysis contexts in [_homePath].
-  void createAnalysisContexts() {
-    _analysisContextCollection = AnalysisContextCollectionImpl(
-      includedPaths: [convertPath(homePath)],
-      enableIndex: true,
-      resourceProvider: overlayResourceProvider,
-      sdkPath: convertPath('/sdk'),
-    );
-
-    _driver = getDriver(convertPath(testsPath));
-  }
-
   /// Return the existing analysis context that should be used to analyze the
   /// given [path], or throw [StateError] if the [path] is not analyzed in any
   /// of the created analysis contexts.
   AnalysisContext getContext(String path) {
+    if (_analysisContextCollection == null) {
+      _createAnalysisContexts();
+    }
     path = convertPath(path);
     return _analysisContextCollection.contextFor(path);
   }
@@ -142,86 +147,6 @@
   sdk: '>=2.9.0 <3.0.0'
 ''');
     }
-    var packageConfigPath = '$testsPath/.dart_tool/package_config.json';
-    // Subclasses may write out a different file first.
-    if (!getFile(packageConfigPath).exists) {
-      // TODO(srawlins): This is a rough hack to allow for the "null safe by
-      // default" flag flip. We need to _opt out_ all packages at the onset.
-      // A better solution likely involves the package config-editing code in
-      // analyzer's [context_collection_resolution.dart].
-      newFile(packageConfigPath, content: '''
-{
-  "configVersion": 2,
-  "packages": [
-    {
-      "name": "args",
-      "rootUri": "${toUriStr('/.pub-cache/args')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "collection",
-      "rootUri": "${toUriStr('/.pub-cache/collection')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "fixnum",
-      "rootUri": "${toUriStr('/.pub-cache/fixnum')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "foo",
-      "rootUri": "${toUriStr('/.pub-cache/foo')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "http",
-      "rootUri": "${toUriStr('/.pub-cache/http')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "meta",
-      "rootUri": "${toUriStr('/.pub-cache/meta')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "quiver",
-      "rootUri": "${toUriStr('/.pub-cache/quiver')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "test",
-      "rootUri": "${toUriStr('/.pub-cache/test')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "test_core",
-      "rootUri": "${toUriStr('/.pub-cache/test_core')}",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    },
-    {
-      "name": "tests",
-      "rootUri": "../",
-      "packageUri": "lib/",
-      "languageVersion": "2.9"
-    }
-  ],
-  "generated": "2020-10-21T21:13:05.186004Z",
-  "generator": "pub",
-  "generatorVersion": "2.10.0"
-}
-''');
-    }
-
-    createAnalysisContexts();
   }
 
   void setupResourceProvider() {}
@@ -230,33 +155,38 @@
     AnalysisEngine.instance.clearCaches();
   }
 
-  void _addTestPackageDependency(String name, String rootPath) {
-    var packagesFile = getFile('$testsPath/.packages');
-    var packagesContent = packagesFile.readAsStringSync();
-
-    // Ignore if there is already the same package dependency.
-    if (packagesContent.contains('$name:file://')) {
-      return;
-    }
-
-    packagesContent += '$name:${toUri('$rootPath/lib')}\n';
-
-    packagesFile.writeAsStringSync(packagesContent);
-
-    _createDriver();
-  }
-
-  void _createDriver() {
-    var collection = AnalysisContextCollectionImpl(
+  /// Create all analysis contexts in [_homePath].
+  void _createAnalysisContexts() {
+    var packageConfigJson = {
+      'configVersion': 2,
+      'packages': [
+        for (var packageName in knownPackages)
+          {
+            'name': packageName,
+            'rootUri': toUriStr('/.pub-cache/$packageName'),
+            'packageUri': 'lib/',
+            'languageVersion': '2.9'
+          },
+        {
+          'name': 'tests',
+          'rootUri': '../',
+          'packageUri': 'lib/',
+          'languageVersion': analyzeWithNnbd ? '2.12' : '2.9'
+        }
+      ],
+      'generated': '2020-10-21T21:13:05.186004Z',
+      'generator': 'pub',
+      'generatorVersion': '2.10.0'
+    };
+    newFile('$testsPath/.dart_tool/package_config.json',
+        content: JsonEncoder.withIndent('  ').convert(packageConfigJson));
+    _analysisContextCollection = AnalysisContextCollectionImpl(
       includedPaths: [convertPath(homePath)],
       enableIndex: true,
-      resourceProvider: resourceProvider,
+      resourceProvider: overlayResourceProvider,
       sdkPath: convertPath('/sdk'),
     );
 
-    var testPath = convertPath(testsPath);
-    var context = collection.contextFor(testPath) as DriverBasedAnalysisContext;
-
-    _driver = context.driver;
+    _driver = getDriver(convertPath(testsPath));
   }
 }
diff --git a/pkg/nnbd_migration/test/abstract_single_unit.dart b/pkg/nnbd_migration/test/abstract_single_unit.dart
index 106a6a0..a9dad66 100644
--- a/pkg/nnbd_migration/test/abstract_single_unit.dart
+++ b/pkg/nnbd_migration/test/abstract_single_unit.dart
@@ -30,13 +30,6 @@
   FindNode findNode;
   FindElement findElement;
 
-  /// Whether the test should perform analysis with NNBD enabled.
-  ///
-  /// `false` by default.  May be overridden in derived test classes.
-  ///
-  /// TODO(paulberry): once NNBD ships, this should no longer be needed.
-  bool get analyzeWithNnbd => false;
-
   void addTestSource(String code, [Uri uri]) {
     testCode = code;
     testSource = addSource(testFile, code, uri);
@@ -81,28 +74,6 @@
 environment:
   sdk: '>=2.12.0 <3.0.0'
 ''');
-      newFile('$testRoot/.dart_tool/package_config.json', content: '''
-{
-  "configVersion": 2,
-  "packages": [
-    {
-      "name": "meta",
-      "rootUri": "file:///.pub-cache/meta",
-      "packageUri": "lib/",
-      "languageVersion": "2.12"
-    },
-    {
-      "name": "tests",
-      "rootUri": "../",
-      "packageUri": "lib/",
-      "languageVersion": "2.12"
-    }
-  ],
-  "generated": "2020-10-21T21:13:05.186004Z",
-  "generator": "pub",
-  "generatorVersion": "2.12.0"
-}
-''');
     }
     super.setUp();
     testFile = convertPath('$testRoot/lib/test.dart');
diff --git a/tools/VERSION b/tools/VERSION
index 953f892..de6f628 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 12
+PRERELEASE 13
 PRERELEASE_PATCH 0
\ No newline at end of file