Version 2.14.0-330.0.dev

Merge commit '55c5e3b680b08c14f7b915d762138fb14c678393' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index c7726fb..4743b03 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 161;
+  static const int DATA_VERSION = 162;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 740d067..4c232e6 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -969,6 +969,13 @@
   @override
   LineInfo? lineInfo;
 
+  /// The path of the file which is derived from the [source], and in addition
+  /// to source declarations contains also declarations added by running
+  /// macro(s).
+  ///
+  /// Might be `null` if there is no corresponding macro-produced file.
+  String? macroPath;
+
   /// The source of the library containing this compilation unit.
   ///
   /// This is the same as the source of the containing [LibraryElement],
@@ -2361,6 +2368,16 @@
   /// children of this element's parent.
   String get identifier => name!;
 
+  /// Return `true` if this element was created from a declaration that
+  /// exists in a macro-generated code, but not in the source code.
+  bool get isFromMacro {
+    return hasModifier(Modifier.IS_FROM_MACRO);
+  }
+
+  set isFromMacro(bool isFromMacro) {
+    setModifier(Modifier.IS_FROM_MACRO, isFromMacro);
+  }
+
   bool get isNonFunctionTypeAliasesEnabled {
     return library!.featureSet.isEnabled(Feature.nonfunction_type_aliases);
   }
@@ -4281,23 +4298,26 @@
   /// type being referred to is the return type.
   static const Modifier IMPLICIT_TYPE = Modifier('IMPLICIT_TYPE', 16);
 
+  /// Indicates that this element was created from macro-generated code.
+  static const Modifier IS_FROM_MACRO = Modifier('IS_FROM_MACRO', 17);
+
   /// Indicates that modifier 'lazy' was applied to the element.
-  static const Modifier LATE = Modifier('LATE', 17);
+  static const Modifier LATE = Modifier('LATE', 18);
 
   /// Indicates that a class is a mixin application.
-  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 18);
+  static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19);
 
   /// Indicates that the pseudo-modifier 'set' was applied to the element.
-  static const Modifier SETTER = Modifier('SETTER', 19);
+  static const Modifier SETTER = Modifier('SETTER', 20);
 
   /// Indicates that the modifier 'static' was applied to the element.
-  static const Modifier STATIC = Modifier('STATIC', 20);
+  static const Modifier STATIC = Modifier('STATIC', 21);
 
   /// Indicates that the element does not appear in the source code but was
   /// implicitly created. For example, if a class does not define any
   /// constructors, an implicit zero-argument constructor will be created and it
   /// will be marked as being synthetic.
-  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 21);
+  static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 22);
 
   static const List<Modifier> values = [
     ABSTRACT,
@@ -4316,6 +4336,7 @@
     HAS_INITIALIZER,
     HAS_PART_OF_DIRECTIVE,
     IMPLICIT_TYPE,
+    IS_FROM_MACRO,
     LATE,
     MIXIN_APPLICATION,
     SETTER,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index cccbbb3..dd65232 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -31,6 +31,7 @@
 class BundleReader {
   final SummaryDataReader _reader;
   final Map<Uri, Uint8List> _unitsInformativeBytes;
+  final Map<Uri, Uint8List> _macroUnitsInformativeBytes;
 
   final Map<String, LibraryReader> libraryMap = {};
 
@@ -38,8 +39,10 @@
     required LinkedElementFactory elementFactory,
     required Uint8List resolutionBytes,
     Map<Uri, Uint8List> unitsInformativeBytes = const {},
+    Map<Uri, Uint8List> macroUnitsInformativeBytes = const {},
   })  : _reader = SummaryDataReader(resolutionBytes),
