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 |