dart-lang / sdk

The Dart SDK, including the VM, dart2js, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
9.95k stars 1.53k forks source link

Macros: resolveIdentifier does not resolve identifiers exported from other libraries #55910

Open alexeyinkin opened 1 month ago

alexeyinkin commented 1 month ago

If library main imports a library A, and A exports a library B, and a macro is augmenting main, then it can resolve identifiers from A but not B.

This example tries to resolve identifiers from args package. args/args.dart does not declare ArgParser class but exports it from src/arg_parser.dart. A macro fails to resolve this identifier in args/args.dart, but successfully resolves it in args/src/arg_parser.dart (and it's not a proper way because libraries under src are considered private).

main.dart:

import 'package:args/args.dart';
import 'macros.dart';

@Args()
class MyArgs {}

void main() {}

macro.dart:

import 'dart:async';
import 'package:macros/macros.dart';

final _argParserPrivateLibrary = Uri.parse('package:args/src/arg_parser.dart');
final _argsLibrary = Uri.parse('package:args/args.dart');

macro class Args implements ClassDeclarationsMacro {
  const Args();

  @override
  Future<void> buildDeclarationsForClass(ClassDeclaration clazz, MemberDeclarationBuilder builder) async {
    await builder.resolveIdentifier(_argParserPrivateLibrary, 'ArgParser'); // OK
    await builder.resolveIdentifier(_argsLibrary, 'ArgParserException'); // MacroImplementationExceptionImpl
  }
}

Output of dart --enable-experiment=macros run lib/main.dart:

lib/main.dart:4:2: Error: MacroImplementationExceptionImpl: Unable to find top level identifier "ArgParserException" in package:args/args.dart
null
@Args()
 ^
pubspec.yaml ```yaml name: args_macro_example environment: sdk: ^3.5.0-164 dependencies: args: ^2.5.0 meta: ^1.15.0 macros: ^0.1.0-main.5 ```
dart info ``` #### General info - Dart 3.5.0-180.2.beta (beta) (Wed May 29 13:59:09 2024 +0000) on "macos_arm64" - on macos / Version 13.6 (Build 22G120) - locale is en-GE #### Project info - sdk constraint: '^3.5.0-164' - dependencies: args, macros, meta - dev_dependencies: #### Process info | Memory | CPU | Elapsed time | Command line | | -----: | ---: | -----------: | ------------------------------------------------------------------------------------------ | | 9 MB | 0.0% | 17-00:11:03 | dart --enable-asserts --pause_isolates_on_start --enable-vm-service:51163 /main.dart | | 9 MB | 0.0% | 17-00:11:26 | dart --pause_isolates_on_start --enable-vm-service:51048 run test -r json /main_test.dart | | 10 MB | 0.0% | 72-17:35:11 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 77 MB | 0.0% | 02-03:32:15 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 175 MB | 0.0% | 04:48:58 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 10 MB | 0.0% | 47-22:18:37 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 10 MB | 0.0% | 237-19:22:21 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 13 MB | 0.0% | 240-18:19:54 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 479 MB | 0.0% | 32:47 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 158 MB | 0.0% | 02-22:55:29 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 13 MB | 0.0% | 18-18:31:53 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 220 MB | 0.0% | 02-20:00:27 | dart language-server --client-id=Android-Studio --client-version=AI-223.8836.35 --protocol=analyzer | | 18 MB | 0.0% | 05-23:20:06 | dart language-server --protocol=lsp --client-id=VS-Code --client-version=3.88.1 | | 12 MB | 0.0% | 05-23:20:06 | dart tooling-daemon --machine | | 56 MB | 0.4% | 04:48:59 | flutter_tools.snapshot daemon ```

This is reproducible for me on:

davidmorgan commented 1 month ago

Thanks! I had noticed this too, it is on a TODO list of mine somewhere to look into it :)

@scheglov @jakemac53 @johnniwinther I'm not sure where this sits in terms of specification / implementation; do we already specify that macros can refer to exported symbols instead of having to refer to the actual source location? If so--is this purely an implementation issue; and do we expect any problems? Thanks :)

scheglov commented 1 month ago

Yes, AFAIK it should by exported symbols, not only declared symbols. I know where the bug is in the analyzer :-)

scheglov commented 1 month ago

https://dart-review.googlesource.com/c/sdk/+/370102

davidmorgan commented 1 month ago

Thanks @scheglov! Then I think remaining is the corresponding CFE fix.