| // 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.kernel.env; |
| |
| import 'package:front_end/src/fasta/kernel/redirecting_factory_body.dart' as ir; |
| import 'package:kernel/ast.dart' as ir; |
| import 'package:kernel/clone.dart'; |
| import 'package:kernel/type_algebra.dart'; |
| import 'package:collection/algorithms.dart' show mergeSort; // a stable sort. |
| |
| import '../common.dart'; |
| import '../constants/constructors.dart'; |
| import '../constants/expressions.dart'; |
| import '../constants/values.dart'; |
| import '../elements/entities.dart'; |
| import '../elements/types.dart'; |
| import '../ordered_typeset.dart'; |
| import '../ssa/type_builder.dart'; |
| import 'element_map.dart'; |
| import 'element_map_impl.dart'; |
| import 'element_map_mixins.dart'; |
| import 'kelements.dart' show KImport; |
| |
| /// Environment for fast lookup of program libraries. |
| class ProgramEnv { |
| final Set<ir.Program> _programs = new Set<ir.Program>(); |
| |
| Map<Uri, LibraryEnv> _libraryMap; |
| |
| /// TODO(johnniwinther): Handle arbitrary load order if needed. |
| ir.Member get mainMethod => _programs.first?.mainMethod; |
| |
| void addProgram(ir.Program program) { |
| if (_programs.add(program)) { |
| if (_libraryMap != null) { |
| _addLibraries(program); |
| } |
| } |
| } |
| |
| void _addLibraries(ir.Program program) { |
| for (ir.Library library in program.libraries) { |
| _libraryMap[library.importUri] = new LibraryEnv(library); |
| } |
| } |
| |
| void _ensureLibraryMap() { |
| if (_libraryMap == null) { |
| _libraryMap = <Uri, LibraryEnv>{}; |
| for (ir.Program program in _programs) { |
| _addLibraries(program); |
| } |
| } |
| } |
| |
| /// Return the [LibraryEnv] for the library with the canonical [uri]. |
| LibraryEnv lookupLibrary(Uri uri) { |
| _ensureLibraryMap(); |
| return _libraryMap[uri]; |
| } |
| |
| /// Calls [f] for each library in this environment. |
| void forEachLibrary(void f(LibraryEnv library)) { |
| _ensureLibraryMap(); |
| _libraryMap.values.forEach(f); |
| } |
| |
| /// Returns the number of libraries in this environment. |
| int get length { |
| _ensureLibraryMap(); |
| return _libraryMap.length; |
| } |
| } |
| |
| /// Environment for fast lookup of library classes and members. |
| class LibraryEnv { |
| final ir.Library library; |
| |
| Map<String, ClassEnv> _classMap; |
| Map<String, ir.Member> _memberMap; |
| Map<String, ir.Member> _setterMap; |
| |
| LibraryEnv(this.library); |
| |
| void _ensureClassMap() { |
| if (_classMap == null) { |
| _classMap = <String, ClassEnv>{}; |
| for (ir.Class cls in library.classes) { |
| _classMap[cls.name] = new ClassEnvImpl(cls); |
| } |
| } |
| } |
| |
| /// Return the [ClassEnv] for the class [name] in [library]. |
| ClassEnv lookupClass(String name) { |
| _ensureClassMap(); |
| return _classMap[name]; |
| } |
| |
| /// Calls [f] for each class in this library. |
| void forEachClass(void f(ClassEnv cls)) { |
| _ensureClassMap(); |
| _classMap.values.forEach(f); |
| } |
| |
| void _ensureMemberMaps() { |
| if (_memberMap == null) { |
| _memberMap = <String, ir.Member>{}; |
| _setterMap = <String, ir.Member>{}; |
| for (ir.Member member in library.members) { |
| if (member.name.name.contains('#')) { |
| // Skip synthetic .dill members. |
| continue; |
| } |
| if (member is ir.Procedure) { |
| if (member.kind == ir.ProcedureKind.Setter) { |
| _setterMap[member.name.name] = member; |
| } else { |
| _memberMap[member.name.name] = member; |
| } |
| } else if (member is ir.Field) { |
| _memberMap[member.name.name] = member; |
| if (member.isMutable) { |
| _setterMap[member.name.name] = member; |
| } |
| } else { |
| failedAt( |
| NO_LOCATION_SPANNABLE, "Unexpected library member node: $member"); |
| } |
| } |
| } |
| } |
| |
| /// Return the [ir.Member] for the member [name] in [library]. |
| ir.Member lookupMember(String name, {bool setter: false}) { |
| _ensureMemberMaps(); |
| return setter ? _setterMap[name] : _memberMap[name]; |
| } |
| |
| void forEachMember(void f(ir.Member member)) { |
| _ensureMemberMaps(); |
| _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 LibraryData { |
| final ir.Library library; |
| Iterable<ConstantValue> _metadata; |
| Map<ir.LibraryDependency, ImportEntity> imports; |
| |
| LibraryData(this.library, [this.imports]); |
| |
| Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) { |
| return _metadata ??= elementMap.getMetadata(library.annotations); |
| } |
| |
| Iterable<ImportEntity> getImports(KernelToElementMapBase elementMap) { |
| if (imports == null) { |
| List<ir.LibraryDependency> dependencies = library.dependencies; |
| if (dependencies.isEmpty) { |
| imports = const <ir.LibraryDependency, ImportEntity>{}; |
| } else { |
| imports = <ir.LibraryDependency, ImportEntity>{}; |
| dependencies.forEach((ir.LibraryDependency node) { |
| if (node.isExport) return; |
| imports[node] = new KImport( |
| node.isDeferred, |
| node.name, |
| node.targetLibrary.importUri, |
| elementMap.getLibrary(node.enclosingLibrary)); |
| }); |
| } |
| } |
| return imports.values; |
| } |
| |
| LibraryData copy() { |
| return new LibraryData(library, imports); |
| } |
| } |
| |
| /// Member data for a class. |
| abstract class ClassEnv { |
| /// The [ir.Class] that defined the class, if any. |
| ir.Class get cls; |
| |
| /// Whether the class is an unnamed mixin application. |
| bool get isUnnamedMixinApplication; |
| |
| /// 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(KernelToElementMap elementMap, String name, |
| {bool setter: false}); |
| |
| /// Calls [f] for each member of the class. |
| void forEachMember( |
| KernelToElementMap elementMap, void f(MemberEntity member)); |
| |
| /// Return the [ConstructorEntity] for the constructor [name] in the class. |
| ConstructorEntity lookupConstructor( |
| KernelToElementMap elementMap, String name); |
| |
| /// Calls [f] for each constructor of the class. |
| void forEachConstructor( |
| KernelToElementMap elementMap, void f(ConstructorEntity constructor)); |
| |
| /// Calls [f] for each constructor body for the live constructors in the |
| /// class. |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)); |
| } |
| |
| int orderByFileOffset(ir.TreeNode a, ir.TreeNode b) { |
| var aLoc = a.location; |
| var bLoc = b.location; |
| var aUri = '${aLoc.file}'; |
| var bUri = '${bLoc.file}'; |
| var uriCompare = aUri.compareTo(bUri); |
| if (uriCompare != 0) return uriCompare; |
| return a.fileOffset.compareTo(b.fileOffset); |
| } |
| |
| /// Environment for fast lookup of class members. |
| class ClassEnvImpl implements ClassEnv { |
| final ir.Class cls; |
| |
| Map<String, ir.Member> _constructorMap; |
| Map<String, ir.Member> _memberMap; |
| Map<String, ir.Member> _setterMap; |
| List<ir.Member> _members; // in declaration order. |
| |
| /// Constructor bodies created for this class. |
| List<ConstructorBodyEntity> _constructorBodyList; |
| |
| ClassEnvImpl(this.cls); |
| |
| bool get isUnnamedMixinApplication => cls.isSyntheticMixinImplementation; |
| |
| /// Copied from 'package:kernel/transformations/mixin_full_resolution.dart'. |
| ir.Constructor _buildForwardingConstructor( |
| CloneVisitor cloner, ir.Constructor superclassConstructor) { |
| var superFunction = superclassConstructor.function; |
| |
| // We keep types and default values for the parameters but always mark the |
| // parameters as final (since we just forward them to the super |
| // constructor). |
| ir.VariableDeclaration cloneVariable(ir.VariableDeclaration variable) { |
| ir.VariableDeclaration clone = cloner.clone(variable); |
| clone.isFinal = true; |
| return clone; |
| } |
| |
| // Build a [FunctionNode] which has the same parameters as the one in the |
| // superclass constructor. |
| var positionalParameters = |
| superFunction.positionalParameters.map(cloneVariable).toList(); |
| var namedParameters = |
| superFunction.namedParameters.map(cloneVariable).toList(); |
| var function = new ir.FunctionNode(new ir.EmptyStatement(), |
| positionalParameters: positionalParameters, |
| namedParameters: namedParameters, |
| requiredParameterCount: superFunction.requiredParameterCount, |
| returnType: const ir.VoidType()); |
| |
| // Build a [SuperInitializer] which takes all positional/named parameters |
| // and forward them to the super class constructor. |
| var positionalArguments = <ir.Expression>[]; |
| for (var variable in positionalParameters) { |
| positionalArguments.add(new ir.VariableGet(variable)); |
| } |
| var namedArguments = <ir.NamedExpression>[]; |
| for (var variable in namedParameters) { |
| namedArguments.add( |
| new ir.NamedExpression(variable.name, new ir.VariableGet(variable))); |
| } |
| var superInitializer = new ir.SuperInitializer(superclassConstructor, |
| new ir.Arguments(positionalArguments, named: namedArguments)); |
| |
| // Assemble the constructor. |
| return new ir.Constructor(function, |
| name: superclassConstructor.name, |
| initializers: <ir.Initializer>[superInitializer]); |
| } |
| |
| void _ensureMaps(KernelToElementMapBase elementMap) { |
| if (_memberMap != null) return; |
| |
| _memberMap = <String, ir.Member>{}; |
| _setterMap = <String, ir.Member>{}; |
| _constructorMap = <String, ir.Member>{}; |
| var members = <ir.Member>[]; |
| |
| void addFields(ir.Class c, {bool includeStatic}) { |
| for (ir.Field member in c.fields) { |
| if (!includeStatic && member.isStatic) continue; |
| var name = member.name.name; |
| if (name.contains('#')) { |
| // Skip synthetic .dill members. |
| continue; |
| } |
| _memberMap[name] = member; |
| if (member.isMutable) { |
| _setterMap[name] = member; |
| } |
| members.add(member); |
| } |
| } |
| |
| void addProcedures(ir.Class c, {bool includeStatic}) { |
| for (ir.Procedure member in c.procedures) { |
| if (!includeStatic && member.isStatic) continue; |
| var name = member.name.name; |
| assert(!name.contains('#')); |
| if (member.kind == ir.ProcedureKind.Factory) { |
| if (member.function.body is ir.RedirectingFactoryBody) { |
| // Don't include redirecting factories. |
| continue; |
| } |
| _constructorMap[name] = member; |
| } else if (member.kind == ir.ProcedureKind.Setter) { |
| _setterMap[name] = member; |
| members.add(member); |
| } else { |
| assert(member.kind == ir.ProcedureKind.Method || |
| member.kind == ir.ProcedureKind.Getter || |
| member.kind == ir.ProcedureKind.Operator); |
| _memberMap[name] = member; |
| members.add(member); |
| } |
| } |
| } |
| |
| void addConstructors(ir.Class c) { |
| for (ir.Constructor member in c.constructors) { |
| var name = member.name.name; |
| assert(!name.contains('#')); |
| _constructorMap[name] = member; |
| } |
| } |
| |
| int mixinMemberCount = 0; |
| if (cls.mixedInClass != null) { |
| addFields(cls.mixedInClass.mixin, includeStatic: false); |
| addProcedures(cls.mixedInClass.mixin, includeStatic: false); |
| mergeSort(members, compare: orderByFileOffset); |
| mixinMemberCount = members.length; |
| } |
| addFields(cls, includeStatic: true); |
| addConstructors(cls); |
| addProcedures(cls, includeStatic: true); |
| |
| if (isUnnamedMixinApplication && _constructorMap.isEmpty) { |
| // Ensure that constructors are created for the superclass in case it |
| // is also an unnamed mixin application. |
| ClassEntity superclass = elementMap.getClass(cls.superclass); |
| elementMap.elementEnvironment.lookupConstructor(superclass, ''); |
| |
| // Unnamed mixin applications have no constructors when read from .dill. |
| // For each generative constructor in the superclass we make a |
| // corresponding forwarding constructor in the subclass. |
| // |
| // This code is copied from |
| // 'package:kernel/transformations/mixin_full_resolution.dart' |
| var superclassSubstitution = getSubstitutionMap(cls.supertype); |
| var superclassCloner = |
| new CloneVisitor(typeSubstitution: superclassSubstitution); |
| |
| for (var superclassConstructor in cls.superclass.constructors) { |
| var forwardingConstructor = _buildForwardingConstructor( |
| superclassCloner, superclassConstructor); |
| cls.addMember(forwardingConstructor); |
| _constructorMap[forwardingConstructor.name.name] = |
| forwardingConstructor; |
| } |
| } |
| |
| mergeSort(members, start: mixinMemberCount, compare: orderByFileOffset); |
| _members = members; |
| } |
| |
| /// Return the [MemberEntity] for the member [name] in [cls]. If [setter] is |
| /// `true`, the setter or assignable field corresponding to [name] is |
| /// returned. |
| MemberEntity lookupMember(KernelToElementMap elementMap, String name, |
| {bool setter: false}) { |
| _ensureMaps(elementMap); |
| ir.Member member = setter ? _setterMap[name] : _memberMap[name]; |
| return member != null ? elementMap.getMember(member) : null; |
| } |
| |
| /// Calls [f] for each member of [cls]. |
| void forEachMember( |
| KernelToElementMap elementMap, void f(MemberEntity member)) { |
| _ensureMaps(elementMap); |
| _members.forEach((ir.Member member) { |
| f(elementMap.getMember(member)); |
| }); |
| } |
| |
| /// Return the [ConstructorEntity] for the constructor [name] in [cls]. |
| ConstructorEntity lookupConstructor( |
| KernelToElementMap elementMap, String name) { |
| _ensureMaps(elementMap); |
| ir.Member constructor = _constructorMap[name]; |
| return constructor != null ? elementMap.getConstructor(constructor) : null; |
| } |
| |
| /// Calls [f] for each constructor of [cls]. |
| void forEachConstructor( |
| KernelToElementMap elementMap, void f(ConstructorEntity constructor)) { |
| _ensureMaps(elementMap); |
| _constructorMap.values.forEach((ir.Member constructor) { |
| f(elementMap.getConstructor(constructor)); |
| }); |
| } |
| |
| void addConstructorBody(ConstructorBodyEntity constructorBody) { |
| _constructorBodyList ??= <ConstructorBodyEntity>[]; |
| _constructorBodyList.add(constructorBody); |
| } |
| |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) { |
| _constructorBodyList?.forEach(f); |
| } |
| } |
| |
| class ClosureClassEnv extends RecordEnv { |
| ClosureClassEnv(Map<String, MemberEntity> memberMap) : super(memberMap); |
| |
| @override |
| MemberEntity lookupMember(KernelToElementMap elementMap, String name, |
| {bool setter: false}) { |
| if (setter) { |
| // All closure fields are final. |
| return null; |
| } |
| return super.lookupMember(elementMap, name, setter: setter); |
| } |
| } |
| |
| class RecordEnv implements ClassEnv { |
| final Map<String, MemberEntity> _memberMap; |
| |
| RecordEnv(this._memberMap); |
| |
| @override |
| void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) { |
| // We do not create constructor bodies for containers. |
| } |
| |
| @override |
| void forEachConstructor( |
| KernelToElementMap elementMap, void f(ConstructorEntity constructor)) { |
| // We do not create constructors for containers. |
| } |
| |
| @override |
| ConstructorEntity lookupConstructor( |
| KernelToElementMap elementMap, String name) { |
| // We do not create constructors for containers. |
| return null; |
| } |
| |
| @override |
| void forEachMember( |
| KernelToElementMap elementMap, void f(MemberEntity member)) { |
| _memberMap.values.forEach(f); |
| } |
| |
| @override |
| MemberEntity lookupMember(KernelToElementMap elementMap, String name, |
| {bool setter: false}) { |
| return _memberMap[name]; |
| } |
| |
| @override |
| bool get isUnnamedMixinApplication => false; |
| |
| @override |
| ir.Class get cls => null; |
| } |
| |
| class ClassData { |
| /// TODO(johnniwinther): Remove this from the [ClassData] interface. Use |
| /// `definition.node` instead. |
| final ir.Class cls; |
| final ClassDefinition definition; |
| bool isMixinApplication; |
| bool isCallTypeComputed = false; |
| |
| InterfaceType thisType; |
| InterfaceType rawType; |
| InterfaceType supertype; |
| InterfaceType mixedInType; |
| List<InterfaceType> interfaces; |
| OrderedTypeSet orderedTypeSet; |
| DartType callType; |
| |
| Iterable<ConstantValue> _metadata; |
| |
| ClassData(this.cls, this.definition); |
| |
| bool get isEnumClass => cls != null && cls.isEnum; |
| |
| Iterable<ConstantValue> getMetadata(KernelToElementMapBase elementMap) { |
| return _metadata ??= elementMap.getMetadata(cls.annotations); |
| } |
| |
| ClassData copy() { |
| return new ClassData(cls, definition); |
| } |
| } |
| |
| abstract class MemberData { |
| MemberDefinition get definition; |
| |
| Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap); |
| |
| InterfaceType getMemberThisType(KernelToElementMapForBuilding elementMap); |
| |
| ClassTypeVariableAccess get classTypeVariableAccess; |
| } |
| |
| abstract class MemberDataImpl implements MemberData { |
| /// TODO(johnniwinther): Remove this from the [MemberData] interface. Use |
| /// `definition.node` instead. |
| final ir.Member node; |
| |
| final MemberDefinition definition; |
| |
| Iterable<ConstantValue> _metadata; |
| |
| MemberDataImpl(this.node, this.definition); |
| |
| Iterable<ConstantValue> getMetadata( |
| covariant KernelToElementMapBase elementMap) { |
| return _metadata ??= elementMap.getMetadata(node.annotations); |
| } |
| |
| InterfaceType getMemberThisType(KernelToElementMapForBuilding elementMap) { |
| MemberEntity member = elementMap.getMember(node); |
| ClassEntity cls = member.enclosingClass; |
| if (cls != null) { |
| return elementMap.elementEnvironment.getThisType(cls); |
| } |
| return null; |
| } |
| |
| MemberData copy(); |
| } |
| |
| abstract class FunctionData implements MemberData { |
| FunctionType getFunctionType(KernelToElementMap elementMap); |
| |
| List<TypeVariableType> getFunctionTypeVariables( |
| KernelToElementMap elementMap); |
| |
| void forEachParameter(KernelToElementMapForBuilding elementMap, |
| void f(DartType type, String name, ConstantValue defaultValue)); |
| } |
| |
| abstract class FunctionDataMixin implements FunctionData { |
| ir.FunctionNode get functionNode; |
| List<TypeVariableType> _typeVariables; |
| |
| List<TypeVariableType> getFunctionTypeVariables( |
| covariant KernelToElementMapBase elementMap) { |
| if (_typeVariables == null) { |
| if (functionNode.typeParameters.isEmpty || |
| !elementMap.options.strongMode) { |
| _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(new ir.TypeParameterType(typeParameter)); |
| }).toList(); |
| } |
| } |
| } |
| return _typeVariables; |
| } |
| } |
| |
| class FunctionDataImpl extends MemberDataImpl |
| with FunctionDataMixin |
| implements FunctionData { |
| final ir.FunctionNode functionNode; |
| FunctionType _type; |
| |
| FunctionDataImpl( |
| ir.Member node, this.functionNode, MemberDefinition definition) |
| : super(node, definition); |
| |
| FunctionType getFunctionType(covariant KernelToElementMapBase elementMap) { |
| return _type ??= elementMap.getFunctionType(functionNode); |
| } |
| |
| void forEachParameter(KernelToElementMapForBuilding elementMap, |
| void f(DartType type, String name, ConstantValue defaultValue)) { |
| void handleParameter(ir.VariableDeclaration node, {bool isOptional: true}) { |
| DartType type = elementMap.getDartType(node.type); |
| String name = node.name; |
| ConstantValue defaultValue; |
| if (isOptional) { |
| if (node.initializer != null) { |
| defaultValue = elementMap.getConstantValue(node.initializer); |
| } else { |
| defaultValue = new NullConstantValue(); |
| } |
| } |
| f(type, name, defaultValue); |
| } |
| |
| for (int i = 0; i < functionNode.positionalParameters.length; i++) { |
| handleParameter(functionNode.positionalParameters[i], |
| isOptional: i >= functionNode.requiredParameterCount); |
| } |
| functionNode.namedParameters.toList() |
| ..sort(namedOrdering) |
| ..forEach(handleParameter); |
| } |
| |
| @override |
| FunctionData copy() { |
| return new FunctionDataImpl(node, functionNode, definition); |
| } |
| |
| @override |
| ClassTypeVariableAccess get classTypeVariableAccess { |
| if (node.isInstanceMember) return ClassTypeVariableAccess.property; |
| return ClassTypeVariableAccess.none; |
| } |
| } |
| |
| class SignatureFunctionData implements FunctionData { |
| final FunctionType functionType; |
| final MemberDefinition definition; |
| final InterfaceType memberThisType; |
| final ClassTypeVariableAccess classTypeVariableAccess; |
| final List<ir.TypeParameter> typeParameters; |
| |
| SignatureFunctionData(this.definition, this.memberThisType, this.functionType, |
| this.typeParameters, this.classTypeVariableAccess); |
| |
| FunctionType getFunctionType(covariant KernelToElementMapBase elementMap) { |
| return functionType; |
| } |
| |
| List<TypeVariableType> getFunctionTypeVariables( |
| KernelToElementMap elementMap) { |
| return typeParameters |
| .map<TypeVariableType>((ir.TypeParameter typeParameter) { |
| return elementMap.getDartType(new ir.TypeParameterType(typeParameter)); |
| }).toList(); |
| } |
| |
| void forEachParameter(KernelToElementMapForBuilding elementMap, |
| void f(DartType type, String name, ConstantValue defaultValue)) { |
| throw new UnimplementedError('SignatureData.forEachParameter'); |
| } |
| |
| @override |
| Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) { |
| return const <ConstantValue>[]; |
| } |
| |
| InterfaceType getMemberThisType(KernelToElementMapForBuilding elementMap) { |
| return memberThisType; |
| } |
| } |
| |
| abstract class ConstructorData extends FunctionData { |
| ConstantConstructor getConstructorConstant( |
| KernelToElementMapBase elementMap, ConstructorEntity constructor); |
| } |
| |
| class ConstructorDataImpl extends FunctionDataImpl implements ConstructorData { |
| ConstantConstructor _constantConstructor; |
| ConstructorBodyEntity constructorBody; |
| |
| ConstructorDataImpl( |
| ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition) |
| : super(node, functionNode, definition); |
| |
| ConstantConstructor getConstructorConstant( |
| KernelToElementMapBase elementMap, ConstructorEntity constructor) { |
| if (_constantConstructor == null) { |
| if (node is ir.Constructor && constructor.isConst) { |
| _constantConstructor = |
| new Constantifier(elementMap).computeConstantConstructor(node); |
| } else { |
| failedAt( |
| constructor, |
| "Unexpected constructor $constructor in " |
| "ConstructorDataImpl._getConstructorConstant"); |
| } |
| } |
| return _constantConstructor; |
| } |
| |
| @override |
| ConstructorData copy() { |
| return new ConstructorDataImpl(node, functionNode, definition); |
| } |
| |
| @override |
| ClassTypeVariableAccess get classTypeVariableAccess => |
| ClassTypeVariableAccess.parameter; |
| } |
| |
| class ConstructorBodyDataImpl extends FunctionDataImpl { |
| ConstructorBodyDataImpl( |
| ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition) |
| : super(node, functionNode, definition); |
| |
| // TODO(johnniwinther,sra): Constructor bodies should access type variables |
| // through `this`. |
| @override |
| ClassTypeVariableAccess get classTypeVariableAccess => |
| ClassTypeVariableAccess.parameter; |
| } |
| |
| abstract class FieldData extends MemberData { |
| DartType getFieldType(KernelToElementMap elementMap); |
| |
| ConstantExpression getFieldConstantExpression( |
| KernelToElementMapBase elementMap); |
| |
| /// Return the [ConstantValue] the initial value of [field] or `null` if |
| /// the initializer is not a constant expression. |
| ConstantValue getFieldConstantValue(KernelToElementMapBase elementMap); |
| |
| bool hasConstantFieldInitializer(KernelToElementMapBase elementMap); |
| |
| ConstantValue getConstantFieldInitializer(KernelToElementMapBase elementMap); |
| } |
| |
| class FieldDataImpl extends MemberDataImpl implements FieldData { |
| DartType _type; |
| bool _isConstantComputed = false; |
| ConstantValue _constantValue; |
| ConstantExpression _constantExpression; |
| |
| FieldDataImpl(ir.Field node, MemberDefinition definition) |
| : super(node, definition); |
| |
| ir.Field get node => super.node; |
| |
| DartType getFieldType(covariant KernelToElementMapBase elementMap) { |
| return _type ??= elementMap.getDartType(node.type); |
| } |
| |
| ConstantExpression getFieldConstantExpression( |
| KernelToElementMapBase elementMap) { |
| if (_constantExpression == null) { |
| if (node.isConst) { |
| _constantExpression = |
| new Constantifier(elementMap).visit(node.initializer); |
| } else { |
| failedAt( |
| definition.member, |
| "Unexpected field ${definition.member} in " |
| "FieldDataImpl.getFieldConstant"); |
| } |
| } |
| return _constantExpression; |
| } |
| |
| @override |
| ConstantValue getFieldConstantValue(KernelToElementMapBase elementMap) { |
| if (!_isConstantComputed) { |
| _constantValue = elementMap.getConstantValue(node.initializer, |
| requireConstant: node.isConst, implicitNull: !node.isConst); |
| _isConstantComputed = true; |
| } |
| return _constantValue; |
| } |
| |
| @override |
| bool hasConstantFieldInitializer(KernelToElementMapBase elementMap) { |
| return getFieldConstantValue(elementMap) != null; |
| } |
| |
| @override |
| ConstantValue getConstantFieldInitializer(KernelToElementMapBase elementMap) { |
| ConstantValue value = getFieldConstantValue(elementMap); |
| assert( |
| value != null, |
| failedAt( |
| definition.member, |
| "Field ${definition.member} doesn't have a " |
| "constant initial value.")); |
| return value; |
| } |
| |
| @override |
| ClassTypeVariableAccess get classTypeVariableAccess { |
| if (node.isInstanceMember) return ClassTypeVariableAccess.instanceField; |
| return ClassTypeVariableAccess.none; |
| } |
| |
| @override |
| FieldData copy() { |
| return new FieldDataImpl(node, definition); |
| } |
| } |
| |
| class TypedefData { |
| final ir.Typedef node; |
| final TypedefEntity element; |
| final TypedefType rawType; |
| |
| TypedefData(this.node, this.element, this.rawType); |
| } |
| |
| class TypeVariableData { |
| final ir.TypeParameter node; |
| DartType _bound; |
| |
| TypeVariableData(this.node); |
| |
| DartType getBound(KernelToElementMap elementMap) { |
| return _bound ??= elementMap.getDartType(node.bound); |
| } |
| |
| TypeVariableData copy() { |
| return new TypeVariableData(node); |
| } |
| } |