|  | // 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. | 
|  |  | 
|  | // @dart = 2.10 | 
|  |  | 
|  | 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/class_relation.dart'; | 
|  | import '../ir/util.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 '../native/behavior.dart'; | 
|  | import '../native/enqueue.dart'; | 
|  | import '../options.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 WorldImpactBuilder impactBuilder; | 
|  | final KernelToElementMap elementMap; | 
|  | final DiagnosticReporter reporter; | 
|  | final CompilerOptions _options; | 
|  | 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; | 
|  |  | 
|  | KernelImpactConverter( | 
|  | this.elementMap, | 
|  | this.currentMember, | 
|  | this.reporter, | 
|  | this._options, | 
|  | this._constantValuefier, | 
|  | this.staticTypeContext, | 
|  | this._impacts, | 
|  | this._nativeResolutionEnqueuer, | 
|  | this._backendUsageBuilder, | 
|  | this._customElementsResolutionAnalysis, | 
|  | this._rtiNeedBuilder, | 
|  | this._annotationsData) | 
|  | : this.impactBuilder = WorldImpactBuilderImpl(currentMember); | 
|  |  | 
|  | 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, _options); | 
|  |  | 
|  | Object _computeReceiverConstraint( | 
|  | ir.DartType receiverType, ClassRelation relation) { | 
|  | if (receiverType is ir.InterfaceType) { | 
|  | return StrongModeConstraint(commonElements, _nativeBasicData, | 
|  | elementMap.getClass(receiverType.classNode), relation); | 
|  | } else if (receiverType is ir.NullType) { | 
|  | return StrongModeConstraint( | 
|  | commonElements, | 
|  | _nativeBasicData, | 
|  | elementMap.getClass(typeEnvironment.coreTypes.deprecatedNullClass), | 
|  | relation); | 
|  | } | 
|  | 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); | 
|  | List<ConstantValue> metadata = | 
|  | elementMap.elementEnvironment.getMemberMetadata(member); | 
|  | 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 registerConstructorNode(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); | 
|  | List<ConstantValue> metadata = | 
|  | elementMap.elementEnvironment.getMemberMetadata(member); | 
|  | 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 registerProcedureNode(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); | 
|  | List<ConstantValue> metadata = | 
|  | elementMap.elementEnvironment.getMemberMetadata(member); | 
|  | 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(int value) { | 
|  | registerBackendImpact(_impacts.intLiteral); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerDoubleLiteral(double value) { | 
|  | registerBackendImpact(_impacts.doubleLiteral); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerBoolLiteral(bool value) { | 
|  | registerBackendImpact(_impacts.boolLiteral); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerStringLiteral(String value) { | 
|  | registerBackendImpact(_impacts.stringLiteral); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerSymbolLiteral(String value) { | 
|  | registerBackendImpact(_impacts.constSymbol); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerNullLiteral() { | 
|  | registerBackendImpact(_impacts.nullLiteral); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerListLiteral(ir.DartType elementType, | 
|  | {bool isConst, 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, | 
|  | {bool isConst, 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, | 
|  | {bool isConst, 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 registerNew( | 
|  | ir.Member target, | 
|  | ir.InterfaceType type, | 
|  | int positionalArguments, | 
|  | List<String> namedArguments, | 
|  | List<ir.DartType> typeArguments, | 
|  | ir.LibraryDependency import, | 
|  | {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.getDartType(type).withoutNullability, deferredImport) | 
|  | : StaticUse.typedConstructorInvoke(constructor, callStructure, | 
|  | elementMap.getDartType(type).withoutNullability, 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 registerStaticInvocationNode(ir.StaticInvocation node) { | 
|  | switch (elementMap.getForeignKind(node)) { | 
|  | case ForeignKind.JS: | 
|  | registerNativeImpact(elementMap.getNativeBehaviorForJsCall(node)); | 
|  | break; | 
|  | case ForeignKind.JS_BUILTIN: | 
|  | registerNativeImpact( | 
|  | elementMap.getNativeBehaviorForJsBuiltinCall(node)); | 
|  | break; | 
|  | case ForeignKind.JS_EMBEDDED_GLOBAL: | 
|  | registerNativeImpact( | 
|  | elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(node)); | 
|  | break; | 
|  | case ForeignKind.JS_INTERCEPTOR_CONSTANT: | 
|  | 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 = dartTypes.eraseLegacy(typeArguments.first); | 
|  |  | 
|  | 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 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) { | 
|  | if (target != null) { | 
|  | FunctionEntity method = elementMap.getMember(target); | 
|  | List<DartType> dartTypeArguments = _getTypeArguments(typeArguments); | 
|  | impactBuilder.registerStaticUse(StaticUse.superInvoke( | 
|  | method, | 
|  | CallStructure(positionalArguments + namedArguments.length, | 
|  | namedArguments, typeArguments.length), | 
|  | dartTypeArguments)); | 
|  | } else { | 
|  | // TODO(johnniwinther): Remove this when the CFE checks for missing | 
|  | //  concrete super targets. | 
|  | impactBuilder.registerStaticUse(StaticUse.superInvoke( | 
|  | elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), | 
|  | CallStructure.ONE_ARG)); | 
|  | registerBackendImpact(_impacts.superNoSuchMethod); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerSuperGet(ir.Member target) { | 
|  | if (target != null) { | 
|  | MemberEntity member = elementMap.getMember(target); | 
|  | if (member.isFunction) { | 
|  | impactBuilder.registerStaticUse(StaticUse.superTearOff(member)); | 
|  | } else { | 
|  | impactBuilder.registerStaticUse(StaticUse.superGet(member)); | 
|  | } | 
|  | } else { | 
|  | // TODO(johnniwinther): Remove this when the CFE checks for missing | 
|  | //  concrete super targets. | 
|  | impactBuilder.registerStaticUse(StaticUse.superInvoke( | 
|  | elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), | 
|  | CallStructure.ONE_ARG)); | 
|  | registerBackendImpact(_impacts.superNoSuchMethod); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerSuperSet(ir.Member target) { | 
|  | if (target != null) { | 
|  | MemberEntity member = elementMap.getMember(target); | 
|  | if (member.isField) { | 
|  | impactBuilder.registerStaticUse(StaticUse.superFieldSet(member)); | 
|  | } else { | 
|  | impactBuilder.registerStaticUse(StaticUse.superSetterSet(member)); | 
|  | } | 
|  | } else { | 
|  | // TODO(johnniwinther): Remove this when the CFE checks for missing | 
|  | //  concrete super targets. | 
|  | impactBuilder.registerStaticUse(StaticUse.superInvoke( | 
|  | elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), | 
|  | CallStructure.ONE_ARG)); | 
|  | registerBackendImpact(_impacts.superNoSuchMethod); | 
|  | } | 
|  | } | 
|  |  | 
|  | @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, | 
|  | ClassRelation relation, | 
|  | 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, relation), 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, ClassRelation.subtype), | 
|  | dartTypeArguments)); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerInstanceInvocation( | 
|  | ir.DartType receiverType, | 
|  | ClassRelation relation, | 
|  | 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, relation), | 
|  | dartTypeArguments)); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerDynamicGet( | 
|  | ir.DartType receiverType, ClassRelation relation, ir.Name name) { | 
|  | impactBuilder.registerDynamicUse(DynamicUse( | 
|  | Selector.getter(elementMap.getName(name)), | 
|  | _computeReceiverConstraint(receiverType, relation), | 
|  | const <DartType>[])); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerInstanceGet( | 
|  | ir.DartType receiverType, ClassRelation relation, ir.Member target) { | 
|  | impactBuilder.registerDynamicUse(DynamicUse( | 
|  | Selector.getter(elementMap.getName(target.name)), | 
|  | _computeReceiverConstraint(receiverType, relation), | 
|  | const <DartType>[])); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerDynamicSet( | 
|  | ir.DartType receiverType, ClassRelation relation, ir.Name name) { | 
|  | impactBuilder.registerDynamicUse(DynamicUse( | 
|  | Selector.setter(elementMap.getName(name)), | 
|  | _computeReceiverConstraint(receiverType, relation), | 
|  | const <DartType>[])); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerInstanceSet( | 
|  | ir.DartType receiverType, ClassRelation relation, ir.Member target) { | 
|  | impactBuilder.registerDynamicUse(DynamicUse( | 
|  | Selector.setter(elementMap.getName(target.name)), | 
|  | _computeReceiverConstraint(receiverType, relation), | 
|  | 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({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, | 
|  | 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(ir.TreeNode 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, | 
|  | ClassRelation iteratorClassRelation) { | 
|  | Object receiverConstraint = | 
|  | _computeReceiverConstraint(iteratorType, iteratorClassRelation); | 
|  | 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, | 
|  | ClassRelation iteratorClassRelation) { | 
|  | Object receiverConstraint = | 
|  | _computeReceiverConstraint(iteratorType, iteratorClassRelation); | 
|  | 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.ONE_ARG)); | 
|  | registerBackendImpact(_impacts.loadLibrary); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void registerSwitchStatementNode(ir.SwitchStatement node) { | 
|  | bool overridesEquals(InterfaceType type) { | 
|  | if (type == commonElements.symbolImplementationType) { | 
|  | // Treat symbol constants as if Symbol doesn't override `==`. | 
|  | return false; | 
|  | } | 
|  | ClassEntity cls = type.element; | 
|  | while (cls != null) { | 
|  | MemberEntity member = | 
|  | elementMap.elementEnvironment.lookupClassMember(cls, '=='); | 
|  | if (member.isAbstract) { | 
|  | cls = elementMap.elementEnvironment.getSuperClass(cls); | 
|  | } else { | 
|  | return member.enclosingClass != commonElements.objectClass && | 
|  | member.enclosingClass != commonElements.jsInterceptorClass; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | for (ir.SwitchCase switchCase in node.cases) { | 
|  | for (ir.Expression expression in switchCase.expressions) { | 
|  | ConstantValue value = | 
|  | elementMap.getConstantValue(staticTypeContext, expression); | 
|  | DartType type = value.getType(elementMap.commonElements); | 
|  | if (type == commonElements.doubleType) { | 
|  | reporter.reportErrorMessage( | 
|  | computeSourceSpanFromTreeNode(expression), | 
|  | MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, | 
|  | {'type': "double"}); | 
|  | } else if (type == commonElements.functionType) { | 
|  | reporter.reportErrorMessage(computeSourceSpanFromTreeNode(node), | 
|  | MessageKind.SWITCH_CASE_FORBIDDEN, {'type': "Function"}); | 
|  | } else if (value is ObjectConstantValue && | 
|  | type != commonElements.typeLiteralType && | 
|  | overridesEquals(type)) { | 
|  | reporter.reportErrorMessage( | 
|  | computeSourceSpanFromTreeNode(expression), | 
|  | MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, | 
|  | {'type': typeToString(type)}); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Converts a [ImpactData] object based on kernel to the corresponding | 
|  | /// [WorldImpact] based on the K model. | 
|  | WorldImpact convert(ImpactData impactData) { | 
|  | impactData.apply(this); | 
|  | return impactBuilder; | 
|  | } | 
|  | } |