blob: 4393f84bbc745c8fde581b766decb6066c6a126a [file] [log] [blame]
// 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/api_unstable/dart2js.dart'
show isRedirectingFactory, isRedirectingFactoryField;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/clone.dart';
import 'package:kernel/type_algebra.dart';
import 'package:kernel/type_environment.dart' as ir;
import 'package:collection/collection.dart' show mergeSort; // a stable sort.
import '../common.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../ir/element_map.dart';
import '../ir/static_type_cache.dart';
import '../ir/util.dart';
import '../js_model/element_map.dart';
import '../js_model/env.dart';
import '../ordered_typeset.dart';
import '../ssa/type_builder.dart';
import '../universe/member_usage.dart';
import 'element_map.dart';
import 'element_map_impl.dart';
/// Environment for fast lookup of component libraries.
class KProgramEnv {
final Set<ir.Component> _components = new Set<ir.Component>();
Map<Uri, KLibraryEnv> _libraryMap;
/// TODO(johnniwinther): Handle arbitrary load order if needed.
ir.Member get mainMethod => _components.first?.mainMethod;
ir.Component get mainComponent => _components.first;
void addComponent(ir.Component component) {
if (_components.add(component)) {
if (_libraryMap != null) {
_addLibraries(component);
}
}
}
void _addLibraries(ir.Component component) {
for (ir.Library library in component.libraries) {
_libraryMap[library.importUri] = new KLibraryEnv(library);
}
}
void _ensureLibraryMap() {
if (_libraryMap == null) {
_libraryMap = <Uri, KLibraryEnv>{};
for (ir.Component component in _components) {
_addLibraries(component);
}
}
}
/// Return the [KLibraryEnv] for the library with the canonical [uri].
KLibraryEnv lookupLibrary(Uri uri) {
_ensureLibraryMap();
return _libraryMap[uri];
}
/// Calls [f] for each library in this environment.
void forEachLibrary(void f(KLibraryEnv library)) {
_ensureLibraryMap();
_libraryMap.values.forEach(f);
}
/// Returns the number of libraries in this environment.
int get length {
_ensureLibraryMap();
return _libraryMap.length;
}
/// Convert this [KProgramEnv] to the corresponding [JProgramEnv].
JProgramEnv convert() => new JProgramEnv(_components);
}
/// Environment for fast lookup of library classes and members.
class KLibraryEnv {
final ir.Library library;
Map<String, KClassEnv> _classMap;
Map<String, ir.Member> _memberMap;
Map<String, ir.Member> _setterMap;
KLibraryEnv(this.library);
void _ensureClassMap() {
if (_classMap == null) {
_classMap = <String, KClassEnv>{};
for (ir.Class cls in library.classes) {
_classMap[cls.name] = new KClassEnvImpl(cls);
}
}
}
/// Return the [KClassEnv] for the class [name] in [library].
KClassEnv lookupClass(String name) {
_ensureClassMap();
return _classMap[name];
}
/// Calls [f] for each class in this library.
void forEachClass(void f(KClassEnv 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 (isRedirectingFactoryField(member)) {
continue;
}
if (member is ir.Procedure) {
if (member.kind == ir.ProcedureKind.Setter) {
_setterMap[member.name.text] = member;
} else {
_memberMap[member.name.text] = member;
}
} else if (member is ir.Field) {
_memberMap[member.name.text] = member;
if (member.hasSetter) {
_setterMap[member.name.text] = 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.
}
}
}
/// Convert this [KLibraryEnv] to a corresponding [JLibraryEnv] containing
/// only the members in [liveMembers].
JLibraryEnv convert(IrToElementMap elementMap,
Map<MemberEntity, MemberUsage> liveMemberUsage) {
Map<String, ir.Member> memberMap;
Map<String, ir.Member> setterMap;
if (_memberMap == null) {
memberMap = const <String, ir.Member>{};
} else {
memberMap = <String, ir.Member>{};
_memberMap.forEach((String name, ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
memberMap[name] = node;
}
});
}
if (_setterMap == null) {
setterMap = const <String, ir.Member>{};
} else {
setterMap = <String, ir.Member>{};
_setterMap.forEach((String name, ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
setterMap[name] = node;
}
});
}
return new JLibraryEnv(library, memberMap, setterMap);
}
}
class KLibraryData {
final ir.Library library;
Iterable<ConstantValue> _metadata;
// TODO(johnniwinther): Avoid direct access to [imports].
Map<ir.LibraryDependency, ImportEntity> imports;
KLibraryData(this.library);
Iterable<ConstantValue> getMetadata(KernelToElementMapImpl elementMap) {
return _metadata ??= elementMap.getMetadata(
new ir.StaticTypeContext.forAnnotations(
library, elementMap.typeEnvironment),
library.annotations);
}
Iterable<ImportEntity> getImports(KernelToElementMapImpl 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 ImportEntity(
node.isDeferred,
node.name,
node.targetLibrary.importUri,
elementMap.getLibrary(node.enclosingLibrary).canonicalUri);
});
}
}
return imports.values;
}
/// Convert this [KLibraryData] to the corresponding [JLibraryData].
// TODO(johnniwinther): Why isn't [imports] ensured to be non-null here?
JLibraryData convert() {
return new JLibraryData(library, imports);
}
}
/// Member data for a class.
abstract class KClassEnv {
/// 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;
/// Ensures that all members have been computed for [cls].
void ensureMembers(KernelToElementMapImpl elementMap);
/// 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));
/// Convert this [KClassEnv] to the corresponding [JClassEnv] containing only
/// the members in [liveMembers].
JClassEnv convert(IrToElementMap elementMap,
Map<MemberEntity, MemberUsage> liveMemberUsage);
/// Returns `true` if [node] is a known member of this class.
///
/// This method is used for checking the integrity of the K-model and does
/// not alter the state of this class environment.
bool checkHasMember(ir.Member node);
}
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 KClassEnvImpl implements KClassEnv {
@override
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.
bool _isMixinApplicationWithMembers;
/// Constructor bodies created for this class.
List<ConstructorBodyEntity> _constructorBodyList;
KClassEnvImpl(this.cls);
KClassEnvImpl.internal(this.cls, this._constructorMap, this._memberMap,
this._setterMap, this._members, this._isMixinApplicationWithMembers);
@override
bool get isUnnamedMixinApplication => cls.isAnonymousMixin;
@override
bool get isMixinApplicationWithMembers {
assert(_isMixinApplicationWithMembers != null);
return _isMixinApplicationWithMembers;
}
@override
bool checkHasMember(ir.Member node) {
if (_memberMap == null) return false;
return _memberMap.values.contains(node) ||
_setterMap.values.contains(node) ||
_constructorMap.values.contains(node);
}
@override
void ensureMembers(KernelToElementMapImpl elementMap) {
_ensureMaps(elementMap);
}
void _ensureMaps(KernelToElementMapImpl elementMap) {
if (_memberMap != null) return;
_memberMap = <String, ir.Member>{};
_setterMap = <String, ir.Member>{};
_constructorMap = <String, ir.Member>{};
var members = <ir.Member>[];
_isMixinApplicationWithMembers = false;
void addField(ir.Field member, {bool includeStatic}) {
if (!includeStatic && member.isStatic) return;
if (isRedirectingFactoryField(member)) return;
var name = member.name.text;
_memberMap[name] = member;
if (member.hasSetter) {
_setterMap[name] = member;
}
members.add(member);
}
void addProcedure(ir.Procedure member,
{bool includeStatic,
bool includeNoSuchMethodForwarders,
bool isFromMixinApplication: false}) {
if (memberIsIgnorable(member, cls: cls)) return;
if (!includeStatic && member.isStatic) return;
if (member.isNoSuchMethodForwarder) {
// TODO(sigmund): remove once #33732 is fixed.
if (!includeNoSuchMethodForwarders ||
member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference) {
return;
}
}
var name = member.name.text;
if (member.kind == ir.ProcedureKind.Factory) {
if (isRedirectingFactory(member)) {
// Don't include redirecting factories.
return;
}
_constructorMap[name] = member;
} else if (member.kind == ir.ProcedureKind.Setter) {
_setterMap[name] = member;
members.add(member);
if (isFromMixinApplication) {
_isMixinApplicationWithMembers = true;
}
} else {
assert(member.kind == ir.ProcedureKind.Method ||
member.kind == ir.ProcedureKind.Getter ||
member.kind == ir.ProcedureKind.Operator);
_memberMap[name] = member;
members.add(member);
if (isFromMixinApplication) {
_isMixinApplicationWithMembers = true;
}
}
}
void addConstructors(ir.Class c) {
for (ir.Constructor member in c.constructors) {
var name = member.name.text;
_constructorMap[name] = member;
}
}
int mixinMemberCount = 0;
if (cls.mixedInClass != null) {
Map<ir.Name, ir.Procedure> existingNonSetters;
Map<ir.Name, ir.Procedure> existingSetters;
void ensureExistingProcedureMaps() {
if (existingNonSetters == null) {
existingNonSetters = {};
existingSetters = {};
for (ir.Procedure procedure in cls.procedures) {
if (procedure.kind == ir.ProcedureKind.Setter) {
existingSetters[procedure.name] = procedure;
} else {
existingNonSetters[procedure.name] = procedure;
}
}
}
}
CloneVisitorWithMembers cloneVisitor;
for (ir.Field field in cls.mixedInClass.mixin.fields) {
if (field.containsSuperCalls) {
_isMixinApplicationWithMembers = true;
cloneVisitor ??= new MixinApplicationCloner(cls,
typeSubstitution: getSubstitutionMap(cls.mixedInType));
// TODO(jensj): Provide a "referenceFrom" if we need to support
// the incremental compiler.
ensureExistingProcedureMaps();
ir.Procedure existingGetter = existingNonSetters[field.name];
ir.Procedure existingSetter = existingSetters[field.name];
cls.addField(cloneVisitor.cloneField(
field, existingGetter?.reference, existingSetter?.reference));
// TODO(johnniwinther): We need to unbind the canonical names before
// serializing these references since the canonical names refer to
// @getters and @setters instead of @fields and @fields=. This will
// not be needed if stop using @fields/@fields= in favor of
// @getters/@setters in general.
if (existingGetter != null) {
cls.procedures.remove(existingGetter);
}
if (existingSetter != null) {
cls.procedures.remove(existingSetter);
}
continue;
}
addField(field, includeStatic: false);
}
for (ir.Procedure procedure in cls.mixedInClass.mixin.procedures) {
if (procedure.containsSuperCalls) {
_isMixinApplicationWithMembers = true;
cloneVisitor ??= new MixinApplicationCloner(cls,
typeSubstitution: getSubstitutionMap(cls.mixedInType));
// TODO(jensj): Provide a "referenceFrom" if we need to support
// the incremental compiler.
ensureExistingProcedureMaps();
ir.Procedure existingProcedure =
procedure.kind == ir.ProcedureKind.Setter
? existingSetters[procedure.name]
: existingNonSetters[procedure.name];
if (existingProcedure != null) {
cls.procedures.remove(existingProcedure);
}
cls.addProcedure(cloneVisitor.cloneProcedure(
procedure, existingProcedure?.reference));
continue;
}
addProcedure(procedure,
includeStatic: false, includeNoSuchMethodForwarders: false);
}
mergeSort(members, compare: orderByFileOffset);
mixinMemberCount = members.length;
}
for (ir.Field member in cls.fields) {
addField(member, includeStatic: true);
}
addConstructors(cls);
for (ir.Procedure member in cls.procedures) {
addProcedure(member,
includeStatic: true,
includeNoSuchMethodForwarders: true,
isFromMixinApplication: cls.mixedInClass != null);
}
mergeSort(members, start: mixinMemberCount, compare: orderByFileOffset);
_members = members;
}
@override
MemberEntity lookupMember(IrToElementMap elementMap, String name,
{bool setter: false}) {
_ensureMaps(elementMap);
ir.Member member = setter ? _setterMap[name] : _memberMap[name];
return member != null ? elementMap.getMember(member) : null;
}
@override
void forEachMember(IrToElementMap elementMap, void f(MemberEntity member)) {
_ensureMaps(elementMap);
_members.forEach((ir.Member member) {
f(elementMap.getMember(member));
});
}
@override
ConstructorEntity lookupConstructor(IrToElementMap elementMap, String name) {
_ensureMaps(elementMap);
ir.Member constructor = _constructorMap[name];
return constructor != null ? elementMap.getConstructor(constructor) : null;
}
@override
void forEachConstructor(
IrToElementMap 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);
}
@override
void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) {
_constructorBodyList?.forEach(f);
}
@override
JClassEnv convert(IrToElementMap elementMap,
Map<MemberEntity, MemberUsage> liveMemberUsage) {
Map<String, ir.Member> constructorMap;
Map<String, ir.Member> memberMap;
Map<String, ir.Member> setterMap;
List<ir.Member> members;
if (_constructorMap == null) {
constructorMap = const <String, ir.Member>{};
} else {
constructorMap = <String, ir.Member>{};
_constructorMap.forEach((String name, ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
constructorMap[name] = node;
}
});
}
if (_memberMap == null) {
memberMap = const <String, ir.Member>{};
} else {
memberMap = <String, ir.Member>{};
_memberMap.forEach((String name, ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
memberMap[name] = node;
}
});
}
if (_setterMap == null) {
setterMap = const <String, ir.Member>{};
} else {
setterMap = <String, ir.Member>{};
_setterMap.forEach((String name, ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
setterMap[name] = node;
}
});
}
if (_members == null) {
members = const <ir.Member>[];
} else {
members = <ir.Member>[];
_members.forEach((ir.Member node) {
MemberEntity member = elementMap.getMember(node);
if (liveMemberUsage.containsKey(member)) {
members.add(node);
}
});
}
return new JClassEnvImpl(cls, constructorMap, memberMap, setterMap, members,
_isMixinApplicationWithMembers ?? false);
}
}
abstract class KClassData {
ir.Class get node;
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;
DartType get callType;
bool get isEnumClass;
bool get isMixinApplication;
Iterable<ConstantValue> getMetadata(IrToElementMap elementMap);
List<Variance> getVariances();
/// Convert this [KClassData] to the corresponding [JClassData].
JClassData convert();
}
class KClassDataImpl implements KClassData {
@override
final ir.Class node;
@override
bool isMixinApplication;
bool isCallTypeComputed = false;
@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;
Iterable<ConstantValue> _metadata;
List<Variance> _variances;
KClassDataImpl(this.node);
@override
bool get isEnumClass => node.isEnum;
@override
DartType get callType => null;
@override
Iterable<ConstantValue> getMetadata(
covariant KernelToElementMapImpl elementMap) {
return _metadata ??= elementMap.getMetadata(
new ir.StaticTypeContext.forAnnotations(
node.enclosingLibrary, elementMap.typeEnvironment),
node.annotations);
}
@override
List<Variance> getVariances() =>
_variances ??= node.typeParameters.map(convertVariance).toList();
@override
JClassData convert() {
return new JClassDataImpl(node, new RegularClassDefinition(node));
}
}
abstract class KMemberData {
ir.Member get node;
StaticTypeCache staticTypes;
Iterable<ConstantValue> getMetadata(IrToElementMap elementMap);
InterfaceType getMemberThisType(JsToElementMap elementMap);
ClassTypeVariableAccess get classTypeVariableAccess;
/// Convert this [KMemberData] to the corresponding [JMemberData].
JMemberData convert();
}
abstract class KMemberDataImpl implements KMemberData {
@override
final ir.Member node;
Iterable<ConstantValue> _metadata;
@override
StaticTypeCache staticTypes;
KMemberDataImpl(this.node);
@override
Iterable<ConstantValue> getMetadata(
covariant KernelToElementMapImpl elementMap) {
return _metadata ??= elementMap.getMetadata(
new ir.StaticTypeContext(node, elementMap.typeEnvironment),
node.annotations);
}
@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 KFunctionData implements KMemberData {
FunctionType getFunctionType(IrToElementMap elementMap);
List<TypeVariableType> getFunctionTypeVariables(IrToElementMap elementMap);
void forEachParameter(JsToElementMap elementMap,
void f(DartType type, String name, ConstantValue defaultValue));
}
abstract class KFunctionDataMixin implements KFunctionData {
ir.FunctionNode get functionNode;
List<TypeVariableType> _typeVariables;
@override
List<TypeVariableType> getFunctionTypeVariables(
covariant KernelToElementMapImpl 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(new ir.TypeParameterType(
typeParameter, ir.Nullability.nonNullable))
.withoutNullability;
}).toList();
}
}
}
return _typeVariables;
}
}
class KFunctionDataImpl extends KMemberDataImpl
with KFunctionDataMixin
implements KFunctionData {
@override
final ir.FunctionNode functionNode;
FunctionType _type;
KFunctionDataImpl(ir.Member node, this.functionNode) : super(node);
@override
FunctionType getFunctionType(covariant KernelToElementMapImpl elementMap) {
return _type ??= elementMap.getFunctionType(functionNode);
}
@override
void forEachParameter(JsToElementMap elementMap,
void f(DartType type, String name, ConstantValue defaultValue)) {
void handleParameter(ir.VariableDeclaration parameter,
{bool isOptional: true}) {
DartType type = elementMap.getDartType(parameter.type);
String name = parameter.name;
ConstantValue defaultValue;
if (isOptional) {
if (parameter.initializer != null) {
defaultValue =
elementMap.getConstantValue(node, parameter.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 convert() {
return new FunctionDataImpl(
node, functionNode, new RegularMemberDefinition(node), staticTypes);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess {
if (node.isInstanceMember) return ClassTypeVariableAccess.property;
return ClassTypeVariableAccess.none;
}
}
abstract class KConstructorData extends KFunctionData {}
class KConstructorDataImpl extends KFunctionDataImpl
implements KConstructorData {
ConstructorBodyEntity constructorBody;
KConstructorDataImpl(ir.Member node, ir.FunctionNode functionNode)
: super(node, functionNode);
@override
JConstructorData convert() {
MemberDefinition definition;
if (node is ir.Constructor) {
definition = new SpecialMemberDefinition(node, MemberKind.constructor);
} else {
definition = new RegularMemberDefinition(node);
}
return new JConstructorDataImpl(
node, functionNode, definition, staticTypes);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess =>
ClassTypeVariableAccess.parameter;
}
abstract class KFieldData extends KMemberData {
DartType getFieldType(IrToElementMap elementMap);
}
class KFieldDataImpl extends KMemberDataImpl implements KFieldData {
DartType _type;
KFieldDataImpl(ir.Field node) : super(node);
@override
ir.Field get node => super.node;
@override
DartType getFieldType(covariant KernelToElementMapImpl elementMap) {
return _type ??= elementMap.getDartType(node.type);
}
@override
ClassTypeVariableAccess get classTypeVariableAccess {
if (node.isInstanceMember) return ClassTypeVariableAccess.instanceField;
return ClassTypeVariableAccess.none;
}
@override
JFieldData convert() {
return new JFieldDataImpl(
node, new RegularMemberDefinition(node), staticTypes);
}
}
class KTypeVariableData {
final ir.TypeParameter node;
DartType _bound;
DartType _defaultType;
KTypeVariableData(this.node);
DartType getBound(IrToElementMap elementMap) {
return _bound ??= elementMap.getDartType(node.bound);
}
DartType getDefaultType(IrToElementMap elementMap) {
// TODO(34522): Remove `?? const ir.DynamicType()` when issue 34522 is
// fixed.
return _defaultType ??=
elementMap.getDartType(node.defaultType ?? const ir.DynamicType());
}
JTypeVariableData copy() {
return new JTypeVariableData(node);
}
}