Mark Kernel classes that were Dart mixin declarations
Add a flag to Kernel classes that indicates that they were Dart mixin
declarations. Also, add an API to Kernel Class that allows a list of
superclass constraints to be gotten from it.
Change-Id: Ie78e7e56b5421dfb9d340e4330135b8d6f4e94f1
Reviewed-on: https://dart-review.googlesource.com/75261
Commit-Queue: Kevin Millikin <kmillikin@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
index e1eaa25..1efee63 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_enum_builder.dart
@@ -88,7 +88,8 @@
int startCharOffset,
int charOffset)
: super(metadata, 0, name, null, null, null, scope, constructors, parent,
- null, startCharOffset, charOffset, TreeNode.noOffset, cls);
+ null, startCharOffset, charOffset, TreeNode.noOffset,
+ cls: cls);
factory KernelEnumBuilder(
MetadataCollector metadataCollector,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
index 37562af..1ff9f83 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -62,7 +62,11 @@
import '../loader.dart' show Loader;
import '../modifier.dart'
- show abstractMask, namedMixinApplicationMask, staticMask;
+ show
+ abstractMask,
+ mixinDeclarationMask,
+ namedMixinApplicationMask,
+ staticMask;
import '../problems.dart' show unexpected, unhandled;
@@ -216,6 +220,11 @@
// library scope.
Scope constructorScope = new Scope(constructors, null, null, "constructors",
isModifiable: false);
+ bool isMixinDeclaration = false;
+ if (modifiers & mixinDeclarationMask != 0) {
+ isMixinDeclaration = true;
+ modifiers = (modifiers & ~mixinDeclarationMask) | abstractMask;
+ }
ClassBuilder cls = new SourceClassBuilder(
metadata,
modifiers,
@@ -230,7 +239,8 @@
new List<ConstructorReferenceBuilder>.from(constructorReferences),
startCharOffset,
charOffset,
- charEndOffset);
+ charEndOffset,
+ isMixinDeclaration: isMixinDeclaration);
loader.target.metadataCollector
?.setDocumentationComment(cls.target, documentationComment);
@@ -470,8 +480,7 @@
startCharOffset,
charOffset,
TreeNode.noOffset,
- null,
- mixin);
+ mixedInType: mixin);
if (isNamedMixinApplication) {
loader.target.metadataCollector?.setDocumentationComment(
application.target, documentationComment);
diff --git a/pkg/front_end/lib/src/fasta/modifier.dart b/pkg/front_end/lib/src/fasta/modifier.dart
index 4c4cb84..52f7017 100644
--- a/pkg/front_end/lib/src/fasta/modifier.dart
+++ b/pkg/front_end/lib/src/fasta/modifier.dart
@@ -32,6 +32,10 @@
const int namedMixinApplicationMask = staticMask << 1;
+/// Not a modifier, used for mixins declared explicitly by using the `mixin`
+/// keyword.
+const int mixinDeclarationMask = namedMixinApplicationMask << 1;
+
/// Not a real modifier, and by setting it to zero, it is automatically ignored
/// by [Modifier.validate] below.
const int varMask = 0;
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 620ce91..c7674c6 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -59,6 +59,7 @@
constMask,
covariantMask,
externalMask,
+ mixinDeclarationMask,
staticMask;
import '../operator.dart'
@@ -535,7 +536,7 @@
library.addClass(
documentationComment,
metadata,
- abstractMask,
+ mixinDeclarationMask,
name,
typeVariables,
supertype,
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 8df5e4a..97430ab 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -80,6 +80,8 @@
KernelTypeBuilder mixedInType;
+ bool isMixinDeclaration;
+
SourceClassBuilder(
List<MetadataBuilder> metadata,
int modifiers,
@@ -94,8 +96,9 @@
int startCharOffset,
int charOffset,
int charEndOffset,
- [ShadowClass cls,
- this.mixedInType])
+ {Class cls,
+ this.mixedInType,
+ this.isMixinDeclaration = false})
: actualCls = initializeClass(cls, typeVariables, name, parent,
startCharOffset, charOffset, charEndOffset),
super(metadata, modifiers, name, typeVariables, supertype, interfaces,
@@ -141,6 +144,7 @@
supertype?.buildSupertype(library, charOffset, fileUri);
actualCls.mixedInType =
mixedInType?.buildMixedInType(library, charOffset, fileUri);
+ actualCls.isMixinDeclaration = isMixinDeclaration;
// TODO(ahe): If `cls.supertype` is null, and this isn't Object, report a
// compile-time error.
cls.isAbstract = isAbstract;
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 9aa8b60..97faf8b 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -291,7 +291,7 @@
FileOffset fileOffset; // Offset of the name of the class.
FileOffset fileEndOffset;
Byte flags (levelBit0, levelBit1, isAbstract, isEnum, isAnonymousMixin,
- isEliminatedMixin); // Where level is index into ClassLevel
+ isEliminatedMixin, isMixinDeclaration); // Where level is index into ClassLevel
StringReference name;
List<Expression> annotations;
List<TypeParameter> typeParameters;
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 03a709a..90aa8c7 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -728,6 +728,7 @@
static const int FlagEnum = 1 << 3;
static const int FlagAnonymousMixin = 1 << 4;
static const int FlagEliminatedMixin = 1 << 5;
+ static const int FlagMixinDeclaration = 1 << 6;
int flags = 0;
@@ -774,6 +775,38 @@
value ? (flags | FlagEliminatedMixin) : (flags & ~FlagEliminatedMixin);
}
+ /// True if this class was a mixin declaration in Dart.
+ ///
+ /// Mixins are declared in Dart with the `mixin` keyword. They are compiled
+ /// to Kernel classes.
+ bool get isMixinDeclaration => flags & FlagMixinDeclaration != 0;
+
+ void set isMixinDeclaration(bool value) {
+ flags = value
+ ? (flags | FlagMixinDeclaration)
+ : (flags & ~FlagMixinDeclaration);
+ }
+
+ List<Supertype> superclassConstraints() {
+ var constraints = <Supertype>[];
+
+ // Not a mixin declaration.
+ if (!isMixinDeclaration) return constraints;
+
+ Class previous = this;
+ Class current = supertype.classNode;
+
+ // Otherwise we have a left-linear binary tree (subtrees are supertype and
+ // mixedInType) of constraints, where all the interior nodes are anonymous
+ // mixin applications.
+ while (current != null && current.isAnonymousMixin) {
+ constraints.add(current.mixedInType);
+ previous = current;
+ current = current.supertype.classNode;
+ }
+ return constraints..add(previous.supertype);
+ }
+
/// The URI of the source file this class was loaded from.
Uri fileUri;