| // 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); |
| } |
| } |