| // 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 dart2js.js_model.env; |
| |
| import 'package:kernel/ast.dart' as ir; |
| |
| import '../constants/values.dart'; |
| import '../elements/entities.dart'; |
| import '../elements/indexed.dart'; |
| import '../elements/types.dart'; |
| import '../ir/element_map.dart'; |
| import '../ir/static_type_cache.dart'; |
| import '../ir/util.dart'; |
| import '../ordered_typeset.dart'; |
| import '../serialization/serialization.dart'; |
| import '../ssa/type_builder.dart'; |
| import 'closure.dart'; |
| import 'element_map.dart'; |
| import 'element_map_impl.dart'; |
| import 'elements.dart'; |
| |
| /// 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 f(JLibraryEnv library)) { |
| _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(DataSource 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(DataSink 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 f(JClassEnv cls)) { |
| _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 f(ir.Member member)) { |
| _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(DataSource 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; |
| } |
| } |
| source.end(tag); |
| return JLibraryData(library, imports); |
| } |
| |
| void writeToDataSink(DataSink sink) { |
| sink.begin(tag); |
| sink.writeLibraryNode(library); |
| if (imports == null) { |
| sink.writeInt(0); |
| } else { |
| 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, record } |
| |
| /// Member data for a class. |
| abstract class JClassEnv { |
| /// Deserializes a [JClassEnv] object from [source]. |
| factory JClassEnv.readFromDataSource(DataSource 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.record: |
| return RecordEnv.readFromDataSource(source); |
| } |
| throw UnsupportedError("Unsupported JClassEnvKind $kind"); |
| } |
| |
| /// Serializes this [JClassEnv] to [sink]. |
| void writeToDataSink(DataSink 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, String name, |
| {bool setter = false}); |
| |
| /// Calls [f] for each member of [cls]. |
| void forEachMember(IrToElementMap elementMap, void f(MemberEntity member)); |
| |
| /// 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 f(ConstructorEntity constructor)); |
| |
| /// Calls [f] for each constructor body for the live constructors in the |
| /// class. |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)); |
| } |
| |
| /// 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<String, ir.Member> _memberMap; |
| final Map<String, ir.Member> _setterMap; |
| 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._setterMap, this._members, this.isMixinApplicationWithMembers); |
| |
| factory JClassEnvImpl.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| ir.Class cls = source.readClassNode(); |
| Map<String, ir.Member> constructorMap = |
| source.readStringMap(source.readMemberNode); |
| Map<String, ir.Member> memberMap = |
| source.readStringMap(source.readMemberNode); |
| Map<String, ir.Member> setterMap = |
| source.readStringMap(source.readMemberNode); |
| List<ir.Member> members = source.readMemberNodes(); |
| bool isSuperMixinApplication = source.readBool(); |
| source.end(tag); |
| return JClassEnvImpl(cls, constructorMap, memberMap, setterMap, members, |
| isSuperMixinApplication); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JClassEnvKind.node); |
| sink.begin(tag); |
| sink.writeClassNode(cls); |
| sink.writeStringMap(_constructorMap, sink.writeMemberNode); |
| sink.writeStringMap(_memberMap, sink.writeMemberNode); |
| sink.writeStringMap(_setterMap, sink.writeMemberNode); |
| sink.writeMemberNodes(_members); |
| sink.writeBool(isMixinApplicationWithMembers); |
| sink.end(tag); |
| } |
| |
| @override |
| bool get isUnnamedMixinApplication => cls.isAnonymousMixin; |
| |
| @override |
| MemberEntity lookupMember(IrToElementMap elementMap, String name, |
| {bool setter = false}) { |
| ir.Member member = setter ? _setterMap[name] : _memberMap[name]; |
| return member != null ? elementMap.getMember(member) : null; |
| } |
| |
| @override |
| void forEachMember(IrToElementMap elementMap, void f(MemberEntity member)) { |
| _members.forEach((ir.Member member) { |
| 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 f(ConstructorEntity constructor)) { |
| _constructorMap.values.forEach((ir.Member constructor) { |
| f(elementMap.getConstructor(constructor)); |
| }); |
| } |
| |
| void addConstructorBody(ConstructorBodyEntity constructorBody) { |
| _constructorBodyList ??= <ConstructorBodyEntity>[]; |
| _constructorBodyList.add(constructorBody); |
| } |
| |
| @override |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) { |
| _constructorBodyList?.forEach(f); |
| } |
| } |
| |
| class RecordEnv implements JClassEnv { |
| /// Tag used for identifying serialized [RecordEnv] objects in a |
| /// debugging data stream. |
| static const String tag = 'record-env'; |
| |
| final Map<String, IndexedMember> _memberMap; |
| |
| RecordEnv(this._memberMap); |
| |
| factory RecordEnv.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| Map<String, IndexedMember> _memberMap = |
| source.readStringMap(() => source.readMember()); |
| source.end(tag); |
| return RecordEnv(_memberMap); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JClassEnvKind.record); |
| sink.begin(tag); |
| sink.writeStringMap( |
| _memberMap, (IndexedMember member) => sink.writeMember(member)); |
| sink.end(tag); |
| } |
| |
| @override |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) { |
| // We do not create constructor bodies for containers. |
| } |
| |
| @override |
| void forEachConstructor( |
| IrToElementMap elementMap, void f(ConstructorEntity constructor)) { |
| // 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 f(MemberEntity member)) { |
| _memberMap.values.forEach(f); |
| } |
| |
| @override |
| MemberEntity lookupMember(IrToElementMap elementMap, String name, |
| {bool setter = false}) { |
| return _memberMap[name]; |
| } |
| |
| @override |
| bool get isUnnamedMixinApplication => false; |
| |
| @override |
| bool get isMixinApplicationWithMembers => false; |
| |
| @override |
| ir.Class get cls => null; |
| } |
| |
| class ClosureClassEnv extends RecordEnv { |
| /// Tag used for identifying serialized [ClosureClassEnv] objects in a |
| /// debugging data stream. |
| static const String tag = 'closure-class-env'; |
| |
| ClosureClassEnv(Map<String, MemberEntity> memberMap) : super(memberMap); |
| |
| factory ClosureClassEnv.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| Map<String, IndexedMember> _memberMap = |
| source.readStringMap(() => source.readMember()); |
| source.end(tag); |
| return ClosureClassEnv(_memberMap); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JClassEnvKind.closure); |
| sink.begin(tag); |
| sink.writeStringMap( |
| _memberMap, (IndexedMember member) => sink.writeMember(member)); |
| sink.end(tag); |
| } |
| |
| @override |
| MemberEntity lookupMember(IrToElementMap elementMap, String name, |
| {bool setter = false}) { |
| if (setter) { |
| // All closure fields are final. |
| return null; |
| } |
| return super.lookupMember(elementMap, name, setter: setter); |
| } |
| } |
| |
| /// Enum used for identifying [JClassData] subclasses in serialization. |
| enum JClassDataKind { node, closure, record } |
| |
| abstract class JClassData { |
| /// Deserializes a [JClassData] object from [source]. |
| factory JClassData.readFromDataSource(DataSource 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.record: |
| return RecordClassData.readFromDataSource(source); |
| } |
| throw UnsupportedError("Unexpected JClassDataKind $kind"); |
| } |
| |
| /// Serializes this [JClassData] to [sink]. |
| void writeToDataSink(DataSink 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 |
| List<InterfaceType> interfaces; |
| @override |
| OrderedTypeSet orderedTypeSet; |
| |
| List<Variance> _variances; |
| |
| JClassDataImpl(this.cls, this.definition); |
| |
| factory JClassDataImpl.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| ir.Class cls = source.readClassNode(); |
| ClassDefinition definition = ClassDefinition.readFromDataSource(source); |
| source.end(tag); |
| return JClassDataImpl(cls, definition); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JClassDataKind.node); |
| sink.begin(tag); |
| sink.writeClassNode(cls); |
| definition.writeToDataSink(sink); |
| sink.end(tag); |
| } |
| |
| @override |
| bool get isEnumClass => cls != null && 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, |
| } |
| |
| abstract class JMemberData { |
| MemberDefinition get definition; |
| |
| InterfaceType getMemberThisType(JsToElementMap elementMap); |
| |
| ClassTypeVariableAccess get classTypeVariableAccess; |
| |
| StaticTypeCache get staticTypes; |
| |
| JMemberData(); |
| |
| /// Deserializes a [JMemberData] object from [source]. |
| factory JMemberData.readFromDataSource(DataSource 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 JConstructorDataImpl.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); |
| } |
| throw UnsupportedError("Unexpected JMemberDataKind $kind"); |
| } |
| |
| /// Serializes this [JMemberData] to [sink]. |
| void writeToDataSink(DataSink sink); |
| } |
| |
| abstract class JMemberDataImpl implements JMemberData { |
| final ir.Member node; |
| |
| @override |
| final MemberDefinition definition; |
| |
| @override |
| final StaticTypeCache staticTypes; |
| |
| JMemberDataImpl(this.node, this.definition, this.staticTypes); |
| |
| @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 f(DartType type, String name, ConstantValue defaultValue), |
| {bool isNative = false}); |
| } |
| |
| abstract class 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; |
| }).toList(); |
| } |
| } |
| } |
| return _typeVariables; |
| } |
| } |
| |
| abstract class FunctionDataForEachParameterMixin implements FunctionData { |
| ir.FunctionNode get functionNode; |
| |
| // TODO(johnniwinther,sigmund): Remove this when it's no longer needed for |
| // `getConstantValue` in [forEachParameter]. |
| ir.Member get memberContext; |
| |
| @override |
| void forEachParameter( |
| JsToElementMap elementMap, |
| ParameterStructure parameterStructure, |
| void f(DartType type, String name, ConstantValue defaultValue), |
| {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) { |
| if (elementMap.types.useLegacySubtyping) { |
| defaultValue = NullConstantValue(); |
| } else { |
| defaultValue = elementMap.getRequiredSentinelConstantValue(); |
| } |
| } else if (isOptional) { |
| if (parameter.initializer != null) { |
| defaultValue = |
| elementMap.getConstantValue(memberContext, parameter.initializer); |
| } else { |
| defaultValue = NullConstantValue(); |
| } |
| } |
| f(type, name, defaultValue); |
| } |
| |
| forEachOrderedParameterByFunctionNode(functionNode, parameterStructure, |
| (ir.VariableDeclaration parameter, {bool isOptional, 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, StaticTypeCache staticTypes) |
| : super(node, definition, staticTypes); |
| |
| factory FunctionDataImpl.readFromDataSource(DataSource 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); |
| StaticTypeCache staticTypes = |
| StaticTypeCache.readFromDataSource(source, node); |
| source.end(tag); |
| return FunctionDataImpl(node, functionNode, definition, staticTypes); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.function); |
| sink.begin(tag); |
| sink.writeMemberNode(node); |
| definition.writeToDataSink(sink); |
| staticTypes.writeToDataSink(sink, node); |
| sink.end(tag); |
| } |
| |
| @override |
| ir.Member get memberContext => node; |
| |
| @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; |
| final List<ir.TypeParameter> typeParameters; |
| |
| SignatureFunctionData(this.definition, this.memberThisType, |
| this.typeParameters, this.classTypeVariableAccess); |
| |
| factory SignatureFunctionData.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| MemberDefinition definition = MemberDefinition.readFromDataSource(source); |
| InterfaceType memberThisType = source.readDartType(allowNull: true); |
| List<ir.TypeParameter> typeParameters = source.readTypeParameterNodes(); |
| ClassTypeVariableAccess classTypeVariableAccess = |
| source.readEnum(ClassTypeVariableAccess.values); |
| source.end(tag); |
| return SignatureFunctionData( |
| definition, memberThisType, typeParameters, classTypeVariableAccess); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.signature); |
| sink.begin(tag); |
| definition.writeToDataSink(sink); |
| sink.writeDartType(memberThisType, allowNull: true); |
| sink.writeTypeParameterNodes(typeParameters); |
| sink.writeEnum(classTypeVariableAccess); |
| sink.end(tag); |
| } |
| |
| @override |
| StaticTypeCache get staticTypes => const StaticTypeCache(); |
| |
| @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; |
| }).toList(); |
| } |
| |
| @override |
| void forEachParameter( |
| JsToElementMap elementMap, |
| ParameterStructure parameterStructure, |
| void f(DartType type, String name, ConstantValue defaultValue), |
| {bool isNative = false}) { |
| throw UnimplementedError('SignatureData.forEachParameter'); |
| } |
| |
| @override |
| InterfaceType getMemberThisType(JsToElementMap elementMap) { |
| return 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 f(DartType type, String name, ConstantValue defaultValue), |
| {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 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(FunctionData baseData, this.definition) |
| : super(baseData); |
| |
| factory GeneratorBodyFunctionData.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| // TODO(johnniwinther): Share the original base data on deserialization. |
| FunctionData baseData = JMemberData.readFromDataSource(source); |
| MemberDefinition definition = MemberDefinition.readFromDataSource(source); |
| source.end(tag); |
| return GeneratorBodyFunctionData(baseData, definition); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.generatorBody); |
| sink.begin(tag); |
| baseData.writeToDataSink(sink); |
| definition.writeToDataSink(sink); |
| sink.end(tag); |
| } |
| |
| @override |
| StaticTypeCache get staticTypes => const StaticTypeCache(); |
| } |
| |
| abstract class JConstructorData extends FunctionData {} |
| |
| class JConstructorDataImpl extends FunctionDataImpl |
| implements JConstructorData { |
| /// Tag used for identifying serialized [JConstructorDataImpl] objects in a |
| /// debugging data stream. |
| static const String tag = 'constructor-data'; |
| |
| JConstructorBody constructorBody; |
| |
| JConstructorDataImpl(ir.Member node, ir.FunctionNode functionNode, |
| MemberDefinition definition, StaticTypeCache staticTypes) |
| : super(node, functionNode, definition, staticTypes); |
| |
| factory JConstructorDataImpl.readFromDataSource(DataSource 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); |
| StaticTypeCache staticTypes = |
| StaticTypeCache.readFromDataSource(source, node); |
| source.end(tag); |
| return JConstructorDataImpl(node, functionNode, definition, staticTypes); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.constructor); |
| sink.begin(tag); |
| sink.writeMemberNode(node); |
| definition.writeToDataSink(sink); |
| assert(constructorBody == null); |
| staticTypes.writeToDataSink(sink, node); |
| 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(ir.Member node, ir.FunctionNode functionNode, |
| MemberDefinition definition, StaticTypeCache staticTypes) |
| : super(node, functionNode, definition, staticTypes); |
| |
| factory ConstructorBodyDataImpl.readFromDataSource(DataSource 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); |
| StaticTypeCache staticTypes = |
| StaticTypeCache.readFromDataSource(source, node); |
| source.end(tag); |
| return ConstructorBodyDataImpl(node, functionNode, definition, staticTypes); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.constructorBody); |
| sink.begin(tag); |
| sink.writeMemberNode(node); |
| definition.writeToDataSink(sink); |
| staticTypes.writeToDataSink(sink, node); |
| 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); |
| } |
| |
| 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( |
| ir.Field node, MemberDefinition definition, StaticTypeCache staticTypes) |
| : super(node, definition, staticTypes); |
| |
| factory JFieldDataImpl.readFromDataSource(DataSource source) { |
| source.begin(tag); |
| ir.Member node = source.readMemberNode(); |
| MemberDefinition definition = MemberDefinition.readFromDataSource(source); |
| StaticTypeCache staticTypes = |
| StaticTypeCache.readFromDataSource(source, node); |
| source.end(tag); |
| return JFieldDataImpl(node, definition, staticTypes); |
| } |
| |
| @override |
| void writeToDataSink(DataSink sink) { |
| sink.writeEnum(JMemberDataKind.field); |
| sink.begin(tag); |
| sink.writeMemberNode(node); |
| definition.writeToDataSink(sink); |
| staticTypes.writeToDataSink(sink, node); |
| sink.end(tag); |
| } |
| |
| @override |
| ir.Field get node => super.node; |
| |
| @override |
| DartType getFieldType(covariant JsKernelToElementMap elementMap) { |
| return _type ??= elementMap.getDartType(node.type); |
| } |
| |
| @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(DataSource source) { |
| source.begin(tag); |
| ir.TypeParameter node = source.readTypeParameterNode(); |
| source.end(tag); |
| return JTypeVariableData(node); |
| } |
| |
| void writeToDataSink(DataSink 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); |
| } |
| } |