Add wrappers for macro arguments to help with serialization.

In particular this allows us to reproduce type arguments for collections in the
macro expansion isolate.

The type arguments have to be explicitly given for collection types,
but this should be doable given they are all constants and only certain
types are allowed.

Bug: https://github.com/dart-lang/language/issues/2212
Change-Id: I14a688ed294cf060c004849efa975b5bef053d5b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/308202
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
index f143d27..9db6e9c 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/bootstrap.dart
@@ -200,9 +200,11 @@
           'macro class "\${request.name}".');
     }
 
-    var instance = Function.apply(constructor, request.arguments.positional, {
-      for (MapEntry<String, Object?> entry in request.arguments.named.entries)
-        new Symbol(entry.key): entry.value,
+    var instance = Function.apply(constructor, [
+      for (var argument in request.arguments.positional) argument.value,
+    ], {
+      for (MapEntry<String, Argument> entry in request.arguments.named.entries)
+        new Symbol(entry.key): entry.value.value,
     }) as Macro;
     var identifier = new MacroInstanceIdentifierImpl(instance, request.instanceId);
     _macroInstances[identifier] = instance;
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
index 00c3b59..e88947d 100644
--- a/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor.dart
@@ -2,11 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:dart_internal/extract_type_arguments.dart';
+import 'package:meta/meta.dart';
+
 import 'api.dart';
 // ignore: unused_import
 import 'bootstrap.dart'; // For doc comments only.
 import 'executor/serialization.dart';
 
+part 'executor/arguments.dart';
+
 /// The interface used by Dart language implementations, in order to load
 /// and execute macros, as well as produce library augmentations from those
 /// macro applications.
@@ -86,146 +91,6 @@
   Future<void> close();
 }
 
-/// The arguments passed to a macro constructor.
-///
-/// All argument instances must be of type [Code] or a built-in value type that
-/// is serializable (num, bool, String, null, etc).
-class Arguments implements Serializable {
-  final List<Object?> positional;
-
-  final Map<String, Object?> named;
-
-  Arguments(this.positional, this.named);
-
-  factory Arguments.deserialize(Deserializer deserializer) {
-    deserializer
-      ..moveNext()
-      ..expectList();
-    List<Object?> positionalArgs = [
-      for (bool hasNext = deserializer.moveNext();
-          hasNext;
-          hasNext = deserializer.moveNext())
-        _deserializeArg(deserializer, alreadyMoved: true),
-    ];
-    deserializer
-      ..moveNext()
-      ..expectList();
-    Map<String, Object?> namedArgs = {
-      for (bool hasNext = deserializer.moveNext();
-          hasNext;
-          hasNext = deserializer.moveNext())
-        deserializer.expectString(): _deserializeArg(deserializer),
-    };
-    return new Arguments(positionalArgs, namedArgs);
-  }
-
-  static Object? _deserializeArg(Deserializer deserializer,
-      {bool alreadyMoved = false}) {
-    if (!alreadyMoved) deserializer.moveNext();
-    _ArgumentKind kind = _ArgumentKind.values[deserializer.expectInt()];
-    return switch (kind) {
-      _ArgumentKind.nil => null,
-      _ArgumentKind.string => (deserializer..moveNext()).expectString(),
-      _ArgumentKind.bool => (deserializer..moveNext()).expectBool(),
-      _ArgumentKind.int => (deserializer..moveNext()).expectInt(),
-      _ArgumentKind.double => (deserializer..moveNext()).expectDouble(),
-      _ArgumentKind.list => [
-          for (bool hasNext = (deserializer
-                    ..moveNext()
-                    ..expectList())
-                  .moveNext();
-              hasNext;
-              hasNext = deserializer.moveNext())
-            _deserializeArg(deserializer, alreadyMoved: true),
-        ],
-      _ArgumentKind.set => {
-          for (bool hasNext = (deserializer
-                    ..moveNext()
-                    ..expectList())
-                  .moveNext();
-              hasNext;
-              hasNext = deserializer.moveNext())
-            _deserializeArg(deserializer, alreadyMoved: true),
-        },
-      _ArgumentKind.map => {
-          for (bool hasNext = (deserializer
-                    ..moveNext()
-                    ..expectList())
-                  .moveNext();
-              hasNext;
-              hasNext = deserializer.moveNext())
-            _deserializeArg(deserializer, alreadyMoved: true):
-                _deserializeArg(deserializer),
-        },
-    };
-  }
-
-  @override
-  void serialize(Serializer serializer) {
-    serializer.startList();
-    for (Object? arg in positional) {
-      _serializeArg(arg, serializer);
-    }
-    serializer.endList();
-
-    serializer.startList();
-    for (MapEntry<String, Object?> arg in named.entries) {
-      serializer.addString(arg.key);
-      _serializeArg(arg.value, serializer);
-    }
-    serializer.endList();
-  }
-
-  static void _serializeArg(Object? arg, Serializer serializer) {
-    if (arg == null) {
-      serializer.addInt(_ArgumentKind.nil.index);
-    } else if (arg is String) {
-      serializer
-        ..addInt(_ArgumentKind.string.index)
-        ..addString(arg);
-    } else if (arg is int) {
-      serializer
-        ..addInt(_ArgumentKind.int.index)
-        ..addInt(arg);
-    } else if (arg is double) {
-      serializer
-        ..addInt(_ArgumentKind.double.index)
-        ..addDouble(arg);
-    } else if (arg is bool) {
-      serializer
-        ..addInt(_ArgumentKind.bool.index)
-        ..addBool(arg);
-    } else if (arg is List) {
-      serializer
-        ..addInt(_ArgumentKind.list.index)
-        ..startList();
-      for (Object? item in arg) {
-        _serializeArg(item, serializer);
-      }
-      serializer.endList();
-    } else if (arg is Set) {
-      serializer
-        ..addInt(_ArgumentKind.set.index)
-        ..startList();
-      for (Object? item in arg) {
-        _serializeArg(item, serializer);
-      }
-      serializer.endList();
-    } else if (arg is Map) {
-      serializer
-        ..addInt(_ArgumentKind.map.index)
-        ..startList();
-      for (MapEntry<Object?, Object?> entry in arg.entries) {
-        _serializeArg(entry.key, serializer);
-        _serializeArg(entry.value, serializer);
-      }
-      serializer.endList();
-    } else {
-      throw new UnsupportedError('Unsupported argument type $arg');
-    }
-  }
-}
-
 /// A resolved [Identifier], this is used when creating augmentation libraries
 /// to qualify identifiers where needed.
 class ResolvedIdentifier implements Identifier {
@@ -325,15 +190,3 @@
   /// This phase allows augmenting existing declarations.
   definitions,
 }
-
-/// Used for serializing and deserializing arguments.
-enum _ArgumentKind {
-  string,
-  bool,
-  double,
-  int,
-  list,
-  map,
-  set,
-  nil,
-}
diff --git a/pkg/_fe_analyzer_shared/lib/src/macros/executor/arguments.dart b/pkg/_fe_analyzer_shared/lib/src/macros/executor/arguments.dart
new file mode 100644
index 0000000..4783299
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/lib/src/macros/executor/arguments.dart
@@ -0,0 +1,424 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of '../executor.dart';
+
+/// Representation of an argument to a macro constructor.
+sealed class Argument implements Serializable {
+  ArgumentKind get kind;
+
+  Object? get value;
+
+  Argument();
+
+  /// Reads the next argument from [Deserializer].
+  ///
+  /// By default this will call `moveNext` on [deserializer] before reading the
+  /// argument kind, but this can be skipped by passing `true` for
+  /// [alreadyMoved].
+  factory Argument.deserialize(Deserializer deserializer,
+      {bool alreadyMoved = false}) {
+    if (!alreadyMoved) deserializer.moveNext();
+    final ArgumentKind kind = ArgumentKind.values[deserializer.expectInt()];
+    return switch (kind) {
+      ArgumentKind.string =>
+        new StringArgument((deserializer..moveNext()).expectString()),
+      ArgumentKind.bool =>
+        new BoolArgument((deserializer..moveNext()).expectBool()),
+      ArgumentKind.double =>
+        new DoubleArgument((deserializer..moveNext()).expectDouble()),
+      ArgumentKind.int =>
+        new IntArgument((deserializer..moveNext()).expectInt()),
+      ArgumentKind.list ||
+      ArgumentKind.set =>
+        new _IterableArgument._deserialize(kind, deserializer),
+      ArgumentKind.map => new MapArgument._deserialize(deserializer),
+      ArgumentKind.nil => new NullArgument(),
+      // These are just for type arguments and aren't supported as actual args.\
+      ArgumentKind.object ||
+      ArgumentKind.dynamic ||
+      ArgumentKind.num ||
+      ArgumentKind.nullable =>
+        throw new StateError('Argument kind $kind is not deserializable'),
+    };
+  }
+
+  @override
+  @mustBeOverridden
+  @mustCallSuper
+  void serialize(Serializer serializer) {
+    serializer.addInt(kind.index);
+  }
+
+  @override
+  String toString() => '$runtimeType:$value';
+}
+
+final class BoolArgument extends Argument {
+  @override
+  ArgumentKind get kind => ArgumentKind.bool;
+
+  @override
+  final bool value;
+
+  BoolArgument(this.value);
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.addBool(value);
+  }
+}
+
+final class DoubleArgument extends Argument {
+  @override
+  ArgumentKind get kind => ArgumentKind.double;
+
+  @override
+  final double value;
+
+  DoubleArgument(this.value);
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.addDouble(value);
+  }
+}
+
+final class IntArgument extends Argument {
+  @override
+  ArgumentKind get kind => ArgumentKind.int;
+
+  @override
+  final int value;
+
+  IntArgument(this.value);
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.addInt(value);
+  }
+}
+
+final class NullArgument extends Argument {
+  @override
+  ArgumentKind get kind => ArgumentKind.nil;
+
+  @override
+  Null get value => null;
+
+  @override
+  void serialize(Serializer serializer) => super.serialize(serializer);
+}
+
+final class StringArgument extends Argument {
+  @override
+  ArgumentKind get kind => ArgumentKind.string;
+
+  @override
+  final String value;
+
+  StringArgument(this.value);
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.addString(value);
+  }
+}
+
+abstract base class _CollectionArgument extends Argument {
+  /// Flat list of the actual reified type arguments for this list, in the order
+  /// they would appear if written in code.
+  ///
+  /// For nullable types, they should be preceded by an [ArgumentKind.nullable].
+  ///
+  /// Note that nested type arguments appear here and are just flattened, so
+  /// the type `List<Map<String, List<int>?>>` would have the type arguments:
+  ///
+  /// [
+  ///   ArgumentKind.map,
+  ///   ArgumentKind.string,
+  ///   ArgumentKind.nullable,
+  ///   ArgumentKind.list,
+  ///   ArgumentKind.int,
+  /// ]
+  final List<ArgumentKind> _typeArguments;
+
+  _CollectionArgument(this._typeArguments);
+
+  /// Creates a one or two element list, based on [_typeArguments]. These lists
+  /// each contain reified generic type arguments that match the serialized
+  /// [_typeArguments].
+  ///
+  /// You can extract the type arguments to build up the actual collection type
+  /// that you need.
+  ///
+  /// For an iterable, this will always have a single value, and for a map it
+  /// will always have two values.
+  List<List<Object?>> _extractTypeArguments() {
+    List<List<Object?>> typedInstanceStack = [];
+
+    // We build up the list type backwards.
+    for (ArgumentKind type in _typeArguments.reversed) {
+      typedInstanceStack.add(switch (type) {
+        ArgumentKind.bool => const <bool>[],
+        ArgumentKind.double => const <double>[],
+        ArgumentKind.int => const <int>[],
+        ArgumentKind.map =>
+          extractIterableTypeArgument(typedInstanceStack.removeLast(), <K>() {
+            return extractIterableTypeArgument(typedInstanceStack.removeLast(),
+                <V>() {
+              return new List<Map<K, V>>.empty();
+            });
+          }) as List<Object?>,
+        ArgumentKind.nil => const <Null>[],
+        ArgumentKind.set =>
+          extractIterableTypeArgument(typedInstanceStack.removeLast(), <S>() {
+            return new List<Set<S>>.empty();
+          }) as List<Object?>,
+        ArgumentKind.string => const <String>[],
+        ArgumentKind.list =>
+          extractIterableTypeArgument(typedInstanceStack.removeLast(), <S>() {
+            return new List<List<S>>.empty();
+          }) as List<Object?>,
+        ArgumentKind.object => const <Object>[],
+        ArgumentKind.dynamic => const <dynamic>[],
+        ArgumentKind.num => const <num>[],
+        ArgumentKind.nullable =>
+          extractIterableTypeArgument(typedInstanceStack.removeLast(), <S>() {
+            return new List<S?>.empty();
+          }) as List<Object?>,
+      });
+    }
+
+    return typedInstanceStack;
+  }
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.startList();
+    for (ArgumentKind typeArgument in _typeArguments) {
+      serializer.addInt(typeArgument.index);
+    }
+    serializer.endList();
+  }
+}
+
+/// The base class for [ListArgument] and [SetArgument], most of the logic is
+/// the same.
+abstract base class _IterableArgument<T extends Iterable<Object?>>
+    extends _CollectionArgument {
+  /// These are the raw argument values for each entry in this iterable.
+  final List<Argument> _arguments;
+
+  _IterableArgument(this._arguments, super._typeArguments);
+
+  factory _IterableArgument._deserialize(
+      ArgumentKind kind, Deserializer deserializer) {
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final List<ArgumentKind> typeArguments = [
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        ArgumentKind.values[deserializer.expectInt()],
+    ];
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final List<Argument> values = [
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        new Argument.deserialize(deserializer, alreadyMoved: true),
+    ];
+    return switch (kind) {
+      ArgumentKind.list => new ListArgument(values, typeArguments),
+      ArgumentKind.set => new SetArgument(values, typeArguments),
+      _ => throw new UnsupportedError(
+          'Could not deserialize argument of kind $kind'),
+    } as _IterableArgument<T>;
+  }
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.startList();
+    for (Argument argument in _arguments) {
+      argument.serialize(serializer);
+    }
+    serializer.endList();
+  }
+}
+
+final class ListArgument extends _IterableArgument<List<Object?>> {
+  @override
+  ArgumentKind get kind => ArgumentKind.list;
+
+  /// Materializes all the `_arguments` as actual values.
+  @override
+  List<Object?> get value {
+    return extractIterableTypeArgument(_extractTypeArguments().single, <S>() {
+      return <S>[for (Argument arg in _arguments) arg.value as S];
+    }) as List<Object?>;
+  }
+
+  ListArgument(super._arguments, super._typeArguments);
+
+  @override
+  void serialize(Serializer serializer) => super.serialize(serializer);
+}
+
+final class SetArgument extends _IterableArgument<Set<Object?>> {
+  @override
+  ArgumentKind get kind => ArgumentKind.set;
+
+  /// Materializes all the `_arguments` as actual values.
+  @override
+  Set<Object?> get value {
+    return extractIterableTypeArgument(_extractTypeArguments().single, <S>() {
+      return <S>{for (Argument arg in _arguments) arg.value as S};
+    }) as Set<Object?>;
+  }
+
+  SetArgument(super._arguments, super._typeArguments);
+
+  @override
+  void serialize(Serializer serializer) => super.serialize(serializer);
+}
+
+final class MapArgument extends _CollectionArgument {
+  @override
+  ArgumentKind get kind => ArgumentKind.map;
+
+  /// These are the raw argument values for the entries in this map.
+  final Map<Argument, Argument> _arguments;
+
+  /// Materializes all the `_arguments` as actual values.
+  @override
+  Map<Object?, Object?> get value {
+    // We should have exactly two type arguments, the key and value types.
+    final List<List<Object?>> extractedTypes = _extractTypeArguments();
+    assert(extractedTypes.length == 2);
+    return extractIterableTypeArgument(extractedTypes.removeLast(), <K>() {
+      return extractIterableTypeArgument(extractedTypes.removeLast(), <V>() {
+        return <K, V>{
+          for (MapEntry<Argument, Argument> argument in _arguments.entries)
+            argument.key.value as K: argument.value.value as V,
+        };
+      });
+    }) as Map<Object?, Object?>;
+  }
+
+  MapArgument(this._arguments, super._typeArguments);
+
+  factory MapArgument._deserialize(Deserializer deserializer) {
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final List<ArgumentKind> typeArguments = [
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        ArgumentKind.values[deserializer.expectInt()],
+    ];
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final Map<Argument, Argument> arguments = {
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        new Argument.deserialize(deserializer, alreadyMoved: true):
+            new Argument.deserialize(deserializer),
+    };
+    return new MapArgument(arguments, typeArguments);
+  }
+
+  @override
+  void serialize(Serializer serializer) {
+    super.serialize(serializer);
+    serializer.startList();
+    for (MapEntry<Argument, Argument> argument in _arguments.entries) {
+      argument.key.serialize(serializer);
+      argument.value.serialize(serializer);
+    }
+    serializer.endList();
+  }
+}
+
+/// The arguments passed to a macro constructor.
+///
+/// All argument instances must be of type [Code] or a built-in value type that
+/// is serializable (num, bool, String, null, etc).
+class Arguments implements Serializable {
+  final List<Argument> positional;
+
+  final Map<String, Argument> named;
+
+  Arguments(this.positional, this.named);
+
+  factory Arguments.deserialize(Deserializer deserializer) {
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final List<Argument> positionalArgs = [
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        new Argument.deserialize(deserializer, alreadyMoved: true),
+    ];
+    deserializer
+      ..moveNext()
+      ..expectList();
+    final Map<String, Argument> namedArgs = {
+      for (bool hasNext = deserializer.moveNext();
+          hasNext;
+          hasNext = deserializer.moveNext())
+        deserializer.expectString(): new Argument.deserialize(deserializer),
+    };
+    return new Arguments(positionalArgs, namedArgs);
+  }
+
+  @override
+  void serialize(Serializer serializer) {
+    serializer.startList();
+    for (Argument arg in positional) {
+      arg.serialize(serializer);
+    }
+    serializer.endList();
+
+    serializer.startList();
+    for (MapEntry<String, Argument> arg in named.entries) {
+      serializer.addString(arg.key);
+      arg.value.serialize(serializer);
+    }
+    serializer.endList();
+  }
+}
+
+/// Used for serializing and deserializing arguments.
+///
+/// Note that the `nullable` variants, as well as `object`, `dynamic`, and `num`
+/// are only used for type arguments. Instances should have an argument kind
+/// that matches their their actual value.
+enum ArgumentKind {
+  bool,
+  string,
+  double,
+  int,
+  list,
+  map,
+  set,
+  nil,
+  object,
+  dynamic,
+  num,
+  nullable,
+}
diff --git a/pkg/_fe_analyzer_shared/pubspec.yaml b/pkg/_fe_analyzer_shared/pubspec.yaml
index 9326bd8..d1df4d4 100644
--- a/pkg/_fe_analyzer_shared/pubspec.yaml
+++ b/pkg/_fe_analyzer_shared/pubspec.yaml
@@ -7,6 +7,7 @@
   sdk: ^3.0.0
 
 dependencies:
