Version 2.18.0-47.0.dev

Merge commit 'db5d9ffc16ab057c9c8ea604562dfed35a7de405' into 'dev'
diff --git a/pkg/compiler/lib/compiler_api.dart b/pkg/compiler/lib/compiler_api.dart
index 5fd5ff1..893b07e 100644
--- a/pkg/compiler/lib/compiler_api.dart
+++ b/pkg/compiler/lib/compiler_api.dart
@@ -2,20 +2,12 @@
 // 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.
 
-// @dart = 2.10
-
 library compiler;
 
 import 'dart:async';
 
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 
-import 'src/compiler.dart' show Compiler;
-import 'src/options.dart' show CompilerOptions;
-
-// Unless explicitly allowed, passing [:null:] for any argument to the
-// methods of library will result in an Error being thrown.
-
 /// Kind of diagnostics that the compiler can report.
 class Diagnostic {
   /// An error as identified by the "Dart Programming Language
@@ -115,7 +107,7 @@
   /// scanner is more efficient in this case. In either case, the data structure
   /// is expected to hold a zero element at the last position. If this is not
   /// the case, the entire data structure is copied before scanning.
-  Future<Input> readFromUri(Uri uri, {InputKind inputKind: InputKind.UTF8});
+  Future<Input> readFromUri(Uri uri, {InputKind inputKind = InputKind.UTF8});
 }
 
 /// Output types used in `CompilerOutput.createOutputSink`.
@@ -154,7 +146,7 @@
 /// Sink interface used for generating binary data from the compiler.
 abstract class BinaryOutputSink {
   /// Writes indices [start] to [end] of [buffer] to the sink.
-  void write(List<int> buffer, [int start = 0, int end]);
+  void write(List<int> buffer, [int start = 0, int? end]);
 
   /// Closes the sink.
   void close();
@@ -193,7 +185,7 @@
   /// is the [Message] used to create the diagnostic, if available, from which
   /// the [MessageKind] is accessible.
   void report(
-      var code, Uri uri, int begin, int end, String text, Diagnostic kind);
+      var code, Uri? uri, int? begin, int? end, String text, Diagnostic kind);
 }
 
 /// Information resulting from the compilation.
@@ -211,44 +203,8 @@
   /// Shared state between compilations.
   ///
   /// This is used to speed up batch mode.
-  final fe.InitializedCompilerState kernelInitializedCompilerState;
+  final fe.InitializedCompilerState? kernelInitializedCompilerState;
 
   CompilationResult(this.compiler,
-      {this.isSuccess: true, this.kernelInitializedCompilerState: null});
-}
-
-/// Returns a future that completes to a [CompilationResult] when the Dart
-/// sources in [options] have been compiled.
-///
-/// The generated compiler output is obtained by providing a [compilerOutput].
-///
-/// If the compilation fails, the future's `CompilationResult.isSuccess` is
-/// `false` and [CompilerDiagnostics.report] on [compilerDiagnostics]
-/// is invoked at least once with `kind == Diagnostic.ERROR` or
-/// `kind == Diagnostic.CRASH`.
-Future<CompilationResult> compile(
-    CompilerOptions compilerOptions,
-    CompilerInput compilerInput,
-    CompilerDiagnostics compilerDiagnostics,
-    CompilerOutput compilerOutput) {
-  if (compilerOptions == null) {
-    throw new ArgumentError("compilerOptions must be non-null");
-  }
-  if (compilerInput == null) {
-    throw new ArgumentError("compilerInput must be non-null");
-  }
-  if (compilerDiagnostics == null) {
-    throw new ArgumentError("compilerDiagnostics must be non-null");
-  }
-  if (compilerOutput == null) {
-    throw new ArgumentError("compilerOutput must be non-null");
-  }
-
-  var compiler = Compiler(
-      compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
-  return compiler.run().then((bool success) {
-    return new CompilationResult(compiler,
-        isSuccess: success,
-        kernelInitializedCompilerState: compiler.initializedCompilerState);
-  });
+      {this.isSuccess = true, this.kernelInitializedCompilerState});
 }
