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