+  dart_internal: ^0.2.7
   meta: ^1.0.2
 
 # We use 'any' version constraints here as we get our package versions from
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart
index 776abaa..94cabdc 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor/executor_test.dart
@@ -92,7 +92,7 @@
                 reason: 'Can create an instance with no arguments.');
 
             instanceId = await executor.instantiateMacro(
-                macroUri, macroName, '', Arguments([1], {}));
+                macroUri, macroName, '', Arguments([IntArgument(1)], {}));
             expect(instanceId, isNotNull,
                 reason: 'Can create an instance with positional arguments.');
 
@@ -101,23 +101,33 @@
                 macroName,
                 'named',
                 Arguments([], {
-                  'myBool': true,
-                  'myDouble': 1.0,
-                  'myInt': 1,
-                  'myList': [
-                    1,
-                    2,
-                    3,
-                  ],
-                  'mySet': {
-                    true,
-                    null,
-                    {'a': 1.0}
-                  },
-                  'myMap': {
-                    'x': 1,
-                  },
-                  'myString': 'a',
+                  'myBool': BoolArgument(true),
+                  'myDouble': DoubleArgument(1.0),
+                  'myInt': IntArgument(1),
+                  'myList': ListArgument([
+                    IntArgument(1),
+                    IntArgument(2),
+                    IntArgument(3),
+                  ], [
+                    ArgumentKind.nullable,
+                    ArgumentKind.int
+                  ]),
+                  'mySet': SetArgument([
+                    BoolArgument(true),
+                    NullArgument(),
+                    MapArgument({StringArgument('a'): DoubleArgument(1.0)},
+                        [ArgumentKind.string, ArgumentKind.double]),
+                  ], [
+                    ArgumentKind.nullable,
+                    ArgumentKind.object,
+                  ]),
+                  'myMap': MapArgument({
+                    StringArgument('x'): IntArgument(1),
+                  }, [
+                    ArgumentKind.string,
+                    ArgumentKind.int
+                  ]),
+                  'myString': StringArgument('a'),
                 }));
             expect(instanceId, isNotNull,
                 reason: 'Can create an instance with named arguments.');
