blob: 5ddd67b211b7aab14125baaf4bcb502125d9c1e5 [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:js_shared/variance.dart';
import 'package:kernel/ast.dart' as ir;
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../ir/element_map.dart';
import '../ir/util.dart';
import '../js_model/class_type_variable_access.dart';
import '../ordered_typeset.dart';
import '../serialization/deferrable.dart';
import '../serialization/serialization.dart';
import 'closure.dart'
show
ClosureClassData,
ContextClassData,
ClosureFunctionData,
ClosureFieldData;
import 'element_map.dart'
show
ClassDefinition,
JsToElementMap,
MemberDefinition,
forEachOrderedParameterByFunctionNode;
import 'element_map_impl.dart';
import 'elements.dart';
import 'records.dart' show RecordClassData, RecordGetterData;
/// Environment for fast lookup of component libraries.
class JProgramEnv {
final Iterable<ir.Component> _components;
final Map<Uri, JLibraryEnv> _libraryMap = {};
JProgramEnv(this._components);
/// TODO(johnniwinther): Handle arbitrary load order if needed.
ir.Member? get mainMethod => _components.first.mainMethod;
ir.Component get mainComponent => _components.first;
void registerLibrary(JLibraryEnv env) {
_libraryMap[env.library.importUri] = env;
}
/// Return the [JLibraryEnv] for the library with the canonical [uri].
JLibraryEnv? lookupLibrary(Uri uri) {
return _libraryMap[uri];
}
/// Calls [f] for each library in this environment.
void forEachLibrary(void Function(JLibraryEnv library) f) {
_libraryMap.values.forEach(f);
}
/// Returns the number of libraries in this environment.
int get length {
return _libraryMap.length;
}
}
/// Environment for fast lookup of library classes and members.
class JLibraryEnv {
/// Tag used for identifying serialized [JLibraryEnv] objects in a
/// debugging data stream.
static const String tag = 'library-env';
final ir.Library library;
final Map<String, JClassEnv> _classMap = {};
final Map<String, ir.Member> _memberMap;
final Map<String, ir.Member> _setterMap;
JLibraryEnv(this.library, this._memberMap, this._setterMap);
/// Deserializes a [JLibraryEnv] object from [source].
factory JLibraryEnv.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Library library = source.readLibraryNode();
Map<String, ir.Member> memberMap = source.readStringMap(
source.readMemberNode,
);
Map<String, ir.Member> setterMap = source.readStringMap(
source.readMemberNode,
);
source.end(tag);
return JLibraryEnv(library, memberMap, setterMap);
}
/// Serializes this [JLibraryEnv] to [sink].
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeLibraryNode(library);
sink.writeStringMap(_memberMap, sink.writeMemberNode);
sink.writeStringMap(_setterMap, sink.writeMemberNode);
sink.end(tag);
}
void registerClass(String name, JClassEnv classEnv) {
_classMap[name] = classEnv;
}
/// Return the [JClassEnv] for the class [name] in [library].
JClassEnv? lookupClass(String name) {
return _classMap[name];
}
/// Calls [f] for each class in this library.
void forEachClass(void Function(JClassEnv cls) f) {
_classMap.values.forEach(f);
}
/// Return the [ir.Member] for the member [name] in [library].
ir.Member? lookupMember(String name, {bool setter = false}) {
return setter ? _setterMap[name] : _memberMap[name];
}
void forEachMember(void Function(ir.Member member) f) {
_memberMap.values.forEach(f);
for (ir.Member member in _setterMap.values) {
if (member is ir.Procedure) {
f(member);
} else {
// Skip fields; these are also in _memberMap.
}
}
}
}
class JLibraryData {
/// Tag used for identifying serialized [JLibraryData] objects in a
/// debugging data stream.
static const String tag = 'library-data';
final ir.Library library;
// TODO(johnniwinther): Avoid direct access to [imports]. It might be null if
// it hasn't been computed for the corresponding [KLibraryData].
final Map<ir.LibraryDependency, ImportEntity> imports;
JLibraryData(this.library, this.imports);
factory JLibraryData.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Library library = source.readLibraryNode();
int importCount = source.readInt();
Map<ir.LibraryDependency, ImportEntity> imports;
if (importCount > 0) {
imports = {};
for (int i = 0; i < importCount; i++) {
int index = source.readInt();
ImportEntity import = source.readImport();
imports[library.dependencies[index]] = import;
}
} else {
imports = const {};
}
source.end(tag);
return JLibraryData(library, imports);
}
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeLibraryNode(library);
sink.writeInt(imports.length);
int index = 0;
for (ir.LibraryDependency node in library.dependencies) {
ImportEntity? import = imports[node];
if (import != null) {
sink.writeInt(index);
sink.writeImport(import);
}
index++;
}
sink.end(tag);
}
}
/// Enum used for identifying [JClassEnv] subclasses in serialization.
enum JClassEnvKind { node, closure, context, record }
/// Member data for a class.
abstract class JClassEnv {
/// Deserializes a [JClassEnv] object from [source].
factory JClassEnv.readFromDataSource(DataSourceReader source) {
JClassEnvKind kind = source.readEnum(JClassEnvKind.values);
switch (kind) {
case JClassEnvKind.node:
return JClassEnvImpl.readFromDataSource(source);
case JClassEnvKind.closure:
return ClosureClassEnv.readFromDataSource(source);
case JClassEnvKind.context:
return ContextEnv.readFromDataSource(source);
case JClassEnvKind.record:
return RecordClassEnv.readFromDataSource(source);
}
}
/// Serializes this [JClassEnv] to [sink].
void writeToDataSink(DataSinkWriter sink);
/// The [ir.Class] that defined the class, if any.
ir.Class? get cls;
/// Whether the class is an unnamed mixin application.
bool get isUnnamedMixinApplication;
/// Whether the class is a mixin application with its own members.
///
/// This occurs when a mixin contains methods with super calls or when
/// the mixin application contains concrete forwarding stubs.
bool get isMixinApplicationWithMembers;
/// Return the [MemberEntity] for the member [name] in the class. If [setter]
/// is `true`, the setter or assignable field corresponding to [name] is
/// returned.
MemberEntity? lookupMember(IrToElementMap elementMap, Name name);
/// Calls [f] for each member of [cls].
void forEachMember(
IrToElementMap elementMap,
void Function(MemberEntity member) f,
);
/// Return the [ConstructorEntity] for the constructor [name] in [cls].
ConstructorEntity? lookupConstructor(IrToElementMap elementMap, String name);
/// Calls [f] for each constructor of [cls].
void forEachConstructor(
IrToElementMap elementMap,
void Function(ConstructorEntity constructor) f,
);
/// Calls [f] for each constructor body for the live constructors in the
/// class.
void forEachConstructorBody(
void Function(ConstructorBodyEntity constructor) f,
);
}
/// Environment for fast lookup of class members.
class JClassEnvImpl implements JClassEnv {
/// Tag used for identifying serialized [JClassEnv] objects in a
/// debugging data stream.
static const String tag = 'class-env';
@override
final ir.Class cls;
final Map<String, ir.Member> _constructorMap;
final Map<Name, ir.Member> _memberMap;
final List<ir.Member> _members; // in declaration order.
@override
final bool isMixinApplicationWithMembers;
/// Constructor bodies created for this class.
List<ConstructorBodyEntity>? _constructorBodyList;
JClassEnvImpl(
this.cls,
this._constructorMap,
this._memberMap,
this._members,
this.isMixinApplicationWithMembers,
);
factory JClassEnvImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Class cls = source.readClassNode();
Map<String, ir.Member> constructorMap = source.readStringMap(
source.readMemberNode,
);
Map<Name, ir.Member> memberMap = source.readNameMap(source.readMemberNode);
List<ir.Member> members = source.readMemberNodes();
bool isSuperMixinApplication = source.readBool();
source.end(tag);
return JClassEnvImpl(
cls,
constructorMap,
memberMap,
members,
isSuperMixinApplication,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassEnvKind.node);
sink.begin(tag);
sink.writeClassNode(cls);
sink.writeStringMap(_constructorMap, sink.writeMemberNode);
sink.writeNameMap(_memberMap, sink.writeMemberNode);
sink.writeMemberNodes(_members);
sink.writeBool(isMixinApplicationWithMembers);
sink.end(tag);
}
@override
bool get isUnnamedMixinApplication => cls.isAnonymousMixin;
@override
MemberEntity? lookupMember(IrToElementMap elementMap, Name name) {
ir.Member? member = _memberMap[name];
return member != null ? elementMap.getMember(member) : null;
}
@override
void forEachMember(
IrToElementMap elementMap,
void Function(MemberEntity member) f,
) {
for (var member in _members) {
f(elementMap.getMember(member));
}
}
@override
ConstructorEntity? lookupConstructor(IrToElementMap elementMap, String name) {
ir.Member? constructor = _constructorMap[name];
return constructor != null ? elementMap.getConstructor(constructor) : null;
}
@override
void forEachConstructor(
IrToElementMap elementMap,
void Function(ConstructorEntity constructor) f,
) {
for (var constructor in _constructorMap.values) {
f(elementMap.getConstructor(constructor));
}
}
void addConstructorBody(ConstructorBodyEntity constructorBody) {
(_constructorBodyList ??= <ConstructorBodyEntity>[]).add(constructorBody);
}
@override
void forEachConstructorBody(
void Function(ConstructorBodyEntity constructor) f,
) {
_constructorBodyList?.forEach(f);
}
}
class ContextEnv implements JClassEnv {
/// Tag used for identifying serialized [ContextEnv] objects in a debugging
/// data stream.
static const String tag = 'context-env';
final Map<Name, MemberEntity> _memberMap;
ContextEnv(this._memberMap);
factory ContextEnv.readFromDataSource(DataSourceReader source) {
source.begin(tag);
Map<Name, MemberEntity> memberMap = source.readNameMap(
() => source.readMember(),
);
source.end(tag);
return ContextEnv(memberMap);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassEnvKind.context);
sink.begin(tag);
sink.writeNameMap(_memberMap, (member) => sink.writeMember(member));
sink.end(tag);
}
@override
void forEachConstructorBody(
void Function(ConstructorBodyEntity constructor) f,
) {
// We do not create constructor bodies for containers.
}
@override
void forEachConstructor(
IrToElementMap elementMap,
void Function(ConstructorEntity constructor) f,
) {
// We do not create constructors for containers.
}
@override
ConstructorEntity? lookupConstructor(IrToElementMap elementMap, String name) {
// We do not create constructors for containers.
return null;
}
@override
void forEachMember(
IrToElementMap elementMap,
void Function(MemberEntity member) f,
) {
_memberMap.values.forEach(f);
}
@override
MemberEntity? lookupMember(IrToElementMap elementMap, Name name) {
return _memberMap[name];
}
@override
bool get isUnnamedMixinApplication => false;
@override
bool get isMixinApplicationWithMembers => false;
@override
ir.Class? get cls => null;
}
class ClosureClassEnv extends ContextEnv {
/// Tag used for identifying serialized [ClosureClassEnv] objects in a
/// debugging data stream.
static const String tag = 'closure-class-env';
ClosureClassEnv(super.memberMap);
factory ClosureClassEnv.readFromDataSource(DataSourceReader source) {
source.begin(tag);
Map<Name, MemberEntity> memberMap = source.readNameMap(
() => source.readMember(),
);
source.end(tag);
return ClosureClassEnv(memberMap);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassEnvKind.closure);
sink.begin(tag);
sink.writeNameMap(_memberMap, (member) => sink.writeMember(member));
sink.end(tag);
}
}
class RecordClassEnv implements JClassEnv {
/// Tag used for identifying serialized [ContextEnv] objects in a debugging
/// data stream.
static const String tag = 'record-env';
final Map<Name, MemberEntity> _memberMap;
RecordClassEnv(this._memberMap);
factory RecordClassEnv.readFromDataSource(DataSourceReader source) {
source.begin(tag);
Map<Name, MemberEntity> memberMap = source.readNameMap(
() => source.readMember(),
);
source.end(tag);
return RecordClassEnv(memberMap);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassEnvKind.record);
sink.begin(tag);
sink.writeNameMap(_memberMap, (member) => sink.writeMember(member));
sink.end(tag);
}
@override
void forEachConstructorBody(
void Function(ConstructorBodyEntity constructor) f,
) {
// We do not create constructor bodies for containers.
}
@override
void forEachConstructor(
IrToElementMap elementMap,
void Function(ConstructorEntity constructor) f,
) {
// We do not create constructors for containers.
}
@override
ConstructorEntity? lookupConstructor(IrToElementMap elementMap, String name) {
// We do not create constructors for containers.
return null;
}
@override
void forEachMember(
IrToElementMap elementMap,
void Function(MemberEntity member) f,
) {
_memberMap.values.forEach(f);
}
@override
MemberEntity? lookupMember(IrToElementMap elementMap, Name name) {
return _memberMap[name];
}
@override
bool get isUnnamedMixinApplication => false;
@override
bool get isMixinApplicationWithMembers => false;
@override
ir.Class? get cls => null;
}
/// Enum used for identifying [JClassData] subclasses in serialization.
enum JClassDataKind { node, closure, context, record }
abstract class JClassData {
/// Deserializes a [JClassData] object from [source].
factory JClassData.readFromDataSource(DataSourceReader source) {
JClassDataKind kind = source.readEnum(JClassDataKind.values);
switch (kind) {
case JClassDataKind.node:
return JClassDataImpl.readFromDataSource(source);
case JClassDataKind.closure:
return ClosureClassData.readFromDataSource(source);
case JClassDataKind.context:
return ContextClassData.readFromDataSource(source);
case JClassDataKind.record:
return RecordClassData.readFromDataSource(source);
}
}
/// Serializes this [JClassData] to [sink].
void writeToDataSink(DataSinkWriter sink);
ClassDefinition get definition;
InterfaceType? get thisType;
InterfaceType? get jsInteropType;
InterfaceType? get rawType;
InterfaceType? get instantiationToBounds;
InterfaceType? get supertype;
InterfaceType? get mixedInType;
List<InterfaceType> get interfaces;
OrderedTypeSet? get orderedTypeSet;
FunctionType? get callType;
bool get isEnumClass;
bool? get isMixinApplication;
List<Variance> getVariances();
}
class JClassDataImpl implements JClassData {
/// Tag used for identifying serialized [JClassDataImpl] objects in a
/// debugging data stream.
static const String tag = 'class-data';
final ir.Class cls;
@override
final ClassDefinition definition;
@override
bool? isMixinApplication;
@override
InterfaceType? thisType;
@override
InterfaceType? jsInteropType;
@override
InterfaceType? rawType;
@override
InterfaceType? instantiationToBounds;
@override
InterfaceType? supertype;
@override
InterfaceType? mixedInType;
@override
late List<InterfaceType> interfaces;
@override
OrderedTypeSet? orderedTypeSet;
List<Variance>? _variances;
JClassDataImpl(this.cls, this.definition);
factory JClassDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Class cls = source.readClassNode();
ClassDefinition definition = ClassDefinition.readFromDataSource(source);
source.end(tag);
return JClassDataImpl(cls, definition);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JClassDataKind.node);
sink.begin(tag);
sink.writeClassNode(cls);
definition.writeToDataSink(sink);
sink.end(tag);
}
@override
bool get isEnumClass => cls.isEnum;
@override
FunctionType? callType;
bool isCallTypeComputed = false;
@override
List<Variance> getVariances() =>
_variances ??= cls.typeParameters.map(convertVariance).toList();
}
/// Enum used for identifying [JMemberData] subclasses in serialization.
enum JMemberDataKind {
function,
field,
constructor,
constructorBody,
signature,
generatorBody,
closureFunction,
closureField,
recordGetter,
}
abstract class JMemberData {
MemberDefinition get definition;
InterfaceType? getMemberThisType(JsToElementMap elementMap);
ClassTypeVariableAccess get classTypeVariableAccess;
JMemberData();
/// Deserializes a [JMemberData] object from [source].
factory JMemberData.readFromDataSource(DataSourceReader source) {
JMemberDataKind kind = source.readEnum(JMemberDataKind.values);
switch (kind) {
case JMemberDataKind.function:
return FunctionDataImpl.readFromDataSource(source);
case JMemberDataKind.field:
return JFieldDataImpl.readFromDataSource(source);
case JMemberDataKind.constructor:
return JConstructorData.readFromDataSource(source);
case JMemberDataKind.constructorBody:
return ConstructorBodyDataImpl.readFromDataSource(source);
case JMemberDataKind.signature:
return SignatureFunctionData.readFromDataSource(source);
case JMemberDataKind.generatorBody:
return GeneratorBodyFunctionData.readFromDataSource(source);
case JMemberDataKind.closureFunction:
return ClosureFunctionData.readFromDataSource(source);
case JMemberDataKind.closureField:
return ClosureFieldData.readFromDataSource(source);
case JMemberDataKind.recordGetter:
return RecordGetterData.readFromDataSource(source);
}
}
/// Serializes this [JMemberData] to [sink].
void writeToDataSink(DataSinkWriter sink);
}
abstract class JMemberDataImpl implements JMemberData {
final ir.Member node;
@override
final MemberDefinition definition;
JMemberDataImpl(this.node, this.definition);
JMemberDataImpl._deserialized(this.node, this.definition);
@override
InterfaceType? getMemberThisType(JsToElementMap elementMap) {
MemberEntity member = elementMap.getMember(node);
ClassEntity? cls = member.enclosingClass;
if (cls != null) {
return elementMap.elementEnvironment.getThisType(cls);
}
return null;
}
}
abstract class FunctionData implements JMemberData {
FunctionType getFunctionType(IrToElementMap elementMap);
List<TypeVariableType> getFunctionTypeVariables(IrToElementMap elementMap);
void forEachParameter(
JsToElementMap elementMap,
ParameterStructure parameterStructure,
void Function(DartType type, String? name, ConstantValue? defaultValue) f, {
bool isNative = false,
});
}
mixin FunctionDataTypeVariablesMixin implements FunctionData {
ir.FunctionNode get functionNode;
List<TypeVariableType>? _typeVariables;
@override
List<TypeVariableType> getFunctionTypeVariables(
covariant JsKernelToElementMap elementMap,
) {
if (_typeVariables == null) {
if (functionNode.typeParameters.isEmpty) {
_typeVariables = const <TypeVariableType>[];
} else {
ir.TreeNode parent = functionNode.parent!;
if (parent is ir.Constructor ||
(parent is ir.Procedure &&
parent.kind == ir.ProcedureKind.Factory)) {
_typeVariables = const <TypeVariableType>[];
} else {
_typeVariables = functionNode.typeParameters.map<TypeVariableType>((
ir.TypeParameter typeParameter,
) {
return elementMap
.getDartType(
ir.TypeParameterType(
typeParameter,
ir.Nullability.nonNullable,
),
)
.withoutNullability
as TypeVariableType;
}).toList();
}
}
}
return _typeVariables!;
}
}
mixin FunctionDataForEachParameterMixin implements FunctionData {
ir.FunctionNode get functionNode;
@override
void forEachParameter(
JsToElementMap elementMap,
ParameterStructure parameterStructure,
void Function(DartType type, String? name, ConstantValue? defaultValue) f, {
bool isNative = false,
}) {
void handleParameter(
ir.VariableDeclaration parameter, {
bool isOptional = true,
}) {
DartType type = elementMap.getDartType(parameter.type);
String? name = parameter.name;
ConstantValue? defaultValue;
if (parameter.isRequired) {
defaultValue = elementMap.getRequiredSentinelConstantValue();
} else if (isOptional) {
if (parameter.initializer != null) {
defaultValue = elementMap.getConstantValue(parameter.initializer!);
} else {
defaultValue = NullConstantValue();
}
}
f(type, name, defaultValue);
}
forEachOrderedParameterByFunctionNode(functionNode, parameterStructure, (
ir.VariableDeclaration parameter, {
required bool isOptional,
required bool isElided,
}) {
if (!isElided) {
handleParameter(parameter, isOptional: isOptional);
}
}, useNativeOrdering: isNative);
}
}
class FunctionDataImpl extends JMemberDataImpl
with FunctionDataTypeVariablesMixin, FunctionDataForEachParameterMixin
implements FunctionData {
/// Tag used for identifying serialized [FunctionDataImpl] objects in a
/// debugging data stream.
static const String tag = 'function-data';
@override
final ir.FunctionNode functionNode;
FunctionType? _type;
FunctionDataImpl(
ir.Member node,
this.functionNode,
MemberDefinition definition,
) : super(node, definition);
FunctionDataImpl._deserialized(
ir.Member node,
this.functionNode,
MemberDefinition definition,
) : super._deserialized(node, definition);
factory FunctionDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).",
);
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
source.end(tag);
return FunctionDataImpl._deserialized(node, functionNode, definition);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.function);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
@override
FunctionType getFunctionType(covariant JsKernelToElementMap elementMap) {
return _type ??= elementMap.getFunctionType(functionNode);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess {
if (node.isInstanceMember) return ClassTypeVariableAccess.property;
return ClassTypeVariableAccess.none;
}
}
class SignatureFunctionData implements FunctionData {
/// Tag used for identifying serialized [SignatureFunctionData] objects in a
/// debugging data stream.
static const String tag = 'signature-function-data';
@override
final MemberDefinition definition;
final InterfaceType? memberThisType;
@override
final ClassTypeVariableAccess classTypeVariableAccess;
List<ir.TypeParameter> get typeParameters => _typeParameters.loaded();
final Deferrable<List<ir.TypeParameter>> _typeParameters;
SignatureFunctionData(
this.definition,
this.memberThisType,
List<ir.TypeParameter> typeParameters,
this.classTypeVariableAccess,
) : _typeParameters = Deferrable.eager(typeParameters);
SignatureFunctionData._deserialized(
this.definition,
this.memberThisType,
this._typeParameters,
this.classTypeVariableAccess,
);
static List<ir.TypeParameter> _readTypeParameterNodes(
DataSourceReader source,
) {
return source.readTypeParameterNodes();
}
factory SignatureFunctionData.readFromDataSource(DataSourceReader source) {
source.begin(tag);
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
InterfaceType? memberThisType =
source.readDartTypeOrNull() as InterfaceType?;
Deferrable<List<ir.TypeParameter>> typeParameters = source.readDeferrable(
_readTypeParameterNodes,
);
ClassTypeVariableAccess classTypeVariableAccess = source.readEnum(
ClassTypeVariableAccess.values,
);
source.end(tag);
return SignatureFunctionData._deserialized(
definition,
memberThisType,
typeParameters,
classTypeVariableAccess,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.signature);
sink.begin(tag);
definition.writeToDataSink(sink);
sink.writeDartTypeOrNull(memberThisType);
sink.writeDeferrable(() => sink.writeTypeParameterNodes(typeParameters));
sink.writeEnum(classTypeVariableAccess);
sink.end(tag);
}
@override
FunctionType getFunctionType(covariant JsKernelToElementMap elementMap) {
throw UnsupportedError("SignatureFunctionData.getFunctionType");
}
@override
List<TypeVariableType> getFunctionTypeVariables(IrToElementMap elementMap) {
return typeParameters.map<TypeVariableType>((
ir.TypeParameter typeParameter,
) {
return elementMap
.getDartType(
ir.TypeParameterType(typeParameter, ir.Nullability.nonNullable),
)
.withoutNullability
as TypeVariableType;
}).toList();
}
@override
void forEachParameter(
JsToElementMap elementMap,
ParameterStructure parameterStructure,
void Function(DartType type, String? name, ConstantValue? defaultValue) f, {
bool isNative = false,
}) {
throw UnimplementedError('SignatureData.forEachParameter');
}
@override
InterfaceType? getMemberThisType(JsToElementMap elementMap) => memberThisType;
}
abstract class DelegatedFunctionData implements FunctionData {
final FunctionData baseData;
DelegatedFunctionData(this.baseData);
@override
FunctionType getFunctionType(covariant JsKernelToElementMap elementMap) {
return baseData.getFunctionType(elementMap);
}
@override
List<TypeVariableType> getFunctionTypeVariables(IrToElementMap elementMap) {
return baseData.getFunctionTypeVariables(elementMap);
}
@override
void forEachParameter(
JsToElementMap elementMap,
ParameterStructure parameterStructure,
void Function(DartType type, String? name, ConstantValue? defaultValue) f, {
bool isNative = false,
}) {
return baseData.forEachParameter(
elementMap,
parameterStructure,
f,
isNative: isNative,
);
}
@override
InterfaceType? getMemberThisType(JsToElementMap elementMap) {
return baseData.getMemberThisType(elementMap);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess =>
baseData.classTypeVariableAccess;
}
class ParameterStubFunctionData extends DelegatedFunctionData {
@override
final MemberDefinition definition;
ParameterStubFunctionData(super.baseData, this.definition);
@override
void writeToDataSink(DataSinkWriter sink) {
throw UnimplementedError('Cannot serialize parameter stub data.');
}
}
class GeneratorBodyFunctionData extends DelegatedFunctionData {
/// Tag used for identifying serialized [GeneratorBodyFunctionData] objects in
/// a debugging data stream.
static const String tag = 'generator-body-data';
@override
final MemberDefinition definition;
GeneratorBodyFunctionData(super.baseData, this.definition);
factory GeneratorBodyFunctionData.readFromDataSource(
DataSourceReader source,
) {
source.begin(tag);
// TODO(johnniwinther): Share the original base data on deserialization.
FunctionData baseData =
JMemberData.readFromDataSource(source) as FunctionData;
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
source.end(tag);
return GeneratorBodyFunctionData(baseData, definition);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.generatorBody);
sink.begin(tag);
baseData.writeToDataSink(sink);
definition.writeToDataSink(sink);
sink.end(tag);
}
}
class JConstructorData extends FunctionDataImpl {
/// Tag used for identifying serialized [JConstructorDataImpl] objects in a
/// debugging data stream.
static const String tag = 'constructor-data';
JConstructorBody? constructorBody;
JConstructorData(super.node, super.functionNode, super.definition);
JConstructorData._deserialized(
super.node,
super.functionNode,
super.definition,
) : super._deserialized();
factory JConstructorData.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).",
);
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
source.end(tag);
return JConstructorData._deserialized(node, functionNode, definition);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.constructor);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
assert(constructorBody == null);
sink.end(tag);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess =>
ClassTypeVariableAccess.parameter;
}
class ConstructorBodyDataImpl extends FunctionDataImpl {
/// Tag used for identifying serialized [ConstructorBodyDataImpl] objects in
/// a debugging data stream.
static const String tag = 'constructor-body-data';
ConstructorBodyDataImpl(super.node, super.functionNode, super.definition);
ConstructorBodyDataImpl._deserialized(
super.node,
super.functionNode,
super.definition,
) : super._deserialized();
factory ConstructorBodyDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
ir.FunctionNode functionNode;
if (node is ir.Procedure) {
functionNode = node.function;
} else if (node is ir.Constructor) {
functionNode = node.function;
} else {
throw UnsupportedError(
"Unexpected member node $node (${node.runtimeType}).",
);
}
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
source.end(tag);
return ConstructorBodyDataImpl._deserialized(
node,
functionNode,
definition,
);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.constructorBody);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
// TODO(johnniwinther,sra): Constructor bodies should access type variables
// through `this`.
@override
ClassTypeVariableAccess get classTypeVariableAccess =>
ClassTypeVariableAccess.parameter;
}
abstract class JFieldData extends JMemberData {
DartType getFieldType(IrToElementMap elementMap);
bool get isCovariantByDeclaration;
}
class JFieldDataImpl extends JMemberDataImpl implements JFieldData {
/// Tag used for identifying serialized [JFieldDataImpl] objects in
/// a debugging data stream.
static const String tag = 'field-data';
DartType? _type;
JFieldDataImpl(super.node, super.definition);
JFieldDataImpl._deserialized(super.node, super.definition)
: super._deserialized();
factory JFieldDataImpl.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.Member node = source.readMemberNode();
MemberDefinition definition = MemberDefinition.readFromDataSource(source);
source.end(tag);
return JFieldDataImpl._deserialized(node as ir.Field, definition);
}
@override
void writeToDataSink(DataSinkWriter sink) {
sink.writeEnum(JMemberDataKind.field);
sink.begin(tag);
sink.writeMemberNode(node);
definition.writeToDataSink(sink);
sink.end(tag);
}
@override
ir.Field get node => super.node as ir.Field;
@override
DartType getFieldType(covariant JsKernelToElementMap elementMap) {
return _type ??= elementMap.getDartType(node.type);
}
@override
bool get isCovariantByDeclaration {
return node.isCovariantByDeclaration;
}
@override
ClassTypeVariableAccess get classTypeVariableAccess {
if (node.isInstanceMember) return ClassTypeVariableAccess.instanceField;
return ClassTypeVariableAccess.none;
}
}
class JTypeVariableData {
/// Tag used for identifying serialized [JTypeVariableData] objects in
/// a debugging data stream.
static const String tag = 'type-variable-data';
final ir.TypeParameter node;
DartType? _bound;
DartType? _defaultType;
JTypeVariableData(this.node);
factory JTypeVariableData.readFromDataSource(DataSourceReader source) {
source.begin(tag);
ir.TypeParameter node = source.readTypeParameterNode();
source.end(tag);
return JTypeVariableData(node);
}
void writeToDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeTypeParameterNode(node);
sink.end(tag);
}
DartType getBound(IrToElementMap elementMap) {
return _bound ??= elementMap.getDartType(node.bound);
}
DartType getDefaultType(IrToElementMap elementMap) {
return _defaultType ??= elementMap.getDartType(node.defaultType);
}
}