| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.kernel.element_map; | |
| 6 | |
| 7 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 8 | 6 |
| 9 import '../common.dart'; | 7 import '../common.dart'; |
| 10 import '../common/names.dart' show Identifiers; | 8 import '../common/names.dart'; |
| 11 import '../common/resolution.dart'; | |
| 12 import '../compile_time_constants.dart'; | |
| 13 import '../constants/constant_system.dart'; | |
| 14 import '../constants/constructors.dart'; | 9 import '../constants/constructors.dart'; |
| 15 import '../constants/evaluation.dart'; | |
| 16 import '../constants/expressions.dart'; | 10 import '../constants/expressions.dart'; |
| 17 import '../constants/values.dart'; | 11 import '../constants/values.dart'; |
| 18 import '../common_elements.dart'; | 12 import '../common_elements.dart'; |
| 19 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
| 20 import '../elements/entities.dart'; | 14 import '../elements/entities.dart'; |
| 15 import '../elements/operators.dart'; |
| 21 import '../elements/types.dart'; | 16 import '../elements/types.dart'; |
| 22 import '../environment.dart'; | 17 import '../js_backend/backend.dart' show JavaScriptBackend; |
| 23 import '../frontend_strategy.dart'; | |
| 24 import '../js_backend/constant_system_javascript.dart'; | |
| 25 import '../js_backend/native_data.dart'; | |
| 26 import '../js_backend/no_such_method_registry.dart'; | |
| 27 import '../native/native.dart' as native; | 18 import '../native/native.dart' as native; |
| 28 import '../native/resolver.dart'; | |
| 29 import '../ordered_typeset.dart'; | |
| 30 import '../ssa/kernel_impact.dart'; | |
| 31 import '../universe/call_structure.dart'; | 19 import '../universe/call_structure.dart'; |
| 32 import '../universe/world_builder.dart'; | 20 import '../universe/selector.dart'; |
| 33 import '../util/util.dart' show Link, LinkBuilder; | 21 import 'kernel_debug.dart'; |
| 34 import 'element_adapter.dart'; | 22 |
| 35 import 'elements.dart'; | 23 /// Interface that translates between Kernel IR nodes and entities. |
| 36 | 24 abstract class KernelToElementMap { |
| 37 part 'native_basic_data.dart'; | 25 /// Access to the commonly used elements and types. |
| 38 part 'no_such_method_resolver.dart'; | 26 CommonElements get commonElements; |
| 39 part 'types.dart'; | 27 |
| 40 | 28 /// [ElementEnvironment] for library, class and member lookup. |
| 41 /// Element builder used for creating elements and types corresponding to Kernel | 29 ElementEnvironment get elementEnvironment; |
| 42 /// IR nodes. | 30 |
| 43 class KernelToElementMap extends KernelElementAdapterMixin { | 31 /// Returns the [DartType] corresponding to [type]. |
| 44 final Environment _environment; | 32 DartType getDartType(ir.DartType type); |
| 45 CommonElements _commonElements; | 33 |
| 46 native.BehaviorBuilder _nativeBehaviorBuilder; | 34 /// Returns the list of [DartType]s corresponding to [types]. |
| 47 final DiagnosticReporter reporter; | 35 List<DartType> getDartTypes(List<ir.DartType> types); |
| 48 ElementEnvironment _elementEnvironment; | 36 |
| 49 DartTypeConverter _typeConverter; | 37 /// Returns the [InterfaceType] corresponding to [type]. |
| 50 KernelConstantEnvironment _constantEnvironment; | 38 InterfaceType getInterfaceType(ir.InterfaceType type); |
| 51 _KernelDartTypes _types; | 39 |
| 52 | 40 /// Return the [InterfaceType] corresponding to the [cls] with the given |
| 53 /// Library environment. Used for fast lookup. | 41 /// [typeArguments]. |
| 54 _KEnv _env = new _KEnv(); | 42 InterfaceType createInterfaceType( |
| 55 | 43 ir.Class cls, List<ir.DartType> typeArguments); |
| 56 /// List of library environments by `KLibrary.libraryIndex`. This is used for | 44 |
| 57 /// fast lookup into library classes and members. | 45 /// Returns the [CallStructure] corresponding to the [arguments]. |
| 58 List<_KLibraryEnv> _libraryEnvs = <_KLibraryEnv>[]; | 46 CallStructure getCallStructure(ir.Arguments arguments); |
| 59 | 47 |
| 60 /// List of class environments by `KClass.classIndex`. This is used for | 48 /// Returns the [Selector] corresponding to the invocation or getter/setter |
| 61 /// fast lookup into class members. | 49 /// access of [node]. |
| 62 List<_KClassEnv> _classEnvs = <_KClassEnv>[]; | 50 Selector getSelector(ir.Expression node); |
| 63 | 51 |
| 64 Map<ir.Library, KLibrary> _libraryMap = <ir.Library, KLibrary>{}; | 52 /// Returns the [ConstructorEntity] corresponding to the generative or factory |
| 65 Map<ir.Class, KClass> _classMap = <ir.Class, KClass>{}; | 53 /// constructor [node]. |
| 66 Map<ir.TypeParameter, KTypeVariable> _typeVariableMap = | 54 ConstructorEntity getConstructor(ir.Member node); |
| 67 <ir.TypeParameter, KTypeVariable>{}; | 55 |
| 68 | 56 /// Returns the [MemberEntity] corresponding to the member [node]. |
| 69 List<_MemberData> _memberList = <_MemberData>[]; | 57 MemberEntity getMember(ir.Member node); |
| 70 | 58 |
| 71 Map<ir.Member, KConstructor> _constructorMap = <ir.Member, KConstructor>{}; | 59 /// Returns the [FunctionEntity] corresponding to the procedure [node]. |
| 72 Map<ir.Procedure, KFunction> _methodMap = <ir.Procedure, KFunction>{}; | 60 FunctionEntity getMethod(ir.Procedure node); |
| 73 Map<ir.Field, KField> _fieldMap = <ir.Field, KField>{}; | 61 |
| 74 | 62 /// Returns the [FieldEntity] corresponding to the field [node]. |
| 75 Map<ir.TreeNode, KLocalFunction> _localFunctionMap = | 63 FieldEntity getField(ir.Field node); |
| 76 <ir.TreeNode, KLocalFunction>{}; | 64 |
| 77 | 65 /// Returns the [ClassEntity] corresponding to the class [node]. |
| 78 KernelToElementMap(this.reporter, this._environment) { | 66 ClassEntity getClass(ir.Class node); |
| 79 _elementEnvironment = new KernelElementEnvironment(this); | 67 |
| 80 _commonElements = new CommonElements(_elementEnvironment); | 68 /// Returns the [Local] corresponding to the [node]. The node must be either |
| 81 _constantEnvironment = new KernelConstantEnvironment(this); | 69 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression]. |
| 82 _nativeBehaviorBuilder = new KernelBehaviorBuilder(_commonElements); | 70 Local getLocalFunction(ir.TreeNode node); |
| 83 _types = new _KernelDartTypes(this); | 71 |
| 84 _typeConverter = new DartTypeConverter(this); | 72 /// Returns the [LibraryEntity] corresponding to the library [node]. |
| 85 } | 73 LibraryEntity getLibrary(ir.Library node); |
| 86 | 74 |
| 87 /// Adds libraries in [program] to the set of libraries. | 75 /// Returns the [Name] corresponding to [name]. |
| 88 /// | 76 Name getName(ir.Name name); |
| 89 /// The main method of the first program is used as the main method for the | 77 |
| 90 /// compilation. | 78 /// Returns `true` is [node] has a `@Native(...)` annotation. |
| 91 void addProgram(ir.Program program) { | 79 bool isNativeClass(ir.Class node); |
| 92 _env.addProgram(program); | 80 |
| 93 } | 81 /// Return `true` if [node] is the `dart:_foreign_helper` library. |
| 94 | 82 bool isForeignLibrary(ir.Library node); |
| 95 KMethod get _mainFunction { | 83 |
| 96 return _env.mainMethod != null ? _getMethod(_env.mainMethod) : null; | 84 /// Computes the native behavior for reading the native [field]. |
| 97 } | 85 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field); |
| 98 | 86 |
| 99 KLibrary get _mainLibrary { | 87 /// Computes the native behavior for writing to the native [field]. |
| 100 return _env.mainMethod != null | 88 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field); |
| 101 ? _getLibrary(_env.mainMethod.enclosingLibrary) | 89 |
| 102 : null; | 90 /// Computes the native behavior for calling [procedure]. |
| 103 } | 91 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure); |
| 104 | 92 |
| 105 Iterable<LibraryEntity> get _libraries { | 93 /// Computes the [native.NativeBehavior] for a call to the [JS] function. |
| 106 if (_env.length != _libraryMap.length) { | 94 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node); |
| 107 // Create a [KLibrary] for each library. | 95 |
| 108 _env.forEachLibrary((_KLibraryEnv env) { | 96 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] |
| 109 _getLibrary(env.library, env); | 97 /// function. |
| 110 }); | 98 native.NativeBehavior getNativeBehaviorForJsBuiltinCall( |
| 111 } | 99 ir.StaticInvocation node); |
| 112 return _libraryMap.values; | 100 |
| 113 } | 101 /// Computes the [native.NativeBehavior] for a call to the |
| 114 | 102 /// [JS_EMBEDDED_GLOBAL] function. |
| 115 @override | 103 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( |
| 116 CommonElements get commonElements => _commonElements; | 104 ir.StaticInvocation node); |
| 117 | 105 |
| 118 @override | 106 /// Compute the kind of foreign helper function called by [node], if any. |
| 119 ElementEnvironment get elementEnvironment => _elementEnvironment; | 107 ForeignKind getForeignKind(ir.StaticInvocation node); |
| 120 | 108 |
| 121 ConstantEnvironment get constantEnvironment => _constantEnvironment; | 109 /// Computes the [InterfaceType] referenced by a call to the |
| 122 | 110 /// [JS_INTERCEPTOR_CONSTANT] function, if any. |
| 123 DartTypes get types => _types; | 111 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node); |
| 124 | 112 |
| 125 @override | 113 /// Computes the [ConstantValue] for the constant [expression]. |
| 126 native.BehaviorBuilder get nativeBehaviorBuilder => _nativeBehaviorBuilder; | 114 ConstantValue getConstantValue(ir.Expression expression); |
| 127 | 115 } |
| 128 @override | 116 |
| 129 ConstantValue computeConstantValue(ConstantExpression constant) { | 117 /// Kinds of foreign functions. |
| 130 return _constantEnvironment.getConstantValue(constant); | 118 enum ForeignKind { |
| 131 } | 119 JS, |
| 132 | 120 JS_BUILTIN, |
| 133 LibraryEntity lookupLibrary(Uri uri) { | 121 JS_EMBEDDED_GLOBAL, |
| 134 _KLibraryEnv libraryEnv = _env.lookupLibrary(uri); | 122 JS_INTERCEPTOR_CONSTANT, |
| 135 if (libraryEnv == null) return null; | 123 NONE, |
| 136 return _getLibrary(libraryEnv.library, libraryEnv); | 124 } |
| 137 } | 125 |
| 138 | 126 abstract class KernelToElementMapMixin implements KernelToElementMap { |
| 139 KLibrary _getLibrary(ir.Library node, [_KLibraryEnv libraryEnv]) { | 127 DiagnosticReporter get reporter; |
| 140 return _libraryMap.putIfAbsent(node, () { | 128 FunctionType getFunctionType(ir.FunctionNode node); |
| 141 Uri canonicalUri = node.importUri; | 129 native.BehaviorBuilder get nativeBehaviorBuilder; |
| 142 _libraryEnvs.add(libraryEnv ?? _env.lookupLibrary(canonicalUri)); | 130 ConstantValue computeConstantValue(ConstantExpression constant); |
| 143 String name = node.name; | 131 |
| 144 if (name == null) { | 132 @override |
| 145 // Use the file name as script name. | 133 Name getName(ir.Name name) { |
| 146 String path = canonicalUri.path; | 134 return new Name( |
| 147 name = path.substring(path.lastIndexOf('/') + 1); | 135 name.name, name.isPrivate ? getLibrary(name.library) : null); |
| 148 } | 136 } |
| 149 return new KLibrary(_libraryMap.length, name, canonicalUri); | 137 |
| 138 @override |
| 139 CallStructure getCallStructure(ir.Arguments arguments) { |
| 140 int argumentCount = arguments.positional.length + arguments.named.length; |
| 141 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); |
| 142 return new CallStructure(argumentCount, namedArguments); |
| 143 } |
| 144 |
| 145 @override |
| 146 Selector getSelector(ir.Expression node) { |
| 147 // TODO(efortuna): This is screaming for a common interface between |
| 148 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel |
| 149 // folks. |
| 150 if (node is ir.PropertyGet) { |
| 151 return getGetterSelector(node.name); |
| 152 } |
| 153 if (node is ir.SuperPropertyGet) { |
| 154 return getGetterSelector(node.name); |
| 155 } |
| 156 if (node is ir.PropertySet) { |
| 157 return getSetterSelector(node.name); |
| 158 } |
| 159 if (node is ir.SuperPropertySet) { |
| 160 return getSetterSelector(node.name); |
| 161 } |
| 162 if (node is ir.InvocationExpression) { |
| 163 return getInvocationSelector(node); |
| 164 } |
| 165 throw new SpannableAssertionFailure( |
| 166 CURRENT_ELEMENT_SPANNABLE, |
| 167 "Can only get the selector for a property get or an invocation: " |
| 168 "${node}"); |
| 169 } |
| 170 |
| 171 Selector getInvocationSelector(ir.InvocationExpression invocation) { |
| 172 Name name = getName(invocation.name); |
| 173 SelectorKind kind; |
| 174 if (Elements.isOperatorName(invocation.name.name)) { |
| 175 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) { |
| 176 kind = SelectorKind.INDEX; |
| 177 } else { |
| 178 kind = SelectorKind.OPERATOR; |
| 179 } |
| 180 } else { |
| 181 kind = SelectorKind.CALL; |
| 182 } |
| 183 |
| 184 CallStructure callStructure = getCallStructure(invocation.arguments); |
| 185 return new Selector(kind, name, callStructure); |
| 186 } |
| 187 |
| 188 Selector getGetterSelector(ir.Name irName) { |
| 189 Name name = new Name( |
| 190 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); |
| 191 return new Selector.getter(name); |
| 192 } |
| 193 |
| 194 Selector getSetterSelector(ir.Name irName) { |
| 195 Name name = new Name( |
| 196 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); |
| 197 return new Selector.setter(name); |
| 198 } |
| 199 |
| 200 ConstantValue getConstantValue(ir.Expression node) { |
| 201 ConstantExpression constant = new Constantifier(this).visit(node); |
| 202 if (constant == null) { |
| 203 throw new UnsupportedError( |
| 204 'No constant for ${DebugPrinter.prettyPrint(node)}'); |
| 205 } |
| 206 return computeConstantValue(constant); |
| 207 } |
| 208 |
| 209 /// Converts [annotations] into a list of [ConstantValue]s. |
| 210 List<ConstantValue> getMetadata(List<ir.Expression> annotations) { |
| 211 if (annotations.isEmpty) return const <ConstantValue>[]; |
| 212 List<ConstantValue> metadata = <ConstantValue>[]; |
| 213 annotations.forEach((ir.Expression node) { |
| 214 metadata.add(getConstantValue(node)); |
| 150 }); | 215 }); |
| 151 } | 216 return metadata; |
| 152 | 217 } |
| 153 MemberEntity lookupLibraryMember(KLibrary library, String name, | 218 |
| 154 {bool setter: false}) { | 219 /// Returns `true` is [node] has a `@Native(...)` annotation. |
| 155 _KLibraryEnv libraryEnv = _libraryEnvs[library.libraryIndex]; | 220 // TODO(johnniwinther): Cache this for later use. |
| 156 ir.Member member = libraryEnv.lookupMember(name, setter: setter); | 221 bool isNativeClass(ir.Class node) { |
| 157 return member != null ? getMember(member) : null; | 222 for (ir.Expression annotation in node.annotations) { |
| 158 } | 223 if (annotation is ir.ConstructorInvocation) { |
| 159 | 224 FunctionEntity target = getConstructor(annotation.target); |
| 160 ClassEntity lookupClass(KLibrary library, String name) { | 225 if (target.enclosingClass == commonElements.nativeAnnotationClass) { |
| 161 _KLibraryEnv libraryEnv = _libraryEnvs[library.libraryIndex]; | 226 return true; |
| 162 _KClassEnv classEnv = libraryEnv.lookupClass(name); | |
| 163 if (classEnv != null) { | |
| 164 return _getClass(classEnv.cls, classEnv); | |
| 165 } | |
| 166 return null; | |
| 167 } | |
| 168 | |
| 169 void _forEachClass(KLibrary library, void f(ClassEntity cls)) { | |
| 170 _KLibraryEnv libraryEnv = _libraryEnvs[library.libraryIndex]; | |
| 171 libraryEnv.forEachClass((_KClassEnv classEnv) { | |
| 172 if (!classEnv.isUnnamedMixinApplication) { | |
| 173 f(_getClass(classEnv.cls, classEnv)); | |
| 174 } | |
| 175 }); | |
| 176 } | |
| 177 | |
| 178 MemberEntity lookupClassMember(KClass cls, String name, | |
| 179 {bool setter: false}) { | |
| 180 _KClassEnv classEnv = _classEnvs[cls.classIndex]; | |
| 181 ir.Member member = classEnv.lookupMember(name, setter: setter); | |
| 182 return member != null ? getMember(member) : null; | |
| 183 } | |
| 184 | |
| 185 ConstructorEntity lookupConstructor(KClass cls, String name) { | |
| 186 _KClassEnv classEnv = _classEnvs[cls.classIndex]; | |
| 187 ir.Member member = classEnv.lookupConstructor(name); | |
| 188 return member != null ? getConstructor(member) : null; | |
| 189 } | |
| 190 | |
| 191 KClass _getClass(ir.Class node, [_KClassEnv classEnv]) { | |
| 192 return _classMap.putIfAbsent(node, () { | |
| 193 KLibrary library = _getLibrary(node.enclosingLibrary); | |
| 194 if (classEnv == null) { | |
| 195 classEnv = _libraryEnvs[library.libraryIndex].lookupClass(node.name); | |
| 196 } | |
| 197 _classEnvs.add(classEnv); | |
| 198 return new KClass(library, _classMap.length, node.name, | |
| 199 isAbstract: node.isAbstract); | |
| 200 }); | |
| 201 } | |
| 202 | |
| 203 Iterable<ConstantValue> _getClassMetadata(KClass cls) { | |
| 204 return _classEnvs[cls.classIndex].getMetadata(this); | |
| 205 } | |
| 206 | |
| 207 KTypeVariable _getTypeVariable(ir.TypeParameter node) { | |
| 208 return _typeVariableMap.putIfAbsent(node, () { | |
| 209 if (node.parent is ir.Class) { | |
| 210 ir.Class cls = node.parent; | |
| 211 int index = cls.typeParameters.indexOf(node); | |
| 212 return new KTypeVariable(_getClass(cls), node.name, index); | |
| 213 } | |
| 214 if (node.parent is ir.FunctionNode) { | |
| 215 ir.FunctionNode func = node.parent; | |
| 216 int index = func.typeParameters.indexOf(node); | |
| 217 if (func.parent is ir.Constructor) { | |
| 218 ir.Constructor constructor = func.parent; | |
| 219 ir.Class cls = constructor.enclosingClass; | |
| 220 return _getTypeVariable(cls.typeParameters[index]); | |
| 221 } | 227 } |
| 222 if (func.parent is ir.Procedure) { | 228 } |
| 223 ir.Procedure procedure = func.parent; | 229 } |
| 224 if (procedure.kind == ir.ProcedureKind.Factory) { | 230 return false; |
| 225 ir.Class cls = procedure.enclosingClass; | 231 } |
| 226 return _getTypeVariable(cls.typeParameters[index]); | 232 |
| 227 } else { | 233 /// Compute the kind of foreign helper function called by [node], if any. |
| 228 return new KTypeVariable(_getMethod(procedure), node.name, index); | 234 ForeignKind getForeignKind(ir.StaticInvocation node) { |
| 235 if (isForeignLibrary(node.target.enclosingLibrary)) { |
| 236 switch (node.target.name.name) { |
| 237 case JavaScriptBackend.JS: |
| 238 return ForeignKind.JS; |
| 239 case JavaScriptBackend.JS_BUILTIN: |
| 240 return ForeignKind.JS_BUILTIN; |
| 241 case JavaScriptBackend.JS_EMBEDDED_GLOBAL: |
| 242 return ForeignKind.JS_EMBEDDED_GLOBAL; |
| 243 case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT: |
| 244 return ForeignKind.JS_INTERCEPTOR_CONSTANT; |
| 245 } |
| 246 } |
| 247 return ForeignKind.NONE; |
| 248 } |
| 249 |
| 250 /// Return `true` if [node] is the `dart:_foreign_helper` library. |
| 251 bool isForeignLibrary(ir.Library node) { |
| 252 return node.importUri == Uris.dart__foreign_helper; |
| 253 } |
| 254 |
| 255 /// Looks up [typeName] for use in the spec-string of a `JS` called. |
| 256 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling |
| 257 // the `ForeignResolver`. |
| 258 // TODO(johnniwinther): Cache the result to avoid redundant lookups? |
| 259 native.TypeLookup typeLookup({bool resolveAsRaw: true}) { |
| 260 DartType lookup(String typeName, {bool required}) { |
| 261 DartType findIn(Uri uri) { |
| 262 LibraryEntity library = elementEnvironment.lookupLibrary(uri); |
| 263 if (library != null) { |
| 264 ClassEntity cls = elementEnvironment.lookupClass(library, typeName); |
| 265 if (cls != null) { |
| 266 // TODO(johnniwinther): Align semantics. |
| 267 return resolveAsRaw |
| 268 ? elementEnvironment.getRawType(cls) |
| 269 : elementEnvironment.getThisType(cls); |
| 229 } | 270 } |
| 230 } | 271 } |
| 231 } | 272 return null; |
| 232 throw new UnsupportedError('Unsupported type parameter type node $node.'); | 273 } |
| 274 |
| 275 // TODO(johnniwinther): Narrow the set of lookups base on the depending |
| 276 // library. |
| 277 DartType type = findIn(Uris.dart_core); |
| 278 type ??= findIn(Uris.dart__js_helper); |
| 279 type ??= findIn(Uris.dart__interceptors); |
| 280 type ??= findIn(Uris.dart__isolate_helper); |
| 281 type ??= findIn(Uris.dart__native_typed_data); |
| 282 type ??= findIn(Uris.dart_collection); |
| 283 type ??= findIn(Uris.dart_math); |
| 284 type ??= findIn(Uris.dart_html); |
| 285 type ??= findIn(Uris.dart_html_common); |
| 286 type ??= findIn(Uris.dart_svg); |
| 287 type ??= findIn(Uris.dart_web_audio); |
| 288 type ??= findIn(Uris.dart_web_gl); |
| 289 type ??= findIn(Uris.dart_web_sql); |
| 290 type ??= findIn(Uris.dart_indexed_db); |
| 291 type ??= findIn(Uris.dart_typed_data); |
| 292 if (type == null && required) { |
| 293 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, |
| 294 MessageKind.GENERIC, {'text': "Type '$typeName' not found."}); |
| 295 } |
| 296 return type; |
| 297 } |
| 298 |
| 299 return lookup; |
| 300 } |
| 301 |
| 302 String _getStringArgument(ir.StaticInvocation node, int index) { |
| 303 return node.arguments.positional[index].accept(new Stringifier()); |
| 304 } |
| 305 |
| 306 /// Computes the [native.NativeBehavior] for a call to the [JS] function. |
| 307 // TODO(johnniwinther): Cache this for later use. |
| 308 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) { |
| 309 if (node.arguments.positional.length < 2 || |
| 310 node.arguments.named.isNotEmpty) { |
| 311 reporter.reportErrorMessage( |
| 312 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS); |
| 313 return new native.NativeBehavior(); |
| 314 } |
| 315 String specString = _getStringArgument(node, 0); |
| 316 if (specString == null) { |
| 317 reporter.reportErrorMessage( |
| 318 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST); |
| 319 return new native.NativeBehavior(); |
| 320 } |
| 321 |
| 322 String codeString = _getStringArgument(node, 1); |
| 323 if (codeString == null) { |
| 324 reporter.reportErrorMessage( |
| 325 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND); |
| 326 return new native.NativeBehavior(); |
| 327 } |
| 328 |
| 329 return native.NativeBehavior.ofJsCall( |
| 330 specString, |
| 331 codeString, |
| 332 typeLookup(resolveAsRaw: true), |
| 333 CURRENT_ELEMENT_SPANNABLE, |
| 334 reporter, |
| 335 commonElements); |
| 336 } |
| 337 |
| 338 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] |
| 339 /// function. |
| 340 // TODO(johnniwinther): Cache this for later use. |
| 341 native.NativeBehavior getNativeBehaviorForJsBuiltinCall( |
| 342 ir.StaticInvocation node) { |
| 343 if (node.arguments.positional.length < 1) { |
| 344 reporter.internalError( |
| 345 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type."); |
| 346 return new native.NativeBehavior(); |
| 347 } |
| 348 if (node.arguments.positional.length < 2) { |
| 349 reporter.internalError( |
| 350 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name."); |
| 351 return new native.NativeBehavior(); |
| 352 } |
| 353 String specString = _getStringArgument(node, 0); |
| 354 if (specString == null) { |
| 355 reporter.internalError( |
| 356 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); |
| 357 return new native.NativeBehavior(); |
| 358 } |
| 359 return native.NativeBehavior.ofJsBuiltinCall( |
| 360 specString, |
| 361 typeLookup(resolveAsRaw: true), |
| 362 CURRENT_ELEMENT_SPANNABLE, |
| 363 reporter, |
| 364 commonElements); |
| 365 } |
| 366 |
| 367 /// Computes the [native.NativeBehavior] for a call to the |
| 368 /// [JS_EMBEDDED_GLOBAL] function. |
| 369 // TODO(johnniwinther): Cache this for later use. |
| 370 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( |
| 371 ir.StaticInvocation node) { |
| 372 if (node.arguments.positional.length < 1) { |
| 373 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 374 "JS embedded global expression has no type."); |
| 375 return new native.NativeBehavior(); |
| 376 } |
| 377 if (node.arguments.positional.length < 2) { |
| 378 reporter.internalError( |
| 379 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name."); |
| 380 return new native.NativeBehavior(); |
| 381 } |
| 382 if (node.arguments.positional.length > 2 || |
| 383 node.arguments.named.isNotEmpty) { |
| 384 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
| 385 "JS embedded global has more than 2 arguments."); |
| 386 return new native.NativeBehavior(); |
| 387 } |
| 388 String specString = _getStringArgument(node, 0); |
| 389 if (specString == null) { |
| 390 reporter.internalError( |
| 391 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); |
| 392 return new native.NativeBehavior(); |
| 393 } |
| 394 return native.NativeBehavior.ofJsEmbeddedGlobalCall( |
| 395 specString, |
| 396 typeLookup(resolveAsRaw: true), |
| 397 CURRENT_ELEMENT_SPANNABLE, |
| 398 reporter, |
| 399 commonElements); |
| 400 } |
| 401 |
| 402 /// Computes the [InterfaceType] referenced by a call to the |
| 403 /// [JS_INTERCEPTOR_CONSTANT] function, if any. |
| 404 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) { |
| 405 if (node.arguments.positional.length != 1 || |
| 406 node.arguments.named.isNotEmpty) { |
| 407 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, |
| 408 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); |
| 409 } |
| 410 ir.Node argument = node.arguments.positional.first; |
| 411 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) { |
| 412 return getInterfaceType(argument.type); |
| 413 } |
| 414 return null; |
| 415 } |
| 416 |
| 417 /// Computes the native behavior for reading the native [field]. |
| 418 // TODO(johnniwinther): Cache this for later use. |
| 419 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) { |
| 420 DartType type = getDartType(field.type); |
| 421 List<ConstantValue> metadata = getMetadata(field.annotations); |
| 422 // TODO(johnniwinther): Provide the correct value for [isJsInterop]. |
| 423 return nativeBehaviorBuilder.buildFieldLoadBehavior( |
| 424 type, metadata, typeLookup(resolveAsRaw: false), |
| 425 isJsInterop: false); |
| 426 } |
| 427 |
| 428 /// Computes the native behavior for writing to the native [field]. |
| 429 // TODO(johnniwinther): Cache this for later use. |
| 430 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) { |
| 431 DartType type = getDartType(field.type); |
| 432 return nativeBehaviorBuilder.buildFieldStoreBehavior(type); |
| 433 } |
| 434 |
| 435 /// Computes the native behavior for calling [procedure]. |
| 436 // TODO(johnniwinther): Cache this for later use. |
| 437 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) { |
| 438 DartType type = getFunctionType(procedure.function); |
| 439 List<ConstantValue> metadata = getMetadata(procedure.annotations); |
| 440 // TODO(johnniwinther): Provide the correct value for [isJsInterop]. |
| 441 return nativeBehaviorBuilder.buildMethodBehavior( |
| 442 type, metadata, typeLookup(resolveAsRaw: false), |
| 443 isJsInterop: false); |
| 444 } |
| 445 } |
| 446 |
| 447 /// Visitor that converts string literals and concatenations of string literals |
| 448 /// into the string value. |
| 449 class Stringifier extends ir.ExpressionVisitor<String> { |
| 450 @override |
| 451 String visitStringLiteral(ir.StringLiteral node) => node.value; |
| 452 |
| 453 @override |
| 454 String visitStringConcatenation(ir.StringConcatenation node) { |
| 455 StringBuffer sb = new StringBuffer(); |
| 456 for (ir.Expression expression in node.expressions) { |
| 457 String value = expression.accept(this); |
| 458 if (value == null) return null; |
| 459 sb.write(value); |
| 460 } |
| 461 return sb.toString(); |
| 462 } |
| 463 } |
| 464 |
| 465 /// Visitor that converts a kernel constant expression into a |
| 466 /// [ConstantExpression]. |
| 467 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { |
| 468 final bool requireConstant; |
| 469 final KernelToElementMapMixin elementAdapter; |
| 470 |
| 471 Constantifier(this.elementAdapter, {this.requireConstant: true}); |
| 472 |
| 473 CommonElements get _commonElements => elementAdapter.commonElements; |
| 474 |
| 475 ConstantExpression visit(ir.Expression node) { |
| 476 ConstantExpression constant = node.accept(this); |
| 477 if (constant == null && requireConstant) { |
| 478 throw new UnsupportedError( |
| 479 "No constant computed for $node (${node.runtimeType})"); |
| 480 } |
| 481 return constant; |
| 482 } |
| 483 |
| 484 ConstantExpression defaultExpression(ir.Expression node) { |
| 485 throw new UnimplementedError( |
| 486 'Unimplemented constant expression $node (${node.runtimeType})'); |
| 487 } |
| 488 |
| 489 List<ConstantExpression> _computeList(List<ir.Expression> expressions) { |
| 490 List<ConstantExpression> list = <ConstantExpression>[]; |
| 491 for (ir.Expression expression in expressions) { |
| 492 ConstantExpression constant = visit(expression); |
| 493 if (constant == null) return null; |
| 494 list.add(constant); |
| 495 } |
| 496 return list; |
| 497 } |
| 498 |
| 499 List<ConstantExpression> _computeArguments(ir.Arguments node) { |
| 500 List<ConstantExpression> arguments = <ConstantExpression>[]; |
| 501 for (ir.Expression argument in node.positional) { |
| 502 ConstantExpression constant = visit(argument); |
| 503 if (constant == null) return null; |
| 504 arguments.add(constant); |
| 505 } |
| 506 for (ir.NamedExpression argument in node.named) { |
| 507 ConstantExpression constant = visit(argument.value); |
| 508 if (constant == null) return null; |
| 509 arguments.add(constant); |
| 510 } |
| 511 return arguments; |
| 512 } |
| 513 |
| 514 ConstructedConstantExpression _computeConstructorInvocation( |
| 515 ir.Constructor target, ir.Arguments arguments) { |
| 516 return new ConstructedConstantExpression( |
| 517 elementAdapter.createInterfaceType( |
| 518 target.enclosingClass, arguments.types), |
| 519 elementAdapter.getConstructor(target), |
| 520 elementAdapter.getCallStructure(arguments), |
| 521 _computeArguments(arguments)); |
| 522 } |
| 523 |
| 524 @override |
| 525 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { |
| 526 return _computeConstructorInvocation(node.target, node.arguments); |
| 527 } |
| 528 |
| 529 @override |
| 530 ConstantExpression visitVariableGet(ir.VariableGet node) { |
| 531 if (node.variable.parent is ir.FunctionNode) { |
| 532 ir.FunctionNode function = node.variable.parent; |
| 533 int index = function.positionalParameters.indexOf(node.variable); |
| 534 if (index != -1) { |
| 535 return new PositionalArgumentReference(index); |
| 536 } else { |
| 537 assert(function.namedParameters.contains(node.variable)); |
| 538 return new NamedArgumentReference(node.variable.name); |
| 539 } |
| 540 } |
| 541 throw new UnimplementedError( |
| 542 'Unimplemented constant expression $node (${node.runtimeType})'); |
| 543 } |
| 544 |
| 545 @override |
| 546 ConstantExpression visitStaticGet(ir.StaticGet node) { |
| 547 if (node.target is ir.Field) { |
| 548 return new FieldConstantExpression(elementAdapter.getField(node.target)); |
| 549 } else if (node.target is ir.Procedure) { |
| 550 FunctionEntity function = elementAdapter.getMethod(node.target); |
| 551 DartType type = elementAdapter.getFunctionType(node.target.function); |
| 552 return new FunctionConstantExpression(function, type); |
| 553 } |
| 554 throw new UnimplementedError( |
| 555 'Unexpected constant expression $node (${node.runtimeType})'); |
| 556 } |
| 557 |
| 558 @override |
| 559 ConstantExpression visitNullLiteral(ir.NullLiteral node) { |
| 560 return new NullConstantExpression(); |
| 561 } |
| 562 |
| 563 @override |
| 564 ConstantExpression visitBoolLiteral(ir.BoolLiteral node) { |
| 565 return new BoolConstantExpression(node.value); |
| 566 } |
| 567 |
| 568 @override |
| 569 ConstantExpression visitIntLiteral(ir.IntLiteral node) { |
| 570 return new IntConstantExpression(node.value); |
| 571 } |
| 572 |
| 573 @override |
| 574 ConstantExpression visitDoubleLiteral(ir.DoubleLiteral node) { |
| 575 return new DoubleConstantExpression(node.value); |
| 576 } |
| 577 |
| 578 @override |
| 579 ConstantExpression visitStringLiteral(ir.StringLiteral node) { |
| 580 return new StringConstantExpression(node.value); |
| 581 } |
| 582 |
| 583 @override |
| 584 ConstantExpression visitSymbolLiteral(ir.SymbolLiteral node) { |
| 585 return new SymbolConstantExpression(node.value); |
| 586 } |
| 587 |
| 588 @override |
| 589 ConstantExpression visitStringConcatenation(ir.StringConcatenation node) { |
| 590 return new ConcatenateConstantExpression(_computeList(node.expressions)); |
| 591 } |
| 592 |
| 593 @override |
| 594 ConstantExpression visitMapLiteral(ir.MapLiteral node) { |
| 595 if (!node.isConst) { |
| 596 throw new UnimplementedError( |
| 597 'Unexpected constant expression $node (${node.runtimeType})'); |
| 598 } |
| 599 DartType keyType = elementAdapter.getDartType(node.keyType); |
| 600 DartType valueType = elementAdapter.getDartType(node.valueType); |
| 601 List<ConstantExpression> keys = <ConstantExpression>[]; |
| 602 List<ConstantExpression> values = <ConstantExpression>[]; |
| 603 for (ir.MapEntry entry in node.entries) { |
| 604 keys.add(visit(entry.key)); |
| 605 values.add(visit(entry.value)); |
| 606 } |
| 607 return new MapConstantExpression( |
| 608 _commonElements.mapType(keyType, valueType), keys, values); |
| 609 } |
| 610 |
| 611 @override |
| 612 ConstantExpression visitListLiteral(ir.ListLiteral node) { |
| 613 if (!node.isConst) { |
| 614 throw new UnimplementedError( |
| 615 'Unexpected constant expression $node (${node.runtimeType})'); |
| 616 } |
| 617 DartType elementType = elementAdapter.getDartType(node.typeArgument); |
| 618 List<ConstantExpression> values = <ConstantExpression>[]; |
| 619 for (ir.Expression value in node.expressions) { |
| 620 values.add(visit(value)); |
| 621 } |
| 622 return new ListConstantExpression( |
| 623 _commonElements.listType(elementType), values); |
| 624 } |
| 625 |
| 626 @override |
| 627 ConstantExpression visitConditionalExpression(ir.ConditionalExpression node) { |
| 628 ConstantExpression condition = visit(node.condition); |
| 629 ConstantExpression trueExp = visit(node.then); |
| 630 ConstantExpression falseExp = visit(node.otherwise); |
| 631 return new ConditionalConstantExpression(condition, trueExp, falseExp); |
| 632 } |
| 633 |
| 634 @override |
| 635 ConstantExpression visitPropertyGet(ir.PropertyGet node) { |
| 636 if (node.name.name != 'length') { |
| 637 throw new UnimplementedError( |
| 638 'Unexpected constant expression $node (${node.runtimeType})'); |
| 639 } |
| 640 ConstantExpression receiver = visit(node.receiver); |
| 641 return new StringLengthConstantExpression(receiver); |
| 642 } |
| 643 |
| 644 @override |
| 645 ConstantExpression visitMethodInvocation(ir.MethodInvocation node) { |
| 646 // Method invocations are generally not constant expressions but unary |
| 647 // and binary expressions are encoded as method invocations in kernel. |
| 648 if (node.arguments.named.isNotEmpty) { |
| 649 throw new UnimplementedError( |
| 650 'Unexpected constant expression $node (${node.runtimeType})'); |
| 651 } |
| 652 if (node.arguments.positional.length == 0) { |
| 653 UnaryOperator operator; |
| 654 if (node.name.name == UnaryOperator.NEGATE.selectorName) { |
| 655 operator = UnaryOperator.NEGATE; |
| 656 } else { |
| 657 operator = UnaryOperator.parse(node.name.name); |
| 658 } |
| 659 if (operator != null) { |
| 660 ConstantExpression expression = visit(node.receiver); |
| 661 return new UnaryConstantExpression(operator, expression); |
| 662 } |
| 663 } |
| 664 if (node.arguments.positional.length == 1) { |
| 665 BinaryOperator operator = BinaryOperator.parse(node.name.name); |
| 666 if (operator != null) { |
| 667 ConstantExpression left = visit(node.receiver); |
| 668 ConstantExpression right = visit(node.arguments.positional.single); |
| 669 return new BinaryConstantExpression(left, operator, right); |
| 670 } |
| 671 } |
| 672 throw new UnimplementedError( |
| 673 'Unexpected constant expression $node (${node.runtimeType})'); |
| 674 } |
| 675 |
| 676 @override |
| 677 ConstantExpression visitStaticInvocation(ir.StaticInvocation node) { |
| 678 MemberEntity member = elementAdapter.getMember(node.target); |
| 679 if (member == _commonElements.identicalFunction) { |
| 680 if (node.arguments.positional.length == 2 && |
| 681 node.arguments.named.isEmpty) { |
| 682 ConstantExpression left = visit(node.arguments.positional[0]); |
| 683 ConstantExpression right = visit(node.arguments.positional[1]); |
| 684 return new IdenticalConstantExpression(left, right); |
| 685 } |
| 686 } else if (member.name == 'fromEnvironment' && |
| 687 node.arguments.positional.length == 1) { |
| 688 ConstantExpression name = visit(node.arguments.positional.single); |
| 689 ConstantExpression defaultValue; |
| 690 if (node.arguments.named.length == 1) { |
| 691 if (node.arguments.named.single.name != 'defaultValue') { |
| 692 throw new UnimplementedError( |
| 693 'Unexpected constant expression $node (${node.runtimeType})'); |
| 694 } |
| 695 defaultValue = visit(node.arguments.named.single.value); |
| 696 } |
| 697 if (member.enclosingClass == _commonElements.boolClass) { |
| 698 return new BoolFromEnvironmentConstantExpression(name, defaultValue); |
| 699 } else if (member.enclosingClass == _commonElements.intClass) { |
| 700 return new IntFromEnvironmentConstantExpression(name, defaultValue); |
| 701 } else if (member.enclosingClass == _commonElements.stringClass) { |
| 702 return new StringFromEnvironmentConstantExpression(name, defaultValue); |
| 703 } |
| 704 } |
| 705 throw new UnimplementedError( |
| 706 'Unexpected constant expression $node (${node.runtimeType})'); |
| 707 } |
| 708 |
| 709 @override |
| 710 ConstantExpression visitLogicalExpression(ir.LogicalExpression node) { |
| 711 BinaryOperator operator = BinaryOperator.parse(node.operator); |
| 712 if (operator != null) { |
| 713 ConstantExpression left = visit(node.left); |
| 714 ConstantExpression right = visit(node.right); |
| 715 return new BinaryConstantExpression(left, operator, right); |
| 716 } |
| 717 throw new UnimplementedError( |
| 718 'Unexpected constant expression $node (${node.runtimeType})'); |
| 719 } |
| 720 |
| 721 /// Compute the [ConstantConstructor] corresponding to the const constructor |
| 722 /// [node]. |
| 723 ConstantConstructor computeConstantConstructor(ir.Constructor node) { |
| 724 assert(node.isConst); |
| 725 ir.Class cls = node.enclosingClass; |
| 726 InterfaceType type = elementAdapter.elementEnvironment |
| 727 .getThisType(elementAdapter.getClass(cls)); |
| 728 |
| 729 Map<dynamic, ConstantExpression> defaultValues = |
| 730 <dynamic, ConstantExpression>{}; |
| 731 int parameterIndex = 0; |
| 732 node.function.positionalParameters |
| 733 .forEach((ir.VariableDeclaration parameter) { |
| 734 if (parameterIndex >= node.function.requiredParameterCount) { |
| 735 if (parameter.initializer != null) { |
| 736 defaultValues[parameterIndex] = parameter.initializer.accept(this); |
| 737 } else { |
| 738 defaultValues[parameterIndex] = new NullConstantExpression(); |
| 739 } |
| 740 } |
| 741 parameterIndex++; |
| 233 }); | 742 }); |
| 234 } | 743 node.function.namedParameters.forEach((ir.VariableDeclaration parameter) { |
| 235 | 744 defaultValues[parameter.name] = parameter.initializer.accept(this); |
| 236 ParameterStructure _getParameterStructure(ir.FunctionNode node) { | 745 }); |
| 237 // TODO(johnniwinther): Cache the computed function type. | 746 |
| 238 int requiredParameters = node.requiredParameterCount; | 747 bool isRedirecting = node.initializers.length == 1 && |
| 239 int positionalParameters = node.positionalParameters.length; | 748 node.initializers.single is ir.RedirectingInitializer; |
| 240 List<String> namedParameters = | 749 |
| 241 node.namedParameters.map((p) => p.name).toList()..sort(); | 750 Map<FieldEntity, ConstantExpression> fieldMap = |
| 242 return new ParameterStructure( | 751 <FieldEntity, ConstantExpression>{}; |
| 243 requiredParameters, positionalParameters, namedParameters); | 752 |
| 244 } | 753 void registerField(ir.Field field, ConstantExpression constant) { |
| 245 | 754 fieldMap[elementAdapter.getField(field)] = constant; |
| 246 KConstructor _getConstructor(ir.Member node) { | 755 } |
| 247 return _constructorMap.putIfAbsent(node, () { | 756 |
| 248 int memberIndex = _memberList.length; | 757 if (!isRedirecting) { |
| 249 KConstructor constructor; | 758 for (ir.Field field in cls.fields) { |
| 250 KClass enclosingClass = _getClass(node.enclosingClass); | 759 if (field.initializer != null) { |
| 251 Name name = getName(node.name); | 760 registerField(field, field.initializer.accept(this)); |
| 252 bool isExternal = node.isExternal; | 761 } |
| 253 | 762 } |
| 254 ir.FunctionNode functionNode; | 763 } |
| 255 if (node is ir.Constructor) { | 764 |
| 256 functionNode = node.function; | 765 ConstructedConstantExpression superConstructorInvocation; |
| 257 constructor = new KGenerativeConstructor(memberIndex, enclosingClass, | 766 for (ir.Initializer initializer in node.initializers) { |
| 258 name, _getParameterStructure(functionNode), | 767 if (initializer is ir.FieldInitializer) { |
| 259 isExternal: isExternal, isConst: node.isConst); | 768 registerField(initializer.field, initializer.value.accept(this)); |
| 260 } else if (node is ir.Procedure) { | 769 } else if (initializer is ir.SuperInitializer) { |
| 261 functionNode = node.function; | 770 superConstructorInvocation = _computeConstructorInvocation( |
| 262 constructor = new KFactoryConstructor(memberIndex, enclosingClass, name, | 771 initializer.target, initializer.arguments); |
| 263 _getParameterStructure(functionNode), | 772 } else if (initializer is ir.RedirectingInitializer) { |
| 264 isExternal: isExternal, isConst: node.isConst); | 773 superConstructorInvocation = _computeConstructorInvocation( |
| 774 initializer.target, initializer.arguments); |
| 265 } else { | 775 } else { |
| 266 // TODO(johnniwinther): Convert `node.location` to a [SourceSpan]. | 776 throw new UnsupportedError( |
| 267 throw new SpannableAssertionFailure( | 777 'Unexpected initializer $node (${node.runtimeType})'); |
| 268 NO_LOCATION_SPANNABLE, "Unexpected constructor node: ${node}."); | 778 } |
| 269 } | 779 } |
| 270 _memberList.add(new _ConstructorData(node, functionNode)); | 780 if (isRedirecting) { |
| 271 return constructor; | 781 return new RedirectingGenerativeConstantConstructor( |
| 272 }); | 782 defaultValues, superConstructorInvocation); |
| 273 } | 783 } else { |
| 274 | 784 return new GenerativeConstantConstructor( |
| 275 KFunction _getMethod(ir.Procedure node) { | 785 type, defaultValues, fieldMap, superConstructorInvocation); |
| 276 return _methodMap.putIfAbsent(node, () { | 786 } |
| 277 int memberIndex = _memberList.length; | |
| 278 KLibrary library; | |
| 279 KClass enclosingClass; | |
| 280 if (node.enclosingClass != null) { | |
| 281 enclosingClass = _getClass(node.enclosingClass); | |
| 282 library = enclosingClass.library; | |
| 283 } else { | |
| 284 library = _getLibrary(node.enclosingLibrary); | |
| 285 } | |
| 286 Name name = getName(node.name); | |
| 287 bool isStatic = node.isStatic; | |
| 288 bool isExternal = node.isExternal; | |
| 289 bool isAbstract = node.isAbstract; | |
| 290 KFunction function; | |
| 291 switch (node.kind) { | |
| 292 case ir.ProcedureKind.Factory: | |
| 293 throw new UnsupportedError("Cannot create method from factory."); | |
| 294 case ir.ProcedureKind.Getter: | |
| 295 function = new KGetter(memberIndex, library, enclosingClass, name, | |
| 296 isStatic: isStatic, | |
| 297 isExternal: isExternal, | |
| 298 isAbstract: isAbstract); | |
| 299 break; | |
| 300 case ir.ProcedureKind.Method: | |
| 301 case ir.ProcedureKind.Operator: | |
| 302 function = new KMethod(memberIndex, library, enclosingClass, name, | |
| 303 _getParameterStructure(node.function), | |
| 304 isStatic: isStatic, | |
| 305 isExternal: isExternal, | |
| 306 isAbstract: isAbstract); | |
| 307 break; | |
| 308 case ir.ProcedureKind.Setter: | |
| 309 function = new KSetter( | |
| 310 memberIndex, library, enclosingClass, getName(node.name).setter, | |
| 311 isStatic: isStatic, | |
| 312 isExternal: isExternal, | |
| 313 isAbstract: isAbstract); | |
| 314 break; | |
| 315 } | |
| 316 _memberList.add(new _FunctionData(node, node.function)); | |
| 317 return function; | |
| 318 }); | |
| 319 } | |
| 320 | |
| 321 /// Returns the kernel [ir.Procedure] node for the [method]. | |
| 322 ir.Procedure _lookupProcedure(KFunction method) { | |
| 323 return _memberList[method.memberIndex].node; | |
| 324 } | |
| 325 | |
| 326 KField _getField(ir.Field node) { | |
| 327 return _fieldMap.putIfAbsent(node, () { | |
| 328 int memberIndex = _memberList.length; | |
| 329 KLibrary library; | |
| 330 KClass enclosingClass; | |
| 331 if (node.enclosingClass != null) { | |
| 332 enclosingClass = _getClass(node.enclosingClass); | |
| 333 library = enclosingClass.library; | |
| 334 } else { | |
| 335 library = _getLibrary(node.enclosingLibrary); | |
| 336 } | |
| 337 Name name = getName(node.name); | |
| 338 bool isStatic = node.isStatic; | |
| 339 _memberList.add(new _FieldData(node)); | |
| 340 return new KField(memberIndex, library, enclosingClass, name, | |
| 341 isStatic: isStatic, | |
| 342 isAssignable: node.isMutable, | |
| 343 isConst: node.isConst); | |
| 344 }); | |
| 345 } | |
| 346 | |
| 347 KLocalFunction _getLocal(ir.TreeNode node) { | |
| 348 return _localFunctionMap.putIfAbsent(node, () { | |
| 349 MemberEntity memberContext; | |
| 350 Entity executableContext; | |
| 351 ir.TreeNode parent = node.parent; | |
| 352 while (parent != null) { | |
| 353 if (parent is ir.Member) { | |
| 354 executableContext = memberContext = getMember(parent); | |
| 355 break; | |
| 356 } | |
| 357 if (parent is ir.FunctionDeclaration || | |
| 358 parent is ir.FunctionExpression) { | |
| 359 KLocalFunction localFunction = _getLocal(parent); | |
| 360 executableContext = localFunction; | |
| 361 memberContext = localFunction.memberContext; | |
| 362 break; | |
| 363 } | |
| 364 parent = parent.parent; | |
| 365 } | |
| 366 String name; | |
| 367 FunctionType functionType; | |
| 368 if (node is ir.FunctionDeclaration) { | |
| 369 name = node.variable.name; | |
| 370 functionType = getFunctionType(node.function); | |
| 371 } else if (node is ir.FunctionExpression) { | |
| 372 functionType = getFunctionType(node.function); | |
| 373 } | |
| 374 return new KLocalFunction( | |
| 375 name, memberContext, executableContext, functionType); | |
| 376 }); | |
| 377 } | |
| 378 | |
| 379 @override | |
| 380 DartType getDartType(ir.DartType type) => _typeConverter.convert(type); | |
| 381 | |
| 382 @override | |
| 383 InterfaceType createInterfaceType( | |
| 384 ir.Class cls, List<ir.DartType> typeArguments) { | |
| 385 return new InterfaceType(getClass(cls), getDartTypes(typeArguments)); | |
| 386 } | |
| 387 | |
| 388 @override | |
| 389 InterfaceType getInterfaceType(ir.InterfaceType type) => | |
| 390 _typeConverter.convert(type); | |
| 391 | |
| 392 @override | |
| 393 List<DartType> getDartTypes(List<ir.DartType> types) { | |
| 394 // TODO(johnniwinther): Add the type argument to the list literal when we | |
| 395 // no longer use resolution types. | |
| 396 List<DartType> list = /*<DartType>*/ []; | |
| 397 types.forEach((ir.DartType type) { | |
| 398 list.add(getDartType(type)); | |
| 399 }); | |
| 400 return list; | |
| 401 } | |
| 402 | |
| 403 void _ensureThisAndRawType(KClass cls, _KClassEnv env) { | |
| 404 if (env.thisType == null) { | |
| 405 ir.Class node = env.cls; | |
| 406 // TODO(johnniwinther): Add the type argument to the list literal when we | |
| 407 // no longer use resolution types. | |
| 408 if (node.typeParameters.isEmpty) { | |
| 409 env.thisType = | |
| 410 env.rawType = new InterfaceType(cls, const/*<DartType>*/ []); | |
| 411 } else { | |
| 412 env.thisType = new InterfaceType( | |
| 413 cls, | |
| 414 new List/*<DartType>*/ .generate(node.typeParameters.length, | |
| 415 (int index) { | |
| 416 return new TypeVariableType( | |
| 417 _getTypeVariable(node.typeParameters[index])); | |
| 418 })); | |
| 419 env.rawType = new InterfaceType( | |
| 420 cls, | |
| 421 new List/*<DartType>*/ .filled( | |
| 422 node.typeParameters.length, const DynamicType())); | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 InterfaceType _getThisType(KClass cls) { | |
| 428 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 429 _ensureThisAndRawType(cls, env); | |
| 430 return env.thisType; | |
| 431 } | |
| 432 | |
| 433 InterfaceType _getRawType(KClass cls) { | |
| 434 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 435 _ensureThisAndRawType(cls, env); | |
| 436 return env.rawType; | |
| 437 } | |
| 438 | |
| 439 InterfaceType _asInstanceOf(InterfaceType type, KClass cls) { | |
| 440 OrderedTypeSet orderedTypeSet = _getOrderedTypeSet(type.element); | |
| 441 InterfaceType supertype = | |
| 442 orderedTypeSet.asInstanceOf(cls, _getHierarchyDepth(cls)); | |
| 443 if (supertype != null) { | |
| 444 supertype = _substByContext(supertype, type); | |
| 445 } | |
| 446 return supertype; | |
| 447 } | |
| 448 | |
| 449 void _ensureSupertypes(KClass cls, _KClassEnv env) { | |
| 450 if (env.orderedTypeSet == null) { | |
| 451 _ensureThisAndRawType(cls, env); | |
| 452 | |
| 453 ir.Class node = env.cls; | |
| 454 | |
| 455 if (node.supertype == null) { | |
| 456 env.orderedTypeSet = new OrderedTypeSet.singleton(env.thisType); | |
| 457 } else { | |
| 458 InterfaceType processSupertype(ir.Supertype node) { | |
| 459 InterfaceType type = _typeConverter.visitSupertype(node); | |
| 460 KClass superclass = type.element; | |
| 461 _KClassEnv env = _classEnvs[superclass.classIndex]; | |
| 462 _ensureSupertypes(superclass, env); | |
| 463 return type; | |
| 464 } | |
| 465 | |
| 466 env.supertype = processSupertype(node.supertype); | |
| 467 LinkBuilder<InterfaceType> linkBuilder = | |
| 468 new LinkBuilder<InterfaceType>(); | |
| 469 if (node.mixedInType != null) { | |
| 470 linkBuilder | |
| 471 .addLast(env.mixedInType = processSupertype(node.mixedInType)); | |
| 472 } | |
| 473 node.implementedTypes.forEach((ir.Supertype supertype) { | |
| 474 linkBuilder.addLast(processSupertype(supertype)); | |
| 475 }); | |
| 476 Link<InterfaceType> interfaces = linkBuilder.toLink(); | |
| 477 OrderedTypeSetBuilder setBuilder = | |
| 478 new _KernelOrderedTypeSetBuilder(this, cls); | |
| 479 env.orderedTypeSet = | |
| 480 setBuilder.createOrderedTypeSet(env.supertype, interfaces); | |
| 481 } | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 OrderedTypeSet _getOrderedTypeSet(KClass cls) { | |
| 486 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 487 _ensureSupertypes(cls, env); | |
| 488 return env.orderedTypeSet; | |
| 489 } | |
| 490 | |
| 491 int _getHierarchyDepth(KClass cls) { | |
| 492 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 493 _ensureSupertypes(cls, env); | |
| 494 return env.orderedTypeSet.maxDepth; | |
| 495 } | |
| 496 | |
| 497 InterfaceType _substByContext(InterfaceType type, InterfaceType context) { | |
| 498 return type.subst( | |
| 499 context.typeArguments, _getThisType(context.element).typeArguments); | |
| 500 } | |
| 501 | |
| 502 InterfaceType _getSuperType(KClass cls) { | |
| 503 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 504 _ensureSupertypes(cls, env); | |
| 505 return env.supertype; | |
| 506 } | |
| 507 | |
| 508 bool _isUnnamedMixinApplication(KClass cls) { | |
| 509 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 510 _ensureSupertypes(cls, env); | |
| 511 return env.isUnnamedMixinApplication; | |
| 512 } | |
| 513 | |
| 514 void _forEachSupertype(KClass cls, void f(InterfaceType supertype)) { | |
| 515 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 516 _ensureSupertypes(cls, env); | |
| 517 env.orderedTypeSet.supertypes.forEach(f); | |
| 518 } | |
| 519 | |
| 520 void _forEachMixin(KClass cls, void f(ClassEntity mixin)) { | |
| 521 while (cls != null) { | |
| 522 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 523 _ensureSupertypes(cls, env); | |
| 524 if (env.mixedInType != null) { | |
| 525 f(env.mixedInType.element); | |
| 526 } | |
| 527 cls = env.supertype?.element; | |
| 528 } | |
| 529 } | |
| 530 | |
| 531 void _forEachClassMember( | |
| 532 KClass cls, void f(ClassEntity cls, MemberEntity member)) { | |
| 533 _KClassEnv env = _classEnvs[cls.classIndex]; | |
| 534 env.forEachMember((ir.Member member) { | |
| 535 f(cls, getMember(member)); | |
| 536 }); | |
| 537 _ensureSupertypes(cls, env); | |
| 538 if (env.supertype != null) { | |
| 539 _forEachClassMember(env.supertype.element, f); | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 @override | |
| 544 FunctionType getFunctionType(ir.FunctionNode node) { | |
| 545 DartType returnType = getDartType(node.returnType); | |
| 546 List<DartType> parameterTypes = /*<DartType>*/ []; | |
| 547 List<DartType> optionalParameterTypes = /*<DartType>*/ []; | |
| 548 for (ir.VariableDeclaration variable in node.positionalParameters) { | |
| 549 if (parameterTypes.length == node.requiredParameterCount) { | |
| 550 optionalParameterTypes.add(getDartType(variable.type)); | |
| 551 } else { | |
| 552 parameterTypes.add(getDartType(variable.type)); | |
| 553 } | |
| 554 } | |
| 555 List<String> namedParameters = <String>[]; | |
| 556 List<DartType> namedParameterTypes = /*<DartType>*/ []; | |
| 557 List<ir.VariableDeclaration> sortedNamedParameters = | |
| 558 node.namedParameters.toList()..sort((a, b) => a.name.compareTo(b.name)); | |
| 559 for (ir.VariableDeclaration variable in sortedNamedParameters) { | |
| 560 namedParameters.add(variable.name); | |
| 561 namedParameterTypes.add(getDartType(variable.type)); | |
| 562 } | |
| 563 return new FunctionType(returnType, parameterTypes, optionalParameterTypes, | |
| 564 namedParameters, namedParameterTypes); | |
| 565 } | |
| 566 | |
| 567 LibraryEntity getLibrary(ir.Library node) => _getLibrary(node); | |
| 568 | |
| 569 ir.Library getKernelLibrary(KLibrary entity) => | |
| 570 _libraryEnvs[entity.libraryIndex].library; | |
| 571 | |
| 572 ir.Class getKernelClass(KClass entity) => _classEnvs[entity.classIndex].cls; | |
| 573 | |
| 574 @override | |
| 575 Local getLocalFunction(ir.TreeNode node) => _getLocal(node); | |
| 576 | |
| 577 @override | |
| 578 ClassEntity getClass(ir.Class node) => _getClass(node); | |
| 579 | |
| 580 @override | |
| 581 FieldEntity getField(ir.Field node) => _getField(node); | |
| 582 | |
| 583 TypeVariableEntity getTypeVariable(ir.TypeParameter node) => | |
| 584 _getTypeVariable(node); | |
| 585 | |
| 586 @override | |
| 587 FunctionEntity getMethod(ir.Procedure node) => _getMethod(node); | |
| 588 | |
| 589 @override | |
| 590 MemberEntity getMember(ir.Member node) { | |
| 591 if (node is ir.Field) { | |
| 592 return _getField(node); | |
| 593 } else if (node is ir.Constructor) { | |
| 594 return _getConstructor(node); | |
| 595 } else if (node is ir.Procedure) { | |
| 596 if (node.kind == ir.ProcedureKind.Factory) { | |
| 597 return _getConstructor(node); | |
| 598 } else { | |
| 599 return _getMethod(node); | |
| 600 } | |
| 601 } | |
| 602 throw new UnsupportedError("Unexpected member: $node"); | |
| 603 } | |
| 604 | |
| 605 @override | |
| 606 FunctionEntity getConstructor(ir.Member node) => _getConstructor(node); | |
| 607 | |
| 608 ConstantConstructor _getConstructorConstant(KConstructor constructor) { | |
| 609 _ConstructorData data = _memberList[constructor.memberIndex]; | |
| 610 return data.getConstructorConstant(this, constructor); | |
| 611 } | |
| 612 | |
| 613 ConstantExpression _getFieldConstant(KField field) { | |
| 614 _FieldData data = _memberList[field.memberIndex]; | |
| 615 return data.getFieldConstant(this, field); | |
| 616 } | |
| 617 | |
| 618 FunctionType _getFunctionType(KFunction function) { | |
| 619 _FunctionData data = _memberList[function.memberIndex]; | |
| 620 return data.getFunctionType(this); | |
| 621 } | |
| 622 | |
| 623 ResolutionImpact computeWorldImpact(KMember member) { | |
| 624 return _memberList[member.memberIndex].getWorldImpact(this); | |
| 625 } | 787 } |
| 626 } | 788 } |
| 627 | |
| 628 /// Environment for fast lookup of program libraries. | |
| 629 class _KEnv { | |
| 630 final Set<ir.Program> programs = new Set<ir.Program>(); | |
| 631 | |
| 632 Map<Uri, _KLibraryEnv> _libraryMap; | |
| 633 | |
| 634 /// TODO(johnniwinther): Handle arbitrary load order if needed. | |
| 635 ir.Member get mainMethod => programs.first?.mainMethod; | |
| 636 | |
| 637 void addProgram(ir.Program program) { | |
| 638 if (programs.add(program)) { | |
| 639 if (_libraryMap != null) { | |
| 640 _addLibraries(program); | |
| 641 } | |
| 642 } | |
| 643 } | |
| 644 | |
| 645 void _addLibraries(ir.Program program) { | |
| 646 for (ir.Library library in program.libraries) { | |
| 647 _libraryMap[library.importUri] = new _KLibraryEnv(library); | |
| 648 } | |
| 649 } | |
| 650 | |
| 651 void _ensureLibraryMap() { | |
| 652 if (_libraryMap == null) { | |
| 653 _libraryMap = <Uri, _KLibraryEnv>{}; | |
| 654 for (ir.Program program in programs) { | |
| 655 _addLibraries(program); | |
| 656 } | |
| 657 } | |
| 658 } | |
| 659 | |
| 660 /// Return the [_KLibraryEnv] for the library with the canonical [uri]. | |
| 661 _KLibraryEnv lookupLibrary(Uri uri) { | |
| 662 _ensureLibraryMap(); | |
| 663 return _libraryMap[uri]; | |
| 664 } | |
| 665 | |
| 666 /// Calls [f] for each library in this environment. | |
| 667 void forEachLibrary(void f(_KLibraryEnv library)) { | |
| 668 _ensureLibraryMap(); | |
| 669 _libraryMap.values.forEach(f); | |
| 670 } | |
| 671 | |
| 672 /// Returns the number of libraries in this environment. | |
| 673 int get length { | |
| 674 _ensureLibraryMap(); | |
| 675 return _libraryMap.length; | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 /// Environment for fast lookup of library classes and members. | |
| 680 class _KLibraryEnv { | |
| 681 final ir.Library library; | |
| 682 | |
| 683 Map<String, _KClassEnv> _classMap; | |
| 684 Map<String, ir.Member> _memberMap; | |
| 685 Map<String, ir.Member> _setterMap; | |
| 686 | |
| 687 _KLibraryEnv(this.library); | |
| 688 | |
| 689 void _ensureClassMap() { | |
| 690 if (_classMap == null) { | |
| 691 _classMap = <String, _KClassEnv>{}; | |
| 692 for (ir.Class cls in library.classes) { | |
| 693 _classMap[cls.name] = new _KClassEnv(cls); | |
| 694 } | |
| 695 } | |
| 696 } | |
| 697 | |
| 698 /// Return the [_KClassEnv] for the class [name] in [library]. | |
| 699 _KClassEnv lookupClass(String name) { | |
| 700 _ensureClassMap(); | |
| 701 return _classMap[name]; | |
| 702 } | |
| 703 | |
| 704 /// Calls [f] for each class in this library. | |
| 705 void forEachClass(void f(_KClassEnv cls)) { | |
| 706 _ensureClassMap(); | |
| 707 _classMap.values.forEach(f); | |
| 708 } | |
| 709 | |
| 710 /// Return the [ir.Member] for the member [name] in [library]. | |
| 711 ir.Member lookupMember(String name, {bool setter: false}) { | |
| 712 if (_memberMap == null) { | |
| 713 _memberMap = <String, ir.Member>{}; | |
| 714 _setterMap = <String, ir.Member>{}; | |
| 715 for (ir.Member member in library.members) { | |
| 716 if (member is ir.Procedure) { | |
| 717 if (member.kind == ir.ProcedureKind.Setter) { | |
| 718 _setterMap[member.name.name] = member; | |
| 719 } else { | |
| 720 _memberMap[member.name.name] = member; | |
| 721 } | |
| 722 } else if (member is ir.Field) { | |
| 723 _memberMap[member.name.name] = member; | |
| 724 if (member.isMutable) { | |
| 725 _setterMap[member.name.name] = member; | |
| 726 } | |
| 727 } else { | |
| 728 throw new SpannableAssertionFailure( | |
| 729 NO_LOCATION_SPANNABLE, "Unexpected library member node: $member"); | |
| 730 } | |
| 731 } | |
| 732 } | |
| 733 return _memberMap[name]; | |
| 734 } | |
| 735 } | |
| 736 | |
| 737 /// Environment for fast lookup of class members. | |
| 738 class _KClassEnv { | |
| 739 final ir.Class cls; | |
| 740 final bool isUnnamedMixinApplication; | |
| 741 | |
| 742 InterfaceType thisType; | |
| 743 InterfaceType rawType; | |
| 744 InterfaceType supertype; | |
| 745 InterfaceType mixedInType; | |
| 746 OrderedTypeSet orderedTypeSet; | |
| 747 | |
| 748 Map<String, ir.Member> _constructorMap; | |
| 749 Map<String, ir.Member> _memberMap; | |
| 750 Map<String, ir.Member> _setterMap; | |
| 751 | |
| 752 Iterable<ConstantValue> _metadata; | |
| 753 | |
| 754 _KClassEnv(this.cls) | |
| 755 // TODO(johnniwinther): Change this to use a property on [cls] when such | |
| 756 // is added to kernel. | |
| 757 : isUnnamedMixinApplication = cls.name.contains('+'); | |
| 758 | |
| 759 void _ensureMaps() { | |
| 760 if (_memberMap == null) { | |
| 761 _memberMap = <String, ir.Member>{}; | |
| 762 _setterMap = <String, ir.Member>{}; | |
| 763 _constructorMap = <String, ir.Member>{}; | |
| 764 | |
| 765 void addMembers(ir.Class c) { | |
| 766 for (ir.Member member in c.members) { | |
| 767 if (member is ir.Constructor || | |
| 768 member is ir.Procedure && | |
| 769 member.kind == ir.ProcedureKind.Factory) { | |
| 770 _constructorMap[member.name.name] = member; | |
| 771 } else if (member is ir.Procedure) { | |
| 772 if (member.kind == ir.ProcedureKind.Setter) { | |
| 773 _setterMap[member.name.name] = member; | |
| 774 } else { | |
| 775 _memberMap[member.name.name] = member; | |
| 776 } | |
| 777 } else if (member is ir.Field) { | |
| 778 _memberMap[member.name.name] = member; | |
| 779 if (member.isMutable) { | |
| 780 _setterMap[member.name.name] = member; | |
| 781 } | |
| 782 _memberMap[member.name.name] = member; | |
| 783 } else { | |
| 784 throw new SpannableAssertionFailure( | |
| 785 NO_LOCATION_SPANNABLE, "Unexpected class member node: $member"); | |
| 786 } | |
| 787 } | |
| 788 } | |
| 789 | |
| 790 if (cls.mixedInClass != null) { | |
| 791 addMembers(cls.mixedInClass); | |
| 792 } | |
| 793 addMembers(cls); | |
| 794 } | |
| 795 } | |
| 796 | |
| 797 /// Return the [ir.Member] for the member [name] in [library]. | |
| 798 ir.Member lookupMember(String name, {bool setter: false}) { | |
| 799 _ensureMaps(); | |
| 800 return setter ? _setterMap[name] : _memberMap[name]; | |
| 801 } | |
| 802 | |
| 803 /// Return the [ir.Member] for the member [name] in [library]. | |
| 804 ir.Member lookupConstructor(String name) { | |
| 805 _ensureMaps(); | |
| 806 return _constructorMap[name]; | |
| 807 } | |
| 808 | |
| 809 void forEachMember(f(ir.Member member)) { | |
| 810 _ensureMaps(); | |
| 811 _memberMap.values.forEach(f); | |
| 812 for (ir.Member member in _setterMap.values) { | |
| 813 if (member is ir.Procedure) { | |
| 814 f(member); | |
| 815 } else { | |
| 816 // Skip fields; these are also in _memberMap. | |
| 817 } | |
| 818 } | |
| 819 } | |
| 820 | |
| 821 Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) { | |
| 822 return _metadata ??= elementMap.getMetadata(cls.annotations); | |
| 823 } | |
| 824 } | |
| 825 | |
| 826 class _MemberData { | |
| 827 final ir.Member node; | |
| 828 Iterable<ConstantValue> _metadata; | |
| 829 | |
| 830 _MemberData(this.node); | |
| 831 | |
| 832 ResolutionImpact getWorldImpact(KernelToElementMap elementMap) { | |
| 833 return buildKernelImpact(node, elementMap); | |
| 834 } | |
| 835 | |
| 836 Iterable<ConstantValue> getMetadata(KernelToElementMap elementMap) { | |
| 837 return _metadata ??= elementMap.getMetadata(node.annotations); | |
| 838 } | |
| 839 } | |
| 840 | |
| 841 class _FunctionData extends _MemberData { | |
| 842 final ir.FunctionNode functionNode; | |
| 843 FunctionType _type; | |
| 844 CallStructure _callStructure; | |
| 845 | |
| 846 _FunctionData(ir.Member node, this.functionNode) : super(node); | |
| 847 | |
| 848 FunctionType getFunctionType(KernelToElementMap elementMap) { | |
| 849 return _type ??= elementMap.getFunctionType(functionNode); | |
| 850 } | |
| 851 | |
| 852 CallStructure get callStructure { | |
| 853 return _callStructure ??= new CallStructure( | |
| 854 functionNode.positionalParameters.length + | |
| 855 functionNode.namedParameters.length, | |
| 856 functionNode.namedParameters.map((d) => d.name).toList()); | |
| 857 } | |
| 858 } | |
| 859 | |
| 860 class _ConstructorData extends _FunctionData { | |
| 861 ConstantConstructor _constantConstructor; | |
| 862 | |
| 863 _ConstructorData(ir.Member node, ir.FunctionNode functionNode) | |
| 864 : super(node, functionNode); | |
| 865 | |
| 866 ConstantConstructor getConstructorConstant( | |
| 867 KernelToElementMap elementMap, KConstructor constructor) { | |
| 868 if (_constantConstructor == null) { | |
| 869 if (node is ir.Constructor && constructor.isConst) { | |
| 870 _constantConstructor = | |
| 871 new Constantifier(elementMap).computeConstantConstructor(node); | |
| 872 } else { | |
| 873 throw new SpannableAssertionFailure( | |
| 874 constructor, | |
| 875 "Unexpected constructor $constructor in " | |
| 876 "KernelWorldBuilder._getConstructorConstant"); | |
| 877 } | |
| 878 } | |
| 879 return _constantConstructor; | |
| 880 } | |
| 881 } | |
| 882 | |
| 883 class _FieldData extends _MemberData { | |
| 884 ConstantExpression _constant; | |
| 885 | |
| 886 _FieldData(ir.Field node) : super(node); | |
| 887 | |
| 888 ir.Field get node => super.node; | |
| 889 | |
| 890 ConstantExpression getFieldConstant( | |
| 891 KernelToElementMap elementMap, KField field) { | |
| 892 if (_constant == null) { | |
| 893 if (node.isConst) { | |
| 894 _constant = new Constantifier(elementMap).visit(node.initializer); | |
| 895 } else { | |
| 896 throw new SpannableAssertionFailure( | |
| 897 field, | |
| 898 "Unexpected field $field in " | |
| 899 "KernelWorldBuilder._getConstructorConstant"); | |
| 900 } | |
| 901 } | |
| 902 return _constant; | |
| 903 } | |
| 904 } | |
| 905 | |
| 906 class KernelElementEnvironment implements ElementEnvironment { | |
| 907 final KernelToElementMap elementMap; | |
| 908 | |
| 909 KernelElementEnvironment(this.elementMap); | |
| 910 | |
| 911 @override | |
| 912 DartType get dynamicType => const DynamicType(); | |
| 913 | |
| 914 @override | |
| 915 LibraryEntity get mainLibrary => elementMap._mainLibrary; | |
| 916 | |
| 917 @override | |
| 918 FunctionEntity get mainFunction => elementMap._mainFunction; | |
| 919 | |
| 920 @override | |
| 921 Iterable<LibraryEntity> get libraries => elementMap._libraries; | |
| 922 | |
| 923 @override | |
| 924 InterfaceType getThisType(ClassEntity cls) { | |
| 925 return elementMap._getThisType(cls); | |
| 926 } | |
| 927 | |
| 928 @override | |
| 929 InterfaceType getRawType(ClassEntity cls) { | |
| 930 return elementMap._getRawType(cls); | |
| 931 } | |
| 932 | |
| 933 @override | |
| 934 bool isGenericClass(ClassEntity cls) { | |
| 935 return getThisType(cls).typeArguments.isNotEmpty; | |
| 936 } | |
| 937 | |
| 938 @override | |
| 939 DartType getTypeVariableBound(TypeVariableEntity typeVariable) { | |
| 940 throw new UnimplementedError( | |
| 941 'KernelElementEnvironment.getTypeVariableBound'); | |
| 942 } | |
| 943 | |
| 944 @override | |
| 945 InterfaceType createInterfaceType( | |
| 946 ClassEntity cls, List<DartType> typeArguments) { | |
| 947 return new InterfaceType(cls, typeArguments); | |
| 948 } | |
| 949 | |
| 950 @override | |
| 951 bool isSubtype(DartType a, DartType b) { | |
| 952 return elementMap.types.isSubtype(a, b); | |
| 953 } | |
| 954 | |
| 955 @override | |
| 956 FunctionType getFunctionType(KFunction function) { | |
| 957 return elementMap._getFunctionType(function); | |
| 958 } | |
| 959 | |
| 960 @override | |
| 961 FunctionType getLocalFunctionType(KLocalFunction function) { | |
| 962 return function.functionType; | |
| 963 } | |
| 964 | |
| 965 @override | |
| 966 DartType getUnaliasedType(DartType type) => type; | |
| 967 | |
| 968 @override | |
| 969 ConstructorEntity lookupConstructor(ClassEntity cls, String name, | |
| 970 {bool required: false}) { | |
| 971 ConstructorEntity constructor = elementMap.lookupConstructor(cls, name); | |
| 972 if (constructor == null && required) { | |
| 973 throw new SpannableAssertionFailure( | |
| 974 CURRENT_ELEMENT_SPANNABLE, | |
| 975 "The constructor '$name' was not found in class '${cls.name}' " | |
| 976 "in library ${cls.library.canonicalUri}."); | |
| 977 } | |
| 978 return constructor; | |
| 979 } | |
| 980 | |
| 981 @override | |
| 982 MemberEntity lookupClassMember(ClassEntity cls, String name, | |
| 983 {bool setter: false, bool required: false}) { | |
| 984 MemberEntity member = | |
| 985 elementMap.lookupClassMember(cls, name, setter: setter); | |
| 986 if (member == null && required) { | |
| 987 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, | |
| 988 "The member '$name' was not found in ${cls.name}."); | |
| 989 } | |
| 990 return member; | |
| 991 } | |
| 992 | |
| 993 @override | |
| 994 ClassEntity getSuperClass(ClassEntity cls, | |
| 995 {bool skipUnnamedMixinApplications: false}) { | |
| 996 ClassEntity superclass = elementMap._getSuperType(cls)?.element; | |
| 997 if (skipUnnamedMixinApplications) { | |
| 998 while (superclass != null && | |
| 999 elementMap._isUnnamedMixinApplication(superclass)) { | |
| 1000 superclass = elementMap._getSuperType(superclass)?.element; | |
| 1001 } | |
| 1002 } | |
| 1003 return superclass; | |
| 1004 } | |
| 1005 | |
| 1006 @override | |
| 1007 void forEachSupertype(ClassEntity cls, void f(InterfaceType supertype)) { | |
| 1008 elementMap._forEachSupertype(cls, f); | |
| 1009 } | |
| 1010 | |
| 1011 @override | |
| 1012 void forEachMixin(ClassEntity cls, void f(ClassEntity mixin)) { | |
| 1013 elementMap._forEachMixin(cls, f); | |
| 1014 } | |
| 1015 | |
| 1016 @override | |
| 1017 void forEachClassMember( | |
| 1018 ClassEntity cls, void f(ClassEntity declarer, MemberEntity member)) { | |
| 1019 elementMap._forEachClassMember(cls, f); | |
| 1020 } | |
| 1021 | |
| 1022 @override | |
| 1023 MemberEntity lookupLibraryMember(LibraryEntity library, String name, | |
| 1024 {bool setter: false, bool required: false}) { | |
| 1025 MemberEntity member = | |
| 1026 elementMap.lookupLibraryMember(library, name, setter: setter); | |
| 1027 if (member == null && required) { | |
| 1028 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, | |
| 1029 "The member '${name}' was not found in library '${library.name}'."); | |
| 1030 } | |
| 1031 return member; | |
| 1032 } | |
| 1033 | |
| 1034 @override | |
| 1035 ClassEntity lookupClass(LibraryEntity library, String name, | |
| 1036 {bool required: false}) { | |
| 1037 ClassEntity cls = elementMap.lookupClass(library, name); | |
| 1038 if (cls == null && required) { | |
| 1039 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, | |
| 1040 "The class '$name' was not found in library '${library.name}'."); | |
| 1041 } | |
| 1042 return cls; | |
| 1043 } | |
| 1044 | |
| 1045 @override | |
| 1046 void forEachClass(KLibrary library, void f(ClassEntity cls)) { | |
| 1047 elementMap._forEachClass(library, f); | |
| 1048 } | |
| 1049 | |
| 1050 @override | |
| 1051 LibraryEntity lookupLibrary(Uri uri, {bool required: false}) { | |
| 1052 LibraryEntity library = elementMap.lookupLibrary(uri); | |
| 1053 if (library == null && required) { | |
| 1054 throw new SpannableAssertionFailure( | |
| 1055 CURRENT_ELEMENT_SPANNABLE, "The library '$uri' was not found."); | |
| 1056 } | |
| 1057 return library; | |
| 1058 } | |
| 1059 | |
| 1060 @override | |
| 1061 CallStructure getCallStructure(KFunction function) { | |
| 1062 _FunctionData data = elementMap._memberList[function.memberIndex]; | |
| 1063 return data.callStructure; | |
| 1064 } | |
| 1065 | |
| 1066 @override | |
| 1067 bool isDeferredLoadLibraryGetter(KMember member) { | |
| 1068 // TODO(johnniwinther): Support these. | |
| 1069 return false; | |
| 1070 } | |
| 1071 | |
| 1072 @override | |
| 1073 Iterable<ConstantValue> getMemberMetadata(KMember member) { | |
| 1074 _MemberData memberData = elementMap._memberList[member.memberIndex]; | |
| 1075 return memberData.getMetadata(elementMap); | |
| 1076 } | |
| 1077 } | |
| 1078 | |
| 1079 /// Visitor that converts kernel dart types into [DartType]. | |
| 1080 class DartTypeConverter extends ir.DartTypeVisitor<DartType> { | |
| 1081 final KernelToElementMap elementAdapter; | |
| 1082 bool topLevel = true; | |
| 1083 | |
| 1084 DartTypeConverter(this.elementAdapter); | |
| 1085 | |
| 1086 DartType convert(ir.DartType type) { | |
| 1087 topLevel = true; | |
| 1088 return type.accept(this); | |
| 1089 } | |
| 1090 | |
| 1091 /// Visit a inner type. | |
| 1092 DartType visitType(ir.DartType type) { | |
| 1093 topLevel = false; | |
| 1094 return type.accept(this); | |
| 1095 } | |
| 1096 | |
| 1097 InterfaceType visitSupertype(ir.Supertype node) { | |
| 1098 ClassEntity cls = elementAdapter.getClass(node.classNode); | |
| 1099 return new InterfaceType(cls, visitTypes(node.typeArguments)); | |
| 1100 } | |
| 1101 | |
| 1102 List<DartType> visitTypes(List<ir.DartType> types) { | |
| 1103 topLevel = false; | |
| 1104 return new List.generate( | |
| 1105 types.length, (int index) => types[index].accept(this)); | |
| 1106 } | |
| 1107 | |
| 1108 @override | |
| 1109 DartType visitTypeParameterType(ir.TypeParameterType node) { | |
| 1110 return new TypeVariableType(elementAdapter.getTypeVariable(node.parameter)); | |
| 1111 } | |
| 1112 | |
| 1113 @override | |
| 1114 DartType visitFunctionType(ir.FunctionType node) { | |
| 1115 return new FunctionType( | |
| 1116 visitType(node.returnType), | |
| 1117 visitTypes(node.positionalParameters | |
| 1118 .take(node.requiredParameterCount) | |
| 1119 .toList()), | |
| 1120 visitTypes(node.positionalParameters | |
| 1121 .skip(node.requiredParameterCount) | |
| 1122 .toList()), | |
| 1123 node.namedParameters.map((n) => n.name).toList(), | |
| 1124 node.namedParameters.map((n) => visitType(n.type)).toList()); | |
| 1125 } | |
| 1126 | |
| 1127 @override | |
| 1128 DartType visitInterfaceType(ir.InterfaceType node) { | |
| 1129 ClassEntity cls = elementAdapter.getClass(node.classNode); | |
| 1130 return new InterfaceType(cls, visitTypes(node.typeArguments)); | |
| 1131 } | |
| 1132 | |
| 1133 @override | |
| 1134 DartType visitVoidType(ir.VoidType node) { | |
| 1135 return const VoidType(); | |
| 1136 } | |
| 1137 | |
| 1138 @override | |
| 1139 DartType visitDynamicType(ir.DynamicType node) { | |
| 1140 return const DynamicType(); | |
| 1141 } | |
| 1142 | |
| 1143 @override | |
| 1144 DartType visitInvalidType(ir.InvalidType node) { | |
| 1145 if (topLevel) { | |
| 1146 throw new UnimplementedError( | |
| 1147 "Outermost invalid types not currently supported"); | |
| 1148 } | |
| 1149 // Nested invalid types are treated as `dynamic`. | |
| 1150 return const DynamicType(); | |
| 1151 } | |
| 1152 } | |
| 1153 | |
| 1154 /// [native.BehaviorBuilder] for kernel based elements. | |
| 1155 class KernelBehaviorBuilder extends native.BehaviorBuilder { | |
| 1156 final CommonElements commonElements; | |
| 1157 | |
| 1158 KernelBehaviorBuilder(this.commonElements); | |
| 1159 | |
| 1160 @override | |
| 1161 bool get trustJSInteropTypeAnnotations { | |
| 1162 throw new UnimplementedError( | |
| 1163 "KernelNativeBehaviorComputer.trustJSInteropTypeAnnotations"); | |
| 1164 } | |
| 1165 | |
| 1166 @override | |
| 1167 DiagnosticReporter get reporter { | |
| 1168 throw new UnimplementedError("KernelNativeBehaviorComputer.reporter"); | |
| 1169 } | |
| 1170 | |
| 1171 @override | |
| 1172 NativeData get nativeData { | |
| 1173 throw new UnimplementedError("KernelNativeBehaviorComputer.nativeData"); | |
| 1174 } | |
| 1175 } | |
| 1176 | |
| 1177 /// Constant environment mapping [ConstantExpression]s to [ConstantValue]s using | |
| 1178 /// [_EvaluationEnvironment] for the evaluation. | |
| 1179 class KernelConstantEnvironment implements ConstantEnvironment { | |
| 1180 KernelToElementMap _worldBuilder; | |
| 1181 Map<ConstantExpression, ConstantValue> _valueMap = | |
| 1182 <ConstantExpression, ConstantValue>{}; | |
| 1183 | |
| 1184 KernelConstantEnvironment(this._worldBuilder); | |
| 1185 | |
| 1186 @override | |
| 1187 ConstantSystem get constantSystem => const JavaScriptConstantSystem(); | |
| 1188 | |
| 1189 @override | |
| 1190 ConstantValue getConstantValueForVariable(VariableElement element) { | |
| 1191 throw new UnimplementedError( | |
| 1192 "KernelConstantEnvironment.getConstantValueForVariable"); | |
| 1193 } | |
| 1194 | |
| 1195 @override | |
| 1196 ConstantValue getConstantValue(ConstantExpression expression) { | |
| 1197 return _valueMap.putIfAbsent(expression, () { | |
| 1198 return expression.evaluate( | |
| 1199 new _EvaluationEnvironment(_worldBuilder), constantSystem); | |
| 1200 }); | |
| 1201 } | |
| 1202 | |
| 1203 @override | |
| 1204 bool hasConstantValue(ConstantExpression expression) { | |
| 1205 throw new UnimplementedError("KernelConstantEnvironment.hasConstantValue"); | |
| 1206 } | |
| 1207 } | |
| 1208 | |
| 1209 /// Evaluation environment used for computing [ConstantValue]s for | |
| 1210 /// kernel based [ConstantExpression]s. | |
| 1211 class _EvaluationEnvironment implements EvaluationEnvironment { | |
| 1212 final KernelToElementMap _elementMap; | |
| 1213 | |
| 1214 _EvaluationEnvironment(this._elementMap); | |
| 1215 | |
| 1216 @override | |
| 1217 CommonElements get commonElements => _elementMap.commonElements; | |
| 1218 | |
| 1219 @override | |
| 1220 InterfaceType substByContext(InterfaceType base, InterfaceType target) { | |
| 1221 return _elementMap._substByContext(base, target); | |
| 1222 } | |
| 1223 | |
| 1224 @override | |
| 1225 ConstantConstructor getConstructorConstant(ConstructorEntity constructor) { | |
| 1226 return _elementMap._getConstructorConstant(constructor); | |
| 1227 } | |
| 1228 | |
| 1229 @override | |
| 1230 ConstantExpression getFieldConstant(FieldEntity field) { | |
| 1231 return _elementMap._getFieldConstant(field); | |
| 1232 } | |
| 1233 | |
| 1234 @override | |
| 1235 ConstantExpression getLocalConstant(Local local) { | |
| 1236 throw new UnimplementedError("_EvaluationEnvironment.getLocalConstant"); | |
| 1237 } | |
| 1238 | |
| 1239 @override | |
| 1240 String readFromEnvironment(String name) { | |
| 1241 return _elementMap._environment.valueOf(name); | |
| 1242 } | |
| 1243 } | |
| 1244 | |
| 1245 class KernelResolutionWorldBuilder extends KernelResolutionWorldBuilderBase { | |
| 1246 final KernelToElementMap elementMap; | |
| 1247 | |
| 1248 KernelResolutionWorldBuilder(this.elementMap, NativeBasicData nativeBasicData, | |
| 1249 SelectorConstraintsStrategy selectorConstraintsStrategy) | |
| 1250 : super(elementMap.elementEnvironment, elementMap.commonElements, | |
| 1251 nativeBasicData, selectorConstraintsStrategy); | |
| 1252 | |
| 1253 @override | |
| 1254 Iterable<InterfaceType> getSupertypes(ClassEntity cls) { | |
| 1255 return elementMap._getOrderedTypeSet(cls).supertypes; | |
| 1256 } | |
| 1257 | |
| 1258 @override | |
| 1259 ClassEntity getSuperClass(ClassEntity cls) { | |
| 1260 return elementMap._getSuperType(cls)?.element; | |
| 1261 } | |
| 1262 | |
| 1263 @override | |
| 1264 bool implementsFunction(ClassEntity cls) { | |
| 1265 // TODO(johnniwinther): Implement this. | |
| 1266 return false; | |
| 1267 } | |
| 1268 | |
| 1269 @override | |
| 1270 int getHierarchyDepth(ClassEntity cls) { | |
| 1271 return elementMap._getHierarchyDepth(cls); | |
| 1272 } | |
| 1273 | |
| 1274 @override | |
| 1275 ClassEntity getAppliedMixin(ClassEntity cls) { | |
| 1276 // TODO(johnniwinther): Implement this. | |
| 1277 return null; | |
| 1278 } | |
| 1279 | |
| 1280 @override | |
| 1281 bool validateClass(ClassEntity cls) => true; | |
| 1282 | |
| 1283 @override | |
| 1284 bool checkClass(ClassEntity cls) => true; | |
| 1285 } | |
| 1286 | |
| 1287 // Interface for testing equivalence of Kernel-based entities. | |
| 1288 class WorldDeconstructionForTesting { | |
| 1289 final KernelToElementMap elementMap; | |
| 1290 | |
| 1291 WorldDeconstructionForTesting(this.elementMap); | |
| 1292 | |
| 1293 KClass getSuperclassForClass(KClass cls) { | |
| 1294 _KClassEnv env = elementMap._classEnvs[cls.classIndex]; | |
| 1295 ir.Supertype supertype = env.cls.supertype; | |
| 1296 if (supertype == null) return null; | |
| 1297 return elementMap.getClass(supertype.classNode); | |
| 1298 } | |
| 1299 | |
| 1300 bool isUnnamedMixinApplication(KClass cls) { | |
| 1301 return elementMap._isUnnamedMixinApplication(cls); | |
| 1302 } | |
| 1303 | |
| 1304 InterfaceType getMixinTypeForClass(KClass cls) { | |
| 1305 _KClassEnv env = elementMap._classEnvs[cls.classIndex]; | |
| 1306 ir.Supertype mixedInType = env.cls.mixedInType; | |
| 1307 if (mixedInType == null) return null; | |
| 1308 return elementMap.createInterfaceType( | |
| 1309 mixedInType.classNode, mixedInType.typeArguments); | |
| 1310 } | |
| 1311 } | |
| OLD | NEW |