-        _unitsInformativeBytes = unitsInformativeBytes {
+        _unitsInformativeBytes = unitsInformativeBytes,
+        _macroUnitsInformativeBytes = macroUnitsInformativeBytes {
     _reader.offset = _reader.bytes.length - 4 * 4;
     var baseResolutionOffset = _reader.readUInt32();
     var librariesOffset = _reader.readUInt32();
@@ -70,6 +73,7 @@
         elementFactory: elementFactory,
         reader: _reader,
         unitsInformativeBytes: _unitsInformativeBytes,
+        macroUnitsInformativeBytes: _macroUnitsInformativeBytes,
         baseResolutionOffset: baseResolutionOffset,
         referenceReader: referenceReader,
         reference: reference,
@@ -84,6 +88,7 @@
   ApplyConstantOffsets? applyConstantOffsets;
   void Function()? _readMembers;
   void Function()? applyInformativeDataToMembers;
+  void Function()? applyInformativeDataToMacroMembers;
 
   ClassElementLinkedData({
     required Reference reference,
@@ -106,6 +111,9 @@
 
       applyInformativeDataToMembers?.call();
       applyInformativeDataToMembers = null;
+
+      applyInformativeDataToMacroMembers?.call();
+      applyInformativeDataToMacroMembers = null;
     }
   }
 
@@ -416,6 +424,7 @@
   final LinkedElementFactory _elementFactory;
   final SummaryDataReader _reader;
   final Map<Uri, Uint8List> _unitsInformativeBytes;
+  final Map<Uri, Uint8List> _macroUnitsInformativeBytes;
   final int _baseResolutionOffset;
   final _ReferenceReader _referenceReader;
   final Reference _reference;
@@ -430,6 +439,7 @@
     required LinkedElementFactory elementFactory,
     required SummaryDataReader reader,
     required Map<Uri, Uint8List> unitsInformativeBytes,
+    required Map<Uri, Uint8List> macroUnitsInformativeBytes,
     required int baseResolutionOffset,
     required _ReferenceReader referenceReader,
     required Reference reference,
@@ -438,6 +448,7 @@
   })  : _elementFactory = elementFactory,
         _reader = reader,
         _unitsInformativeBytes = unitsInformativeBytes,
+        _macroUnitsInformativeBytes = macroUnitsInformativeBytes,
         _baseResolutionOffset = baseResolutionOffset,
         _referenceReader = referenceReader,
         _reference = reference,
@@ -496,6 +507,10 @@
     InformativeDataApplier(_elementFactory, _unitsInformativeBytes)
         .applyTo(libraryElement);
 
+    InformativeDataApplier(_elementFactory, _macroUnitsInformativeBytes,
+            onlyIfFromMacro: true)
+        .applyTo(libraryElement);
+
     return libraryElement;
   }
 
@@ -1208,6 +1223,7 @@
     unitElement.uri = _reader.readOptionalStringReference();
     unitElement.isSynthetic = _reader.readBool();
     unitElement.sourceContent = _reader.readOptionalStringUtf8();
+    unitElement.macroPath = _reader.readOptionalStringUtf8();
 
     _readClasses(unitElement, unitReference);
     _readEnums(unitElement, unitReference);
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 528b9d2..cb33459 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -441,6 +441,7 @@
     _sink._writeOptionalStringReference(unitElement.uri);
     _sink.writeBool(unitElement.isSynthetic);
     _sink.writeOptionalStringUtf8(unitElement.sourceContent);
+    _sink.writeOptionalStringUtf8(unitElement.macroPath);
     _resolutionSink._writeAnnotationList(unitElement.metadata);
     _writeList(unitElement.classes, _writeClassElement);
     _writeList(unitElement.enums, _writeEnumElement);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 3737f6e..2d5d9c2 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -56,6 +56,21 @@
     _unitElement.typeAliases = _enclosingContext.typeAliases;
   }
 
+  void buildDeclarationElementsMacro(CompilationUnit? unit) {
+    if (unit == null) {
+      return;
+    }
+
+    _visitPropertyFirst<TopLevelVariableDeclaration>(unit.declarations);
+
+    _unitElement.classes = _mergeElements(
+      _unitElement.classes,
+      _enclosingContext.classes,
+    );
+
+    // TODO(scheglov) other top-level elements
+  }
+
   /// Build exports and imports, metadata into [_libraryElement].
   void buildLibraryElementChildren(CompilationUnit unit) {
     unit.directives.accept(this);
@@ -972,6 +987,41 @@
     node?.accept(this);
   }
 
