| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library types; | |
| 6 | |
| 7 import '../dart2jslib.dart' hide Selector, TypedSelector; | |
| 8 import '../elements/elements.dart'; | |
| 9 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer; | |
| 10 import '../tree/tree.dart'; | |
| 11 import '../util/util.dart'; | |
| 12 import '../universe/universe.dart'; | |
| 13 import '../inferrer/concrete_types_inferrer.dart' show ConcreteTypesInferrer; | |
| 14 | |
| 15 part 'container_type_mask.dart'; | |
| 16 part 'dictionary_type_mask.dart'; | |
| 17 part 'flat_type_mask.dart'; | |
| 18 part 'forwarding_type_mask.dart'; | |
| 19 part 'map_type_mask.dart'; | |
| 20 part 'type_mask.dart'; | |
| 21 part 'union_type_mask.dart'; | |
| 22 part 'value_type_mask.dart'; | |
| 23 | |
| 24 /** | |
| 25 * Common super class for our type inferrers. | |
| 26 */ | |
| 27 abstract class TypesInferrer { | |
| 28 void analyzeMain(Element element); | |
| 29 TypeMask getReturnTypeOfElement(Element element); | |
| 30 TypeMask getTypeOfElement(Element element); | |
| 31 TypeMask getTypeOfNode(Element owner, Node node); | |
| 32 TypeMask getTypeOfSelector(Selector selector); | |
| 33 void clear(); | |
| 34 bool isCalledOnce(Element element); | |
| 35 bool isFixedArrayCheckedForGrowable(Node node); | |
| 36 } | |
| 37 | |
| 38 /** | |
| 39 * The types task infers guaranteed types globally. | |
| 40 */ | |
| 41 class TypesTask extends CompilerTask { | |
| 42 static final bool DUMP_BAD_CPA_RESULTS = false; | |
| 43 static final bool DUMP_GOOD_CPA_RESULTS = false; | |
| 44 | |
| 45 final String name = 'Type inference'; | |
| 46 final ClassWorld classWorld; | |
| 47 TypesInferrer typesInferrer; | |
| 48 ConcreteTypesInferrer concreteTypesInferrer; | |
| 49 | |
| 50 TypesTask(Compiler compiler) | |
| 51 : this.classWorld = compiler.world, | |
| 52 super(compiler) { | |
| 53 typesInferrer = new TypeGraphInferrer(compiler); | |
| 54 if (compiler.enableConcreteTypeInference) { | |
| 55 concreteTypesInferrer = new ConcreteTypesInferrer(compiler); | |
| 56 } | |
| 57 } | |
| 58 | |
| 59 TypeMask dynamicTypeCache; | |
| 60 TypeMask nonNullTypeCache; | |
| 61 TypeMask nullTypeCache; | |
| 62 TypeMask intTypeCache; | |
| 63 TypeMask uint32TypeCache; | |
| 64 TypeMask uint31TypeCache; | |
| 65 TypeMask positiveIntTypeCache; | |
| 66 TypeMask doubleTypeCache; | |
| 67 TypeMask numTypeCache; | |
| 68 TypeMask boolTypeCache; | |
| 69 TypeMask functionTypeCache; | |
| 70 TypeMask listTypeCache; | |
| 71 TypeMask constListTypeCache; | |
| 72 TypeMask fixedListTypeCache; | |
| 73 TypeMask growableListTypeCache; | |
| 74 TypeMask mapTypeCache; | |
| 75 TypeMask constMapTypeCache; | |
| 76 TypeMask stringTypeCache; | |
| 77 TypeMask typeTypeCache; | |
| 78 | |
| 79 TypeMask get dynamicType { | |
| 80 if (dynamicTypeCache == null) { | |
| 81 dynamicTypeCache = | |
| 82 new TypeMask.subclass(classWorld.objectClass, classWorld); | |
| 83 } | |
| 84 return dynamicTypeCache; | |
| 85 } | |
| 86 | |
| 87 TypeMask get nonNullType { | |
| 88 if (nonNullTypeCache == null) { | |
| 89 nonNullTypeCache = | |
| 90 new TypeMask.nonNullSubclass(classWorld.objectClass, classWorld); | |
| 91 } | |
| 92 return nonNullTypeCache; | |
| 93 } | |
| 94 | |
| 95 TypeMask get intType { | |
| 96 if (intTypeCache == null) { | |
| 97 intTypeCache = new TypeMask.nonNullSubclass( | |
| 98 compiler.backend.intImplementation, compiler.world); | |
| 99 } | |
| 100 return intTypeCache; | |
| 101 } | |
| 102 | |
| 103 TypeMask get uint32Type { | |
| 104 if (uint32TypeCache == null) { | |
| 105 uint32TypeCache = new TypeMask.nonNullSubclass( | |
| 106 compiler.backend.uint32Implementation, compiler.world); | |
| 107 } | |
| 108 return uint32TypeCache; | |
| 109 } | |
| 110 | |
| 111 TypeMask get uint31Type { | |
| 112 if (uint31TypeCache == null) { | |
| 113 uint31TypeCache = new TypeMask.nonNullExact( | |
| 114 compiler.backend.uint31Implementation, compiler.world); | |
| 115 } | |
| 116 return uint31TypeCache; | |
| 117 } | |
| 118 | |
| 119 TypeMask get positiveIntType { | |
| 120 if (positiveIntTypeCache == null) { | |
| 121 positiveIntTypeCache = new TypeMask.nonNullSubclass( | |
| 122 compiler.backend.positiveIntImplementation, compiler.world); | |
| 123 } | |
| 124 return positiveIntTypeCache; | |
| 125 } | |
| 126 | |
| 127 TypeMask get doubleType { | |
| 128 if (doubleTypeCache == null) { | |
| 129 doubleTypeCache = new TypeMask.nonNullExact( | |
| 130 compiler.backend.doubleImplementation, compiler.world); | |
| 131 } | |
| 132 return doubleTypeCache; | |
| 133 } | |
| 134 | |
| 135 TypeMask get numType { | |
| 136 if (numTypeCache == null) { | |
| 137 numTypeCache = new TypeMask.nonNullSubclass( | |
| 138 compiler.backend.numImplementation, compiler.world); | |
| 139 } | |
| 140 return numTypeCache; | |
| 141 } | |
| 142 | |
| 143 TypeMask get boolType { | |
| 144 if (boolTypeCache == null) { | |
| 145 boolTypeCache = new TypeMask.nonNullExact( | |
| 146 compiler.backend.boolImplementation, compiler.world); | |
| 147 } | |
| 148 return boolTypeCache; | |
| 149 } | |
| 150 | |
| 151 TypeMask get functionType { | |
| 152 if (functionTypeCache == null) { | |
| 153 functionTypeCache = new TypeMask.nonNullSubtype( | |
| 154 compiler.backend.functionImplementation, classWorld); | |
| 155 } | |
| 156 return functionTypeCache; | |
| 157 } | |
| 158 | |
| 159 TypeMask get listType { | |
| 160 if (listTypeCache == null) { | |
| 161 listTypeCache = new TypeMask.nonNullExact( | |
| 162 compiler.backend.listImplementation, compiler.world); | |
| 163 } | |
| 164 return listTypeCache; | |
| 165 } | |
| 166 | |
| 167 TypeMask get constListType { | |
| 168 if (constListTypeCache == null) { | |
| 169 constListTypeCache = new TypeMask.nonNullExact( | |
| 170 compiler.backend.constListImplementation, compiler.world); | |
| 171 } | |
| 172 return constListTypeCache; | |
| 173 } | |
| 174 | |
| 175 TypeMask get fixedListType { | |
| 176 if (fixedListTypeCache == null) { | |
| 177 fixedListTypeCache = new TypeMask.nonNullExact( | |
| 178 compiler.backend.fixedListImplementation, compiler.world); | |
| 179 } | |
| 180 return fixedListTypeCache; | |
| 181 } | |
| 182 | |
| 183 TypeMask get growableListType { | |
| 184 if (growableListTypeCache == null) { | |
| 185 growableListTypeCache = new TypeMask.nonNullExact( | |
| 186 compiler.backend.growableListImplementation, compiler.world); | |
| 187 } | |
| 188 return growableListTypeCache; | |
| 189 } | |
| 190 | |
| 191 TypeMask get mapType { | |
| 192 if (mapTypeCache == null) { | |
| 193 mapTypeCache = new TypeMask.nonNullSubtype( | |
| 194 compiler.backend.mapImplementation, classWorld); | |
| 195 } | |
| 196 return mapTypeCache; | |
| 197 } | |
| 198 | |
| 199 TypeMask get constMapType { | |
| 200 if (constMapTypeCache == null) { | |
| 201 constMapTypeCache = new TypeMask.nonNullSubtype( | |
| 202 compiler.backend.constMapImplementation, classWorld); | |
| 203 } | |
| 204 return constMapTypeCache; | |
| 205 } | |
| 206 | |
| 207 TypeMask get stringType { | |
| 208 if (stringTypeCache == null) { | |
| 209 stringTypeCache = new TypeMask.nonNullExact( | |
| 210 compiler.backend.stringImplementation, compiler.world); | |
| 211 } | |
| 212 return stringTypeCache; | |
| 213 } | |
| 214 | |
| 215 TypeMask get typeType { | |
| 216 if (typeTypeCache == null) { | |
| 217 typeTypeCache = new TypeMask.nonNullExact( | |
| 218 compiler.backend.typeImplementation, compiler.world); | |
| 219 } | |
| 220 return typeTypeCache; | |
| 221 } | |
| 222 | |
| 223 TypeMask get nullType { | |
| 224 if (nullTypeCache == null) { | |
| 225 // TODO(johnniwinther): Assert that the null type has been resolved. | |
| 226 nullTypeCache = const TypeMask.empty(); | |
| 227 } | |
| 228 return nullTypeCache; | |
| 229 } | |
| 230 | |
| 231 /** Helper method for [intersection]. */ | |
| 232 TypeMask _intersection(TypeMask type1, TypeMask type2) { | |
| 233 if (type1 == null) return type2; | |
| 234 if (type2 == null) return type1; | |
| 235 return type1.intersection(type2, classWorld); | |
| 236 } | |
| 237 | |
| 238 /** Computes the intersection of [type1] and [type2] */ | |
| 239 TypeMask intersection(TypeMask type1, TypeMask type2, element) { | |
| 240 TypeMask result = _intersection(type1, type2); | |
| 241 if (DUMP_BAD_CPA_RESULTS && better(type1, type2)) { | |
| 242 print("CPA is worse for $element: $type1 /\\ $type2 = $result"); | |
| 243 } | |
| 244 if (DUMP_GOOD_CPA_RESULTS && better(type2, type1)) { | |
| 245 print("CPA is better for $element: $type1 /\\ $type2 = $result"); | |
| 246 } | |
| 247 return result; | |
| 248 } | |
| 249 | |
| 250 /** Returns true if [type1] is strictly bettern than [type2]. */ | |
| 251 bool better(TypeMask type1, TypeMask type2) { | |
| 252 if (type1 == null) return false; | |
| 253 if (type2 == null) { | |
| 254 return (type1 != null) && | |
| 255 (type1 != dynamicType); | |
| 256 } | |
| 257 return (type1 != type2) && | |
| 258 type2.containsMask(type1, classWorld) && | |
| 259 !type1.containsMask(type2, classWorld); | |
| 260 } | |
| 261 | |
| 262 /** | |
| 263 * Called when resolution is complete. | |
| 264 */ | |
| 265 void onResolutionComplete(Element mainElement) { | |
| 266 measure(() { | |
| 267 typesInferrer.analyzeMain(mainElement); | |
| 268 if (concreteTypesInferrer != null) { | |
| 269 bool success = concreteTypesInferrer.analyzeMain(mainElement); | |
| 270 if (!success) { | |
| 271 // If the concrete type inference bailed out, we pretend it didn't | |
| 272 // happen. In the future we might want to record that it failed but | |
| 273 // use the partial results as hints. | |
| 274 concreteTypesInferrer = null; | |
| 275 } | |
| 276 } | |
| 277 }); | |
| 278 typesInferrer.clear(); | |
| 279 } | |
| 280 | |
| 281 /** | |
| 282 * Return the (inferred) guaranteed type of [element] or null. | |
| 283 */ | |
| 284 TypeMask getGuaranteedTypeOfElement(Element element) { | |
| 285 return measure(() { | |
| 286 TypeMask guaranteedType = typesInferrer.getTypeOfElement(element); | |
| 287 return (concreteTypesInferrer == null) | |
| 288 ? guaranteedType | |
| 289 : intersection(guaranteedType, | |
| 290 concreteTypesInferrer.getTypeOfElement(element), | |
| 291 element); | |
| 292 }); | |
| 293 } | |
| 294 | |
| 295 TypeMask getGuaranteedReturnTypeOfElement(Element element) { | |
| 296 return measure(() { | |
| 297 TypeMask guaranteedType = | |
| 298 typesInferrer.getReturnTypeOfElement(element); | |
| 299 return (concreteTypesInferrer == null) | |
| 300 ? guaranteedType | |
| 301 : intersection(guaranteedType, | |
| 302 concreteTypesInferrer.getReturnTypeOfElement(element), | |
| 303 element); | |
| 304 }); | |
| 305 } | |
| 306 | |
| 307 /** | |
| 308 * Return the (inferred) guaranteed type of [node] or null. | |
| 309 * [node] must be an AST node of [owner]. | |
| 310 */ | |
| 311 TypeMask getGuaranteedTypeOfNode(owner, node) { | |
| 312 return measure(() { | |
| 313 TypeMask guaranteedType = typesInferrer.getTypeOfNode(owner, node); | |
| 314 return (concreteTypesInferrer == null) | |
| 315 ? guaranteedType | |
| 316 : intersection(guaranteedType, | |
| 317 concreteTypesInferrer.getTypeOfNode(owner, node), | |
| 318 node); | |
| 319 }); | |
| 320 } | |
| 321 | |
| 322 /** | |
| 323 * Return the (inferred) guaranteed type of [selector] or null. | |
| 324 */ | |
| 325 TypeMask getGuaranteedTypeOfSelector(Selector selector) { | |
| 326 return measure(() { | |
| 327 TypeMask guaranteedType = | |
| 328 typesInferrer.getTypeOfSelector(selector); | |
| 329 return (concreteTypesInferrer == null) | |
| 330 ? guaranteedType | |
| 331 : intersection(guaranteedType, | |
| 332 concreteTypesInferrer.getTypeOfSelector(selector), | |
| 333 selector); | |
| 334 }); | |
| 335 } | |
| 336 } | |
| OLD | NEW |