diff --git a/pkg/compiler/lib/compiler_api_unmigrated.dart b/pkg/compiler/lib/compiler_api_unmigrated.dart
new file mode 100644
index 0000000..bdffbff
--- /dev/null
+++ b/pkg/compiler/lib/compiler_api_unmigrated.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+// @dart = 2.10
+
+library compiler_api_migrated;
+
+import 'dart:async';
+
+import 'src/compiler.dart' show Compiler;
+import 'src/options.dart' show CompilerOptions;
+
+import 'compiler_api.dart';
+
+// Unless explicitly allowed, passing [:null:] for any argument to the
+// methods of library will result in an Error being thrown.
+
+/// Returns a future that completes to a [CompilationResult] when the Dart
+/// sources in [options] have been compiled.
+///
+/// The generated compiler output is obtained by providing a [compilerOutput].
+///
+/// If the compilation fails, the future's `CompilationResult.isSuccess` is
+/// `false` and [CompilerDiagnostics.report] on [compilerDiagnostics]
+/// is invoked at least once with `kind == Diagnostic.ERROR` or
+/// `kind == Diagnostic.CRASH`.
+Future<CompilationResult> compile(
+    CompilerOptions compilerOptions,
+    CompilerInput compilerInput,
+    CompilerDiagnostics compilerDiagnostics,
+    CompilerOutput compilerOutput) {
+  if (compilerOptions == null) {
+    throw new ArgumentError("compilerOptions must be non-null");
+  }
+  if (compilerInput == null) {
+    throw new ArgumentError("compilerInput must be non-null");
+  }
+  if (compilerDiagnostics == null) {
+    throw new ArgumentError("compilerDiagnostics must be non-null");
+  }
+  if (compilerOutput == null) {
+    throw new ArgumentError("compilerOutput must be non-null");
+  }
+
+  var compiler = Compiler(
+      compilerInput, compilerOutput, compilerDiagnostics, compilerOptions);
+  return compiler.run().then((bool success) {
+    return new CompilationResult(compiler,
+        isSuccess: success,
+        kernelInitializedCompilerState: compiler.initializedCompilerState);
+  });
+}
diff --git a/pkg/compiler/lib/src/common.dart b/pkg/compiler/lib/src/common.dart
index aa2f28b..cb18897 100644
--- a/pkg/compiler/lib/src/common.dart
+++ b/pkg/compiler/lib/src/common.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.10
-
 /// Library that re-exports libraries used throughout the compiler regardless
 /// of phase or subfunctionality.
 library dart2js.common;
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index beb9896..6da4ba4 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -143,7 +143,7 @@
         () => NativeBehavior.readFromDataSource(source),
         emptyAsNull: true);
     Set<FunctionEntity> nativeMethods =
-        source.readMembers<FunctionEntity>(emptyAsNull: true)?.toSet();
+        source.readMembersOrNull<FunctionEntity>()?.toSet();
     Set<Selector> oneShotInterceptors = source
         .readList(() => Selector.readFromDataSource(source), emptyAsNull: true)
         ?.toSet();
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index e1fc64b..c482566 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -25,6 +25,8 @@
 import 'deferred_load/program_split_constraints/nodes.dart' as psc
     show ConstraintData;
 import 'deferred_load/program_split_constraints/parser.dart' as psc show Parser;
+import 'diagnostics/compiler_diagnostics_facade.dart'
+    show CompilerDiagnosticsFacade;
 import 'diagnostics/messages.dart' show Message;
 import 'dump_info.dart' show DumpInfoStateData, DumpInfoTask;
 import 'elements/entities.dart';
@@ -63,7 +65,7 @@
 
 /// Implementation of the compiler using  a [api.CompilerInput] for supplying
 /// the sources.
-class Compiler {
+class Compiler implements CompilerDiagnosticsFacade {
   final Measurer measurer;
   final api.CompilerInput provider;
   final api.CompilerDiagnostics handler;
@@ -76,6 +78,7 @@
   GenericTask userProviderTask;
 
   /// Options provided from command-line arguments.
+  @override // CompilerDiagnosticsFacade
   final CompilerOptions options;
 
   // These internal flags are used to stop compilation after a specific phase.
@@ -102,8 +105,6 @@
 
   final Environment environment;
 
-  Entity get currentElement => _reporter.currentElement;
-
   List<CompilerTask> tasks;
   GenericTask loadKernelTask;
   fe.InitializedCompilerState initializedCompilerState;
@@ -128,6 +129,7 @@
   static const int PHASE_COMPILING = 3;
   int phase;
 
+  @override // CompilerDiagnosticsFacade
   bool compilationFailed = false;
 
   psc.ConstraintData programSplitConstraintsData;
@@ -756,6 +758,7 @@
         'Compiled ', enqueuer.processedEntities.length, ' methods.');
   }
 