diff --git a/pkg/_fe_analyzer_shared/test/macros/executor/serialization_test.dart b/pkg/_fe_analyzer_shared/test/macros/executor/serialization_test.dart
index 6ecb6bc..5958981 100644
--- a/pkg/_fe_analyzer_shared/test/macros/executor/serialization_test.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/executor/serialization_test.dart
@@ -3,10 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:_fe_analyzer_shared/src/macros/api.dart';
+import 'package:_fe_analyzer_shared/src/macros/executor.dart';
 import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart';
 import 'package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart';
 import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
-import 'package:_fe_analyzer_shared/src/macros/executor/serialization_extensions.dart';
 import 'package:test/test.dart';
 
 import '../util.dart';
@@ -156,7 +156,8 @@
     ]) {
       group('with mode $mode', () {
         test('NamedTypeAnnotation', () {
-          expectSerializationEquality(fooType, mode);
+          expectSerializationEquality<TypeAnnotationImpl>(
+              fooType, mode, RemoteInstance.deserialize);
         });
 
         final fooNamedParam = ParameterDeclarationImpl(
@@ -214,7 +215,8 @@
             returnType: fooType,
             typeParameters: [zapTypeParam],
           );
-          expectSerializationEquality(functionType, mode);
+          expectSerializationEquality<TypeAnnotationImpl>(
+              functionType, mode, RemoteInstance.deserialize);
         });
 
         test('FunctionDeclaration', () {
@@ -231,7 +233,8 @@
               positionalParameters: [],
               returnType: fooType,
               typeParameters: []);
-          expectSerializationEquality(function, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              function, mode, RemoteInstance.deserialize);
         });
 
         test('MethodDeclaration', () {
@@ -250,7 +253,8 @@
               typeParameters: [zapTypeParam],
               definingType: fooType.identifier,
               isStatic: false);
-          expectSerializationEquality(method, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              method, mode, RemoteInstance.deserialize);
         });
 
         test('ConstructorDeclaration', () {
@@ -270,7 +274,8 @@
             definingType: fooType.identifier,
             isFactory: true,
           );
-          expectSerializationEquality(constructor, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              constructor, mode, RemoteInstance.deserialize);
         });
 
         test('VariableDeclaration', () {
@@ -283,7 +288,8 @@
             isLate: true,
             type: barType,
           );
-          expectSerializationEquality(bar, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              bar, mode, RemoteInstance.deserialize);
         });
 
         test('FieldDeclaration', () {
@@ -298,7 +304,8 @@
             definingType: fooType.identifier,
             isStatic: false,
           );
-          expectSerializationEquality(bar, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              bar, mode, RemoteInstance.deserialize);
         });
 
         var objectType = NamedTypeAnnotationImpl(
@@ -334,7 +341,8 @@
               superclass: objectType,
               typeParameters: [zapTypeParam],
             );
