Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TargetKind has no value for representing a type parameter #49796

Closed
mateusfccp opened this issue Aug 23, 2022 · 20 comments
Closed

TargetKind has no value for representing a type parameter #49796

mateusfccp opened this issue Aug 23, 2022 · 20 comments
Assignees
Labels
analyzer-pkg-meta Issues related to package:meta area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-enhancement A request for a change that isn't a bug

Comments

@mateusfccp
Copy link
Contributor

The Dart specification says:

Metadata can appear before a library, part header, class, typedef, type parameter, constructor, factory, function, parameter, or variable declaration, and before an import, export, or part directive.

This is also the way it's implemented, such that

class A<@Annotation T> {}

is valid code.

However, TargetKind lacks any value that may represent this case.

I propose creating a TargetKind.typeParameter to fulfill this necessity.

@mateusfccp
Copy link
Contributor Author

I may implement this, as long as I have some guidance on this, as AFAIK we are going to have to make changes in many places and I am not sure if I know everything that has to been changed.

I know of the following places where we are going to have to change:

  • meta package, where the annotation is defined;
  • analyzer package, specially the _isValidTarget method.

Is there anywhere else?

@lrhn
Copy link
Member

lrhn commented Aug 24, 2022

The TargetKind "enum" should probably not be an enum because it's likely that it will need to be extended in the future (say, when we add struct, view, macro, etc. declarations to the language, and want to be able to target those too).

Adding members to an enum makes existing switches over the values non-exhaustive, so it's a breaking change.
It's probably safer to just make it a normal class with some constant instances, which can be added to in the future without making code not compile (and that code will likely have needed to add a default case already, so it's ready for the change).

It'll be a breaking change to make it so, but at least it should only be one break.
(And any code which would most likely break from that change would also break from adding typeParameter as a value anyway.)

@lrhn lrhn added area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. analyzer-pkg-meta Issues related to package:meta labels Aug 24, 2022
@mateusfccp
Copy link
Contributor Author

Are you proposing that this change be done in the same PR or should we open a different PR for this? Also, should we open a tracking issue?

@srawlins
Copy link
Member

CC @bwilkerson @pq for the idea of changing TargetKind from an enum. I think it's a good idea.

@srawlins srawlins added the P3 A lower priority bug or feature request label Aug 26, 2022
@bwilkerson
Copy link
Member

I have no objection to changing it.

@srawlins
Copy link
Member

srawlins commented Aug 26, 2022

I know of the following places where we are going to have to change:

  • meta package, where the annotation is defined;
  • analyzer package, specially the _isValidTarget method.

Is there anywhere else?

I think that covers it! We accept PRs.

@mateusfccp
Copy link
Contributor Author

mateusfccp commented Aug 26, 2022

Thanks, @srawlins.

Do I turn the enum into a class in the same PR as the one including the new value?

@srawlins
Copy link
Member

I think that would be fine; they're related insofar as: adding typeParameter would be a breaking change, but changing it to a class will make it not breaking. 🤷

@pq
Copy link
Member

pq commented Aug 29, 2022

SGTM too!

@mateusfccp
Copy link
Contributor Author

I am working on it!

@mateusfccp
Copy link
Contributor Author

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

I am not sure if I did everything right... testing it through the analyzer example worked for me, but I am having some issues setting up a reliable environment for dart-sdk, so I am afraid that I didn't test exactly as expected.

@srawlins
Copy link
Member

srawlins commented Sep 8, 2022

@bwilkerson do you think it is a breaking change to make an enum into a const class with a constructor?