+  @override // CompilerDiagnosticsFacade
   void reportDiagnostic(DiagnosticMessage message,
       List<DiagnosticMessage> infos, api.Diagnostic kind) {
     _reportDiagnosticMessage(message, kind);
@@ -768,7 +771,7 @@
       DiagnosticMessage diagnosticMessage, api.Diagnostic kind) {
     var span = diagnosticMessage.sourceSpan;
     var message = diagnosticMessage.message;
-    if (span == null || span.uri == null) {
+    if (span.isUnknown) {
       callUserHandler(message, null, null, null, '$message', kind);
     } else {
       callUserHandler(
@@ -820,6 +823,7 @@
     return !BENIGN_ERRORS.contains(message.message.kind);
   }
 
+  @override // CompilerDiagnosticsFacade
   void fatalDiagnosticReported(DiagnosticMessage message,
       List<DiagnosticMessage> infos, api.Diagnostic kind) {
     if (markCompilationAsFailed(message, kind)) {
@@ -827,7 +831,22 @@
     }
   }
 
+  /// Compute a [SourceSpan] from spannable using the [currentElement] as
+  /// context.
+  @override // CompilerDiagnosticsFacade
+  SourceSpan spanFromSpannable(
+      Spannable spannable, Entity /*?*/ currentElement) {
+    SourceSpan span;
+    if (phase == Compiler.PHASE_COMPILING) {
+      span = backendStrategy.spanFromSpannable(spannable, currentElement);
+    } else {
+      span = frontendStrategy.spanFromSpannable(spannable, currentElement);
+    }
+    return span;
+  }
+
   /// Helper for determining whether [element] is declared within 'user code'.
+  @override // CompilerDiagnosticsFacade
   bool inUserCode(Entity element) {
     return element == null || _uriFromElement(element) != null;
   }
@@ -837,6 +856,7 @@
   /// For a package library with canonical URI 'package:foo/bar/baz.dart' the
   /// return URI is 'package:foo'. For non-package libraries the returned URI is
   /// the canonical URI of the library itself.
+  @override // CompilerDiagnosticsFacade
   Uri getCanonicalUri(Entity element) {
     Uri libraryUri = _uriFromElement(element);
     if (libraryUri == null) return null;
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index acae13d..26b15e7 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -14,6 +14,7 @@
 import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
 
 import '../compiler_api.dart' as api;
+import '../compiler_api_unmigrated.dart' as api_unmigrated;
 import 'commandline_options.dart';
 import 'options.dart' show CompilerOptions, FeatureOptions;
 import 'source_file_provider.dart';
@@ -1270,7 +1271,7 @@
 
     -O3
        Enables optimizations that respect the language semantics only on
-       programs that don't ever throw any subtype of `Error`.  These
+       programs that do not ever throw any subtype of `Error`.  These
        optimizations improve the generated code, but they may cause programs to
        behave unexpectedly if this assumption is not met.  To use this
        option, we recommend that you properly test your application first
@@ -1433,7 +1434,7 @@
     api.CompilerOutput compilerOutput);
 
 ExitFunc exitFunc = exit;
-CompileFunc compileFunc = api.compile;
+CompileFunc compileFunc = api_unmigrated.compile;
 
 /// If `true` a '.deps' file will be generated after compilation.
 ///
diff --git a/pkg/compiler/lib/src/diagnostics/compiler_diagnostics_facade.dart b/pkg/compiler/lib/src/diagnostics/compiler_diagnostics_facade.dart
new file mode 100644
index 0000000..7dcbc76
--- /dev/null
+++ b/pkg/compiler/lib/src/diagnostics/compiler_diagnostics_facade.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// 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.
+
+library dart2js.compiler_diagnostics_facade;
+
+import '../../compiler_api.dart' as api show Diagnostic;
+import '../elements/entities.dart' show Entity;
+import '../options.dart' show CompilerOptions;
+
+import 'diagnostic_listener.dart' show DiagnosticMessage;
+import 'source_span.dart';
+import 'spannable.dart';
+
+/// This interface is a subset of the [Compiler] methods that are needed by
+/// [DiagnosticListener].
+///
+/// See definitions on [Compiler] for documentation.
+// TODO(48820): Remove after compiler.dart is migrated.
+abstract class CompilerDiagnosticsFacade {
+  CompilerOptions get options;
+
+  bool inUserCode(Entity element);
+
+  Uri getCanonicalUri(Entity element);
+
+  void reportDiagnostic(DiagnosticMessage message,
+      List<DiagnosticMessage> infos, api.Diagnostic kind);
+
+  void fatalDiagnosticReported(DiagnosticMessage message,
+      List<DiagnosticMessage> infos, api.Diagnostic kind);
+
+  bool get compilationFailed;
+
+  SourceSpan spanFromSpannable(Spannable spannable, Entity? currentElement);
+}
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index 98e583a..3ccca48 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -2,26 +2,23 @@
 // 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.
 
-// @dart = 2.10
-
 library dart2js.diagnostic_listener;
 
 import '../../compiler_api.dart' as api;
-import '../compiler.dart' show Compiler;
+import 'compiler_diagnostics_facade.dart';
 import '../elements/entities.dart';
-import '../io/source_information.dart';
 import '../options.dart';
-import '../ssa/nodes.dart' show HInstruction;
 import 'messages.dart';
 import 'source_span.dart' show SourceSpan;
 import 'spannable.dart';
+import 'spannable_with_entity.dart';
 
 class DiagnosticReporter {
-  final Compiler _compiler;
+  final CompilerDiagnosticsFacade _compiler;
 
   CompilerOptions get options => _compiler.options;
 
-  Entity _currentElement;
+  Entity? _currentElement;
   bool _hasCrashed = false;
 
   /// `true` if the last diagnostic was filtered, in which case the
@@ -34,12 +31,12 @@
 
   DiagnosticReporter(this._compiler);
 
-  Entity get currentElement => _currentElement;
+  Entity? get currentElement => _currentElement;
 
   DiagnosticMessage createMessage(Spannable spannable, MessageKind messageKind,
       [Map<String, String> arguments = const {}]) {
     SourceSpan span = spanFromSpannable(spannable);
-    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind]!;
     Message message = template.message(arguments, options);
     return DiagnosticMessage(span, spannable, message);
   }
@@ -91,8 +88,8 @@
       switch (kind) {
         case api.Diagnostic.WARNING:
         case api.Diagnostic.HINT:
-          Entity element = _elementFromSpannable(message.spannable);
-          if (!_compiler.inUserCode(element)) {
+          Entity? element = _elementFromSpannable(message.spannable);
+          if (element != null && !_compiler.inUserCode(element)) {
             Uri uri = _compiler.getCanonicalUri(element);
             if (options.showPackageWarningsFor(uri)) {
               _reportDiagnostic(message, infos, kind);
@@ -139,7 +136,7 @@
   /// value from [f].  If an error occurs then report it as having occurred
   /// during compilation of [element].  Can be nested.
   dynamic withCurrentElement(Entity element, dynamic f()) {
-    Entity old = currentElement;
+    Entity? old = currentElement;
     _currentElement = element;
     try {
       return f();
@@ -176,19 +173,10 @@
         api.Diagnostic.CRASH);
   }
 
-  /// Using [frontendStrategy] to compute a [SourceSpan] from spannable using
-  /// the [currentElement] as context.
+  /// Use the compiler context [SourceSpan] from spannable using the
+  /// [currentElement] as context.
   SourceSpan _spanFromStrategy(Spannable spannable) {
-    SourceSpan span;
-    if (_compiler.phase == Compiler.PHASE_COMPILING) {
-      span = _compiler.backendStrategy
-          .spanFromSpannable(spannable, currentElement);
-    } else {
-      span = _compiler.frontendStrategy
-          .spanFromSpannable(spannable, currentElement);
-    }
-    if (span != null) return span;
-    throw 'No error location.';
+    return _compiler.spanFromSpannable(spannable, currentElement);
   }
 
   /// Creates a [SourceSpan] for [node] in scope of the current element.
@@ -197,28 +185,30 @@
   /// tokens can be found within the tokens of the current element.
   SourceSpan spanFromSpannable(Spannable spannable) {
     if (spannable == CURRENT_ELEMENT_SPANNABLE) {
-      spannable = currentElement;
+      if (currentElement == null) return SourceSpan.unknown();
+      spannable = currentElement!;
     } else if (spannable == NO_LOCATION_SPANNABLE) {
-      if (currentElement == null) return null;
-      spannable = currentElement;
+      if (currentElement == null) return SourceSpan.unknown();
+      spannable = currentElement!;
     }
     if (spannable is SourceSpan) {
       return spannable;
-    } else if (spannable is HInstruction) {
-      Entity element = spannable.sourceElement;
-      if (element == null) element = currentElement;
-      SourceInformation position = spannable.sourceInformation;
-      if (position != null) return position.sourceSpan;
-      return _spanFromStrategy(element);
-    } else {
-      return _spanFromStrategy(spannable);
     }
+    if (spannable is SpannableWithEntity) {
+      SourceSpan? span = spannable.sourceSpan;
+      if (span != null) return span;
+      Entity? element = spannable.sourceEntity ?? currentElement;
+      if (element == null) return SourceSpan.unknown();
+      return _spanFromStrategy(element);
+    }
+    return _spanFromStrategy(spannable);
   }
 
-  dynamic internalError(Spannable spannable, reason) {
+  dynamic internalError(Spannable? spannable, reason) {
     String message = tryToString(reason);
     _reportDiagnosticInternal(
-        createMessage(spannable, MessageKind.GENERIC, {'text': message}),
+        createMessage(spannable ?? SourceSpan.unknown(), MessageKind.GENERIC,
+            {'text': message}),
         const <DiagnosticMessage>[],
         api.Diagnostic.CRASH);
     throw 'Internal Error: $message';
@@ -233,27 +223,29 @@
   }
 
   void _pleaseReportCrash() {
-    print(MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+    print(MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]!
         .message({'buildId': _compiler.options.buildId}, options));
   }
 
   /// Finds the approximate [Element] for [node]. [currentElement] is used as
   /// the default value.
-  Entity _elementFromSpannable(Spannable node) {
-    Entity element;
+  Entity? _elementFromSpannable(Spannable? node) {
+    Entity? element;
     if (node is Entity) {
       element = node;
-    } else if (node is HInstruction) {
-      element = node.sourceElement;
+    } else if (node is SpannableWithEntity) {
+      element = node.sourceEntity;
     }
     return element ?? currentElement;
   }
 
   void log(message) {
-    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]!
         .message({'text': '$message'}, options);
-    _reportDiagnostic(DiagnosticMessage(null, null, msg),
-        const <DiagnosticMessage>[], api.Diagnostic.VERBOSE_INFO);
+    _reportDiagnostic(
+        DiagnosticMessage(SourceSpan.unknown(), NO_LOCATION_SPANNABLE, msg),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.VERBOSE_INFO);
   }
 
   String tryToString(object) {
@@ -264,7 +256,7 @@
     }
   }
 
-  Future onError(Uri uri, error, StackTrace stackTrace) {
+  Future onError(Uri? uri, error, StackTrace stackTrace) {
     try {
       if (!_hasCrashed) {
         _hasCrashed = true;
@@ -273,7 +265,7 @@
         } else {
           _reportDiagnostic(
               createMessage(
-                  SourceSpan(uri, 0, 0), MessageKind.COMPILER_CRASHED),
+                  SourceSpan(uri ?? Uri(), 0, 0), MessageKind.COMPILER_CRASHED),
               const <DiagnosticMessage>[],
               api.Diagnostic.CRASH);
         }
@@ -302,14 +294,17 @@
         } else if (info.hints == 0) {
           kind = MessageKind.HIDDEN_WARNINGS;
         }
-        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+        MessageTemplate template = MessageTemplate.TEMPLATES[kind]!;
         Message message = template.message({
           'warnings': info.warnings.toString(),
           'hints': info.hints.toString(),
           'uri': uri.toString(),
         }, options);
-        _reportDiagnostic(DiagnosticMessage(null, null, message),
-            const <DiagnosticMessage>[], api.Diagnostic.HINT);
+        _reportDiagnostic(
+            DiagnosticMessage(
+                SourceSpan.unknown(), NO_LOCATION_SPANNABLE, message),
+            const <DiagnosticMessage>[],
+            api.Diagnostic.HINT);
       });
     }
   }
diff --git a/pkg/compiler/lib/src/diagnostics/source_span.dart b/pkg/compiler/lib/src/diagnostics/source_span.dart
index 2b24c11..6ccbbfb 100644
--- a/pkg/compiler/lib/src/diagnostics/source_span.dart
+++ b/pkg/compiler/lib/src/diagnostics/source_span.dart
@@ -11,7 +11,14 @@
   final int begin;
   final int end;
 
-  const SourceSpan(this.uri, this.begin, this.end);
+  SourceSpan(this.uri, this.begin, this.end);
+
+  factory SourceSpan.unknown() => _unknown;
+
+  static final SourceSpan _unknown = SourceSpan(Uri(), 0, 0);
+
+  bool get isUnknown => this == _unknown;
+  bool get isKnown => !isUnknown;
 
   @override
   int get hashCode {
@@ -22,7 +29,7 @@
   bool operator ==(other) {
     if (identical(this, other)) return true;
     if (other is! SourceSpan) return false;
-    return uri == other.uri && begin == other.begin && end == other.end;
+    return begin == other.begin && end == other.end && uri == other.uri;
   }
 
   @override
diff --git a/pkg/compiler/lib/src/diagnostics/spannable_with_entity.dart b/pkg/compiler/lib/src/diagnostics/spannable_with_entity.dart
new file mode 100644
index 0000000..0bf008a
--- /dev/null
+++ b/pkg/compiler/lib/src/diagnostics/spannable_with_entity.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// 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 '../elements/entities.dart' show Entity;
+import 'source_span.dart';
+import 'spannable.dart';
+
+abstract class SpannableWithEntity implements Spannable {
+  Entity? get sourceEntity;
+  SourceSpan? get sourceSpan;
+}
diff --git a/pkg/compiler/lib/src/ir/util.dart b/pkg/compiler/lib/src/ir/util.dart
index e8d244f..1dcc687 100644
--- a/pkg/compiler/lib/src/ir/util.dart
+++ b/pkg/compiler/lib/src/ir/util.dart
@@ -29,7 +29,7 @@
   return a.fileOffset.compareTo(b.fileOffset);
 }
 
-SourceSpan? computeSourceSpanFromTreeNode(ir.TreeNode node) {
+SourceSpan computeSourceSpanFromTreeNode(ir.TreeNode node) {
   // TODO(johnniwinther): Use [ir.Location] directly as a [SourceSpan].
   Uri? uri;
   late int offset;
@@ -44,7 +44,7 @@
   if (uri != null) {
     return SourceSpan(uri, offset, offset + 1);
   }
-  return null;
+  return SourceSpan.unknown();
 }
 
 /// Returns the `AsyncMarker` corresponding to `node.asyncMarker`.
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 50c9e00..7cc6ec9 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -166,9 +166,7 @@
 
   final DiagnosticReporter reporter;
   // For error reporting only.
-  Spannable get spannable {
-    return (_spannable == null) ? NO_LOCATION_SPANNABLE : _spannable;
-  }
+  Spannable get spannable => _spannable ?? NO_LOCATION_SPANNABLE;
 
   Spannable _spannable;
 
diff --git a/pkg/compiler/lib/src/js_backend/field_analysis.dart b/pkg/compiler/lib/src/js_backend/field_analysis.dart
index 299bb33..09f6add 100644
--- a/pkg/compiler/lib/src/js_backend/field_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/field_analysis.dart
@@ -614,7 +614,7 @@
     bool isEager = source.readBool();
     int eagerCreationIndex = source.readIntOrNull();
     List<FieldEntity> eagerFieldDependencies =
-        source.readMembers<FieldEntity>(emptyAsNull: true);
+        source.readMembersOrNull<FieldEntity>();
     source.end(tag);
     return FieldAnalysisData(
         initialValue: initialValue,
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 1cb41cc..ee8f10c 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -545,12 +545,12 @@
       } else if (spannable is JLocal) {
         return getSourceSpan(spannable.memberContext, currentElement);
       }
-      return null;
+      return SourceSpan.unknown();
     }
 
     SourceSpan sourceSpan = fromSpannable(spannable);
-    sourceSpan ??= fromSpannable(currentElement);
-    return sourceSpan;
+    if (sourceSpan.isKnown) return sourceSpan;
+    return fromSpannable(currentElement);
   }
 
   LibraryEntity lookupLibrary(Uri uri) {
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index f9af7ae..c59e85e 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -161,12 +161,12 @@
       } else if (spannable is JLocal) {
         return getSourceSpan(spannable.memberContext, currentElement);
       }
-      return null;
+      return SourceSpan.unknown();
     }
 
     SourceSpan sourceSpan = fromSpannable(spannable);
-    sourceSpan ??= fromSpannable(currentElement);
-    return sourceSpan;
+    if (sourceSpan.isKnown) return sourceSpan;
+    return fromSpannable(currentElement);
   }
 
   LibraryEntity lookupLibrary(Uri uri) {
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index b796cc4..3d34dce 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -899,7 +899,7 @@
   }
 
   /// Reads a reference to an indexed member from this data source.
-  IndexedMember readMember() {
+  IndexedMember /*!*/ readMember() {
     return _entityReader.readMemberFromDataSource(this, entityLookup);
   }
 
@@ -914,15 +914,24 @@
   }
 
   /// Reads a list of references to indexed members from this data source.
-  /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
   ///
   /// This is a convenience method to be used together with
   /// [DataSinkWriter.writeMembers].
-  List<E> readMembers<E extends MemberEntity>({bool emptyAsNull = false}) {
+  List<E /*!*/ > readMembers<E extends MemberEntity /*!*/ >() {
+    return readMembersOrNull() ?? List.empty();
+  }
+
+  /// Reads a list of references to indexed members from this data source.
+  /// `null` is returned instead of an empty list.
+  ///
+  /// This is a convenience method to be used together with
+  /// [DataSinkWriter.writeMembers].
+  List<E /*!*/ > readMembersOrNull<E extends MemberEntity /*!*/ >() {
     int count = readInt();
-    if (count == 0 && emptyAsNull) return null;
-    List<E> list = List<E>.filled(count, null);
-    for (int i = 0; i < count; i++) {
+    if (count == 0) return null;
+    MemberEntity firstMember = readMember();
+    List<E> list = List<E>.filled(count, firstMember);
+    for (int i = 1; i < count; i++) {
       MemberEntity member = readMember();
       list[i] = member;
     }
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 6e8e464..3a96d59 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -11,6 +11,7 @@
 import '../common/elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
+import '../diagnostics/spannable_with_entity.dart';
 import '../elements/entities.dart';
 import '../elements/jumps.dart';
 import '../elements/types.dart';
@@ -1037,7 +1038,7 @@
   toString() => 'HBasicBlock($id)';
 }
 
-abstract class HInstruction implements Spannable {
+abstract class HInstruction implements SpannableWithEntity {
   Entity sourceElement;
   SourceInformation sourceInformation;
 
@@ -1120,6 +1121,12 @@
   }
 
   @override
+  Entity /*?*/ get sourceEntity => sourceElement;
+
+  @override
+  SourceSpan /*?*/ get sourceSpan => sourceInformation?.sourceSpan;
+
+  @override
   int get hashCode => id;
 
   bool useGvn() => _useGvn;
diff --git a/pkg/dart2wasm/bin/dart2wasm.dart b/pkg/dart2wasm/bin/dart2wasm.dart
index 19b9604..6a77001 100644
--- a/pkg/dart2wasm/bin/dart2wasm.dart
+++ b/pkg/dart2wasm/bin/dart2wasm.dart
@@ -13,6 +13,7 @@
 
 final Map<String, void Function(TranslatorOptions, bool)> boolOptionMap = {
   "export-all": (o, value) => o.exportAll = value,
+  "import-shared-memory": (o, value) => o.importSharedMemory = value,
   "inlining": (o, value) => o.inlining = value,
   "lazy-constants": (o, value) => o.lazyConstants = value,
   "local-nullability": (o, value) => o.localNullability = value,
@@ -27,6 +28,7 @@
   "string-data-segments": (o, value) => o.stringDataSegments = value,
 };
 final Map<String, void Function(TranslatorOptions, int)> intOptionMap = {
+  "shared-memory-max-pages": (o, value) => o.sharedMemoryMaxPages = value,
   "watch": (o, value) => (o.watchPoints ??= []).add(value),
 };
 
@@ -83,6 +85,11 @@
     usage("Missing argument to ${args.last}");
   }
 
+  if (options.importSharedMemory && options.sharedMemoryMaxPages == null) {
+    usage("--shared-memory-max-pages must be "
+        "specified if --import-shared-memory is used.");
+  }
+
   if (nonOptions.length != 2) usage("Requires two file arguments");
   String input = nonOptions[0];
   String output = nonOptions[1];
diff --git a/pkg/dart2wasm/dart2wasm.md b/pkg/dart2wasm/dart2wasm.md
index bfc2d47..8cc6b91 100644
--- a/pkg/dart2wasm/dart2wasm.md
+++ b/pkg/dart2wasm/dart2wasm.md
@@ -12,6 +12,7 @@
 | --------------------------------------- | ------- | ----------- |
 | `--dart-sdk=`*path*                     | relative to script | The location of the `sdk` directory inside the Dart SDK, containing the core library sources.
 | `--`[`no-`]`export-all`                 | no      | Export all functions; otherwise, just export `main`.
+| `--`[`no-`]`import-shared-memory`       | no      | Import a shared memory buffer. If this is on, `--shared-memory-max-pages` must also be specified.
 | `--`[`no-`]`inlining`                   | no      | Inline small functions.
 | `--`[`no-`]`lazy-constants`             | no      | Instantiate constants lazily.
 | `--`[`no-`]`local-nullability`          | no      | Use non-nullable types for non-nullable locals and temporaries.
@@ -22,6 +23,7 @@
 | `--`[`no-`]`print-kernel`               | no      | Print IR for each function before compiling it.
 | `--`[`no-`]`print-wasm`                 | no      | Print Wasm instructions of each compiled function.
 | `--`[`no-`]`runtime-types`              | no      | Use RTTs for allocations and casts.
+| `--shared-memory-max-pages` *pagecount* |         | Max size of the imported memory buffer. If `--shared-import-memory` is specified, this must also be specified.
 | `--`[`no-`]`string-data-segments`       | no      | Use experimental array init from data segment for string constants.
 | `--watch` *offset*                      |         | Print stack trace leading to the byte at offset *offset* in the `.wasm` output file. Can be specified multiple times.
 
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 4440b45..2744ea7 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -175,7 +175,7 @@
         .toBytes();
 
     w.Memory stringMemory =
-        m.addMemory(stringsAsBytes.length, stringsAsBytes.length);
+        m.addMemory(false, stringsAsBytes.length, stringsAsBytes.length);
     m.addDataSegment(stringsAsBytes, stringMemory, 0);
     makeStringFunctionBody(translator.oneByteStringClass, oneByteStringFunction,
         (b) {
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 2a61d3c..ecb5a41 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -27,6 +27,7 @@
 /// Options controlling the translation.
 class TranslatorOptions {
   bool exportAll = false;
+  bool importSharedMemory = false;
   bool inlining = false;
   int inliningLimit = 3;
   bool lazyConstants = false;
@@ -38,6 +39,7 @@
   bool printKernel = false;
   bool printWasm = false;
   bool runtimeTypes = false;
+  int? sharedMemoryMaxPages;
   bool stringDataSegments = false;
   List<int>? watchPoints = null;
 
@@ -127,7 +129,8 @@
   // Lazily create exception tag if used.
   late final w.Tag exceptionTag = createExceptionTag();
   // Lazily import FFI memory if used.
-  late final w.Memory ffiMemory = m.importMemory("ffi", "memory", 0);
+  late final w.Memory ffiMemory = m.importMemory("ffi", "memory",
+      options.importSharedMemory, 0, options.sharedMemoryMaxPages);
 
   // Caches for when identical source constructs need a common representation.
   final Map<w.StorageType, w.ArrayType> arrayTypeCache = {};
diff --git a/pkg/wasm_builder/lib/src/module.dart b/pkg/wasm_builder/lib/src/module.dart
index 2e03919..f75618e 100644
--- a/pkg/wasm_builder/lib/src/module.dart
+++ b/pkg/wasm_builder/lib/src/module.dart
@@ -130,9 +130,9 @@
   }
 
   /// Add a new memory to the module.
-  DefinedMemory addMemory(int minSize, [int? maxSize]) {
+  DefinedMemory addMemory(bool shared, int minSize, [int? maxSize]) {
     anyMemoriesDefined = true;
-    final memory = DefinedMemory(memories.length, minSize, maxSize);
+    final memory = DefinedMemory(memories.length, shared, minSize, maxSize);
     memories.add(memory);
     return memory;
   }
@@ -195,13 +195,14 @@
   ///
   /// All imported memories must be specified before any memories are declared
   /// using [Module.addMemory].
-  ImportedMemory importMemory(String module, String name, int minSize,
+  ImportedMemory importMemory(
+      String module, String name, bool shared, int minSize,
       [int? maxSize]) {
     if (anyMemoriesDefined) {
       throw "All memory imports must be specified before any definitions.";
     }
     final memory =
-        ImportedMemory(module, name, memories.length, minSize, maxSize);
+        ImportedMemory(module, name, memories.length, shared, minSize, maxSize);
     memories.add(memory);
     return memory;
   }
@@ -410,13 +411,23 @@
 /// A memory in a module.
 class Memory {
   final int index;
+  final bool shared;
   final int minSize;
   final int? maxSize;
 
-  Memory(this.index, this.minSize, [this.maxSize]);
+  Memory(this.index, this.shared, this.minSize, [this.maxSize]) {
+    if (shared && maxSize == null) {
+      throw "Shared memory must specify a maximum size.";
+    }
+  }
 
   void _serializeLimits(Serializer s) {
-    if (maxSize == null) {
+    if (shared) {
+      assert(maxSize != null);
+      s.writeByte(0x03);
+      s.writeUnsigned(minSize);
+      s.writeUnsigned(maxSize!);
+    } else if (maxSize == null) {
       s.writeByte(0x00);
       s.writeUnsigned(minSize);
     } else {
@@ -428,8 +439,8 @@
 }
 
 class DefinedMemory extends Memory implements Serializable {
-  DefinedMemory(int index, int minSize, int? maxSize)
-      : super(index, minSize, maxSize);
+  DefinedMemory(int index, bool shared, int minSize, int? maxSize)
+      : super(index, shared, minSize, maxSize);
 
   @override
   void serialize(Serializer s) => _serializeLimits(s);
@@ -556,8 +567,9 @@
   final String module;
   final String name;
 
-  ImportedMemory(this.module, this.name, int index, int minSize, int? maxSize)
-      : super(index, minSize, maxSize);
+  ImportedMemory(
+      this.module, this.name, int index, bool shared, int minSize, int? maxSize)
+      : super(index, shared, minSize, maxSize);
 
   @override
   void serialize(Serializer s) {
diff --git a/tests/lib/wasm/fn_import_error_test.dart b/tests/lib/wasm/fn_import_error_test.dart
index aeca278..8e4aa00 100644
--- a/tests/lib/wasm/fn_import_error_test.dart
+++ b/tests/lib/wasm/fn_import_error_test.dart
@@ -38,7 +38,7 @@
 
   // Wrong kind of import.
   Expect.throws(
-      () => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)),
+      () => mod.instantiate().addMemory(false, "env", "someFn", mod.createMemory(10)),
       (Exception e) => "$e".contains("Import is not a memory"));
 
   // Wrong namespace.
diff --git a/tests/lib_2/wasm/fn_import_error_test.dart b/tests/lib_2/wasm/fn_import_error_test.dart
index b15a1be..c99054c 100644
--- a/tests/lib_2/wasm/fn_import_error_test.dart
+++ b/tests/lib_2/wasm/fn_import_error_test.dart
@@ -40,7 +40,7 @@
 
   // Wrong kind of import.
   Expect.throws(
-      () => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)),
+      () => mod.instantiate().addMemory(false, "env", "someFn", mod.createMemory(10)),
       (Exception e) => "$e".contains("Import is not a memory"));
 
   // Wrong namespace.
diff --git a/tools/VERSION b/tools/VERSION
index 401b5ca..b523152 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 46
+PRERELEASE 47
 PRERELEASE_PATCH 0
\ No newline at end of file