| 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 import 'package:js_runtime/shared/embedded_names.dart'; | |
| 6 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 7 | 6 |
| 8 import '../closure.dart'; | 7 import '../closure.dart'; |
| 9 import '../common.dart'; | 8 import '../common.dart'; |
| 10 import '../common/names.dart'; | |
| 11 import '../constants/constructors.dart'; | |
| 12 import '../constants/expressions.dart'; | |
| 13 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
| 14 import '../common_elements.dart'; | 10 import '../common_elements.dart'; |
| 15 import '../elements/entities.dart'; | 11 import '../elements/entities.dart'; |
| 16 import '../elements/jumps.dart'; | 12 import '../elements/jumps.dart'; |
| 17 import '../elements/names.dart'; | 13 import '../elements/names.dart'; |
| 18 import '../elements/operators.dart'; | |
| 19 import '../elements/types.dart'; | 14 import '../elements/types.dart'; |
| 20 import '../js/js.dart' as js; | 15 import '../js/js.dart' as js; |
| 21 import '../js_backend/backend.dart' show JavaScriptBackend; | |
| 22 import '../js_backend/namer.dart'; | 16 import '../js_backend/namer.dart'; |
| 23 import '../js_emitter/code_emitter_task.dart'; | 17 import '../js_emitter/code_emitter_task.dart'; |
| 24 import '../native/native.dart' as native; | 18 import '../native/native.dart' as native; |
| 25 import '../types/types.dart'; | 19 import '../types/types.dart'; |
| 26 import '../universe/call_structure.dart'; | 20 import '../universe/call_structure.dart'; |
| 27 import '../universe/selector.dart'; | 21 import '../universe/selector.dart'; |
| 28 import '../world.dart'; | 22 import '../world.dart'; |
| 29 import 'kernel_debug.dart'; | |
| 30 | 23 |
| 31 /// Interface that translates between Kernel IR nodes and entities. | 24 /// Interface that translates between Kernel IR nodes and entities. |
| 32 abstract class KernelToElementMap { | 25 abstract class KernelToElementMap { |
| 33 /// Access to the commonly used elements and types. | 26 /// Access to the commonly used elements and types. |
| 34 CommonElements get commonElements; | 27 CommonElements get commonElements; |
| 35 | 28 |
| 36 /// Returns the [DartType] corresponding to [type]. | 29 /// Returns the [DartType] corresponding to [type]. |
| 37 DartType getDartType(ir.DartType type); | 30 DartType getDartType(ir.DartType type); |
| 38 | 31 |
| 32 /// Returns the [InterfaceType] corresponding to [type]. |
| 33 InterfaceType getInterfaceType(ir.InterfaceType type); |
| 34 |
| 35 /// Returns the [FunctionType] of the [node]. |
| 36 FunctionType getFunctionType(ir.FunctionNode node); |
| 37 |
| 39 /// Return the [InterfaceType] corresponding to the [cls] with the given | 38 /// Return the [InterfaceType] corresponding to the [cls] with the given |
| 40 /// [typeArguments]. | 39 /// [typeArguments]. |
| 41 InterfaceType createInterfaceType( | 40 InterfaceType createInterfaceType( |
| 42 ir.Class cls, List<ir.DartType> typeArguments); | 41 ir.Class cls, List<ir.DartType> typeArguments); |
| 43 | 42 |
| 43 /// Returns the [CallStructure] corresponding to the [arguments]. |
| 44 CallStructure getCallStructure(ir.Arguments arguments); |
| 45 |
| 44 /// Returns the [Selector] corresponding to the invocation or getter/setter | 46 /// Returns the [Selector] corresponding to the invocation or getter/setter |
| 45 /// access of [node]. | 47 /// access of [node]. |
| 46 Selector getSelector(ir.Expression node); | 48 Selector getSelector(ir.Expression node); |
| 47 | 49 |
| 48 /// Returns the [MemberEntity] corresponding to the member [node]. | 50 /// Returns the [MemberEntity] corresponding to the member [node]. |
| 49 MemberEntity getMember(ir.Member node); | 51 MemberEntity getMember(ir.Member node); |
| 50 | 52 |
| 51 /// Returns the [FunctionEntity] corresponding to the procedure [node]. | 53 /// Returns the [FunctionEntity] corresponding to the procedure [node]. |
| 52 FunctionEntity getMethod(ir.Procedure node); | 54 FunctionEntity getMethod(ir.Procedure node); |
| 53 | 55 |
| 54 /// Returns the [ConstructorEntity] corresponding to the generative or factory | 56 /// Returns the [ConstructorEntity] corresponding to the generative or factory |
| 55 /// constructor [node]. | 57 /// constructor [node]. |
| 56 ConstructorEntity getConstructor(ir.Member node); | 58 ConstructorEntity getConstructor(ir.Member node); |
| 57 | 59 |
| 58 /// Returns the [FieldEntity] corresponding to the field [node]. | 60 /// Returns the [FieldEntity] corresponding to the field [node]. |
| 59 FieldEntity getField(ir.Field node); | 61 FieldEntity getField(ir.Field node); |
| 60 | 62 |
| 63 /// Returns the [ClassEntity] corresponding to the class [node]. |
| 64 ClassEntity getClass(ir.Class node); |
| 65 |
| 61 /// Returns the [Local] corresponding to the [node]. The node must be either | 66 /// Returns the [Local] corresponding to the [node]. The node must be either |
| 62 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression]. | 67 /// a [ir.FunctionDeclaration] or [ir.FunctionExpression]. |
| 63 Local getLocalFunction(ir.TreeNode node); | 68 Local getLocalFunction(ir.TreeNode node); |
| 64 | 69 |
| 65 /// Returns the super [MemberEntity] for a super invocation, get or set of | 70 /// Returns the super [MemberEntity] for a super invocation, get or set of |
| 66 /// [name] from the member [context]. | 71 /// [name] from the member [context]. |
| 67 /// | 72 /// |
| 68 /// The IR doesn't always resolve super accesses to the corresponding | 73 /// The IR doesn't always resolve super accesses to the corresponding |
| 69 /// [target]. If not, the target is computed using [name] and [setter] from | 74 /// [target]. If not, the target is computed using [name] and [setter] from |
| 70 /// the enclosing class of [context]. | 75 /// the enclosing class of [context]. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 96 /// Computes the [ConstantValue] for the constant [expression]. | 101 /// Computes the [ConstantValue] for the constant [expression]. |
| 97 // TODO(johnniwinther): Move to [KernelToElementMapForBuilding]. This is only | 102 // TODO(johnniwinther): Move to [KernelToElementMapForBuilding]. This is only |
| 98 // used in impact builder for symbol constants. | 103 // used in impact builder for symbol constants. |
| 99 ConstantValue getConstantValue(ir.Expression expression, | 104 ConstantValue getConstantValue(ir.Expression expression, |
| 100 {bool requireConstant: true, bool implicitNull: false}); | 105 {bool requireConstant: true, bool implicitNull: false}); |
| 101 } | 106 } |
| 102 | 107 |
| 103 /// Interface that translates between Kernel IR nodes and entities used for | 108 /// Interface that translates between Kernel IR nodes and entities used for |
| 104 /// computing the [WorldImpact] for members. | 109 /// computing the [WorldImpact] for members. |
| 105 abstract class KernelToElementMapForImpact extends KernelToElementMap { | 110 abstract class KernelToElementMapForImpact extends KernelToElementMap { |
| 106 /// Returns the [CallStructure] corresponding to the [arguments]. | |
| 107 CallStructure getCallStructure(ir.Arguments arguments); | |
| 108 | |
| 109 /// Returns the [ConstructorEntity] corresponding to a super initializer in | 111 /// Returns the [ConstructorEntity] corresponding to a super initializer in |
| 110 /// [constructor]. | 112 /// [constructor]. |
| 111 /// | 113 /// |
| 112 /// The IR resolves super initializers to a [target] up in the type hierarchy. | 114 /// The IR resolves super initializers to a [target] up in the type hierarchy. |
| 113 /// Most of the time, the result of this function will be the entity | 115 /// Most of the time, the result of this function will be the entity |
| 114 /// corresponding to that target. In the presence of unnamed mixins, this | 116 /// corresponding to that target. In the presence of unnamed mixins, this |
| 115 /// function returns an entity for an intermediate synthetic constructor that | 117 /// function returns an entity for an intermediate synthetic constructor that |
| 116 /// kernel doesn't explicitly represent. | 118 /// kernel doesn't explicitly represent. |
| 117 /// | 119 /// |
| 118 /// For example: | 120 /// For example: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 146 /// [JS_INTERCEPTOR_CONSTANT] function, if any. | 148 /// [JS_INTERCEPTOR_CONSTANT] function, if any. |
| 147 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node); | 149 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node); |
| 148 } | 150 } |
| 149 | 151 |
| 150 /// Interface that translates between Kernel IR nodes and entities used for | 152 /// Interface that translates between Kernel IR nodes and entities used for |
| 151 /// global type inference and building the SSA graph for members. | 153 /// global type inference and building the SSA graph for members. |
| 152 abstract class KernelToElementMapForBuilding implements KernelToElementMap { | 154 abstract class KernelToElementMapForBuilding implements KernelToElementMap { |
| 153 /// [ElementEnvironment] for library, class and member lookup. | 155 /// [ElementEnvironment] for library, class and member lookup. |
| 154 ElementEnvironment get elementEnvironment; | 156 ElementEnvironment get elementEnvironment; |
| 155 | 157 |
| 156 /// Returns the [FunctionType] of the [node]. | |
| 157 FunctionType getFunctionType(ir.FunctionNode node); | |
| 158 | |
| 159 /// Returns the list of [DartType]s corresponding to [types]. | 158 /// Returns the list of [DartType]s corresponding to [types]. |
| 160 List<DartType> getDartTypes(List<ir.DartType> types); | 159 List<DartType> getDartTypes(List<ir.DartType> types); |
| 161 | 160 |
| 162 /// Returns the [InterfaceType] corresponding to [type]. | |
| 163 InterfaceType getInterfaceType(ir.InterfaceType type); | |
| 164 | |
| 165 /// Returns the kernel IR node that defines the [member]. | 161 /// Returns the kernel IR node that defines the [member]. |
| 166 ir.Node getMemberNode(covariant MemberEntity member); | 162 ir.Node getMemberNode(covariant MemberEntity member); |
| 167 | 163 |
| 168 /// Returns the [ClassEntity] corresponding to the class [node]. | |
| 169 ClassEntity getClass(ir.Class node); | |
| 170 | |
| 171 /// Returns the [LibraryEntity] corresponding to the library [node]. | 164 /// Returns the [LibraryEntity] corresponding to the library [node]. |
| 172 LibraryEntity getLibrary(ir.Library node); | 165 LibraryEntity getLibrary(ir.Library node); |
| 173 | 166 |
| 174 /// Returns the [js.Template] for the `JsBuiltin` [constant] value. | 167 /// Returns the [js.Template] for the `JsBuiltin` [constant] value. |
| 175 js.Template getJsBuiltinTemplate( | 168 js.Template getJsBuiltinTemplate( |
| 176 ConstantValue constant, CodeEmitterTask emitter); | 169 ConstantValue constant, CodeEmitterTask emitter); |
| 177 | 170 |
| 178 /// Return the [ConstantValue] the initial value of [field] or `null` if | 171 /// Return the [ConstantValue] the initial value of [field] or `null` if |
| 179 /// the initializer is not a constant expression. | 172 /// the initializer is not a constant expression. |
| 180 ConstantValue getFieldConstantValue(ir.Field field); | 173 ConstantValue getFieldConstantValue(ir.Field field); |
| 181 | 174 |
| 182 /// Returns the `noSuchMethod` [FunctionEntity] call from a | 175 /// Returns the `noSuchMethod` [FunctionEntity] call from a |
| 183 /// `super.noSuchMethod` invocation within [cls]. | 176 /// `super.noSuchMethod` invocation within [cls]. |
| 184 FunctionEntity getSuperNoSuchMethod(ClassEntity cls); | 177 FunctionEntity getSuperNoSuchMethod(ClassEntity cls); |
| 185 | 178 |
| 186 /// Returns a [Spannable] for a message pointing to the IR [node] in the | 179 /// Returns a [Spannable] for a message pointing to the IR [node] in the |
| 187 /// context of [member]. | 180 /// context of [member]. |
| 188 Spannable getSpannable(MemberEntity member, ir.Node node); | 181 Spannable getSpannable(MemberEntity member, ir.Node node); |
| 189 } | 182 } |
| 190 | 183 |
| 191 /// Kinds of foreign functions. | 184 /// Kinds of foreign functions. |
| 192 enum ForeignKind { | 185 enum ForeignKind { |
| 193 JS, | 186 JS, |
| 194 JS_BUILTIN, | 187 JS_BUILTIN, |
| 195 JS_EMBEDDED_GLOBAL, | 188 JS_EMBEDDED_GLOBAL, |
| 196 JS_INTERCEPTOR_CONSTANT, | 189 JS_INTERCEPTOR_CONSTANT, |
| 197 NONE, | 190 NONE, |
| 198 } | 191 } |
| 199 | 192 |
| 200 abstract class KernelToElementMapMixin | |
| 201 implements KernelToElementMapForBuilding { | |
| 202 DiagnosticReporter get reporter; | |
| 203 native.BehaviorBuilder get nativeBehaviorBuilder; | |
| 204 ConstantValue computeConstantValue(ConstantExpression constant, | |
| 205 {bool requireConstant: true}); | |
| 206 | |
| 207 @override | |
| 208 Name getName(ir.Name name) { | |
| 209 return new Name( | |
| 210 name.name, name.isPrivate ? getLibrary(name.library) : null); | |
| 211 } | |
| 212 | |
| 213 CallStructure getCallStructure(ir.Arguments arguments) { | |
| 214 int argumentCount = arguments.positional.length + arguments.named.length; | |
| 215 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); | |
| 216 return new CallStructure(argumentCount, namedArguments); | |
| 217 } | |
| 218 | |
| 219 @override | |
| 220 Selector getSelector(ir.Expression node) { | |
| 221 // TODO(efortuna): This is screaming for a common interface between | |
| 222 // PropertyGet and SuperPropertyGet (and same for *Get). Talk to kernel | |
| 223 // folks. | |
| 224 if (node is ir.PropertyGet) { | |
| 225 return getGetterSelector(node.name); | |
| 226 } | |
| 227 if (node is ir.SuperPropertyGet) { | |
| 228 return getGetterSelector(node.name); | |
| 229 } | |
| 230 if (node is ir.PropertySet) { | |
| 231 return getSetterSelector(node.name); | |
| 232 } | |
| 233 if (node is ir.SuperPropertySet) { | |
| 234 return getSetterSelector(node.name); | |
| 235 } | |
| 236 if (node is ir.InvocationExpression) { | |
| 237 return getInvocationSelector(node); | |
| 238 } | |
| 239 throw new SpannableAssertionFailure( | |
| 240 CURRENT_ELEMENT_SPANNABLE, | |
| 241 "Can only get the selector for a property get or an invocation: " | |
| 242 "${node}"); | |
| 243 } | |
| 244 | |
| 245 Selector getInvocationSelector(ir.InvocationExpression invocation) { | |
| 246 Name name = getName(invocation.name); | |
| 247 SelectorKind kind; | |
| 248 if (Selector.isOperatorName(name.text)) { | |
| 249 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) { | |
| 250 kind = SelectorKind.INDEX; | |
| 251 } else { | |
| 252 kind = SelectorKind.OPERATOR; | |
| 253 } | |
| 254 } else { | |
| 255 kind = SelectorKind.CALL; | |
| 256 } | |
| 257 | |
| 258 CallStructure callStructure = getCallStructure(invocation.arguments); | |
| 259 return new Selector(kind, name, callStructure); | |
| 260 } | |
| 261 | |
| 262 Selector getGetterSelector(ir.Name irName) { | |
| 263 Name name = new Name( | |
| 264 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); | |
| 265 return new Selector.getter(name); | |
| 266 } | |
| 267 | |
| 268 Selector getSetterSelector(ir.Name irName) { | |
| 269 Name name = new Name( | |
| 270 irName.name, irName.isPrivate ? getLibrary(irName.library) : null); | |
| 271 return new Selector.setter(name); | |
| 272 } | |
| 273 | |
| 274 ConstantValue getConstantValue(ir.Expression node, | |
| 275 {bool requireConstant: true, bool implicitNull: false}) { | |
| 276 ConstantExpression constant; | |
| 277 if (node == null) { | |
| 278 if (!implicitNull) { | |
| 279 throw new SpannableAssertionFailure( | |
| 280 CURRENT_ELEMENT_SPANNABLE, 'No expression for constant.'); | |
| 281 } | |
| 282 constant = new NullConstantExpression(); | |
| 283 } else { | |
| 284 constant = | |
| 285 new Constantifier(this, requireConstant: requireConstant).visit(node); | |
| 286 } | |
| 287 if (constant == null) { | |
| 288 if (requireConstant) { | |
| 289 throw new UnsupportedError( | |
| 290 'No constant for ${DebugPrinter.prettyPrint(node)}'); | |
| 291 } | |
| 292 return null; | |
| 293 } | |
| 294 return computeConstantValue(constant, requireConstant: requireConstant); | |
| 295 } | |
| 296 | |
| 297 /// Converts [annotations] into a list of [ConstantValue]s. | |
| 298 List<ConstantValue> getMetadata(List<ir.Expression> annotations) { | |
| 299 if (annotations.isEmpty) return const <ConstantValue>[]; | |
| 300 List<ConstantValue> metadata = <ConstantValue>[]; | |
| 301 annotations.forEach((ir.Expression node) { | |
| 302 metadata.add(getConstantValue(node)); | |
| 303 }); | |
| 304 return metadata; | |
| 305 } | |
| 306 | |
| 307 /// Returns `true` is [node] has a `@Native(...)` annotation. | |
| 308 // TODO(johnniwinther): Cache this for later use. | |
| 309 bool isNativeClass(ir.Class node) { | |
| 310 for (ir.Expression annotation in node.annotations) { | |
| 311 if (annotation is ir.ConstructorInvocation) { | |
| 312 FunctionEntity target = getConstructor(annotation.target); | |
| 313 if (target.enclosingClass == commonElements.nativeAnnotationClass) { | |
| 314 return true; | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 return false; | |
| 319 } | |
| 320 | |
| 321 /// Compute the kind of foreign helper function called by [node], if any. | |
| 322 ForeignKind getForeignKind(ir.StaticInvocation node) { | |
| 323 if (isForeignLibrary(node.target.enclosingLibrary)) { | |
| 324 switch (node.target.name.name) { | |
| 325 case JavaScriptBackend.JS: | |
| 326 return ForeignKind.JS; | |
| 327 case JavaScriptBackend.JS_BUILTIN: | |
| 328 return ForeignKind.JS_BUILTIN; | |
| 329 case JavaScriptBackend.JS_EMBEDDED_GLOBAL: | |
| 330 return ForeignKind.JS_EMBEDDED_GLOBAL; | |
| 331 case JavaScriptBackend.JS_INTERCEPTOR_CONSTANT: | |
| 332 return ForeignKind.JS_INTERCEPTOR_CONSTANT; | |
| 333 } | |
| 334 } | |
| 335 return ForeignKind.NONE; | |
| 336 } | |
| 337 | |
| 338 /// Return `true` if [node] is the `dart:_foreign_helper` library. | |
| 339 bool isForeignLibrary(ir.Library node) { | |
| 340 return node.importUri == Uris.dart__foreign_helper; | |
| 341 } | |
| 342 | |
| 343 /// Looks up [typeName] for use in the spec-string of a `JS` called. | |
| 344 // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling | |
| 345 // the `ForeignResolver`. | |
| 346 // TODO(johnniwinther): Cache the result to avoid redundant lookups? | |
| 347 native.TypeLookup typeLookup({bool resolveAsRaw: true}) { | |
| 348 DartType lookup(String typeName, {bool required}) { | |
| 349 DartType findIn(Uri uri) { | |
| 350 LibraryEntity library = elementEnvironment.lookupLibrary(uri); | |
| 351 if (library != null) { | |
| 352 ClassEntity cls = elementEnvironment.lookupClass(library, typeName); | |
| 353 if (cls != null) { | |
| 354 // TODO(johnniwinther): Align semantics. | |
| 355 return resolveAsRaw | |
| 356 ? elementEnvironment.getRawType(cls) | |
| 357 : elementEnvironment.getThisType(cls); | |
| 358 } | |
| 359 } | |
| 360 return null; | |
| 361 } | |
| 362 | |
| 363 // TODO(johnniwinther): Narrow the set of lookups base on the depending | |
| 364 // library. | |
| 365 DartType type = findIn(Uris.dart_core); | |
| 366 type ??= findIn(Uris.dart__js_helper); | |
| 367 type ??= findIn(Uris.dart__interceptors); | |
| 368 type ??= findIn(Uris.dart__isolate_helper); | |
| 369 type ??= findIn(Uris.dart__native_typed_data); | |
| 370 type ??= findIn(Uris.dart_collection); | |
| 371 type ??= findIn(Uris.dart_math); | |
| 372 type ??= findIn(Uris.dart_html); | |
| 373 type ??= findIn(Uris.dart_html_common); | |
| 374 type ??= findIn(Uris.dart_svg); | |
| 375 type ??= findIn(Uris.dart_web_audio); | |
| 376 type ??= findIn(Uris.dart_web_gl); | |
| 377 type ??= findIn(Uris.dart_web_sql); | |
| 378 type ??= findIn(Uris.dart_indexed_db); | |
| 379 type ??= findIn(Uris.dart_typed_data); | |
| 380 if (type == null && required) { | |
| 381 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, | |
| 382 MessageKind.GENERIC, {'text': "Type '$typeName' not found."}); | |
| 383 } | |
| 384 return type; | |
| 385 } | |
| 386 | |
| 387 return lookup; | |
| 388 } | |
| 389 | |
| 390 String _getStringArgument(ir.StaticInvocation node, int index) { | |
| 391 return node.arguments.positional[index].accept(new Stringifier()); | |
| 392 } | |
| 393 | |
| 394 /// Computes the [native.NativeBehavior] for a call to the [JS] function. | |
| 395 // TODO(johnniwinther): Cache this for later use. | |
| 396 native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) { | |
| 397 if (node.arguments.positional.length < 2 || | |
| 398 node.arguments.named.isNotEmpty) { | |
| 399 reporter.reportErrorMessage( | |
| 400 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS); | |
| 401 return new native.NativeBehavior(); | |
| 402 } | |
| 403 String specString = _getStringArgument(node, 0); | |
| 404 if (specString == null) { | |
| 405 reporter.reportErrorMessage( | |
| 406 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST); | |
| 407 return new native.NativeBehavior(); | |
| 408 } | |
| 409 | |
| 410 String codeString = _getStringArgument(node, 1); | |
| 411 if (codeString == null) { | |
| 412 reporter.reportErrorMessage( | |
| 413 CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND); | |
| 414 return new native.NativeBehavior(); | |
| 415 } | |
| 416 | |
| 417 return native.NativeBehavior.ofJsCall( | |
| 418 specString, | |
| 419 codeString, | |
| 420 typeLookup(resolveAsRaw: true), | |
| 421 CURRENT_ELEMENT_SPANNABLE, | |
| 422 reporter, | |
| 423 commonElements); | |
| 424 } | |
| 425 | |
| 426 /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] | |
| 427 /// function. | |
| 428 // TODO(johnniwinther): Cache this for later use. | |
| 429 native.NativeBehavior getNativeBehaviorForJsBuiltinCall( | |
| 430 ir.StaticInvocation node) { | |
| 431 if (node.arguments.positional.length < 1) { | |
| 432 reporter.internalError( | |
| 433 CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type."); | |
| 434 return new native.NativeBehavior(); | |
| 435 } | |
| 436 if (node.arguments.positional.length < 2) { | |
| 437 reporter.internalError( | |
| 438 CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name."); | |
| 439 return new native.NativeBehavior(); | |
| 440 } | |
| 441 String specString = _getStringArgument(node, 0); | |
| 442 if (specString == null) { | |
| 443 reporter.internalError( | |
| 444 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | |
| 445 return new native.NativeBehavior(); | |
| 446 } | |
| 447 return native.NativeBehavior.ofJsBuiltinCall( | |
| 448 specString, | |
| 449 typeLookup(resolveAsRaw: true), | |
| 450 CURRENT_ELEMENT_SPANNABLE, | |
| 451 reporter, | |
| 452 commonElements); | |
| 453 } | |
| 454 | |
| 455 /// Computes the [native.NativeBehavior] for a call to the | |
| 456 /// [JS_EMBEDDED_GLOBAL] function. | |
| 457 // TODO(johnniwinther): Cache this for later use. | |
| 458 native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall( | |
| 459 ir.StaticInvocation node) { | |
| 460 if (node.arguments.positional.length < 1) { | |
| 461 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
| 462 "JS embedded global expression has no type."); | |
| 463 return new native.NativeBehavior(); | |
| 464 } | |
| 465 if (node.arguments.positional.length < 2) { | |
| 466 reporter.internalError( | |
| 467 CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name."); | |
| 468 return new native.NativeBehavior(); | |
| 469 } | |
| 470 if (node.arguments.positional.length > 2 || | |
| 471 node.arguments.named.isNotEmpty) { | |
| 472 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
| 473 "JS embedded global has more than 2 arguments."); | |
| 474 return new native.NativeBehavior(); | |
| 475 } | |
| 476 String specString = _getStringArgument(node, 0); | |
| 477 if (specString == null) { | |
| 478 reporter.internalError( | |
| 479 CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument."); | |
| 480 return new native.NativeBehavior(); | |
| 481 } | |
| 482 return native.NativeBehavior.ofJsEmbeddedGlobalCall( | |
| 483 specString, | |
| 484 typeLookup(resolveAsRaw: true), | |
| 485 CURRENT_ELEMENT_SPANNABLE, | |
| 486 reporter, | |
| 487 commonElements); | |
| 488 } | |
| 489 | |
| 490 /// Computes the [InterfaceType] referenced by a call to the | |
| 491 /// [JS_INTERCEPTOR_CONSTANT] function, if any. | |
| 492 InterfaceType getInterfaceTypeForJsInterceptorCall(ir.StaticInvocation node) { | |
| 493 if (node.arguments.positional.length != 1 || | |
| 494 node.arguments.named.isNotEmpty) { | |
| 495 reporter.reportErrorMessage(CURRENT_ELEMENT_SPANNABLE, | |
| 496 MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT); | |
| 497 } | |
| 498 ir.Node argument = node.arguments.positional.first; | |
| 499 if (argument is ir.TypeLiteral && argument.type is ir.InterfaceType) { | |
| 500 return getInterfaceType(argument.type); | |
| 501 } | |
| 502 return null; | |
| 503 } | |
| 504 | |
| 505 /// Computes the native behavior for reading the native [field]. | |
| 506 // TODO(johnniwinther): Cache this for later use. | |
| 507 native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field, | |
| 508 {bool isJsInterop}) { | |
| 509 DartType type = getDartType(field.type); | |
| 510 List<ConstantValue> metadata = getMetadata(field.annotations); | |
| 511 return nativeBehaviorBuilder.buildFieldLoadBehavior( | |
| 512 type, metadata, typeLookup(resolveAsRaw: false), | |
| 513 isJsInterop: isJsInterop); | |
| 514 } | |
| 515 | |
| 516 /// Computes the native behavior for writing to the native [field]. | |
| 517 // TODO(johnniwinther): Cache this for later use. | |
| 518 native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) { | |
| 519 DartType type = getDartType(field.type); | |
| 520 return nativeBehaviorBuilder.buildFieldStoreBehavior(type); | |
| 521 } | |
| 522 | |
| 523 /// Computes the native behavior for calling [procedure]. | |
| 524 // TODO(johnniwinther): Cache this for later use. | |
| 525 native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure, | |
| 526 {bool isJsInterop}) { | |
| 527 DartType type = getFunctionType(procedure.function); | |
| 528 List<ConstantValue> metadata = getMetadata(procedure.annotations); | |
| 529 return nativeBehaviorBuilder.buildMethodBehavior( | |
| 530 type, metadata, typeLookup(resolveAsRaw: false), | |
| 531 isJsInterop: isJsInterop); | |
| 532 } | |
| 533 | |
| 534 @override | |
| 535 FunctionEntity getSuperNoSuchMethod(ClassEntity cls) { | |
| 536 while (cls != null) { | |
| 537 cls = elementEnvironment.getSuperClass(cls); | |
| 538 MemberEntity member = | |
| 539 elementEnvironment.lookupClassMember(cls, Identifiers.noSuchMethod_); | |
| 540 if (member != null) { | |
| 541 if (member.isFunction) { | |
| 542 FunctionEntity function = member; | |
| 543 if (function.parameterStructure.positionalParameters >= 1) { | |
| 544 return function; | |
| 545 } | |
| 546 } | |
| 547 // If [member] is not a valid `noSuchMethod` the target is | |
| 548 // `Object.superNoSuchMethod`. | |
| 549 break; | |
| 550 } | |
| 551 } | |
| 552 FunctionEntity function = elementEnvironment.lookupClassMember( | |
| 553 commonElements.objectClass, Identifiers.noSuchMethod_); | |
| 554 assert(function != null, | |
| 555 failedAt(cls, "No super noSuchMethod found for class $cls.")); | |
| 556 return function; | |
| 557 } | |
| 558 | |
| 559 js.Name getNameForJsGetName(ConstantValue constant, Namer namer) { | |
| 560 int index = _extractEnumIndexFromConstantValue( | |
| 561 constant, commonElements.jsGetNameEnum); | |
| 562 if (index == null) return null; | |
| 563 return namer.getNameForJsGetName( | |
| 564 CURRENT_ELEMENT_SPANNABLE, JsGetName.values[index]); | |
| 565 } | |
| 566 | |
| 567 js.Template getJsBuiltinTemplate( | |
| 568 ConstantValue constant, CodeEmitterTask emitter) { | |
| 569 int index = _extractEnumIndexFromConstantValue( | |
| 570 constant, commonElements.jsBuiltinEnum); | |
| 571 if (index == null) return null; | |
| 572 return emitter.builtinTemplateFor(JsBuiltin.values[index]); | |
| 573 } | |
| 574 | |
| 575 int _extractEnumIndexFromConstantValue( | |
| 576 ConstantValue constant, ClassEntity classElement) { | |
| 577 if (constant is ConstructedConstantValue) { | |
| 578 if (constant.type.element == classElement) { | |
| 579 assert(constant.fields.length == 1 || constant.fields.length == 2); | |
| 580 ConstantValue indexConstant = constant.fields.values.first; | |
| 581 if (indexConstant is IntConstantValue) { | |
| 582 return indexConstant.primitiveValue; | |
| 583 } | |
| 584 } | |
| 585 } | |
| 586 return null; | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 /// Visitor that converts string literals and concatenations of string literals | |
| 591 /// into the string value. | |
| 592 class Stringifier extends ir.ExpressionVisitor<String> { | |
| 593 @override | |
| 594 String visitStringLiteral(ir.StringLiteral node) => node.value; | |
| 595 | |
| 596 @override | |
| 597 String visitStringConcatenation(ir.StringConcatenation node) { | |
| 598 StringBuffer sb = new StringBuffer(); | |
| 599 for (ir.Expression expression in node.expressions) { | |
| 600 String value = expression.accept(this); | |
| 601 if (value == null) return null; | |
| 602 sb.write(value); | |
| 603 } | |
| 604 return sb.toString(); | |
| 605 } | |
| 606 } | |
| 607 | |
| 608 /// Visitor that converts a kernel constant expression into a | |
| 609 /// [ConstantExpression]. | |
| 610 class Constantifier extends ir.ExpressionVisitor<ConstantExpression> { | |
| 611 final bool requireConstant; | |
| 612 final KernelToElementMapMixin elementAdapter; | |
| 613 | |
| 614 Constantifier(this.elementAdapter, {this.requireConstant: true}); | |
| 615 | |
| 616 CommonElements get _commonElements => elementAdapter.commonElements; | |
| 617 | |
| 618 ConstantExpression visit(ir.Expression node) { | |
| 619 ConstantExpression constant = node.accept(this); | |
| 620 if (constant == null && requireConstant) { | |
| 621 throw new UnsupportedError( | |
| 622 "No constant computed for $node (${node.runtimeType})"); | |
| 623 } | |
| 624 return constant; | |
| 625 } | |
| 626 | |
| 627 ConstantExpression defaultExpression(ir.Expression node) { | |
| 628 if (requireConstant) { | |
| 629 throw new UnimplementedError( | |
| 630 'Unimplemented constant expression $node (${node.runtimeType})'); | |
| 631 } | |
| 632 return null; | |
| 633 } | |
| 634 | |
| 635 List<ConstantExpression> _computeList(List<ir.Expression> expressions) { | |
| 636 List<ConstantExpression> list = <ConstantExpression>[]; | |
| 637 for (ir.Expression expression in expressions) { | |
| 638 ConstantExpression constant = visit(expression); | |
| 639 if (constant == null) return null; | |
| 640 list.add(constant); | |
| 641 } | |
| 642 return list; | |
| 643 } | |
| 644 | |
| 645 List<ConstantExpression> _computeArguments(ir.Arguments node) { | |
| 646 List<ConstantExpression> arguments = <ConstantExpression>[]; | |
| 647 for (ir.Expression argument in node.positional) { | |
| 648 ConstantExpression constant = visit(argument); | |
| 649 if (constant == null) return null; | |
| 650 arguments.add(constant); | |
| 651 } | |
| 652 for (ir.NamedExpression argument in node.named) { | |
| 653 ConstantExpression constant = visit(argument.value); | |
| 654 if (constant == null) return null; | |
| 655 arguments.add(constant); | |
| 656 } | |
| 657 return arguments; | |
| 658 } | |
| 659 | |
| 660 ConstructedConstantExpression _computeConstructorInvocation( | |
| 661 ir.Constructor target, ir.Arguments arguments) { | |
| 662 List<ConstantExpression> expressions = _computeArguments(arguments); | |
| 663 if (expressions == null) return null; | |
| 664 return new ConstructedConstantExpression( | |
| 665 elementAdapter.createInterfaceType( | |
| 666 target.enclosingClass, arguments.types), | |
| 667 elementAdapter.getConstructor(target), | |
| 668 elementAdapter.getCallStructure(arguments), | |
| 669 expressions); | |
| 670 } | |
| 671 | |
| 672 @override | |
| 673 ConstantExpression visitConstructorInvocation(ir.ConstructorInvocation node) { | |
| 674 return _computeConstructorInvocation(node.target, node.arguments); | |
| 675 } | |
| 676 | |
| 677 @override | |
| 678 ConstantExpression visitVariableGet(ir.VariableGet node) { | |
| 679 if (node.variable.parent is ir.FunctionNode) { | |
| 680 ir.FunctionNode function = node.variable.parent; | |
| 681 int index = function.positionalParameters.indexOf(node.variable); | |
| 682 if (index != -1) { | |
| 683 return new PositionalArgumentReference(index); | |
| 684 } else { | |
| 685 assert(function.namedParameters.contains(node.variable)); | |
| 686 return new NamedArgumentReference(node.variable.name); | |
| 687 } | |
| 688 } else if (node.variable.isConst) { | |
| 689 return visit(node.variable.initializer); | |
| 690 } | |
| 691 return defaultExpression(node); | |
| 692 } | |
| 693 | |
| 694 @override | |
| 695 ConstantExpression visitStaticGet(ir.StaticGet node) { | |
| 696 ir.Member target = node.target; | |
| 697 if (target is ir.Field && target.isConst) { | |
| 698 return new FieldConstantExpression(elementAdapter.getField(node.target)); | |
| 699 } else if (node.target is ir.Procedure) { | |
| 700 FunctionEntity function = elementAdapter.getMethod(node.target); | |
| 701 DartType type = elementAdapter.getFunctionType(node.target.function); | |
| 702 return new FunctionConstantExpression(function, type); | |
| 703 } | |
| 704 return defaultExpression(node); | |
| 705 } | |
| 706 | |
| 707 @override | |
| 708 ConstantExpression visitNullLiteral(ir.NullLiteral node) { | |
| 709 return new NullConstantExpression(); | |
| 710 } | |
| 711 | |
| 712 @override | |
| 713 ConstantExpression visitBoolLiteral(ir.BoolLiteral node) { | |
| 714 return new BoolConstantExpression(node.value); | |
| 715 } | |
| 716 | |
| 717 @override | |
| 718 ConstantExpression visitIntLiteral(ir.IntLiteral node) { | |
| 719 return new IntConstantExpression(node.value); | |
| 720 } | |
| 721 | |
| 722 @override | |
| 723 ConstantExpression visitDoubleLiteral(ir.DoubleLiteral node) { | |
| 724 return new DoubleConstantExpression(node.value); | |
| 725 } | |
| 726 | |
| 727 @override | |
| 728 ConstantExpression visitStringLiteral(ir.StringLiteral node) { | |
| 729 return new StringConstantExpression(node.value); | |
| 730 } | |
| 731 | |
| 732 @override | |
| 733 ConstantExpression visitSymbolLiteral(ir.SymbolLiteral node) { | |
| 734 return new SymbolConstantExpression(node.value); | |
| 735 } | |
| 736 | |
| 737 @override | |
| 738 ConstantExpression visitStringConcatenation(ir.StringConcatenation node) { | |
| 739 List<ConstantExpression> expressions = _computeList(node.expressions); | |
| 740 if (expressions == null) return null; | |
| 741 return new ConcatenateConstantExpression(expressions); | |
| 742 } | |
| 743 | |
| 744 @override | |
| 745 ConstantExpression visitMapLiteral(ir.MapLiteral node) { | |
| 746 if (!node.isConst) { | |
| 747 return defaultExpression(node); | |
| 748 } | |
| 749 DartType keyType = elementAdapter.getDartType(node.keyType); | |
| 750 DartType valueType = elementAdapter.getDartType(node.valueType); | |
| 751 List<ConstantExpression> keys = <ConstantExpression>[]; | |
| 752 List<ConstantExpression> values = <ConstantExpression>[]; | |
| 753 for (ir.MapEntry entry in node.entries) { | |
| 754 ConstantExpression key = visit(entry.key); | |
| 755 if (key == null) return null; | |
| 756 keys.add(key); | |
| 757 ConstantExpression value = visit(entry.value); | |
| 758 if (value == null) return null; | |
| 759 values.add(value); | |
| 760 } | |
| 761 return new MapConstantExpression( | |
| 762 _commonElements.mapType(keyType, valueType), keys, values); | |
| 763 } | |
| 764 | |
| 765 @override | |
| 766 ConstantExpression visitListLiteral(ir.ListLiteral node) { | |
| 767 if (!node.isConst) { | |
| 768 return defaultExpression(node); | |
| 769 } | |
| 770 DartType elementType = elementAdapter.getDartType(node.typeArgument); | |
| 771 List<ConstantExpression> values = <ConstantExpression>[]; | |
| 772 for (ir.Expression expression in node.expressions) { | |
| 773 ConstantExpression value = visit(expression); | |
| 774 if (value == null) return null; | |
| 775 values.add(value); | |
| 776 } | |
| 777 return new ListConstantExpression( | |
| 778 _commonElements.listType(elementType), values); | |
| 779 } | |
| 780 | |
| 781 @override | |
| 782 ConstantExpression visitTypeLiteral(ir.TypeLiteral node) { | |
| 783 DartType type = elementAdapter.getDartType(node.type); | |
| 784 String name; | |
| 785 if (type.isDynamic) { | |
| 786 name = 'dynamic'; | |
| 787 } else if (type is InterfaceType) { | |
| 788 name = type.element.name; | |
| 789 } else if (type.isFunctionType || type.isTypedef) { | |
| 790 // TODO(johnniwinther): Compute a name for the type literal? It is only | |
| 791 // used in error messages in the old SSA builder. | |
| 792 name = '?'; | |
| 793 } else { | |
| 794 return defaultExpression(node); | |
| 795 } | |
| 796 return new TypeConstantExpression(type, name); | |
| 797 } | |
| 798 | |
| 799 @override | |
| 800 ConstantExpression visitNot(ir.Not node) { | |
| 801 ConstantExpression expression = visit(node.operand); | |
| 802 if (expression == null) return null; | |
| 803 return new UnaryConstantExpression(UnaryOperator.NOT, expression); | |
| 804 } | |
| 805 | |
| 806 @override | |
| 807 ConstantExpression visitConditionalExpression(ir.ConditionalExpression node) { | |
| 808 ConstantExpression condition = visit(node.condition); | |
| 809 if (condition == null) return null; | |
| 810 ConstantExpression trueExp = visit(node.then); | |
| 811 if (trueExp == null) return null; | |
| 812 ConstantExpression falseExp = visit(node.otherwise); | |
| 813 if (falseExp == null) return null; | |
| 814 return new ConditionalConstantExpression(condition, trueExp, falseExp); | |
| 815 } | |
| 816 | |
| 817 @override | |
| 818 ConstantExpression visitPropertyGet(ir.PropertyGet node) { | |
| 819 if (node.name.name != 'length') { | |
| 820 throw new UnimplementedError( | |
| 821 'Unexpected constant expression $node (${node.runtimeType})'); | |
| 822 } | |
| 823 ConstantExpression receiver = visit(node.receiver); | |
| 824 if (receiver == null) return null; | |
| 825 return new StringLengthConstantExpression(receiver); | |
| 826 } | |
| 827 | |
| 828 @override | |
| 829 ConstantExpression visitMethodInvocation(ir.MethodInvocation node) { | |
| 830 // Method invocations are generally not constant expressions but unary | |
| 831 // and binary expressions are encoded as method invocations in kernel. | |
| 832 if (node.arguments.named.isNotEmpty) { | |
| 833 return defaultExpression(node); | |
| 834 } | |
| 835 if (node.arguments.positional.length == 0) { | |
| 836 UnaryOperator operator; | |
| 837 if (node.name.name == UnaryOperator.NEGATE.selectorName) { | |
| 838 operator = UnaryOperator.NEGATE; | |
| 839 } else { | |
| 840 operator = UnaryOperator.parse(node.name.name); | |
| 841 } | |
| 842 if (operator != null) { | |
| 843 ConstantExpression expression = visit(node.receiver); | |
| 844 if (expression == null) return null; | |
| 845 return new UnaryConstantExpression(operator, expression); | |
| 846 } | |
| 847 } | |
| 848 if (node.arguments.positional.length == 1) { | |
| 849 BinaryOperator operator = BinaryOperator.parse(node.name.name); | |
| 850 if (operator != null) { | |
| 851 ConstantExpression left = visit(node.receiver); | |
| 852 if (left == null) return null; | |
| 853 ConstantExpression right = visit(node.arguments.positional.single); | |
| 854 if (right == null) return null; | |
| 855 return new BinaryConstantExpression(left, operator, right); | |
| 856 } | |
| 857 } | |
| 858 return defaultExpression(node); | |
| 859 } | |
| 860 | |
| 861 @override | |
| 862 ConstantExpression visitStaticInvocation(ir.StaticInvocation node) { | |
| 863 MemberEntity member = elementAdapter.getMember(node.target); | |
| 864 if (member == _commonElements.identicalFunction) { | |
| 865 if (node.arguments.positional.length == 2 && | |
| 866 node.arguments.named.isEmpty) { | |
| 867 ConstantExpression left = visit(node.arguments.positional[0]); | |
| 868 if (left == null) return null; | |
| 869 ConstantExpression right = visit(node.arguments.positional[1]); | |
| 870 if (right == null) return null; | |
| 871 return new IdenticalConstantExpression(left, right); | |
| 872 } | |
| 873 } else if (member.name == 'fromEnvironment' && | |
| 874 node.arguments.positional.length == 1) { | |
| 875 ConstantExpression name = visit(node.arguments.positional.single); | |
| 876 if (name == null) return null; | |
| 877 ConstantExpression defaultValue; | |
| 878 if (node.arguments.named.length == 1) { | |
| 879 if (node.arguments.named.single.name != 'defaultValue') { | |
| 880 return defaultExpression(node); | |
| 881 } | |
| 882 defaultValue = visit(node.arguments.named.single.value); | |
| 883 if (defaultValue == null) return null; | |
| 884 } | |
| 885 if (member.enclosingClass == _commonElements.boolClass) { | |
| 886 return new BoolFromEnvironmentConstantExpression(name, defaultValue); | |
| 887 } else if (member.enclosingClass == _commonElements.intClass) { | |
| 888 return new IntFromEnvironmentConstantExpression(name, defaultValue); | |
| 889 } else if (member.enclosingClass == _commonElements.stringClass) { | |
| 890 return new StringFromEnvironmentConstantExpression(name, defaultValue); | |
| 891 } | |
| 892 } | |
| 893 return defaultExpression(node); | |
| 894 } | |
| 895 | |
| 896 @override | |
| 897 ConstantExpression visitLogicalExpression(ir.LogicalExpression node) { | |
| 898 BinaryOperator operator = BinaryOperator.parse(node.operator); | |
| 899 if (operator != null) { | |
| 900 ConstantExpression left = visit(node.left); | |
| 901 if (left == null) return null; | |
| 902 ConstantExpression right = visit(node.right); | |
| 903 if (right == null) return null; | |
| 904 return new BinaryConstantExpression(left, operator, right); | |
| 905 } | |
| 906 return defaultExpression(node); | |
| 907 } | |
| 908 | |
| 909 @override | |
| 910 ConstantExpression visitLet(ir.Let node) { | |
| 911 ir.Expression body = node.body; | |
| 912 if (body is ir.ConditionalExpression) { | |
| 913 ir.Expression condition = body.condition; | |
| 914 if (condition is ir.MethodInvocation) { | |
| 915 ir.Expression receiver = condition.receiver; | |
| 916 ir.Expression otherwise = body.otherwise; | |
| 917 if (condition.name.name == BinaryOperator.EQ.name && | |
| 918 receiver is ir.VariableGet && | |
| 919 condition.arguments.positional.single is ir.NullLiteral && | |
| 920 otherwise is ir.VariableGet) { | |
| 921 if (receiver.variable == node.variable && | |
| 922 otherwise.variable == node.variable) { | |
| 923 // We have <left> ?? <right> encoded as: | |
| 924 // let #1 = <left> in #1 == null ? <right> : #1 | |
| 925 ConstantExpression left = visit(node.variable.initializer); | |
| 926 if (left == null) return null; | |
| 927 ConstantExpression right = visit(body.then); | |
| 928 if (right == null) return null; | |
| 929 // TODO(johnniwinther): Remove [IF_NULL] binary constant expression | |
| 930 // when the resolver is removed; then we no longer need the | |
| 931 // expressions to be structurally equivalence for equivalence | |
| 932 // testing. | |
| 933 return new BinaryConstantExpression( | |
| 934 left, BinaryOperator.IF_NULL, right); | |
| 935 } | |
| 936 } | |
| 937 } | |
| 938 } | |
| 939 return defaultExpression(node); | |
| 940 } | |
| 941 | |
| 942 /// Compute the [ConstantConstructor] corresponding to the const constructor | |
| 943 /// [node]. | |
| 944 ConstantConstructor computeConstantConstructor(ir.Constructor node) { | |
| 945 assert(node.isConst); | |
| 946 ir.Class cls = node.enclosingClass; | |
| 947 InterfaceType type = elementAdapter.elementEnvironment | |
| 948 .getThisType(elementAdapter.getClass(cls)); | |
| 949 | |
| 950 Map<dynamic, ConstantExpression> defaultValues = | |
| 951 <dynamic, ConstantExpression>{}; | |
| 952 int parameterIndex = 0; | |
| 953 for (ir.VariableDeclaration parameter | |
| 954 in node.function.positionalParameters) { | |
| 955 if (parameterIndex >= node.function.requiredParameterCount) { | |
| 956 ConstantExpression defaultValue; | |
| 957 if (parameter.initializer != null) { | |
| 958 defaultValue = parameter.initializer.accept(this); | |
| 959 } else { | |
| 960 defaultValue = new NullConstantExpression(); | |
| 961 } | |
| 962 if (defaultValue == null) return null; | |
| 963 defaultValues[parameterIndex] = defaultValue; | |
| 964 } | |
| 965 parameterIndex++; | |
| 966 } | |
| 967 for (ir.VariableDeclaration parameter in node.function.namedParameters) { | |
| 968 ConstantExpression defaultValue = parameter.initializer.accept(this); | |
| 969 if (defaultValue == null) return null; | |
| 970 defaultValues[parameter.name] = defaultValue; | |
| 971 } | |
| 972 | |
| 973 bool isRedirecting = node.initializers.length == 1 && | |
| 974 node.initializers.single is ir.RedirectingInitializer; | |
| 975 | |
| 976 Map<FieldEntity, ConstantExpression> fieldMap = | |
| 977 <FieldEntity, ConstantExpression>{}; | |
| 978 | |
| 979 void registerField(ir.Field field, ConstantExpression constant) { | |
| 980 fieldMap[elementAdapter.getField(field)] = constant; | |
| 981 } | |
| 982 | |
| 983 if (!isRedirecting) { | |
| 984 for (ir.Field field in cls.fields) { | |
| 985 if (field.isStatic) continue; | |
| 986 if (field.initializer != null) { | |
| 987 registerField(field, field.initializer.accept(this)); | |
| 988 } | |
| 989 } | |
| 990 } | |
| 991 | |
| 992 ConstructedConstantExpression superConstructorInvocation; | |
| 993 for (ir.Initializer initializer in node.initializers) { | |
| 994 if (initializer is ir.FieldInitializer) { | |
| 995 registerField(initializer.field, initializer.value.accept(this)); | |
| 996 } else if (initializer is ir.SuperInitializer) { | |
| 997 superConstructorInvocation = _computeConstructorInvocation( | |
| 998 initializer.target, initializer.arguments); | |
| 999 } else if (initializer is ir.RedirectingInitializer) { | |
| 1000 superConstructorInvocation = _computeConstructorInvocation( | |
| 1001 initializer.target, initializer.arguments); | |
| 1002 } else { | |
| 1003 throw new UnsupportedError( | |
| 1004 'Unexpected initializer $node (${node.runtimeType})'); | |
| 1005 } | |
| 1006 } | |
| 1007 if (isRedirecting) { | |
| 1008 return new RedirectingGenerativeConstantConstructor( | |
| 1009 defaultValues, superConstructorInvocation); | |
| 1010 } else { | |
| 1011 return new GenerativeConstantConstructor( | |
| 1012 type, defaultValues, fieldMap, superConstructorInvocation); | |
| 1013 } | |
| 1014 } | |
| 1015 } | |
| 1016 | |
| 1017 /// Interface for type inference results for kernel IR nodes. | 193 /// Interface for type inference results for kernel IR nodes. |
| 1018 abstract class KernelToTypeInferenceMap { | 194 abstract class KernelToTypeInferenceMap { |
| 1019 /// Returns the inferred return type of [function]. | 195 /// Returns the inferred return type of [function]. |
| 1020 TypeMask getReturnTypeOf(FunctionEntity function); | 196 TypeMask getReturnTypeOf(FunctionEntity function); |
| 1021 | 197 |
| 1022 /// Returns the inferred receiver type of the dynamic [invocation]. | 198 /// Returns the inferred receiver type of the dynamic [invocation]. |
| 1023 TypeMask typeOfInvocation( | 199 TypeMask typeOfInvocation( |
| 1024 ir.MethodInvocation invocation, ClosedWorld closedWorld); | 200 ir.MethodInvocation invocation, ClosedWorld closedWorld); |
| 1025 | 201 |
| 1026 /// Returns the inferred receiver type of the dynamic [read]. | 202 /// Returns the inferred receiver type of the dynamic [read]. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1125 /// Returns the [LoopClosureScope] for the loop [node] in [closureClassMaps]. | 301 /// Returns the [LoopClosureScope] for the loop [node] in [closureClassMaps]. |
| 1126 LoopClosureScope getLoopClosureScope( | 302 LoopClosureScope getLoopClosureScope( |
| 1127 ClosureDataLookup closureLookup, ir.TreeNode node); | 303 ClosureDataLookup closureLookup, ir.TreeNode node); |
| 1128 } | 304 } |
| 1129 | 305 |
| 1130 /// Comparator for the canonical order or named arguments. | 306 /// Comparator for the canonical order or named arguments. |
| 1131 // TODO(johnniwinther): Remove this when named parameters are sorted in dill. | 307 // TODO(johnniwinther): Remove this when named parameters are sorted in dill. |
| 1132 int namedOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) { | 308 int namedOrdering(ir.VariableDeclaration a, ir.VariableDeclaration b) { |
| 1133 return a.name.compareTo(b.name); | 309 return a.name.compareTo(b.name); |
| 1134 } | 310 } |
| OLD | NEW |