-            expectSerializationEquality(fooClass, mode);
+            expectSerializationEquality<DeclarationImpl>(
+                fooClass, mode, RemoteInstance.deserialize);
           }
         });
 
@@ -347,7 +355,8 @@
             mixins: [serializableType],
             typeParameters: [zapTypeParam],
           );
-          expectSerializationEquality(fooEnum, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              fooEnum, mode, RemoteInstance.deserialize);
         });
 
         test('EnumValueDeclaration', () {
@@ -357,7 +366,8 @@
             definingEnum:
                 IdentifierImpl(id: RemoteInstance.uniqueId, name: 'MyEnum'),
           );
-          expectSerializationEquality(entry, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              entry, mode, RemoteInstance.deserialize);
         });
 
         test('MixinDeclaration', () {
@@ -371,7 +381,8 @@
               superclassConstraints: [serializableType],
               typeParameters: [zapTypeParam],
             );
-            expectSerializationEquality(mixin, mode);
+            expectSerializationEquality<DeclarationImpl>(
+                mixin, mode, RemoteInstance.deserialize);
           }
         });
 
@@ -388,7 +399,8 @@
                     IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
                 typeArguments: [barType]),
           );
-          expectSerializationEquality(typeAlias, mode);
+          expectSerializationEquality<DeclarationImpl>(
+              typeAlias, mode, RemoteInstance.deserialize);
         });
 
         /// Transitively tests [RecordField]
@@ -415,17 +427,135 @@
               ),
             ],
           );
-          expectSerializationEquality(recordType, mode);
+          expectSerializationEquality<TypeAnnotationImpl>(
+              recordType, mode, RemoteInstance.deserialize);
         });
       });
     }
   });
