Revert "Add wrappers for macro arguments to help with serialization."

This reverts commit ea7e014c3c.

Reason for revert: breaks Analyzer tests, CBuild regression.

Original change's description:
> 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>

Bug: https://github.com/dart-lang/language/issues/2212
Change-Id: I402802c7a1c27f9aee3f23baef8c0deb71ec06e9
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/309284
Commit-Queue: Ilya Yanok <yanok@google.com>
Reviewed-by: Alexander Thomas <athom@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
This commit is contained in:
Ilya Yanok 2023-06-14 15:34:37 +00:00 committed by Commit Queue
parent c1969260e8
commit 396ed71267
14 changed files with 321 additions and 816 deletions

View file

@ -200,11 +200,9 @@ Future<SerializableResponse> _instantiateMacro(
'macro class "\${request.name}".');
}
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,
var instance = Function.apply(constructor, request.arguments.positional, {
for (MapEntry<String, Object?> entry in request.arguments.named.entries)
new Symbol(entry.key): entry.value,
}) as Macro;
var identifier = new MacroInstanceIdentifierImpl(instance, request.instanceId);
_macroInstances[identifier] = instance;

View file

@ -2,16 +2,11 @@
// 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.
@ -91,6 +86,146 @@ abstract class MacroExecutor {
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 {
@ -190,3 +325,15 @@ enum Phase {
/// This phase allows augmenting existing declarations.
definitions,
}
/// Used for serializing and deserializing arguments.
enum _ArgumentKind {
string,
bool,
double,
int,
list,
map,
set,
nil,
}

View file

@ -1,424 +0,0 @@
// 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,
}

View file

@ -7,7 +7,6 @@ environment:
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

View file

@ -92,7 +92,7 @@ void main() {
reason: 'Can create an instance with no arguments.');
instanceId = await executor.instantiateMacro(
macroUri, macroName, '', Arguments([IntArgument(1)], {}));
macroUri, macroName, '', Arguments([1], {}));
expect(instanceId, isNotNull,
reason: 'Can create an instance with positional arguments.');
@ -101,33 +101,23 @@ void main() {
macroName,
'named',
Arguments([], {
'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'),
'myBool': true,
'myDouble': 1.0,
'myInt': 1,
'myList': [
1,
2,
3,
],
'mySet': {
true,
null,
{'a': 1.0}
},
'myMap': {
'x': 1,
},
'myString': 'a',
}));
expect(instanceId, isNotNull,
reason: 'Can create an instance with named arguments.');

View file

