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.08k stars 1.56k forks source link

Macro with explicit "dart:core" import doesn't work #56478

Open Sadhorsephile opened 4 weeks ago

Sadhorsephile commented 4 weeks ago

Problem

Cannot launch the project with the following macro:

Macro ```dart import 'dart:async'; import 'package:macros/macros.dart'; macro class ExampleMacro implements MethodDeclarationsMacro, MethodDefinitionMacro { const ExampleMacro(); @override FutureOr buildDeclarationsForMethod(MethodDeclaration method, MemberDeclarationBuilder builder) async { builder.declareInLibrary(DeclarationCode.fromString('import \'dart:core\';')); } @override FutureOr buildDefinitionForMethod(MethodDeclaration method, FunctionDefinitionBuilder builder) async { builder.augment(FunctionBodyCode.fromString('{ final String foo = "foo";}')); } } ```
Example ```dart import 'package:test_macros/reproduce/macro.dart'; class SomeClass { @ExampleMacro() external void testMethod(String id); } void main() { SomeClass().testMethod(''); } ```

I have no analyzer errors, but I get errors when I run it:

org-dartlang-augmentation:/_/test_macros/lib/reproduce/example.dart-1:6:56: Error: 'String' isn't a type.
  augment void testMethod(prefix0.String id, ) { final String foo = "foo";}

As I see it, the problem is the use of twoString types - prefix0.String from 'dart:core' as prefix0 and String from dart:core.

Additional info

dart info output:

#### General info

- Dart 3.5.0-180.3.beta (beta) (Wed Jun 5 15:06:15 2024 +0000) on "macos_arm64"
- on macos / Version 14.4.1 (Build 23E224)
- locale is en-RU

#### Project info

- sdk constraint: '^3.5.0-180'
- dependencies: collection, dio, flutter, json, macros, provider
- dev_dependencies: flutter_lints, flutter_test
dart-github-bot commented 4 weeks ago

Summary: The macro fails to correctly import dart:core when using DeclarationCode.fromString('import \'dart:core\';'). This results in a runtime error because the generated code references String from both dart:core and the imported dart:core as a prefix, leading to a type conflict.

lrhn commented 4 weeks ago

This does sound like a bug, relative to the current specification of part files with imports. It may be correct relative to the prior specification of augmentation libraries that this specification replaces.

The implicit import of dart:core of a library file only happens if you do not explicitly import dart:core in the library file, with or without a prefix. There is no implicit import of dart:core in part files, they inherit the imports of the parent file, and an explicit import of dart:core in a part file should not affect the import of dart:core in the library file. Imports in part files can always shadow imports inherited from the parent file, so there is no need to prevent the inheritance.

What looks to be happening here is that the import of dart:core with a prefix makes the implicit import of dart:core go away. (Which makes sense for the prior augmentation-library specification, where each augmentation library was treated as having its own implicit import of dart:core.)

It shouldn't work like that, but "parts with imports" is likely not implemented yet.

It's not that there are two string types, rather there is no String name imported into the top-level scope at all. That's why the error is "String is not a type".