blob: 38e20f53bb04d01ba44005bcc291e12f9f854c34 [file] [log] [blame] [edit]
// Copyright (c) 2017, 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;
import 'package:kernel/ast.dart' as ir show LocalFunction;
import '../common/names.dart' show Names;
import '../elements/entities.dart';
import '../elements/entity_map.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../serialization/serialization.dart';
import '../universe/class_set.dart' show ClassHierarchyNodesMapKey;
import '../universe/selector.dart';
import 'closure.dart';
import 'records.dart' show JRecordClass, JRecordGetter;
const String jsElementPrefix = 'j:';
class JLibrary with EntityMapKey implements LibraryEntity {
/// Tag used for identifying serialized [JLibrary] objects in a
/// debugging data stream.
static const String tag = 'library';
@override
final String name;
@override
final Uri canonicalUri;
JLibrary(this.name, this.canonicalUri);
/// Deserializes a [JLibrary] object from [source].
factory JLibrary.readFromDataSource(DataSourceReader source) {
source.begin(tag);
String name = source.readString();
Uri canonicalUri = source.readUri();
source.end(tag);
return JLibrary(name, canonicalUri);
}
/// Serializes this [JLibrary] to [sink].
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeString(name);
sink.writeUri(canonicalUri);
sink.end(tag);
}
@override
String toString() => '${jsElementPrefix}library($name)';
}
/// Enum used for identifying [JClass] subclasses in serialization.
enum JClassKind { node, closure, context, record }
class JClass
with ClassHierarchyNodesMapKey, EntityMapKey
implements ClassEntity {
/// Tag used for identifying serialized [JClass] objects in a
/// debugging data stream.
static const String tag = 'class';
@override
final JLibrary library;
@override
final String name;
@override
final bool isAbstract;
JClass(this.library, this.name, {required this.isAbstract});
/// Deserializes a [JClass] object from [source].
factory JClass.readFromDataSource(DataSourceReader source) {
JClassKind kind = source.readEnum(JClassKind.values);
switch (kind) {
case JClassKind.node:
source.begin(tag);
final library = source.readLibrary() as JLibrary;
String name = source.readString();
bool isAbstract = source.readBool();
source.end(tag);
return JClass(library, name, isAbstract: isAbstract);
case JClassKind.closure:
return JClosureClass.readFromDataSource(source);
case JClassKind.context:
return JContext.readFromDataSource(source);
case JClassKind.record:
return JRecordClass.readFromDataSource(source);
}
}
/// Serializes this [JClass] to [sink].
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassKind.node);
sink.begin(tag);
sink.writeLibrary(library);
sink.writeString(name);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isClosure => false;
@override
String toString() => '${jsElementPrefix}class($name)';
}
/// Enum used for identifying [JMember] subclasses in serialization.
enum JMemberKind {
generativeConstructor,
factoryConstructor,
constructorBody,
field,
getter,
setter,
method,
closureField,
closureCallMethod,
generatorBody,
signatureMethod,
contextField,
recordGetter,
parameterStub,
}
@override
String _membertoString(JMember member) =>
'$jsElementPrefix${member._kind}'
'(${member.enclosingClass != null ? '${member.enclosingClass!.name}.' : ''}'
'${member.name})';
abstract class JMember with EntityMapKey implements MemberEntity {
@override
final JLibrary library;
@override
final JClass? enclosingClass;
final Name _name;
final bool _isStatic;
JMember(
this.library,
this.enclosingClass,
this._name, {
bool isStatic = false,
}) : _isStatic = isStatic;
/// Deserializes a [JMember] object from [source].
factory JMember.readFromDataSource(DataSourceReader source) {
JMemberKind kind = source.readEnum(JMemberKind.values);
switch (kind) {
case JMemberKind.generativeConstructor:
return JGenerativeConstructor.readFromDataSource(source);
case JMemberKind.factoryConstructor:
return JFactoryConstructor.readFromDataSource(source);
case JMemberKind.constructorBody:
return JConstructorBody.readFromDataSource(source);
case JMemberKind.field:
return JField.readFromDataSource(source);
case JMemberKind.getter:
return JGetter.readFromDataSource(source);
case JMemberKind.setter:
return JSetter.readFromDataSource(source);
case JMemberKind.method:
return JMethod.readFromDataSource(source);
case JMemberKind.closureField:
return JClosureField.readFromDataSource(source);
case JMemberKind.closureCallMethod:
return JClosureCallMethod.readFromDataSource(source);
case JMemberKind.generatorBody:
return JGeneratorBody.readFromDataSource(source);
case JMemberKind.signatureMethod:
return JSignatureMethod.readFromDataSource(source);
case JMemberKind.contextField:
return JContextField.readFromDataSource(source);
case JMemberKind.recordGetter:
return JRecordGetter.readFromDataSource(source);
case JMemberKind.parameterStub:
return JParameterStub.readFromDataSource(source);
}
}
/// Serializes this [JMember] to [sink].
void writeToDataSink(DataSinkWriter sink);
@override
String get name => _name.text;
@override
Name get memberName => _name;
@override
bool get isAssignable => false;
@override
bool get isConst => false;
@override
bool get isAbstract => false;
@override
bool get isSetter => false;
@override
bool get isGetter => false;
@override
bool get isFunction => false;
@override
bool get isInstanceMember => enclosingClass != null && !_isStatic;
@override
bool get isStatic => enclosingClass != null && _isStatic;
@override
bool get isTopLevel => enclosingClass == null;
String get _kind;
@override
String toString() => _membertoString(this);
}
abstract class JFunction extends JMember implements FunctionEntity {
@override
final ParameterStructure parameterStructure;
@override
final bool isExternal;
@override
final AsyncMarker asyncMarker;
JFunction(
super.library,
super.enclosingClass,
super.name,
this.parameterStructure,
this.asyncMarker, {
super.isStatic,
this.isExternal = false,
});
}
abstract class JConstructor extends JFunction implements ConstructorEntity {
@override
final bool isConst;
JConstructor(
JClass enclosingClass,
Name name,
ParameterStructure parameterStructure, {
required bool isExternal,
required this.isConst,
}) : super(
enclosingClass.library,
enclosingClass,
name,
parameterStructure,
AsyncMarker.sync,
isExternal: isExternal,
);
@override
JClass get enclosingClass => super.enclosingClass!;
@override
bool get isInstanceMember => false;
@override
bool get isStatic => false;
@override
bool get isTopLevel => false;
@override
bool get isFromEnvironmentConstructor => false;
@override
String get _kind => 'constructor';
}
class JGenerativeConstructor extends JConstructor {
/// Tag used for identifying serialized [JGenerativeConstructor] objects in a
/// debugging data stream.
static const String tag = 'generative-constructor';
JGenerativeConstructor(
super.enclosingClass,
super.name,
super.parameterStructure, {
required super.isExternal,
required super.isConst,
});
factory JGenerativeConstructor.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final enclosingClass = source.readClass() as JClass;
String name = source.readString();
ParameterStructure parameterStructure =
ParameterStructure.readFromDataSource(source);
bool isExternal = source.readBool();
bool isConst = source.readBool();
source.end(tag);
return JGenerativeConstructor(
enclosingClass,
Name(name, enclosingClass.library.canonicalUri),
parameterStructure,
isExternal: isExternal,
isConst: isConst,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.generativeConstructor);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.writeString(name);
parameterStructure.writeToDataSink(sink);
sink.writeBool(isExternal);
sink.writeBool(isConst);
sink.end(tag);
}
@override
bool get isFactoryConstructor => false;
@override
bool get isGenerativeConstructor => true;
}
class JFactoryConstructor extends JConstructor {
/// Tag used for identifying serialized [JFactoryConstructor] objects in a
/// debugging data stream.
static const String tag = 'factory-constructor';
@override
final bool isFromEnvironmentConstructor;
JFactoryConstructor(
super.enclosingClass,
super.name,
super.parameterStructure, {
required super.isExternal,
required super.isConst,
required this.isFromEnvironmentConstructor,
});
factory JFactoryConstructor.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final enclosingClass = source.readClass() as JClass;
String name = source.readString();
ParameterStructure parameterStructure =
ParameterStructure.readFromDataSource(source);
bool isExternal = source.readBool();
bool isConst = source.readBool();
bool isFromEnvironmentConstructor = source.readBool();
source.end(tag);
return JFactoryConstructor(
enclosingClass,
Name(name, enclosingClass.library.canonicalUri),
parameterStructure,
isExternal: isExternal,
isConst: isConst,
isFromEnvironmentConstructor: isFromEnvironmentConstructor,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.factoryConstructor);
sink.begin(tag);
sink.writeClass(enclosingClass);
sink.writeString(name);
parameterStructure.writeToDataSink(sink);
sink.writeBool(isExternal);
sink.writeBool(isConst);
sink.writeBool(isFromEnvironmentConstructor);
sink.end(tag);
}
@override
bool get isFactoryConstructor => true;
@override
bool get isGenerativeConstructor => false;
}
class JConstructorBody extends JFunction implements ConstructorBodyEntity {
/// Tag used for identifying serialized [JConstructorBody] objects in a
/// debugging data stream.
static const String tag = 'constructor-body';
@override
final JConstructor constructor;
JConstructorBody(this.constructor, ParameterStructure parameterStructure)
: super(
constructor.library,
constructor.enclosingClass,
constructor.memberName,
parameterStructure,
AsyncMarker.sync,
isStatic: false,
isExternal: constructor.isExternal,
);
factory JConstructorBody.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final constructor = source.readMember() as JConstructor;
ParameterStructure parameterStructure =
ParameterStructure.readFromDataSource(source);
source.end(tag);
return JConstructorBody(constructor, parameterStructure);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.constructorBody);
sink.begin(tag);
sink.writeMember(constructor);
parameterStructure.writeToDataSink(sink);
sink.end(tag);
}
@override
String get _kind => 'constructor_body';
/// These lazy member bodies implement `==` since different SSA shards can
/// create different copies of the same constructor body. Upon deserialization
/// we should consider the different copies equivalent.
@override
bool operator ==(Object other) {
return other is JConstructorBody && constructor == other.constructor;
}
@override
int get hashCode => constructor.hashCode + 7;
}
class JParameterStub with EntityMapKey implements JMethod {
static const String kind = 'parameter-stub';
final JFunction target;
@override
final ParameterStructure parameterStructure;
final Selector? callSelector;
final bool needsSuper;
JParameterStub(
this.target,
this.parameterStructure, {
required this.callSelector,
required this.needsSuper,
});
@override
String toString() => _membertoString(this);
@override
String get _kind => 'parameter_stub';
@override
bool get _isStatic => target._isStatic;
@override
Name get _name => target._name;
@override
AsyncMarker get asyncMarker => target.asyncMarker;
@override
JClass? get enclosingClass => target.enclosingClass;
@override
bool get isAbstract => target.isAbstract;
@override
bool get isAssignable => target.isAssignable;
@override
bool get isConst => target.isConst;
@override
bool get isExternal => target.isExternal;
@override
bool get isFunction => target.isFunction;
@override
bool get isGetter => target.isGetter;
@override
bool get isInstanceMember => target.isInstanceMember;
@override
bool get isSetter => target.isSetter;
@override
bool get isStatic => target.isStatic;
@override
bool get isTopLevel => target.isTopLevel;
@override
JLibrary get library => target.library;
@override
Name get memberName => target.memberName;
@override
String get name => target.name;
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.parameterStub);
sink.begin(kind);
sink.writeMember(target);
parameterStructure.writeToDataSink(sink);
sink.writeValueOrNull(callSelector, (value) => value.writeToDataSink(sink));
sink.writeBool(needsSuper);
sink.end(kind);
}
factory JParameterStub.readFromDataSource(DataSourceReader source) {
source.begin(kind);
final target = source.readMember() as JFunction;
final parameterStructure = ParameterStructure.readFromDataSource(source);
final callSelector = source.readValueOrNull(
() => Selector.readFromDataSource(source),
);
final needsSuper = source.readBool();
source.end(kind);
return JParameterStub(
target,
parameterStructure,
callSelector: callSelector,
needsSuper: needsSuper,
);
}
}
class JMethod extends JFunction {
/// Tag used for identifying serialized [JMethod] objects in a
/// debugging data stream.
static const String tag = 'method';
@override
final bool isAbstract;
JMethod(
super.library,
super.enclosingClass,
super.name,
super.parameterStructure,
super.asyncMarker, {
required super.isStatic,
required super.isExternal,
required this.isAbstract,
});
factory JMethod.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
late final JLibrary library;
JClass? enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary() as JLibrary;
break;
case MemberContextKind.cls:
enclosingClass = source.readClass() as JClass;
library = enclosingClass.library;
break;
}
Name memberName = source.readMemberName();
ParameterStructure parameterStructure =
ParameterStructure.readFromDataSource(source);
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return JMethod(
library,
enclosingClass,
memberName,
parameterStructure,
asyncMarker,
isStatic: isStatic,
isExternal: isExternal,
isAbstract: isAbstract,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.method);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass!);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeMemberName(memberName);
parameterStructure.writeToDataSink(sink);
sink.writeEnum(asyncMarker);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isFunction => true;
@override
String get _kind => 'method';
}
class JGeneratorBody extends JFunction {
/// Tag used for identifying serialized [JGeneratorBody] objects in a
/// debugging data stream.
static const String tag = 'generator-body';
final JFunction function;
final DartType elementType;
@override
final int hashCode;
JGeneratorBody(this.function, this.elementType)
: hashCode = function.hashCode + 1, // Hack stabilize sort order.
super(
function.library,
function.enclosingClass,
function.memberName,
function.parameterStructure,
function.asyncMarker,
isStatic: function.isStatic,
isExternal: false,
);
factory JGeneratorBody.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final function = source.readMember() as JFunction;
DartType elementType = source.readDartType();
source.end(tag);
return JGeneratorBody(function, elementType);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.generatorBody);
sink.begin(tag);
sink.writeMember(function);
sink.writeDartType(elementType);
sink.end(tag);
}
@override
String get _kind => 'generator_body';
/// These lazy member bodies implement `==` since different SSA shards can
/// create different copies of the same constructor body. Upon deserialization
/// we should consider the different copies equivalent.
@override
bool operator ==(Object other) {
return other is JGeneratorBody && function == other.function;
}
}
class JGetter extends JFunction {
/// Tag used for identifying serialized [JGetter] objects in a
/// debugging data stream.
static const String tag = 'getter';
@override
final bool isAbstract;
JGetter(
JLibrary library,
JClass? enclosingClass,
Name name,
AsyncMarker asyncMarker, {
required bool isStatic,
required bool isExternal,
required this.isAbstract,
}) : super(
library,
enclosingClass,
name,
ParameterStructure.getter,
asyncMarker,
isStatic: isStatic,
isExternal: isExternal,
);
factory JGetter.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
late final JLibrary library;
JClass? enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary() as JLibrary;
break;
case MemberContextKind.cls:
enclosingClass = source.readClass() as JClass;
library = enclosingClass.library;
break;
}
Name memberName = source.readMemberName();
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return JGetter(
library,
enclosingClass,
memberName,
asyncMarker,
isStatic: isStatic,
isExternal: isExternal,
isAbstract: isAbstract,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.getter);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass!);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeMemberName(memberName);
sink.writeEnum(asyncMarker);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isGetter => true;
@override
String get _kind => 'getter';
}
class JSetter extends JFunction {
/// Tag used for identifying serialized [JSetter] objects in a
/// debugging data stream.
static const String tag = 'setter';
@override
final bool isAbstract;
JSetter(
JLibrary library,
JClass? enclosingClass,
Name name, {
required bool isStatic,
required bool isExternal,
required this.isAbstract,
}) : super(
library,
enclosingClass,
name,
ParameterStructure.setter,
AsyncMarker.sync,
isStatic: isStatic,
isExternal: isExternal,
);
factory JSetter.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
late final JLibrary library;
JClass? enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary() as JLibrary;
break;
case MemberContextKind.cls:
enclosingClass = source.readClass() as JClass;
library = enclosingClass.library;
break;
}
Name memberName = source.readMemberName();
bool isStatic = source.readBool();
bool isExternal = source.readBool();
bool isAbstract = source.readBool();
source.end(tag);
return JSetter(
library,
enclosingClass,
memberName,
isStatic: isStatic,
isExternal: isExternal,
isAbstract: isAbstract,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.setter);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass!);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeMemberName(memberName);
sink.writeBool(isStatic);
sink.writeBool(isExternal);
sink.writeBool(isAbstract);
sink.end(tag);
}
@override
bool get isAssignable => true;
@override
bool get isSetter => true;
@override
String get _kind => 'setter';
}
class JField extends JMember implements FieldEntity {
/// Tag used for identifying serialized [JField] objects in a
/// debugging data stream.
static const String tag = 'field';
@override
final bool isAssignable;
@override
final bool isConst;
JField(
super.library,
super.enclosingClass,
super.name, {
required super.isStatic,
required this.isAssignable,
required this.isConst,
});
factory JField.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberContextKind kind = source.readEnum(MemberContextKind.values);
late final JLibrary library;
JClass? enclosingClass;
switch (kind) {
case MemberContextKind.library:
library = source.readLibrary() as JLibrary;
break;
case MemberContextKind.cls:
enclosingClass = source.readClass() as JClass;
library = enclosingClass.library;
break;
}
Name memberName = source.readMemberName();
bool isStatic = source.readBool();
bool isAssignable = source.readBool();
bool isConst = source.readBool();
source.end(tag);
return JField(
library,
enclosingClass,
memberName,
isStatic: isStatic,
isAssignable: isAssignable,
isConst: isConst,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.field);
sink.begin(tag);
if (enclosingClass != null) {
sink.writeEnum(MemberContextKind.cls);
sink.writeClass(enclosingClass!);
} else {
sink.writeEnum(MemberContextKind.library);
sink.writeLibrary(library);
}
sink.writeMemberName(memberName);
sink.writeBool(isStatic);
sink.writeBool(isAssignable);
sink.writeBool(isConst);
sink.end(tag);
}
@override
String get _kind => 'field';
}
class JClosureCallMethod extends JMethod {
/// Tag used for identifying serialized [JClosureCallMethod] objects in a
/// debugging data stream.
static const String tag = 'closure-call-method';
JClosureCallMethod(
ClassEntity enclosingClass,
ParameterStructure parameterStructure,
AsyncMarker asyncMarker,
) : super(
enclosingClass.library as JLibrary,
enclosingClass as JClass,
Names.call,
parameterStructure,
asyncMarker,
isStatic: false,
isExternal: false,
isAbstract: false,
);
factory JClosureCallMethod.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final enclosingClass = source.readClass() as JClass;
ParameterStructure parameterStructure =
ParameterStructure.readFromDataSource(source);
AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
source.end(tag);
return JClosureCallMethod(enclosingClass, parameterStructure, asyncMarker);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.closureCallMethod);
sink.begin(tag);
sink.writeClass(enclosingClass!);
parameterStructure.writeToDataSink(sink);
sink.writeEnum(asyncMarker);
sink.end(tag);
}
@override
String get _kind => 'closure_call';
}
/// A method that returns the signature of the Dart closure/tearoff that this
/// method's parent class is representing.
class JSignatureMethod extends JMethod {
/// Tag used for identifying serialized [JSignatureMethod] objects in a
/// debugging data stream.
static const String tag = 'signature-method';
JSignatureMethod(ClassEntity enclosingClass)
: super(
enclosingClass.library as JLibrary,
enclosingClass as JClass,
Names.signature,
ParameterStructure.zeroArguments,
AsyncMarker.sync,
isStatic: false,
isExternal: false,
isAbstract: false,
);
factory JSignatureMethod.readFromDataSource(DataSourceReader source) {
source.begin(tag);
final cls = source.readClass() as JClass;
source.end(tag);
return JSignatureMethod(cls);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberKind.signatureMethod);
sink.begin(tag);
sink.writeClass(enclosingClass!);
sink.end(tag);
}
@override
String get _kind => 'signature';
}
/// Enum used for identifying [JTypeVariable] variants in serialization.
///
/// [JLocalTypeVariable] in the K-world can contain a [Local] as its
/// `typeDeclaration` but those are never serialized. When converted to the
/// J-world they use a [JClosureCallMethod] as [JTypeVariable.typeDeclaration].
enum JTypeVariableKind { cls, member }
class JTypeVariable with EntityMapKey implements TypeVariableEntity {
/// Tag used for identifying serialized [JTypeVariable] objects in a
/// debugging data stream.
static const String tag = 'type-variable';
@override
final Entity typeDeclaration;
@override
final String name;
@override
final int index;
JTypeVariable(this.typeDeclaration, this.name, this.index) {
assert(typeDeclaration is ClassEntity || typeDeclaration is MemberEntity);
}
/// Deserializes a [JTypeVariable] object from [source].
factory JTypeVariable.readFromDataSource(DataSourceReader source) {
source.begin(tag);
JTypeVariableKind kind = source.readEnum(JTypeVariableKind.values);
Entity typeDeclaration;
switch (kind) {
case JTypeVariableKind.cls:
typeDeclaration = source.readClass();
break;
case JTypeVariableKind.member:
typeDeclaration = source.readMember();
break;
}
String name = source.readString();
int index = source.readInt();
source.end(tag);
return JTypeVariable(typeDeclaration, name, index);
}
/// Serializes this [JTypeVariable] to [sink].
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
final declaration = typeDeclaration;
if (declaration is ClassEntity) {
sink.writeEnum(JTypeVariableKind.cls);
sink.writeClass(declaration);
} else if (declaration is MemberEntity) {
sink.writeEnum(JTypeVariableKind.member);
sink.writeMember(declaration);
} else {
throw UnsupportedError(
"Unexpected type variable declarer $typeDeclaration.",
);
}
sink.writeString(name);
sink.writeInt(index);
sink.end(tag);
}
@override
String toString() =>
'${jsElementPrefix}type_variable(${typeDeclaration.name}.$name)';
}
class JLocalFunction implements Local {
@override
final String? name;
final MemberEntity memberContext;
final Entity executableContext;
final ir.LocalFunction node;
late final FunctionType functionType;
JLocalFunction(
this.name,
this.memberContext,
this.executableContext,
this.node,
);
@override
String toString() =>
'${jsElementPrefix}local_function'
'(${memberContext.name}.${name ?? '<anonymous>'})';
}
class JLocalTypeVariable implements TypeVariableEntity {
@override
final JLocalFunction typeDeclaration;
@override
final String name;
@override
final int index;
late final DartType bound;
late final DartType defaultType;
JLocalTypeVariable(this.typeDeclaration, this.name, this.index);
@override
String toString() =>
'${jsElementPrefix}local_type_variable(${typeDeclaration.name}.$name)';
}