From 931fd976c60fb335fb885f6ff23ae036667ffbea Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Fri, 18 Feb 2022 11:00:31 +0000 Subject: [PATCH] [cfe] Apply phase 2 macro results Results of Phase 2 macros are now applied. The macro application code has been refactored to support that Phase 1 can apply all macro applications within a library in bulk, but Phase 2 can apply each macro application in sequence. The later is to prepare for making added member visible to subsequent macro applications within Phase 2. This functionality has not been completed yet. Change-Id: Idaf2702e21bde75aedb1509d88e02f270196af5e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/233380 Reviewed-by: Jens Johansen Commit-Queue: Johnni Winther --- .../lib/src/messages/codes_generated.dart | 28 ++++ .../lib/src/fasta/incremental_compiler.dart | 2 + .../lib/src/fasta/kernel/kernel_target.dart | 25 ++- pkg/front_end/lib/src/fasta/kernel/macro.dart | 147 +++++++++++------- .../fasta/source/source_class_builder.dart | 28 +++- .../fasta/source/source_library_builder.dart | 29 ++-- .../lib/src/fasta/source/source_loader.dart | 15 +- pkg/front_end/messages.status | 2 + pkg/front_end/messages.yaml | 4 + .../test/fasta/generator_to_string_test.dart | 3 +- .../data/pkgs/macro/lib/macro.dart | 39 ++++- .../data/tests/declarations.dart | 2 +- .../data/tests/declarations.dart.expect | 32 ++++ .../data/tests/subtypes.dart.expect | 4 + .../data/tests/to_string.dart | 47 ++++++ .../data/tests/to_string.dart.expect | 52 +++++++ .../macro_application_test.dart | 12 +- .../macros/data/tests/macro_declarations.dart | 16 +- pkg/front_end/test/macros/macro_test.dart | 13 ++ .../test/spell_checking_list_messages.txt | 1 + pkg/front_end/tool/dart_doctest_impl.dart | 1 + 21 files changed, 407 insertions(+), 95 deletions(-) create mode 100644 pkg/front_end/test/macro_application/data/tests/to_string.dart create mode 100644 pkg/front_end/test/macro_application/data/tests/to_string.dart.expect diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart index 73122407f78..54a1efcf8a3 100644 --- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart +++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart @@ -7010,6 +7010,34 @@ const MessageCode messageLoadLibraryTakesNoArguments = const MessageCode( analyzerCodes: ["LOAD_LIBRARY_TAKES_NO_ARGUMENTS"], problemMessage: r"""'loadLibrary' takes no arguments."""); +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Template< + Message Function( + String + name)> templateMacroClassNotDeclaredMacro = const Template< + Message Function(String name)>( + problemMessageTemplate: + r"""Non-abstract class '#name' implements 'Macro' but isn't declared as a macro class.""", + correctionMessageTemplate: r"""Try adding the 'macro' class modifier.""", + withArguments: _withArgumentsMacroClassNotDeclaredMacro); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Code codeMacroClassNotDeclaredMacro = + const Code( + "MacroClassNotDeclaredMacro", +); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +Message _withArgumentsMacroClassNotDeclaredMacro(String name) { + if (name.isEmpty) throw 'No name provided'; + name = demangleMixinApplicationName(name); + return new Message(codeMacroClassNotDeclaredMacro, + problemMessage: + """Non-abstract class '${name}' implements 'Macro' but isn't declared as a macro class.""", + correctionMessage: """Try adding the 'macro' class modifier.""", + arguments: {'name': name}); +} + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const Code codeMainNotFunctionDeclaration = messageMainNotFunctionDeclaration; diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart index 3e10ccd295a..74902b33bdb 100644 --- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart +++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart @@ -1749,6 +1749,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator { loader: lastGoodKernelTarget.loader, nameOrigin: libraryBuilder, isUnsupported: libraryBuilder.isUnsupported, + isAugmentation: false, ); libraryBuilder.scope.forEachLocalMember((name, member) { debugLibrary.scope.addLocalMember(name, member, setter: false); @@ -1803,6 +1804,7 @@ class IncrementalCompiler implements IncrementalKernelGenerator { scope: debugLibrary.scope.createNestedScope("expression"), nameOrigin: libraryBuilder, isUnsupported: libraryBuilder.isUnsupported, + isAugmentation: false, ); HybridFileSystem hfs = diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart index 755208cb3d1..55f7c9a2197 100644 --- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart @@ -427,12 +427,25 @@ class KernelTarget extends TargetImplementation { Future _buildForPhase1( Iterable augmentationLibraries) async { await loader.buildOutlines(); + // Normally patch libraries are applied in [SourceLoader.resolveParts]. + // For augmentation libraries we instead apply them directly here. + for (SourceLibraryBuilder augmentationLibrary in augmentationLibraries) { + augmentationLibrary.applyPatches(); + } loader.computeLibraryScopes(augmentationLibraries); // TODO(johnniwinther): Support computation of macro applications in // augmentation libraries? loader.resolveTypes(augmentationLibraries); } + /// Builds [augmentationLibrary] to the state expected after applying phase + /// 2 macros. + void _buildForPhase2(SourceLibraryBuilder augmentationLibrary) { + augmentationLibrary.finishTypeVariables(objectClassBuilder, dynamicType); + augmentationLibrary.build(loader.coreLibrary, modifyTarget: false); + augmentationLibrary.resolveConstructors(); + } + Future buildOutlines({CanonicalName? nameRoot}) async { if (loader.first == null) return new BuildResult(); return withCrashReporting(() async { @@ -483,7 +496,8 @@ class KernelTarget extends TargetImplementation { loader.checkSemantics(objectClassBuilder); benchmarker?.enterPhase(BenchmarkPhases.outline_finishTypeVariables); - loader.finishTypeVariables(objectClassBuilder, dynamicType); + loader.finishTypeVariables( + loader.sourceLibraryBuilders, objectClassBuilder, dynamicType); benchmarker ?.enterPhase(BenchmarkPhases.outline_createTypeInferenceEngine); @@ -500,7 +514,7 @@ class KernelTarget extends TargetImplementation { installSyntheticConstructors(sourceClassBuilders); benchmarker?.enterPhase(BenchmarkPhases.outline_resolveConstructors); - loader.resolveConstructors(); + loader.resolveConstructors(loader.sourceLibraryBuilders); benchmarker?.enterPhase(BenchmarkPhases.outline_link); component = @@ -517,8 +531,11 @@ class KernelTarget extends TargetImplementation { if (macroApplications != null) { benchmarker?.enterPhase(BenchmarkPhases.outline_applyDeclarationMacros); - await macroApplications - .applyDeclarationsMacros(loader.hierarchyBuilder); + await macroApplications.applyDeclarationsMacros(loader.hierarchyBuilder, + (SourceLibraryBuilder augmentationLibrary) async { + await _buildForPhase1([augmentationLibrary]); + _buildForPhase2(augmentationLibrary); + }); } benchmarker diff --git a/pkg/front_end/lib/src/fasta/kernel/macro.dart b/pkg/front_end/lib/src/fasta/kernel/macro.dart index c4a34b36798..c81a969b94c 100644 --- a/pkg/front_end/lib/src/fasta/kernel/macro.dart +++ b/pkg/front_end/lib/src/fasta/kernel/macro.dart @@ -116,6 +116,7 @@ class MacroApplications { final macro.MacroExecutor _macroExecutor; final Map libraryData; final MacroApplicationDataForTesting? dataForTesting; + List<_ApplicationData>? _applicationDataCache; MacroApplications( this._macroExecutor, this.libraryData, this.dataForTesting) { @@ -272,60 +273,57 @@ class MacroApplications { } } - Future>> - _applyMacros( - Future> Function( - Builder, macro.Declaration, List) - applyMacros) async { - Map> libraryResults = - {}; - for (MapEntry libraryEntry in libraryData.entries) { - SourceLibraryBuilder libraryBuilder = libraryEntry.key; - List results = []; - LibraryMacroApplicationData libraryMacroApplicationData = - libraryEntry.value; - for (MapEntry> memberEntry - in libraryMacroApplicationData.memberApplications.entries) { - MemberBuilder memberBuilder = memberEntry.key; - macro.Declaration? declaration = _getMemberDeclaration(memberBuilder); - if (declaration != null) { - results.addAll( - await applyMacros(memberBuilder, declaration, memberEntry.value)); - } - } - for (MapEntry classEntry - in libraryMacroApplicationData.classData.entries) { - SourceClassBuilder classBuilder = classEntry.key; - ClassMacroApplicationData classData = classEntry.value; - List? classApplications = classData.classApplications; - if (classApplications != null) { - macro.ClassDeclaration classDeclaration = - _getClassDeclaration(classBuilder); - results.addAll(await applyMacros( - classBuilder, classDeclaration, classApplications)); - } + Iterable<_ApplicationData> get _applicationData { + if (_applicationDataCache == null) { + List<_ApplicationData> data = _applicationDataCache = []; + for (MapEntry libraryEntry in libraryData.entries) { + SourceLibraryBuilder libraryBuilder = libraryEntry.key; + LibraryMacroApplicationData libraryMacroApplicationData = + libraryEntry.value; for (MapEntry> memberEntry - in classData.memberApplications.entries) { + in libraryMacroApplicationData.memberApplications.entries) { MemberBuilder memberBuilder = memberEntry.key; macro.Declaration? declaration = _getMemberDeclaration(memberBuilder); if (declaration != null) { - results.addAll(await applyMacros( - memberBuilder, declaration, memberEntry.value)); + data.add(new _ApplicationData( + libraryBuilder, memberBuilder, declaration, memberEntry.value)); + } + } + for (MapEntry classEntry + in libraryMacroApplicationData.classData.entries) { + SourceClassBuilder classBuilder = classEntry.key; + ClassMacroApplicationData classData = classEntry.value; + List? classApplications = + classData.classApplications; + if (classApplications != null) { + macro.ClassDeclaration classDeclaration = + _getClassDeclaration(classBuilder); + data.add(new _ApplicationData(libraryBuilder, classBuilder, + classDeclaration, classApplications)); + } + for (MapEntry> memberEntry + in classData.memberApplications.entries) { + MemberBuilder memberBuilder = memberEntry.key; + macro.Declaration? declaration = + _getMemberDeclaration(memberBuilder); + if (declaration != null) { + data.add(new _ApplicationData(libraryBuilder, memberBuilder, + declaration, memberEntry.value)); + } } } } - libraryResults[libraryBuilder] = results; } - return libraryResults; + return _applicationDataCache!; } Future> _applyTypeMacros( - Builder builder, - macro.Declaration declaration, - List macroApplications) async { + _ApplicationData applicationData) async { + macro.Declaration declaration = applicationData.declaration; List results = []; - for (MacroApplication macroApplication in macroApplications) { + for (MacroApplication macroApplication + in applicationData.macroApplications) { if (macroApplication.instanceIdentifier .shouldExecute(_declarationKind(declaration), macro.Phase.types)) { macro.MacroExecutionResult result = @@ -336,6 +334,7 @@ class MacroApplications { } if (retainDataForTesting) { + Builder builder = applicationData.builder; if (builder is SourceClassBuilder) { dataForTesting?.classTypesResults[builder] = results; } else { @@ -347,8 +346,13 @@ class MacroApplications { Future> applyTypeMacros() async { List augmentationLibraries = []; - Map> results = - await _applyMacros(_applyTypeMacros); + Map> results = {}; + for (_ApplicationData macroApplication in _applicationData) { + List executionResults = + await _applyTypeMacros(macroApplication); + (results[macroApplication.libraryBuilder] ??= []) + .addAll(executionResults); + } for (MapEntry> entry in results.entries) { SourceLibraryBuilder sourceLibraryBuilder = entry.key; @@ -363,12 +367,12 @@ class MacroApplications { return augmentationLibraries; } - Future> _applyDeclarationsMacros( - Builder builder, - macro.Declaration declaration, - List macroApplications) async { + Future _applyDeclarationsMacros(_ApplicationData applicationData, + Future Function(SourceLibraryBuilder) onAugmentationLibrary) async { List results = []; - for (MacroApplication macroApplication in macroApplications) { + macro.Declaration declaration = applicationData.declaration; + for (MacroApplication macroApplication + in applicationData.macroApplications) { if (macroApplication.instanceIdentifier.shouldExecute( _declarationKind(declaration), macro.Phase.declarations)) { macro.MacroExecutionResult result = @@ -377,10 +381,19 @@ class MacroApplications { declaration, typeResolver, classIntrospector); - results.add(result); + String source = _macroExecutor + .buildAugmentationLibrary([result], _resolveIdentifier); + SourceLibraryBuilder augmentationLibrary = await applicationData + .libraryBuilder + .createAugmentationLibrary(source); + await onAugmentationLibrary(augmentationLibrary); + if (retainDataForTesting) { + results.add(result); + } } } if (retainDataForTesting) { + Builder builder = applicationData.builder; if (builder is SourceClassBuilder) { dataForTesting?.classDeclarationsResults[builder] = results; } else { @@ -388,27 +401,28 @@ class MacroApplications { results; } } - return results; } late Types types; late macro.TypeResolver typeResolver; late macro.ClassIntrospector classIntrospector; - Future applyDeclarationsMacros( - ClassHierarchyBase classHierarchy) async { + Future applyDeclarationsMacros(ClassHierarchyBase classHierarchy, + Future Function(SourceLibraryBuilder) onAugmentationLibrary) async { types = new Types(classHierarchy); typeResolver = new _TypeResolver(this); classIntrospector = new _ClassIntrospector(this); - await _applyMacros(_applyDeclarationsMacros); + for (_ApplicationData macroApplication in _applicationData) { + await _applyDeclarationsMacros(macroApplication, onAugmentationLibrary); + } } Future> _applyDefinitionMacros( - Builder builder, - macro.Declaration declaration, - List macroApplications) async { + _ApplicationData applicationData) async { List results = []; - for (MacroApplication macroApplication in macroApplications) { + macro.Declaration declaration = applicationData.declaration; + for (MacroApplication macroApplication + in applicationData.macroApplications) { if (macroApplication.instanceIdentifier.shouldExecute( _declarationKind(declaration), macro.Phase.definitions)) { macro.MacroExecutionResult result = @@ -422,6 +436,7 @@ class MacroApplications { } } if (retainDataForTesting) { + Builder builder = applicationData.builder; if (builder is SourceClassBuilder) { dataForTesting?.classDefinitionsResults[builder] = results; } else { @@ -436,13 +451,16 @@ class MacroApplications { Future applyDefinitionMacros() async { typeDeclarationResolver = new _TypeDeclarationResolver(); - await _applyMacros(_applyDefinitionMacros); + for (_ApplicationData macroApplication in _applicationData) { + await _applyDefinitionMacros(macroApplication); + } } void close() { _macroExecutor.close(); _staticTypeCache.clear(); _typeAnnotationCache.clear(); + _applicationDataCache?.clear(); } macro.ClassDeclaration _createClassDeclaration(SourceClassBuilder builder) { @@ -951,3 +969,14 @@ macro.DeclarationKind _declarationKind(macro.Declaration declaration) { throw new UnsupportedError( "Unexpected declaration ${declaration} (${declaration.runtimeType})"); } + +/// Data needed to apply a list of macro applications to a class or member. +class _ApplicationData { + final SourceLibraryBuilder libraryBuilder; + final Builder builder; + final macro.Declaration declaration; + final List macroApplications; + + _ApplicationData(this.libraryBuilder, this.builder, this.declaration, + this.macroApplications); +} diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart index 128d00fd92f..d26b6a20f02 100644 --- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart @@ -618,8 +618,11 @@ class SourceClassBuilder extends ClassBuilderImpl } } - void checkSupertypes(CoreTypes coreTypes, - ClassHierarchyBuilder hierarchyBuilder, Class enumClass) { + void checkSupertypes( + CoreTypes coreTypes, + ClassHierarchyBuilder hierarchyBuilder, + Class enumClass, + Class? macroClass) { // This method determines whether the class (that's being built) its super // class appears both in 'extends' and 'implements' clauses and whether any // interface appears multiple times in the 'implements' clause. @@ -679,6 +682,27 @@ class SourceClassBuilder extends ClassBuilderImpl } } } + if (macroClass != null && !cls.isMacro && !cls.isAbstract) { + // TODO(johnniwinther): Merge this check with the loop above. + bool isMacroFound = false; + List interfaces = + hierarchyBuilder.getNodeFromClass(cls).superclasses; + for (int i = 0; !isMacroFound && i < interfaces.length; i++) { + if (interfaces[i].classNode == macroClass) { + isMacroFound = true; + } + } + interfaces = hierarchyBuilder.getNodeFromClass(cls).interfaces; + for (int i = 0; !isMacroFound && i < interfaces.length; i++) { + if (interfaces[i].classNode == macroClass) { + isMacroFound = true; + } + } + if (isMacroFound) { + addProblem(templateMacroClassNotDeclaredMacro.withArguments(name), + charOffset, noLength); + } + } void fail(NamedTypeBuilder target, Message message, TypeAliasBuilder? aliasBuilder) { diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart index 878536f8e17..37de8c94cf5 100644 --- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart @@ -243,6 +243,9 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { List? _patchLibraries; + /// `true` if this is an augmentation library. + final bool isAugmentation; + SourceLibraryBuilder.internal( SourceLoader loader, Uri fileUri, @@ -253,8 +256,9 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { Library library, LibraryBuilder? nameOrigin, Library? referencesFrom, - bool? referenceIsPartOwner, - bool isUnsupported) + {bool? referenceIsPartOwner, + required bool isUnsupported, + required bool isAugmentation}) : this.fromScopes( loader, fileUri, @@ -266,7 +270,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { library, nameOrigin, referencesFrom, - isUnsupported); + isUnsupported: isUnsupported, + isAugmentation: isAugmentation); SourceLibraryBuilder.fromScopes( this.loader, @@ -279,7 +284,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { this.library, this._nameOrigin, this.referencesFrom, - this.isUnsupported) + {required this.isUnsupported, + required this.isAugmentation}) : _languageVersion = packageLanguageVersion, currentTypeParameterScopeBuilder = _libraryTypeParameterScopeBuilder, referencesFromIndexed = @@ -469,7 +475,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { LibraryBuilder? nameOrigin, Library? referencesFrom, bool? referenceIsPartOwner, - required bool isUnsupported}) + required bool isUnsupported, + required bool isAugmentation}) : this.internal( loader, fileUri, @@ -487,8 +494,9 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { ..setLanguageVersion(packageLanguageVersion.version)), nameOrigin, referencesFrom, - referenceIsPartOwner, - isUnsupported); + referenceIsPartOwner: referenceIsPartOwner, + isUnsupported: isUnsupported, + isAugmentation: isAugmentation); @override bool get isPart => partOfName != null || partOfUri != null; @@ -520,7 +528,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { loader: loader, isUnsupported: false, target: library, - origin: this); + origin: this, + isAugmentation: true); addPatchLibrary(augmentationLibrary); loader.registerUnparsedLibrarySource(augmentationLibrary, source); return augmentationLibrary; @@ -3896,9 +3905,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { Builder member = patchDeclarations.current; // We need to inject all non-patch members into the origin library. This // should only apply to private members. + // For augmentation libraries, all members are injected into the origin + // library, regardless of privacy. if (member.isPatch) { // Ignore patches. - } else if (name.startsWith("_")) { + } else if (name.startsWith("_") || isAugmentation) { origin.injectMemberFromPatch(name, member); } else { origin.exportMemberFromPatch(name, member); diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart index a429ef014a4..b77b5c9684f 100644 --- a/pkg/front_end/lib/src/fasta/source/source_loader.dart +++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart @@ -328,7 +328,8 @@ class SourceLoader extends Loader { referenceIsPartOwner: referenceIsPartOwner, isUnsupported: origin?.library.isUnsupported ?? importUri.isScheme('dart') && - !target.uriTranslator.isLibrarySupported(importUri.path)); + !target.uriTranslator.isLibrarySupported(importUri.path), + isAugmentation: false); } /// Return `"true"` if the [dottedName] is a 'dart.library.*' qualifier for a @@ -1689,9 +1690,9 @@ severity: $severity ticker.logMs("Finished forwarders for $count procedures"); } - void resolveConstructors() { + void resolveConstructors(List libraryBuilders) { int count = 0; - for (SourceLibraryBuilder library in sourceLibraryBuilders) { + for (SourceLibraryBuilder library in libraryBuilders) { count += library.resolveConstructors(); } ticker.logMs("Resolved $count constructors"); @@ -1705,9 +1706,10 @@ severity: $severity } } - void finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) { + void finishTypeVariables(Iterable libraryBuilders, + ClassBuilder object, TypeBuilder dynamicType) { int count = 0; - for (SourceLibraryBuilder library in sourceLibraryBuilders) { + for (SourceLibraryBuilder library in libraryBuilders) { count += library.finishTypeVariables(object, dynamicType); } ticker.logMs("Resolved $count type-variable bounds"); @@ -2065,7 +2067,8 @@ severity: $severity List sourceClasses, Class enumClass) { for (SourceClassBuilder builder in sourceClasses) { if (builder.library.loader == this && !builder.isPatch) { - builder.checkSupertypes(coreTypes, hierarchyBuilder, enumClass); + builder.checkSupertypes( + coreTypes, hierarchyBuilder, enumClass, _macroClassBuilder?.cls); } } ticker.logMs("Checked supertypes"); diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status index 0e1957f7a4a..b2e67dc1e73 100644 --- a/pkg/front_end/messages.status +++ b/pkg/front_end/messages.status @@ -578,6 +578,8 @@ LibraryDirectiveNotFirst/script2: Fail LibraryDirectiveNotFirst/script3: Fail ListLiteralTooManyTypeArguments/example: Fail LoadLibraryTakesNoArguments/example: Fail +MacroClassNotDeclaredMacro/analyzerCode: Fail +MacroClassNotDeclaredMacro/example: Fail MainNotFunctionDeclaration/analyzerCode: Fail MainNotFunctionDeclarationExported/analyzerCode: Fail MainNotFunctionDeclarationExported/part_wrapped_script: Fail diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index 043a64d4958..72c975af48c 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -5479,3 +5479,7 @@ EnumContainsValuesDeclaration: EnumImplementerContainsValuesDeclaration: problemMessage: "'#name' has 'Enum' as a superinterface and can't contain non-static member with name 'values'." + +MacroClassNotDeclaredMacro: + problemMessage: "Non-abstract class '#name' implements 'Macro' but isn't declared as a macro class." + correctionMessage: "Try adding the 'macro' class modifier." diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart index 787ad86e8c0..9db87a411ff 100644 --- a/pkg/front_end/test/fasta/generator_to_string_test.dart +++ b/pkg/front_end/test/fasta/generator_to_string_test.dart @@ -95,7 +95,8 @@ Future main() async { new NoneTarget(new TargetFlags())), uriTranslator) .loader, - isUnsupported: false); + isUnsupported: false, + isAugmentation: false); libraryBuilder.markLanguageVersionFinal(); LoadLibraryBuilder loadLibraryBuilder = new LoadLibraryBuilder(libraryBuilder, dummyLibraryDependency, -1); diff --git a/pkg/front_end/test/macro_application/data/pkgs/macro/lib/macro.dart b/pkg/front_end/test/macro_application/data/pkgs/macro/lib/macro.dart index 5f4db94a541..15d9fb7cb9c 100644 --- a/pkg/front_end/test/macro_application/data/pkgs/macro/lib/macro.dart +++ b/pkg/front_end/test/macro_application/data/pkgs/macro/lib/macro.dart @@ -51,7 +51,8 @@ class FunctionTypesMacro1 implements FunctionTypesMacro { name, new DeclarationCode.fromParts([''' class $name { external ''', function.returnType.code, ''' method(); -}'''])); +}''' + ])); } } @@ -129,8 +130,14 @@ class MethodDeclarationsMacro1 implements MethodDeclarationsMacro { if (method.isSetter) { sb.write('s'); } + String name; + if (method.isOperator) { + name = 'operator'; + } else { + name = method.identifier.name; + } builder.declareInLibrary(new DeclarationCode.fromString(''' -void ${method.definingClass.name}_${method.identifier.name}GeneratedMethod_${sb}() {} +void ${method.definingClass.name}_${name}GeneratedMethod_${sb}() {} ''')); } } @@ -288,3 +295,31 @@ void ${constructor.definingClass.name}_${constructor.identifier ''')); } } + +macro + +class ToStringMacro implements ClassDeclarationsMacro { + const ToStringMacro(); + + FutureOr buildDeclarationsForClass(ClassDeclaration clazz, + ClassMemberDeclarationBuilder builder) async { + Iterable methods = await builder.methodsOf(clazz); + if (!methods.any((m) => m.identifier.name == 'toString')) { + Iterable fields = await builder.fieldsOf(clazz); + List parts = [''' + toString() { + return "${clazz.identifier.name}(''']; + String comma = ''; + for (FieldDeclaration field in fields) { + parts.add(comma); + parts.add('${field.identifier.name}=\${'); + parts.add(field.identifier.name); + parts.add('}'); + comma = ','; + } + parts.add(''')"; + }'''); + builder.declareInClass(new DeclarationCode.fromParts(parts)); + } + } +} \ No newline at end of file diff --git a/pkg/front_end/test/macro_application/data/tests/declarations.dart b/pkg/front_end/test/macro_application/data/tests/declarations.dart index dfed26d4704..7a69a25c066 100644 --- a/pkg/front_end/test/macro_application/data/tests/declarations.dart +++ b/pkg/front_end/test/macro_application/data/tests/declarations.dart @@ -112,7 +112,7 @@ void Class1_instanceSetter1GeneratedMethod_s() {} void set instanceSetter1(int? value) {} /*member: Class1.[]: -void Class1_[]GeneratedMethod_o() {} +void Class1_operatorGeneratedMethod_o() {} */ @MethodDeclarationsMacro1() int operator [](int i) => i; diff --git a/pkg/front_end/test/macro_application/data/tests/declarations.dart.expect b/pkg/front_end/test/macro_application/data/tests/declarations.dart.expect index 786028fbd98..dfe99d0d90e 100644 --- a/pkg/front_end/test/macro_application/data/tests/declarations.dart.expect +++ b/pkg/front_end/test/macro_application/data/tests/declarations.dart.expect @@ -19,6 +19,9 @@ class Class1 extends core::Object { constructor •() → self::Class1 : super core::Object::•() ; + method /* from org-dartlang-augmentation:/a/b/c/main.dart-18 */ Class1_GeneratedMethod_() → void {} + method /* from org-dartlang-augmentation:/a/b/c/main.dart-19 */ Class1_redirectGeneratedMethod_f() → void {} + method /* from org-dartlang-augmentation:/a/b/c/main.dart-20 */ Class1_factGeneratedMethod_f() → void {} @#C5 static factory redirect() → self::Class1 return new self::Class1::•(); @@ -68,6 +71,35 @@ static get topLevelGetter1() → core::int? return null; @#C8 static set topLevelSetter1(core::int? value) → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-1 */ topLevelFunction1GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-2 */ topLevelFunction2GeneratedMethod_e() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-3 */ topLevelField1GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-4 */ topLevelField2GeneratedMethod_e() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-5 */ topLevelField3GeneratedMethod_f() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-6 */ topLevelField4GeneratedMethod_l() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-7 */ topLevelGetter1GeneratedMethod_g() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-8 */ topLevelSetter1GeneratedMethod_s() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-9 */ Class1GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-10 */ Class1Introspection() → void { + core::print("constructors=''"); + core::print("fields='instanceField1','instanceField2','instanceField3'"); + core::print("methods='instanceMethod1','instanceGetter1','[]','instanceSetter1'"); +} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-11 */ Class1_instanceMethod1GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-12 */ Class1_instanceGetter1GeneratedMethod_g() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-13 */ Class1_operatorGeneratedMethod_o() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-14 */ Class1_instanceField1GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-15 */ Class1_instanceField2GeneratedMethod_f() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-16 */ Class1_instanceField3GeneratedMethod_fl() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-17 */ Class1_instanceSetter1GeneratedMethod_s() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-21 */ Class2GeneratedMethod_a() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-22 */ Class2Introspection() → void { + core::print("constructors="); + core::print("fields='instanceField1'"); + core::print("methods='instanceMethod1'"); +} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-23 */ Class2_instanceMethod1GeneratedMethod_a() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-24 */ Class2_instanceField1GeneratedMethod_() → void {} constants { #C1 = mac::ClassDeclarationsMacro1 {} diff --git a/pkg/front_end/test/macro_application/data/tests/subtypes.dart.expect b/pkg/front_end/test/macro_application/data/tests/subtypes.dart.expect index d4281835b79..07374b2a74b 100644 --- a/pkg/front_end/test/macro_application/data/tests/subtypes.dart.expect +++ b/pkg/front_end/test/macro_application/data/tests/subtypes.dart.expect @@ -52,6 +52,10 @@ external static method topLevelFunction3(self::C1 a) → self::C2; @#C1 @#C2 external static method topLevelFunction4(self::D1 a) → self::D2; +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-1 */ topLevelFunction1GeneratedMethod_es() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-2 */ topLevelFunction2GeneratedMethod_s() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-3 */ topLevelFunction3GeneratedMethod_() → void {} +static method /* from org-dartlang-augmentation:/a/b/c/main.dart-4 */ topLevelFunction4GeneratedMethod_() → void {} constants { #C1 = mac::FunctionDeclarationsMacro2 {} diff --git a/pkg/front_end/test/macro_application/data/tests/to_string.dart b/pkg/front_end/test/macro_application/data/tests/to_string.dart new file mode 100644 index 00000000000..b5327e537a8 --- /dev/null +++ b/pkg/front_end/test/macro_application/data/tests/to_string.dart @@ -0,0 +1,47 @@ +// 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: + + +*/ + +import 'package:macro/macro.dart'; + +@ToStringMacro() +/*class: A: +augment class A { + toString() { + return "A(a=${a},b=${b})"; + } +}*/ +class A { + var a; + var b; +} + +@ToStringMacro() +/*class: B: +augment class B { + toString() { + return "B(c=${c},d=${d},e=${e})"; + } +}*/ +class B { + var c, d; + var e; +} + +@ToStringMacro() +class C { + var f; + + @override + String toString() => 'C()'; +} + +class D { + var g; + var h; +} diff --git a/pkg/front_end/test/macro_application/data/tests/to_string.dart.expect b/pkg/front_end/test/macro_application/data/tests/to_string.dart.expect new file mode 100644 index 00000000000..431c8a2589f --- /dev/null +++ b/pkg/front_end/test/macro_application/data/tests/to_string.dart.expect @@ -0,0 +1,52 @@ +library /*isNonNullableByDefault*/; +import self as self; +import "package:macro/macro.dart" as mac; +import "dart:core" as core; + +import "package:macro/macro.dart"; + +@#C1 +class A extends core::Object { + field dynamic a = null; + field dynamic b = null; + synthetic constructor •() → self::A + : super core::Object::•() + ; + method /* from org-dartlang-augmentation:/a/b/c/main.dart-1 */ toString() → dynamic { + return "A(a=${this.{self::A::a}{dynamic}},b=${this.{self::A::b}{dynamic}})"; + } +} +@#C1 +class B extends core::Object { + field dynamic c = null; + field dynamic d = null; + field dynamic e = null; + synthetic constructor •() → self::B + : super core::Object::•() + ; + method /* from org-dartlang-augmentation:/a/b/c/main.dart-2 */ toString() → dynamic { + return "B(c=${this.{self::B::c}{dynamic}},d=${this.{self::B::d}{dynamic}},e=${this.{self::B::e}{dynamic}})"; + } +} +@#C1 +class C extends core::Object { + field dynamic f = null; + synthetic constructor •() → self::C + : super core::Object::•() + ; + @#C2 + method toString() → core::String + return "C()"; +} +class D extends core::Object { + field dynamic g = null; + field dynamic h = null; + synthetic constructor •() → self::D + : super core::Object::•() + ; +} + +constants { + #C1 = mac::ToStringMacro {} + #C2 = core::_Override {} +} diff --git a/pkg/front_end/test/macro_application/macro_application_test.dart b/pkg/front_end/test/macro_application/macro_application_test.dart index fd317c75e29..647c544ea6c 100644 --- a/pkg/front_end/test/macro_application/macro_application_test.dart +++ b/pkg/front_end/test/macro_application/macro_application_test.dart @@ -184,7 +184,9 @@ class MacroDataComputer extends DataComputer { in macroApplicationData.classTypesResults.entries) { if (entry.key.cls == cls) { for (MacroExecutionResult result in entry.value) { - sb.write('\n${codeToString(result.augmentations.first)}'); + if (result.augmentations.isNotEmpty) { + sb.write('\n${codeToString(result.augmentations.first)}'); + } } } } @@ -192,7 +194,9 @@ class MacroDataComputer extends DataComputer { in macroApplicationData.classDeclarationsResults.entries) { if (entry.key.cls == cls) { for (MacroExecutionResult result in entry.value) { - sb.write('\n${codeToString(result.augmentations.first)}'); + if (result.augmentations.isNotEmpty) { + sb.write('\n${codeToString(result.augmentations.first)}'); + } } } } @@ -200,7 +204,9 @@ class MacroDataComputer extends DataComputer { in macroApplicationData.classDefinitionsResults.entries) { if (entry.key.cls == cls) { for (MacroExecutionResult result in entry.value) { - sb.write('\n${codeToString(result.augmentations.first)}'); + if (result.augmentations.isNotEmpty) { + sb.write('\n${codeToString(result.augmentations.first)}'); + } } } } diff --git a/pkg/front_end/test/macros/data/tests/macro_declarations.dart b/pkg/front_end/test/macros/data/tests/macro_declarations.dart index c780d613c87..1ddcfd501df 100644 --- a/pkg/front_end/test/macros/data/tests/macro_declarations.dart +++ b/pkg/front_end/test/macros/data/tests/macro_declarations.dart @@ -38,20 +38,20 @@ macro class ImplementsAlias implements Alias {} macro class MixinAlias with Alias {} -class ExtendsNoKeyword extends Macro {} +class /*error: error=MacroClassNotDeclaredMacro*/ExtendsNoKeyword extends Macro {} -class ImplementsNoKeyword implements Macro {} +class /*error: error=MacroClassNotDeclaredMacro*/ImplementsNoKeyword implements Macro {} -class MixinNoKeyword with Macro {} +class /*error: error=MacroClassNotDeclaredMacro*/MixinNoKeyword with Macro {} -class ExtendsAliasNoKeyword extends Alias {} +class /*error: error=MacroClassNotDeclaredMacro*/ExtendsAliasNoKeyword extends Alias {} -class ImplementsAliasNoKeyword implements Alias {} +class /*error: error=MacroClassNotDeclaredMacro*/ImplementsAliasNoKeyword implements Alias {} -class MixinAliasNoKeyword with Alias {} +class /*error: error=MacroClassNotDeclaredMacro*/MixinAliasNoKeyword with Alias {} -class NamedMixin1NoKeyword = Macro with _Mixin; +class /*error: error=MacroClassNotDeclaredMacro*/NamedMixin1NoKeyword = Macro with _Mixin; -class NamedMixin2NoKeyword = Object with Macro; +class /*error: error=MacroClassNotDeclaredMacro*/NamedMixin2NoKeyword = Object with Macro; void main() {} diff --git a/pkg/front_end/test/macros/macro_test.dart b/pkg/front_end/test/macros/macro_test.dart index e583b6be846..a20eaf24e1c 100644 --- a/pkg/front_end/test/macros/macro_test.dart +++ b/pkg/front_end/test/macros/macro_test.dart @@ -17,6 +17,7 @@ import 'package:front_end/src/fasta/builder/library_builder.dart'; import 'package:front_end/src/fasta/builder/member_builder.dart'; import 'package:front_end/src/fasta/kernel/macro.dart'; import 'package:front_end/src/testing/id_testing_helper.dart'; +import 'package:front_end/src/testing/id_testing_utils.dart'; import 'package:kernel/ast.dart' hide Arguments; Future main(List args) async { @@ -77,6 +78,17 @@ class MacroDataComputer extends DataComputer { .computeForLibrary(library); } + @override + bool get supportsErrors => true; + + @override + Features? computeErrorData( + TestResultData testResultData, Id id, List errors) { + Features features = new Features(); + features[Tags.error] = errorsToText(errors, useCodes: true); + return features; + } + @override DataInterpreter get dataValidator => const FeaturesDataInterpreter(); @@ -91,6 +103,7 @@ class Tags { static const String appliedMacros = 'appliedMacros'; static const String macroClassIds = 'macroClassIds'; static const String macroInstanceIds = 'macroInstanceIds'; + static const String error = 'error'; } String constructorNameToString(String constructorName) { diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt index 3230d251102..e6964cdc50e 100644 --- a/pkg/front_end/test/spell_checking_list_messages.txt +++ b/pkg/front_end/test/spell_checking_list_messages.txt @@ -45,6 +45,7 @@ js_util libraries.json list.filled loadlibrary +macro migrate name.#name name.stack diff --git a/pkg/front_end/tool/dart_doctest_impl.dart b/pkg/front_end/tool/dart_doctest_impl.dart index 6481a4c22f6..09a9e7f6149 100644 --- a/pkg/front_end/tool/dart_doctest_impl.dart +++ b/pkg/front_end/tool/dart_doctest_impl.dart @@ -834,6 +834,7 @@ class DocTestIncrementalCompiler extends IncrementalCompiler { scope: libraryBuilder.scope.createNestedScope("dartdoctest"), nameOrigin: libraryBuilder, isUnsupported: false, + isAugmentation: false, ); if (libraryBuilder is DillLibraryBuilder) {