+
+  group('Arguments', () {
+    test('can create properly typed collections', () {
+      withSerializationMode(SerializationMode.jsonClient, () {
+        final parsed = Arguments.deserialize(deserializerFactory([
+          // positional args
+          [
+            // int
+            ArgumentKind.int.index,
+            1,
+            // List<int>
+            ArgumentKind.list.index,
+            [ArgumentKind.int.index],
+            [
+              ArgumentKind.int.index,
+              1,
+              ArgumentKind.int.index,
+              2,
+              ArgumentKind.int.index,
+              3,
+            ],
+            // List<Set<String>>
+            ArgumentKind.list.index,
+            [ArgumentKind.set.index, ArgumentKind.string.index],
+            [
+              // Set<String>
+              ArgumentKind.set.index,
+              [ArgumentKind.string.index],
+              [
+                ArgumentKind.string.index,
+                'hello',
+                ArgumentKind.string.index,
+                'world',
+              ]
+            ],
+            // Map<int, List<String>>
+            ArgumentKind.map.index,
+            [
+              ArgumentKind.int.index,
+              ArgumentKind.nullable.index,
+              ArgumentKind.list.index,
+              ArgumentKind.string.index
+            ],
+            [
+              // key: int
+              ArgumentKind.int.index,
+              4,
+              // value: List<String>
+              ArgumentKind.list.index,
+              [ArgumentKind.string.index],
+              [
+                ArgumentKind.string.index,
+                'zip',
+              ],
+              ArgumentKind.int.index,
+              5,
+              ArgumentKind.nil.index,
+            ]
+          ],
+          // named args
+          [],
+        ]));
+        expect(parsed.positional.length, 4);
+        expect(parsed.positional.first.value, 1);
+        expect(parsed.positional[1].value, [1, 2, 3]);
+        expect(parsed.positional[1].value, isA<List<int>>());
+        expect(parsed.positional[2].value, [
+          {'hello', 'world'}
+        ]);
+        expect(parsed.positional[2].value, isA<List<Set<String>>>());
+        expect(
+          parsed.positional[3].value,
+          {
+            4: ['zip'],
+            5: null,
+          },
+        );
+        expect(parsed.positional[3].value, isA<Map<int, List<String>?>>());
+      });
+    });
+
+    group('can be serialized and deserialized', () {
+      for (var mode in [
+        SerializationMode.byteDataServer,
+        SerializationMode.jsonServer
+      ]) {
+        test('with mode $mode', () {
+          final arguments = Arguments([
+            MapArgument({
+              StringArgument('hello'): ListArgument(
+                  [BoolArgument(true), NullArgument()],
+                  [ArgumentKind.nullable, ArgumentKind.bool]),
+            }, [
+              ArgumentKind.string,
+              ArgumentKind.list,
+              ArgumentKind.nullable,
+              ArgumentKind.bool
+            ]),
+          ], {
+            'a': SetArgument([
+              MapArgument({
+                IntArgument(1): StringArgument('1'),
+              }, [
+                ArgumentKind.int,
+                ArgumentKind.string
+              ])
+            ], [
+              ArgumentKind.map,
+              ArgumentKind.int,
+              ArgumentKind.string
+            ])
+          });
+          expectSerializationEquality(arguments, mode, Arguments.deserialize);
+        });
+      }
+    });
+  });
 }
 
 /// Serializes [serializable] in server mode, then deserializes it in client
 /// mode, and checks that all the fields are the same.
