blob: 4883adb3859897d0cdad1b0e3787f519202d47b7 [file] [log] [blame]
// Copyright (c) 2016, 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.
library dart2js.serialization.util;
import '../common.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../diagnostics/messages.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' show WrappedMessage;
import '../resolution/access_semantics.dart';
import '../resolution/operators.dart';
import '../resolution/send_structure.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import 'keys.dart';
import 'serialization.dart';
/// Serialize [name] into [encoder].
void serializeName(Name name, ObjectEncoder encoder) {
encoder.setString(Key.NAME, name.text);
encoder.setBool(Key.IS_SETTER, name.isSetter);
if (name.library != null) {
encoder.setElement(Key.LIBRARY, name.library);
}
}
/// Deserialize a [Name] from [decoder].
Name deserializeName(ObjectDecoder decoder) {
String name = decoder.getString(Key.NAME);
bool isSetter = decoder.getBool(Key.IS_SETTER);
LibraryElement library = decoder.getElement(Key.LIBRARY, isOptional: true);
return new Name(name, library, isSetter: isSetter);
}
/// Serialize [selector] into [encoder].
void serializeSelector(Selector selector, ObjectEncoder encoder) {
encoder.setEnum(Key.KIND, selector.kind);
encoder.setInt(Key.ARGUMENTS, selector.callStructure.argumentCount);
encoder.setStrings(
Key.NAMED_ARGUMENTS, selector.callStructure.namedArguments);
serializeName(selector.memberName, encoder);
}
/// Deserialize a [Selector] from [decoder].
Selector deserializeSelector(ObjectDecoder decoder) {
SelectorKind kind = decoder.getEnum(Key.KIND, SelectorKind.values);
int argumentCount = decoder.getInt(Key.ARGUMENTS);
List<String> namedArguments =
decoder.getStrings(Key.NAMED_ARGUMENTS, isOptional: true);
String name = decoder.getString(Key.NAME);
bool isSetter = decoder.getBool(Key.IS_SETTER);
LibraryElement library = decoder.getElement(Key.LIBRARY, isOptional: true);
return new Selector(kind, deserializeName(decoder),
new CallStructure(argumentCount, namedArguments));
}
/// Serialize [sendStructure] into [encoder].
void serializeSendStructure(
SendStructure sendStructure, ObjectEncoder encoder) {
encoder.setEnum(Key.KIND, sendStructure.kind);
switch (sendStructure.kind) {
case SendStructureKind.IF_NULL:
case SendStructureKind.LOGICAL_AND:
case SendStructureKind.LOGICAL_OR:
case SendStructureKind.NOT:
case SendStructureKind.INVALID_UNARY:
case SendStructureKind.INVALID_BINARY:
// No additional properties.
break;
case SendStructureKind.IS:
IsStructure structure = sendStructure;
encoder.setType(Key.TYPE, structure.type);
break;
case SendStructureKind.IS_NOT:
IsNotStructure structure = sendStructure;
encoder.setType(Key.TYPE, structure.type);
break;
case SendStructureKind.AS:
AsStructure structure = sendStructure;
encoder.setType(Key.TYPE, structure.type);
break;
case SendStructureKind.INVOKE:
InvokeStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
break;
case SendStructureKind.INCOMPATIBLE_INVOKE:
IncompatibleInvokeStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
break;
case SendStructureKind.GET:
GetStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.SET:
SetStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.UNARY:
UnaryStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.INDEX:
IndexStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.EQUALS:
EqualsStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.NOT_EQUALS:
NotEqualsStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.BINARY:
BinaryStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.INDEX_SET:
IndexSetStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.INDEX_PREFIX:
IndexPrefixStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.INDEX_POSTFIX:
IndexPostfixStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.COMPOUND:
CompoundStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.SET_IF_NULL:
SetIfNullStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.COMPOUND_INDEX_SET:
CompoundIndexSetStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.INDEX_SET_IF_NULL:
IndexSetIfNullStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
break;
case SendStructureKind.PREFIX:
PrefixStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.POSTFIX:
PostfixStructure structure = sendStructure;
serializeAccessSemantics(
structure.semantics, encoder.createObject(Key.SEMANTICS));
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
break;
case SendStructureKind.DEFERRED_PREFIX:
DeferredPrefixStructure structure = sendStructure;
encoder.setElement(Key.PREFIX, structure.prefix);
serializeSendStructure(
structure.sendStructure, encoder.createObject(Key.SEND_STRUCTURE));
break;
}
}
/// Deserialize a [SendStructure] from [decoder].
SendStructure deserializeSendStructure(ObjectDecoder decoder) {
SendStructureKind kind = decoder.getEnum(Key.KIND, SendStructureKind.values);
switch (kind) {
case SendStructureKind.IF_NULL:
return const IfNullStructure();
case SendStructureKind.LOGICAL_AND:
return const LogicalAndStructure();
case SendStructureKind.LOGICAL_OR:
return const LogicalOrStructure();
case SendStructureKind.IS:
return new IsStructure(decoder.getType(Key.TYPE));
case SendStructureKind.IS_NOT:
return new IsNotStructure(decoder.getType(Key.TYPE));
case SendStructureKind.AS:
return new AsStructure(decoder.getType(Key.TYPE));
case SendStructureKind.INVOKE:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
return new InvokeStructure(semantics, selector);
case SendStructureKind.INCOMPATIBLE_INVOKE:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
return new IncompatibleInvokeStructure(semantics, selector);
case SendStructureKind.GET:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new GetStructure(semantics);
case SendStructureKind.SET:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new SetStructure(semantics);
case SendStructureKind.NOT:
return const NotStructure();
case SendStructureKind.UNARY:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new UnaryStructure(
semantics,
UnaryOperator.fromKind(
decoder.getEnum(Key.OPERATOR, UnaryOperatorKind.values)));
case SendStructureKind.INVALID_UNARY:
return new InvalidUnaryStructure();
case SendStructureKind.INDEX:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new IndexStructure(semantics);
case SendStructureKind.EQUALS:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new EqualsStructure(semantics);
case SendStructureKind.NOT_EQUALS:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new NotEqualsStructure(semantics);
case SendStructureKind.BINARY:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new BinaryStructure(
semantics,
BinaryOperator.fromKind(
decoder.getEnum(Key.OPERATOR, BinaryOperatorKind.values)));
case SendStructureKind.INVALID_BINARY:
return const InvalidBinaryStructure();
case SendStructureKind.INDEX_SET:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new IndexSetStructure(semantics);
case SendStructureKind.INDEX_PREFIX:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new IndexPrefixStructure(
semantics,
IncDecOperator.fromKind(
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
case SendStructureKind.INDEX_POSTFIX:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new IndexPostfixStructure(
semantics,
IncDecOperator.fromKind(
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
case SendStructureKind.COMPOUND:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new CompoundStructure(
semantics,
AssignmentOperator.fromKind(
decoder.getEnum(Key.OPERATOR, AssignmentOperatorKind.values)));
case SendStructureKind.SET_IF_NULL:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new SetIfNullStructure(semantics);
case SendStructureKind.COMPOUND_INDEX_SET:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new CompoundIndexSetStructure(
semantics,
AssignmentOperator.fromKind(
decoder.getEnum(Key.OPERATOR, AssignmentOperatorKind.values)));
case SendStructureKind.INDEX_SET_IF_NULL:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new IndexSetIfNullStructure(semantics);
case SendStructureKind.PREFIX:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new PrefixStructure(
semantics,
IncDecOperator.fromKind(
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
case SendStructureKind.POSTFIX:
AccessSemantics semantics =
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
return new PostfixStructure(
semantics,
IncDecOperator.fromKind(
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
case SendStructureKind.DEFERRED_PREFIX:
PrefixElement prefix = decoder.getElement(Key.PREFIX);
SendStructure sendStructure =
deserializeSendStructure(decoder.getObject(Key.SEND_STRUCTURE));
return new DeferredPrefixStructure(prefix, sendStructure);
}
}
/// Serialize [newStructure] into [encoder].
void serializeNewStructure(NewStructure newStructure, ObjectEncoder encoder) {
encoder.setEnum(Key.KIND, newStructure.kind);
switch (newStructure.kind) {
case NewStructureKind.NEW_INVOKE:
NewInvokeStructure structure = newStructure;
encoder.setEnum(Key.SUB_KIND, structure.semantics.kind);
encoder.setElement(Key.ELEMENT, structure.semantics.element);
encoder.setType(Key.TYPE, structure.semantics.type);
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
break;
case NewStructureKind.CONST_INVOKE:
ConstInvokeStructure structure = newStructure;
encoder.setEnum(Key.SUB_KIND, structure.constantInvokeKind);
encoder.setConstant(Key.CONSTANT, structure.constant);
break;
case NewStructureKind.LATE_CONST:
throw new UnsupportedError(
'Unsupported NewStructure kind ${newStructure.kind}.');
}
}
/// Deserialize a [NewStructure] from [decoder].
NewStructure deserializeNewStructure(ObjectDecoder decoder) {
NewStructureKind kind = decoder.getEnum(Key.KIND, NewStructureKind.values);
switch (kind) {
case NewStructureKind.NEW_INVOKE:
ConstructorAccessKind constructorAccessKind =
decoder.getEnum(Key.SUB_KIND, ConstructorAccessKind.values);
Element element = decoder.getElement(Key.ELEMENT);
DartType type = decoder.getType(Key.TYPE);
ConstructorAccessSemantics semantics =
new ConstructorAccessSemantics(constructorAccessKind, element, type);
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
return new NewInvokeStructure(semantics, selector);
case NewStructureKind.CONST_INVOKE:
ConstantInvokeKind constantInvokeKind =
decoder.getEnum(Key.SUB_KIND, ConstantInvokeKind.values);
ConstantExpression constant = decoder.getConstant(Key.CONSTANT);
return new ConstInvokeStructure(constantInvokeKind, constant);
case NewStructureKind.LATE_CONST:
throw new UnsupportedError('Unsupported NewStructure kind $kind.');
}
}
/// Serialize [semantics] into [encoder].
void serializeAccessSemantics(
AccessSemantics semantics, ObjectEncoder encoder) {
encoder.setEnum(Key.KIND, semantics.kind);
switch (semantics.kind) {
case AccessKind.EXPRESSION:
case AccessKind.THIS:
// No additional properties.
break;
case AccessKind.THIS_PROPERTY:
case AccessKind.DYNAMIC_PROPERTY:
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
serializeName(semantics.name, encoder);
break;
case AccessKind.CLASS_TYPE_LITERAL:
case AccessKind.TYPEDEF_TYPE_LITERAL:
case AccessKind.DYNAMIC_TYPE_LITERAL:
encoder.setConstant(Key.CONSTANT, semantics.constant);
break;
case AccessKind.LOCAL_FUNCTION:
case AccessKind.LOCAL_VARIABLE:
case AccessKind.FINAL_LOCAL_VARIABLE:
case AccessKind.PARAMETER:
case AccessKind.FINAL_PARAMETER:
case AccessKind.STATIC_FIELD:
case AccessKind.FINAL_STATIC_FIELD:
case AccessKind.STATIC_METHOD:
case AccessKind.STATIC_GETTER:
case AccessKind.STATIC_SETTER:
case AccessKind.TOPLEVEL_FIELD:
case AccessKind.FINAL_TOPLEVEL_FIELD:
case AccessKind.TOPLEVEL_METHOD:
case AccessKind.TOPLEVEL_GETTER:
case AccessKind.TOPLEVEL_SETTER:
case AccessKind.SUPER_FIELD:
case AccessKind.SUPER_FINAL_FIELD:
case AccessKind.SUPER_METHOD:
case AccessKind.SUPER_GETTER:
case AccessKind.SUPER_SETTER:
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
case AccessKind.UNRESOLVED:
case AccessKind.UNRESOLVED_SUPER:
case AccessKind.INVALID:
encoder.setElement(Key.ELEMENT, semantics.element);
break;
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundAccess = semantics;
encoder.setEnum(Key.SUB_KIND, compoundAccess.compoundAccessKind);
encoder.setElement(Key.GETTER, semantics.getter);
encoder.setElement(Key.SETTER, semantics.setter);
break;
case AccessKind.CONSTANT:
throw new UnsupportedError('Unsupported access kind: ${semantics.kind}');
}
}
/// Deserialize a [AccessSemantics] from [decoder].
AccessSemantics deserializeAccessSemantics(ObjectDecoder decoder) {
AccessKind kind = decoder.getEnum(Key.KIND, AccessKind.values);
switch (kind) {
case AccessKind.EXPRESSION:
return const DynamicAccess.expression();
case AccessKind.THIS:
return const DynamicAccess.thisAccess();
case AccessKind.THIS_PROPERTY:
return new DynamicAccess.thisProperty(deserializeName(decoder));
case AccessKind.DYNAMIC_PROPERTY:
return new DynamicAccess.dynamicProperty(deserializeName(decoder));
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
return new DynamicAccess.ifNotNullProperty(deserializeName(decoder));
case AccessKind.CLASS_TYPE_LITERAL:
case AccessKind.TYPEDEF_TYPE_LITERAL:
case AccessKind.DYNAMIC_TYPE_LITERAL:
return new ConstantAccess(kind, decoder.getConstant(Key.CONSTANT));
case AccessKind.LOCAL_FUNCTION:
case AccessKind.LOCAL_VARIABLE:
case AccessKind.FINAL_LOCAL_VARIABLE:
case AccessKind.PARAMETER:
case AccessKind.FINAL_PARAMETER:
case AccessKind.STATIC_FIELD:
case AccessKind.FINAL_STATIC_FIELD:
case AccessKind.STATIC_METHOD:
case AccessKind.STATIC_GETTER:
case AccessKind.STATIC_SETTER:
case AccessKind.TOPLEVEL_FIELD:
case AccessKind.FINAL_TOPLEVEL_FIELD:
case AccessKind.TOPLEVEL_METHOD:
case AccessKind.TOPLEVEL_GETTER:
case AccessKind.TOPLEVEL_SETTER:
case AccessKind.SUPER_FIELD:
case AccessKind.SUPER_FINAL_FIELD:
case AccessKind.SUPER_METHOD:
case AccessKind.SUPER_GETTER:
case AccessKind.SUPER_SETTER:
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
case AccessKind.UNRESOLVED:
case AccessKind.UNRESOLVED_SUPER:
case AccessKind.INVALID:
return new StaticAccess.internal(kind, decoder.getElement(Key.ELEMENT));
case AccessKind.COMPOUND:
CompoundAccessKind compoundAccessKind =
decoder.getEnum(Key.SUB_KIND, CompoundAccessKind.values);
Element getter = decoder.getElement(Key.GETTER);
Element setter = decoder.getElement(Key.SETTER);
return new CompoundAccessSemantics(compoundAccessKind, getter, setter);
case AccessKind.CONSTANT:
throw new UnsupportedError('Unsupported access kind: $kind');
}
}
/// Serialize a reference from [context] to an [element] which might be a member
/// of an unnamed mixin application. If it is, [element] is by serialized
/// indirectly by name in the [nameKey] of [encoder], otherwise [element] is
/// serialized directly in [elementKey] in [encoder].
void serializeElementReference(Element context, Key elementKey, Key nameKey,
ObjectEncoder encoder, Element element) {
if (element.isGenerativeConstructor &&
element.enclosingClass.isUnnamedMixinApplication) {
assert(invariant(element, element.isConstructor,
message: "Unexpected reference of forwarding constructor "
"${element} from $context."));
encoder.setString(nameKey, element.name);
} else {
encoder.setElement(elementKey, element);
}
}
/// Deserialize a reference from [context] to an [Element] which might be a
/// member of an unnamed mixin application. If it is, the [Element] is by
/// deserialized indirectly by name from [nameKey] in [decoder], otherwise
/// the [Element] is deserialized directly from [elementKey] in [encoder].
Element deserializeElementReference(
Element context, Key elementKey, Key nameKey, ObjectDecoder decoder,
{bool isOptional: false}) {
Element element = decoder.getElement(elementKey, isOptional: true);
if (element == null) {
String elementName = decoder.getString(nameKey, isOptional: isOptional);
if (elementName == null) {
return null;
}
ClassElement cls;
if (context is ClassElement) {
assert(invariant(NO_LOCATION_SPANNABLE, context.isNamedMixinApplication,
message: "Unexpected reference of forwarding constructor "
"'${elementName}' from $context."));
cls = context;
} else {
assert(invariant(NO_LOCATION_SPANNABLE, context.isConstructor,
message: "Unexpected reference of forwarding constructor "
"'${elementName}' from $context."));
cls = context.enclosingClass;
}
ClassElement superclass = cls.superclass;
element = superclass.lookupConstructor(elementName);
assert(invariant(NO_LOCATION_SPANNABLE, element != null,
message: "Unresolved reference of forwarding constructor "
"'${elementName}' from $context."));
}
return element;
}
void serializeMessageArguments(
ObjectEncoder encoder, Key key, Map<String, dynamic> messageArguments) {
if (messageArguments.isNotEmpty) {
MapEncoder mapEncoder = encoder.createMap(Key.ARGUMENTS);
messageArguments.forEach((String key, var value) {
mapEncoder.setString(key, Message.convertToString(value));
});
}
}
Map<String, String> deserializeMessageArguments(
ObjectDecoder decoder, Key key) {
Map<String, String> arguments = <String, String>{};
MapDecoder mapDecoder = decoder.getMap(key, isOptional: true);
if (mapDecoder != null) {
mapDecoder.forEachKey((String key) {
arguments[key] = mapDecoder.getString(key);
});
}
return arguments;
}
void serializeSourceSpan(ObjectEncoder encoder, SourceSpan sourceSpan) {
encoder.setUri(Key.URI, sourceSpan.uri, sourceSpan.uri);
encoder.setInt(Key.OFFSET, sourceSpan.begin);
encoder.setInt(Key.LENGTH, sourceSpan.end - sourceSpan.begin);
}
SourceSpan deserializeSourceSpan(ObjectDecoder decoder) {
Uri uri = decoder.getUri(Key.URI);
int offset = decoder.getInt(Key.OFFSET);
int length = decoder.getInt(Key.LENGTH);
return new SourceSpan(uri, offset, offset + length);
}
void serializeWrappedMessage(
ObjectEncoder encoder, Key key, WrappedMessage message) {
ObjectEncoder object = encoder.createObject(key);
if (message.sourceSpan != null) {
serializeSourceSpan(
object.createObject(Key.SOURCE_SPAN), message.sourceSpan);
}
object.setEnum(Key.KIND, message.messageKind);
serializeMessageArguments(object, Key.ARGUMENTS, message.messageArguments);
}
WrappedMessage deserializeWrappedMessage(ObjectDecoder decoder, Key key) {
ObjectDecoder object = decoder.getObject(key);
SourceSpan sourceSpan;
ObjectDecoder sourceSpanDecoder =
object.getObject(Key.SOURCE_SPAN, isOptional: true);
if (sourceSpanDecoder != null) {
sourceSpan = deserializeSourceSpan(sourceSpanDecoder);
}
MessageKind messageKind = object.getEnum(Key.KIND, MessageKind.values);
Map<String, dynamic> messageArguments =
deserializeMessageArguments(object, Key.ARGUMENTS);
return new WrappedMessage(sourceSpan, messageKind, messageArguments);
}