| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 '../common.dart'; | 5 import '../common.dart'; |
| 6 import '../common/backend_api.dart' show ForeignResolver; | 6 import '../common/backend_api.dart' show ForeignResolver; |
| 7 import '../common/resolution.dart' show ParsingContext, Resolution; | 7 import '../common/resolution.dart' show ParsingContext, Resolution; |
| 8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 * If there is one or more `@Returns` annotations, the union of the named types | 123 * If there is one or more `@Returns` annotations, the union of the named types |
| 124 * replaces the declared return type. | 124 * replaces the declared return type. |
| 125 * | 125 * |
| 126 * @Returns('IDBRequest') | 126 * @Returns('IDBRequest') |
| 127 * IDBRequest openCursor(); | 127 * IDBRequest openCursor(); |
| 128 * | 128 * |
| 129 * Types in annotations are non-nullable, so include `@Returns('Null')` if | 129 * Types in annotations are non-nullable, so include `@Returns('Null')` if |
| 130 * `null` may be returned. | 130 * `null` may be returned. |
| 131 */ | 131 */ |
| 132 class NativeBehavior { | 132 class NativeBehavior { |
| 133 /// [DartType]s or [SpecialType]s returned or yielded by the native element. | 133 /// [ResolutionDartType]s or [SpecialType]s returned or yielded by the native |
| 134 /// element. |
| 134 final List typesReturned = []; | 135 final List typesReturned = []; |
| 135 | 136 |
| 136 /// [DartType]s or [SpecialType]s instantiated by the native element. | 137 /// [ResolutionDartType]s or [SpecialType]s instantiated by the native |
| 138 /// element. |
| 137 final List typesInstantiated = []; | 139 final List typesInstantiated = []; |
| 138 | 140 |
| 139 String codeTemplateText; | 141 String codeTemplateText; |
| 140 // If this behavior is for a JS expression, [codeTemplate] contains the | 142 // If this behavior is for a JS expression, [codeTemplate] contains the |
| 141 // parsed tree. | 143 // parsed tree. |
| 142 js.Template codeTemplate; | 144 js.Template codeTemplate; |
| 143 | 145 |
| 144 final SideEffects sideEffects; | 146 final SideEffects sideEffects; |
| 145 | 147 |
| 146 NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY; | 148 NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY; |
| (...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 behavior.sideEffects.setTo(new SideEffects.empty()); | 739 behavior.sideEffects.setTo(new SideEffects.empty()); |
| 738 behavior.throwBehavior = NativeThrowBehavior.NEVER; | 740 behavior.throwBehavior = NativeThrowBehavior.NEVER; |
| 739 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( | 741 _fillNativeBehaviorOfBuiltinOrEmbeddedGlobal( |
| 740 behavior, spannable, specString, lookupType, reporter, commonElements, | 742 behavior, spannable, specString, lookupType, reporter, commonElements, |
| 741 validTags: ['returns', 'creates']); | 743 validTags: ['returns', 'creates']); |
| 742 return behavior; | 744 return behavior; |
| 743 } | 745 } |
| 744 | 746 |
| 745 static NativeBehavior ofMethodElement( | 747 static NativeBehavior ofMethodElement( |
| 746 FunctionElement element, Compiler compiler) { | 748 FunctionElement element, Compiler compiler) { |
| 747 FunctionType type = element.computeType(compiler.resolution); | 749 ResolutionFunctionType type = element.computeType(compiler.resolution); |
| 748 List<ConstantExpression> metadata = <ConstantExpression>[]; | 750 List<ConstantExpression> metadata = <ConstantExpression>[]; |
| 749 for (MetadataAnnotation annotation in element.implementation.metadata) { | 751 for (MetadataAnnotation annotation in element.implementation.metadata) { |
| 750 annotation.ensureResolved(compiler.resolution); | 752 annotation.ensureResolved(compiler.resolution); |
| 751 metadata.add(annotation.constant); | 753 metadata.add(annotation.constant); |
| 752 } | 754 } |
| 753 | 755 |
| 754 DartType lookup(String name) { | 756 ResolutionDartType lookup(String name) { |
| 755 Element e = element.buildScope().lookup(name); | 757 Element e = element.buildScope().lookup(name); |
| 756 if (e == null) return null; | 758 if (e == null) return null; |
| 757 if (e is! ClassElement) return null; | 759 if (e is! ClassElement) return null; |
| 758 ClassElement cls = e; | 760 ClassElement cls = e; |
| 759 cls.ensureResolved(compiler.resolution); | 761 cls.ensureResolved(compiler.resolution); |
| 760 return cls.thisType; | 762 return cls.thisType; |
| 761 } | 763 } |
| 762 | 764 |
| 763 return ofMethod(element, type, metadata, lookup, compiler, | 765 return ofMethod(element, type, metadata, lookup, compiler, |
| 764 isJsInterop: compiler.backend.isJsInterop(element)); | 766 isJsInterop: compiler.backend.isJsInterop(element)); |
| 765 } | 767 } |
| 766 | 768 |
| 767 static NativeBehavior ofMethod( | 769 static NativeBehavior ofMethod( |
| 768 Spannable spannable, | 770 Spannable spannable, |
| 769 FunctionType type, | 771 ResolutionFunctionType type, |
| 770 List<ConstantExpression> metadata, | 772 List<ConstantExpression> metadata, |
| 771 TypeLookup lookupType, | 773 TypeLookup lookupType, |
| 772 Compiler compiler, | 774 Compiler compiler, |
| 773 {bool isJsInterop}) { | 775 {bool isJsInterop}) { |
| 774 var behavior = new NativeBehavior(); | 776 var behavior = new NativeBehavior(); |
| 775 var returnType = type.returnType; | 777 var returnType = type.returnType; |
| 776 // Note: For dart:html and other internal libraries we maintain, we can | 778 // Note: For dart:html and other internal libraries we maintain, we can |
| 777 // trust the return type and use it to limit what we enqueue. We have to | 779 // trust the return type and use it to limit what we enqueue. We have to |
| 778 // be more conservative about JS interop types and assume they can return | 780 // be more conservative about JS interop types and assume they can return |
| 779 // anything (unless the user provides the experimental flag to trust the | 781 // anything (unless the user provides the experimental flag to trust the |
| 780 // type of js-interop APIs). We do restrict the allocation effects and say | 782 // type of js-interop APIs). We do restrict the allocation effects and say |
| 781 // that interop calls create only interop types (which may be unsound if | 783 // that interop calls create only interop types (which may be unsound if |
| 782 // an interop call returns a DOM type and declares a dynamic return type, | 784 // an interop call returns a DOM type and declares a dynamic return type, |
| 783 // but otherwise we would include a lot of code by default). | 785 // but otherwise we would include a lot of code by default). |
| 784 // TODO(sigmund,sra): consider doing something better for numeric types. | 786 // TODO(sigmund,sra): consider doing something better for numeric types. |
| 785 behavior.typesReturned.add( | 787 behavior.typesReturned.add( |
| 786 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations | 788 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations |
| 787 ? returnType | 789 ? returnType |
| 788 : const DynamicType()); | 790 : const ResolutionDynamicType()); |
| 789 if (!type.returnType.isVoid) { | 791 if (!type.returnType.isVoid) { |
| 790 // Declared types are nullable. | 792 // Declared types are nullable. |
| 791 behavior.typesReturned.add(compiler.commonElements.nullType); | 793 behavior.typesReturned.add(compiler.commonElements.nullType); |
| 792 } | 794 } |
| 793 behavior._capture(type, compiler.resolution, | 795 behavior._capture(type, compiler.resolution, |
| 794 isInterop: isJsInterop, compiler: compiler); | 796 isInterop: isJsInterop, compiler: compiler); |
| 795 | 797 |
| 796 for (DartType type in type.optionalParameterTypes) { | 798 for (ResolutionDartType type in type.optionalParameterTypes) { |
| 797 behavior._escape(type, compiler.resolution); | 799 behavior._escape(type, compiler.resolution); |
| 798 } | 800 } |
| 799 for (DartType type in type.namedParameterTypes) { | 801 for (ResolutionDartType type in type.namedParameterTypes) { |
| 800 behavior._escape(type, compiler.resolution); | 802 behavior._escape(type, compiler.resolution); |
| 801 } | 803 } |
| 802 | 804 |
| 803 behavior._overrideWithAnnotations( | 805 behavior._overrideWithAnnotations( |
| 804 spannable, metadata, lookupType, compiler); | 806 spannable, metadata, lookupType, compiler); |
| 805 return behavior; | 807 return behavior; |
| 806 } | 808 } |
| 807 | 809 |
| 808 static NativeBehavior ofFieldElementLoad( | 810 static NativeBehavior ofFieldElementLoad( |
| 809 MemberElement element, Compiler compiler) { | 811 MemberElement element, Compiler compiler) { |
| 810 Resolution resolution = compiler.resolution; | 812 Resolution resolution = compiler.resolution; |
| 811 DartType type = element.computeType(resolution); | 813 ResolutionDartType type = element.computeType(resolution); |
| 812 List<ConstantExpression> metadata = <ConstantExpression>[]; | 814 List<ConstantExpression> metadata = <ConstantExpression>[]; |
| 813 for (MetadataAnnotation annotation in element.implementation.metadata) { | 815 for (MetadataAnnotation annotation in element.implementation.metadata) { |
| 814 annotation.ensureResolved(compiler.resolution); | 816 annotation.ensureResolved(compiler.resolution); |
| 815 metadata.add(annotation.constant); | 817 metadata.add(annotation.constant); |
| 816 } | 818 } |
| 817 | 819 |
| 818 DartType lookup(String name) { | 820 ResolutionDartType lookup(String name) { |
| 819 Element e = element.buildScope().lookup(name); | 821 Element e = element.buildScope().lookup(name); |
| 820 if (e == null) return null; | 822 if (e == null) return null; |
| 821 if (e is! ClassElement) return null; | 823 if (e is! ClassElement) return null; |
| 822 ClassElement cls = e; | 824 ClassElement cls = e; |
| 823 cls.ensureResolved(compiler.resolution); | 825 cls.ensureResolved(compiler.resolution); |
| 824 return cls.thisType; | 826 return cls.thisType; |
| 825 } | 827 } |
| 826 | 828 |
| 827 return ofFieldLoad(element, type, metadata, lookup, compiler, | 829 return ofFieldLoad(element, type, metadata, lookup, compiler, |
| 828 isJsInterop: compiler.backend.isJsInterop(element)); | 830 isJsInterop: compiler.backend.isJsInterop(element)); |
| 829 } | 831 } |
| 830 | 832 |
| 831 static NativeBehavior ofFieldLoad( | 833 static NativeBehavior ofFieldLoad( |
| 832 Spannable spannable, | 834 Spannable spannable, |
| 833 DartType type, | 835 ResolutionDartType type, |
| 834 List<ConstantExpression> metadata, | 836 List<ConstantExpression> metadata, |
| 835 TypeLookup lookupType, | 837 TypeLookup lookupType, |
| 836 Compiler compiler, | 838 Compiler compiler, |
| 837 {bool isJsInterop}) { | 839 {bool isJsInterop}) { |
| 838 Resolution resolution = compiler.resolution; | 840 Resolution resolution = compiler.resolution; |
| 839 var behavior = new NativeBehavior(); | 841 var behavior = new NativeBehavior(); |
| 840 // TODO(sigmund,sra): consider doing something better for numeric types. | 842 // TODO(sigmund,sra): consider doing something better for numeric types. |
| 841 behavior.typesReturned.add( | 843 behavior.typesReturned.add( |
| 842 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations | 844 !isJsInterop || compiler.options.trustJSInteropTypeAnnotations |
| 843 ? type | 845 ? type |
| 844 : const DynamicType()); | 846 : const ResolutionDynamicType()); |
| 845 // Declared types are nullable. | 847 // Declared types are nullable. |
| 846 behavior.typesReturned.add(resolution.commonElements.nullType); | 848 behavior.typesReturned.add(resolution.commonElements.nullType); |
| 847 behavior._capture(type, resolution, | 849 behavior._capture(type, resolution, |
| 848 isInterop: isJsInterop, compiler: compiler); | 850 isInterop: isJsInterop, compiler: compiler); |
| 849 behavior._overrideWithAnnotations( | 851 behavior._overrideWithAnnotations( |
| 850 spannable, metadata, lookupType, compiler); | 852 spannable, metadata, lookupType, compiler); |
| 851 return behavior; | 853 return behavior; |
| 852 } | 854 } |
| 853 | 855 |
| 854 static NativeBehavior ofFieldElementStore( | 856 static NativeBehavior ofFieldElementStore( |
| 855 MemberElement field, Resolution resolution) { | 857 MemberElement field, Resolution resolution) { |
| 856 DartType type = field.computeType(resolution); | 858 ResolutionDartType type = field.computeType(resolution); |
| 857 return ofFieldStore(type, resolution); | 859 return ofFieldStore(type, resolution); |
| 858 } | 860 } |
| 859 | 861 |
| 860 static NativeBehavior ofFieldStore(DartType type, Resolution resolution) { | 862 static NativeBehavior ofFieldStore( |
| 863 ResolutionDartType type, Resolution resolution) { |
| 861 var behavior = new NativeBehavior(); | 864 var behavior = new NativeBehavior(); |
| 862 behavior._escape(type, resolution); | 865 behavior._escape(type, resolution); |
| 863 // We don't override the default behaviour - the annotations apply to | 866 // We don't override the default behaviour - the annotations apply to |
| 864 // loading the field. | 867 // loading the field. |
| 865 return behavior; | 868 return behavior; |
| 866 } | 869 } |
| 867 | 870 |
| 868 void _overrideWithAnnotations( | 871 void _overrideWithAnnotations( |
| 869 Spannable spannable, | 872 Spannable spannable, |
| 870 Iterable<ConstantExpression> metadata, | 873 Iterable<ConstantExpression> metadata, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 917 var type = _parseType(typeString, spannable, reporter, lookupType); | 920 var type = _parseType(typeString, spannable, reporter, lookupType); |
| 918 if (types == null) types = []; | 921 if (types == null) types = []; |
| 919 types.add(type); | 922 types.add(type); |
| 920 } | 923 } |
| 921 } | 924 } |
| 922 return types; | 925 return types; |
| 923 } | 926 } |
| 924 | 927 |
| 925 /// Models the behavior of having intances of [type] escape from Dart code | 928 /// Models the behavior of having intances of [type] escape from Dart code |
| 926 /// into native code. | 929 /// into native code. |
| 927 void _escape(DartType type, Resolution resolution) { | 930 void _escape(ResolutionDartType type, Resolution resolution) { |
| 928 type.computeUnaliased(resolution); | 931 type.computeUnaliased(resolution); |
| 929 type = type.unaliased; | 932 type = type.unaliased; |
| 930 if (type is FunctionType) { | 933 if (type is ResolutionFunctionType) { |
| 931 FunctionType functionType = type; | 934 ResolutionFunctionType functionType = type; |
| 932 // A function might be called from native code, passing us novel | 935 // A function might be called from native code, passing us novel |
| 933 // parameters. | 936 // parameters. |
| 934 _escape(functionType.returnType, resolution); | 937 _escape(functionType.returnType, resolution); |
| 935 for (DartType parameter in functionType.parameterTypes) { | 938 for (ResolutionDartType parameter in functionType.parameterTypes) { |
| 936 _capture(parameter, resolution); | 939 _capture(parameter, resolution); |
| 937 } | 940 } |
| 938 } | 941 } |
| 939 } | 942 } |
| 940 | 943 |
| 941 /// Models the behavior of Dart code receiving instances and methods of [type] | 944 /// Models the behavior of Dart code receiving instances and methods of [type] |
| 942 /// from native code. We usually start the analysis by capturing a native | 945 /// from native code. We usually start the analysis by capturing a native |
| 943 /// method that has been used. | 946 /// method that has been used. |
| 944 /// | 947 /// |
| 945 /// We assume that JS-interop APIs cannot instantiate Dart types or | 948 /// We assume that JS-interop APIs cannot instantiate Dart types or |
| 946 /// non-JSInterop native types. | 949 /// non-JSInterop native types. |
| 947 void _capture(DartType type, Resolution resolution, | 950 void _capture(ResolutionDartType type, Resolution resolution, |
| 948 {bool isInterop: false, Compiler compiler}) { | 951 {bool isInterop: false, Compiler compiler}) { |
| 949 type.computeUnaliased(resolution); | 952 type.computeUnaliased(resolution); |
| 950 type = type.unaliased; | 953 type = type.unaliased; |
| 951 if (type is FunctionType) { | 954 if (type is ResolutionFunctionType) { |
| 952 FunctionType functionType = type; | 955 ResolutionFunctionType functionType = type; |
| 953 _capture(functionType.returnType, resolution, | 956 _capture(functionType.returnType, resolution, |
| 954 isInterop: isInterop, compiler: compiler); | 957 isInterop: isInterop, compiler: compiler); |
| 955 for (DartType parameter in functionType.parameterTypes) { | 958 for (ResolutionDartType parameter in functionType.parameterTypes) { |
| 956 _escape(parameter, resolution); | 959 _escape(parameter, resolution); |
| 957 } | 960 } |
| 958 } else { | 961 } else { |
| 959 JavaScriptBackend backend = compiler?.backend; | 962 JavaScriptBackend backend = compiler?.backend; |
| 960 if (!isInterop) { | 963 if (!isInterop) { |
| 961 typesInstantiated.add(type); | 964 typesInstantiated.add(type); |
| 962 } else { | 965 } else { |
| 963 if (type.element != null && backend.isNative(type.element)) { | 966 if (type.element != null && backend.isNative(type.element)) { |
| 964 // Any declared native or interop type (isNative implies isJsInterop) | 967 // Any declared native or interop type (isNative implies isJsInterop) |
| 965 // is assumed to be allocated. | 968 // is assumed to be allocated. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 985 // API. | 988 // API. |
| 986 } | 989 } |
| 987 } | 990 } |
| 988 } | 991 } |
| 989 } | 992 } |
| 990 | 993 |
| 991 static dynamic /*DartType|SpecialType*/ _parseType(String typeString, | 994 static dynamic /*DartType|SpecialType*/ _parseType(String typeString, |
| 992 Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) { | 995 Spannable spannable, DiagnosticReporter reporter, TypeLookup lookupType) { |
| 993 if (typeString == '=Object') return SpecialType.JsObject; | 996 if (typeString == '=Object') return SpecialType.JsObject; |
| 994 if (typeString == 'dynamic') { | 997 if (typeString == 'dynamic') { |
| 995 return const DynamicType(); | 998 return const ResolutionDynamicType(); |
| 996 } | 999 } |
| 997 var type = lookupType(typeString); | 1000 var type = lookupType(typeString); |
| 998 if (type != null) return type; | 1001 if (type != null) return type; |
| 999 | 1002 |
| 1000 int index = typeString.indexOf('<'); | 1003 int index = typeString.indexOf('<'); |
| 1001 if (index < 1) { | 1004 if (index < 1) { |
| 1002 reporter.reportErrorMessage(spannable, MessageKind.GENERIC, | 1005 reporter.reportErrorMessage(spannable, MessageKind.GENERIC, |
| 1003 {'text': "Type '$typeString' not found."}); | 1006 {'text': "Type '$typeString' not found."}); |
| 1004 return const DynamicType(); | 1007 return const ResolutionDynamicType(); |
| 1005 } | 1008 } |
| 1006 type = lookupType(typeString.substring(0, index)); | 1009 type = lookupType(typeString.substring(0, index)); |
| 1007 if (type != null) { | 1010 if (type != null) { |
| 1008 // TODO(sra): Parse type parameters. | 1011 // TODO(sra): Parse type parameters. |
| 1009 return type; | 1012 return type; |
| 1010 } | 1013 } |
| 1011 reporter.reportErrorMessage(spannable, MessageKind.GENERIC, | 1014 reporter.reportErrorMessage(spannable, MessageKind.GENERIC, |
| 1012 {'text': "Type '$typeString' not found."}); | 1015 {'text': "Type '$typeString' not found."}); |
| 1013 return const DynamicType(); | 1016 return const ResolutionDynamicType(); |
| 1014 } | 1017 } |
| 1015 } | 1018 } |
| OLD | NEW |