(Of course given that we have no definition of breaking change and Hyrum's Law etc.) I can't think of a way that it is breaking.

@bwilkerson
Copy link
Member

There's a chance that it isn't. I was assuming that it was because someone I respect said that it was, but it's possible that they were wrong. I can't think of any case where the enum could have been used in a way that isn't compatible with the class.

@mateusfccp
Copy link
Contributor Author

There's a chance that it isn't. I was assuming that it was because someone I respect said that it was, but it's possible that they were wrong. I can't think of any case where the enum could have been used in a way that isn't compatible with the class.

If someone uses the enum in a switch the static analysis won't required a default case if it is exhaustive. In this specific case, won't add a new value break the switch? Although I think it's improbable that someone is using it this way.

@srawlins
Copy link
Member

srawlins commented Sep 9, 2022

@mateusfccp you've got it. It will trigger "body_might_complete_normally" when flow analysis (or definite assignment) detects the missing default case here:

int f2(E2 e2) {
  switch (e2) {
    case E2.one: return 1;
    case E2.two: return 2;
  }
}

@srawlins
Copy link
Member

srawlins commented Sep 9, 2022

I think it might be most pragmatic to release this "breaking change" in a non-major release. Similar to the Dart and Flutter SDKs.

In this code, if E is an enum with two values:

int f(E e) {
  switch (e) {
    case E.one: return 1;
    case E.two: return 2;
    default: return 3;
  }
}

we can include the default case whether E is an enum or not. (In other words, whether the other cases are exhaustive or not.) (This is probably a hole in the analyzer: such a default should be reported as dead_code if the above cases are exhaustive.)

So we can pre-migrate clients to use default.

@bwilkerson
Copy link
Member

Pre-migrating clients, where we can, sounds good to me. I'm not sure how widely TargetKind is used in this way, but hopefully it's rare.

That said, the last time we made a breaking change without bumping the major version number (we didn't realize it was a breaking change) it caused a lot of pain for the community. While this will hopefully be less impactful, I'm still not sure it's a wise thing to do. Of course, releasing a new major version won't be without pain, so we need to balance the two.

@srawlins
Copy link
Member

srawlins commented Sep 9, 2022

Yeah I believe releasing a new major version is more pain.

@mateusfccp
Copy link
Contributor Author

I commented this on the PR, but no one answered, so maybe here it will get more visibility.

I am trying to fix the tests, but I am having problem running them in my local machine. Maybe I didn't set up properly the environment.

I followed the "Contributing" and "Building" documentation and I can build the source with no issues. However, when running dart test on pkg/analyzer directory, the following error happens:

mateusfccp@ArchPinto ~/D/d/s/p/analyzer (add_type_parameter_to_target_kind)> dart test
Building package executable... (6.3s)
Failed to build test:test:
../../../../../.pub-cache/hosted/pub.dartlang.org/test_core-0.4.11/lib/src/runner/parse_metadata.dart:223:46: Error: The getter 'type2' isn't defined for the class 'ConstructorName'.
 - 'ConstructorName' is from 'package:analyzer/dart/ast/ast.dart' ('lib/dart/ast/ast.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'type2'.
                  expression.constructorName.type2.name,
                                             ^^^^^
../../../../../.pub-cache/hosted/pub.dartlang.org/test_core-0.4.11/lib/src/runner/parse_metadata.dart:359:64: Error: The getter 'type2' isn't defined for the class 'ConstructorName'.
 - 'ConstructorName' is from 'package:analyzer/dart/ast/ast.dart' ('lib/dart/ast/ast.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'type2'.
    var pair = _resolveConstructor(constructor.constructorName.type2.name,
                                                               ^^^^^
Failed to build test:test:
../../../../../.pub-cache/hosted/pub.dartlang.org/test_core-0.4.11/lib/src/runner/parse_metadata.dart:223:46: Error: The getter 'type2' isn't defined for the class 'ConstructorName'.
 - 'ConstructorName' is from 'package:analyzer/dart/ast/ast.dart' ('lib/dart/ast/ast.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'type2'.
                  expression.constructorName.type2.name,
                                             ^^^^^
../../../../../.pub-cache/hosted/pub.dartlang.org/test_core-0.4.11/lib/src/runner/parse_metadata.dart:359:64: Error: The getter 'type2' isn't defined for the class 'ConstructorName'.
 - 'ConstructorName' is from 'package:analyzer/dart/ast/ast.dart' ('lib/dart/ast/ast.dart').
Try correcting the name to the name of an existing getter, or defining a getter or field named 'type2'.
    var pair = _resolveConstructor(constructor.constructorName.type2.name,
                                                               ^^^^^

I automatically though that the issue was that I was using the local dart, so I made an alias (dart-md) to call out/DebugX64/dart instead.

Using it, I got the following error:

…eusfccp@ArchPinto ~/D/d/s/p/analyzer (add_type_parameter_to_target_kind) [65]  dart-md test
Building package executable... Could not find a command named "$HOME/Development/dart-sdk/sdk/out/bin/snapshots/frontend_server.dart.snapshot".

For some reason, the executable is trying to get the snapshots from out/bin/snapshots. I verified that they exist in out/DebugX64/, so I made a symbolic link.

Now, I am getting the following:

mateusfccp@ArchPinto ~/D/d/s/p/analyzer (add_type_parameter_to_target_kind)> dart-md test
Building package executable... (4.0s)Unhandled exception:
Crash when compiling null,
at character offset null:
Bad state: No element
#0      List.single (dart:core-patch/growable_array.dart:353:22)
#1      ClassBuilderImpl.buildAliasedTypeWithBuiltArguments (package:front_end/src/fasta/builder/class_builder.dart:326:44)
#2      ClassBuilderImpl.buildAliasedType (package:front_end/src/fasta/builder/class_builder.dart:349:12)
#3      NamedTypeBuilder._buildAliasedInternal (package:front_end/src/fasta/builder/named_type_builder.dart:417:25)
#4      NamedTypeBuilder.buildAliased (package:front_end/src/fasta/builder/named_type_builder.dart:411:12)
#5      FunctionTypeBuilder.buildAliased (package:front_end/src/fasta/builder/function_type_builder.dart:125:20)
#6      FunctionTypeBuilder._buildInternal (package:front_end/src/fasta/builder/function_type_builder.dart:115:28)
#7      _ExplicitFunctionTypeBuilder.build (package:front_end/src/fasta/builder/function_type_builder.dart:233:22)
#8      FormalParameterBuilder.build (package:front_end/src/fasta/builder/formal_parameter_builder.dart:152:34)
#9      SourceFunctionBuilderImpl.buildFunction (package:front_end/src/fasta/source/source_function_builder.dart:344:48)
#10     SourceFactoryBuilder._build (package:front_end/src/fasta/source/source_factory_builder.dart:144:5)
#11     SourceFactoryBuilder.buildOutlineNodes (package:front_end/src/fasta/source/source_factory_builder.dart:136:5)
#12     SourceClassBuilder.build.buildBuilders (package:front_end/src/fasta/source/source_class_builder.dart:204:14)
#13     IteratorExtension.forEach (package:front_end/src/fasta/scope.dart:1204:8)
#14     SourceClassBuilder.build (package:front_end/src/fasta/source/source_class_builder.dart:214:41)
#15     SourceLibraryBuilder._buildOutlineNodes (package:front_end/src/fasta/source/source_library_builder.dart:3085:31)
#16     SourceLibraryBuilder.buildOutlineNodes (package:front_end/src/fasta/source/source_library_builder.dart:1079:7)
#17     SourceLoader.buildOutlineNodes (package:front_end/src/fasta/source/source_loader.dart:2037:32)
#18     KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:476:14)
<asynchronous suspension>
#19     withCrashReporting (package:front_end/src/fasta/crash.dart:122:12)
<asynchronous suspension>
#20     IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:407:33)
<asynchronous suspension>
#21     IncrementalCompiler.compile (package:vm/incremental_compiler.dart:68:50)
<asynchronous suspension>
#22     FrontendCompiler.compile (package:frontend_server/frontend_server.dart:572:11)
<asynchronous suspension>
#23     listenAndCompile.<anonymous closure> (package:frontend_server/frontend_server.dart:1223:11)
<asynchronous suspension>


#0      List.single (dart:core-patch/growable_array.dart:353:22)
#1      ClassBuilderImpl.buildAliasedTypeWithBuiltArguments (package:front_end/src/fasta/builder/class_builder.dart:326:44)
#2      ClassBuilderImpl.buildAliasedType (package:front_end/src/fasta/builder/class_builder.dart:349:12)
#3      NamedTypeBuilder._buildAliasedInternal (package:front_end/src/fasta/builder/named_type_builder.dart:417:25)
#4      NamedTypeBuilder.buildAliased (package:front_end/src/fasta/builder/named_type_builder.dart:411:12)
#5      FunctionTypeBuilder.buildAliased (package:front_end/src/fasta/builder/function_type_builder.dart:125:20)
#6      FunctionTypeBuilder._buildInternal (package:front_end/src/fasta/builder/function_type_builder.dart:115:28)
#7      _ExplicitFunctionTypeBuilder.build (package:front_end/src/fasta/builder/function_type_builder.dart:233:22)
#8      FormalParameterBuilder.build (package:front_end/src/fasta/builder/formal_parameter_builder.dart:152:34)
#9      SourceFunctionBuilderImpl.buildFunction (package:front_end/src/fasta/source/source_function_builder.dart:344:48)
#10     SourceFactoryBuilder._build (package:front_end/src/fasta/source/source_factory_builder.dart:144:5)
#11     SourceFactoryBuilder.buildOutlineNodes (package:front_end/src/fasta/source/source_factory_builder.dart:136:5)
#12     SourceClassBuilder.build.buildBuilders (package:front_end/src/fasta/source/source_class_builder.dart:204:14)
#13     IteratorExtension.forEach (package:front_end/src/fasta/scope.dart:1204:8)
#14     SourceClassBuilder.build (package:front_end/src/fasta/source/source_class_builder.dart:214:41)
#15     SourceLibraryBuilder._buildOutlineNodes (package:front_end/src/fasta/source/source_library_builder.dart:3085:31)
#16     SourceLibraryBuilder.buildOutlineNodes (package:front_end/src/fasta/source/source_library_builder.dart:1079:7)
#17     SourceLoader.buildOutlineNodes (package:front_end/src/fasta/source/source_loader.dart:2037:32)
#18     KernelTarget.buildOutlines.<anonymous closure> (package:front_end/src/fasta/kernel/kernel_target.dart:476:14)
<asynchronous suspension>
#19     withCrashReporting (package:front_end/src/fasta/crash.dart:122:12)
<asynchronous suspension>
#20     IncrementalCompiler.computeDelta.<anonymous closure> (package:front_end/src/fasta/incremental_compiler.dart:407:33)
<asynchronous suspension>
#21     IncrementalCompiler.compile (package:vm/incremental_compiler.dart:68:50)
<asynchronous suspension>
#22     FrontendCompiler.compile (package:frontend_server/frontend_server.dart:572:11)
<asynchronous suspension>
#23     listenAndCompile.<anonymous closure> (package:frontend_server/frontend_server.dart:1223:11)
<asynchronous suspension>
(4.1s)
Built test:test.
Can't load Kernel binary: Invalid kernel binary format version.

I feel like I missed something when setting up the development environment... Is there any documentation that maybe I missed?

@bwilkerson
Copy link
Member

I commented this on the PR, but no one answered ...

I'm sorry I missed your question on the PR, sometimes I miss the notifications when PRs are updated. Thanks for reaching out again.

However, when running dart test on pkg/analyzer directory, the following error happens:

It looks to me like there's a version mismatch between the version of package analyzer that the package test is depending on and the version of analyzer that's actually being used. I haven't seen that happen and I'm not sure how it could, but that's my best guess from what I'm seeing.

Personally, I never use dart test to run the analyzer tests. I always run either the file containing the tests I'm interested in or one of the test_all.dart files in the test directory. (Each test_all.dart file runs the tests in the directory that contains it, including all of the tests in child directories.) That gives me a fair bit of control over which tests are run. When I want more control I add a @soloTest annotation before the specific test methods that I want to run. Also, I run them from the IDE so that I can add breakpoints and use the debugger to debug the tests.

I'm not sure how to resolve the issue you're seeing, but perhaps running the test files directly will work around the problem.

copybara-service bot pushed a commit that referenced this issue Nov 4, 2022
…rgetKind to represent type parameter

Bug: #49796
Change-Id: Ide144ceb57bae94a71b9d1a7ec841d03363fc121
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258200
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
copybara-service bot pushed a commit that referenced this issue Nov 7, 2022
…ue in TargetKind to represent type parameter"

This reverts commit 82143e6.

Reason for revert: This commit appears to have negatively affected the analyze benchmark:

* https://golem.corp.goog/Revision?repository=flutter-analyze&team=dartanalyzer&revision=114193

We need to revert and analyze it.

Original change's description:
> [analyzer][meta] Refactor TargetKind to be a class, add a value in TargetKind to represent type parameter
>
> Bug: #49796
> Change-Id: Ide144ceb57bae94a71b9d1a7ec841d03363fc121
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/258200
> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: #49796
Change-Id: I6ec04ffe8d85c417d138626ffa4f1a7ac7dafe2b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268380
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
@srawlins srawlins added the type-enhancement A request for a change that isn't a bug label Mar 14, 2024
@srawlins srawlins self-assigned this Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
analyzer-pkg-meta Issues related to package:meta area-analyzer Use area-analyzer for Dart analyzer issues, including the analysis server and code completion. P3 A lower priority bug or feature request type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

5 participants