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 // 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 'dart:collection' show HashSet, HashMap, SplayTreeSet; | 5 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/src/generated/constant.dart'; | 10 import 'package:analyzer/src/generated/constant.dart'; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can | 49 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can |
50 // import and generate calls to, rather than dart_runtime.js | 50 // import and generate calls to, rather than dart_runtime.js |
51 const DPUT = 'dput'; | 51 const DPUT = 'dput'; |
52 const DLOAD = 'dload'; | 52 const DLOAD = 'dload'; |
53 const DINDEX = 'dindex'; | 53 const DINDEX = 'dindex'; |
54 const DSETINDEX = 'dsetindex'; | 54 const DSETINDEX = 'dsetindex'; |
55 const DCALL = 'dcall'; | 55 const DCALL = 'dcall'; |
56 const DSEND = 'dsend'; | 56 const DSEND = 'dsend'; |
57 | 57 |
58 class JSCodegenVisitor extends GeneralizingAstVisitor | 58 class JSCodegenVisitor extends GeneralizingAstVisitor |
59 with ClosureAnnotator, JsTypeRefCodegen { | 59 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { |
60 final AbstractCompiler compiler; | 60 final AbstractCompiler compiler; |
61 final CodegenOptions options; | 61 final CodegenOptions options; |
62 final LibraryElement currentLibrary; | 62 final LibraryElement currentLibrary; |
63 final StrongTypeSystemImpl rules; | 63 final StrongTypeSystemImpl rules; |
64 | 64 |
65 /// The global extension type table. | 65 /// The global extension type table. |
66 final ExtensionTypeSet _extensionTypes; | 66 final ExtensionTypeSet _extensionTypes; |
67 | 67 |
68 /// Information that is precomputed for this library, indicates which fields | 68 /// Information that is precomputed for this library, indicates which fields |
69 /// need storage slots. | 69 /// need storage slots. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 ModuleItemLoadOrder _loader; | 104 ModuleItemLoadOrder _loader; |
105 | 105 |
106 /// _interceptors.JSArray<E>, used for List literals. | 106 /// _interceptors.JSArray<E>, used for List literals. |
107 ClassElement _jsArray; | 107 ClassElement _jsArray; |
108 | 108 |
109 /// The default value of the module object. See [visitLibraryDirective]. | 109 /// The default value of the module object. See [visitLibraryDirective]. |
110 String _jsModuleValue; | 110 String _jsModuleValue; |
111 | 111 |
112 bool _isDartRuntime; | 112 bool _isDartRuntime; |
113 | 113 |
114 NullableTypeInference _nullInference; | |
115 | |
116 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, | 114 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, |
117 this._extensionTypes, this._fieldsNeedingStorage) | 115 this._extensionTypes, this._fieldsNeedingStorage) |
118 : compiler = compiler, | 116 : compiler = compiler, |
119 options = compiler.options.codegenOptions, | 117 options = compiler.options.codegenOptions, |
120 _types = compiler.context.typeProvider { | 118 _types = compiler.context.typeProvider { |
121 _loader = new ModuleItemLoadOrder(_emitModuleItem); | 119 _loader = new ModuleItemLoadOrder(_emitModuleItem); |
122 | 120 |
123 var context = compiler.context; | 121 var context = compiler.context; |
124 var src = context.sourceFactory.forUri('dart:_interceptors'); | 122 var src = context.sourceFactory.forUri('dart:_interceptors'); |
125 var interceptors = context.computeLibraryElement(src); | 123 var interceptors = context.computeLibraryElement(src); |
(...skipping 22 matching lines...) Expand all Loading... |
148 // visit them. It has the ability to sort elements on demand, so | 146 // visit them. It has the ability to sort elements on demand, so |
149 // dependencies between top level items are handled with a minimal | 147 // dependencies between top level items are handled with a minimal |
150 // reordering of the user's input code. The loader will call back into | 148 // reordering of the user's input code. The loader will call back into |
151 // this visitor via [_emitModuleItem] when it's ready to visit the item | 149 // this visitor via [_emitModuleItem] when it's ready to visit the item |
152 // for real. | 150 // for real. |
153 _loader.collectElements(currentLibrary, units); | 151 _loader.collectElements(currentLibrary, units); |
154 | 152 |
155 // TODO(jmesserly): ideally we could do this at a smaller granularity. | 153 // TODO(jmesserly): ideally we could do this at a smaller granularity. |
156 // We'll need to be consistent about when we're generating functions, and | 154 // We'll need to be consistent about when we're generating functions, and |
157 // only run this on the outermost function. | 155 // only run this on the outermost function. |
158 _nullInference = | 156 inferNullableTypesInLibrary(units); |
159 new NullableTypeInference.forLibrary(_isPrimitiveType, units); | |
160 | 157 |
161 _constField = new ConstFieldVisitor(types, library.library.element.source); | 158 _constField = new ConstFieldVisitor(types, library.library.element.source); |
162 | 159 |
163 for (var unit in units) { | 160 for (var unit in units) { |
164 for (var decl in unit.declarations) { | 161 for (var decl in unit.declarations) { |
165 if (decl is TopLevelVariableDeclaration) { | 162 if (decl is TopLevelVariableDeclaration) { |
166 visitTopLevelVariableDeclaration(decl); | 163 visitTopLevelVariableDeclaration(decl); |
167 } else { | 164 } else { |
168 _loader.loadDeclaration(decl, decl.element); | 165 _loader.loadDeclaration(decl, decl.element); |
169 } | 166 } |
(...skipping 2463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2633 var name = constructor.name; | 2630 var name = constructor.name; |
2634 var type = constructor.type.type; | 2631 var type = constructor.type.type; |
2635 return _emitInstanceCreationExpression( | 2632 return _emitInstanceCreationExpression( |
2636 element, type, name, node.argumentList, node.isConst); | 2633 element, type, name, node.argumentList, node.isConst); |
2637 } | 2634 } |
2638 | 2635 |
2639 /// True if this type is built-in to JS, and we use the values unwrapped. | 2636 /// True if this type is built-in to JS, and we use the values unwrapped. |
2640 /// For these types we generate a calling convention via static | 2637 /// For these types we generate a calling convention via static |
2641 /// "extension methods". This allows types to be extended without adding | 2638 /// "extension methods". This allows types to be extended without adding |
2642 /// extensions directly on the prototype. | 2639 /// extensions directly on the prototype. |
2643 bool _isPrimitiveType(DartType t) => | 2640 bool isPrimitiveType(DartType t) => |
2644 typeIsPrimitiveInJS(t) || t == _types.stringType; | 2641 typeIsPrimitiveInJS(t) || t == _types.stringType; |
2645 | 2642 |
2646 bool typeIsPrimitiveInJS(DartType t) => | 2643 bool typeIsPrimitiveInJS(DartType t) => |
2647 _isNumberInJS(t) || t == _types.boolType; | 2644 _isNumberInJS(t) || t == _types.boolType; |
2648 | 2645 |
2649 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => | 2646 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => |
2650 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); | 2647 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); |
2651 | 2648 |
2652 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); | 2649 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); |
2653 | 2650 |
2654 JS.Expression notNull(Expression expr) { | 2651 JS.Expression notNull(Expression expr) { |
2655 if (expr == null) return null; | 2652 if (expr == null) return null; |
2656 var jsExpr = _visit(expr); | 2653 var jsExpr = _visit(expr); |
2657 if (!_isNullable(expr)) return jsExpr; | 2654 if (!isNullable(expr)) return jsExpr; |
2658 return js.call('dart.notNull(#)', jsExpr); | 2655 return js.call('dart.notNull(#)', jsExpr); |
2659 } | 2656 } |
2660 | 2657 |
2661 /// Returns true if [expr] can be null, optionally using [localIsNullable] | |
2662 /// for locals. | |
2663 /// | |
2664 /// This analysis is conservative and incomplete, but it can optimize many | |
2665 /// common patterns. | |
2666 bool _isNullable(Expression expr) => _nullInference.isNullable(expr); | |
2667 | |
2668 @override | 2658 @override |
2669 JS.Expression visitBinaryExpression(BinaryExpression node) { | 2659 JS.Expression visitBinaryExpression(BinaryExpression node) { |
2670 var op = node.operator; | 2660 var op = node.operator; |
2671 var left = node.leftOperand; | 2661 var left = node.leftOperand; |
2672 var right = node.rightOperand; | 2662 var right = node.rightOperand; |
2673 | 2663 |
2674 var leftType = getStaticType(left); | 2664 var leftType = getStaticType(left); |
2675 var rightType = getStaticType(right); | 2665 var rightType = getStaticType(right); |
2676 | 2666 |
2677 var code; | 2667 var code; |
2678 if (op.type.isEqualityOperator) { | 2668 if (op.type.isEqualityOperator) { |
2679 // If we statically know LHS or RHS is null we can generate a clean check. | 2669 // If we statically know LHS or RHS is null we can generate a clean check. |
2680 // We can also do this if both sides are the same primitive type. | 2670 // We can also do this if both sides are the same primitive type. |
2681 if (_canUsePrimitiveEquality(left, right)) { | 2671 if (_canUsePrimitiveEquality(left, right)) { |
2682 code = op.type == TokenType.EQ_EQ ? '# == #' : '# != #'; | 2672 code = op.type == TokenType.EQ_EQ ? '# == #' : '# != #'; |
2683 } else if (left is SuperExpression) { | 2673 } else if (left is SuperExpression) { |
2684 return _emitSend(left, op.lexeme, [right]); | 2674 return _emitSend(left, op.lexeme, [right]); |
2685 } else { | 2675 } else { |
2686 var bang = op.type == TokenType.BANG_EQ ? '!' : ''; | 2676 var bang = op.type == TokenType.BANG_EQ ? '!' : ''; |
2687 code = '${bang}dart.equals(#, #)'; | 2677 code = '${bang}dart.equals(#, #)'; |
2688 } | 2678 } |
2689 return js.call(code, [_visit(left), _visit(right)]); | 2679 return js.call(code, [_visit(left), _visit(right)]); |
2690 } | 2680 } |
2691 | 2681 |
2692 if (op.type.lexeme == '??') { | 2682 if (op.type.lexeme == '??') { |
2693 // TODO(jmesserly): leave RHS for debugging? | 2683 // TODO(jmesserly): leave RHS for debugging? |
2694 // This should be a hint or warning for dead code. | 2684 // This should be a hint or warning for dead code. |
2695 if (!_isNullable(left)) return _visit(left); | 2685 if (!isNullable(left)) return _visit(left); |
2696 | 2686 |
2697 var vars = <String, JS.Expression>{}; | 2687 var vars = <String, JS.Expression>{}; |
2698 // Desugar `l ?? r` as `l != null ? l : r` | 2688 // Desugar `l ?? r` as `l != null ? l : r` |
2699 var l = _visit(_bindValue(vars, 'l', left, context: left)); | 2689 var l = _visit(_bindValue(vars, 'l', left, context: left)); |
2700 return new JS.MetaLet(vars, [ | 2690 return new JS.MetaLet(vars, [ |
2701 js.call('# != null ? # : #', [l, l, _visit(right)]) | 2691 js.call('# != null ? # : #', [l, l, _visit(right)]) |
2702 ]); | 2692 ]); |
2703 } | 2693 } |
2704 | 2694 |
2705 if (binaryOperationIsPrimitive(leftType, rightType) || | 2695 if (binaryOperationIsPrimitive(leftType, rightType) || |
(...skipping 24 matching lines...) Expand all Loading... |
2730 var numType = types.numType; | 2720 var numType = types.numType; |
2731 if (rules.isSubtypeOf(t, numType)) return numType; | 2721 if (rules.isSubtypeOf(t, numType)) return numType; |
2732 return t; | 2722 return t; |
2733 } | 2723 } |
2734 | 2724 |
2735 bool _canUsePrimitiveEquality(Expression left, Expression right) { | 2725 bool _canUsePrimitiveEquality(Expression left, Expression right) { |
2736 if (_isNull(left) || _isNull(right)) return true; | 2726 if (_isNull(left) || _isNull(right)) return true; |
2737 | 2727 |
2738 var leftType = _canonicalizeNumTypes(getStaticType(left)); | 2728 var leftType = _canonicalizeNumTypes(getStaticType(left)); |
2739 var rightType = _canonicalizeNumTypes(getStaticType(right)); | 2729 var rightType = _canonicalizeNumTypes(getStaticType(right)); |
2740 return _isPrimitiveType(leftType) && leftType == rightType; | 2730 return isPrimitiveType(leftType) && leftType == rightType; |
2741 } | 2731 } |
2742 | 2732 |
2743 bool _isNull(Expression expr) => expr is NullLiteral; | 2733 bool _isNull(Expression expr) => expr is NullLiteral; |
2744 | 2734 |
2745 SimpleIdentifier _createTemporary(String name, DartType type, | 2735 SimpleIdentifier _createTemporary(String name, DartType type, |
2746 {bool nullable: true}) { | 2736 {bool nullable: true}) { |
2747 // We use an invalid source location to signal that this is a temporary. | 2737 // We use an invalid source location to signal that this is a temporary. |
2748 // See [_isTemporary]. | 2738 // See [_isTemporary]. |
2749 // TODO(jmesserly): alternatives are | 2739 // TODO(jmesserly): alternatives are |
2750 // * (ab)use Element.isSynthetic, which isn't currently used for | 2740 // * (ab)use Element.isSynthetic, which isn't currently used for |
2751 // LocalVariableElementImpl, so we could repurpose to mean "temp". | 2741 // LocalVariableElementImpl, so we could repurpose to mean "temp". |
2752 // * add a new property to LocalVariableElementImpl. | 2742 // * add a new property to LocalVariableElementImpl. |
2753 // * create a new subtype of LocalVariableElementImpl to mark a temp. | 2743 // * create a new subtype of LocalVariableElementImpl to mark a temp. |
2754 var id = | 2744 var id = |
2755 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); | 2745 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); |
2756 id.staticElement = new TemporaryVariableElement.forNode(id); | 2746 id.staticElement = new TemporaryVariableElement.forNode(id); |
2757 id.staticType = type; | 2747 id.staticType = type; |
2758 DynamicInvoke.set(id, type.isDynamic); | 2748 DynamicInvoke.set(id, type.isDynamic); |
2759 _nullInference.addVariable(id.staticElement, nullable: nullable); | 2749 addTemporaryVariable(id.staticElement, nullable: nullable); |
2760 return id; | 2750 return id; |
2761 } | 2751 } |
2762 | 2752 |
2763 JS.Expression _emitConst(JS.Expression expr()) { | 2753 JS.Expression _emitConst(JS.Expression expr()) { |
2764 // TODO(jmesserly): emit the constants at top level if possible. | 2754 // TODO(jmesserly): emit the constants at top level if possible. |
2765 // This wasn't quite working, so disabled for now. | 2755 // This wasn't quite working, so disabled for now. |
2766 return js.call('dart.const(#)', expr()); | 2756 return js.call('dart.const(#)', expr()); |
2767 } | 2757 } |
2768 | 2758 |
2769 /// Returns a new expression, which can be be used safely *once* on the | 2759 /// Returns a new expression, which can be be used safely *once* on the |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2856 /// | 2846 /// |
2857 /// The [JS.MetaLet] nodes automatically simplify themselves if they can. | 2847 /// The [JS.MetaLet] nodes automatically simplify themselves if they can. |
2858 /// For example, if the result value is not used, then `t` goes away. | 2848 /// For example, if the result value is not used, then `t` goes away. |
2859 @override | 2849 @override |
2860 JS.Expression visitPostfixExpression(PostfixExpression node) { | 2850 JS.Expression visitPostfixExpression(PostfixExpression node) { |
2861 var op = node.operator; | 2851 var op = node.operator; |
2862 var expr = node.operand; | 2852 var expr = node.operand; |
2863 | 2853 |
2864 var dispatchType = getStaticType(expr); | 2854 var dispatchType = getStaticType(expr); |
2865 if (unaryOperationIsPrimitive(dispatchType)) { | 2855 if (unaryOperationIsPrimitive(dispatchType)) { |
2866 if (!_isNullable(expr)) { | 2856 if (!isNullable(expr)) { |
2867 return js.call('#$op', _visit(expr)); | 2857 return js.call('#$op', _visit(expr)); |
2868 } | 2858 } |
2869 } | 2859 } |
2870 | 2860 |
2871 assert(op.lexeme == '++' || op.lexeme == '--'); | 2861 assert(op.lexeme == '++' || op.lexeme == '--'); |
2872 | 2862 |
2873 // Handle the left hand side, to ensure each of its subexpressions are | 2863 // Handle the left hand side, to ensure each of its subexpressions are |
2874 // evaluated only once. | 2864 // evaluated only once. |
2875 var vars = <String, JS.Expression>{}; | 2865 var vars = <String, JS.Expression>{}; |
2876 var left = _bindLeftHandSide(vars, expr, context: expr); | 2866 var left = _bindLeftHandSide(vars, expr, context: expr); |
(...skipping 11 matching lines...) Expand all Loading... |
2888 return new JS.MetaLet(vars, body, statelessResult: true); | 2878 return new JS.MetaLet(vars, body, statelessResult: true); |
2889 } | 2879 } |
2890 | 2880 |
2891 @override | 2881 @override |
2892 JS.Expression visitPrefixExpression(PrefixExpression node) { | 2882 JS.Expression visitPrefixExpression(PrefixExpression node) { |
2893 var op = node.operator; | 2883 var op = node.operator; |
2894 var expr = node.operand; | 2884 var expr = node.operand; |
2895 | 2885 |
2896 var dispatchType = getStaticType(expr); | 2886 var dispatchType = getStaticType(expr); |
2897 if (unaryOperationIsPrimitive(dispatchType)) { | 2887 if (unaryOperationIsPrimitive(dispatchType)) { |
2898 if (!_isNullable(expr)) { | 2888 if (!isNullable(expr)) { |
2899 return js.call('$op#', _visit(expr)); | 2889 return js.call('$op#', _visit(expr)); |
2900 } else if (op.lexeme == '++' || op.lexeme == '--') { | 2890 } else if (op.lexeme == '++' || op.lexeme == '--') { |
2901 // We need a null check, so the increment must be expanded out. | 2891 // We need a null check, so the increment must be expanded out. |
2902 var vars = <String, JS.Expression>{}; | 2892 var vars = <String, JS.Expression>{}; |
2903 var x = _bindLeftHandSide(vars, expr, context: expr); | 2893 var x = _bindLeftHandSide(vars, expr, context: expr); |
2904 | 2894 |
2905 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 2895 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
2906 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) | 2896 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) |
2907 ..staticElement = node.staticElement | 2897 ..staticElement = node.staticElement |
2908 ..staticType = getStaticType(expr); | 2898 ..staticType = getStaticType(expr); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2987 // This pattern has the benefit of preserving order, as well as minimizing | 2977 // This pattern has the benefit of preserving order, as well as minimizing |
2988 // code expansion: each `?.` becomes `, _ => _`, plus one helper call. | 2978 // code expansion: each `?.` becomes `, _ => _`, plus one helper call. |
2989 // | 2979 // |
2990 // TODO(jmesserly): we could desugar with MetaLet instead, which may | 2980 // TODO(jmesserly): we could desugar with MetaLet instead, which may |
2991 // lead to higher performing code, but at the cost of readability. | 2981 // lead to higher performing code, but at the cost of readability. |
2992 var tail = <JS.Expression>[]; | 2982 var tail = <JS.Expression>[]; |
2993 for (;;) { | 2983 for (;;) { |
2994 var op = _getOperator(node); | 2984 var op = _getOperator(node); |
2995 if (op != null && op.lexeme == '?.') { | 2985 if (op != null && op.lexeme == '?.') { |
2996 var nodeTarget = _getTarget(node); | 2986 var nodeTarget = _getTarget(node); |
2997 if (!_isNullable(nodeTarget)) { | 2987 if (!isNullable(nodeTarget)) { |
2998 node = _stripNullAwareOp(node, nodeTarget); | 2988 node = _stripNullAwareOp(node, nodeTarget); |
2999 break; | 2989 break; |
3000 } | 2990 } |
3001 | 2991 |
3002 var param = | 2992 var param = |
3003 _createTemporary('_', nodeTarget.staticType, nullable: false); | 2993 _createTemporary('_', nodeTarget.staticType, nullable: false); |
3004 var baseNode = _stripNullAwareOp(node, param); | 2994 var baseNode = _stripNullAwareOp(node, param); |
3005 tail.add(new JS.ArrowFun([_visit(param)], _visit(baseNode))); | 2995 tail.add(new JS.ArrowFun([_visit(param)], _visit(baseNode))); |
3006 node = nodeTarget; | 2996 node = nodeTarget; |
3007 } else { | 2997 } else { |
(...skipping 16 matching lines...) Expand all Loading... |
3024 return AstBuilder.propertyAccess(newTarget, node.propertyName); | 3014 return AstBuilder.propertyAccess(newTarget, node.propertyName); |
3025 } else { | 3015 } else { |
3026 var invoke = node as MethodInvocation; | 3016 var invoke = node as MethodInvocation; |
3027 return AstBuilder.methodInvoke( | 3017 return AstBuilder.methodInvoke( |
3028 newTarget, invoke.methodName, invoke.argumentList.arguments); | 3018 newTarget, invoke.methodName, invoke.argumentList.arguments); |
3029 } | 3019 } |
3030 } | 3020 } |
3031 | 3021 |
3032 bool _requiresStaticDispatch(Expression target, String memberName) { | 3022 bool _requiresStaticDispatch(Expression target, String memberName) { |
3033 var type = getStaticType(target); | 3023 var type = getStaticType(target); |
3034 if (!_isObjectProperty(memberName)) { | 3024 if (!isObjectProperty(memberName)) { |
3035 return false; | 3025 return false; |
3036 } | 3026 } |
3037 | 3027 |
3038 // If the target could be `null`, we need static dispatch. | 3028 // If the target could be `null`, we need static dispatch. |
3039 // If the target may be an extension type, we also use static dispatch | 3029 // If the target may be an extension type, we also use static dispatch |
3040 // as we don't symbolize object properties like hashCode. | 3030 // as we don't symbolize object properties like hashCode. |
3041 return _isNullable(target) || | 3031 return isNullable(target) || |
3042 (_extensionTypes.contains(type.element) && target is! SuperExpression); | 3032 (_extensionTypes.contains(type.element) && target is! SuperExpression); |
3043 } | 3033 } |
3044 | 3034 |
3045 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 3035 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
3046 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { | 3036 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { |
3047 var member = memberId.staticElement; | 3037 var member = memberId.staticElement; |
3048 if (member is PropertyAccessorElement) { | 3038 if (member is PropertyAccessorElement) { |
3049 member = (member as PropertyAccessorElement).variable; | 3039 member = (member as PropertyAccessorElement).variable; |
3050 } | 3040 } |
3051 bool isStatic = member is ClassMemberElement && member.isStatic; | 3041 bool isStatic = member is ClassMemberElement && member.isStatic; |
(...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3622 } | 3612 } |
3623 | 3613 |
3624 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 3614 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
3625 var baseType = type; | 3615 var baseType = type; |
3626 while (baseType is TypeParameterType) { | 3616 while (baseType is TypeParameterType) { |
3627 baseType = baseType.element.bound; | 3617 baseType = baseType.element.bound; |
3628 } | 3618 } |
3629 if (allowExtensions && | 3619 if (allowExtensions && |
3630 baseType != null && | 3620 baseType != null && |
3631 _extensionTypes.contains(baseType.element) && | 3621 _extensionTypes.contains(baseType.element) && |
3632 !_isObjectProperty(name)) { | 3622 !isObjectProperty(name)) { |
3633 return js.call('dartx.#', _propertyName(name)); | 3623 return js.call('dartx.#', _propertyName(name)); |
3634 } | 3624 } |
3635 | 3625 |
3636 return _propertyName(name); | 3626 return _propertyName(name); |
3637 } | 3627 } |
3638 | 3628 |
3639 bool _externalOrNative(node) => | 3629 bool _externalOrNative(node) => |
3640 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3630 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
3641 | 3631 |
3642 FunctionBody _functionBody(node) => | 3632 FunctionBody _functionBody(node) => |
(...skipping 28 matching lines...) Expand all Loading... |
3671 bool _isObjectGetter(String name) { | 3661 bool _isObjectGetter(String name) { |
3672 PropertyAccessorElement element = _types.objectType.element.getGetter(name); | 3662 PropertyAccessorElement element = _types.objectType.element.getGetter(name); |
3673 return (element != null && !element.isStatic); | 3663 return (element != null && !element.isStatic); |
3674 } | 3664 } |
3675 | 3665 |
3676 bool _isObjectMethod(String name) { | 3666 bool _isObjectMethod(String name) { |
3677 MethodElement element = _types.objectType.element.getMethod(name); | 3667 MethodElement element = _types.objectType.element.getMethod(name); |
3678 return (element != null && !element.isStatic); | 3668 return (element != null && !element.isStatic); |
3679 } | 3669 } |
3680 | 3670 |
3681 bool _isObjectProperty(String name) { | 3671 bool isObjectProperty(String name) { |
3682 return _isObjectGetter(name) || _isObjectMethod(name); | 3672 return _isObjectGetter(name) || _isObjectMethod(name); |
3683 } | 3673 } |
3684 | 3674 |
3685 // TODO(leafp): Various analyzer pieces computed similar things. | 3675 // TODO(leafp): Various analyzer pieces computed similar things. |
3686 // Share this logic somewhere? | 3676 // Share this logic somewhere? |
3687 DartType _getExpectedReturnType(ExecutableElement element) { | 3677 DartType _getExpectedReturnType(ExecutableElement element) { |
3688 FunctionType functionType = element.type; | 3678 FunctionType functionType = element.type; |
3689 if (functionType == null) { | 3679 if (functionType == null) { |
3690 return DynamicTypeImpl.instance; | 3680 return DynamicTypeImpl.instance; |
3691 } | 3681 } |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3861 | 3851 |
3862 /// A special kind of element created by the compiler, signifying a temporary | 3852 /// A special kind of element created by the compiler, signifying a temporary |
3863 /// variable. These objects use instance equality, and should be shared | 3853 /// variable. These objects use instance equality, and should be shared |
3864 /// everywhere in the tree where they are treated as the same variable. | 3854 /// everywhere in the tree where they are treated as the same variable. |
3865 class TemporaryVariableElement extends LocalVariableElementImpl { | 3855 class TemporaryVariableElement extends LocalVariableElementImpl { |
3866 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3856 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); |
3867 | 3857 |
3868 int get hashCode => identityHashCode(this); | 3858 int get hashCode => identityHashCode(this); |
3869 bool operator ==(Object other) => identical(this, other); | 3859 bool operator ==(Object other) => identical(this, other); |
3870 } | 3860 } |
OLD | NEW |