| // 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/resolution.dart'; |
| import '../common_elements.dart'; |
| import '../constants/expressions.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/scope.dart'; |
| import '../ir/static_type.dart'; |
| import '../ir/util.dart'; |
| import '../ir/visitors.dart'; |
| import '../js_backend/annotations.dart'; |
| import '../js_backend/native_data.dart'; |
| import '../native/behavior.dart'; |
| import '../options.dart'; |
| import '../resolution/registry.dart' show ResolutionWorldImpactBuilder; |
| import '../universe/call_structure.dart'; |
| import '../universe/feature.dart'; |
| import '../universe/selector.dart'; |
| import '../universe/use.dart'; |
| import '../universe/world_builder.dart'; |
| import 'element_map.dart'; |
| |
| /// Visitor that computes the world impact of a member. |
| class KernelImpactBuilder extends ImpactBuilderBase |
| with KernelImpactRegistryMixin { |
| @override |
| final ResolutionWorldImpactBuilder impactBuilder; |
| @override |
| final KernelToElementMap elementMap; |
| @override |
| final DiagnosticReporter reporter; |
| @override |
| final CompilerOptions _options; |
| @override |
| final MemberEntity currentMember; |
| final Set<PragmaAnnotation> _annotations; |
| @override |
| final ConstantValuefier _constantValuefier; |
| |
| KernelImpactBuilder( |
| this.elementMap, |
| this.currentMember, |
| this.reporter, |
| this._options, |
| VariableScopeModel variableScopeModel, |
| this._annotations, |
| this._constantValuefier) |
| : this.impactBuilder = |
| new ResolutionWorldImpactBuilder('${currentMember}'), |
| super(elementMap.typeEnvironment, elementMap.classHierarchy, |
| variableScopeModel); |
| |
| @override |
| CommonElements get commonElements => elementMap.commonElements; |
| |
| @override |
| NativeBasicData get _nativeBasicData => elementMap.nativeBasicData; |
| |
| @override |
| bool get useAsserts => _options.enableUserAssertions; |
| |
| @override |
| bool get inferEffectivelyFinalVariableTypes => |
| !_annotations.contains(PragmaAnnotation.disableFinal); |
| } |
| |
| /// Converts a [ImpactData] object based on kernel to the corresponding |
| /// [ResolutionImpact] based on the K model. |
| class KernelImpactConverter extends KernelImpactRegistryMixin { |
| @override |
| final ResolutionWorldImpactBuilder impactBuilder; |
| @override |
| final KernelToElementMap elementMap; |
| @override |
| final DiagnosticReporter reporter; |
| @override |
| final CompilerOptions _options; |
| @override |
| final MemberEntity currentMember; |
| @override |
| final ConstantValuefier _constantValuefier; |
| |
| KernelImpactConverter(this.elementMap, this.currentMember, this.reporter, |
| this._options, this._constantValuefier) |
| : this.impactBuilder = |
| new ResolutionWorldImpactBuilder('${currentMember}'); |
| |
| @override |
| ir.TypeEnvironment get typeEnvironment => elementMap.typeEnvironment; |
| |
| @override |
| CommonElements get commonElements => elementMap.commonElements; |
| |
| @override |
| NativeBasicData get _nativeBasicData => elementMap.nativeBasicData; |
| |
| /// Converts a [ImpactData] object based on kernel to the corresponding |
| /// [ResolutionImpact] based on the K model. |
| ResolutionImpact convert(ImpactData impactData) { |
| impactData.apply(this); |
| return impactBuilder; |
| } |
| } |
| |
| /// [ImpactRegistry] that converts kernel based impact data to world impact |
| /// object based on the K model. |
| abstract class KernelImpactRegistryMixin implements ImpactRegistry { |
| CompilerOptions get _options; |
| DiagnosticReporter get reporter; |
| KernelToElementMap get elementMap; |
| MemberEntity get currentMember; |
| ResolutionWorldImpactBuilder get impactBuilder; |
| ir.TypeEnvironment get typeEnvironment; |
| CommonElements get commonElements; |
| NativeBasicData get _nativeBasicData; |
| ConstantValuefier get _constantValuefier; |
| |
| Object _computeReceiverConstraint( |
| ir.DartType receiverType, ClassRelation relation) { |
| if (receiverType is ir.InterfaceType) { |
| if (receiverType.classNode == typeEnvironment.futureOrClass) { |
| // CFE encodes FutureOr as an interface type! |
| return null; |
| } |
| return new StrongModeConstraint(commonElements, _nativeBasicData, |
| elementMap.getClass(receiverType.classNode), relation); |
| } |
| return null; |
| } |
| |
| @override |
| void registerParameterCheck(ir.DartType irType) { |
| DartType type = elementMap.getDartType(irType); |
| if (!type.isDynamic) { |
| impactBuilder.registerTypeUse(new TypeUse.parameterCheck(type)); |
| } |
| } |
| |
| List<DartType> _getTypeArguments(List<ir.DartType> types) { |
| if (types.isEmpty) return null; |
| return types.map(elementMap.getDartType).toList(); |
| } |
| |
| @override |
| void registerLazyField() { |
| impactBuilder.registerFeature(Feature.LAZY_FIELD); |
| } |
| |
| @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(reporter, commonElements, metadata); |
| Iterable<String> returnsAnnotations = |
| getReturnsAnnotations(reporter, commonElements, metadata); |
| impactBuilder.registerNativeData(elementMap.getNativeBehaviorForFieldLoad( |
| field, createsAnnotations, returnsAnnotations, |
| isJsInterop: isJsInterop)); |
| impactBuilder |
| .registerNativeData(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(reporter, commonElements, metadata); |
| Iterable<String> returnsAnnotations = |
| getReturnsAnnotations(reporter, commonElements, metadata); |
| impactBuilder.registerNativeData(elementMap.getNativeBehaviorForMethod( |
| constructor, createsAnnotations, returnsAnnotations, |
| isJsInterop: isJsInterop)); |
| } |
| } |
| |
| @override |
| void registerSyncStar(ir.DartType elementType) { |
| impactBuilder.registerFeature(Feature.SYNC_STAR); |
| impactBuilder.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.syncStarIterableFactory, |
| const CallStructure.unnamed(1, 1), |
| <DartType>[elementMap.getDartType(elementType)])); |
| } |
| |
| @override |
| void registerAsync(ir.DartType elementType) { |
| impactBuilder.registerFeature(Feature.ASYNC); |
| impactBuilder.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.asyncAwaitCompleterFactory, |
| const CallStructure.unnamed(0, 1), |
| <DartType>[elementMap.getDartType(elementType)])); |
| } |
| |
| @override |
| void registerAsyncStar(ir.DartType elementType) { |
| impactBuilder.registerFeature(Feature.ASYNC_STAR); |
| impactBuilder.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.asyncStarStreamControllerFactory, |
| const 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(reporter, commonElements, metadata); |
| Iterable<String> returnsAnnotations = |
| getReturnsAnnotations(reporter, commonElements, metadata); |
| impactBuilder.registerNativeData(elementMap.getNativeBehaviorForMethod( |
| procedure, createsAnnotations, returnsAnnotations, |
| isJsInterop: isJsInterop)); |
| } |
| } |
| |
| @override |
| void registerIntLiteral(int value) { |
| impactBuilder.registerConstantLiteral( |
| new IntConstantExpression(new BigInt.from(value).toUnsigned(64))); |
| } |
| |
| @override |
| void registerDoubleLiteral(double value) { |
| impactBuilder.registerConstantLiteral(new DoubleConstantExpression(value)); |
| } |
| |
| @override |
| void registerBoolLiteral(bool value) { |
| impactBuilder.registerConstantLiteral(new BoolConstantExpression(value)); |
| } |
| |
| @override |
| void registerStringLiteral(String value) { |
| impactBuilder.registerConstantLiteral(new StringConstantExpression(value)); |
| } |
| |
| @override |
| void registerSymbolLiteral(String value) { |
| impactBuilder.registerConstSymbolName(value); |
| } |
| |
| @override |
| void registerNullLiteral() { |
| impactBuilder.registerConstantLiteral(new NullConstantExpression()); |
| } |
| |
| @override |
| void registerListLiteral(ir.DartType elementType, |
| {bool isConst, bool isEmpty}) { |
| impactBuilder.registerListLiteral(new ListLiteralUse( |
| commonElements.listType(elementMap.getDartType(elementType)), |
| isConstant: isConst, |
| isEmpty: isEmpty)); |
| } |
| |
| @override |
| void registerSetLiteral(ir.DartType elementType, |
| {bool isConst, bool isEmpty}) { |
| impactBuilder.registerSetLiteral(new SetLiteralUse( |
| commonElements.setType(elementMap.getDartType(elementType)), |
| isConstant: isConst, |
| isEmpty: isEmpty)); |
| } |
| |
| @override |
| void registerMapLiteral(ir.DartType keyType, ir.DartType valueType, |
| {bool isConst, bool isEmpty}) { |
| impactBuilder.registerMapLiteral(new MapLiteralUse( |
| commonElements.mapType( |
| elementMap.getDartType(keyType), elementMap.getDartType(valueType)), |
| isConstant: isConst, |
| isEmpty: isEmpty)); |
| } |
| |
| @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 = new CallStructure( |
| positionalArguments + namedArguments.length, |
| namedArguments, |
| typeArguments.length); |
| ImportEntity deferredImport = elementMap.getImport(import); |
| impactBuilder.registerStaticUse(isConst |
| ? new StaticUse.constConstructorInvoke(constructor, callStructure, |
| elementMap.getDartType(type), deferredImport) |
| : new StaticUse.typedConstructorInvoke(constructor, callStructure, |
| elementMap.getDartType(type), deferredImport)); |
| if (type.typeArguments.any((ir.DartType type) => type is! ir.DynamicType)) { |
| impactBuilder.registerFeature(Feature.TYPE_VARIABLE_BOUNDS_CHECK); |
| } |
| |
| if (commonElements.isSymbolConstructor(constructor)) { |
| impactBuilder.registerFeature(Feature.SYMBOL_CONSTRUCTOR); |
| } |
| |
| if (target.isExternal && |
| constructor.isFromEnvironmentConstructor && |
| !isConst) { |
| impactBuilder.registerFeature(Feature.THROW_UNSUPPORTED_ERROR); |
| // 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(new TypeUse.constInstantiation(type, deferredImport)); |
| } |
| |
| @override |
| void registerConstConstructorInvocationNode(ir.ConstructorInvocation node) { |
| assert(node.isConst); |
| ConstructorEntity constructor = elementMap.getConstructor(node.target); |
| if (commonElements.isSymbolConstructor(constructor)) { |
| ConstantValue value = |
| elementMap.getConstantValue(node.arguments.positional.first); |
| if (!value.isString) { |
| // TODO(het): Get the actual span for the Symbol constructor argument |
| reporter.reportErrorMessage( |
| CURRENT_ELEMENT_SPANNABLE, |
| MessageKind.STRING_EXPECTED, |
| {'type': value.getType(elementMap.commonElements)}); |
| return; |
| } |
| StringConstantValue stringValue = value; |
| impactBuilder.registerConstSymbolName(stringValue.stringValue); |
| } |
| } |
| |
| @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(new StaticUse.superConstructorInvoke( |
| constructor, |
| new 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 = new 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(new StaticUse.staticInvoke( |
| target, callStructure, dartTypeArguments, deferredImport)); |
| } |
| } |
| |
| @override |
| void registerStaticInvocationNode(ir.StaticInvocation node) { |
| switch (elementMap.getForeignKind(node)) { |
| case ForeignKind.JS: |
| impactBuilder |
| .registerNativeData(elementMap.getNativeBehaviorForJsCall(node)); |
| break; |
| case ForeignKind.JS_BUILTIN: |
| impactBuilder.registerNativeData( |
| elementMap.getNativeBehaviorForJsBuiltinCall(node)); |
| break; |
| case ForeignKind.JS_EMBEDDED_GLOBAL: |
| impactBuilder.registerNativeData( |
| elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(node)); |
| break; |
| case ForeignKind.JS_INTERCEPTOR_CONSTANT: |
| InterfaceType type = |
| elementMap.getInterfaceTypeForJsInterceptorCall(node); |
| if (type != null) { |
| impactBuilder.registerTypeUse(new 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( |
| new StaticUse.staticInvoke(target, callStructure, typeArguments)); |
| |
| if (typeArguments.length != 1) return; |
| DartType matchedType = typeArguments.first; |
| |
| if (matchedType is! InterfaceType) return; |
| InterfaceType interfaceType = matchedType; |
| ClassEntity cls = interfaceType.element; |
| InterfaceType thisType = elementMap.elementEnvironment.getThisType(cls); |
| |
| impactBuilder.registerTypeUse(new TypeUse.isCheck(thisType)); |
| |
| Selector selector = new Selector.callClosure( |
| 0, const <String>[], thisType.typeArguments.length); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(selector, null, thisType.typeArguments)); |
| } |
| |
| @override |
| void registerStaticTearOff( |
| ir.Procedure procedure, ir.LibraryDependency import) { |
| impactBuilder.registerStaticUse(new StaticUse.staticTearOff( |
| elementMap.getMethod(procedure), elementMap.getImport(import))); |
| } |
| |
| @override |
| void registerStaticGet(ir.Member member, ir.LibraryDependency import) { |
| impactBuilder.registerStaticUse(new StaticUse.staticGet( |
| elementMap.getMember(member), elementMap.getImport(import))); |
| } |
| |
| @override |
| void registerStaticSet(ir.Member member, ir.LibraryDependency import) { |
| impactBuilder.registerStaticUse(new StaticUse.staticSet( |
| elementMap.getMember(member), elementMap.getImport(import))); |
| } |
| |
| @override |
| void registerSuperInvocation(ir.Name name, int positionalArguments, |
| List<String> namedArguments, List<ir.DartType> typeArguments) { |
| FunctionEntity method = |
| elementMap.getSuperMember(currentMember, name, setter: false); |
| List<DartType> dartTypeArguments = _getTypeArguments(typeArguments); |
| if (method != null) { |
| impactBuilder.registerStaticUse(new StaticUse.superInvoke( |
| method, |
| new CallStructure(positionalArguments + namedArguments.length, |
| namedArguments, typeArguments.length), |
| dartTypeArguments)); |
| } else { |
| impactBuilder.registerStaticUse(new StaticUse.superInvoke( |
| elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), |
| CallStructure.ONE_ARG)); |
| impactBuilder.registerFeature(Feature.SUPER_NO_SUCH_METHOD); |
| } |
| } |
| |
| @override |
| void registerSuperGet(ir.Name name) { |
| MemberEntity member = |
| elementMap.getSuperMember(currentMember, name, setter: false); |
| if (member != null) { |
| if (member.isFunction) { |
| impactBuilder.registerStaticUse(new StaticUse.superTearOff(member)); |
| } else { |
| impactBuilder.registerStaticUse(new StaticUse.superGet(member)); |
| } |
| } else { |
| impactBuilder.registerStaticUse(new StaticUse.superInvoke( |
| elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), |
| CallStructure.ONE_ARG)); |
| impactBuilder.registerFeature(Feature.SUPER_NO_SUCH_METHOD); |
| } |
| } |
| |
| @override |
| void registerSuperSet(ir.Name name) { |
| MemberEntity member = |
| elementMap.getSuperMember(currentMember, name, setter: true); |
| if (member != null) { |
| if (member.isField) { |
| impactBuilder.registerStaticUse(new StaticUse.superFieldSet(member)); |
| } else { |
| impactBuilder.registerStaticUse(new StaticUse.superSetterSet(member)); |
| } |
| } else { |
| impactBuilder.registerStaticUse(new StaticUse.superInvoke( |
| elementMap.getSuperNoSuchMethod(currentMember.enclosingClass), |
| CallStructure.ONE_ARG)); |
| impactBuilder.registerFeature(Feature.SUPER_NO_SUCH_METHOD); |
| } |
| } |
| |
| @override |
| void registerLocalFunctionInvocation( |
| ir.FunctionDeclaration localFunction, |
| int positionalArguments, |
| List<String> namedArguments, |
| List<ir.DartType> typeArguments) { |
| CallStructure callStructure = new 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(new 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( |
| new 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(new DynamicUse(selector, |
| _computeReceiverConstraint(receiverType, relation), dartTypeArguments)); |
| } |
| |
| @override |
| void registerFunctionInvocation( |
| ir.DartType receiverType, |
| int positionalArguments, |
| List<String> namedArguments, |
| List<ir.DartType> typeArguments) { |
| CallStructure callStructure = new CallStructure( |
| positionalArguments + namedArguments.length, |
| namedArguments, |
| typeArguments.length); |
| List<DartType> dartTypeArguments = _getTypeArguments(typeArguments); |
| impactBuilder.registerDynamicUse(new 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(new 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(new DynamicUse( |
| new Selector.getter(elementMap.getName(name)), |
| _computeReceiverConstraint(receiverType, relation), |
| const <DartType>[])); |
| } |
| |
| @override |
| void registerInstanceGet( |
| ir.DartType receiverType, ClassRelation relation, ir.Member target) { |
| impactBuilder.registerDynamicUse(new DynamicUse( |
| new Selector.getter(elementMap.getName(target.name)), |
| _computeReceiverConstraint(receiverType, relation), |
| const <DartType>[])); |
| } |
| |
| @override |
| void registerDynamicSet( |
| ir.DartType receiverType, ClassRelation relation, ir.Name name) { |
| impactBuilder.registerDynamicUse(new DynamicUse( |
| new Selector.setter(elementMap.getName(name)), |
| _computeReceiverConstraint(receiverType, relation), |
| const <DartType>[])); |
| } |
| |
| @override |
| void registerInstanceSet( |
| ir.DartType receiverType, ClassRelation relation, ir.Member target) { |
| impactBuilder.registerDynamicUse(new DynamicUse( |
| new Selector.setter(elementMap.getName(target.name)), |
| _computeReceiverConstraint(receiverType, relation), |
| const <DartType>[])); |
| } |
| |
| @override |
| void registerRuntimeTypeUse(ir.PropertyGet node, RuntimeTypeUseKind kind, |
| ir.DartType receiverType, ir.DartType argumentType) { |
| DartType receiverDartType = elementMap.getDartType(receiverType); |
| DartType argumentDartType = |
| argumentType == null ? null : elementMap.getDartType(argumentType); |
| |
| if (_options.omitImplicitChecks) { |
| switch (kind) { |
| case RuntimeTypeUseKind.string: |
| if (!_options.laxRuntimeTypeToString) { |
| if (receiverDartType == commonElements.objectType) { |
| reporter.reportHintMessage(computeSourceSpanFromTreeNode(node), |
| MessageKind.RUNTIME_TYPE_TO_STRING_OBJECT); |
| } else { |
| reporter.reportHintMessage( |
| computeSourceSpanFromTreeNode(node), |
| MessageKind.RUNTIME_TYPE_TO_STRING_SUBTYPE, |
| {'receiverType': '${receiverDartType}.'}); |
| } |
| } |
| break; |
| case RuntimeTypeUseKind.equals: |
| case RuntimeTypeUseKind.unknown: |
| break; |
| } |
| } |
| impactBuilder.registerRuntimeTypeUse( |
| new RuntimeTypeUse(kind, receiverDartType, argumentDartType)); |
| } |
| |
| @override |
| void registerAssert({bool withMessage}) { |
| impactBuilder.registerFeature( |
| withMessage ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT); |
| } |
| |
| @override |
| void registerGenericInstantiation( |
| ir.FunctionType expressionType, List<ir.DartType> typeArguments) { |
| // TODO(johnniwinther): Track which arities are used in instantiation. |
| impactBuilder.registerInstantiation(new GenericInstantiation( |
| elementMap.getDartType(expressionType), |
| typeArguments.map(elementMap.getDartType).toList())); |
| } |
| |
| @override |
| void registerStringConcatenation() { |
| impactBuilder.registerFeature(Feature.STRING_INTERPOLATION); |
| impactBuilder.registerFeature(Feature.STRING_JUXTAPOSITION); |
| } |
| |
| @override |
| void registerLocalFunction(ir.TreeNode node) { |
| Local function = elementMap.getLocalFunction(node); |
| impactBuilder.registerStaticUse(new StaticUse.closure(function)); |
| } |
| |
| @override |
| void registerLocalWithoutInitializer() { |
| impactBuilder.registerFeature(Feature.LOCAL_WITHOUT_INITIALIZER); |
| } |
| |
| @override |
| void registerIsCheck(ir.DartType type) { |
| impactBuilder |
| .registerTypeUse(new TypeUse.isCheck(elementMap.getDartType(type))); |
| } |
| |
| @override |
| void registerImplicitCast(ir.DartType type) { |
| impactBuilder.registerTypeUse( |
| new TypeUse.implicitCast(elementMap.getDartType(type))); |
| } |
| |
| @override |
| void registerAsCast(ir.DartType type) { |
| impactBuilder |
| .registerTypeUse(new TypeUse.asCast(elementMap.getDartType(type))); |
| } |
| |
| @override |
| void registerThrow() { |
| impactBuilder.registerFeature(Feature.THROW_EXPRESSION); |
| } |
| |
| @override |
| void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType, |
| ClassRelation iteratorClassRelation) { |
| Object receiverConstraint = |
| _computeReceiverConstraint(iteratorType, iteratorClassRelation); |
| impactBuilder.registerFeature(Feature.SYNC_FOR_IN); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.iterator, receiverConstraint, const [])); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.current, receiverConstraint, const [])); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.moveNext, receiverConstraint, const [])); |
| } |
| |
| @override |
| void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType, |
| ClassRelation iteratorClassRelation) { |
| Object receiverConstraint = |
| _computeReceiverConstraint(iteratorType, iteratorClassRelation); |
| impactBuilder.registerFeature(Feature.ASYNC_FOR_IN); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.cancel, receiverConstraint, const [])); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.current, receiverConstraint, const [])); |
| impactBuilder.registerDynamicUse( |
| new DynamicUse(Selectors.moveNext, receiverConstraint, const [])); |
| } |
| |
| @override |
| void registerCatch() { |
| impactBuilder.registerFeature(Feature.CATCH_STATEMENT); |
| } |
| |
| @override |
| void registerStackTrace() { |
| impactBuilder.registerFeature(Feature.STACK_TRACE_IN_CATCH); |
| } |
| |
| @override |
| void registerCatchType(ir.DartType type) { |
| impactBuilder |
| .registerTypeUse(new TypeUse.catchType(elementMap.getDartType(type))); |
| } |
| |
| @override |
| void registerTypeLiteral(ir.DartType type, ir.LibraryDependency import) { |
| ImportEntity deferredImport = elementMap.getImport(import); |
| impactBuilder.registerTypeUse( |
| new TypeUse.typeLiteral(elementMap.getDartType(type), deferredImport)); |
| if (type is ir.FunctionType) { |
| assert(type.typedef != null); |
| // TODO(johnniwinther): Can we avoid the typedef type altogether? |
| // We need to ensure that the typedef is live. |
| elementMap.getTypedefType(type.typedef); |
| } |
| } |
| |
| @override |
| void registerFieldInitialization(ir.Field node) { |
| impactBuilder |
| .registerStaticUse(new StaticUse.fieldInit(elementMap.getField(node))); |
| } |
| |
| @override |
| void registerFieldConstantInitialization( |
| ir.Field node, ConstantReference constant) { |
| impactBuilder.registerStaticUse(new StaticUse.fieldConstantInit( |
| elementMap.getField(node), |
| constant.constant.accept(_constantValuefier))); |
| } |
| |
| @override |
| void registerRedirectingInitializer( |
| ir.Constructor constructor, |
| int positionalArguments, |
| List<String> namedArguments, |
| List<ir.DartType> typeArguments) { |
| ConstructorEntity target = elementMap.getConstructor(constructor); |
| impactBuilder.registerStaticUse(new StaticUse.superConstructorInvoke( |
| target, |
| new CallStructure(positionalArguments + namedArguments.length, |
| namedArguments, typeArguments.length))); |
| } |
| |
| @override |
| void registerLoadLibrary() { |
| impactBuilder.registerStaticUse(new StaticUse.staticInvoke( |
| commonElements.loadDeferredLibrary, CallStructure.ONE_ARG)); |
| impactBuilder.registerFeature(Feature.LOAD_LIBRARY); |
| } |
| |
| @override |
| void registerSwitchStatementNode(ir.SwitchStatement node) { |
| // TODO(32557): Remove this when issue 32557 is fixed. |
| ir.TreeNode firstCase; |
| DartType firstCaseType; |
| DiagnosticMessage error; |
| List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| |
| 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; |
| } |
| } |
| return false; |
| } |
| |
| for (ir.SwitchCase switchCase in node.cases) { |
| for (ir.Expression expression in switchCase.expressions) { |
| ConstantValue value = elementMap.getConstantValue(expression); |
| DartType type = value.getType(elementMap.commonElements); |
| if (firstCaseType == null) { |
| firstCase = expression; |
| firstCaseType = type; |
| |
| // We only report the bad type on the first class element. All others |
| // get a "type differs" error. |
| 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.isObject && |
| type != commonElements.typeLiteralType && |
| overridesEquals(type)) { |
| reporter.reportErrorMessage( |
| computeSourceSpanFromTreeNode(firstCase), |
| MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS, |
| {'type': type}); |
| } |
| } else { |
| if (type != firstCaseType) { |
| if (error == null) { |
| error = reporter.createMessage( |
| computeSourceSpanFromTreeNode(node), |
| MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL, |
| {'type': firstCaseType}); |
| infos.add(reporter.createMessage( |
| computeSourceSpanFromTreeNode(firstCase), |
| MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE, |
| {'type': firstCaseType})); |
| } |
| infos.add(reporter.createMessage( |
| computeSourceSpanFromTreeNode(expression), |
| MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE, |
| {'type': type})); |
| } |
| } |
| } |
| } |
| if (error != null) { |
| reporter.reportError(error, infos); |
| } |
| } |
| } |