+  /// Return a new list that includes [sourceElements] plus elements
+  /// with not yet existing names from [macroElements].
+  List<T> _mergeElements<T extends Element>(
+    List<T> sourceElements,
+    List<T> macroElements,
+  ) {
+    var result = <T>[];
+
+    var sourceMap = <String, T>{};
+    for (var element in sourceElements) {
+      var name = element.name;
+      if (name != null) {
+        result.add(element);
+        sourceMap[name] = element;
+      }
+    }
+
+    for (var element in macroElements) {
+      var sourceElement = sourceMap[element.name];
+      if (sourceElement == null) {
+        (element as ElementImpl).isFromMacro = true;
+        result.add(element);
+      } else if (sourceElement is ClassElementImpl &&
+          element is ClassElementImpl) {
+        sourceElement.methods = _mergeElements(
+          sourceElement.methods,
+          element.methods,
+        );
+      }
+      // TODO(scheglov) Other class members.
+    }
+
+    return result;
+  }
+
   Uri? _selectAbsoluteUri(NamespaceDirective directive) {
     var relativeUriStr = _selectRelativeUri(
       directive.configurations,
diff --git a/pkg/analyzer/lib/src/summary2/element_flags.dart b/pkg/analyzer/lib/src/summary2/element_flags.dart
index e808000..a2bce77 100644
--- a/pkg/analyzer/lib/src/summary2/element_flags.dart
+++ b/pkg/analyzer/lib/src/summary2/element_flags.dart
@@ -8,12 +8,14 @@
 
 class ClassElementFlags {
   static const int _isAbstract = 1 << 0;
-  static const int _isMixinApplication = 1 << 1;
-  static const int _isSimplyBounded = 1 << 2;
+  static const int _isFromMacro = 1 << 1;
+  static const int _isMixinApplication = 1 << 2;
+  static const int _isSimplyBounded = 1 << 3;
 
   static void read(SummaryDataReader reader, ClassElementImpl element) {
     var byte = reader.readByte();
     element.isAbstract = (byte & _isAbstract) != 0;
+    element.isFromMacro = (byte & _isFromMacro) != 0;
     element.isMixinApplication = (byte & _isMixinApplication) != 0;
     element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
   }
@@ -21,6 +23,7 @@
   static void write(BufferedSink sink, ClassElementImpl element) {
     var result = 0;
     result |= element.isAbstract ? _isAbstract : 0;
+    result |= element.isFromMacro ? _isFromMacro : 0;
     result |= element.isMixinApplication ? _isMixinApplication : 0;
     result |= element.isSimplyBounded ? _isSimplyBounded : 0;
     sink.writeByte(result);
@@ -161,8 +164,9 @@
   static const int _isAbstract = 1 << 1;
   static const int _isAsynchronous = 1 << 2;
   static const int _isExternal = 1 << 3;
-  static const int _isGenerator = 1 << 4;
-  static const int _isStatic = 1 << 5;
+  static const int _isFromMacro = 1 << 4;
+  static const int _isGenerator = 1 << 5;
+  static const int _isStatic = 1 << 6;
 
   static void read(SummaryDataReader reader, MethodElementImpl element) {
     var byte = reader.readByte();
@@ -170,6 +174,7 @@
     element.isAbstract = (byte & _isAbstract) != 0;
     element.isAsynchronous = (byte & _isAsynchronous) != 0;
     element.isExternal = (byte & _isExternal) != 0;
+    element.isFromMacro = (byte & _isFromMacro) != 0;
     element.isGenerator = (byte & _isGenerator) != 0;
     element.isStatic = (byte & _isStatic) != 0;
   }
@@ -180,6 +185,7 @@
     result |= element.isAbstract ? _isAbstract : 0;
     result |= element.isAsynchronous ? _isAsynchronous : 0;
     result |= element.isExternal ? _isExternal : 0;
+    result |= element.isFromMacro ? _isFromMacro : 0;
     result |= element.isGenerator ? _isGenerator : 0;
     result |= element.isStatic ? _isStatic : 0;
     sink.writeByte(result);
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 1dd1e5f..fda2dbc 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -55,12 +55,16 @@
 
 class InformativeDataApplier {
   final LinkedElementFactory _elementFactory;
-  final Map<Uri, Uint8List> _unitsInformativeBytes2;
+  final Map<Uri, Uint8List> _unitsInformativeBytes;
+
+  /// Apply only to elements that are from macro-generated code.
+  final bool _onlyIfFromMacro;
 
   InformativeDataApplier(
     this._elementFactory,
-    this._unitsInformativeBytes2,
-  );
+    this._unitsInformativeBytes, {
+    bool onlyIfFromMacro = false,
+  }) : _onlyIfFromMacro = onlyIfFromMacro;
 
   void applyTo(LibraryElementImpl libraryElement) {
     if (_elementFactory.isApplyingInformativeData) {
@@ -72,7 +76,7 @@
     for (var i = 0; i < unitElements.length; i++) {
       var unitElement = unitElements[i] as CompilationUnitElementImpl;
       var unitUri = unitElement.source.uri;
-      var unitInfoBytes = _unitsInformativeBytes2[unitUri];
+      var unitInfoBytes = _unitsInformativeBytes[unitUri];
       if (unitInfoBytes != null) {
         var unitReader = SummaryDataReader(unitInfoBytes);
         var unitInfo = _InfoUnit(unitReader);
@@ -177,28 +181,37 @@
     _InfoClassDeclaration info,
   ) {
     element as ClassElementImpl;
-    element.setCodeRange(info.codeOffset, info.codeLength);
-    element.nameOffset = info.nameOffset;
-    element.documentationComment = info.documentationComment;
-    _applyToTypeParameters(
-      element.typeParameters_unresolved,
-      info.typeParameters,
-    );
-
     var linkedData = element.linkedData as ClassElementLinkedData;
-    linkedData.applyConstantOffsets = ApplyConstantOffsets(
-      info.constantOffsets,
-      (applier) {
-        applier.applyToMetadata(element);
-        applier.applyToTypeParameters(element.typeParameters);
-      },
-    );
-    linkedData.applyInformativeDataToMembers = () {
-      _applyToConstructors(element.constructors, info.constructors);
-      _applyToFields(element.fields, info.fields);
-      _applyToAccessors(element.accessors, info.accessors);
-      _applyToMethods(element.methods, info.methods);
-    };
+    if (_shouldApply(element)) {
+      element.setCodeRange(info.codeOffset, info.codeLength);
+      element.nameOffset = info.nameOffset;
+      element.documentationComment = info.documentationComment;
+      _applyToTypeParameters(
+        element.typeParameters_unresolved,
+        info.typeParameters,
+      );
+
+      linkedData.applyConstantOffsets = ApplyConstantOffsets(
+        info.constantOffsets,
+        (applier) {
+          applier.applyToMetadata(element);
+          applier.applyToTypeParameters(element.typeParameters);
+        },
+      );
+      linkedData.applyInformativeDataToMembers = () {
+        _applyToConstructors(element.constructors, info.constructors);
+        _applyToFields(element.fields, info.fields);
+        _applyToAccessors(element.accessors, info.accessors);
+        _applyToMethods(element.methods, info.methods);
+      };
+    } else {
+      linkedData.applyInformativeDataToMacroMembers = () {
+        _applyToConstructors(element.constructors, info.constructors);
+        _applyToFields(element.fields, info.fields);
+        _applyToAccessors(element.accessors, info.accessors);
+        _applyToMethods(element.methods, info.methods);
+      };
+    }
   }
 
   void _applyToClassTypeAlias(
@@ -508,6 +521,10 @@
       infoList,
       (element, info) {
         element as MethodElementImpl;
+        if (!_shouldApply(element)) {
+          return;
+        }
+
         element.setCodeRange(info.codeOffset, info.codeLength);
         element.nameOffset = info.nameOffset;
         element.documentationComment = info.documentationComment;
@@ -627,6 +644,10 @@
       },
     );
   }
+
+  bool _shouldApply(ElementImpl element) {
+    return !_onlyIfFromMacro || element.isFromMacro;
+  }
 }
 
 class _InfoClassDeclaration {
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index 2c1a0b3..3340f8a 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -110,6 +110,12 @@
         elementBuilder.buildLibraryElementChildren(linkingUnit.node);
       }
       elementBuilder.buildDeclarationElements(linkingUnit.node);
+
+      ElementBuilder(
+        libraryBuilder: this,
+        unitReference: linkingUnit.reference,
+        unitElement: linkingUnit.element,
+      ).buildDeclarationElementsMacro(linkingUnit.macroNode);
     }
     if ('$uri' == 'dart:core') {
       localScope.declare('dynamic', reference.getChild('dynamic'));
@@ -171,6 +177,7 @@
         linkingUnit.node.featureSet.isEnabled(Feature.non_nullable),
       );
       linkingUnit.node.accept(resolver);
+      linkingUnit.macroNode?.accept(resolver);
     }
   }
 
@@ -236,6 +243,7 @@
     var linkingUnits = <LinkingUnit>[];
     for (var inputUnit in inputLibrary.units) {
       var unitNode = inputUnit.unit as ast.CompilationUnitImpl;
+      var unitMacroNode = inputUnit.macro?.unit as ast.CompilationUnitImpl?;
 
       var unitElement = CompilationUnitElementImpl();
       unitElement.isSynthetic = inputUnit.isSynthetic;
@@ -243,6 +251,7 @@
       unitElement.lineInfo = unitNode.lineInfo;
       unitElement.source = inputUnit.source;
       unitElement.sourceContent = inputUnit.sourceContent;
+      unitElement.macroPath = inputUnit.macro?.path;
       unitElement.uri = inputUnit.partUriStr;
       unitElement.setCodeRange(0, unitNode.length);
 
@@ -256,6 +265,7 @@
           isDefiningUnit: isDefiningUnit,
           reference: unitReference,
           node: unitNode,
+          macroNode: unitMacroNode,
           element: unitElement,
         ),
       );
@@ -287,6 +297,7 @@
   final bool isDefiningUnit;
   final Reference reference;
   final ast.CompilationUnitImpl node;
+  final ast.CompilationUnitImpl? macroNode;
   final CompilationUnitElementImpl element;
 
   LinkingUnit({
@@ -294,6 +305,7 @@
     required this.isDefiningUnit,
     required this.reference,
     required this.node,
+    required this.macroNode,
     required this.element,
   });
 }
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index f0b0174..3b51acc 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -251,6 +251,7 @@
   final String? sourceContent;
   final bool isSynthetic;
   final ast.CompilationUnit unit;
