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

mixin on a ClassMirror of a class which is the result of a mixin application of the form S with M doesn't work #33240

Closed
a-siva opened this issue May 25, 2018 · 4 comments
Assignees
Labels
area-front-end Use area-front-end for front end / CFE / kernel format related issues. front-end-kernel P1 A high priority bug; for example, a single project is unusable or has many test failures

Comments

@a-siva
Copy link
Contributor

a-siva commented May 25, 2018

The ClassMirror of a class which is the result of mixing application of the form S with M returns a class mirror of the reflectee and not the mixin.

The code below -

import 'dart:mirrors';
class Super {}
class Mixin {}
class Mixin2 {}
class Mixin3 {}
class MixinApplication = Super with Mixin;
class Class extends Super with Mixin {}
class MultipleMixins extends Super with Mixin, Mixin2, Mixin3 {}
main() {
  print(reflectClass(MixinApplication).mixin);
}

prints
"ClassMirror on 'Mixin'" when run with Dart 1 and
"ClassMirror on 'MixinApplication'" with Dart 2.

Cause - The mixin_ field in the RawClass object in the VM is not being correctly populated,
The kernel file does not have this information to be able to populate this field correctly when loading the kernel file in the VM.

@a-siva a-siva added P1 A high priority bug; for example, a single project is unusable or has many test failures area-kernel labels May 25, 2018
@a-siva a-siva added this to the Dart2Prerelease1 milestone May 25, 2018
@alexmarkov
Copy link
Contributor

The mixed-in type of a mixin application is not available as it is removed while mixins are de-sugared by kernel mixin transformation. This transformation erases mixed-in type and adds it into the list of interfaces.

In order to correctly implement dart:mirrors, CFE should leave some information about original mixed-in type and original list of interfaces in Dart sources, or at least inform VM about performed transformation. While keeping original mixed-in type and original list of interfaces is a cleaner solution, it will increase size of kernel binaries.

Instead of adding those fields, we can introduce 'isTransformedMixinApplication' flag and propagate it all the way to the dart:mirrors implementation. Using this flag, dart:mirrrors implementation can 'undo' the changes in mixed-in type and superinterfaces.

This solution is implemented here: https://dart-review.googlesource.com/c/sdk/+/56721.

@kmillikin please take a look. Can you suggest a better way of representing such information in kernel?

@kmillikin
Copy link

Just a quick comment because it's late.

That was exactly the intent of isSyntheticMixinApplication (https://codereview.chromium.org/2982373002) but it turns out that the implementation was incomplete. The flag was not documented in binary.md and was not set in all cases.

For classes marked as synthetic mixins, you should be able to rely on the superclass being the superclass and the mixed-in class being the only implemented interface.

Is there any reason that the VM needs to distinguish between "synthetic mixins" and "transformed mixins"? If not, I think a change like this should be sufficient on the Kernel side:

diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 13b28bf961..b3b35e54e4 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -286,7 +286,8 @@ type Class extends Node {
   UriReference fileUri;
   FileOffset fileOffset;
   FileOffset fileEndOffset;
-  Byte flags (isAbstract, isEnum, xx); // Where xx is index into ClassLevel
+  Byte flags (isAbstract, isEnum, isSyntheticMixinApplication,
+              xx); // Where xx is index into ClassLevel
   StringReference name;
   List<Expression> annotations;
   List<TypeParameter> typeParameters;
diff --git a/pkg/kernel/lib/transformations/mixin_full_resolution.dart b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
index a2f3926209..1b01660a1e 100644
--- a/pkg/kernel/lib/transformations/mixin_full_resolution.dart
+++ b/pkg/kernel/lib/transformations/mixin_full_resolution.dart
@@ -237,6 +237,7 @@ class MixinFullResolution {
 
     // This class is now a normal class.
     class_.mixedInType = null;
+    class_.isSyntheticMixinImplementation = true;
   }
 
   Constructor buildForwardingConstructor(

(We should probably consider updating the text format but that requires rebasing tests.)

@alexmarkov
Copy link
Contributor

Thank you for quick feedback!

We need a flag which covers mixin applications which were transformed to normal classes, including anonymous mixin applications and named mixin applications.

Synthetic mixin flag was not set for named mixin applications (mixin aliases):

application.cls.isSyntheticMixinImplementation =
!isNamedMixinApplication;

I was afraid to change the semantics of the isSyntheticMixinImplementation flag as other backends might not expect that:

bool get isUnnamedMixinApplication => cls.isSyntheticMixinImplementation;

Do you think it's a good idea to set 'isSyntheticMixinImplementation' for named mixin applications even though they are present in sources and not really synthetic?

AFAICT, currently VM doesn't use synthetic mixin application flag, but it could be need in future. For example, dart:mirrors implementation distinguishes between named and anonymous mixin applications for Dart 1 mixins, and eventually we might need this for desugared Dart 2 mixins as well.

Also, named mixin applications may have implemented interfaces, so mixed-in type is not the only type in their lists of interfaces.

Please advise how to proceed.

@kmillikin
Copy link

The VM is the only backend that uses the mixin elimination transformation. So the question is: does the VM need to distinguish between classes that were originally named or anonymous mixin applications. If not, we don't need a separate flag.

Dart2js only sees named (never anonymous) mixin applications. If it sees the flag on a named mixin application it knows that it was originally anonymous.

The VM only sees normal classes (never mixin applications). If it sees the flag on a normal class it knows it was originally a mixin application.

Is that sufficient? (The name is not great, but I can't think of anything that's much better so I'm inclined to just leave it for now.)

You're right about named mixing being able to implement interfaces. That means you can rely on there being at least one implementedType and implementedTypes.last is the original mixed-in type.

dart-bot pushed a commit that referenced this issue May 28, 2018
To implement dart:mirrors correctly, a backend like the VM needs to
know that a class was originally a mixin application.  Use the
`isSyntheticMixinImplementation` flag which was already there and
ignored by the VM.

Now the property is:

- if `isSyntheticMixinImplementation` is set on a class with a
  mixed-in type, then it was originally an anonymous mixin application

- if `isSyntheticMixinImplementation` is set on a normal class then it
  was originally a mixin application of some kind and the mixed-in
  type can be found as the last impelemented type

Bug: #33240
Change-Id: I004adc6bfe08e583efba8e511076a6c603c0c687
Reviewed-on: https://dart-review.googlesource.com/56760
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Kevin Millikin <kmillikin@google.com>
@kmillikin kmillikin added area-front-end Use area-front-end for front end / CFE / kernel format related issues. front-end-kernel and removed area-front-end Use area-front-end for front end / CFE / kernel format related issues. labels Sep 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-front-end Use area-front-end for front end / CFE / kernel format related issues. front-end-kernel P1 A high priority bug; for example, a single project is unusable or has many test failures
Projects
None yet
Development

No branches or pull requests

3 participants