sdk icon indicating copy to clipboard operation
sdk copied to clipboard

Nested macro application fails on analyzer

Open davidmorgan opened this issue 1 year ago • 1 comments

New test language/macros/nesting/macro_impl_uses_macro1_test added here has a macro implementation that relies an a macro application, currently it fails on the analyzer.

It's possible the fault is not in the analyzer, it also fails on the CFE ... but confusingly, passes on the VM.

davidmorgan avatar Feb 15 '24 08:02 davidmorgan

The compile time error is found during compilation of declare_count1_macro.dart to kernel, so it is when CFE, not the analyzer should apply @DeclareCount0(). So, I don't think that this is an issue with the analyzer.

Click me
/Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros
  /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/macro_impl_uses_macro1_test.dart
----------------------------------------------------------------
[compile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart.macro]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/.dart_tool/package_config.json]
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/.dart_tool/package_config.json]
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart.macro]
  import 'dart:io';
  import 'dart:isolate';
  
  import 'package:_fe_analyzer_shared/src/macros/executor/client.dart';
  import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
  
  import 'file:///Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart';
  
  
  /// Entrypoint to be spawned with [Isolate.spawnUri] or [Process.start].
  ///
  /// Supports the client side of the macro expansion protocol.
  void main(List<String> arguments, [SendPort? sendPort]) async {
    await MacroExpansionClient.start(
        SerializationMode.byteData, _macroConstructors, arguments, sendPort);
  }
  
  /// Maps libraries by uri to macros by name, and then constructors by name.
  final _macroConstructors = <Uri, Map<String, Map<String, Function>>>{
    Uri.parse('file:///Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart'): {
  'DeclareCount0': {
  '': DeclareCount0.new,
  },
  },
  
  };
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart]
  import 'package:_fe_analyzer_shared/src/macros/api.dart';
  
  macro class DeclareCount0 implements ClassDeclarationsMacro {
    const DeclareCount0();
  
    @override
    Future<void> buildDeclarationsForClass(
        ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
      builder.declareInType(DeclarationCode.fromString('int get count => 0;'));
    }
  }
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/pkg/meta/lib/meta.dart]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/pkg/meta/lib/meta_meta.dart]
----------------------------------------------------------------
[compile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart.macro]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/.dart_tool/package_config.json]
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/.dart_tool/package_config.json]
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/.dart_tool/package_config.json]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart.macro]
  import 'dart:io';
  import 'dart:isolate';
  
  import 'package:_fe_analyzer_shared/src/macros/executor/client.dart';
  import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
  
  import 'file:///Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart';
  
  
  /// Entrypoint to be spawned with [Isolate.spawnUri] or [Process.start].
  ///
  /// Supports the client side of the macro expansion protocol.
  void main(List<String> arguments, [SendPort? sendPort]) async {
    await MacroExpansionClient.start(
        SerializationMode.byteData, _macroConstructors, arguments, sendPort);
  }
  
  /// Maps libraries by uri to macros by name, and then constructors by name.
  final _macroConstructors = <Uri, Map<String, Map<String, Function>>>{
    Uri.parse('file:///Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart'): {
  'DeclareCount1': {
  '': DeclareCount1.new,
  },
  },
  
  };
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart]
  import 'package:_fe_analyzer_shared/src/macros/api.dart';
  
  import 'declare_count0_macro.dart';
  
  @DeclareCount0()
  macro class DeclareCount1 implements ClassDeclarationsMacro {
    const DeclareCount1();
  
    @override
    Future<void> buildDeclarationsForClass(
        ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
      builder.declareInType(DeclarationCode.fromString('int get count => ${count + 1};'));
    }
  }
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count0_macro.dart]
  import 'package:_fe_analyzer_shared/src/macros/api.dart';
  
  macro class DeclareCount0 implements ClassDeclarationsMacro {
    const DeclareCount0();
  
    @override
    Future<void> buildDeclarationsForClass(
        ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
      builder.declareInType(DeclarationCode.fromString('int get count => 0;'));
    }
  }
  
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/pkg/meta/lib/meta.dart]
[uriStrToFile][path: /Users/scheglov/Source/Dart/sdk.git/sdk/pkg/meta/lib/meta_meta.dart]
    /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/macro_impl_uses_macro1_test.dart
      [/Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/macro_impl_uses_macro1_test.dart(404..408): The getter 'count' isn't defined for the type 'A'., /Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/macro_impl_uses_macro1_test.dart(341..356): Unhandled error: 'file:///Users/scheglov/Source/Dart/sdk.git/sdk/tests/language/macros/nesting/impl/declare_count1_macro.dart': error: ../../tests/language/macros/nesting/impl/declare_count1_macro.dart:12:74: Error: The getter 'count' isn't defined for the class 'DeclareCount1'.
 - 'DeclareCount1' is from '../../tests/language/macros/nesting/impl/declare_count1_macro.dart'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'count'.
    builder.declareInType(DeclarationCode.fromString('int get count => ${count + 1};'));
                                                                         ^^^^^
Stack trace:
#0      executeDeclarationsMacro (package:_fe_analyzer_shared/src/macros/executor/execute_macro.dart:113:21)
#1      MacroExpansionClient._executeDeclarationsPhase (package:_fe_analyzer_shared/src/macros/executor/client.dart:249:43)
#2      MacroExpansionClient._handleMessage.<anonymous closure> (package:_fe_analyzer_shared/src/macros/executor/client.dart:136:18)
#3      _rootRun (dart:async/zone.dart:1399:13)
#4      _CustomZone.run (dart:async/zone.dart:1301:19)
#5      withRemoteInstanceZone (package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart:173:15)
#6      MacroExpansionClient._handleMessage (package:_fe_analyzer_shared/src/macros/executor/client.dart:118:11)
#7      new MacroExpansionClient._.<anonymous closure> (package:_fe_analyzer_shared/src/macros/executor/client.dart:37:39)
#8      _rootRunUnary (dart:async/zone.dart:1415:13)
#9      _CustomZone.runUnary (dart:async/zone.dart:1308:19)
#10     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
#11     _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:339:11)
#12     _BufferingStreamSubscription._add (dart:async/stream_impl.dart:271:7)
#13     _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#14     _StreamController._add (dart:async/stream_controller.dart:658:7)
#15     _StreamController.add (dart:async/stream_controller.dart:606:5)
#16     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
]
---
// Copyright (c) 2024, 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.
// SharedOptions=--enable-experiment=macros

