blob: 5fd5bfb0f918538691794f9ba069959ae996f986 [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.element_map;
import 'package:front_end/src/fasta/util/link.dart' show Link, LinkBuilder;
import 'package:js_runtime/shared/embedded_names.dart';
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/type_algebra.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import '../common.dart';
import '../common/names.dart';
import '../common/resolution.dart';
import '../common_elements.dart';
import '../compile_time_constants.dart';
import '../constants/constant_system.dart';
import '../constants/constructors.dart';
import '../constants/evaluation.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/indexed.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../environment.dart';
import '../frontend_strategy.dart';
import '../ir/debug.dart';
import '../ir/element_map.dart';
import '../ir/types.dart';
import '../ir/visitors.dart';
import '../ir/util.dart';
import '../js/js.dart' as js;
import '../js_backend/annotations.dart';
import '../js_backend/allocator_analysis.dart' show KAllocatorAnalysis;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../js_backend/backend_usage.dart';
import '../js_backend/constant_system_javascript.dart';
import '../js_backend/interceptor_data.dart';
import '../js_backend/namer.dart';
import '../js_backend/native_data.dart';
import '../js_backend/no_such_method_registry.dart';
import '../js_backend/runtime_types.dart';
import '../js_model/closure.dart';
import '../js_model/elements.dart';
import '../js_model/locals.dart';
import '../native/native.dart' as native;
import '../native/resolver.dart';
import '../options.dart';
import '../ordered_typeset.dart';
import '../ssa/kernel_impact.dart';
import '../universe/call_structure.dart';
import '../universe/class_hierarchy.dart';
import '../universe/class_set.dart';
import '../universe/selector.dart';
import '../universe/world_builder.dart';
import '../world.dart';
import 'element_map.dart';
import 'env.dart';
import 'kelements.dart';
part 'native_basic_data.dart';
part 'no_such_method_resolver.dart';
abstract class KernelToElementMapBase implements IrToElementMap {
final CompilerOptions options;
final DiagnosticReporter reporter;
CommonElementsImpl _commonElements;
KernelElementEnvironment _elementEnvironment;
DartTypeConverter _typeConverter;
KernelConstantEnvironment _constantEnvironment;
KernelDartTypes _types;
ir.TypeEnvironment _typeEnvironment;
/// Library environment. Used for fast lookup.
ProgramEnv env = new ProgramEnv();
final EntityDataEnvMap<IndexedLibrary, LibraryData, LibraryEnv> libraries =
new EntityDataEnvMap<IndexedLibrary, LibraryData, LibraryEnv>();
final EntityDataEnvMap<IndexedClass, ClassData, ClassEnv> classes =
new EntityDataEnvMap<IndexedClass, ClassData, ClassEnv>();
final EntityDataMap<IndexedMember, MemberData> members =
new EntityDataMap<IndexedMember, MemberData>();
final EntityDataMap<IndexedTypeVariable, TypeVariableData> typeVariables =
new EntityDataMap<IndexedTypeVariable, TypeVariableData>();
final EntityDataMap<IndexedTypedef, TypedefData> typedefs =
new EntityDataMap<IndexedTypedef, TypedefData>();
KernelToElementMapBase(this.options, this.reporter, Environment environment) {
_elementEnvironment = new KernelElementEnvironment(this);
_commonElements = new CommonElementsImpl(_elementEnvironment);
_constantEnvironment = new KernelConstantEnvironment(this, environment);
_typeConverter = new DartTypeConverter(this);
_types = new KernelDartTypes(this);
}
bool checkFamily(Entity entity);
DartTypes get types => _types;
KernelElementEnvironment get elementEnvironment => _elementEnvironment;
@override
CommonElementsImpl get commonElements => _commonElements;
/// NativeBasicData is need for computation of the default super class.
NativeBasicData get nativeBasicData;
FunctionEntity get _mainFunction {
return env.mainMethod != null ? getMethodInternal(env.mainMethod) : null;
}
LibraryEntity get _mainLibrary {
return env.mainMethod != null
? getLibraryInternal(env.mainMethod.enclosingLibrary)
: null;
}
Iterable<LibraryEntity> get libraryListInternal;
SourceSpan getSourceSpan(Spannable spannable, Entity currentElement) {
SourceSpan fromSpannable(Spannable spannable) {
if (spannable is IndexedLibrary &&
spannable.libraryIndex < libraries.length) {
LibraryEnv env = libraries.getEnv(spannable);
return computeSourceSpanFromTreeNode(env.library);
} else if (spannable is IndexedClass &&
spannable.classIndex < classes.length) {
ClassData data = classes.getData(spannable);
assert(data != null, "No data for $spannable in $this");
return data.definition.location;
} else if (spannable is IndexedMember &&
spannable.memberIndex < members.length) {
MemberData data = members.getData(spannable);
assert(data != null, "No data for $spannable in $this");
return data.definition.location;
} else if (spannable is KLocalFunction) {
return getSourceSpan(spannable.memberContext, currentElement);
} else if (spannable is JLocal) {
return getSourceSpan(spannable.memberContext, currentElement);
}
return null;
}
SourceSpan sourceSpan = fromSpannable(spannable);
sourceSpan ??= fromSpannable(currentElement);
return sourceSpan;
}
LibraryEntity lookupLibrary(Uri uri) {
LibraryEnv libraryEnv = env.lookupLibrary(uri);
if (libraryEnv == null) return null;
return getLibraryInternal(libraryEnv.library, libraryEnv);
}
String _getLibraryName(IndexedLibrary library) {
assert(checkFamily(library));
LibraryEnv libraryEnv = libraries.getEnv(library);
return libraryEnv.library.name ?? '';
}
MemberEntity lookupLibraryMember(IndexedLibrary library, String name,
{bool setter: false}) {
assert(checkFamily(library));
LibraryEnv libraryEnv = libraries.getEnv(library);
ir.Member member = libraryEnv.lookupMember(name, setter: setter);
return member != null ? getMember(member) : null;
}
void _forEachLibraryMember(
IndexedLibrary library, void f(MemberEntity member)) {
assert(checkFamily(library));
LibraryEnv libraryEnv = libraries.getEnv(library);
libraryEnv.forEachMember((ir.Member node) {
f(getMember(node));
});
}
ClassEntity lookupClass(IndexedLibrary library, String name) {
assert(checkFamily(library));
LibraryEnv libraryEnv = libraries.getEnv(library);
ClassEnv classEnv = libraryEnv.lookupClass(name);
if (classEnv != null) {
return getClassInternal(classEnv.cls, classEnv);
}
return null;
}
void _forEachClass(IndexedLibrary library, void f(ClassEntity cls)) {
assert(checkFamily(library));
LibraryEnv libraryEnv = libraries.getEnv(library);
libraryEnv.forEachClass((ClassEnv classEnv) {
if (!classEnv.isUnnamedMixinApplication) {
f(getClassInternal(classEnv.cls, classEnv));
}
});
}
void ensureClassMembers(ir.Class node) {
classes.getEnv(getClassInternal(node)).ensureMembers(this);
}
MemberEntity lookupClassMember(IndexedClass cls, String name,
{bool setter: false}) {
assert(checkFamily(cls));
ClassEnv classEnv = classes.getEnv(cls);
return classEnv.lookupMember(this, name, setter: setter);
}
ConstructorEntity lookupConstructor(IndexedClass cls, String name) {
assert(checkFamily(cls));
ClassEnv classEnv = classes.getEnv(cls);
return classEnv.lookupConstructor(this, name);
}
@override
InterfaceType createInterfaceType(
ir.Class cls, List<ir.DartType> typeArguments) {
return new InterfaceType(getClass(cls), getDartTypes(typeArguments));
}
LibraryEntity getLibrary(ir.Library node) => getLibraryInternal(node);
LibraryEntity getLibraryInternal(ir.Library node, [LibraryEnv libraryEnv]);
@override
ClassEntity getClass(ir.Class node) => getClassInternal(node);
ClassEntity getClassInternal(ir.Class node, [ClassEnv classEnv]);
InterfaceType getSuperType(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.supertype;
}
void _ensureThisAndRawType(ClassEntity cls, ClassData data) {
assert(checkFamily(cls));
if (data is ClassDataImpl && data.thisType == null) {
ir.Class node = data.cls;
if (node.typeParameters.isEmpty) {
data.thisType =
data.rawType = new InterfaceType(cls, const <DartType>[]);
} else {
data.thisType = new InterfaceType(
cls,
new List<DartType>.generate(node.typeParameters.length,
(int index) {
return new TypeVariableType(
getTypeVariableInternal(node.typeParameters[index]));
}));
data.rawType = new InterfaceType(
cls,
new List<DartType>.filled(
node.typeParameters.length, const DynamicType()));
}
}
}
TypeVariableEntity getTypeVariable(ir.TypeParameter node) =>
getTypeVariableInternal(node);
TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node);
void _ensureSupertypes(ClassEntity cls, ClassData data) {
assert(checkFamily(cls));
if (data is ClassDataImpl && data.orderedTypeSet == null) {
_ensureThisAndRawType(cls, data);
ir.Class node = data.cls;
if (node.supertype == null) {
data.orderedTypeSet = new OrderedTypeSet.singleton(data.thisType);
data.isMixinApplication = false;
data.interfaces = const <InterfaceType>[];
} else {
InterfaceType processSupertype(ir.Supertype node) {
InterfaceType supertype = _typeConverter.visitSupertype(node);
IndexedClass superclass = supertype.element;
ClassData superdata = classes.getData(superclass);
_ensureSupertypes(superclass, superdata);
return supertype;
}
InterfaceType supertype;
LinkBuilder<InterfaceType> linkBuilder =
new LinkBuilder<InterfaceType>();
if (node.isMixinDeclaration) {
// A mixin declaration
//
// mixin M on A, B, C {}
//
// is encoded by CFE as
//
// abstract class M extends A with B, C {}
//
// but we encode it as
//
// abstract class M extends Object implements A, B, C {}
//
// so we need to collect the non-Object superclasses and add them
// to the interfaces of M.
ir.Class superclass = node.superclass;
while (superclass != null) {
if (superclass.isAnonymousMixin) {
// Add second to last mixed in superclasses. `B` and `C` in the
// example above.
ir.DartType mixinType = typeEnvironment.hierarchy
.getTypeAsInstanceOf(node.thisType, superclass.mixedInClass);
linkBuilder.addLast(getDartType(mixinType));
} else {
// Add first mixed in superclass. `A` in the example above.
ir.DartType mixinType = typeEnvironment.hierarchy
.getTypeAsInstanceOf(node.thisType, superclass);
linkBuilder.addLast(getDartType(mixinType));
break;
}
superclass = superclass.superclass;
}
// Set superclass to `Object`.
supertype = _commonElements.objectType;
} else {
supertype = processSupertype(node.supertype);
}
if (supertype == _commonElements.objectType) {
ClassEntity defaultSuperclass =
_commonElements.getDefaultSuperclass(cls, nativeBasicData);
data.supertype = _elementEnvironment.getRawType(defaultSuperclass);
} else {
data.supertype = supertype;
}
if (node.mixedInType != null) {
data.isMixinApplication = true;
linkBuilder
.addLast(data.mixedInType = processSupertype(node.mixedInType));
} else {
data.isMixinApplication = false;
}
node.implementedTypes.forEach((ir.Supertype supertype) {
linkBuilder.addLast(processSupertype(supertype));
});
Link<InterfaceType> interfaces =
linkBuilder.toLink(const Link<InterfaceType>());
OrderedTypeSetBuilder setBuilder =
new KernelOrderedTypeSetBuilder(this, cls);
data.orderedTypeSet = setBuilder.createOrderedTypeSet(
data.supertype, interfaces.reverse(const Link<InterfaceType>()));
data.interfaces = new List<InterfaceType>.from(interfaces.toList());
}
}
}
@override
TypedefType getTypedefType(ir.Typedef node) {
IndexedTypedef typedef = getTypedefInternal(node);
return typedefs.getData(typedef).rawType;
}
TypedefEntity getTypedefInternal(ir.Typedef node);
@override
MemberEntity getMember(ir.Member node) {
if (node is ir.Field) {
return getFieldInternal(node);
} else if (node is ir.Constructor) {
return getConstructorInternal(node);
} else if (node is ir.Procedure) {
if (node.kind == ir.ProcedureKind.Factory) {
return getConstructorInternal(node);
} else {
return getMethodInternal(node);
}
}
throw new UnsupportedError("Unexpected member: $node");
}
MemberEntity getSuperMember(
MemberEntity context, ir.Name name, ir.Member target,
{bool setter: false}) {
if (target != null && !target.isAbstract && target.isInstanceMember) {
return getMember(target);
}
ClassEntity cls = context.enclosingClass;
assert(
cls != null,
failedAt(context,
"No enclosing class for super member access in $context."));
IndexedClass superclass = getSuperType(cls)?.element;
while (superclass != null) {
ClassEnv env = classes.getEnv(superclass);
MemberEntity superMember =
env.lookupMember(this, name.name, setter: setter);
if (superMember != null) {
if (!superMember.isInstanceMember) return null;
if (!superMember.isAbstract) {
return superMember;
}
}
superclass = getSuperType(superclass)?.element;
}
return null;
}
@override
ConstructorEntity getConstructor(ir.Member node) =>
getConstructorInternal(node);
ConstructorEntity getConstructorInternal(ir.Member node);
ConstructorEntity getSuperConstructor(
ir.Constructor sourceNode, ir.Member targetNode) {
ConstructorEntity source = getConstructor(sourceNode);
ClassEntity sourceClass = source.enclosingClass;
ConstructorEntity target = getConstructor(targetNode);
ClassEntity targetClass = target.enclosingClass;
IndexedClass superClass = getSuperType(sourceClass)?.element;
if (superClass == targetClass) {
return target;
}
ClassEnv env = classes.getEnv(superClass);
ConstructorEntity constructor = env.lookupConstructor(this, target.name);
if (constructor != null) {
return constructor;
}
throw failedAt(source, "Super constructor for $source not found.");
}
@override
FunctionEntity getMethod(ir.Procedure node) => getMethodInternal(node);
FunctionEntity getMethodInternal(ir.Procedure node);
@override
FieldEntity getField(ir.Field node) => getFieldInternal(node);
FieldEntity getFieldInternal(ir.Field node);
@override
DartType getDartType(ir.DartType type) => _typeConverter.convert(type);
TypeVariableType getTypeVariableType(ir.TypeParameterType type) =>
getDartType(type);
List<DartType> getDartTypes(List<ir.DartType> types) {
List<DartType> list = <DartType>[];
types.forEach((ir.DartType type) {
list.add(getDartType(type));
});
return list;
}
InterfaceType getInterfaceType(ir.InterfaceType type) =>
_typeConverter.convert(type);
@override
FunctionType getFunctionType(ir.FunctionNode node) {
DartType returnType;
if (node.parent is ir.Constructor) {
// The return type on generative constructors is `void`, but we need
// `dynamic` type to match the element model.
returnType = const DynamicType();
} else {
returnType = getDartType(node.returnType);
}
List<DartType> parameterTypes = <DartType>[];
List<DartType> optionalParameterTypes = <DartType>[];
DartType getParameterType(ir.VariableDeclaration variable) {
if (variable.isCovariant || variable.isGenericCovariantImpl) {
// A covariant parameter has type `Object` in the method signature.
return commonElements.objectType;
}
return getDartType(variable.type);
}
for (ir.VariableDeclaration variable in node.positionalParameters) {
if (parameterTypes.length == node.requiredParameterCount) {
optionalParameterTypes.add(getParameterType(variable));
} else {
parameterTypes.add(getParameterType(variable));
}
}
List<String> namedParameters = <String>[];
List<DartType> namedParameterTypes = <DartType>[];
List<ir.VariableDeclaration> sortedNamedParameters =
node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name));
for (ir.VariableDeclaration variable in sortedNamedParameters) {
namedParameters.add(variable.name);
namedParameterTypes.add(getParameterType(variable));
}
List<FunctionTypeVariable> typeVariables;
if (node.typeParameters.isNotEmpty) {
List<DartType> typeParameters = <DartType>[];
for (ir.TypeParameter typeParameter in node.typeParameters) {
typeParameters
.add(getDartType(new ir.TypeParameterType(typeParameter)));
}
typeVariables = new List<FunctionTypeVariable>.generate(
node.typeParameters.length,
(int index) => new FunctionTypeVariable(index));
DartType subst(DartType type) {
return type.subst(typeVariables, typeParameters);
}
returnType = subst(returnType);
parameterTypes = parameterTypes.map(subst).toList();
optionalParameterTypes = optionalParameterTypes.map(subst).toList();
namedParameterTypes = namedParameterTypes.map(subst).toList();
for (int index = 0; index < typeVariables.length; index++) {
typeVariables[index].bound =
subst(getDartType(node.typeParameters[index].bound));
}
} else {
typeVariables = const <FunctionTypeVariable>[];
}
return new FunctionType(returnType, parameterTypes, optionalParameterTypes,
namedParameters, namedParameterTypes, typeVariables);
}
ConstantValue computeConstantValue(
Spannable spannable, ConstantExpression constant,
{bool requireConstant: true}) {
return _constantEnvironment._getConstantValue(spannable, constant,
constantRequired: requireConstant);
}
DartType substByContext(DartType type, InterfaceType context) {
return type.subst(
context.typeArguments, getThisType(context.element).typeArguments);
}
/// Returns the type of the `call` method on 'type'.
///
/// If [type] doesn't have a `call` member `null` is returned. If [type] has
/// an invalid `call` member (non-method or a synthesized method with both
/// optional and named parameters) a [DynamicType] is returned.
DartType getCallType(InterfaceType type) {
IndexedClass cls = type.element;
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
if (data.callType != null) {
return substByContext(data.callType, type);
}
return null;
}
InterfaceType getThisType(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureThisAndRawType(cls, data);
return data.thisType;
}
InterfaceType _getRawType(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureThisAndRawType(cls, data);
return data.rawType;
}
FunctionType _getFunctionType(IndexedFunction function) {
assert(checkFamily(function));
FunctionData data = members.getData(function);
return data.getFunctionType(this);
}
List<TypeVariableType> _getFunctionTypeVariables(IndexedFunction function) {
assert(checkFamily(function));
FunctionData data = members.getData(function);
return data.getFunctionTypeVariables(this);
}
DartType _getFieldType(IndexedField field) {
assert(checkFamily(field));
FieldData data = members.getData(field);
return data.getFieldType(this);
}
DartType getTypeVariableBound(IndexedTypeVariable typeVariable) {
assert(checkFamily(typeVariable));
TypeVariableData data = typeVariables.getData(typeVariable);
return data.getBound(this);
}
DartType _getTypeVariableDefaultType(IndexedTypeVariable typeVariable) {
assert(checkFamily(typeVariable));
TypeVariableData data = typeVariables.getData(typeVariable);
return data.getDefaultType(this);
}
ClassEntity getAppliedMixin(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.mixedInType?.element;
}
bool _isMixinApplication(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.isMixinApplication;
}
bool _isUnnamedMixinApplication(IndexedClass cls) {
assert(checkFamily(cls));
ClassEnv env = classes.getEnv(cls);
return env.isUnnamedMixinApplication;
}
bool _isSuperMixinApplication(IndexedClass cls) {
assert(checkFamily(cls));
ClassEnv env = classes.getEnv(cls);
env.ensureMembers(this);
return env.isSuperMixinApplication;
}
void _forEachSupertype(IndexedClass cls, void f(InterfaceType supertype)) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
data.orderedTypeSet.supertypes.forEach(f);
}
void _forEachMixin(IndexedClass cls, void f(ClassEntity mixin)) {
assert(checkFamily(cls));
while (cls != null) {
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
if (data.mixedInType != null) {
f(data.mixedInType.element);
}
cls = data.supertype?.element;
}
}
void _forEachConstructor(IndexedClass cls, void f(ConstructorEntity member)) {
assert(checkFamily(cls));
ClassEnv env = classes.getEnv(cls);
env.forEachConstructor(this, f);
}
void forEachConstructorBody(
IndexedClass cls, void f(ConstructorBodyEntity member)) {
throw new UnsupportedError(
'KernelToElementMapBase._forEachConstructorBody');
}
void forEachNestedClosure(
MemberEntity member, void f(FunctionEntity closure));
void _forEachLocalClassMember(IndexedClass cls, void f(MemberEntity member)) {
assert(checkFamily(cls));
ClassEnv env = classes.getEnv(cls);
env.forEachMember(this, (MemberEntity member) {
f(member);
});
}
void forEachInjectedClassMember(
IndexedClass cls, void f(MemberEntity member)) {
assert(checkFamily(cls));
throw new UnsupportedError(
'KernelToElementMapBase._forEachInjectedClassMember');
}
void _forEachClassMember(
IndexedClass cls, void f(ClassEntity cls, MemberEntity member)) {
assert(checkFamily(cls));
ClassEnv env = classes.getEnv(cls);
env.forEachMember(this, (MemberEntity member) {
f(cls, member);
});
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
if (data.supertype != null) {
_forEachClassMember(data.supertype.element, f);
}
}
ConstantConstructor _getConstructorConstant(IndexedConstructor constructor) {
assert(checkFamily(constructor));
ConstructorData data = members.getData(constructor);
return data.getConstructorConstant(this, constructor);
}
ConstantExpression _getFieldConstantExpression(IndexedField field) {
assert(checkFamily(field));
FieldData data = members.getData(field);
return data.getFieldConstantExpression(this);
}
InterfaceType asInstanceOf(InterfaceType type, ClassEntity cls) {
assert(checkFamily(cls));
OrderedTypeSet orderedTypeSet = getOrderedTypeSet(type.element);
InterfaceType supertype =
orderedTypeSet.asInstanceOf(cls, getHierarchyDepth(cls));
if (supertype != null) {
supertype = substByContext(supertype, type);
}
return supertype;
}
OrderedTypeSet getOrderedTypeSet(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.orderedTypeSet;
}
int getHierarchyDepth(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.orderedTypeSet.maxDepth;
}
Iterable<InterfaceType> getInterfaces(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
_ensureSupertypes(cls, data);
return data.interfaces;
}
MemberDefinition getMemberDefinitionInternal(covariant IndexedMember member) {
assert(checkFamily(member));
return members.getData(member).definition;
}
ClassDefinition getClassDefinitionInternal(covariant IndexedClass cls) {
assert(checkFamily(cls));
return classes.getData(cls).definition;
}
ir.Typedef _getTypedefNode(covariant IndexedTypedef typedef) {
return typedefs.getData(typedef).node;
}
ImportEntity getImport(ir.LibraryDependency node) {
ir.Library library = node.parent;
LibraryData data = libraries.getData(getLibraryInternal(library));
return data.imports[node];
}
ir.TypeEnvironment get typeEnvironment {
if (_typeEnvironment == null) {
_typeEnvironment ??= new ir.TypeEnvironment(
new ir.CoreTypes(env.mainComponent),
new ir.ClassHierarchy(env.mainComponent));
}
return _typeEnvironment;
}
DartType getStaticType(ir.Expression node) {
ir.TreeNode enclosingClass = node;
while (enclosingClass != null && enclosingClass is! ir.Class) {
enclosingClass = enclosingClass.parent;
}
try {
typeEnvironment.thisType =
enclosingClass is ir.Class ? enclosingClass.thisType : null;
return getDartType(node.getStaticType(typeEnvironment));
} catch (e) {
// The static type computation crashes on type errors. Use `dynamic`
// as static type.
return commonElements.dynamicType;
}
}
Name getName(ir.Name name) {
return new Name(
name.name, name.isPrivate ? getLibrary(name.library) : null);
}
CallStructure getCallStructure(ir.Arguments arguments) {
int argumentCount = arguments.positional.length + arguments.named.length;
List<String> namedArguments = arguments.named.map((e) => e.name).toList();
return new CallStructure(
argumentCount, namedArguments, arguments.types.length);
}
ParameterStructure getParameterStructure(ir.FunctionNode node,
// TODO(johnniwinther): Remove this when type arguments are passed to
// constructors like calling a generic method.
{bool includeTypeParameters: true}) {
// TODO(johnniwinther): Cache the computed function type.
int requiredParameters = node.requiredParameterCount;
int positionalParameters = node.positionalParameters.length;
int typeParameters = node.typeParameters.length;
List<String> namedParameters =
node.namedParameters.map((p) => p.name).toList()..sort();
return new ParameterStructure(requiredParameters, positionalParameters,
namedParameters, includeTypeParameters ? typeParameters : 0);
}
Selector getSelector(ir.Expression node) {
// TODO(efortuna): This is screaming for a common interface between
// PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel
// folks.
if (node is ir.PropertyGet) {
return getGetterSelector(node.name);
}
if (node is ir.SuperPropertyGet) {
return getGetterSelector(node.name);
}
if (node is ir.PropertySet) {
return getSetterSelector(node.name);
}
if (node is ir.SuperPropertySet) {
return getSetterSelector(node.name);
}
if (node is ir.InvocationExpression) {
return getInvocationSelector(node);
}
throw failedAt(
CURRENT_ELEMENT_SPANNABLE,
"Can only get the selector for a property get or an invocation: "
"${node}");
}
Selector getInvocationSelector(ir.InvocationExpression invocation) {
Name name = getName(invocation.name);
SelectorKind kind;
if (Selector.isOperatorName(name.text)) {
if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
kind = SelectorKind.INDEX;
} else {
kind = SelectorKind.OPERATOR;
}
} else {
kind = SelectorKind.CALL;
}
CallStructure callStructure = getCallStructure(invocation.arguments);
return new Selector(kind, name, callStructure);
}
Selector getGetterSelector(ir.Name irName) {
Name name = new Name(
irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
return new Selector.getter(name);
}
Selector getSetterSelector(ir.Name irName) {
Name name = new Name(
irName.name, irName.isPrivate ? getLibrary(irName.library) : null);
return new Selector.setter(name);
}
/// Looks up [typeName] for use in the spec-string of a `JS` call.
// TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling
// the `ForeignResolver`.
native.TypeLookup typeLookup({bool resolveAsRaw: true}) {
return resolveAsRaw
? (_cachedTypeLookupRaw ??= _typeLookup(resolveAsRaw: true))
: (_cachedTypeLookupFull ??= _typeLookup(resolveAsRaw: false));
}
native.TypeLookup _cachedTypeLookupRaw;
native.TypeLookup _cachedTypeLookupFull;
native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
bool cachedMayLookupInMain;
bool mayLookupInMain() {
var mainUri = elementEnvironment.mainLibrary.canonicalUri;
// Tests permit lookup outside of dart: libraries.
return mainUri.path.contains('tests/compiler/dart2js_native') ||
mainUri.path.contains('tests/compiler/dart2js_extra');
}
DartType lookup(String typeName, {bool required}) {
DartType findInLibrary(LibraryEntity library) {
if (library != null) {
ClassEntity cls = elementEnvironment.lookupClass(library, typeName);
if (cls != null) {
// TODO(johnniwinther): Align semantics.
return resolveAsRaw
? elementEnvironment.getRawType(cls)
: elementEnvironment.getThisType(cls);
}
}
return null;
}
DartType findIn(Uri uri) {
return findInLibrary(elementEnvironment.lookupLibrary(uri));
}
// TODO(johnniwinther): Narrow the set of lookups based on the depending
// library.
// TODO(johnniwinther): Cache more results to avoid redundant lookups?
DartType type;
if (cachedMayLookupInMain ??= mayLookupInMain()) {
type ??= findInLibrary(elementEnvironment.mainLibrary);
}
type ??= findIn(Uris.dart_core);
type ??= findIn(Uris.dart__js_helper);
type ??= findIn(Uris.dart__interceptors);
type ??= findIn(Uris.dart__native_typed_data);
type ??= findIn(Uris.dart_collection);
type ??= findIn(Uris.dart_math);
type ??= findIn(Uris.dart_html);
type ??= findIn(Uris.dart_html_common);
type ??= findIn(Uris.dart_svg);
type ??= findIn(Uris.dart_web_audio);
type ??= findIn(Uris.dart_web_gl);
type ??= findIn(Uris.dart_web_sql);
type ??= findIn(Uris.dart_indexed_db);
type ??= findIn(Uris.dart_typed_data);
type ??= findIn(Uris.dart_mirrors);
if (type == null && required) {
reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
MessageKind.GENERIC, {'text': "Type '$typeName' not found."});
}
return type;
}
return lookup;
}
String _getStringArgument(ir.StaticInvocation node, int index) {
return node.arguments.positional[index].accept(new Stringifier());
}
/// Computes the [native.NativeBehavior] for a call to the [JS] function.
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
if (node.arguments.positional.length < 2 ||
node.arguments.named.isNotEmpty) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
return new native.NativeBehavior();
}
String codeString = _getStringArgument(node, 1);
if (codeString == null) {
reporter.reportErrorMessage(
CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
return new native.NativeBehavior();
}
return native.NativeBehavior.ofJsCall(
specString,
codeString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
reporter,
commonElements);
}
/// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN]
/// function.
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
return new native.NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
return new native.NativeBehavior();
}
return native.NativeBehavior.ofJsBuiltinCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
reporter,
commonElements);
}
/// Computes the [native.NativeBehavior] for a call to the
/// [JS_EMBEDDED_GLOBAL] function.
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
ir.StaticInvocation node) {
if (node.arguments.positional.length < 1) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global expression has no type.");
return new native.NativeBehavior();
}
if (node.arguments.positional.length < 2) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
return new native.NativeBehavior();
}
if (node.arguments.positional.length > 2 ||
node.arguments.named.isNotEmpty) {
reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
"JS embedded global has more than 2 arguments.");
return new native.NativeBehavior();
}
String specString = _getStringArgument(node, 0);
if (specString == null) {
reporter.internalError(
CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
return new native.NativeBehavior();
}
return native.NativeBehavior.ofJsEmbeddedGlobalCall(
specString,
typeLookup(resolveAsRaw: true),
CURRENT_ELEMENT_SPANNABLE,
reporter,
commonElements);
}
js.Name getNameForJsGetName(ConstantValue constant, Namer namer) {
int index = extractEnumIndexFromConstantValue(
constant, commonElements.jsGetNameEnum);
if (index == null) return null;
return namer.getNameForJsGetName(
CURRENT_ELEMENT_SPANNABLE, JsGetName.values[index]);
}
int extractEnumIndexFromConstantValue(
ConstantValue constant, ClassEntity classElement) {
if (constant is ConstructedConstantValue) {
if (constant.type.element == classElement) {
assert(constant.fields.length == 1 || constant.fields.length == 2);
ConstantValue indexConstant = constant.fields.values.first;
if (indexConstant is IntConstantValue) {
return indexConstant.intValue.toInt();
}
}
}
return null;
}
ConstantValue getConstantValue(ir.Expression node,
{bool requireConstant: true, bool implicitNull: false}) {
ConstantExpression constant;
if (node == null) {
if (!implicitNull) {
throw failedAt(
CURRENT_ELEMENT_SPANNABLE, 'No expression for constant.');
}
constant = new NullConstantExpression();
} else {
constant =
new Constantifier(this, requireConstant: requireConstant).visit(node);
}
if (constant == null) {
if (requireConstant) {
throw new UnsupportedError(
'No constant for ${DebugPrinter.prettyPrint(node)}');
}
return null;
}
ConstantValue value = computeConstantValue(
computeSourceSpanFromTreeNode(node), constant,
requireConstant: requireConstant);
if (!value.isConstant && !requireConstant) {
return null;
}
return value;
}
/// Converts [annotations] into a list of [ConstantValue]s.
List<ConstantValue> getMetadata(List<ir.Expression> annotations) {
if (annotations.isEmpty) return const <ConstantValue>[];
List<ConstantValue> metadata = <ConstantValue>[];
annotations.forEach((ir.Expression node) {
metadata.add(getConstantValue(node));
});
return metadata;
}
FunctionEntity getSuperNoSuchMethod(ClassEntity cls) {
while (cls != null) {
cls = elementEnvironment.getSuperClass(cls);
MemberEntity member = elementEnvironment.lookupLocalClassMember(
cls, Identifiers.noSuchMethod_);
if (member != null && !member.isAbstract) {
if (member.isFunction) {
FunctionEntity function = member;
if (function.parameterStructure.positionalParameters >= 1) {
return function;
}
}
// If [member] is not a valid `noSuchMethod` the target is
// `Object.superNoSuchMethod`.
break;
}
}
FunctionEntity function = elementEnvironment.lookupLocalClassMember(
commonElements.objectClass, Identifiers.noSuchMethod_);
assert(function != null,
failedAt(cls, "No super noSuchMethod found for class $cls."));
return function;
}
}
/// Mixin that implements the abstract methods in [KernelToElementMapBase].
abstract class ElementCreatorMixin implements KernelToElementMapBase {
/// Set to `true` before creating the J-World from the K-World to assert that
/// no entities are created late.
bool envIsClosed = false;
ProgramEnv get env;
EntityDataEnvMap<IndexedLibrary, LibraryData, LibraryEnv> get libraries;
EntityDataEnvMap<IndexedClass, ClassData, ClassEnv> get classes;
EntityDataMap<IndexedMember, MemberData> get members;
EntityDataMap<IndexedTypeVariable, TypeVariableData> get typeVariables;
EntityDataMap<IndexedTypedef, TypedefData> get typedefs;
final Map<ir.Library, IndexedLibrary> libraryMap = {};
final Map<ir.Class, IndexedClass> classMap = {};
final Map<ir.Typedef, IndexedTypedef> typedefMap = {};
/// Map from [ir.TypeParameter] nodes to the corresponding
/// [TypeVariableEntity].
///
/// Normally the type variables are [IndexedTypeVariable]s, but for type
/// parameters on local function (in the frontend) these are _not_ since
/// their type declaration is neither a class nor a member. In the backend,
/// these type parameters belong to the call-method and are therefore indexed.
final Map<ir.TypeParameter, TypeVariableEntity> typeVariableMap = {};
final Map<ir.Member, IndexedConstructor> constructorMap = {};
final Map<ir.Procedure, IndexedFunction> methodMap = {};
final Map<ir.Field, IndexedField> fieldMap = {};
final Map<ir.TreeNode, Local> localFunctionMap = {};
Name getName(ir.Name node);
FunctionType getFunctionType(ir.FunctionNode node);
MemberEntity getMember(ir.Member node);
Entity getClosure(ir.FunctionDeclaration node);
Iterable<LibraryEntity> get libraryListInternal {
if (env.length != libraryMap.length) {
// Create a [KLibrary] for each library.
env.forEachLibrary((LibraryEnv env) {
getLibraryInternal(env.library, env);
});
}
return libraryMap.values;
}
LibraryEntity getLibraryInternal(ir.Library node, [LibraryEnv libraryEnv]) {
return libraryMap[node] ??= _getLibraryCreate(node, libraryEnv);
}
LibraryEntity _getLibraryCreate(ir.Library node, LibraryEnv libraryEnv) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"library for $node.");
Uri canonicalUri = node.importUri;
String name = node.name;
if (name == null) {
// Use the file name as script name.
String path = canonicalUri.path;
name = path.substring(path.lastIndexOf('/') + 1);
}
IndexedLibrary library = createLibrary(name, canonicalUri);
return libraries.register(library, new LibraryData(node),
libraryEnv ?? env.lookupLibrary(canonicalUri));
}
ClassEntity getClassInternal(ir.Class node, [ClassEnv classEnv]) {
return classMap[node] ??= _getClassCreate(node, classEnv);
}
ClassEntity _getClassCreate(ir.Class node, ClassEnv classEnv) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"class for $node.");
KLibrary library = getLibraryInternal(node.enclosingLibrary);
if (classEnv == null) {
classEnv = libraries.getEnv(library).lookupClass(node.name);
}
IndexedClass cls =
createClass(library, node.name, isAbstract: node.isAbstract);
return classes.register(
cls,
new ClassDataImpl(node, new RegularClassDefinition(cls, node)),
classEnv);
}
TypedefEntity getTypedefInternal(ir.Typedef node) {
return typedefMap[node] ??= _getTypedefCreate(node);
}
TypedefEntity _getTypedefCreate(ir.Typedef node) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"typedef for $node.");
IndexedLibrary library = getLibraryInternal(node.enclosingLibrary);
IndexedTypedef typedef = createTypedef(library, node.name);
TypedefType typedefType = new TypedefType(
typedef,
new List<DartType>.filled(
node.typeParameters.length, const DynamicType()),
getDartType(node.type));
return typedefs.register(
typedef, new TypedefData(node, typedef, typedefType));
}
TypeVariableEntity getTypeVariableInternal(ir.TypeParameter node) {
return typeVariableMap[node] ??= _getTypeVariableCreate(node);
}
TypeVariableEntity _getTypeVariableCreate(ir.TypeParameter node) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"type variable for $node.");
if (node.parent is ir.Class) {
ir.Class cls = node.parent;
int index = cls.typeParameters.indexOf(node);
return typeVariables.register(
createTypeVariable(getClassInternal(cls), node.name, index),
new TypeVariableData(node));
}
if (node.parent is ir.FunctionNode) {
ir.FunctionNode func = node.parent;
int index = func.typeParameters.indexOf(node);
if (func.parent is ir.Constructor) {
ir.Constructor constructor = func.parent;
ir.Class cls = constructor.enclosingClass;
return getTypeVariableInternal(cls.typeParameters[index]);
} else if (func.parent is ir.Procedure) {
ir.Procedure procedure = func.parent;
if (procedure.kind == ir.ProcedureKind.Factory) {
ir.Class cls = procedure.enclosingClass;
return getTypeVariableInternal(cls.typeParameters[index]);
} else {
return typeVariables.register(
createTypeVariable(
getMethodInternal(procedure), node.name, index),
new TypeVariableData(node));
}
} else {
throw new UnsupportedError('Unsupported function type parameter parent '
'node ${func.parent}.');
}
}
throw new UnsupportedError('Unsupported type parameter type node $node.');
}
ConstructorEntity getConstructorInternal(ir.Member node) {
return constructorMap[node] ??= _getConstructorCreate(node);
}
ConstructorEntity _getConstructorCreate(ir.Member node) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"constructor for $node.");
MemberDefinition definition;
ir.FunctionNode functionNode;
ClassEntity enclosingClass = getClassInternal(node.enclosingClass);
Name name = getName(node.name);
bool isExternal = node.isExternal;
IndexedConstructor constructor;
if (node is ir.Constructor) {
functionNode = node.function;
constructor = createGenerativeConstructor(enclosingClass, name,
getParameterStructure(functionNode, includeTypeParameters: false),
isExternal: isExternal, isConst: node.isConst);
definition = new SpecialMemberDefinition(
constructor, node, MemberKind.constructor);
} else if (node is ir.Procedure) {
functionNode = node.function;
bool isFromEnvironment = isExternal &&
name.text == 'fromEnvironment' &&
const ['int', 'bool', 'String'].contains(enclosingClass.name);
constructor = createFactoryConstructor(enclosingClass, name,
getParameterStructure(functionNode, includeTypeParameters: false),
isExternal: isExternal,
isConst: node.isConst,
isFromEnvironmentConstructor: isFromEnvironment);
definition = new RegularMemberDefinition(constructor, node);
} else {
// TODO(johnniwinther): Convert `node.location` to a [SourceSpan].
throw failedAt(
NO_LOCATION_SPANNABLE, "Unexpected constructor node: ${node}.");
}
return members.register<IndexedConstructor, ConstructorData>(
constructor, new ConstructorDataImpl(node, functionNode, definition));
}
FunctionEntity getMethodInternal(ir.Procedure node) {
// [_getMethodCreate] inserts the created function in [methodMap] so we
// don't need to use ??= here.
return methodMap[node] ?? _getMethodCreate(node);
}
FunctionEntity _getMethodCreate(ir.Procedure node) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"function for $node.");
FunctionEntity function;
LibraryEntity library;
ClassEntity enclosingClass;
if (node.enclosingClass != null) {
enclosingClass = getClassInternal(node.enclosingClass);
library = enclosingClass.library;
} else {
library = getLibraryInternal(node.enclosingLibrary);
}
Name name = getName(node.name);
bool isStatic = node.isStatic;
bool isExternal = node.isExternal;
// TODO(johnniwinther): Remove `&& !node.isExternal` when #31233 is fixed.
bool isAbstract = node.isAbstract && !node.isExternal;
AsyncMarker asyncMarker = getAsyncMarker(node.function);
switch (node.kind) {
case ir.ProcedureKind.Factory:
throw new UnsupportedError("Cannot create method from factory.");
case ir.ProcedureKind.Getter:
function = createGetter(library, enclosingClass, name, asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
break;
case ir.ProcedureKind.Method:
case ir.ProcedureKind.Operator:
function = createMethod(library, enclosingClass, name,
getParameterStructure(node.function), asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
break;
case ir.ProcedureKind.Setter:
assert(asyncMarker == AsyncMarker.SYNC);
function = createSetter(library, enclosingClass, name.setter,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
break;
}
members.register<IndexedFunction, FunctionData>(
function,
new FunctionDataImpl(
node, node.function, new RegularMemberDefinition(function, node)));
// We need to register the function before creating the type variables.
methodMap[node] = function;
for (ir.TypeParameter typeParameter in node.function.typeParameters) {
getTypeVariable(typeParameter);
}
return function;
}
FieldEntity getFieldInternal(ir.Field node) {
return fieldMap[node] ??= _getFieldCreate(node);
}
FieldEntity _getFieldCreate(ir.Field node) {
assert(
!envIsClosed,
"Environment of $this is closed. Trying to create "
"field for $node.");
LibraryEntity library;
ClassEntity enclosingClass;
if (node.enclosingClass != null) {
enclosingClass = getClassInternal(node.enclosingClass);
library = enclosingClass.library;
} else {
library = getLibraryInternal(node.enclosingLibrary);
}
Name name = getName(node.name);
bool isStatic = node.isStatic;
IndexedField field = createField(library, enclosingClass, name,
isStatic: isStatic,
isAssignable: node.isMutable,
isConst: node.isConst);
return members.register<IndexedField, FieldData>(field,
new FieldDataImpl(node, new RegularMemberDefinition(field, node)));
}
IndexedLibrary createLibrary(String name, Uri canonicalUri);
IndexedClass createClass(LibraryEntity library, String name,
{bool isAbstract});
IndexedTypedef createTypedef(LibraryEntity library, String name);
TypeVariableEntity createTypeVariable(
Entity typeDeclaration, String name, int index);
IndexedConstructor createGenerativeConstructor(ClassEntity enclosingClass,
Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst});
IndexedConstructor createFactoryConstructor(ClassEntity enclosingClass,
Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst, bool isFromEnvironmentConstructor});
IndexedFunction createGetter(LibraryEntity library,
ClassEntity enclosingClass, Name name, AsyncMarker asyncMarker,
{bool isStatic, bool isExternal, bool isAbstract});
IndexedFunction createMethod(
LibraryEntity library,
ClassEntity enclosingClass,
Name name,
ParameterStructure parameterStructure,
AsyncMarker asyncMarker,
{bool isStatic,
bool isExternal,
bool isAbstract});
IndexedFunction createSetter(
LibraryEntity library, ClassEntity enclosingClass, Name name,
{bool isStatic, bool isExternal, bool isAbstract});
IndexedField createField(
LibraryEntity library, ClassEntity enclosingClass, Name name,
{bool isStatic, bool isAssignable, bool isConst});
}
/// Implementation of [KernelToElementMap] that only supports world
/// impact computation.
class KernelToElementMapImpl extends KernelToElementMapBase
with ElementCreatorMixin
implements KernelToElementMap {
native.BehaviorBuilder _nativeBehaviorBuilder;
FrontendStrategy _frontendStrategy;
KernelToElementMapImpl(DiagnosticReporter reporter, Environment environment,
this._frontendStrategy, CompilerOptions options)
: super(options, reporter, environment);
@override
bool checkFamily(Entity entity) {
assert(
'$entity'.startsWith(kElementPrefix),
failedAt(entity,
"Unexpected entity $entity, expected family $kElementPrefix."));
return true;
}
DartType getTypeVariableBound(TypeVariableEntity typeVariable) {
if (typeVariable is KLocalTypeVariable) return typeVariable.bound;
return super.getTypeVariableBound(typeVariable);
}
DartType _getTypeVariableDefaultType(TypeVariableEntity typeVariable) {
if (typeVariable is KLocalTypeVariable) return typeVariable.defaultType;
return super._getTypeVariableDefaultType(typeVariable);
}
@override
void forEachNestedClosure(
MemberEntity member, void f(FunctionEntity closure)) {
throw new UnsupportedError(
"KernelToElementMapForImpactImpl._forEachNestedClosure");
}
@override
NativeBasicData get nativeBasicData => _frontendStrategy.nativeBasicData;
/// Adds libraries in [component] to the set of libraries.
///
/// The main method of the first component is used as the main method for the
/// compilation.
void addComponent(ir.Component component) {
env.addComponent(component);
}
native.BehaviorBuilder get nativeBehaviorBuilder =>
_nativeBehaviorBuilder ??= new KernelBehaviorBuilder(elementEnvironment,
commonElements, nativeBasicData, reporter, options);
ResolutionImpact computeWorldImpact(KMember member) {
return buildKernelImpact(
members.getData(member).definition.node, this, reporter, options);
}
ScopeModel computeScopeModel(KMember member) {
ir.Member node = members.getData(member).definition.node;
return KernelClosureAnalysis.computeScopeModel(member, node);
}
/// Returns the kernel [ir.Procedure] node for the [method].
ir.Procedure _lookupProcedure(KFunction method) {
return members.getData(method).definition.node;
}
@override
ir.Library getLibraryNode(LibraryEntity library) {
return libraries.getData(library).library;
}
@override
Entity getClosure(ir.FunctionDeclaration node) {
return getLocalFunction(node);
}
@override
Local getLocalFunction(ir.TreeNode node) {
assert(
node is ir.FunctionDeclaration || node is ir.FunctionExpression,
failedAt(
CURRENT_ELEMENT_SPANNABLE, 'Invalid local function node: $node'));
KLocalFunction localFunction = localFunctionMap[node];
if (localFunction == null) {
MemberEntity memberContext;
Entity executableContext;
ir.TreeNode parent = node.parent;
while (parent != null) {
if (parent is ir.Member) {
executableContext = memberContext = getMember(parent);
break;
}
if (parent is ir.FunctionDeclaration ||
parent is ir.FunctionExpression) {
KLocalFunction localFunction = getLocalFunction(parent);
executableContext = localFunction;
memberContext = localFunction.memberContext;
break;
}
parent = parent.parent;
}
String name;
ir.FunctionNode function;
if (node is ir.FunctionDeclaration) {
name = node.variable.name;
function = node.function;
} else if (node is ir.FunctionExpression) {
function = node.function;
}
localFunction = localFunctionMap[node] =
new KLocalFunction(name, memberContext, executableContext, node);
int index = 0;
List<KLocalTypeVariable> typeVariables = <KLocalTypeVariable>[];
for (ir.TypeParameter typeParameter in function.typeParameters) {
typeVariables.add(typeVariableMap[typeParameter] =
new KLocalTypeVariable(localFunction, typeParameter.name, index));
index++;
}
index = 0;
for (ir.TypeParameter typeParameter in function.typeParameters) {
typeVariables[index].bound = getDartType(typeParameter.bound);
typeVariables[index].defaultType =
getDartType(typeParameter.defaultType);
index++;
}
localFunction.functionType = getFunctionType(function);
}
return localFunction;
}
bool _implementsFunction(IndexedClass cls) {
assert(checkFamily(cls));
ClassData data = classes.getData(cls);
OrderedTypeSet orderedTypeSet = data.orderedTypeSet;
InterfaceType supertype = orderedTypeSet.asInstanceOf(
commonElements.functionClass,
getHierarchyDepth(commonElements.functionClass));
if (supertype != null) {
return true;
}
return data.callType is FunctionType;
}
@override
MemberDefinition getMemberDefinition(MemberEntity member) {
return getMemberDefinitionInternal(member);
}
@override
ClassDefinition getClassDefinition(ClassEntity cls) {
return getClassDefinitionInternal(cls);
}
@override
ir.Typedef getTypedefNode(TypedefEntity typedef) {
return _getTypedefNode(typedef);
}
/// Returns the element type of a async/sync*/async* function.
@override
DartType getFunctionAsyncOrSyncStarElementType(ir.FunctionNode functionNode) {
DartType returnType = getDartType(functionNode.returnType);
switch (functionNode.asyncMarker) {
case ir.AsyncMarker.SyncStar:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.SYNC_STAR, returnType);
case ir.AsyncMarker.Async:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.ASYNC, returnType);
case ir.AsyncMarker.AsyncStar:
return elementEnvironment.getAsyncOrSyncStarElementType(
AsyncMarker.ASYNC_STAR, returnType);
default:
failedAt(CURRENT_ELEMENT_SPANNABLE,
"Unexpected ir.AsyncMarker: ${functionNode.asyncMarker}");
}
return null;
}
/// Returns `true` is [node] has a `@Native(...)` annotation.
// TODO(johnniwinther): Cache this for later use.
bool isNativeClass(ir.Class node) {
for (ir.Expression annotation in node.annotations) {
if (annotation is ir.ConstructorInvocation) {
FunctionEntity target = getConstructor(annotation.target);
if (target.enclosingClass == commonElements.nativeAnnotationClass) {
return true;
}
}
}
return false;
}
/// Compute the kind of foreign helper function called by [node], if any.
ForeignKind getForeignKind(ir.StaticInvocation node) {
if (commonElements.isForeignHelper(getMember(node.target))) {
switch (node.target.name.name) {
case JavaScriptBackend.JS:
return ForeignKind.JS;
case JavaScriptBackend.JS_BUILTIN:
return ForeignKind.JS_BUILTIN;
case JavaScriptBackend.JS_EMBEDDED_GLOBAL:
return ForeignKind.JS_EMBEDDED_GLOBAL;
case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT:
return ForeignKind.JS_INTERCEPTOR_CONSTANT;
}
}
return ForeignKind.NONE;
}
/// Computes the [InterfaceType] referenced by a call to the
/// [JS_INTERCEPTOR_CONSTANT] function, if any.
InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) {
if (node.arguments.positional.length != 1 ||
node.arguments.named.isNotEmpty) {
reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE,
MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
}
ir.Node argument = node.arguments.positional.first;
if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) {
return getInterfaceType(argument.type);
}
return null;
}
/// Computes the native behavior for reading the native [field].
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field,
{bool isJsInterop}) {
DartType type = getDartType(field.type);
List<ConstantValue> metadata = getMetadata(field.annotations);
return nativeBehaviorBuilder.buildFieldLoadBehavior(
type, metadata, typeLookup(resolveAsRaw: false),
isJsInterop: isJsInterop);
}
/// Computes the native behavior for writing to the native [field].
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
DartType type = getDartType(field.type);
return nativeBehaviorBuilder.buildFieldStoreBehavior(type);
}
/// Computes the native behavior for calling [member].
// TODO(johnniwinther): Cache this for later use.
native.NativeBehavior getNativeBehaviorForMethod(ir.Member member,
{bool isJsInterop}) {
DartType type;
if (member is ir.Procedure) {
type = getFunctionType(member.function);
} else if (member is ir.Constructor) {
type = getFunctionType(member.function);
} else {
failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected method node $member.");
}
List<ConstantValue> metadata = getMetadata(member.annotations);
return nativeBehaviorBuilder.buildMethodBehavior(
type, metadata, typeLookup(resolveAsRaw: false),
isJsInterop: isJsInterop);
}
IndexedLibrary createLibrary(String name, Uri canonicalUri) {
return new KLibrary(name, canonicalUri);
}
IndexedClass createClass(LibraryEntity library, String name,
{bool isAbstract}) {
return new KClass(library, name, isAbstract: isAbstract);
}
@override
IndexedTypedef createTypedef(LibraryEntity library, String name) {
return new KTypedef(library, name);
}
TypeVariableEntity createTypeVariable(
Entity typeDeclaration, String name, int index) {
return new KTypeVariable(typeDeclaration, name, index);
}
IndexedConstructor createGenerativeConstructor(ClassEntity enclosingClass,
Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst}) {
return new KGenerativeConstructor(enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
}
IndexedConstructor createFactoryConstructor(ClassEntity enclosingClass,
Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst, bool isFromEnvironmentConstructor}) {
return new KFactoryConstructor(enclosingClass, name, parameterStructure,
isExternal: isExternal,
isConst: isConst,
isFromEnvironmentConstructor: isFromEnvironmentConstructor);
}
IndexedFunction createGetter(LibraryEntity library,
ClassEntity enclosingClass, Name name, AsyncMarker asyncMarker,
{bool isStatic, bool isExternal, bool isAbstract}) {
return new KGetter(library, enclosingClass, name, asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
IndexedFunction createMethod(
LibraryEntity library,
ClassEntity enclosingClass,
Name name,
ParameterStructure parameterStructure,
AsyncMarker asyncMarker,
{bool isStatic,
bool isExternal,
bool isAbstract}) {
return new KMethod(
library, enclosingClass, name, parameterStructure, asyncMarker,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
IndexedFunction createSetter(
LibraryEntity library, ClassEntity enclosingClass, Name name,
{bool isStatic, bool isExternal, bool isAbstract}) {
return new KSetter(library, enclosingClass, name,
isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
}
IndexedField createField(
LibraryEntity library, ClassEntity enclosingClass, Name name,
{bool isStatic, bool isAssignable, bool isConst}) {
return new KField(library, enclosingClass, name,
isStatic: isStatic, isAssignable: isAssignable, isConst: isConst);
}
}
class KernelElementEnvironment extends ElementEnvironment
implements KElementEnvironment, JElementEnvironment {
final KernelToElementMapBase elementMap;
KernelElementEnvironment(this.elementMap);
@override
DartType get dynamicType => const DynamicType();
@override
LibraryEntity get mainLibrary => elementMap._mainLibrary;
@override
FunctionEntity get mainFunction => elementMap._mainFunction;
@override
Iterable<LibraryEntity> get libraries => elementMap.libraryListInternal;
@override
String getLibraryName(LibraryEntity library) {
return elementMap._getLibraryName(library);
}
@override
InterfaceType getThisType(ClassEntity cls) {
return elementMap.getThisType(cls);
}
@override
InterfaceType getRawType(ClassEntity cls) {
return elementMap._getRawType(cls);
}
@override
bool isGenericClass(ClassEntity cls) {
return getThisType(cls).typeArguments.isNotEmpty;
}
@override
bool isMixinApplication(ClassEntity cls) {
return elementMap._isMixinApplication(cls);
}
@override
bool isUnnamedMixinApplication(ClassEntity cls) {
return elementMap._isUnnamedMixinApplication(cls);
}
@override
bool isSuperMixinApplication(ClassEntity cls) {
return elementMap._isSuperMixinApplication(cls);
}
@override
ClassEntity getEffectiveMixinClass(ClassEntity cls) {
if (!isMixinApplication(cls)) return null;
do {
cls = elementMap.getAppliedMixin(cls);
} while (isMixinApplication(cls));
return cls;
}
@override
DartType getTypeVariableBound(TypeVariableEntity typeVariable) {
return elementMap.getTypeVariableBound(typeVariable);
}
@override
DartType getTypeVariableDefaultType(TypeVariableEntity typeVariable) {
return elementMap._getTypeVariableDefaultType(typeVariable);
}
@override
InterfaceType createInterfaceType(
ClassEntity cls, List<DartType> typeArguments) {
return new InterfaceType(cls, typeArguments);
}
@override
FunctionType getFunctionType(FunctionEntity function) {
return elementMap._getFunctionType(function);
}
@override
List<TypeVariableType> getFunctionTypeVariables(FunctionEntity function) {
return elementMap._getFunctionTypeVariables(function);
}
@override
DartType getFunctionAsyncOrSyncStarElementType(FunctionEntity function) {
// TODO(sra): Should be getting the DartType from the node.
DartType returnType = getFunctionType(function).returnType;
return getAsyncOrSyncStarElementType(function.asyncMarker, returnType);
}
@override
DartType getAsyncOrSyncStarElementType(
AsyncMarker asyncMarker, DartType returnType) {
switch (asyncMarker) {
case AsyncMarker.SYNC:
return returnType;
case AsyncMarker.SYNC_STAR:
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.iterableClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
case AsyncMarker.ASYNC:
if (returnType is FutureOrType) return returnType.typeArgument;
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.futureClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
case AsyncMarker.ASYNC_STAR:
if (returnType is InterfaceType) {
if (returnType.element == elementMap.commonElements.streamClass) {
return returnType.typeArguments.first;
}
}
return dynamicType;
}
assert(false, 'Unexpected marker ${asyncMarker}');
return null;
}
@override
DartType getFieldType(FieldEntity field) {
return elementMap._getFieldType(field);
}
@override
FunctionType getLocalFunctionType(covariant KLocalFunction function) {
return function.functionType;
}
@override
ConstantExpression getFieldConstantForTesting(FieldEntity field) {
return elementMap._getFieldConstantExpression(field);
}
@override
DartType getUnaliasedType(DartType type) => type;
@override
ConstructorEntity lookupConstructor(ClassEntity cls, String name,
{bool required: false}) {
ConstructorEntity constructor = elementMap.lookupConstructor(cls, name);
if (constructor == null && required) {
throw failedAt(
CURRENT_ELEMENT_SPANNABLE,
"The constructor '$name' was not found in class '${cls.name}' "
"in library ${cls.library.canonicalUri}.");
}
return constructor;
}
@override
MemberEntity lookupLocalClassMember(ClassEntity cls, String name,
{bool setter: false, bool required: false}) {
MemberEntity member =
elementMap.lookupClassMember(cls, name, setter: setter);
if (member == null && required) {
throw failedAt(CURRENT_ELEMENT_SPANNABLE,
"The member '$name' was not found in ${cls.name}.");
}
return member;
}
@override
ClassEntity getSuperClass(ClassEntity cls,
{bool skipUnnamedMixinApplications: false}) {
assert(elementMap.checkFamily(cls));
ClassEntity superclass = elementMap.getSuperType(cls)?.element;
if (skipUnnamedMixinApplications) {
while (superclass != null &&
elementMap._isUnnamedMixinApplication(superclass)) {
superclass = elementMap.getSuperType(superclass)?.element;
}
}
return superclass;
}
@override
void forEachSupertype(ClassEntity cls, void f(InterfaceType supertype)) {
elementMap._forEachSupertype(cls, f);
}
@override
void forEachMixin(ClassEntity cls, void f(ClassEntity mixin)) {
elementMap._forEachMixin(cls, f);
}
@override
void forEachLocalClassMember(ClassEntity cls, void f(MemberEntity member)) {
elementMap._forEachLocalClassMember(cls, f);
}
@override
void forEachInjectedClassMember(
ClassEntity cls, void f(MemberEntity member)) {
elementMap.forEachInjectedClassMember(cls, f);
}
@override
void forEachClassMember(
ClassEntity cls, void f(ClassEntity declarer, MemberEntity member)) {
elementMap._forEachClassMember(cls, f);
}
@override
void forEachConstructor(
ClassEntity cls, void f(ConstructorEntity constructor)) {
elementMap._forEachConstructor(cls, f);
}
@override
void forEachConstructorBody(
ClassEntity cls, void f(ConstructorBodyEntity constructor)) {
elementMap.forEachConstructorBody(cls, f);
}
@override
void forEachNestedClosure(
MemberEntity member, void f(FunctionEntity closure)) {
elementMap.forEachNestedClosure(member, f);
}
@override
void forEachLibraryMember(
LibraryEntity library, void f(MemberEntity member)) {
elementMap._forEachLibraryMember(library, f);
}
@override
MemberEntity lookupLibraryMember(LibraryEntity library, String name,
{bool setter: false, bool required: false}) {
MemberEntity member =
elementMap.lookupLibraryMember(library, name, setter: setter);
if (member == null && required) {
failedAt(CURRENT_ELEMENT_SPANNABLE,
"The member '${name}' was not found in library '${library.name}'.");
}
return member;
}
@override
ClassEntity lookupClass(LibraryEntity library, String name,
{bool required: false}) {
ClassEntity cls = elementMap.lookupClass(library, name);
if (cls == null && required) {
failedAt(CURRENT_ELEMENT_SPANNABLE,
"The class '$name' was not found in library '${library.name}'.");
}
return cls;
}
@override
void forEachClass(LibraryEntity library, void f(ClassEntity cls)) {
elementMap._forEachClass(library, f);
}
@override
LibraryEntity lookupLibrary(Uri uri, {bool required: false}) {
LibraryEntity library = elementMap.lookupLibrary(uri);
if (library == null && required) {
failedAt(CURRENT_ELEMENT_SPANNABLE, "The library '$uri' was not found.");
}
return library;
}
@override
bool isDeferredLoadLibraryGetter(MemberEntity member) {
// The front-end generates the getter of loadLibrary explicitly as code
// so there is no implicit representation based on a "loadLibrary" member.
return false;
}
@override
Iterable<ConstantValue> getLibraryMetadata(covariant IndexedLibrary library) {
assert(elementMap.checkFamily(library));
LibraryData libraryData = elementMap.libraries.getData(library);
return libraryData.getMetadata(elementMap);
}
@override
Iterable<ImportEntity> getImports(covariant IndexedLibrary library) {
assert(elementMap.checkFamily(library));
LibraryData libraryData = elementMap.libraries.getData(library);
return libraryData.getImports(elementMap);
}
@override
Iterable<ConstantValue> getClassMetadata(covariant IndexedClass cls) {
assert(elementMap.checkFamily(cls));
ClassData classData = elementMap.classes.getData(cls);
return classData.getMetadata(elementMap);
}
@override
Iterable<ConstantValue> getMemberMetadata(covariant IndexedMember member,
{bool includeParameterMetadata: false}) {
// TODO(redemption): Support includeParameterMetadata.
assert(elementMap.checkFamily(member));
MemberData memberData = elementMap.members.getData(member);
return memberData.getMetadata(elementMap);
}
@override
bool isEnumClass(ClassEntity cls) {
assert(elementMap.checkFamily(cls));
ClassData classData = elementMap.classes.getData(cls);
return classData.isEnumClass;
}
}
/// [native.BehaviorBuilder] for kernel based elements.
class KernelBehaviorBuilder extends native.BehaviorBuilder {
final ElementEnvironment elementEnvironment;
final CommonElements commonElements;
final DiagnosticReporter reporter;
final NativeBasicData nativeBasicData;
final CompilerOptions _options;
KernelBehaviorBuilder(this.elementEnvironment, this.commonElements,
this.nativeBasicData, this.reporter, this._options);
@override
bool get trustJSInteropTypeAnnotations =>
_options.trustJSInteropTypeAnnotations;
}
/// Constant environment mapping [ConstantExpression]s to [ConstantValue]s using
/// [_EvaluationEnvironment] for the evaluation.
class KernelConstantEnvironment implements ConstantEnvironment {
final KernelToElementMapBase _elementMap;
final Environment _environment;
Map<ConstantExpression, ConstantValue> _valueMap =
<ConstantExpression, ConstantValue>{};
KernelConstantEnvironment(this._elementMap, this._environment);
@override
ConstantSystem get constantSystem => JavaScriptConstantSystem.only;
ConstantValue _getConstantValue(
Spannable spannable, ConstantExpression expression,
{bool constantRequired}) {
return _valueMap.putIfAbsent(expression, () {
return expression.evaluate(
new KernelEvaluationEnvironment(_elementMap, _environment, spannable,
constantRequired: constantRequired),
constantSystem);
});
}
}
/// Evaluation environment used for computing [ConstantValue]s for
/// kernel based [ConstantExpression]s.
class KernelEvaluationEnvironment extends EvaluationEnvironmentBase {
final KernelToElementMapBase _elementMap;
final Environment _environment;
KernelEvaluationEnvironment(
this._elementMap, this._environment, Spannable spannable,
{bool constantRequired})
: super(spannable, constantRequired: constantRequired);
@override
CommonElements get commonElements => _elementMap.commonElements;
@override
DartTypes get types => _elementMap.types;
@override
DartType substByContext(DartType base, InterfaceType target) {
return _elementMap.substByContext(base, target);
}
@override
ConstantConstructor getConstructorConstant(ConstructorEntity constructor) {
return _elementMap._getConstructorConstant(constructor);
}
@override
ConstantExpression getFieldConstant(FieldEntity field) {
return _elementMap._getFieldConstantExpression(field);
}
@override
ConstantExpression getLocalConstant(Local local) {
throw new UnimplementedError("_EvaluationEnvironment.getLocalConstant");
}
@override
String readFromEnvironment(String name) {
return _environment.valueOf(name);
}
@override
DiagnosticReporter get reporter => _elementMap.reporter;
@override
bool get enableAssertions => _elementMap.options.enableUserAssertions;
}
class KClosedWorldImpl extends ClosedWorldRtiNeedMixin implements KClosedWorld {
final KernelToElementMapImpl elementMap;
final KElementEnvironment elementEnvironment;
final DartTypes dartTypes;
final KCommonElements commonElements;
final NativeData nativeData;
final InterceptorData interceptorData;
final BackendUsage backendUsage;
final NoSuchMethodData noSuchMethodData;
final Map<ClassEntity, Set<ClassEntity>> mixinUses;
final Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses;
// TODO(johnniwinther): Can this be derived from [ClassSet]s?
final Set<ClassEntity> _implementedClasses;
final Iterable<MemberEntity> liveInstanceMembers;
/// Members that are written either directly or through a setter selector.
final Iterable<MemberEntity> assignedInstanceMembers;
final KAllocatorAnalysis allocatorAnalysis;
final Iterable<ClassEntity> liveNativeClasses;
final Iterable<MemberEntity> processedMembers;
final ClassHierarchy classHierarchy;
final AnnotationsData annotationsData;
KClosedWorldImpl(this.elementMap,
{CompilerOptions options,
this.elementEnvironment,
this.dartTypes,
this.commonElements,
this.nativeData,
this.interceptorData,
this.backendUsage,
this.noSuchMethodData,
ResolutionWorldBuilder resolutionWorldBuilder,
RuntimeTypesNeedBuilder rtiNeedBuilder,
this.allocatorAnalysis,
Set<ClassEntity> implementedClasses,
this.liveNativeClasses,
this.liveInstanceMembers,
this.assignedInstanceMembers,
this.processedMembers,
this.mixinUses,
this.typesImplementedBySubclasses,
Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes,
Map<ClassEntity, ClassSet> classSets,
this.annotationsData})
: _implementedClasses = implementedClasses,
classHierarchy = new ClassHierarchyImpl(
commonElements, classHierarchyNodes, classSets) {
computeRtiNeed(resolutionWorldBuilder, rtiNeedBuilder, options);
}
/// Returns `true` if [cls] is implemented by an instantiated class.
bool isImplemented(ClassEntity cls) {
return _implementedClasses.contains(cls);
}
}
class KernelNativeMemberResolver extends NativeMemberResolverBase {
final KernelToElementMapImpl elementMap;
final NativeBasicData nativeBasicData;
final NativeDataBuilder nativeDataBuilder;
KernelNativeMemberResolver(
this.elementMap, this.nativeBasicData, this.nativeDataBuilder);
@override
KElementEnvironment get elementEnvironment => elementMap.elementEnvironment;
@override
CommonElements get commonElements => elementMap.commonElements;
@override
native.NativeBehavior computeNativeFieldStoreBehavior(
covariant KField field) {
ir.Field node = elementMap.members.getData(field).definition.node;
return elementMap.getNativeBehaviorForFieldStore(node);
}
@override
native.NativeBehavior computeNativeFieldLoadBehavior(covariant KField field,
{bool isJsInterop}) {
ir.Field node = elementMap.members.getData(field).definition.node;
return elementMap.getNativeBehaviorForFieldLoad(node,
isJsInterop: isJsInterop);
}
@override
native.NativeBehavior computeNativeMethodBehavior(
covariant KFunction function,
{bool isJsInterop}) {
ir.Member node = elementMap.members.getData(function).definition.node;
return elementMap.getNativeBehaviorForMethod(node,
isJsInterop: isJsInterop);
}
@override
bool isNativeMethod(covariant KFunction function) {
if (!native.maybeEnableNative(function.library.canonicalUri)) return false;
ir.Member node = elementMap.members.getData(function).definition.node;
return node.annotations.any((ir.Expression expression) {
return expression is ir.ConstructorInvocation &&
elementMap.getInterfaceType(expression.constructedType) ==
commonElements.externalNameType;
});
}
@override
bool isJsInteropMember(MemberEntity element) {
return nativeBasicData.isJsInteropMember(element);
}
}
class JsToFrontendMapImpl extends JsToFrontendMapBase
implements JsToFrontendMap {
final KernelToElementMapBase _backend;
JsToFrontendMapImpl(this._backend);
LibraryEntity toBackendLibrary(covariant IndexedLibrary library) {
return _backend.libraries.getEntity(library.libraryIndex);
}
ClassEntity toBackendClass(covariant IndexedClass cls) {
return _backend.classes.getEntity(cls.classIndex);
}
MemberEntity toBackendMember(covariant IndexedMember member) {
return _backend.members.getEntity(member.memberIndex);
}
TypedefEntity toBackendTypedef(covariant IndexedTypedef typedef) {
return _backend.typedefs.getEntity(typedef.typedefIndex);
}
TypeVariableEntity toBackendTypeVariable(TypeVariableEntity typeVariable) {
if (typeVariable is KLocalTypeVariable) {
failedAt(
typeVariable, "Local function type variables are not supported.");
}
IndexedTypeVariable indexedTypeVariable = typeVariable;
return _backend.typeVariables
.getEntity(indexedTypeVariable.typeVariableIndex);
}
}
class KernelClassQueries extends ClassQueries {
final KernelToElementMapImpl elementMap;
KernelClassQueries(this.elementMap);
@override
ClassEntity getDeclaration(ClassEntity cls) {
return cls;
}
@override
Iterable<InterfaceType> getSupertypes(ClassEntity cls) {
return elementMap.getOrderedTypeSet(cls).supertypes;
}
@override
ClassEntity getSuperClass(ClassEntity cls) {
return elementMap.getSuperType(cls)?.element;
}
@override
bool implementsFunction(ClassEntity cls) {
return elementMap._implementsFunction(cls);
}
@override
int getHierarchyDepth(ClassEntity cls) {
return elementMap.getHierarchyDepth(cls);
}
@override
ClassEntity getAppliedMixin(ClassEntity cls) {
return elementMap.getAppliedMixin(cls);
}
}