+  final LinkInputUnitMacro? macro;
 
   LinkInputUnit({
     required this.partDirectiveIndex,
@@ -259,6 +260,7 @@
     this.sourceContent,
     required this.isSynthetic,
     required this.unit,
+    this.macro,
   });
 
   Uri get uri => source.uri;
@@ -266,6 +268,19 @@
   String get uriStr => '$uri';
 }
 
+class LinkInputUnitMacro {
+  /// The path of the file that was parsed into [unit].
+  /// We don't need complete [Source] because this file does not have a
+  /// separate [Uri], it is a reflection of the source file.
+  final String path;
+  final ast.CompilationUnit unit;
+
+  LinkInputUnitMacro({
+    required this.path,
+    required this.unit,
+  });
+}
+
 class LinkResult {
   @Deprecated('This field is not used anymore')
   final Uint8List astBytes = Uint8List(0);
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 4243b45..61f9169 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -269,6 +269,7 @@
 
   void _writeClassElement(ClassElement e) {
     _writeIndentedLine(() {
+      _writeFromMacro(e);
       _writeIf(e.isAbstract && !e.isMixin, 'abstract ');
       _writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
 
@@ -470,6 +471,10 @@
     _assertNonSyntheticElementSelf(e);
   }
 
+  void _writeFromMacro(Element e) {
+    _writeIf((e as ElementImpl).isFromMacro, 'fromMacro ');
+  }
+
   void _writeFunctionElement(FunctionElement e) {
     _writeIndentedLine(() {
       _writeIf(e.isExternal, 'external ');
@@ -541,6 +546,7 @@
 
   void _writeMethodElement(MethodElement e) {
     _writeIndentedLine(() {
+      _writeFromMacro(e);
       _writeIf(e.isSynthetic, 'synthetic ');
       _writeIf(e.isStatic, 'static ');
       _writeIf(e.isAbstract, 'abstract ');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 3a95b46..2466ab4 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -100,10 +100,17 @@
     _addNonDartLibraries({}, inputLibraries, source);
 
     var unitsInformativeBytes = <Uri, Uint8List>{};
+    var macroUnitsInformativeBytes = <Uri, Uint8List>{};
     for (var inputLibrary in inputLibraries) {
       for (var inputUnit in inputLibrary.units) {
         var informativeBytes = writeUnitInformative(inputUnit.unit);
         unitsInformativeBytes[inputUnit.uri] = informativeBytes;
+
+        var macroUnit = inputUnit.macro?.unit;
+        if (macroUnit != null) {
+          var informativeBytes = writeUnitInformative(macroUnit);
+          macroUnitsInformativeBytes[inputUnit.uri] = informativeBytes;
+        }
       }
     }
 
@@ -138,6 +145,7 @@
         BundleReader(
           elementFactory: elementFactory,
           unitsInformativeBytes: unitsInformativeBytes,
+          macroUnitsInformativeBytes: macroUnitsInformativeBytes,
           resolutionBytes: linkResult.resolutionBytes,
         ),
       );
@@ -156,12 +164,31 @@
     List<LinkInputUnit> units,
     FeatureSet featureSet,
   ) {
+    LinkInputUnitMacro? definingUnitMacro;
+    {
+      var macroSource = sourceFactory.resolveUri(
+        definingSource,
+        definingSource.shortName.replaceAll('.dart', '.macro_dart'),
+      );
+      var macroPath = macroSource?.fullName;
+      if (macroPath != null) {
+        var text = _readSafely(macroPath);
+        if (text.isNotEmpty) {
+          definingUnitMacro = LinkInputUnitMacro(
+            path: macroPath,
+            unit: parseText(text, featureSet),
+          );
+        }
+      }
+    }
+
     units.add(
       LinkInputUnit(
         partDirectiveIndex: null,
         source: definingSource,
         isSynthetic: false,
         unit: definingUnit,
+        macro: definingUnitMacro,
       ),
     );
 
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 3859042..fe2372d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -21246,6 +21246,96 @@
 ''');
   }
 
+  test_macro_addClass() async {
+    newFile('/test.macro_dart', content: r'''
+class A {}
+class B {}
+''');
+    var library = await checkLibrary('''
+class A {}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          synthetic @-1
+      fromMacro class B @17
+        constructors
+          synthetic @-1
+''');
+    _assertMacroPath(
+      library.definingCompilationUnit,
+      convertPath('/test.macro_dart'),
+    );
+  }
+
+  test_macro_addToClass_addMethod() async {
+    newFile('/test.macro_dart', content: r'''
+class A {
+  void foo() {}
+  void bar(int a) {}
+}
+''');
+    var library = await checkLibrary('''
+class A {
+  void foo() {}
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          synthetic @-1
+        methods
+          foo @17
+            returnType: void
+          fromMacro bar @33
+            parameters
+              requiredPositional a @41
+                type: int
+            returnType: void
+''');
+  }
+
+  test_macro_addToClass_addMethod_offsets() async {
+    newFile('/test.macro_dart', content: r'''
+class A {
+  void foo() {}
+  void bar(int a) {}
+}
+''');
+    var library = await checkLibrary('''
+/// shift
+class A {
+  void foo() {}
+}
+''');
+    // The source code has an additional comment, and offsets of the
+    // elements that are declared in the source correspond to the state
+    // of the source code, not a (slightly) out of date macro-generated code.
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @16
+        documentationComment: /// shift
+        constructors
+          synthetic @-1
+        methods
+          foo @27
+            returnType: void
+          fromMacro bar @33
+            parameters
+              requiredPositional a @41
+                type: int
+            returnType: void
+''');
+  }
+
   test_main_class() async {
     var library = await checkLibrary('class main {}');
     checkElementText(library, r'''
@@ -33578,6 +33668,11 @@
 ''');
   }
 
+  void _assertMacroPath(CompilationUnitElement unitElement, String expected) {
+    unitElement as CompilationUnitElementImpl;
+    expect(unitElement.macroPath, expected);
+  }
+
   void _assertTypeStr(DartType type, String expected) {
     var typeStr = type.getDisplayString(withNullability: true);
     expect(typeStr, expected);
diff --git a/pkg/compiler/lib/src/elements/entity_utils.dart b/pkg/compiler/lib/src/elements/entity_utils.dart
index 82be8db..2942392 100644
--- a/pkg/compiler/lib/src/elements/entity_utils.dart
+++ b/pkg/compiler/lib/src/elements/entity_utils.dart
@@ -7,6 +7,7 @@
 import 'package:front_end/src/api_unstable/dart2js.dart'
     show isUserDefinableOperator, isMinusOperator;
 
+import '../js_backend/namer.dart';
 import 'entities.dart';
 
 // Somewhat stable ordering for libraries using [Uri]s
@@ -154,7 +155,7 @@
   } else if (name == 'unary-') {
     return r'operator$negate';
   } else {
-    return name;
+    return Namer.replaceNonIdentifierCharacters(name);
   }
 }
 
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 3544fa3..359d642 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -435,6 +435,26 @@
         ..remove('P')
         ..remove('W');
 
+  static final RegExp _identifierStartRE = RegExp(r'[A-Za-z_$]');
+  static final RegExp _nonIdentifierRE = RegExp(r'[^A-Za-z0-9_$]');
+
+  /// Returns `true` iff [s] begins with an ASCII character that can begin a
+  /// JavaScript identifier.
+  ///
+  /// In particular, [s] must begin with an ASCII letter, an underscore, or a
+  /// dollar sign.
+  static bool startsWithIdentifierCharacter(String s) =>
+      s.startsWith(_identifierStartRE);
+
+  /// Returns a copy of [s] in which characters which cannot be part of an ASCII
+  /// JavaScript identifier have been replaced by underscores.
+  ///
+  /// Note that the result may not be unconditionally used as a JavaScript
+  /// identifier. For example, the result may still begin with a digit or it may
+  /// be a reserved keyword.
+  static String replaceNonIdentifierCharacters(String s) =>
+      s.replaceAll(_nonIdentifierRE, '_');
+
   Set<String> _jsReserved = null;
 
   /// Names that cannot be used by members, top level and static
@@ -621,9 +641,7 @@
   ///
   /// The resulting name is a *proposed name* and is never minified.
   String privateName(Name originalName) {
-    String text = originalName.text;
-
-    text = text.replaceAll(_nonIdentifierRE, '_');
+    String text = replaceNonIdentifierCharacters(originalName.text);
 
     // Public names are easy.
     if (!originalName.isPrivate) return text;
@@ -673,7 +691,7 @@
       // TODO(sra): If the generator is for a closure's 'call' method, we don't
       // need to incorporate the enclosing class.
       String className =
-          method.enclosingClass.name.replaceAll(_nonIdentifierRE, '_');
+          replaceNonIdentifierCharacters(method.enclosingClass.name);
       return '${invocationName}\$body\$${className}';
     });
   }
@@ -847,9 +865,8 @@
     if (element is JSEntity) {
       return _disambiguateInternalMember(
           element,
-          () => (element as JSEntity)
-              .declaredName
-              .replaceAll(_nonIdentifierRE, '_'));
+          () => replaceNonIdentifierCharacters(
+              (element as JSEntity).declaredName));
     }
 
     // If the name of the field might clash with another field,
@@ -862,8 +879,8 @@
     if (_closedWorld.isUsedAsMixin(enclosingClass) ||
         _isShadowingSuperField(element) ||
         _isUserClassExtendingNative(enclosingClass)) {
-      String proposeName() => '${enclosingClass.name}_${element.name}'
-          .replaceAll(_nonIdentifierRE, '_');
+      String proposeName() => replaceNonIdentifierCharacters(
+          '${enclosingClass.name}_${element.name}');
       return _disambiguateInternalMember(element, proposeName);
     }
 
@@ -1207,11 +1224,9 @@
   /// Returns a proposed name for the given typedef or class [element].
   /// The returned id is guaranteed to be a valid JavaScript identifier.
   String _proposeNameForType(Entity element) {
-    return element.name.replaceAll(_nonIdentifierRE, '_');
+    return replaceNonIdentifierCharacters(element.name);
   }
 
-  static RegExp _nonIdentifierRE = new RegExp(r'[^A-Za-z0-9_$]');
-
   /// Returns a proposed name for the given top-level or static member
   /// [element]. The returned id is guaranteed to be a valid JavaScript
   /// identifier.
@@ -1222,10 +1237,10 @@
       return _proposeNameForMember(element.function) + r'$body';
     } else if (element.enclosingClass != null) {
       ClassEntity enclosingClass = element.enclosingClass;
-      return '${enclosingClass.name}_${element.name}'
-          .replaceAll(_nonIdentifierRE, '_');
+      return replaceNonIdentifierCharacters(
+          '${enclosingClass.name}_${element.name}');
     }
-    return element.name.replaceAll(_nonIdentifierRE, '_');
+    return replaceNonIdentifierCharacters(element.name);
   }
 
   String _proposeNameForLazyStaticGetter(MemberEntity element) {
@@ -1360,7 +1375,7 @@
     String enclosing =
         element.enclosingClass == null ? "" : element.enclosingClass.name;
     String library = _proposeNameForLibrary(element.library);
-    String name = element.name.replaceAll(_nonIdentifierRE, '_');
+    String name = replaceNonIdentifierCharacters(element.name);
     return _disambiguateInternalGlobal(
         "${library}_${enclosing}_${name}\$closure");
   }
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index 4ec5745..a845b95 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -77,6 +77,7 @@
 import '../serialization/serialization.dart';
 import '../util/util.dart' show Hashing;
 import 'frequency_assignment.dart';
+import 'namer.dart';
 import 'runtime_types_new.dart' show RecipeEncoder;
 
 /// Run the minifier for 'type$' property names even in non-minified mode,
@@ -582,9 +583,6 @@
   final Map<DartType, int> _backrefs = Map.identity();
   final List<String> _fragments = [];
 
-  static RegExp identifierStartRE = RegExp(r'[A-Za-z_$]');
-  static RegExp nonIdentifierRE = RegExp(r'[^A-Za-z0-9_$]');
-
   String run(TypeRecipe recipe) {
     if (recipe is TypeExpressionRecipe) {
       _visit(recipe.type, null);
@@ -605,7 +603,7 @@
       throw StateError('Unexpected recipe: $recipe');
     }
     String result = _fragments.join('_');
-    if (result.startsWith(identifierStartRE)) return result;
+    if (Namer.startsWithIdentifierCharacter(result)) return result;
     return 'z' + result;
   }
 
@@ -614,7 +612,7 @@
   }
 
   void _identifier(String text) {
-    _add(text.replaceAll(nonIdentifierRE, '_'));
+    _add(Namer.replaceNonIdentifierCharacters(text));
   }
 
   bool _comma(bool needsComma) {
diff --git a/runtime/vm/virtual_memory_win.cc b/runtime/vm/virtual_memory_win.cc
index 1bab7a3..e352adc 100644
--- a/runtime/vm/virtual_memory_win.cc
+++ b/runtime/vm/virtual_memory_win.cc
@@ -62,7 +62,7 @@
                             PAGE_READWRITE, nullptr);
     if (address == nullptr) {
       int error = GetLastError();
-      FATAL2("Failed to reserve region for compressed heap: %d", error);
+      FATAL("Failed to reserve region for compressed heap: %d", error);
     }
     VirtualMemoryCompressedHeap::Init(address);
   }
