OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of js_backend.backend; | 5 part of js_backend.backend; |
6 | 6 |
7 /// For each class, stores the possible class subtype tests that could succeed. | 7 /// For each class, stores the possible class subtype tests that could succeed. |
8 abstract class TypeChecks { | 8 abstract class TypeChecks { |
9 /// Get the set of checks required for class [element]. | 9 /// Get the set of checks required for class [element]. |
10 Iterable<TypeCheck> operator [](ClassElement element); | 10 Iterable<TypeCheck> operator [](ClassElement element); |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
871 return '$name<$arguments>'; | 871 return '$name<$arguments>'; |
872 } | 872 } |
873 } | 873 } |
874 | 874 |
875 class TypeRepresentationGenerator implements DartTypeVisitor { | 875 class TypeRepresentationGenerator implements DartTypeVisitor { |
876 final Namer namer; | 876 final Namer namer; |
877 final CodeEmitterTask emitter; | 877 final CodeEmitterTask emitter; |
878 OnVariableCallback onVariable; | 878 OnVariableCallback onVariable; |
879 ShouldEncodeTypedefCallback shouldEncodeTypedef; | 879 ShouldEncodeTypedefCallback shouldEncodeTypedef; |
880 | 880 |
| 881 Map<ResolutionTypeVariableType, jsAst.Expression> typedefBindings; |
| 882 |
881 TypeRepresentationGenerator(this.namer, this.emitter); | 883 TypeRepresentationGenerator(this.namer, this.emitter); |
882 | 884 |
883 /** | 885 /** |
884 * Creates a type representation for [type]. [onVariable] is called to provide | 886 * Creates a type representation for [type]. [onVariable] is called to provide |
885 * the type representation for type variables. | 887 * the type representation for type variables. |
886 */ | 888 */ |
887 jsAst.Expression getTypeRepresentation( | 889 jsAst.Expression getTypeRepresentation( |
888 ResolutionDartType type, | 890 ResolutionDartType type, |
889 OnVariableCallback onVariable, | 891 OnVariableCallback onVariable, |
890 ShouldEncodeTypedefCallback encodeTypedef) { | 892 ShouldEncodeTypedefCallback encodeTypedef) { |
| 893 assert(typedefBindings == null); |
891 this.onVariable = onVariable; | 894 this.onVariable = onVariable; |
892 this.shouldEncodeTypedef = (encodeTypedef != null) | 895 this.shouldEncodeTypedef = (encodeTypedef != null) |
893 ? encodeTypedef | 896 ? encodeTypedef |
894 : (ResolutionTypedefType type) => false; | 897 : (ResolutionTypedefType type) => false; |
895 jsAst.Expression representation = visit(type); | 898 jsAst.Expression representation = visit(type); |
896 this.onVariable = null; | 899 this.onVariable = null; |
897 this.shouldEncodeTypedef = null; | 900 this.shouldEncodeTypedef = null; |
898 return representation; | 901 return representation; |
899 } | 902 } |
900 | 903 |
901 jsAst.Expression getJavaScriptClassName(Element element) { | 904 jsAst.Expression getJavaScriptClassName(Element element) { |
902 return emitter.typeAccess(element); | 905 return emitter.typeAccess(element); |
903 } | 906 } |
904 | 907 |
905 @override | 908 @override |
906 visit(ResolutionDartType type, [_]) => type.accept(this, null); | 909 visit(ResolutionDartType type, [_]) => type.accept(this, null); |
907 | 910 |
908 visitTypeVariableType(ResolutionTypeVariableType type, _) { | 911 visitTypeVariableType(ResolutionTypeVariableType type, _) { |
| 912 if (typedefBindings != null) { |
| 913 assert(typedefBindings[type] != null); |
| 914 return typedefBindings[type]; |
| 915 } |
909 return onVariable(type); | 916 return onVariable(type); |
910 } | 917 } |
911 | 918 |
912 visitDynamicType(ResolutionDynamicType type, _) { | 919 visitDynamicType(ResolutionDynamicType type, _) { |
913 return js('null'); | 920 return js('null'); |
914 } | 921 } |
915 | 922 |
916 visitInterfaceType(ResolutionInterfaceType type, _) { | 923 visitInterfaceType(ResolutionInterfaceType type, _) { |
917 jsAst.Expression name = getJavaScriptClassName(type.element); | 924 jsAst.Expression name = getJavaScriptClassName(type.element); |
918 return type.treatAsRaw ? name : visitList(type.typeArguments, head: name); | 925 return type.treatAsRaw ? name : visitList(type.typeArguments, head: name); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 } | 1001 } |
995 | 1002 |
996 visitVoidType(ResolutionVoidType type, _) { | 1003 visitVoidType(ResolutionVoidType type, _) { |
997 // TODO(ahe): Reify void type ("null" means "dynamic"). | 1004 // TODO(ahe): Reify void type ("null" means "dynamic"). |
998 return js('null'); | 1005 return js('null'); |
999 } | 1006 } |
1000 | 1007 |
1001 visitTypedefType(ResolutionTypedefType type, _) { | 1008 visitTypedefType(ResolutionTypedefType type, _) { |
1002 bool shouldEncode = shouldEncodeTypedef(type); | 1009 bool shouldEncode = shouldEncodeTypedef(type); |
1003 ResolutionDartType unaliasedType = type.unaliased; | 1010 ResolutionDartType unaliasedType = type.unaliased; |
| 1011 |
| 1012 var oldBindings = typedefBindings; |
| 1013 if (typedefBindings == null) { |
| 1014 // First level typedef - capture arguments for re-use within typedef body. |
| 1015 // |
| 1016 // The type `Map<T, Foo<Set<T>>>` contains one type variable referenced |
| 1017 // twice, so there are two inputs into the HTypeInfoExpression |
| 1018 // instruction. |
| 1019 // |
| 1020 // If Foo is a typedef, T can be reused, e.g. |
| 1021 // |
| 1022 // typedef E Foo<E>(E a, E b); |
| 1023 // |
| 1024 // As the typedef is expanded (to (Set<T>, Set<T>) => Set<T>) it should |
| 1025 // not consume additional types from the to-level input. We prevent this |
| 1026 // by capturing the types and using the captured type expressions inside |
| 1027 // the typedef expansion. |
| 1028 // |
| 1029 // TODO(sra): We should make the type subexpression Foo<...> be a second |
| 1030 // HTypeInfoExpression, with Set<T> as its input (a third |
| 1031 // HTypeInfoExpression). This would share all the Set<T> subexpressions |
| 1032 // instead of duplicating them. This would require HTypeInfoExpression |
| 1033 // inputs to correspond to type variables AND typedefs. |
| 1034 typedefBindings = <ResolutionTypeVariableType, jsAst.Expression>{}; |
| 1035 type.forEachTypeVariable((variable) { |
| 1036 if (variable is! MethodTypeVariableType) { |
| 1037 typedefBindings[variable] = onVariable(variable); |
| 1038 } |
| 1039 }); |
| 1040 } |
| 1041 |
| 1042 jsAst.Expression finish(jsAst.Expression result) { |
| 1043 typedefBindings = oldBindings; |
| 1044 return result; |
| 1045 } |
| 1046 |
1004 if (shouldEncode) { | 1047 if (shouldEncode) { |
1005 jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null); | 1048 jsAst.ObjectInitializer initializer = unaliasedType.accept(this, null); |
1006 // We have to encode the aliased type. | 1049 // We have to encode the aliased type. |
1007 jsAst.Expression name = getJavaScriptClassName(type.element); | 1050 jsAst.Expression name = getJavaScriptClassName(type.element); |
1008 jsAst.Expression encodedTypedef = | 1051 jsAst.Expression encodedTypedef = |
1009 type.treatAsRaw ? name : visitList(type.typeArguments, head: name); | 1052 type.treatAsRaw ? name : visitList(type.typeArguments, head: name); |
1010 | 1053 |
1011 // Add it to the function-type object. | 1054 // Add it to the function-type object. |
1012 jsAst.LiteralString tag = js.string(namer.typedefTag); | 1055 jsAst.LiteralString tag = js.string(namer.typedefTag); |
1013 initializer.properties.add(new jsAst.Property(tag, encodedTypedef)); | 1056 initializer.properties.add(new jsAst.Property(tag, encodedTypedef)); |
1014 return initializer; | 1057 return finish(initializer); |
1015 } else { | 1058 } else { |
1016 return unaliasedType.accept(this, null); | 1059 return finish(unaliasedType.accept(this, null)); |
1017 } | 1060 } |
1018 } | 1061 } |
1019 } | 1062 } |
1020 | 1063 |
1021 class TypeCheckMapping implements TypeChecks { | 1064 class TypeCheckMapping implements TypeChecks { |
1022 final Map<ClassElement, Set<TypeCheck>> map = | 1065 final Map<ClassElement, Set<TypeCheck>> map = |
1023 new Map<ClassElement, Set<TypeCheck>>(); | 1066 new Map<ClassElement, Set<TypeCheck>>(); |
1024 | 1067 |
1025 Iterable<TypeCheck> operator [](ClassElement element) { | 1068 Iterable<TypeCheck> operator [](ClassElement element) { |
1026 Set<TypeCheck> result = map[element]; | 1069 Set<TypeCheck> result = map[element]; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1134 * substition for this check. | 1177 * substition for this check. |
1135 */ | 1178 */ |
1136 class TypeCheck { | 1179 class TypeCheck { |
1137 final ClassElement cls; | 1180 final ClassElement cls; |
1138 final Substitution substitution; | 1181 final Substitution substitution; |
1139 final int hashCode = _nextHash = (_nextHash + 100003).toUnsigned(30); | 1182 final int hashCode = _nextHash = (_nextHash + 100003).toUnsigned(30); |
1140 static int _nextHash = 0; | 1183 static int _nextHash = 0; |
1141 | 1184 |
1142 TypeCheck(this.cls, this.substitution); | 1185 TypeCheck(this.cls, this.substitution); |
1143 } | 1186 } |
OLD | NEW |