blob: d0aa02a02463dd8664645b9198b4f10185a08211 [file] [log] [blame]
// Copyright (c) 2016, 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.
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import '../common.dart';
import '../common/names.dart';
import '../common/elements.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../ir/constants.dart';
import '../ir/impact.dart';
import '../ir/impact_data.dart';
import '../ir/runtime_type_analysis.dart';
import '../ir/visitors.dart';
import '../js_backend/annotations.dart';
import '../js_backend/backend_impact.dart';
import '../js_backend/backend_usage.dart';
import '../js_backend/custom_elements_analysis.dart';
import '../js_backend/native_data.dart';
import '../js_backend/runtime_types_resolution.dart';
import '../js_model/elements.dart';
import '../native/behavior.dart';
import '../native/enqueue.dart';
import '../universe/call_structure.dart';
import '../universe/feature.dart';
import '../universe/selector.dart';
import '../universe/use.dart';
import '../universe/world_builder.dart';
import '../universe/world_impact.dart';
import 'element_map.dart';
/// [ImpactRegistry] that converts kernel based impact data to world impact
/// object based on the K model.
class KernelImpactConverter implements ImpactRegistry {
final KernelToElementMap elementMap;
final DiagnosticReporter reporter;
final MemberEntity currentMember;
final ConstantValuefier _constantValuefier;
final ir.StaticTypeContext staticTypeContext;
final BackendImpacts _impacts;
final NativeResolutionEnqueuer _nativeResolutionEnqueuer;
final BackendUsageBuilder _backendUsageBuilder;
final CustomElementsResolutionAnalysis _customElementsResolutionAnalysis;
final RuntimeTypesNeedBuilder _rtiNeedBuilder;
final AnnotationsData _annotationsData;
WorldImpactBuilder? _impactBuilder;
WorldImpactBuilder get impactBuilder => _impactBuilder!;
KernelImpactConverter(
this.elementMap,
this.currentMember,
this.reporter,
this._constantValuefier,
this.staticTypeContext,
this._impacts,
this._nativeResolutionEnqueuer,
this._backendUsageBuilder,
this._customElementsResolutionAnalysis,
this._rtiNeedBuilder,
this._annotationsData,
);
ir.TypeEnvironment get typeEnvironment => elementMap.typeEnvironment;
CommonElements get commonElements => elementMap.commonElements;
NativeBasicData get _nativeBasicData => elementMap.nativeBasicData;
ElementEnvironment get elementEnvironment => elementMap.elementEnvironment;
DartTypes get dartTypes => commonElements.dartTypes;
String typeToString(DartType type) => type.toStructuredText(dartTypes);
Object? _computeReceiverConstraint(ir.DartType receiverType) {
if (receiverType is ir.InterfaceType) {
return defaultReceiverClass(
commonElements,
_nativeBasicData,
elementMap.getClass(receiverType.classNode),
);
} else if (receiverType is ir.NullType) {
return elementMap.getClass(typeEnvironment.coreTypes.deprecatedNullClass);
}
return null;
}
void registerBackendImpact(BackendImpact impact) {
impact.registerImpact(impactBuilder, elementEnvironment);
_backendUsageBuilder.processBackendImpact(impact);
}
void registerNativeImpact(NativeBehavior behavior) {
_nativeResolutionEnqueuer.registerNativeBehavior(
impactBuilder,
behavior,
impactBuilder,
);
}
// TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType].
void onIsCheck(DartType type) {
registerBackendImpact(_impacts.typeCheck);
var typeWithoutNullability = type.withoutNullability;
if (!dartTypes.treatAsRawType(typeWithoutNullability) ||
typeWithoutNullability.containsTypeVariables ||
typeWithoutNullability is FunctionType) {
registerBackendImpact(_impacts.genericTypeCheck);
if (typeWithoutNullability is TypeVariableType) {
registerBackendImpact(_impacts.typeVariableTypeCheck);
}
}
if (typeWithoutNullability is FunctionType) {
registerBackendImpact(_impacts.functionTypeCheck);
}
if (typeWithoutNullability is InterfaceType &&
_nativeBasicData.isNativeClass(typeWithoutNullability.element)) {
registerBackendImpact(_impacts.nativeTypeCheck);
}
if (typeWithoutNullability is FutureOrType) {
registerBackendImpact(_impacts.futureOrTypeCheck);
}
}
@override
void registerParameterCheck(ir.DartType irType) {
DartType type = elementMap.getDartType(irType);
if (type is! DynamicType) {
impactBuilder.registerTypeUse(TypeUse.parameterCheck(type));
if (_annotationsData.getParameterCheckPolicy(currentMember).isEmitted) {
onIsCheck(type);
}
}
}
List<DartType>? _getTypeArguments(List<ir.DartType> types) {
if (types.isEmpty) return null;
return types.map(elementMap.getDartType).toList();
}
@override
void registerLazyField() {
registerBackendImpact(_impacts.lazyField);
}
@override
void registerFieldNode(ir.Field field) {
if (field.isInstanceMember &&
_nativeBasicData.isNativeClass(
elementMap.getClass(field.enclosingClass!),
)) {
MemberEntity member = elementMap.getMember(field);
// TODO(johnniwinther): NativeDataBuilder already has the native behavior
// at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
Iterable<ConstantValue> metadata = elementMap.elementEnvironment
.getMemberMetadata(member as JMember);
Iterable<String> createsAnnotations = getCreatesAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
Iterable<String> returnsAnnotations = getReturnsAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
registerNativeImpact(
elementMap.getNativeBehaviorForFieldLoad(
field,
createsAnnotations,
returnsAnnotations,
isJsInterop: isJsInterop,
),
);
registerNativeImpact(elementMap.getNativeBehaviorForFieldStore(field));
}
}
@override
void registerExternalConstructorNode(ir.Constructor constructor) {
MemberEntity member = elementMap.getMember(constructor);
if (constructor.isExternal && !commonElements.isForeignHelper(member)) {
// TODO(johnniwinther): NativeDataBuilder already has the native behavior
// at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
Iterable<ConstantValue> metadata = elementMap.elementEnvironment
.getMemberMetadata(member as JMember);
Iterable<String> createsAnnotations = getCreatesAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
Iterable<String> returnsAnnotations = getReturnsAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
registerNativeImpact(
elementMap.getNativeBehaviorForMethod(
constructor,
createsAnnotations,
returnsAnnotations,
isJsInterop: isJsInterop,
),
);
}
}
@override
void registerSyncStar(ir.DartType elementType) {
registerBackendImpact(_impacts.syncStarBody);
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(
commonElements.syncStarIterableFactory,
CallStructure.unnamed(1, 1),
<DartType>[elementMap.getDartType(elementType)],
),
);
}
@override
void registerAsync(ir.DartType elementType) {
registerBackendImpact(_impacts.asyncBody);
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(
commonElements.asyncAwaitCompleterFactory,
CallStructure.unnamed(0, 1),
<DartType>[elementMap.getDartType(elementType)],
),
);
}
@override
void registerAsyncStar(ir.DartType elementType) {
registerBackendImpact(_impacts.asyncStarBody);
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(
commonElements.asyncStarStreamControllerFactory,
CallStructure.unnamed(1, 1),
<DartType>[elementMap.getDartType(elementType)],
),
);
}
@override
void registerExternalProcedureNode(ir.Procedure procedure) {
MemberEntity member = elementMap.getMember(procedure);
if (procedure.isExternal && !commonElements.isForeignHelper(member)) {
// TODO(johnniwinther): NativeDataBuilder already has the native behavior
// at this point. Use that instead.
bool isJsInterop = _nativeBasicData.isJsInteropMember(member);
Iterable<ConstantValue> metadata = elementMap.elementEnvironment
.getMemberMetadata(member as JMember);
Iterable<String> createsAnnotations = getCreatesAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
Iterable<String> returnsAnnotations = getReturnsAnnotations(
dartTypes,
reporter,
commonElements,
metadata,
);
registerNativeImpact(
elementMap.getNativeBehaviorForMethod(
procedure,
createsAnnotations,
returnsAnnotations,
isJsInterop: isJsInterop,
),
);
}
}
@override
void registerIntLiteral() {
registerBackendImpact(_impacts.intLiteral);
}
@override
void registerDoubleLiteral() {
registerBackendImpact(_impacts.doubleLiteral);
}
@override
void registerBoolLiteral() {
registerBackendImpact(_impacts.boolLiteral);
}
@override
void registerStringLiteral() {
registerBackendImpact(_impacts.stringLiteral);
}
@override
void registerSymbolLiteral() {
registerBackendImpact(_impacts.constSymbol);
}
@override
void registerNullLiteral() {
registerBackendImpact(_impacts.nullLiteral);
}
@override
void registerListLiteral(
ir.DartType elementType, {
required bool isConst,
required bool isEmpty,
}) {
// TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when
// factory constructors are registered directly.
impactBuilder.registerTypeUse(
TypeUse.instantiation(
commonElements.listType(elementMap.getDartType(elementType)),
),
);
}
@override
void registerSetLiteral(
ir.DartType elementType, {
required bool isConst,
required bool isEmpty,
}) {
// TODO(johnniwinther): Use the [isEmpty] property when factory
// constructors are registered directly.
if (isConst) {
registerBackendImpact(_impacts.constantSetLiteral);
} else {
impactBuilder.registerTypeUse(
TypeUse.instantiation(
commonElements.setType(elementMap.getDartType(elementType)),
),
);
}
}
@override
void registerMapLiteral(
ir.DartType keyType,
ir.DartType valueType, {
required bool isConst,
required bool isEmpty,
}) {
// TODO(johnniwinther): Use the [isEmpty] property when factory
// constructors are registered directly.
if (isConst) {
registerBackendImpact(_impacts.constantMapLiteral);
} else {
impactBuilder.registerTypeUse(
TypeUse.instantiation(
commonElements.mapType(
elementMap.getDartType(keyType),
elementMap.getDartType(valueType),
),
),
);
}
}
@override
void registerRecordLiteral(
ir.RecordType recordType, {
required bool isConst,
}) {
registerBackendImpact(_impacts.recordInstantiation);
final type = elementMap.getDartType(recordType) as RecordType;
impactBuilder.registerTypeUse(TypeUse.recordInstantiation(type));
}
@override
void registerNew(
ir.Member target,
ir.InterfaceType type,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import, {
required bool isConst,
}) {
ConstructorEntity constructor = elementMap.getConstructor(target);
CallStructure callStructure = CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
);
ImportEntity? deferredImport = elementMap.getImport(import);
impactBuilder.registerStaticUse(
isConst
? StaticUse.constConstructorInvoke(
constructor,
callStructure,
elementMap.getInterfaceType(type),
deferredImport,
)
: StaticUse.typedConstructorInvoke(
constructor,
callStructure,
elementMap.getInterfaceType(type),
deferredImport,
),
);
if (type.typeArguments.any((ir.DartType type) => type is! ir.DynamicType)) {
registerBackendImpact(_impacts.typeVariableBoundCheck);
}
if (target.isExternal &&
constructor.isFromEnvironmentConstructor &&
!isConst) {
registerBackendImpact(_impacts.throwUnsupportedError);
// We need to register the external constructor as live below, so don't
// return here.
}
}
@override
void registerConstInstantiation(
ir.Class cls,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import,
) {
ImportEntity? deferredImport = elementMap.getImport(import);
InterfaceType type = elementMap.createInterfaceType(cls, typeArguments);
impactBuilder.registerTypeUse(
TypeUse.constInstantiation(type, deferredImport),
);
}
@override
void registerConstSymbolConstructorInvocationNode() {
registerBackendImpact(_impacts.constSymbol);
}
@override
void registerSuperInitializer(
ir.Constructor source,
ir.Constructor target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
// TODO(johnniwinther): Maybe rewrite `node.target` to point to a
// synthesized unnamed mixin constructor when needed. This would require us
// to consider impact building a required pre-step for inference and
// ssa-building.
ConstructorEntity constructor = elementMap.getSuperConstructor(
source,
target,
);
impactBuilder.registerStaticUse(
StaticUse.superConstructorInvoke(
constructor,
CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
),
),
);
}
@override
void registerStaticInvocation(
ir.Procedure procedure,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import,
) {
FunctionEntity target = elementMap.getMethod(procedure);
CallStructure callStructure = CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
);
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
if (commonElements.isExtractTypeArguments(target)) {
_handleExtractTypeArguments(target, dartTypeArguments!, callStructure);
return;
} else {
ImportEntity? deferredImport = elementMap.getImport(import);
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(
target,
callStructure,
dartTypeArguments,
deferredImport,
),
);
}
}
@override
void registerForeignStaticInvocationNode(ir.StaticInvocation node) {
switch (elementMap.getForeignKind(node)) {
case ForeignKind.js:
registerNativeImpact(elementMap.getNativeBehaviorForJsCall(node));
break;
case ForeignKind.jsBuiltin:
registerNativeImpact(
elementMap.getNativeBehaviorForJsBuiltinCall(node),
);
break;
case ForeignKind.jsEmbeddedGlobal:
registerNativeImpact(
elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(node),
);
break;
case ForeignKind.jsInterceptorConstant:
InterfaceType? type = elementMap.getInterfaceTypeForJsInterceptorCall(
node,
);
if (type != null) {
impactBuilder.registerTypeUse(TypeUse.instantiation(type));
}
break;
case ForeignKind.none:
break;
}
}
void _handleExtractTypeArguments(
FunctionEntity target,
List<DartType> typeArguments,
CallStructure callStructure,
) {
// extractTypeArguments<Map>(obj, fn) has additional impacts:
//
// 1. All classes implementing Map need to carry type arguments (similar
// to checking `o is Map<K, V>`).
//
// 2. There is an invocation of fn with some number of type arguments.
//
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(target, callStructure, typeArguments),
);
if (typeArguments.length != 1) return;
DartType matchedType = typeArguments.single;
if (matchedType is! InterfaceType) return;
InterfaceType interfaceType = matchedType;
ClassEntity cls = interfaceType.element;
InterfaceType thisType = elementMap.elementEnvironment.getThisType(cls);
_registerIsCheckInternal(thisType);
Selector selector = Selector.callClosure(
0,
const <String>[],
thisType.typeArguments.length,
);
impactBuilder.registerDynamicUse(
DynamicUse(selector, null, thisType.typeArguments),
);
}
@override
void registerStaticTearOff(
ir.Procedure procedure,
ir.LibraryDependency? import,
) {
impactBuilder.registerStaticUse(
StaticUse.staticTearOff(
elementMap.getMethod(procedure),
elementMap.getImport(import),
),
);
}
@override
void registerWeakStaticTearOff(
ir.Procedure procedure,
ir.LibraryDependency? import,
) {
impactBuilder.registerStaticUse(
StaticUse.weakStaticTearOff(
elementMap.getMethod(procedure),
elementMap.getImport(import),
),
);
}
@override
void registerStaticGet(ir.Member member, ir.LibraryDependency? import) {
impactBuilder.registerStaticUse(
StaticUse.staticGet(
elementMap.getMember(member),
elementMap.getImport(import),
),
);
}
@override
void registerStaticSet(ir.Member member, ir.LibraryDependency? import) {
impactBuilder.registerStaticUse(
StaticUse.staticSet(
elementMap.getMember(member),
elementMap.getImport(import),
),
);
}
@override
void registerSuperInvocation(
ir.Member target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
FunctionEntity method = elementMap.getMember(target) as FunctionEntity;
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
impactBuilder.registerStaticUse(
StaticUse.superInvoke(
method,
CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
),
dartTypeArguments,
),
);
}
@override
void registerSuperGet(ir.Member target) {
MemberEntity member = elementMap.getMember(target);
if (member.isFunction) {
impactBuilder.registerStaticUse(
StaticUse.superTearOff(member as FunctionEntity),
);
} else {
impactBuilder.registerStaticUse(StaticUse.superGet(member));
}
}
@override
void registerSuperSet(ir.Member target) {
MemberEntity member = elementMap.getMember(target);
if (member is FieldEntity) {
impactBuilder.registerStaticUse(StaticUse.superFieldSet(member));
} else {
impactBuilder.registerStaticUse(
StaticUse.superSetterSet(member as FunctionEntity),
);
}
}
@override
void registerLocalFunctionInvocation(
ir.FunctionDeclaration localFunction,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
CallStructure callStructure = CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
);
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
// Invocation of a local function. No need for dynamic use, but
// we need to track the type arguments.
impactBuilder.registerStaticUse(
StaticUse.closureCall(
elementMap.getLocalFunction(localFunction),
callStructure,
dartTypeArguments,
),
);
// TODO(johnniwinther): Yet, alas, we need the dynamic use for now. Remove
// this when kernel adds an `isFunctionCall` flag to
// [ir.MethodInvocation].
impactBuilder.registerDynamicUse(
DynamicUse(callStructure.callSelector, null, dartTypeArguments),
);
}
@override
void registerDynamicInvocation(
ir.DartType receiverType,
ir.Name name,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
Selector selector = elementMap.getInvocationSelector(
name,
positionalArguments,
namedArguments,
typeArguments.length,
);
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
impactBuilder.registerDynamicUse(
DynamicUse(
selector,
_computeReceiverConstraint(receiverType),
dartTypeArguments,
),
);
}
@override
void registerFunctionInvocation(
ir.DartType receiverType,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
CallStructure callStructure = CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
);
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
impactBuilder.registerDynamicUse(
DynamicUse(
callStructure.callSelector,
_computeReceiverConstraint(receiverType),
dartTypeArguments,
),
);
}
@override
void registerInstanceInvocation(
ir.DartType receiverType,
ir.Member target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments);
impactBuilder.registerDynamicUse(
DynamicUse(
elementMap.getInvocationSelector(
target.name,
positionalArguments,
namedArguments,
typeArguments.length,
),
_computeReceiverConstraint(receiverType),
dartTypeArguments,
),
);
}
@override
void registerDynamicGet(ir.DartType receiverType, ir.Name name) {
impactBuilder.registerDynamicUse(
DynamicUse(
Selector.getter(elementMap.getName(name)),
_computeReceiverConstraint(receiverType),
const <DartType>[],
),
);
}
@override
void registerInstanceGet(ir.DartType receiverType, ir.Member target) {
impactBuilder.registerDynamicUse(
DynamicUse(
Selector.getter(elementMap.getName(target.name)),
_computeReceiverConstraint(receiverType),
const <DartType>[],
),
);
}
@override
void registerDynamicSet(ir.DartType receiverType, ir.Name name) {
impactBuilder.registerDynamicUse(
DynamicUse(
Selector.setter(elementMap.getName(name)),
_computeReceiverConstraint(receiverType),
const <DartType>[],
),
);
}
@override
void registerInstanceSet(ir.DartType receiverType, ir.Member target) {
impactBuilder.registerDynamicUse(
DynamicUse(
Selector.setter(elementMap.getName(target.name)),
_computeReceiverConstraint(receiverType),
const <DartType>[],
),
);
}
@override
void registerRuntimeTypeUse(
RuntimeTypeUseKind kind,
ir.DartType receiverType,
ir.DartType? argumentType,
) {
DartType receiverDartType = elementMap.getDartType(receiverType);
DartType? argumentDartType =
argumentType == null ? null : elementMap.getDartType(argumentType);
// Enable runtime type support if we discover a getter called
// runtimeType. We have to enable runtime type before hitting the
// codegen, so that constructors know whether they need to generate code
// for runtime type.
_backendUsageBuilder.registerRuntimeTypeUse(
RuntimeTypeUse(kind, receiverDartType, argumentDartType),
);
}
@override
void registerAssert({required bool withMessage}) {
registerBackendImpact(
withMessage ? _impacts.assertWithMessage : _impacts.assertWithoutMessage,
);
}
@override
void registerGenericInstantiation(
ir.FunctionType expressionType,
List<ir.DartType> typeArguments,
) {
// TODO(johnniwinther): Track which arities are used in instantiation.
final instantiation = GenericInstantiation(
elementMap.getDartType(expressionType).withoutNullability as FunctionType,
typeArguments.map(elementMap.getDartType).toList(),
);
registerBackendImpact(
_impacts.getGenericInstantiation(instantiation.typeArguments.length),
);
_rtiNeedBuilder.registerGenericInstantiation(instantiation);
}
@override
void registerStringConcatenation() {
registerBackendImpact(_impacts.stringInterpolation);
registerBackendImpact(_impacts.stringJuxtaposition);
}
@override
void registerLocalFunction(covariant ir.LocalFunction node) {
Local function = elementMap.getLocalFunction(node);
impactBuilder.registerStaticUse(StaticUse.closure(function));
registerBackendImpact(_impacts.closure);
registerBackendImpact(_impacts.computeSignature);
}
@override
void registerLocalWithoutInitializer() {
impactBuilder.registerTypeUse(
TypeUse.instantiation(commonElements.nullType),
);
registerBackendImpact(_impacts.nullLiteral);
}
void _registerIsCheckInternal(DartType type) {
impactBuilder.registerTypeUse(TypeUse.isCheck(type));
onIsCheck(type);
}
@override
void registerIsCheck(ir.DartType irType) {
_registerIsCheckInternal(elementMap.getDartType(irType));
}
@override
void registerImplicitCast(ir.DartType irType) {
DartType type = elementMap.getDartType(irType);
impactBuilder.registerTypeUse(TypeUse.implicitCast(type));
if (_annotationsData
.getImplicitDowncastCheckPolicy(currentMember)
.isEmitted) {
onIsCheck(type);
}
}
@override
void registerAsCast(ir.DartType irType) {
DartType type = elementMap.getDartType(irType);
impactBuilder.registerTypeUse(TypeUse.asCast(type));
if (_annotationsData.getExplicitCastCheckPolicy(currentMember).isEmitted) {
onIsCheck(type);
registerBackendImpact(_impacts.asCheck);
}
}
@override
void registerThrow() {
registerBackendImpact(_impacts.throwExpression);
}
@override
void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType) {
Object? receiverConstraint = _computeReceiverConstraint(iteratorType);
registerBackendImpact(_impacts.syncForIn);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.iterator, receiverConstraint, const []),
);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.current, receiverConstraint, const []),
);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.moveNext, receiverConstraint, const []),
);
}
@override
void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType) {
Object? receiverConstraint = _computeReceiverConstraint(iteratorType);
registerBackendImpact(_impacts.asyncForIn);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.cancel, receiverConstraint, const []),
);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.current, receiverConstraint, const []),
);
impactBuilder.registerDynamicUse(
DynamicUse(Selectors.moveNext, receiverConstraint, const []),
);
}
@override
void registerCatch() {
registerBackendImpact(_impacts.catchStatement);
}
@override
void registerStackTrace() {
registerBackendImpact(_impacts.stackTraceInCatch);
}
@override
void registerCatchType(ir.DartType irType) {
DartType type = elementMap.getDartType(irType);
impactBuilder.registerTypeUse(TypeUse.catchType(type));
onIsCheck(type);
}
@override
void registerTypeLiteral(ir.DartType irType, ir.LibraryDependency? import) {
ImportEntity? deferredImport = elementMap.getImport(import);
DartType type = elementMap.getDartType(irType);
impactBuilder.registerTypeUse(TypeUse.typeLiteral(type, deferredImport));
_customElementsResolutionAnalysis.registerTypeLiteral(type);
type.forEachTypeVariable((TypeVariableType variable) {
_rtiNeedBuilder.registerTypeVariableLiteral(variable);
registerBackendImpact(_impacts.typeVariableExpression);
});
impactBuilder.registerTypeUse(
TypeUse.instantiation(commonElements.typeType),
);
registerBackendImpact(_impacts.typeLiteral);
}
@override
void registerFieldInitialization(ir.Field node) {
impactBuilder.registerStaticUse(
StaticUse.fieldInit(elementMap.getField(node)),
);
}
@override
void registerFieldConstantInitialization(
ir.Field node,
ConstantReference constant,
) {
impactBuilder.registerStaticUse(
StaticUse.fieldConstantInit(
elementMap.getField(node),
_constantValuefier.visitConstant(constant.constant),
),
);
}
@override
void registerRedirectingInitializer(
ir.Constructor constructor,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
) {
ConstructorEntity target = elementMap.getConstructor(constructor);
impactBuilder.registerStaticUse(
StaticUse.superConstructorInvoke(
target,
CallStructure(
positionalArguments + namedArguments.length,
namedArguments,
typeArguments.length,
),
),
);
}
@override
void registerLoadLibrary() {
impactBuilder.registerStaticUse(
StaticUse.staticInvoke(
commonElements.loadDeferredLibrary,
CallStructure.oneArg,
),
);
registerBackendImpact(_impacts.loadLibrary);
}
/// Converts a [ImpactData] object based on kernel to the corresponding
/// [WorldImpact] based on the K model.
WorldImpact convert(ImpactData impactData) {
final oldBuilder = _impactBuilder;
final newBuilder = _impactBuilder = WorldImpactBuilderImpl(currentMember);
impactData.apply(this);
_impactBuilder = oldBuilder;
return newBuilder;
}
@override
void registerConditionalImpact(ConditionalImpactData impact) {
final conditionalUse = ConditionalUse.withReplacement(
impact: convert(impact.impactData),
replacementImpact: convert(impact.replacementImpactData),
originalConditions:
impact.originalConditions.map(elementMap.getMember).toList(),
original: impact.original,
replacement: impact.replacement,
);
impactBuilder.registerConditionalUse(conditionalUse);
}
}