Coder Social home page Coder Social logo

Comments (9)

scheglov avatar scheglov commented on June 27, 2024

I can reproduce this.
image

Code

import 'package:macro_test/macro_test.dart';

@ControllerMacro()
class MyControllerText {
  @CustomAnnotation()
  void main() {}
}

class CustomAnnotation {
  const CustomAnnotation();
}

The reason it crashes is that the macro attempts to access the identifier @CustomAnnotation during the declarations phase. At this time this identifier is not resolved yet - we resolve metadata after the declarations phase, but before the definitions phase.

The reason we cannot resolve annotations until after the declarations phase is that resolution potentially depends on constructors that might be added at any point during the declarations phase.

From the macro API implementation inside the analyzer we don't have any better solution than to throw - macro.ResolvedIdentifier resolveIdentifier() must return something, and if the identifier cannot be resolved, there is nothing to return.

@jakemac53 For any API suggestions.

from sdk.

scheglov avatar scheglov commented on June 27, 2024

With https://dart-review.googlesource.com/c/sdk/+/366966 we will tell the name of the unresolved identifier.

Theoretically we know much more - the exact AST node (so the offset), and the content of the file. So, if this happens regularly, we can provide more details to simplify identification of the problematic identifier.

from sdk.

jakemac53 avatar jakemac53 commented on June 27, 2024

The reason we cannot resolve annotations until after the declarations phase is that resolution potentially depends on constructors that might be added at any point during the declarations phase.

The type is definitely already known, and it seems like we should be able to then know the assumed "identifier" for any constructor (it must be a const constructor with that name on that known type). So, while you can't tie the constructor identifier to a specific AST node or element, we should know everything we need to know to output a reference to that identifier as Code, which is the important part (the import URI for it plus the scope (class name) and the name of the constructor)?

from sdk.

scheglov avatar scheglov commented on June 27, 2024

True, we should be able to resolve the type element.

from sdk.

scheglov avatar scheglov commented on June 27, 2024

BTW, here is the script that I use to see if the example runs well, and generated code.

import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';

void main() async {
  var collection = AnalysisContextCollectionImpl(
    includedPaths: [
      '/Users/scheglov/tmp/2024-05-17/AnalyzerCrashResolveIdentifier/lib/controller.dart',
    ],
  );

  var timer = Stopwatch()..start();
  for (var analysisContext in collection.contexts) {
    print(analysisContext.contextRoot.root.path);
    var analysisSession = analysisContext.currentSession;
    for (var path in analysisContext.contextRoot.analyzedFiles()) {
      if (path.endsWith('.dart')) {
        var libResult = await analysisSession.getResolvedLibrary(path);
        if (libResult is ResolvedLibraryResult) {
          for (var unitResult in libResult.units) {
            print('    ${unitResult.path}');
            var ep = '\n        ';
            print('      errors:$ep${unitResult.errors.join(ep)}');
            print('---');
            print(unitResult.content);
            print('---');
          }
        }
      }
    }
  }
  print('[time: ${timer.elapsedMilliseconds} ms]');

  await collection.dispose();
}

from sdk.

scheglov avatar scheglov commented on June 27, 2024

https://dart-review.googlesource.com/c/sdk/+/366895 fixes the crash.

from sdk.

helightdev avatar helightdev commented on June 27, 2024

The solution now indeed works for the const constructor annotations, though using a reference to a global const field still results in a crash.

import 'package:macro_test/macro_test.dart';

@ControllerMacro()
class MyControllerText {
  @CustomAnnotation()
  @refAnnotation
  void main() {

  }
}

class CustomAnnotation {
  const CustomAnnotation();
}

const refAnnotation = CustomAnnotation();

This code now fails with

Invalid argument(s): Unresolved identifier: ref
#0      DeclarationBuilder.resolveIdentifier (package:analyzer/src/summary2/macro_declarations.dart:308:9)
#1      _Builder._buildIdentifier (package:_macros/src/executor/augmentation_library.dart:73:53)
#2      _Builder._buildCode (package:_macros/src/executor/augmentation_library.dart:133:9)
#3      _Builder._buildCode (package:_macros/src/executor/augmentation_library.dart:131:9)
#4      _Builder.build (package:_macros/src/executor/augmentation…

As expected since 2fa0501 now outputs the reference to the offending identifier.

Could there be a possibility to also assume the identifier code of the const field similarly to how constructor identifiers are assumed or is this not possible with the information known in the declaration phase? Reading @jakemac53's explanation on how this is possible for constructors also let's me assume this is possible for const fields, since we should know both the import uri of the const field's library as well as the name of the global field.

from sdk.

scheglov avatar scheglov commented on June 27, 2024

During the declarations phase we cannot resolve identifiers that are not guaranteed to be names of types.
Because resolution @refAnnotation could change if the next macro will declare refAnnotation in this library.
Of course we technically can do this in the analyzer, but the result might be sometimes surprising.

My reading of @jakemac53 comment "you can't tie the constructor identifier to a specific AST node or element" - we don't know the element, but this does not matter because we can output the constructor name, and regardless what it is, it will be the same as the referenced by the annotation.

from sdk.

helightdev avatar helightdev commented on June 27, 2024

Ah okay I see the problem. So if I want to have declarative macros which are copying metadata, this will only work for const constructor invocations. Thanks for clarifying!

from sdk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.