dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.57k forks source link

macro_application_argument_error when passing an enum value as a macro parameter #56377

Open alexeyinkin opened 2 months ago

alexeyinkin commented 2 months ago

Looks like a macro can't accept enum values as parameters although it can declare such parameters and have default values for them.

macro.dart:

import 'dart:async';

import 'package:macros/macros.dart';

enum MyEnum { hello, hola }

macro class MyMacro implements ClassDeclarationsMacro {
  final MyEnum enumValue;
  final int intValue;

  const MyMacro({
    this.enumValue = MyEnum.hello,
    this.intValue = 1,
  });

  @override
  FutureOr<void> buildDeclarationsForClass(ClassDeclaration clazz, MemberDeclarationBuilder builder) {
    builder.declareInLibrary(
      DeclarationCode.fromParts([
        'augment class ${clazz.identifier.name} {',
        '  static const intValue = $intValue;',
        '  static const hello = "', enumValue.name, '";',
        '}',
      ]),
    );
  }
}

main.dart:

import 'macro.dart';

@MyMacro(
  enumValue: MyEnum.hello, // Comment this out, and it works.
  intValue: 3,
)
class Foo {
  void sayHello() {
    for (int i = 0; i < intValue; i++)
      print(hello);
  }
}

void main() {
  (new Foo()).sayHello();
}
pubspec.yaml

```yaml name: temp1 environment: sdk: ^3.5.0-180 dependencies: macros: ^0.1.0-main.5 # For 3.5.0-180 ```

Expected

dart run --enable-experiment=macros main.dart:

hello
hello
hello

Actual

dart run --enable-experiment=macros main.dart:

main.dart:9:25: Error: The getter 'intValue' isn't defined for the class 'Foo'.
 - 'Foo' is from 'package:temp1/macro-enum/main.dart' ('main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'intValue'.
    for (int i = 0; i < intValue; i++)
                        ^^^^^^^^
main.dart:10:13: Error: The getter 'hello' isn't defined for the class 'Foo'.
 - 'Foo' is from 'package:temp1/macro-enum/main.dart' ('main.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'hello'.
      print(hello);
            ^^^^^
main.dart:3:2: Error: This macro application didn't apply correctly due to an unhandled send.
@MyMacro(
 ^

dart analyze:

Analyzing macro-enum...                0.5s

  error • main.dart:4:3 • Not supported: PrefixedIdentifierImpl •
          macro_application_argument_error
  error • main.dart:9:25 • Undefined name 'intValue'. Try correcting the
          name to one that is defined, or defining the name. •
          undefined_identifier
  error • main.dart:10:13 • Undefined name 'hello'. Try correcting the
          name to one that is defined, or defining the name. •
          undefined_identifier

3 issues found.
dart info

``` If providing this information as part of reporting a bug, please review the information below to ensure it only contains things you're comfortable posting publicly. #### General info - Dart 3.5.0-323.2.beta (beta) (Mon Jul 29 04:29:41 2024 +0000) on "macos_arm64" - on macos / Version 13.6 (Build 22G120) - locale is es-GE #### Process info | Memory | CPU | Elapsed time | Command line | | ------: | ---: | -----------: | ------------------------------------------------------------------------------------------ | | 14 MB | 0.0% | 03-23:17:43 | dart devtools --machine --dtd-uri=ws:/0vhzmGQ5d7QlMnqZ | | 16 MB | 0.0% | 05-03:07:32 | dart devtools --machine --dtd-uri=ws:/563fXWb9URFyRWt8 | | 7 MB | 0.0% | 14-07:14:59 | dart devtools --machine --dtd-uri=ws:/8cdxpf3B0Q1F9jFY | | 13 MB | 0.0% | 05-22:03:35 | dart devtools --machine --dtd-uri=ws:/LOjlfHO5jN4iJsR3 | | 17 MB | 0.0% | 04-22:47:06 | dart devtools --machine --dtd-uri=ws:/Sirkb3N4HiIZqC0o | | 68 MB | 0.0% | 17:21 | dart devtools --machine --dtd-uri=ws:/cqTYO8HCTYfhQ6HT | | 810 MB | 0.0% | 06:54:47 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 3021 MB | 0.0% | 02-23:07:02 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 697 MB | 0.0% | 17:22 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 191 MB | 0.0% | 05:07:38 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 145 MB | 0.0% | 05-03:07:33 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 120 MB | 0.0% | 03-23:17:45 | dart language-server --client-id=Android-Studio --client-version=AI-241.15989.150 --protocol=analyzer | | 8 MB | 0.0% | 14-07:14:59 | dart tooling-daemon --machine | | 83 MB | 0.0% | 17:21 | dart tooling-daemon --machine | | 17 MB | 0.0% | 05-03:07:32 | dart tooling-daemon --machine | | 12 MB | 0.0% | 03-23:17:43 | dart tooling-daemon --machine | | 19 MB | 0.0% | 05-22:03:35 | dart tooling-daemon --machine | | 20 MB | 0.0% | 04-22:47:06 | dart tooling-daemon --machine | | 55 MB | 0.1% | 02-23:09:53 | flutter_tools.snapshot daemon | | 53 MB | 0.1% | 02-23:09:53 | flutter_tools.snapshot daemon | | 53 MB | 0.1% | 02-23:09:53 | flutter_tools.snapshot daemon | | 52 MB | 0.0% | 02-23:09:53 | flutter_tools.snapshot daemon | | 101 MB | 0.2% | 17:25 | flutter_tools.snapshot daemon | ```

dart-github-bot commented 2 months ago

Summary: The issue is that macros cannot accept enum values as parameters, even though they can declare such parameters and have default values. This results in a macro_application_argument_error when passing an enum value as a macro parameter.

alexeyinkin commented 2 months ago

A workaround is to subclass the macro and hardcode a value for the parameter:

macro class MyMacroHello extends MyMacro {
  const MyMacroHello({
    super.intValue = 1,
  }) : super(enumValue: MyEnum.hello);

This should be done for each of the enum values you need.