diff --git a/sdk/lib/_internal/js_runtime/lib/constant_map.dart b/sdk/lib/_internal/js_runtime/lib/constant_map.dart
index c7a2d84..669a7e8 100644
--- a/sdk/lib/_internal/js_runtime/lib/constant_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/constant_map.dart
@@ -173,13 +173,35 @@
   Map<K, V> _getMap() {
     LinkedHashMap<K, V>? backingMap = JS('LinkedHashMap|Null', r'#.$map', this);
     if (backingMap == null) {
-      backingMap = JsLinkedHashMap<K, V>();
+      backingMap = LinkedHashMap<K, V>(
+          hashCode: _constantMapHashCode,
+          // In legacy mode (--no-sound-null-safety), `null` keys are
+          // permitted. In sound mode, `null` keys are permitted only if [K] is
+          // nullable.
+          isValidKey: JS_GET_FLAG('LEGACY') ? _typeTest<K?>() : _typeTest<K>());
       fillLiteralMap(_jsData, backingMap);
       JS('', r'#.$map = #', this, backingMap);
     }
     return backingMap;
   }
 
+  static int _constantMapHashCode(Object? key) {
+    // Types are tested here one-by-one so that each call to get:hashCode can be
+    // resolved differently.
+
+    // Some common primitives in a GeneralConstantMap.
+    if (key is num) return key.hashCode; // One method on JSNumber.
+
+    // Specially handled known types.
+    if (key is Symbol) return key.hashCode;
+    if (key is Type) return key.hashCode;
+
+    // Everything else, including less common primitives.
+    return identityHashCode(key);
+  }
+
+  static bool Function(Object?) _typeTest<T>() => (Object? o) => o is T;
+
   bool containsValue(Object? needle) {
     return _getMap().containsValue(needle);
   }
