Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 | 2 |
| 3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
| 4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
| 7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
| 8 | 8 |
| 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 301 items.addAll(_typeTable.discharge()); | 301 items.addAll(_typeTable.discharge()); |
| 302 | 302 |
| 303 // Add the module's code (produced by visiting compilation units, above) | 303 // Add the module's code (produced by visiting compilation units, above) |
| 304 _copyAndFlattenBlocks(items, _moduleItems); | 304 _copyAndFlattenBlocks(items, _moduleItems); |
| 305 | 305 |
| 306 // Build the module. | 306 // Build the module. |
| 307 return new JS.Program(items, name: _buildUnit.name); | 307 return new JS.Program(items, name: _buildUnit.name); |
| 308 } | 308 } |
| 309 | 309 |
| 310 List<String> _getJSName(Element e) { | 310 List<String> _getJSName(Element e) { |
| 311 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 311 if (e.library == null || |
|
Jennifer Messerly
2016/11/22 18:18:19
nice fix. I'm curious, do you know how this happen
Jacob
2016/11/22 18:51:37
I suspect one of dynamic or bottom doesn't show up
| |
| 312 findAnnotation(e.library, isPublicJSAnnotation) == null) { | |
| 312 return null; | 313 return null; |
| 313 } | 314 } |
| 314 | 315 |
| 315 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 316 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
| 316 var libraryPrefix = <String>[]; | 317 var libraryPrefix = <String>[]; |
| 317 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 318 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
| 318 libraryPrefix.addAll(libraryJSName.split('.')); | 319 libraryPrefix.addAll(libraryJSName.split('.')); |
| 319 } | 320 } |
| 320 | 321 |
| 321 String elementJSName; | 322 String elementJSName; |
| 322 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 323 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
| 323 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 324 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
| 324 } | 325 } |
| 326 | |
| 325 if (e is TopLevelVariableElement && | 327 if (e is TopLevelVariableElement && |
| 326 e.getter != null && | 328 e.getter != null && |
| 327 (e.getter.isExternal || | 329 (e.getter.isExternal || |
| 328 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | 330 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { |
| 329 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | 331 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; |
| 330 } | 332 } |
| 331 if (elementJSName == null) return null; | 333 if (elementJSName == null) return null; |
| 332 | 334 |
| 333 var elementJSParts = <String>[]; | 335 var elementJSParts = <String>[]; |
| 334 if (elementJSName.isNotEmpty) { | 336 if (elementJSName.isNotEmpty) { |
| (...skipping 2363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2698 | 2700 |
| 2699 var name = element.name; | 2701 var name = element.name; |
| 2700 | 2702 |
| 2701 // Unqualified class member. This could mean implicit-this, or implicit | 2703 // Unqualified class member. This could mean implicit-this, or implicit |
| 2702 // call to a static from the same class. | 2704 // call to a static from the same class. |
| 2703 if (element is ClassMemberElement && element is! ConstructorElement) { | 2705 if (element is ClassMemberElement && element is! ConstructorElement) { |
| 2704 bool isStatic = element.isStatic; | 2706 bool isStatic = element.isStatic; |
| 2705 var type = element.enclosingElement.type; | 2707 var type = element.enclosingElement.type; |
| 2706 var member = _emitMemberName(name, isStatic: isStatic, type: type); | 2708 var member = _emitMemberName(name, isStatic: isStatic, type: type); |
| 2707 | 2709 |
| 2708 // For static methods, we add the raw type name, without generics or | |
| 2709 // library prefix. We don't need those because static calls can't use | |
| 2710 // the generic type. | |
| 2711 if (isStatic) { | 2710 if (isStatic) { |
| 2712 var dynType = _emitType(fillDynamicTypeArgs(type)); | 2711 var dynType = _emitStaticAccess(type); |
| 2713 return new JS.PropertyAccess(dynType, member); | 2712 return new JS.PropertyAccess(dynType, member); |
| 2714 } | 2713 } |
| 2715 | 2714 |
| 2716 // For instance members, we add implicit-this. | 2715 // For instance members, we add implicit-this. |
| 2717 // For method tear-offs, we ensure it's a bound method. | 2716 // For method tear-offs, we ensure it's a bound method. |
| 2718 var tearOff = element is MethodElement && !inInvocationContext(node); | 2717 var tearOff = element is MethodElement && !inInvocationContext(node); |
| 2719 if (tearOff) return _callHelper('bind(this, #)', member); | 2718 if (tearOff) return _callHelper('bind(this, #)', member); |
| 2720 return js.call('this.#', member); | 2719 return js.call('this.#', member); |
| 2721 } | 2720 } |
| 2722 | 2721 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2901 ]; | 2900 ]; |
| 2902 } else { | 2901 } else { |
| 2903 typeParts = [ | 2902 typeParts = [ |
| 2904 js.call('(#) => {#; return #;}', [tf, names, parts]) | 2903 js.call('(#) => {#; return #;}', [tf, names, parts]) |
| 2905 ]; | 2904 ]; |
| 2906 } | 2905 } |
| 2907 } | 2906 } |
| 2908 return typeParts; | 2907 return typeParts; |
| 2909 } | 2908 } |
| 2910 | 2909 |
| 2910 /// Emits an expression that lets you access statics on a [[type]] from code. | |
|
Jennifer Messerly
2016/11/22 18:18:19
comment nit: I don't think you want two brackets,
Jacob
2016/11/22 18:51:37
[[[done]]]
| |
| 2911 /// | |
| 2912 /// If [nameType] is true, then the type will be named. In addition, | |
| 2913 /// if [hoistType] is true, then the named type will be hoisted. | |
| 2914 JS.Expression _emitConstructorAccess(DartType type, | |
|
Jennifer Messerly
2016/11/22 18:18:19
just wanted to say, this is factored in a lovely w
Jacob
2016/11/22 18:51:36
yay!
| |
| 2915 {bool nameType: true, bool hoistType: true}) { | |
| 2916 var interop = _emitJSInterop(type.element); | |
|
Jennifer Messerly
2016/11/22 18:18:19
this could be:
return _emitJSInterop(type.elemen
Jacob
2016/11/22 18:51:36
Done.
| |
| 2917 if (interop != null) return interop; | |
| 2918 | |
| 2919 // TODO(jacobr): we could consider duplicating logic instead of calling | |
|
Jennifer Messerly
2016/11/22 18:18:19
personally I'm not sure we need this TODO ... we c
Jacob
2016/11/22 18:51:36
sounds good. My only concern is that this is only
| |
| 2920 // through to the somewhat unrelated _emitType mode. Calling _emitType here | |
| 2921 // is acceptable as the type cannot be a JS interop type. | |
| 2922 return _emitType(type, nameType: nameType, hoistType: hoistType); | |
| 2923 } | |
| 2924 | |
| 2925 /// Emits an expression that lets you access statics on a [[type]] from code. | |
|
Jennifer Messerly
2016/11/22 18:18:19
comment nit again: [type] instead of [[type]]
Jacob
2016/11/22 18:51:36
Done.
| |
| 2926 JS.Expression _emitStaticAccess(DartType type) { | |
| 2927 // Make sure we aren't attempting to emit a static access path to a type | |
| 2928 // that does not have a valid static access path. | |
| 2929 assert(!type.isVoid && | |
| 2930 !type.isDynamic && | |
| 2931 !type.isBottom && | |
| 2932 type is! TypeParameterType); | |
| 2933 | |
| 2934 // For statics, we add the raw type name, without generics or | |
| 2935 // library prefix. We don't need those because static calls can't use | |
| 2936 // the generic type. | |
| 2937 type = fillDynamicTypeArgs(type); | |
| 2938 var element = type.element; | |
| 2939 _declareBeforeUse(element); | |
| 2940 | |
| 2941 var interop = _emitJSInterop(element); | |
| 2942 if (interop != null) return interop; | |
| 2943 | |
| 2944 assert(type.name != '' && type.name != null); | |
| 2945 | |
| 2946 return _emitTopLevelNameNoInterop(element); | |
| 2947 } | |
| 2948 | |
| 2911 /// Emits a Dart [type] into code. | 2949 /// Emits a Dart [type] into code. |
| 2912 /// | 2950 /// |
| 2913 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a | 2951 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a |
| 2914 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form | 2952 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form |
| 2915 /// will be used instead of `List`. These flags are used when generating | 2953 /// will be used instead of `List`. These flags are used when generating |
| 2916 /// the definitions for typedefs and generic types, respectively. | 2954 /// the definitions for typedefs and generic types, respectively. |
| 2917 /// | 2955 /// |
| 2918 /// If [subClass] is set, then we are setting the base class for the given | 2956 /// If [subClass] is set, then we are setting the base class for the given |
| 2919 /// class and should emit the given [className], which will already be | 2957 /// class and should emit the given [className], which will already be |
| 2920 /// defined. | 2958 /// defined. |
| 2921 /// | 2959 /// |
| 2922 /// If [nameType] is true, then the type will be named. In addition, | 2960 /// If [nameType] is true, then the type will be named. In addition, |
| 2923 /// if [hoistType] is true, then the named type will be hoisted. | 2961 /// if [hoistType] is true, then the named type will be hoisted. |
| 2924 JS.Expression _emitType(DartType type, | 2962 JS.Expression _emitType(DartType type, |
| 2925 {bool lowerTypedef: false, | 2963 {bool lowerTypedef: false, |
| 2926 bool lowerGeneric: false, | 2964 bool lowerGeneric: false, |
| 2927 bool nameType: true, | 2965 bool nameType: true, |
| 2928 bool hoistType: true, | 2966 bool hoistType: true, |
| 2929 ClassElement subClass, | 2967 ClassElement subClass, |
| 2930 JS.Expression className}) { | 2968 JS.Expression className}) { |
| 2931 // The void and dynamic types are not defined in core. | 2969 // The void and dynamic types are not defined in core. |
| 2932 if (type.isVoid) { | 2970 if (type.isVoid) { |
| 2933 return _callHelper('void'); | 2971 return _callHelper('void'); |
| 2934 } else if (type.isDynamic) { | 2972 } else if (type.isDynamic) { |
| 2935 return _callHelper('dynamic'); | 2973 return _callHelper('dynamic'); |
| 2936 } else if (type.isBottom) { | 2974 } else if (type.isBottom) { |
| 2937 return _callHelper('bottom'); | 2975 return _callHelper('bottom'); |
| 2938 } | 2976 } |
| 2939 | 2977 |
| 2940 _declareBeforeUse(type.element); | 2978 var element = type.element; |
| 2979 _declareBeforeUse(element); | |
| 2980 | |
| 2981 var interop = _emitJSInterop(element); | |
| 2982 // Type parameters don't matter as JS interop types cannot be reified. | |
|
Jennifer Messerly
2016/11/22 18:18:19
should we error out if the type is generic?
I'm g
Jacob
2016/11/22 18:51:36
Would really like to allow it assuming JS interop
| |
| 2983 // We have to use lazy JS types because until we have proper module | |
|
Jennifer Messerly
2016/11/22 18:18:19
This comment is good, but maybe a code example wou
Jacob
2016/11/22 18:51:37
Done.
| |
| 2984 // loading for JS libraries bundled with Dart libraries, we will sometimes | |
| 2985 // need to load Dart libraries before the corresponding JS libraries are | |
| 2986 // actually loaded. | |
| 2987 if (interop != null) { | |
| 2988 if (_isObjectLiteral(element)) { | |
| 2989 return _callHelper( | |
| 2990 'lazyAnonymousJSType(#)', js.string(element.displayName)); | |
| 2991 } else { | |
| 2992 return _callHelper('lazyJSType(() => #, #)', | |
| 2993 [interop, js.string(_getJSName(element).join('.'))]); | |
| 2994 } | |
| 2995 } | |
| 2941 | 2996 |
| 2942 // TODO(jmesserly): like constants, should we hoist function types out of | 2997 // TODO(jmesserly): like constants, should we hoist function types out of |
| 2943 // methods? Similar issue with generic types. For all of these, we may want | 2998 // methods? Similar issue with generic types. For all of these, we may want |
| 2944 // to canonicalize them too, at least when inside the same library. | 2999 // to canonicalize them too, at least when inside the same library. |
| 2945 var name = type.name; | 3000 var name = type.name; |
| 2946 var element = type.element; | |
| 2947 if (name == '' || name == null || lowerTypedef) { | 3001 if (name == '' || name == null || lowerTypedef) { |
| 2948 // TODO(jmesserly): should we change how typedefs work? They currently | 3002 // TODO(jmesserly): should we change how typedefs work? They currently |
| 2949 // go through use similar logic as generic classes. This makes them | 3003 // go through use similar logic as generic classes. This makes them |
| 2950 // different from universal function types. | 3004 // different from universal function types. |
| 2951 return _emitFunctionType(type as FunctionType, | 3005 return _emitFunctionType(type as FunctionType, |
| 2952 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); | 3006 lowerTypedef: lowerTypedef, nameType: nameType, hoistType: hoistType); |
| 2953 } | 3007 } |
| 2954 | 3008 |
| 2955 if (type is TypeParameterType) { | 3009 if (type is TypeParameterType) { |
| 2956 _typeParamInConst?.add(type); | 3010 _typeParamInConst?.add(type); |
| 2957 return new JS.Identifier(name); | 3011 return new JS.Identifier(name); |
| 2958 } | 3012 } |
| 2959 | 3013 |
| 2960 if (type == subClass?.type) { | 3014 if (type == subClass?.type) return className; |
|
Jennifer Messerly
2016/11/22 18:18:19
nice!
Jacob
2016/11/22 18:51:36
Acknowledged.
| |
| 2961 return className; | |
| 2962 } | |
| 2963 | 3015 |
| 2964 if (type is ParameterizedType) { | 3016 if (type is ParameterizedType) { |
| 2965 var args = type.typeArguments; | 3017 var args = type.typeArguments; |
| 2966 Iterable jsArgs = null; | 3018 Iterable jsArgs = null; |
| 2967 if (args.any((a) => !a.isDynamic)) { | 3019 if (args.any((a) => !a.isDynamic)) { |
| 2968 jsArgs = args.map((x) => _emitType(x, | 3020 jsArgs = args.map((x) => _emitType(x, |
| 2969 nameType: nameType, | 3021 nameType: nameType, |
| 2970 hoistType: hoistType, | 3022 hoistType: hoistType, |
| 2971 subClass: subClass, | 3023 subClass: subClass, |
| 2972 className: className)); | 3024 className: className)); |
| 2973 } else if (lowerGeneric || element == subClass) { | 3025 } else if (lowerGeneric || element == subClass) { |
| 2974 jsArgs = []; | 3026 jsArgs = []; |
| 2975 } | 3027 } |
| 2976 if (jsArgs != null) { | 3028 if (jsArgs != null) { |
| 2977 var genericName = _emitTopLevelName(element, suffix: '\$'); | 3029 var genericName = _emitTopLevelName(element, suffix: '\$'); |
| 2978 var typeRep = js.call('#(#)', [genericName, jsArgs]); | 3030 var typeRep = js.call('#(#)', [genericName, jsArgs]); |
| 2979 return nameType | 3031 return nameType |
| 2980 ? _typeTable.nameType(type, typeRep, hoistType: hoistType) | 3032 ? _typeTable.nameType(type, typeRep, hoistType: hoistType) |
| 2981 : typeRep; | 3033 : typeRep; |
| 2982 } | 3034 } |
| 2983 } | 3035 } |
| 2984 | 3036 |
| 2985 return _emitTopLevelName(element); | 3037 return _emitTopLevelNameNoInterop(element); |
| 2986 } | 3038 } |
| 2987 | 3039 |
| 2988 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 3040 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| 2989 var interop = _emitJSInterop(e); | 3041 var interop = _emitJSInterop(e); |
| 2990 if (interop != null) return interop; | 3042 if (interop != null) return interop; |
| 3043 return _emitTopLevelNameNoInterop(e, suffix: suffix); | |
| 3044 } | |
| 3045 | |
| 3046 JS.PropertyAccess _emitTopLevelNameNoInterop(Element e, {String suffix: ''}) { | |
| 2991 String name = getJSExportName(e) + suffix; | 3047 String name = getJSExportName(e) + suffix; |
| 2992 return new JS.PropertyAccess( | 3048 return new JS.PropertyAccess( |
| 2993 emitLibraryName(e.library), _propertyName(name)); | 3049 emitLibraryName(e.library), _propertyName(name)); |
| 2994 } | 3050 } |
| 2995 | 3051 |
| 2996 @override | 3052 @override |
| 2997 JS.Expression visitAssignmentExpression(AssignmentExpression node) { | 3053 JS.Expression visitAssignmentExpression(AssignmentExpression node) { |
| 2998 var left = node.leftHandSide; | 3054 var left = node.leftHandSide; |
| 2999 var right = node.rightHandSide; | 3055 var right = node.rightHandSide; |
| 3000 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); | 3056 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3204 } | 3260 } |
| 3205 | 3261 |
| 3206 /// Emits assignment to a static field element or property. | 3262 /// Emits assignment to a static field element or property. |
| 3207 JS.Expression _emitSetStaticProperty( | 3263 JS.Expression _emitSetStaticProperty( |
| 3208 Expression lhs, Element element, Expression rhs) { | 3264 Expression lhs, Element element, Expression rhs) { |
| 3209 // For static methods, we add the raw type name, without generics or | 3265 // For static methods, we add the raw type name, without generics or |
| 3210 // library prefix. We don't need those because static calls can't use | 3266 // library prefix. We don't need those because static calls can't use |
| 3211 // the generic type. | 3267 // the generic type. |
| 3212 ClassElement classElement = element.enclosingElement; | 3268 ClassElement classElement = element.enclosingElement; |
| 3213 var type = classElement.type; | 3269 var type = classElement.type; |
| 3214 var dynType = _emitType(fillDynamicTypeArgs(type)); | 3270 var dynType = _emitStaticAccess(type); |
| 3215 var member = _emitMemberName(element.name, isStatic: true, type: type); | 3271 var member = _emitMemberName(element.name, isStatic: true, type: type); |
| 3216 return _visit(rhs).toAssignExpression( | 3272 return _visit(rhs).toAssignExpression( |
| 3217 annotate(new JS.PropertyAccess(dynType, member), lhs)); | 3273 annotate(new JS.PropertyAccess(dynType, member), lhs)); |
| 3218 } | 3274 } |
| 3219 | 3275 |
| 3220 /// Emits an assignment to the [element] property of instance referenced by | 3276 /// Emits an assignment to the [element] property of instance referenced by |
| 3221 /// [jsTarget]. | 3277 /// [jsTarget]. |
| 3222 JS.Expression _emitWriteInstanceProperty(Expression lhs, | 3278 JS.Expression _emitWriteInstanceProperty(Expression lhs, |
| 3223 JS.Expression jsTarget, Element element, JS.Expression value) { | 3279 JS.Expression jsTarget, Element element, JS.Expression value) { |
| 3224 String memberName = element.name; | 3280 String memberName = element.name; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3284 visitMethodInvocation(MethodInvocation node) { | 3340 visitMethodInvocation(MethodInvocation node) { |
| 3285 if (_isDeferredLoadLibrary(node.target, node.methodName)) { | 3341 if (_isDeferredLoadLibrary(node.target, node.methodName)) { |
| 3286 // We are calling loadLibrary() on a deferred library prefix. | 3342 // We are calling loadLibrary() on a deferred library prefix. |
| 3287 return _callHelper('loadLibrary()'); | 3343 return _callHelper('loadLibrary()'); |
| 3288 } | 3344 } |
| 3289 | 3345 |
| 3290 if (node.operator?.lexeme == '?.') { | 3346 if (node.operator?.lexeme == '?.') { |
| 3291 return _emitNullSafe(node); | 3347 return _emitNullSafe(node); |
| 3292 } | 3348 } |
| 3293 | 3349 |
| 3350 // SSS | |
|
Jennifer Messerly
2016/11/22 18:18:19
remove this?
Jacob
2016/11/22 18:51:37
Done.
| |
| 3294 var result = _emitForeignJS(node); | 3351 var result = _emitForeignJS(node); |
| 3295 if (result != null) return result; | 3352 if (result != null) return result; |
| 3296 | 3353 |
| 3297 var target = _getTarget(node); | 3354 var target = _getTarget(node); |
| 3298 if (target == null || isLibraryPrefix(target)) { | 3355 if (target == null || isLibraryPrefix(target)) { |
| 3299 return _emitFunctionCall(node); | 3356 return _emitFunctionCall(node); |
| 3300 } | 3357 } |
| 3301 if (node.methodName.name == 'call') { | 3358 if (node.methodName.name == 'call') { |
| 3302 var targetType = target.staticType; | 3359 var targetType = target.staticType; |
| 3303 if (targetType is FunctionType) { | 3360 if (targetType is FunctionType) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3355 JS.Expression _getSuperHelperFor(String name, JS.Expression forwardedCall, | 3412 JS.Expression _getSuperHelperFor(String name, JS.Expression forwardedCall, |
| 3356 List<JS.Expression> helperArgs) { | 3413 List<JS.Expression> helperArgs) { |
| 3357 var helperMethod = | 3414 var helperMethod = |
| 3358 new JS.Fun(helperArgs, new JS.Block([new JS.Return(forwardedCall)])); | 3415 new JS.Fun(helperArgs, new JS.Block([new JS.Return(forwardedCall)])); |
| 3359 var helperMethodName = new JS.TemporaryId('super\$$name'); | 3416 var helperMethodName = new JS.TemporaryId('super\$$name'); |
| 3360 _superHelperSymbols.add(helperMethodName); | 3417 _superHelperSymbols.add(helperMethodName); |
| 3361 _superHelpers.add(new JS.Method(helperMethodName, helperMethod)); | 3418 _superHelpers.add(new JS.Method(helperMethodName, helperMethod)); |
| 3362 return helperMethodName; | 3419 return helperMethodName; |
| 3363 } | 3420 } |
| 3364 | 3421 |
| 3422 JS.Expression _emitTarget(Expression target, Element element, bool isStatic) { | |
| 3423 if (isStatic) { | |
| 3424 if (element is ConstructorElement) | |
| 3425 return _emitConstructorAccess(element.enclosingElement.type); | |
|
Jennifer Messerly
2016/11/22 18:18:19
style nit: should have curly braces if it's more t
Jacob
2016/11/22 18:51:36
Done.
| |
| 3426 if (element is ExecutableElement) | |
| 3427 return _emitStaticAccess( | |
|
Jennifer Messerly
2016/11/22 18:18:19
same here
Jacob
2016/11/22 18:51:36
Done.
| |
| 3428 (element.enclosingElement as ClassElement).type); | |
| 3429 } | |
| 3430 return _visit(target); | |
| 3431 } | |
| 3432 | |
| 3365 /// Emits a (possibly generic) instance method call. | 3433 /// Emits a (possibly generic) instance method call. |
| 3366 JS.Expression _emitMethodCallInternal( | 3434 JS.Expression _emitMethodCallInternal( |
| 3367 Expression target, | 3435 Expression target, |
| 3368 MethodInvocation node, | 3436 MethodInvocation node, |
| 3369 List<JS.Expression> args, | 3437 List<JS.Expression> args, |
| 3370 List<JS.Expression> typeArgs) { | 3438 List<JS.Expression> typeArgs) { |
| 3371 var type = getStaticType(target); | 3439 var type = getStaticType(target); |
| 3372 var name = node.methodName.name; | 3440 var name = node.methodName.name; |
| 3373 var element = node.methodName.staticElement; | 3441 var element = node.methodName.staticElement; |
| 3374 bool isStatic = element is ExecutableElement && element.isStatic; | 3442 bool isStatic = element is ExecutableElement && element.isStatic; |
| 3375 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); | 3443 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); |
| 3376 | 3444 |
| 3377 JS.Expression jsTarget = _visit(target); | 3445 JS.Expression jsTarget = _emitTarget(target, element, isStatic); |
| 3378 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { | 3446 if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) { |
| 3379 if (_inWhitelistCode(target)) { | 3447 if (_inWhitelistCode(target)) { |
| 3380 var vars = <JS.MetaLetVariable, JS.Expression>{}; | 3448 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
| 3381 var l = _visit(_bindValue(vars, 'l', target)); | 3449 var l = _visit(_bindValue(vars, 'l', target)); |
| 3382 jsTarget = new JS.MetaLet(vars, [ | 3450 jsTarget = new JS.MetaLet(vars, [ |
| 3383 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [ | 3451 js.call('(#[(#[#._extensionType]) ? #[#] : #]).bind(#)', [ |
| 3384 l, | 3452 l, |
| 3385 l, | 3453 l, |
| 3386 _runtimeModule, | 3454 _runtimeModule, |
| 3387 _extensionSymbolsModule, | 3455 _extensionSymbolsModule, |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3892 : parent.getSetter(element.name); | 3960 : parent.getSetter(element.name); |
| 3893 } | 3961 } |
| 3894 return null; | 3962 return null; |
| 3895 } | 3963 } |
| 3896 | 3964 |
| 3897 JS.Expression _emitConstructorName( | 3965 JS.Expression _emitConstructorName( |
| 3898 ConstructorElement element, DartType type, SimpleIdentifier name) { | 3966 ConstructorElement element, DartType type, SimpleIdentifier name) { |
| 3899 var classElem = element.enclosingElement; | 3967 var classElem = element.enclosingElement; |
| 3900 var interop = _emitJSInterop(classElem); | 3968 var interop = _emitJSInterop(classElem); |
| 3901 if (interop != null) return interop; | 3969 if (interop != null) return interop; |
| 3902 var typeName = _emitType(type); | 3970 var typeName = _emitConstructorAccess(type); |
| 3903 if (name != null || element.isFactory) { | 3971 if (name != null || element.isFactory) { |
| 3904 var namedCtor = _constructorName(element); | 3972 var namedCtor = _constructorName(element); |
| 3905 return new JS.PropertyAccess(typeName, namedCtor); | 3973 return new JS.PropertyAccess(typeName, namedCtor); |
| 3906 } | 3974 } |
| 3907 return typeName; | 3975 return typeName; |
| 3908 } | 3976 } |
| 3909 | 3977 |
| 3910 @override | 3978 @override |
| 3911 visitConstructorName(ConstructorName node) { | 3979 visitConstructorName(ConstructorName node) { |
| 3912 return _emitConstructorName(node.staticElement, node.type.type, node.name); | 3980 return _emitConstructorName(node.staticElement, node.type.type, node.name); |
| 3913 } | 3981 } |
| 3914 | 3982 |
| 3915 JS.Expression _emitInstanceCreationExpression( | 3983 JS.Expression _emitInstanceCreationExpression( |
| 3916 ConstructorElement element, | 3984 ConstructorElement element, |
| 3917 DartType type, | 3985 DartType type, |
| 3918 SimpleIdentifier name, | 3986 SimpleIdentifier name, |
| 3919 ArgumentList argumentList, | 3987 ArgumentList argumentList, |
| 3920 bool isConst) { | 3988 bool isConst) { |
| 3921 JS.Expression emitNew() { | 3989 JS.Expression emitNew() { |
| 3922 JS.Expression ctor; | 3990 JS.Expression ctor; |
| 3923 bool isFactory = false; | 3991 bool isFactory = false; |
| 3924 bool isNative = false; | 3992 bool isNative = false; |
| 3925 if (element == null) { | 3993 if (element == null) { |
| 3926 // TODO(jmesserly): this only happens if we had a static error. | 3994 // TODO(jmesserly): this only happens if we had a static error. |
| 3927 // Should we generate a throw instead? | 3995 // Should we generate a throw instead? |
| 3928 ctor = _emitType(type, | 3996 ctor = _emitConstructorAccess(type, |
| 3929 nameType: options.hoistInstanceCreation, | 3997 nameType: options.hoistInstanceCreation, |
| 3930 hoistType: options.hoistInstanceCreation); | 3998 hoistType: options.hoistInstanceCreation); |
| 3931 if (name != null) { | 3999 if (name != null) { |
| 3932 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); | 4000 ctor = new JS.PropertyAccess(ctor, _propertyName(name.name)); |
| 3933 } | 4001 } |
| 3934 } else { | 4002 } else { |
| 3935 ctor = _emitConstructorName(element, type, name); | 4003 ctor = _emitConstructorName(element, type, name); |
| 3936 isFactory = element.isFactory; | 4004 isFactory = element.isFactory; |
| 3937 var classElem = element.enclosingElement; | 4005 var classElem = element.enclosingElement; |
| 3938 isNative = _isJSNative(classElem); | 4006 isNative = _isJSNative(classElem); |
| (...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4742 var l = _visit(_bindValue(vars, 'l', target)); | 4810 var l = _visit(_bindValue(vars, 'l', target)); |
| 4743 return new JS.MetaLet(vars, [ | 4811 return new JS.MetaLet(vars, [ |
| 4744 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', | 4812 js.call('(#[#._extensionType]) ? #[#[#]] : #.#', |
| 4745 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) | 4813 [l, _runtimeModule, l, _extensionSymbolsModule, name, l, name]) |
| 4746 ]); | 4814 ]); |
| 4747 } | 4815 } |
| 4748 return _callHelper('#(#, #)', | 4816 return _callHelper('#(#, #)', |
| 4749 [_emitDynamicOperationName('dload'), _visit(target), name]); | 4817 [_emitDynamicOperationName('dload'), _visit(target), name]); |
| 4750 } | 4818 } |
| 4751 | 4819 |
| 4752 var jsTarget = _visit(target); | 4820 var jsTarget = _emitTarget(target, member, isStatic); |
| 4753 bool isSuper = jsTarget is JS.Super; | 4821 bool isSuper = jsTarget is JS.Super; |
| 4754 | 4822 |
| 4755 if (isSuper && member is FieldElement && !member.isSynthetic) { | 4823 if (isSuper && member is FieldElement && !member.isSynthetic) { |
| 4756 // If super.x is actually a field, then x is an instance property since | 4824 // If super.x is actually a field, then x is an instance property since |
| 4757 // subclasses cannot override x. | 4825 // subclasses cannot override x. |
| 4758 jsTarget = new JS.This(); | 4826 jsTarget = new JS.This(); |
| 4759 } | 4827 } |
| 4760 | 4828 |
| 4761 JS.Expression result; | 4829 JS.Expression result; |
| 4762 if (member != null && member is MethodElement && !isStatic) { | 4830 if (member != null && member is MethodElement && !isStatic) { |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5116 | 5184 |
| 5117 @override | 5185 @override |
| 5118 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 5186 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
| 5119 | 5187 |
| 5120 @override | 5188 @override |
| 5121 visitSymbolLiteral(SymbolLiteral node) { | 5189 visitSymbolLiteral(SymbolLiteral node) { |
| 5122 JS.Expression emitSymbol() { | 5190 JS.Expression emitSymbol() { |
| 5123 // TODO(vsm): When we canonicalize, we need to treat private symbols | 5191 // TODO(vsm): When we canonicalize, we need to treat private symbols |
| 5124 // correctly. | 5192 // correctly. |
| 5125 var name = js.string(node.components.join('.'), "'"); | 5193 var name = js.string(node.components.join('.'), "'"); |
| 5126 return js.call('#.new(#)', [_emitType(types.symbolType), name]); | 5194 return js |
| 5195 .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]); | |
| 5127 } | 5196 } |
| 5128 | 5197 |
| 5129 return _emitConst(emitSymbol); | 5198 return _emitConst(emitSymbol); |
| 5130 } | 5199 } |
| 5131 | 5200 |
| 5132 @override | 5201 @override |
| 5133 visitListLiteral(ListLiteral node) { | 5202 visitListLiteral(ListLiteral node) { |
| 5134 var isConst = node.constKeyword != null; | 5203 var isConst = node.constKeyword != null; |
| 5135 JS.Expression emitList() { | 5204 JS.Expression emitList() { |
| 5136 JS.Expression list = new JS.ArrayInitializer( | 5205 JS.Expression list = new JS.ArrayInitializer( |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5644 var targetIdentifier = target as SimpleIdentifier; | 5713 var targetIdentifier = target as SimpleIdentifier; |
| 5645 | 5714 |
| 5646 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5715 if (targetIdentifier.staticElement is! PrefixElement) return false; |
| 5647 var prefix = targetIdentifier.staticElement as PrefixElement; | 5716 var prefix = targetIdentifier.staticElement as PrefixElement; |
| 5648 | 5717 |
| 5649 // The library the prefix is referring to must come from a deferred import. | 5718 // The library the prefix is referring to must come from a deferred import. |
| 5650 var containingLibrary = (target.root as CompilationUnit).element.library; | 5719 var containingLibrary = (target.root as CompilationUnit).element.library; |
| 5651 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5720 var imports = containingLibrary.getImportsWithPrefix(prefix); |
| 5652 return imports.length == 1 && imports[0].isDeferred; | 5721 return imports.length == 1 && imports[0].isDeferred; |
| 5653 } | 5722 } |
| OLD | NEW |