@ -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,8 +156,7 @@ void main() {
]) {
group('with mode $mode', () {
test('NamedTypeAnnotation', () {
expectSerializationEquality<TypeAnnotationImpl>(
fooType, mode, RemoteInstance.deserialize);
expectSerializationEquality(fooType, mode);
});
final fooNamedParam = ParameterDeclarationImpl(
@ -215,8 +214,7 @@ void main() {
returnType: fooType,
typeParameters: [zapTypeParam],
);
expectSerializationEquality<TypeAnnotationImpl>(
functionType, mode, RemoteInstance.deserialize);
expectSerializationEquality(functionType, mode);
});
test('FunctionDeclaration', () {
@ -233,8 +231,7 @@ void main() {
positionalParameters: [],
returnType: fooType,
typeParameters: []);
expectSerializationEquality<DeclarationImpl>(
function, mode, RemoteInstance.deserialize);
expectSerializationEquality(function, mode);
});
test('MethodDeclaration', () {
@ -253,8 +250,7 @@ void main() {
typeParameters: [zapTypeParam],
definingType: fooType.identifier,
isStatic: false);
expectSerializationEquality<DeclarationImpl>(
method, mode, RemoteInstance.deserialize);
expectSerializationEquality(method, mode);
});
test('ConstructorDeclaration', () {
@ -274,8 +270,7 @@ void main() {
definingType: fooType.identifier,
isFactory: true,
);
expectSerializationEquality<DeclarationImpl>(
constructor, mode, RemoteInstance.deserialize);
expectSerializationEquality(constructor, mode);
});
test('VariableDeclaration', () {
@ -288,8 +283,7 @@ void main() {
isLate: true,
type: barType,
);
expectSerializationEquality<DeclarationImpl>(
bar, mode, RemoteInstance.deserialize);
expectSerializationEquality(bar, mode);
});
test('FieldDeclaration', () {
@ -304,8 +298,7 @@ void main() {
definingType: fooType.identifier,
isStatic: false,
);
expectSerializationEquality<DeclarationImpl>(
bar, mode, RemoteInstance.deserialize);
expectSerializationEquality(bar, mode);
});
var objectType = NamedTypeAnnotationImpl(
@ -341,8 +334,7 @@ void main() {
superclass: objectType,
typeParameters: [zapTypeParam],
);
expectSerializationEquality<DeclarationImpl>(
fooClass, mode, RemoteInstance.deserialize);
expectSerializationEquality(fooClass, mode);
}
});
@ -355,8 +347,7 @@ void main() {
mixins: [serializableType],
typeParameters: [zapTypeParam],
);
expectSerializationEquality<DeclarationImpl>(
fooEnum, mode, RemoteInstance.deserialize);
expectSerializationEquality(fooEnum, mode);
});
test('EnumValueDeclaration', () {
@ -366,8 +357,7 @@ void main() {
definingEnum:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'MyEnum'),
);
expectSerializationEquality<DeclarationImpl>(
entry, mode, RemoteInstance.deserialize);
expectSerializationEquality(entry, mode);
});
test('MixinDeclaration', () {
@ -381,8 +371,7 @@ void main() {
superclassConstraints: [serializableType],
typeParameters: [zapTypeParam],
);
expectSerializationEquality<DeclarationImpl>(
mixin, mode, RemoteInstance.deserialize);
expectSerializationEquality(mixin, mode);
}
});
@ -399,8 +388,7 @@ void main() {
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
typeArguments: [barType]),
);
expectSerializationEquality<DeclarationImpl>(
typeAlias, mode, RemoteInstance.deserialize);
expectSerializationEquality(typeAlias, mode);
});
/// Transitively tests [RecordField]
@ -427,135 +415,17 @@ void main() {
),
],
);
expectSerializationEquality<TypeAnnotationImpl>(
recordType, mode, RemoteInstance.deserialize);
expectSerializationEquality(recordType, mode);
});
});
}
});
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<T extends Serializable>(T serializable,
SerializationMode serverMode, T deserialize(Deserializer deserializer)) {
void expectSerializationEquality(
Serializable serializable, SerializationMode serverMode) {
late Object? serialized;
withSerializationMode(serverMode, () {
var serializer = serializerFactory();
@ -564,18 +434,14 @@ void expectSerializationEquality<T extends Serializable>(T serializable,
});
withSerializationMode(_clientModeForServerMode(serverMode), () {
var deserializer = deserializerFactory(serialized);
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'),
}));
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');
}
});
}
@ -583,7 +449,8 @@ void expectSerializationEquality<T extends Serializable>(T serializable,
Object? roundTrip<Declaration>(Object? serialized) {
return withSerializationMode(_clientModeForServerMode(serializationMode), () {
var deserializer = deserializerFactory(serialized);
var instance = RemoteInstance.deserialize(deserializer);
var instance =
RemoteInstance.deserialize<NamedTypeAnnotationImpl>(deserializer);
var serializer = serializerFactory();
instance.serialize(serializer);
return serializer.result;

View file

@ -175,10 +175,6 @@ Matcher deepEqualsDeclaration(Declaration declaration) =>
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 {
@ -191,11 +187,10 @@ class _DeepEqualityMatcher extends Matcher {
@override
bool matches(item, Map matchState) {
// For type promotion.
final instance = this.instance;
if (!equals(item.runtimeType).matches(instance.runtimeType, matchState)) {
if (item.runtimeType != instance.runtimeType) {
return false;
}
if (instance is Declaration || instance is TypeAnnotation) {
var instanceReflector = reflect(instance);
var itemReflector = reflect(item);
@ -211,52 +206,47 @@ class _DeepEqualityMatcher extends Matcher {
var instanceValue = instanceField.reflectee;
var itemValue = itemField.reflectee;
if (!_DeepEqualityMatcher(instanceValue)
.matches(itemValue, matchState)) {
return false;
// 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;
}
}
}
} else if (instance is Code) {
item as Code;
if (!_DeepEqualityMatcher(instance.parts)
.matches(item.parts, matchState)) {
if (!_listEquals(
(instance as Code).parts, (item as Code).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 (!equals(instance).matches(item, matchState)) {
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)) {
return false;
}
}

View file

@ -22,47 +22,6 @@ import 'package:analyzer/src/summary2/macro_application_error.dart';
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;
@ -384,8 +343,8 @@ class LibraryMacroApplier {
required int annotationIndex,
required ArgumentList node,
}) {
final positional = <macro.Argument>[];
final named = <String, macro.Argument>{};
final positional = <Object?>[];
final named = <String, Object?>{};
for (var i = 0; i < node.arguments.length; ++i) {
final argument = node.arguments[i];
final evaluation = _ArgumentEvaluation(
@ -445,43 +404,38 @@ class _ArgumentEvaluation {
required this.argumentIndex,
});
macro.Argument evaluate(Expression node) {
Object? evaluate(Expression node) {
if (node is AdjacentStrings) {
return macro.StringArgument(node.strings.map(evaluate).join(''));
return node.strings.map(evaluate).join('');
} else if (node is BooleanLiteral) {
return macro.BoolArgument(node.value);
return node.value;
} else if (node is DoubleLiteral) {
return macro.DoubleArgument(node.value);
return node.value;
} else if (node is IntegerLiteral) {
return macro.IntArgument(node.value!);
return node.value;
} else if (node is ListLiteral) {
final typeArguments = _typeArgumentsForNode(node);
return macro.ListArgument(
node.elements.cast<Expression>().map(evaluate).toList(),
typeArguments);
return node.elements.cast<Expression>().map(evaluate).toList();
} else if (node is NullLiteral) {
return macro.NullArgument();
return null;
} else if (node is PrefixExpression &&
node.operator.type == TokenType.MINUS) {
final operandValue = evaluate(node.operand);
if (operandValue is macro.DoubleArgument) {
return macro.DoubleArgument(-operandValue.value);
} else if (operandValue is macro.IntArgument) {
return macro.IntArgument(-operandValue.value);
if (operandValue is double) {
return -operandValue;
} else if (operandValue is int) {
return -operandValue;
}
} else if (node is SetOrMapLiteral) {
return _setOrMapLiteral(node);
} else if (node is SimpleStringLiteral) {
return macro.StringArgument(node.value);
return node.value;
}
_throwError(node, 'Not supported: ${node.runtimeType}');
}
macro.Argument _setOrMapLiteral(SetOrMapLiteral node) {
final typeArguments = _typeArgumentsForNode(node);
Object _setOrMapLiteral(SetOrMapLiteral node) {
if (node.elements.every((e) => e is Expression)) {
final result = <macro.Argument>[];
final result = <Object?>{};
for (final element in node.elements) {
if (element is! Expression) {
_throwError(element, 'Expression expected');
@ -489,10 +443,10 @@ class _ArgumentEvaluation {
final value = evaluate(element);
result.add(value);
}
return macro.SetArgument(result, typeArguments);
return result;
}
final result = <macro.Argument, macro.Argument>{};
final result = <Object?, Object?>{};
for (final element in node.elements) {
if (element is! MapLiteralEntry) {
_throwError(element, 'MapLiteralEntry expected');
@ -501,7 +455,7 @@ class _ArgumentEvaluation {
final value = evaluate(element.value);
result[key] = value;
}
return macro.MapArgument(result, typeArguments);
return result;
}
Never _throwError(AstNode node, String message) {

View file

@ -83,18 +83,16 @@ class _NoArgumentsNode implements _Node {
}
class _ArgumentsNode implements _Node {
final List<macro.Argument> positionalArguments;
final Map<String, macro.Argument> namedArguments;
final List<Object?> positionalArguments;
final Map<String, Object?> namedArguments;
_ArgumentsNode(this.positionalArguments, this.namedArguments);
}
class _PrimitiveValueNode implements _Node {
Object? get value => argument.value;
final Object? value;
final macro.Argument argument;
_PrimitiveValueNode(this.argument);
_PrimitiveValueNode(this.value);
}
class _TokenNode implements _Node {
@ -111,11 +109,9 @@ class _NamedArgumentIdentifierNode implements _Node {
class _NamedArgumentNode implements _Node {
final String name;
final macro.Argument argument;
final Object? value;
Object? get value => argument.value;
_NamedArgumentNode(this.name, this.argument);
_NamedArgumentNode(this.name, this.value);
}
class _MacroListener implements Listener {
@ -271,15 +267,15 @@ class _MacroListener implements Listener {
pushUnsupported();
return;
}
List<macro.Argument> positionalArguments = [];
Map<String, macro.Argument> namedArguments = {};
List<Object?> positionalArguments = [];
Map<String, Object?> namedArguments = {};
for (int i = 0; i < count; i++) {
_Node node = pop();
if (node is _PrimitiveValueNode) {
positionalArguments.add(node.argument);
positionalArguments.add(node.value);
} else if (node is _NamedArgumentNode &&
!namedArguments.containsKey(node.name)) {
namedArguments[node.name] = node.argument;
namedArguments[node.name] = node.value;
} else {
_unsupported();
}
@ -321,7 +317,7 @@ class _MacroListener implements Listener {
_Node name = pop();
if (name is _NamedArgumentIdentifierNode &&
value is _PrimitiveValueNode) {
push(new _NamedArgumentNode(name.name, value.argument));
push(new _NamedArgumentNode(name.name, value.value));
} else {
pushUnsupported();
}
@ -339,25 +335,22 @@ class _MacroListener implements Listener {
@override
void handleLiteralNull(Token token) {
push(new _PrimitiveValueNode(new macro.NullArgument()));
push(new _PrimitiveValueNode(null));
}
@override
void handleLiteralBool(Token token) {
push(new _PrimitiveValueNode(
new macro.BoolArgument(token.lexeme == 'true')));
push(new _PrimitiveValueNode(token.lexeme == 'true'));
}
@override
void handleLiteralDouble(Token token) {
push(new _PrimitiveValueNode(
new macro.DoubleArgument(double.parse(token.lexeme))));
push(new _PrimitiveValueNode(double.parse(token.lexeme)));
}
@override
void handleLiteralInt(Token token) {
push(new _PrimitiveValueNode(
new macro.IntArgument(int.parse(token.lexeme))));
push(new _PrimitiveValueNode(int.parse(token.lexeme)));
}
@override
@ -378,7 +371,7 @@ class _MacroListener implements Listener {
if (unrecognized) {
pushUnsupported();
} else {
push(new _PrimitiveValueNode(new macro.StringArgument(text)));
push(new _PrimitiveValueNode(text));
}
} else {
pushUnsupported();
@ -412,8 +405,7 @@ class _MacroListener implements Listener {
if (unrecognized) {
pushUnsupported();
} else {
push(new _PrimitiveValueNode(
new macro.StringArgument(values.reversed.join())));
push(new _PrimitiveValueNode(values.reversed.join()));
}
}
}

View file

@ -23,7 +23,6 @@ import 'utils/io_utils.dart' show computeRepoDirUri;
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",

View file

@ -14,10 +14,6 @@
{
"name": "_fe_analyzer_shared",
"rootUri": "../../../../../_fe_analyzer_shared/lib/"
},
{
"name": "dart_internal",
"rootUri": "../../../../../dart_internal/lib/"
}
]
}

View file

@ -4,28 +4,28 @@
/*library:
Declarations Order:
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)*/
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)*/
import 'package:macro/macro.dart';

View file

@ -7,20 +7,20 @@
package:_fe_analyzer_shared/src/macros/api.dart|package:macro/macro.dart,
main.dart],
macroInstanceIds=[
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)],
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)],
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(NullArgument:null),
Macro4.new(NullArgument:null,named:NullArgument:null)]*/
Macro4.new(null),
Macro4.new(null,named:null)]*/
@Macro4(null)
@Macro4(null, named: null)
function1() {}
/*member: function2:appliedMacros=[
Macro4.new(IntArgument:42),
Macro4.new(IntArgument:87,named:IntArgument:42)]*/
Macro4.new(42),
Macro4.new(87,named:42)]*/
@Macro4(42)
@Macro4(87, named: 42)
function2() {}
/*member: function3:appliedMacros=[
Macro4.new(BoolArgument:false,named:BoolArgument:true),
Macro4.new(BoolArgument:true)]*/
Macro4.new(false,named:true),
Macro4.new(true)]*/
@Macro4(true)
@Macro4(false, named: true)
function3() {}
/*member: function4:appliedMacros=[Macro4.new(BoolArgument:false)]*/
/*member: function4:appliedMacros=[Macro4.new(false)]*/
@Macro4(false)
function4() {}
/*member: function5:appliedMacros=[
Macro4.new(StringArgument:bar,named:StringArgument:baz),
Macro4.new(StringArgument:foo),
Macro4.new(StringArgument:qux,named:StringArgument:boz)]*/
Macro4.new(bar,named:baz),
Macro4.new(foo),
Macro4.new(qux,named:boz)]*/
@Macro4("foo")
@Macro4("bar", named: "baz")
@Macro4(named: "boz", "qux")
function5() {}
/*member: function6:appliedMacros=[
Macro4.new(DoubleArgument:3.14),
Macro4.new(DoubleArgument:3.14,named:DoubleArgument:1.41)]*/
Macro4.new(3.14),
Macro4.new(3.14,named:1.41)]*/
@Macro4(3.14)
@Macro4(3.14, named: 1.41)
function6() {}
/*member: function7:appliedMacros=[
Macro4.new(StringArgument:foobar),
Macro4.new(StringArgument:foobar,named:StringArgument:boz_qux)]*/
Macro4.new(foobar),
Macro4.new(foobar,named:boz_qux)]*/
@Macro4("foo" "bar")
@Macro4("foo" "bar", named: "boz" "_" "qux")
function7() {}

View file

@ -381,7 +381,6 @@ dereferencing
deregister
descent
descriptive
deserializable
deserializer
deserializers
deserializes
@ -903,7 +902,6 @@ masks
master
matchers
materialize
materializes
matters
mature
mb
@ -1250,7 +1248,6 @@ regenerations
regis
registering
rehash
reified
reindexed
reinstate
reissued