diff --git a/pkg/kernel/lib/text/text_serialization_verifier.dart b/pkg/kernel/lib/text/text_serialization_verifier.dart index ee673a61b995..747920efc067 100644 --- a/pkg/kernel/lib/text/text_serialization_verifier.dart +++ b/pkg/kernel/lib/text/text_serialization_verifier.dart @@ -333,7 +333,6 @@ class VerificationState { node is Component || node is Constructor || node is Extension || - node is Field || node is FieldInitializer || node is InvalidInitializer || node is Library || @@ -474,8 +473,8 @@ class TextSerializationVerifier extends RecursiveVisitor { makeRoundTrip(node, argumentsSerializer); } else if (node is FunctionNode) { makeRoundTrip(node, functionNodeSerializer); - } else if (node is Procedure) { - makeRoundTrip(node, procedureSerializer); + } else if (node is Member) { + makeRoundTrip(node, memberSerializer); } else if (node is TypeParameter) { makeRoundTrip(node, typeParameterSerializer); } else if (node is NamedType) { diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart index 00316f626da1..4514bf79068b 100644 --- a/pkg/kernel/lib/text/text_serializer.dart +++ b/pkg/kernel/lib/text/text_serializer.dart @@ -799,76 +799,53 @@ Arguments wrapArguments( return new Arguments(tuple.second, types: tuple.first, named: tuple.third); } -class VariableDeclarationTagger implements Tagger { - const VariableDeclarationTagger(); - - String tag(VariableDeclaration decl) { - String prefix = ""; - if (decl.isCovariant) { - prefix = "${prefix}covariant-"; - if (decl.isFieldFormal) { - // Field formals can only be used in constructors, - // and "covariant" keyword doesn't make sense for them. - throw StateError("Encountered covariant field formal."); - } - } - if (decl.isFieldFormal) { - prefix = "${prefix}fieldformal-"; - } - - if (decl.isConst) { - // It's not clear what invariants we assume about const/final. For now - // throw if we have both. - if (decl.isFinal) { - throw UnimplementedError( - "Encountered a variable that is both const and final."); - } - return "${prefix}const"; - } - if (decl.isFinal) { - return "${prefix}final"; - } - return "${prefix}var"; +const Map variableDeclarationFlagToName = const { + VariableDeclaration.FlagFinal: "final", + VariableDeclaration.FlagConst: "const", + VariableDeclaration.FlagFieldFormal: "field-formal", + VariableDeclaration.FlagCovariant: "covariant", + VariableDeclaration.FlagInScope: "in-scope", + VariableDeclaration.FlagGenericCovariantImpl: "generic-covariant-impl", + VariableDeclaration.FlagLate: "late", + VariableDeclaration.FlagRequired: "required", +}; + +class VariableDeclarationFlagTagger implements Tagger { + String tag(IntLiteral wrappedFlag) { + int flag = wrappedFlag.value; + return variableDeclarationFlagToName[flag] ?? + (throw StateError("Unknown VariableDeclaration flag value: ${flag}.")); } } -TextSerializer makeVariableDeclarationSerializer( - {bool isFinal = false, - bool isConst = false, - bool isCovariant = false, - bool isFieldFormal = false}) => - new Wrapped( - (w) => Tuple3(w.type, w.initializer, w.annotations), - (u) => u.third.fold( - VariableDeclaration(null, - type: u.first, - initializer: u.second, - isFinal: isFinal, - isConst: isConst, - isCovariant: isCovariant, - isFieldFormal: isFieldFormal), - (v, a) => v..addAnnotation(a)), - Tuple3Serializer(dartTypeSerializer, new Optional(expressionSerializer), - new ListSerializer(expressionSerializer))); +TextSerializer variableDeclarationFlagsSerializer = Wrapped( + (w) => List.generate(30, (i) => IntLiteral(w & (1 << i))) + .where((f) => f.value != 0) + .toList(), + (u) => u.fold(0, (fs, f) => fs |= f.value), + ListSerializer(Case( + VariableDeclarationFlagTagger(), + Map.fromIterable(variableDeclarationFlagToName.entries, + key: (e) => e.value, + value: (e) => + Wrapped((_) => null, (_) => IntLiteral(e.key), Nothing()))))); TextSerializer variableDeclarationSerializer = Wrapped( (v) => Tuple2(v.name, v), (t) => t.second..name = t.first, - Binder(Case(VariableDeclarationTagger(), { - "var": makeVariableDeclarationSerializer(), - "final": makeVariableDeclarationSerializer(isFinal: true), - "const": makeVariableDeclarationSerializer(isConst: true), - "covariant-var": makeVariableDeclarationSerializer(isCovariant: true), - "covariant-final": - makeVariableDeclarationSerializer(isCovariant: true, isFinal: true), - "covariant-const": - makeVariableDeclarationSerializer(isCovariant: true, isConst: true), - "fieldformal-var": makeVariableDeclarationSerializer(isFieldFormal: true), - "fieldformal-final": - makeVariableDeclarationSerializer(isFieldFormal: true, isFinal: true), - "fieldformal-const": - makeVariableDeclarationSerializer(isFieldFormal: true, isConst: true), - }))); + Binder( + new Wrapped( + (w) => Tuple4(w.flags, w.type, w.initializer, w.annotations), + (u) => u.fourth.fold( + VariableDeclaration(null, + flags: u.first, type: u.second, initializer: u.third), + (v, a) => v..addAnnotation(a)), + Tuple4Serializer( + variableDeclarationFlagsSerializer, + dartTypeSerializer, + new Optional(expressionSerializer), + new ListSerializer(expressionSerializer))), + )); TextSerializer typeParameterSerializer = Wrapped( (p) => Tuple2(p.name, p), @@ -1593,36 +1570,112 @@ FunctionNode wrapSyncYieldingFunctionNode( Case functionNodeSerializer = new Case.uninitialized(const FunctionNodeTagger()); -class ProcedureTagger implements Tagger { - const ProcedureTagger(); - - String tag(Procedure node) { - String prefix = node.isStatic ? "static-" : ""; - switch (node.kind) { - case ProcedureKind.Method: - return "${prefix}method"; - default: - throw new UnsupportedError("${node.kind}"); - } +const Map procedureFlagToName = const { + Procedure.FlagStatic: "static", + Procedure.FlagAbstract: "abstract", + Procedure.FlagExternal: "external", + Procedure.FlagConst: "const", + Procedure.FlagForwardingStub: "forwarding-stub", + Procedure.FlagForwardingSemiStub: "forwarding-semi-stub", + Procedure.FlagRedirectingFactoryConstructor: + "redirecting-factory-constructor", + Procedure.FlagNoSuchMethodForwarder: "no-such-method-forwarder", + Procedure.FlagExtensionMember: "extension-member", + Procedure.FlagMemberSignature: "member-signature", + Procedure.FlagNonNullableByDefault: "non-nullable-by-default", +}; + +class ProcedureFlagTagger implements Tagger { + const ProcedureFlagTagger(); + + String tag(IntLiteral wrappedFlag) { + int flag = wrappedFlag.value; + return procedureFlagToName[flag] ?? + (throw StateError("Unknown Procedure flag value: ${flag}.")); } } -TextSerializer staticMethodSerializer = new Wrapped( - unwrapStaticMethod, - wrapStaticMethod, - new Tuple2Serializer(nameSerializer, functionNodeSerializer)); - -Tuple2 unwrapStaticMethod(Procedure procedure) { - return new Tuple2(procedure.name, procedure.function); +TextSerializer procedureFlagsSerializer = Wrapped( + (w) => List.generate(30, (i) => IntLiteral(w & (1 << i))) + .where((f) => f.value != 0) + .toList(), + (u) => u.fold(0, (fs, f) => fs |= f.value), + ListSerializer(Case( + ProcedureFlagTagger(), + Map.fromIterable(procedureFlagToName.entries, + key: (e) => e.value, + value: (e) => + Wrapped((_) => null, (_) => IntLiteral(e.key), Nothing()))))); + +const Map fieldFlagToName = const { + Field.FlagFinal: "final", + Field.FlagConst: "const", + Field.FlagStatic: "static", + Field.FlagHasImplicitGetter: "has-implicit-getter", + Field.FlagHasImplicitSetter: "has-implicit-setter", + Field.FlagCovariant: "covariant", + Field.FlagGenericCovariantImpl: "generic-covariant-impl", + Field.FlagLate: "late", + Field.FlagExtensionMember: "extension-member", + Field.FlagNonNullableByDefault: "non-nullable-by-default", + Field.FlagInternalImplementation: "internal-implementation", +}; + +class FieldFlagTagger implements Tagger { + const FieldFlagTagger(); + + String tag(IntLiteral wrappedFlag) { + int flag = wrappedFlag.value; + return fieldFlagToName[flag] ?? + (throw StateError("Unknown Field flag value: ${flag}.")); + } } -Procedure wrapStaticMethod(Tuple2 tuple) { - return new Procedure(tuple.first, ProcedureKind.Method, tuple.second, - isStatic: true); +TextSerializer fieldFlagsSerializer = Wrapped( + (w) => List.generate(30, (i) => IntLiteral(w & (1 << i))) + .where((f) => f.value != 0) + .toList(), + (u) => u.fold(0, (fs, f) => fs |= f.value), + ListSerializer(Case( + FieldFlagTagger(), + Map.fromIterable(fieldFlagToName.entries, + key: (e) => e.value, + value: (e) => + Wrapped((_) => null, (_) => IntLiteral(e.key), Nothing()))))); + +class MemberTagger implements Tagger { + const MemberTagger(); + + String tag(Member node) { + if (node is Field) { + return "field"; + } else if (node is Procedure) { + switch (node.kind) { + case ProcedureKind.Method: + return "method"; + default: + throw new UnsupportedError("${node.kind}"); + } + } else { + throw UnimplementedError("MemberTagger.tag(${node.runtimeType})"); + } + } } -Case procedureSerializer = - new Case.uninitialized(const ProcedureTagger()); +TextSerializer fieldSerializer = Wrapped( + (w) => Tuple4(w.name, w.flags, w.type, w.initializer), + (u) => + Field(u.first, type: u.third, initializer: u.fourth)..flags = u.second, + Tuple4Serializer(nameSerializer, fieldFlagsSerializer, dartTypeSerializer, + Optional(expressionSerializer))); + +TextSerializer methodSerializer = Wrapped( + (w) => Tuple3(w.name, w.flags, w.function), + (u) => Procedure(u.first, ProcedureKind.Method, u.third)..flags = u.second, + Tuple3Serializer( + nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); + +Case memberSerializer = new Case.uninitialized(const MemberTagger()); class LibraryTagger implements Tagger { const LibraryTagger(); @@ -1633,20 +1686,14 @@ class LibraryTagger implements Tagger { } TextSerializer libraryContentsSerializer = new Wrapped( - unwrapLibraryNode, - wrapLibraryNode, - new Tuple2Serializer( - const UriSerializer(), new ListSerializer(procedureSerializer)), + (w) => Tuple2(w.importUri, [...w.fields, ...w.procedures]), + (u) => Library(u.first, + fields: u.second.where((m) => m is Field).cast().toList(), + procedures: + u.second.where((m) => m is Procedure).cast().toList()), + new Tuple2Serializer(const UriSerializer(), ListSerializer(memberSerializer)), ); -Tuple2> unwrapLibraryNode(Library library) { - return new Tuple2(library.importUri, library.procedures); -} - -Library wrapLibraryNode(Tuple2> tuple) { - return new Library(tuple.first, procedures: tuple.second); -} - Case librarySerializer = new Case.uninitialized(const LibraryTagger()); class ShowHideTagger implements Tagger { @@ -1881,7 +1928,8 @@ void initializeSerializers() { "async-star": asyncStarFunctionNodeSerializer, "sync-yielding": syncYieldingStarFunctionNodeSerializer, }); - procedureSerializer.registerTags({"static-method": staticMethodSerializer}); + memberSerializer + .registerTags({"field": fieldSerializer, "method": methodSerializer}); librarySerializer.registerTags({ "legacy": libraryContentsSerializer, "null-safe": libraryContentsSerializer, diff --git a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart index 6c25315fb07c..aa5fe6d31668 100644 --- a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart +++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart @@ -66,7 +66,7 @@ void test() { return new ExpressionStatement(new Let(x, new VariableGet(x))); }(), expectation: '' - '(expr (let "x^0" (var (dynamic) (int 42) ())' + '(expr (let "x^0" () (dynamic) (int 42) ()' ' (get-var "x^0" _)))', serializer: statementSerializer), new TestCase( @@ -80,8 +80,8 @@ void test() { new Let(innerLetVar, new VariableGet(outterLetVar)))); }(), expectation: '' - '(expr (let "x^0" (var (dynamic) (int 42) ())' - ' (let "x^1" (var (bottom) (null) ())' + '(expr (let "x^0" () (dynamic) (int 42) ()' + ' (let "x^1" () (bottom) (null) ()' ' (get-var "x^0" _))))', serializer: statementSerializer), new TestCase( @@ -95,8 +95,8 @@ void test() { new Let(innerLetVar, new VariableGet(innerLetVar)))); }(), expectation: '' - '(expr (let "x^0" (var (dynamic) (int 42) ())' - ' (let "x^1" (var (bottom) (null) ())' + '(expr (let "x^0" () (dynamic) (int 42) ()' + ' (let "x^1" () (bottom) (null) ()' ' (get-var "x^1" _))))', serializer: statementSerializer), () { @@ -390,8 +390,8 @@ void test() { asyncMarker: AsyncMarker.Sync))), expectation: '' '(expr (fun (sync ("T^0") ((dynamic)) ((dynamic)) ("t1^1" ' - '(var (par "T^0" _) _ ())) ("t2^2" (var (par "T^0" _) ' - '_ ())) () (par "T^0" _) (ret (get-var "t1^1" _)))))', + '() (par "T^0" _) _ ()) ("t2^2" () (par "T^0" _) ' + '_ ()) () (par "T^0" _) (ret (get-var "t1^1" _)))))', makeSerializationState: () => new SerializationState(new SerializationEnvironment(null)), makeDeserializationState: () => new DeserializationState( @@ -410,18 +410,18 @@ void test() { procedures: [foo]); Component component = Component(libraries: [library]); component.computeCanonicalNames(); - return new TestCase( + return new TestCase( name: 'foo(x) => x;', node: foo, expectation: '' - '(static-method (public "foo")' - ' (sync () () () ("x^0" (var (dynamic) _ ())) () ()' + '(method (public "foo") ((static))' + ' (sync () () () ("x^0" () (dynamic) _ ()) () ()' ' (dynamic) (ret (get-var "x^0" _))))', makeSerializationState: () => new SerializationState(new SerializationEnvironment(null)), makeDeserializationState: () => new DeserializationState( new DeserializationEnvironment(null), null), - serializer: procedureSerializer); + serializer: memberSerializer); }(), () { VariableDeclaration x1 = VariableDeclaration('x', type: DynamicType()); @@ -450,12 +450,12 @@ void test() { expectation: '' '(legacy "package:foo/bar.dart"' '' - ' ((static-method (public "foo")' - ' (sync () () () ("x^0" (var (dynamic) _ ())) () () (dynamic)' + ' ((method (public "foo") ((static))' + ' (sync () () () ("x^0" () (dynamic) _ ()) () () (dynamic)' ' (ret (get-var "x^0" _))))' '' - ' (static-method (public "bar")' - ' (sync () () () ("x^0" (var (dynamic) _ ())) () () (dynamic)' + ' (method (public "bar") ((static))' + ' (sync () () () ("x^0" () (dynamic) _ ()) () () (dynamic)' ' (ret (invoke-static "package:foo/bar.dart::@methods::foo"' ' () ((get-var "x^0" _)) ()))))))', makeSerializationState: () => @@ -481,7 +481,7 @@ void test() { node: library, expectation: '' '(legacy "package:foo/bar.dart"' - ' ((static-method (public "foo")' + ' ((method (public "foo") ((static))' ' (sync () () () () () ()' ' (interface "package:foo/bar.dart::A" ())' ' (ret (null))))))', @@ -495,7 +495,7 @@ void test() { return new TestCase( name: 'dynamic x;', node: VariableDeclaration('x', type: const DynamicType()), - expectation: '(local "x^0" (var (dynamic) _ ()))', + expectation: '(local "x^0" () (dynamic) _ ())', makeSerializationState: () => new SerializationState(new SerializationEnvironment(null)), makeDeserializationState: () => new DeserializationState( diff --git a/pkg/kernel/test/text_serializer_test.dart b/pkg/kernel/test/text_serializer_test.dart index 2b79abb6791d..f4b363159520 100644 --- a/pkg/kernel/test/text_serializer_test.dart +++ b/pkg/kernel/test/text_serializer_test.dart @@ -47,12 +47,12 @@ class TestRunner { test('(invoke-method (int 0) (public "foo") () ((int 1) (int 2)) ())'); test('(invoke-method (int 0) (public "foo") ((dynamic) (void)) ' '((int 1) (int 2)) ("others" (list (dynamic) ((int 3) (int 4)))))'); - test('(let "x^0" (var (dynamic) (int 0) ()) (null))'); - test('(let "x^0" (var (dynamic) _ ()) (null))'); - test('(let "x^0" (const (dynamic) (int 0) ()) (null))'); - test('(let "x^0" (const (dynamic) _ ()) (null))'); - test('(let "x^0" (final (dynamic) (int 0) ()) (null))'); - test('(let "x^0" (final (dynamic) _ ()) (null))'); + test('(let "x^0" () (dynamic) (int 0) () (null))'); + test('(let "x^0" () (dynamic) _ () (null))'); + test('(let "x^0" ((const)) (dynamic) (int 0) () (null))'); + test('(let "x^0" ((const)) (dynamic) _ () (null))'); + test('(let "x^0" ((final)) (dynamic) (int 0) () (null))'); + test('(let "x^0" ((final)) (dynamic) _ () (null))'); test(r'''(string "Hello, 'string'!")'''); test(r'''(string "Hello, \"string\"!")'''); test(r'''(string "Yeah nah yeah, here is\nthis really long string haiku\n'''