diff --git a/tests/language/map/literal15_test.dart b/tests/language/map/literal15_test.dart
new file mode 100644
index 0000000..049486e
--- /dev/null
+++ b/tests/language/map/literal15_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2021, 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.
+
+// Test the use of `null` keys in const maps.
+
+library map_literal15_test;
+
+import "package:expect/expect.dart";
+
+void main() {
+  var m1 = const <String, int>{null: 10, 'null': 20};
+  //                           ^^^^
+  // [analyzer] COMPILE_TIME_ERROR.MAP_KEY_TYPE_NOT_ASSIGNABLE
+  // [cfe] The value 'null' can't be assigned to a variable of type 'String' because 'String' is not nullable.
+
+  var m2 = const <Comparable, int>{null: 10, 'null': 20};
+  //                               ^^^^
+  // [analyzer] COMPILE_TIME_ERROR.MAP_KEY_TYPE_NOT_ASSIGNABLE
+  // [cfe] The value 'null' can't be assigned to a variable of type 'Comparable<dynamic>' because 'Comparable<dynamic>' is not nullable.
+}
diff --git a/tests/language_2/map/literal15_test.dart b/tests/language_2/map/literal15_test.dart
new file mode 100644
index 0000000..3ce3460
--- /dev/null
+++ b/tests/language_2/map/literal15_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, 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.9
+
+// Test the use of `null` keys in const maps. In versions before 2.12, when
+// nullable types were introduced, types were nullable so it was legal to have
+// `null` keys in maps.
+
+library map_literal15_test;
+
+import "package:expect/expect.dart";
+
+void test1() {
+  var m1 = const <String, int>{null: 10, 'null': 20};
+  Expect.isTrue(m1.containsKey(null));
+  Expect.isTrue(m1.containsKey(undefined()));
+  Expect.equals(10, m1[null]);
+  Expect.equals(10, m1[undefined()]);
+  Expect.isTrue(m1.containsKey('null'));
+  Expect.equals(20, m1['null']);
+  // The '.keys' carry the 'String' type
+  Expect.type<Iterable<String>>(m1.keys);
+  Expect.type<Iterable<Comparable>>(m1.keys);
+  Expect.notType<Iterable<int>>(m1.keys);
+}
+
+void test2() {
+  var m2 = const <Comparable, int>{null: 10, 'null': 20};
+  Expect.isTrue(m2.containsKey(null));
+  Expect.isTrue(m2.containsKey(undefined()));
+  Expect.equals(10, m2[null]);
+  Expect.equals(10, m2[undefined()]);
+  Expect.isTrue(m2.containsKey('null'));
+  Expect.equals(20, m2['null']);
+  // The '.keys' carry the 'Comparable' type
+  Expect.notType<Iterable<String>>(m2.keys);
+  Expect.type<Iterable<Comparable>>(m2.keys);
+  Expect.notType<Iterable<int>>(m2.keys);
+}
+
+main() {
+  test1();
+  test2();
+}
+
+// Calling `undefined()` gives us a `null` that is implemented as JavaScript
+// `undefined` on dart2js.
+@pragma('dart2js:noInline')
+dynamic get undefined => _undefined;
+
+@pragma('dart2js:noInline')
+void _undefined() {}
diff --git a/tools/VERSION b/tools/VERSION
index 4e0fc8a..1f9d50f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 329
+PRERELEASE 330
 PRERELEASE_PATCH 0
\ No newline at end of file