import 'package:expect/expect.dart';

import 'impl/declare_count1_macro.dart';

@DeclareCount1()
class A {}

void main() {
  Expect.equals(A().count, 1);
}

---
[time: 2146 ms]

scheglov avatar Feb 15 '24 18:02 scheglov

I'm hitting a similar error when writing macros that utilize generated declarations, but only with the analyzer (dart analyze and in VSCode) - running the application works just fine. Let me know if you'd like a separate issue.

// ** META-MACRO IMPL **
import 'package:macros/macros.dart';

/// Useful for building helper functionality for macros.
macro class MetaMacro implements ClassDeclarationsMacro {
  const MetaMacro();

  @override
  Future<void> buildDeclarationsForClass(
    ClassDeclaration clazz,
    MemberDeclarationBuilder builder,
  ) async {
    builder.declareInType(
      DeclarationCode.fromParts(
        ['  const ', clazz.identifier.name, '(this.value);\n\n', '  final String value;\n'],
      ),
    );
  }
}

// ** META MACRO USAGE **
import 'meta_macro.dart';

/// A utility class to help with building macros.
@MetaMacro()
class MacroUtility {}

// ** A MACRO THAT USES HELPER CLASS **
import 'package:macros/macros.dart';

import 'macro_utility.dart';

macro class MyMacro implements ClassDeclarationsMacro {
  const MyMacro();

  @override
  Future<void> buildDeclarationsForClass(
    ClassDeclaration clazz,
    MemberDeclarationBuilder builder,
  ) async {
    // Create an instance of the utility class using the generated unnamed ctor.
    final utils = MacroUtility('Hello from MyMacro');

    // Access the value from the generated [value] field.
    final value = utils.value;

    builder.declareInType(
      DeclarationCode.fromParts(['final value = \'', value, '\';\n']),
    );
  }
}
import 'my_macro.dart';

@MyMacro()
//^^^^^^^^ ERROR: Macro application failed due to a bug in the macro.
class MyMacroUsage {}

void main() {
  final value = MyMacroUsage().value;
  //                           ^^^^^ ERROR: The getter 'value' isn't defined for the type 'FooUsage'.
  print(value); // prints `Hello from MyMacro` when run via cli
}

Full error / stack trace:

Macro application failed due to a bug in the macro.
Try reporting the failure to the macro author.dart(macro_error)
foo_macro_usage.dart(3, 1): 'package:drpc_workspace/nested_macros/my_macro.dart': error: Users/pattobrien/dev/pattobrien/drpc/lib/nested_macros/my_macro.dart:14:31: Error: Too many positional arguments: 0 allowed, but 1 found.
Try removing the extra positional arguments.
final utils = MacroUtility('Hello from MyMacro');
^
#0 executeDeclarationsMacro (package:_macros/src/executor/execute_macro.dart:113:21)
#1 MacroExpansionClient._executeDeclarationsPhase (package:_macros/src/executor/client.dart:247:43)
#2 MacroExpansionClient._handleMessage.<anonymous closure> (package:_macros/src/executor/client.dart:135:18)
#3 _rootRun (dart:async/zone.dart:1399:13)
#4 _CustomZone.run (dart:async/zone.dart:1301:19)
#5 withRemoteInstanceZone (package:_macros/src/executor/remote_instance.dart:172:15)
#6 MacroExpansionClient._handleMessage (package:_macros/src/executor/client.dart:118:11)
#7 new MacroExpansionClient._.<anonymous closure> (package:_macros/src/executor/client.dart:37:39)
#8 _rootRunUnary (dart:async/zone.dart:1415:13)
#9 _CustomZone.runUnary (dart:async/zone.dart:1308:19)
#10 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1217:7)
#11 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:365:11)
#12 _BufferingStreamSubscription._add (dart:async/stream_impl.dart:297:7)
#13 _SyncStreamControllerDispatch._sendData (dart:async/stream_controller.dart:784:19)
#14 _StreamController._add (dart:async/stream_controller.dart:658:7)
#15 _StreamController.add (dart:async/stream_controller.dart:606:5)
#16 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

SDK Details

Dart SDK version: 3.5.0-131.0.dev (dev) (Fri May 3 09:02:58 2024 -0700) on "macos_arm64"

pattobrien avatar May 08 '24 12:05 pattobrien

Thanks @pattobrien! ... I expect there will be some churn in this area that may naturally resolve the issue, so we will check back on this one afterwards.

davidmorgan avatar May 29 '24 16:05 davidmorgan