-void expectSerializationEquality(
-    Serializable serializable, SerializationMode serverMode) {
+void expectSerializationEquality<T extends Serializable>(T serializable,
+    SerializationMode serverMode, T deserialize(Deserializer deserializer)) {
   late Object? serialized;
   withSerializationMode(serverMode, () {
     var serializer = serializerFactory();
@@ -434,14 +564,18 @@
   });
   withSerializationMode(_clientModeForServerMode(serverMode), () {
     var deserializer = deserializerFactory(serialized);
-    var deserialized = (deserializer..moveNext()).expectRemoteInstance();
-    if (deserialized is Declaration) {
-      expect(serializable, deepEqualsDeclaration(deserialized));
-    } else if (deserialized is TypeAnnotation) {
-      expect(serializable, deepEqualsTypeAnnotation(deserialized));
-    } else {
-      throw new UnsupportedError('Unsupported object type $deserialized');
-    }
+    var deserialized = deserialize(deserializer);
+
+    expect(
+        serializable,
+        (switch (deserialized) {
+          Declaration() => deepEqualsDeclaration(deserialized as Declaration),
+          TypeAnnotation() =>
+            deepEqualsTypeAnnotation(deserialized as TypeAnnotation),
+          Arguments() => deepEqualsArguments(deserialized),
+          _ =>
+            throw new UnsupportedError('Unsupported object type $deserialized'),
+        }));
   });
 }
 
@@ -449,8 +583,7 @@
 Object? roundTrip<Declaration>(Object? serialized) {
   return withSerializationMode(_clientModeForServerMode(serializationMode), () {
     var deserializer = deserializerFactory(serialized);
-    var instance =
-        RemoteInstance.deserialize<NamedTypeAnnotationImpl>(deserializer);
+    var instance = RemoteInstance.deserialize(deserializer);
     var serializer = serializerFactory();
     instance.serialize(serializer);
     return serializer.result;
diff --git a/pkg/_fe_analyzer_shared/test/macros/util.dart b/pkg/_fe_analyzer_shared/test/macros/util.dart
index 8605b35..66ad515 100644
--- a/pkg/_fe_analyzer_shared/test/macros/util.dart
+++ b/pkg/_fe_analyzer_shared/test/macros/util.dart
@@ -175,6 +175,10 @@
 Matcher deepEqualsTypeAnnotation(TypeAnnotation declaration) =>
     _DeepEqualityMatcher(declaration);
 
+/// Checks if two [Arguments]s are identical
+Matcher deepEqualsArguments(Arguments arguments) =>
+    _DeepEqualityMatcher(arguments);
+
 /// Checks if two [Declaration]s, [TypeAnnotation]s, or [Code] objects are of
 /// the same type and all their fields are equal.
 class _DeepEqualityMatcher extends Matcher {
@@ -187,10 +191,11 @@
 
   @override
   bool matches(item, Map matchState) {
-    if (item.runtimeType != instance.runtimeType) {
+    // For type promotion.
+    final instance = this.instance;
+    if (!equals(item.runtimeType).matches(instance.runtimeType, matchState)) {
       return false;
     }
-
     if (instance is Declaration || instance is TypeAnnotation) {
       var instanceReflector = reflect(instance);
       var itemReflector = reflect(item);
@@ -206,47 +211,52 @@
         var instanceValue = instanceField.reflectee;
         var itemValue = itemField.reflectee;
 
-        // Handle lists of things
-        if (instanceValue is List) {
-          if (!_listEquals(instanceValue, itemValue, matchState)) {
-            return false;
-          }
-        } else if (instanceValue is Declaration ||
-            instanceValue is Code ||
-            instanceValue is TypeAnnotation) {
-          // Handle nested declarations and code objects
-          if (!_DeepEqualityMatcher(instanceValue)
-              .matches(itemValue, matchState)) {
-            return false;
-          }
-        } else {
-          // Handles basic values and identity
-          if (instanceValue != itemValue) {
-            return false;
-          }
+        if (!_DeepEqualityMatcher(instanceValue)
+            .matches(itemValue, matchState)) {
+          return false;
         }
       }
     } else if (instance is Code) {
-      if (!_listEquals(
-          (instance as Code).parts, (item as Code).parts, matchState)) {
+      item as Code;
+      if (!_DeepEqualityMatcher(instance.parts)
+          .matches(item.parts, matchState)) {
         return false;
       }
+    } else if (instance is Arguments) {
+      item as Arguments;
+      if (!equals(instance.positional.length)
+          .matches(item.positional.length, matchState)) {
+        return false;
+      }
+      for (var i = 0; i < instance.positional.length; i++) {
+        if (!_DeepEqualityMatcher(instance.positional[i].value)
+            .matches(item.positional[i].value, matchState)) {
+          return false;
+        }
+      }
+      if (instance.named.length != item.named.length) return false;
+      if (!equals(instance.named.keys).matches(item.named.keys, matchState)) {
+        return false;
+      }
+      for (var key in instance.named.keys) {
+        if (!_DeepEqualityMatcher(instance.named[key]!.value)
+            .matches(item.named[key]!.value, matchState)) {
+          return false;
+        }
+      }
+    } else if (instance is List) {
+      item as List;
+      if (!equals(instance.length).matches(item.length, matchState)) {
+        return false;
+      }
+      for (var i = 0; i < instance.length; i++) {
+        if (!_DeepEqualityMatcher(instance[i]).matches(item[i], matchState)) {
+          return false;
+        }
+      }
     } else {
       // Handles basic values and identity
-      if (instance != item) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  bool _listEquals(List instanceValue, List itemValue, Map matchState) {
-    if (instanceValue.length != itemValue.length) {
-      return false;
-    }
-    for (var i = 0; i < instanceValue.length; i++) {
-      if (!_DeepEqualityMatcher(instanceValue[i])
-          .matches(itemValue[i], matchState)) {
+      if (!equals(instance).matches(item, matchState)) {
         return false;
       }
     }
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart
index 943c543..af999eb 100644
--- a/pkg/analyzer/lib/src/summary2/macro_application.dart
+++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -22,6 +22,47 @@
 import 'package:analyzer/src/summary2/macro_declarations.dart';
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 
+/// The full list of [macro.ArgumentKind]s for this dart type (includes the type
+/// itself as well as type arguments, in source order with
+/// [macro.ArgumentKind.nullable] modifiers preceding the nullable types).
+List<macro.ArgumentKind> _dartTypeArgumentKinds(DartType dartType) => [
+      if (dartType.nullabilitySuffix == NullabilitySuffix.question)
+        macro.ArgumentKind.nullable,
+      switch (dartType) {
+        DartType(isDartCoreBool: true) => macro.ArgumentKind.bool,
+        DartType(isDartCoreDouble: true) => macro.ArgumentKind.double,
+        DartType(isDartCoreInt: true) => macro.ArgumentKind.int,
+        DartType(isDartCoreNum: true) => macro.ArgumentKind.num,
+        DartType(isDartCoreNull: true) => macro.ArgumentKind.nil,
+        DartType(isDartCoreObject: true) => macro.ArgumentKind.object,
+        DartType(isDartCoreString: true) => macro.ArgumentKind.string,
+        // TODO: Support nested type arguments for collections.
+        DartType(isDartCoreList: true) => macro.ArgumentKind.list,
+        DartType(isDartCoreMap: true) => macro.ArgumentKind.map,
+        DartType(isDartCoreSet: true) => macro.ArgumentKind.set,
+        DynamicType() => macro.ArgumentKind.dynamic,
+        _ =>
+          throw UnsupportedError('Unsupported macro type argument $dartType'),
+      },
+      if (dartType is ParameterizedType) ...[
+        for (var type in dartType.typeArguments)
+          ..._dartTypeArgumentKinds(type),
+      ]
+    ];
+
+List<macro.ArgumentKind> _typeArgumentsForNode(TypedLiteral node) {
+  if (node.typeArguments == null) {
+    return [
+      // TODO: Use inferred type here.
+      macro.ArgumentKind.dynamic,
+    ];
+  }
+  return [
+    for (var type in node.typeArguments!.arguments.map((arg) => arg.type!))
+      ..._dartTypeArgumentKinds(type),
+  ];
+}
+
 class LibraryMacroApplier {
   final DeclarationBuilder declarationBuilder;
   final LibraryBuilder libraryBuilder;
@@ -343,8 +384,8 @@
     required int annotationIndex,
     required ArgumentList node,
   }) {
-    final positional = <Object?>[];
-    final named = <String, Object?>{};
+    final positional = <macro.Argument>[];
+    final named = <String, macro.Argument>{};
     for (var i = 0; i < node.arguments.length; ++i) {
       final argument = node.arguments[i];
       final evaluation = _ArgumentEvaluation(
@@ -404,38 +445,43 @@
     required this.argumentIndex,
   });
 
-  Object? evaluate(Expression node) {
+  macro.Argument evaluate(Expression node) {
     if (node is AdjacentStrings) {
-      return node.strings.map(evaluate).join('');
+      return macro.StringArgument(node.strings.map(evaluate).join(''));
     } else if (node is BooleanLiteral) {
-      return node.value;
+      return macro.BoolArgument(node.value);
     } else if (node is DoubleLiteral) {
-      return node.value;
+      return macro.DoubleArgument(node.value);
     } else if (node is IntegerLiteral) {
-      return node.value;
+      return macro.IntArgument(node.value!);
     } else if (node is ListLiteral) {
-      return node.elements.cast<Expression>().map(evaluate).toList();
+      final typeArguments = _typeArgumentsForNode(node);
+      return macro.ListArgument(
+          node.elements.cast<Expression>().map(evaluate).toList(),
+          typeArguments);
     } else if (node is NullLiteral) {
-      return null;
+      return macro.NullArgument();
     } else if (node is PrefixExpression &&
         node.operator.type == TokenType.MINUS) {
       final operandValue = evaluate(node.operand);
-      if (operandValue is double) {
-        return -operandValue;
-      } else if (operandValue is int) {
-        return -operandValue;
+      if (operandValue is macro.DoubleArgument) {
+        return macro.DoubleArgument(-operandValue.value);
+      } else if (operandValue is macro.IntArgument) {
+        return macro.IntArgument(-operandValue.value);
       }
     } else if (node is SetOrMapLiteral) {
       return _setOrMapLiteral(node);
     } else if (node is SimpleStringLiteral) {
-      return node.value;
+      return macro.StringArgument(node.value);
     }
     _throwError(node, 'Not supported: ${node.runtimeType}');
   }
 
-  Object _setOrMapLiteral(SetOrMapLiteral node) {
+  macro.Argument _setOrMapLiteral(SetOrMapLiteral node) {
+    final typeArguments = _typeArgumentsForNode(node);
+
     if (node.elements.every((e) => e is Expression)) {
-      final result = <Object?>{};
+      final result = <macro.Argument>[];
       for (final element in node.elements) {
         if (element is! Expression) {
           _throwError(element, 'Expression expected');
@@ -443,10 +489,10 @@
         final value = evaluate(element);
         result.add(value);
       }
-      return result;
+      return macro.SetArgument(result, typeArguments);
     }
 
-    final result = <Object?, Object?>{};
+    final result = <macro.Argument, macro.Argument>{};
     for (final element in node.elements) {
       if (element is! MapLiteralEntry) {
         _throwError(element, 'MapLiteralEntry expected');
@@ -455,7 +501,7 @@
       final value = evaluate(element.value);
       result[key] = value;
     }
-    return result;
+    return macro.MapArgument(result, typeArguments);
   }
 
   Never _throwError(AstNode node, String message) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart
index 2bc15e9..43a7630 100644
--- a/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/macro/annotation_parser.dart
@@ -83,16 +83,18 @@
 }
 
 class _ArgumentsNode implements _Node {
-  final List<Object?> positionalArguments;
-  final Map<String, Object?> namedArguments;
+  final List<macro.Argument> positionalArguments;
+  final Map<String, macro.Argument> namedArguments;
 
   _ArgumentsNode(this.positionalArguments, this.namedArguments);
 }
 
 class _PrimitiveValueNode implements _Node {
-  final Object? value;
+  Object? get value => argument.value;
 
-  _PrimitiveValueNode(this.value);
+  final macro.Argument argument;
+
+  _PrimitiveValueNode(this.argument);
 }
 
 class _TokenNode implements _Node {
@@ -109,9 +111,11 @@
 
 class _NamedArgumentNode implements _Node {
   final String name;
-  final Object? value;
+  final macro.Argument argument;
 
-  _NamedArgumentNode(this.name, this.value);
+  Object? get value => argument.value;
+
+  _NamedArgumentNode(this.name, this.argument);
 }
 
 class _MacroListener implements Listener {
@@ -267,15 +271,15 @@
       pushUnsupported();
       return;
     }
-    List<Object?> positionalArguments = [];
-    Map<String, Object?> namedArguments = {};
+    List<macro.Argument> positionalArguments = [];
+    Map<String, macro.Argument> namedArguments = {};
     for (int i = 0; i < count; i++) {
       _Node node = pop();
       if (node is _PrimitiveValueNode) {
-        positionalArguments.add(node.value);
+        positionalArguments.add(node.argument);
       } else if (node is _NamedArgumentNode &&
           !namedArguments.containsKey(node.name)) {
-        namedArguments[node.name] = node.value;
+        namedArguments[node.name] = node.argument;
       } else {
         _unsupported();
       }
@@ -317,7 +321,7 @@
       _Node name = pop();
       if (name is _NamedArgumentIdentifierNode &&
           value is _PrimitiveValueNode) {
-        push(new _NamedArgumentNode(name.name, value.value));
+        push(new _NamedArgumentNode(name.name, value.argument));
       } else {
         pushUnsupported();
       }
@@ -335,22 +339,25 @@
 
   @override
   void handleLiteralNull(Token token) {
-    push(new _PrimitiveValueNode(null));
+    push(new _PrimitiveValueNode(new macro.NullArgument()));
   }
 
   @override
   void handleLiteralBool(Token token) {
-    push(new _PrimitiveValueNode(token.lexeme == 'true'));
+    push(new _PrimitiveValueNode(
+        new macro.BoolArgument(token.lexeme == 'true')));
   }
 
   @override
   void handleLiteralDouble(Token token) {
-    push(new _PrimitiveValueNode(double.parse(token.lexeme)));
+    push(new _PrimitiveValueNode(
+        new macro.DoubleArgument(double.parse(token.lexeme))));
   }
 
   @override
   void handleLiteralInt(Token token) {
-    push(new _PrimitiveValueNode(int.parse(token.lexeme)));
+    push(new _PrimitiveValueNode(
+        new macro.IntArgument(int.parse(token.lexeme))));
   }
 
   @override
@@ -371,7 +378,7 @@
         if (unrecognized) {
           pushUnsupported();
         } else {
-          push(new _PrimitiveValueNode(text));
+          push(new _PrimitiveValueNode(new macro.StringArgument(text)));
         }
       } else {
         pushUnsupported();
@@ -405,7 +412,8 @@
       if (unrecognized) {
         pushUnsupported();
       } else {
-        push(new _PrimitiveValueNode(values.reversed.join()));
+        push(new _PrimitiveValueNode(
+            new macro.StringArgument(values.reversed.join())));
       }
     }
   }
diff --git a/pkg/front_end/test/deps_git_test.dart b/pkg/front_end/test/deps_git_test.dart
index 5969343..5e5e14b 100644
--- a/pkg/front_end/test/deps_git_test.dart
+++ b/pkg/front_end/test/deps_git_test.dart
@@ -23,6 +23,7 @@
 final Uri repoDir = computeRepoDirUri();
 
 Set<String> allowlistedExternalDartFiles = {
+  "pkg/dart_internal/lib/extract_type_arguments.dart",
   "third_party/pkg/package_config/lib/package_config.dart",
   "third_party/pkg/package_config/lib/package_config_types.dart",
   "third_party/pkg/package_config/lib/src/discovery.dart",
diff --git a/pkg/front_end/test/macros/application/data/package_config.json b/pkg/front_end/test/macros/application/data/package_config.json
index 596dbc0..331f752 100644
--- a/pkg/front_end/test/macros/application/data/package_config.json
+++ b/pkg/front_end/test/macros/application/data/package_config.json
@@ -14,6 +14,10 @@
     {
       "name": "_fe_analyzer_shared",
       "rootUri": "../../../../../_fe_analyzer_shared/lib/"
+    },
+    {
+      "name": "dart_internal",
+      "rootUri": "../../../../../dart_internal/lib/"
     }
   ]
 }
diff --git a/pkg/front_end/test/macros/application/data/tests/sequence.dart b/pkg/front_end/test/macros/application/data/tests/sequence.dart
index cfb975b..9abea7b 100644
--- a/pkg/front_end/test/macros/application/data/tests/sequence.dart
+++ b/pkg/front_end/test/macros/application/data/tests/sequence.dart
@@ -4,28 +4,28 @@
 
 /*library: 
 Declarations Order:
- Class1:SequenceMacro.new(0)
- Class2:SequenceMacro.new(1)
- Class2:SequenceMacro.new(0)
- Class3.method:SequenceMacro.new(1)
- Class3:SequenceMacro.new(0)
- Class4.method:SequenceMacro.new(3)
- Class4.method2:SequenceMacro.new(5)
- Class4.method2:SequenceMacro.new(4)
- Class4:SequenceMacro.new(2)
- Class4:SequenceMacro.new(1)
- Class4:SequenceMacro.new(0)
- Class5a:SequenceMacro.new(0)
- Class5b:SequenceMacro.new(0)
- Class5c:SequenceMacro.new(0)
- Class6c:SequenceMacro.new(0)
- Class6a:SequenceMacro.new(0)
- Class6b:SequenceMacro.new(0)
- Class6d:SequenceMacro.new(0)
- Class7a:SequenceMacro.new(0)
- Class7b:SequenceMacro.new(0)
- Class7c:SequenceMacro.new(0)
- Class7d:SequenceMacro.new(0)*/
+ Class1:SequenceMacro.new(IntArgument:0)
+ Class2:SequenceMacro.new(IntArgument:1)
+ Class2:SequenceMacro.new(IntArgument:0)
+ Class3.method:SequenceMacro.new(IntArgument:1)
+ Class3:SequenceMacro.new(IntArgument:0)
+ Class4.method:SequenceMacro.new(IntArgument:3)
+ Class4.method2:SequenceMacro.new(IntArgument:5)
+ Class4.method2:SequenceMacro.new(IntArgument:4)
+ Class4:SequenceMacro.new(IntArgument:2)
+ Class4:SequenceMacro.new(IntArgument:1)
+ Class4:SequenceMacro.new(IntArgument:0)
+ Class5a:SequenceMacro.new(IntArgument:0)
+ Class5b:SequenceMacro.new(IntArgument:0)
+ Class5c:SequenceMacro.new(IntArgument:0)
+ Class6c:SequenceMacro.new(IntArgument:0)
+ Class6a:SequenceMacro.new(IntArgument:0)
+ Class6b:SequenceMacro.new(IntArgument:0)
+ Class6d:SequenceMacro.new(IntArgument:0)
+ Class7a:SequenceMacro.new(IntArgument:0)
+ Class7b:SequenceMacro.new(IntArgument:0)
+ Class7c:SequenceMacro.new(IntArgument:0)
+ Class7d:SequenceMacro.new(IntArgument:0)*/
 
 import 'package:macro/macro.dart';
 
diff --git a/pkg/front_end/test/macros/declaration/data/tests/macro_arguments.dart b/pkg/front_end/test/macros/declaration/data/tests/macro_arguments.dart
index 3f14d68..497dccb 100644
--- a/pkg/front_end/test/macros/declaration/data/tests/macro_arguments.dart
+++ b/pkg/front_end/test/macros/declaration/data/tests/macro_arguments.dart
@@ -7,20 +7,20 @@
   package:_fe_analyzer_shared/src/macros/api.dart|package:macro/macro.dart,
   main.dart],
  macroInstanceIds=[
-  package:macro/macro.dart/Macro4/(3.14),
-  package:macro/macro.dart/Macro4/(3.14,named:1.41),
-  package:macro/macro.dart/Macro4/(42),
-  package:macro/macro.dart/Macro4/(87,named:42),
-  package:macro/macro.dart/Macro4/(bar,named:baz),
-  package:macro/macro.dart/Macro4/(false),
-  package:macro/macro.dart/Macro4/(false,named:true),
-  package:macro/macro.dart/Macro4/(foo),
-  package:macro/macro.dart/Macro4/(foobar),
-  package:macro/macro.dart/Macro4/(foobar,named:boz_qux),
-  package:macro/macro.dart/Macro4/(null),
-  package:macro/macro.dart/Macro4/(null,named:null),
-  package:macro/macro.dart/Macro4/(qux,named:boz),
-  package:macro/macro.dart/Macro4/(true)],
+  package:macro/macro.dart/Macro4/(BoolArgument:false),
+  package:macro/macro.dart/Macro4/(BoolArgument:false,named:BoolArgument:true),
+  package:macro/macro.dart/Macro4/(BoolArgument:true),
+  package:macro/macro.dart/Macro4/(DoubleArgument:3.14),
+  package:macro/macro.dart/Macro4/(DoubleArgument:3.14,named:DoubleArgument:1.41),
+  package:macro/macro.dart/Macro4/(IntArgument:42),
+  package:macro/macro.dart/Macro4/(IntArgument:87,named:IntArgument:42),
+  package:macro/macro.dart/Macro4/(NullArgument:null),
+  package:macro/macro.dart/Macro4/(NullArgument:null,named:NullArgument:null),
+  package:macro/macro.dart/Macro4/(StringArgument:bar,named:StringArgument:baz),
+  package:macro/macro.dart/Macro4/(StringArgument:foo),
+  package:macro/macro.dart/Macro4/(StringArgument:foobar),
+  package:macro/macro.dart/Macro4/(StringArgument:foobar,named:StringArgument:boz_qux),
+  package:macro/macro.dart/Macro4/(StringArgument:qux,named:StringArgument:boz)],
  macrosAreApplied,
  macrosAreAvailable,
  neededPrecompilations=[package:macro/macro.dart=Macro1(named/new)|Macro2(named/new)|Macro3(named/new)|Macro4(new)]
@@ -29,49 +29,49 @@
 import 'package:macro/macro.dart';
 
 /*member: function1:appliedMacros=[
-  Macro4.new(null),
-  Macro4.new(null,named:null)]*/
+  Macro4.new(NullArgument:null),
+  Macro4.new(NullArgument:null,named:NullArgument:null)]*/
 @Macro4(null)
 @Macro4(null, named: null)
 function1() {}
 
 /*member: function2:appliedMacros=[
-  Macro4.new(42),
-  Macro4.new(87,named:42)]*/
+  Macro4.new(IntArgument:42),
+  Macro4.new(IntArgument:87,named:IntArgument:42)]*/
 @Macro4(42)
 @Macro4(87, named: 42)
 function2() {}
 
 /*member: function3:appliedMacros=[
-  Macro4.new(false,named:true),
-  Macro4.new(true)]*/
+  Macro4.new(BoolArgument:false,named:BoolArgument:true),
+  Macro4.new(BoolArgument:true)]*/
 @Macro4(true)
 @Macro4(false, named: true)
 function3() {}
 
-/*member: function4:appliedMacros=[Macro4.new(false)]*/
+/*member: function4:appliedMacros=[Macro4.new(BoolArgument:false)]*/
 @Macro4(false)
 function4() {}
 
 /*member: function5:appliedMacros=[
-  Macro4.new(bar,named:baz),
-  Macro4.new(foo),
-  Macro4.new(qux,named:boz)]*/
+  Macro4.new(StringArgument:bar,named:StringArgument:baz),
+  Macro4.new(StringArgument:foo),
+  Macro4.new(StringArgument:qux,named:StringArgument:boz)]*/
 @Macro4("foo")
 @Macro4("bar", named: "baz")
 @Macro4(named: "boz", "qux")
 function5() {}
 
 /*member: function6:appliedMacros=[
-  Macro4.new(3.14),
-  Macro4.new(3.14,named:1.41)]*/
+  Macro4.new(DoubleArgument:3.14),
+  Macro4.new(DoubleArgument:3.14,named:DoubleArgument:1.41)]*/
 @Macro4(3.14)
 @Macro4(3.14, named: 1.41)
 function6() {}
 
 /*member: function7:appliedMacros=[
-  Macro4.new(foobar),
-  Macro4.new(foobar,named:boz_qux)]*/
+  Macro4.new(StringArgument:foobar),
+  Macro4.new(StringArgument:foobar,named:StringArgument:boz_qux)]*/
 @Macro4("foo" "bar")
 @Macro4("foo" "bar", named: "boz" "_" "qux")
 function7() {}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 3663312..1f87a63 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -381,6 +381,7 @@
 deregister
 descent
 descriptive
+deserializable
 deserializer
 deserializers
 deserializes
@@ -902,6 +903,7 @@
 master
 matchers
 materialize
+materializes
 matters
 mature
 mb
@@ -1248,6 +1250,7 @@
 regis
 registering
 rehash
+reified
 reindexed
 reinstate
 reissued