add an extra cast, support positional args
diff --git a/pkg/kernel/lib/transformations/json_decode_experimental.dart b/pkg/kernel/lib/transformations/json_decode_experimental.dart
index cc72c8a..1eb49d8 100644
--- a/pkg/kernel/lib/transformations/json_decode_experimental.dart
+++ b/pkg/kernel/lib/transformations/json_decode_experimental.dart
@@ -13,14 +13,14 @@
class JsonDecodeExperimentalTransformer extends Transformer {
final CoreTypes coreTypes;
final InterfaceType iterableDynamic;
- final InterfaceType mapDynamic;
+ final InterfaceType mapStringDynamic;
final Class mapEntryClass;
JsonDecodeExperimentalTransformer(this.coreTypes)
: iterableDynamic =
InterfaceType(coreTypes.iterableClass, const [DynamicType()]),
- mapDynamic = InterfaceType(
- coreTypes.mapClass, const [DynamicType(), DynamicType()]),
+ mapStringDynamic = InterfaceType(coreTypes.mapClass,
+ [coreTypes.stringClass.thisType, DynamicType()]),
mapEntryClass = coreTypes.index.getClass('dart:core', 'MapEntry');
@override
@@ -143,7 +143,7 @@
var kParam = VariableDeclaration('k', type: const DynamicType());
var vParam = VariableDeclaration('v', type: const DynamicType());
return MethodInvocation(
- AsExpression(argExpr, mapDynamic),
+ AsExpression(argExpr, mapStringDynamic),
Name('map'),
Arguments([
FunctionExpression(
@@ -178,69 +178,79 @@
InterfaceType type, Expression argExpr) {
var clazz = type.classNode;
- var defaultConstructor = clazz.constructors
+ var constructor = clazz.constructors
.firstWhere((c) => c.name.name == '', orElse: () => null);
- if (defaultConstructor == null) {
- throw 'no unnamed constructor for class: ${clazz.name} from library: ${clazz.enclosingLibrary.importUri}';
+ if (constructor == null) {
+ throw UnsupportedError('''
+Unable to find an unnamed constructor for type:
+
+ class: ${clazz.name}
+ library: ${clazz.enclosingLibrary.importUri}
+
+jsonAutoDecode only works for core types and types with unnamed constructors.
+''');
}
- // TODO: positional parameters
- // var positionalArgs = <Expression>[];
- // var positionalParams = defaultConstructor.function.positionalParameters;
+ var positionalParams = constructor.function.positionalParameters;
+ var positionalArgs = [
+ for (var param in positionalParams) _parameterValue(type, param, argExpr)
+ ];
- var namedArgs = <NamedExpression>[];
- var namedParams = defaultConstructor.function.namedParameters;
-
- for (var param in namedParams) {
- // First, build the expression to get the value out of the map
- Expression mapValueExpr;
-
- if (argExpr is MapLiteral) {
- mapValueExpr = argExpr.entries
- .firstWhere((e) => (e.key as StringLiteral).value == param.name)
- .value;
- } else if (argExpr is VariableGet || argExpr is MethodInvocation) {
- mapValueExpr = MethodInvocation(
- argExpr, Name('[]'), Arguments([StringLiteral(param.name)]));
- } else {
- throw '''
- Unrecognized type of map argument:
- runtimeType: ${argExpr.runtimeType}
- value: $argExpr
- ''';
- }
-
- // Now build the actual argument expression based on the type of the argument.
- if (param.type is! InterfaceType) {
- throw '''
- Unsupported type, only classes are supported: ${type}
- ''';
- }
- var paramType = param.type as InterfaceType;
-
- var newTypeArgs = paramType.typeArguments.map((typeArg) {
- if (typeArg is TypeParameterType) {
- var index = type.classNode.typeParameters.indexOf(typeArg.parameter);
- return type.typeArguments[index];
- }
- return typeArg;
- }).toList();
-
- paramType = InterfaceType(paramType.classNode, newTypeArgs);
-
- namedArgs.add(
- NamedExpression(param.name, _newInstance(paramType, mapValueExpr)));
- }
+ var namedParams = constructor.function.namedParameters;
+ var namedArgs = [
+ for (var param in namedParams)
+ NamedExpression(param.name, _parameterValue(type, param, argExpr))
+ ];
return ConstructorInvocation(
- defaultConstructor,
+ constructor,
Arguments(
- [] /* TODO: support positional args */,
+ positionalArgs,
named: namedArgs,
types: type.typeArguments,
));
}
+ Expression _parameterValue(InterfaceType parent,
+ VariableDeclaration methodParam, Expression argExpr) {
+ // First, build the expression to get the value out of the map
+ Expression mapValueExpr;
+
+ if (argExpr is VariableGet || argExpr is MethodInvocation) {
+ mapValueExpr = MethodInvocation(
+ AsExpression(argExpr, mapStringDynamic),
+ Name('[]'),
+ Arguments([StringLiteral(methodParam.name)]),
+ );
+ } else {
+ throw '''
+ Unrecognized argument type:
+
+ runtimeType: ${argExpr.runtimeType}
+ value: $argExpr
+ ''';
+ }
+
+ // Now build the actual argument expression based on the type of the argument.
+ if (methodParam.type is! InterfaceType) {
+ throw '''
+ Unsupported type, only classes are supported: ${methodParam.type}
+ ''';
+ }
+ var paramType = methodParam.type as InterfaceType;
+
+ var newTypeArgs = paramType.typeArguments.map((typeArg) {
+ if (typeArg is TypeParameterType) {
+ var index = parent.classNode.typeParameters.indexOf(typeArg.parameter);
+ return parent.typeArguments[index];
+ }
+ return typeArg;
+ }).toList();
+
+ paramType = InterfaceType(paramType.classNode, newTypeArgs);
+ return _newInstance(paramType, mapValueExpr);
+ }
+
ConstructorInvocation _newLazyCollection(
InterfaceType type, Expression argExpr) {
var clazz = type.classNode;