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; | 5 part of js_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); |
| 11 |
11 /// Get the iterable for all classes that need type checks. | 12 /// Get the iterable for all classes that need type checks. |
12 Iterable<ClassElement> get classes; | 13 Iterable<ClassElement> get classes; |
13 } | 14 } |
14 | 15 |
15 typedef jsAst.Expression OnVariableCallback(TypeVariableType variable); | 16 typedef jsAst.Expression OnVariableCallback(TypeVariableType variable); |
16 typedef bool ShouldEncodeTypedefCallback(TypedefType variable); | 17 typedef bool ShouldEncodeTypedefCallback(TypedefType variable); |
17 | 18 |
18 // TODO(johnniwinther): Rename to something like [RuntimeTypeUsageCollector] | 19 // TODO(johnniwinther): Rename to something like [RuntimeTypeUsageCollector] |
19 // we semantics is more clear. | 20 // we semantics is more clear. |
20 abstract class RuntimeTypes { | 21 abstract class RuntimeTypes { |
21 TypeChecks get requiredChecks; | 22 TypeChecks get requiredChecks; |
22 Iterable<ClassElement> get classesNeedingRti; | 23 Iterable<ClassElement> get classesNeedingRti; |
23 Iterable<Element> get methodsNeedingRti; | 24 Iterable<Element> get methodsNeedingRti; |
24 | 25 |
25 /// The set of classes that use one of their type variables as expressions | 26 /// The set of classes that use one of their type variables as expressions |
26 /// to get the runtime type. | 27 /// to get the runtime type. |
27 Iterable<ClassElement> get classesUsingTypeVariableExpression; | 28 Iterable<ClassElement> get classesUsingTypeVariableExpression; |
28 | 29 |
29 void registerClassUsingTypeVariableExpression(ClassElement cls); | 30 void registerClassUsingTypeVariableExpression(ClassElement cls); |
30 void registerRtiDependency(Element element, Element dependency); | 31 void registerRtiDependency(Element element, Element dependency); |
31 void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument, | 32 void registerTypeVariableBoundsSubtypeCheck( |
32 DartType bound); | 33 DartType typeArgument, DartType bound); |
33 | 34 |
34 Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend, | 35 Set<ClassElement> getClassesUsedInSubstitutions( |
35 TypeChecks checks); | 36 JavaScriptBackend backend, TypeChecks checks); |
36 void computeClassesNeedingRti(); | 37 void computeClassesNeedingRti(); |
37 | 38 |
38 /// Compute the required type checkes and substitutions for the given | 39 /// Compute the required type checkes and substitutions for the given |
39 /// instantitated and checked classes. | 40 /// instantitated and checked classes. |
40 TypeChecks computeChecks(Set<ClassElement> instantiated, | 41 TypeChecks computeChecks( |
41 Set<ClassElement> checked); | 42 Set<ClassElement> instantiated, Set<ClassElement> checked); |
42 | 43 |
43 /// Compute type arguments of classes that use one of their type variables in | 44 /// Compute type arguments of classes that use one of their type variables in |
44 /// is-checks and add the is-checks that they imply. | 45 /// is-checks and add the is-checks that they imply. |
45 /// | 46 /// |
46 /// This function must be called after all is-checks have been registered. | 47 /// This function must be called after all is-checks have been registered. |
47 void addImplicitChecks(Universe universe, | 48 void addImplicitChecks( |
48 Iterable<ClassElement> classesUsingChecks); | 49 Universe universe, Iterable<ClassElement> classesUsingChecks); |
49 | 50 |
50 /// Return all classes that are referenced in the type of the function, i.e., | 51 /// Return all classes that are referenced in the type of the function, i.e., |
51 /// in the return type or the argument types. | 52 /// in the return type or the argument types. |
52 Set<ClassElement> getReferencedClasses(FunctionType type); | 53 Set<ClassElement> getReferencedClasses(FunctionType type); |
53 | 54 |
54 /// Return all classes that are uses a type arguments. | 55 /// Return all classes that are uses a type arguments. |
55 Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend); | 56 Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend); |
56 | 57 |
57 bool isTrivialSubstitution(ClassElement cls, ClassElement check); | 58 bool isTrivialSubstitution(ClassElement cls, ClassElement check); |
58 | 59 |
59 Substitution getSubstitution(ClassElement cls, ClassElement other); | 60 Substitution getSubstitution(ClassElement cls, ClassElement other); |
60 | 61 |
61 static bool hasTypeArguments(DartType type) { | 62 static bool hasTypeArguments(DartType type) { |
62 if (type is InterfaceType) { | 63 if (type is InterfaceType) { |
63 InterfaceType interfaceType = type; | 64 InterfaceType interfaceType = type; |
64 return !interfaceType.treatAsRaw; | 65 return !interfaceType.treatAsRaw; |
65 } | 66 } |
66 return false; | 67 return false; |
67 } | 68 } |
68 } | 69 } |
69 | 70 |
70 abstract class RuntimeTypesEncoder { | 71 abstract class RuntimeTypesEncoder { |
71 bool isSimpleFunctionType(FunctionType type); | 72 bool isSimpleFunctionType(FunctionType type); |
72 | 73 |
73 jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_); | 74 jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_); |
74 | 75 |
75 jsAst.Expression getSubstitutionRepresentation( | 76 jsAst.Expression getSubstitutionRepresentation( |
76 List<DartType> types, | 77 List<DartType> types, OnVariableCallback onVariable); |
77 OnVariableCallback onVariable); | |
78 jsAst.Expression getSubstitutionCode(Substitution substitution); | 78 jsAst.Expression getSubstitutionCode(Substitution substitution); |
79 jsAst.Expression getSubstitutionCodeForVariable( | 79 jsAst.Expression getSubstitutionCodeForVariable( |
80 Substitution substitution, int index); | 80 Substitution substitution, int index); |
81 | 81 |
82 /// Returns the JavaScript template to determine at runtime if a type object | 82 /// Returns the JavaScript template to determine at runtime if a type object |
83 /// is a function type. | 83 /// is a function type. |
84 jsAst.Template get templateForIsFunctionType; | 84 jsAst.Template get templateForIsFunctionType; |
85 | 85 |
86 /// Returns the JavaScript template that creates at runtime a new function | 86 /// Returns the JavaScript template that creates at runtime a new function |
87 /// type object. | 87 /// type object. |
88 jsAst.Template get templateForCreateFunctionType; | 88 jsAst.Template get templateForCreateFunctionType; |
89 jsAst.Name get getFunctionThatReturnsNullName; | 89 jsAst.Name get getFunctionThatReturnsNullName; |
90 | 90 |
91 jsAst.Expression getTypeRepresentation( | 91 jsAst.Expression getTypeRepresentation( |
92 DartType type, | 92 DartType type, OnVariableCallback onVariable, |
93 OnVariableCallback onVariable, | 93 [ShouldEncodeTypedefCallback shouldEncodeTypedef]); |
94 [ShouldEncodeTypedefCallback shouldEncodeTypedef]); | |
95 /** | 94 /** |
96 * Returns a [jsAst.Expression] representing the given [type]. Type | 95 * Returns a [jsAst.Expression] representing the given [type]. Type |
97 * variables are replaced by placeholders in the ast. | 96 * variables are replaced by placeholders in the ast. |
98 * | 97 * |
99 * [firstPlaceholderIndex] is the index to use for the first placeholder. | 98 * [firstPlaceholderIndex] is the index to use for the first placeholder. |
100 * This is useful if the returned [jsAst.Expression] is only part of a | 99 * This is useful if the returned [jsAst.Expression] is only part of a |
101 * larger template. By default, indexing starts with 0. | 100 * larger template. By default, indexing starts with 0. |
102 */ | 101 */ |
103 jsAst.Expression getTypeRepresentationWithPlaceholders(DartType type, | 102 jsAst.Expression getTypeRepresentationWithPlaceholders( |
104 OnVariableCallback onVariable, {int firstPlaceholderIndex : 0}); | 103 DartType type, OnVariableCallback onVariable, |
| 104 {int firstPlaceholderIndex: 0}); |
105 | 105 |
106 String getTypeRepresentationForTypeConstant(DartType type); | 106 String getTypeRepresentationForTypeConstant(DartType type); |
107 } | 107 } |
108 | 108 |
109 class _RuntimeTypes implements RuntimeTypes { | 109 class _RuntimeTypes implements RuntimeTypes { |
110 final Compiler compiler; | 110 final Compiler compiler; |
111 | 111 |
112 final Map<ClassElement, Set<ClassElement>> rtiDependencies; | 112 final Map<ClassElement, Set<ClassElement>> rtiDependencies; |
113 | 113 |
114 @override | 114 @override |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 @override | 150 @override |
151 void registerRtiDependency(Element element, Element dependency) { | 151 void registerRtiDependency(Element element, Element dependency) { |
152 // We're not dealing with typedef for now. | 152 // We're not dealing with typedef for now. |
153 if (!element.isClass || !dependency.isClass) return; | 153 if (!element.isClass || !dependency.isClass) return; |
154 Set<ClassElement> classes = | 154 Set<ClassElement> classes = |
155 rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>()); | 155 rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>()); |
156 classes.add(dependency); | 156 classes.add(dependency); |
157 } | 157 } |
158 | 158 |
159 @override | 159 @override |
160 void registerTypeVariableBoundsSubtypeCheck(DartType typeArgument, | 160 void registerTypeVariableBoundsSubtypeCheck( |
161 DartType bound) { | 161 DartType typeArgument, DartType bound) { |
162 checkedTypeArguments.add(typeArgument); | 162 checkedTypeArguments.add(typeArgument); |
163 checkedBounds.add(bound); | 163 checkedBounds.add(bound); |
164 } | 164 } |
165 | 165 |
166 // TODO(21969): remove this and analyze instantiated types and factory calls | 166 // TODO(21969): remove this and analyze instantiated types and factory calls |
167 // instead to find out which types are instantiated, if finitely many, or if | 167 // instead to find out which types are instantiated, if finitely many, or if |
168 // we have to use the more imprecise generic algorithm. | 168 // we have to use the more imprecise generic algorithm. |
169 bool get cannotDetermineInstantiatedTypesPrecisely => true; | 169 bool get cannotDetermineInstantiatedTypesPrecisely => true; |
170 | 170 |
171 /** | 171 /** |
172 * Compute type arguments of classes that use one of their type variables in | 172 * Compute type arguments of classes that use one of their type variables in |
173 * is-checks and add the is-checks that they imply. | 173 * is-checks and add the is-checks that they imply. |
174 * | 174 * |
175 * This function must be called after all is-checks have been registered. | 175 * This function must be called after all is-checks have been registered. |
176 * | 176 * |
177 * TODO(karlklose): move these computations into a function producing an | 177 * TODO(karlklose): move these computations into a function producing an |
178 * immutable datastructure. | 178 * immutable datastructure. |
179 */ | 179 */ |
180 @override | 180 @override |
181 void addImplicitChecks(Universe universe, | 181 void addImplicitChecks( |
182 Iterable<ClassElement> classesUsingChecks) { | 182 Universe universe, Iterable<ClassElement> classesUsingChecks) { |
183 // If there are no classes that use their variables in checks, there is | 183 // If there are no classes that use their variables in checks, there is |
184 // nothing to do. | 184 // nothing to do. |
185 if (classesUsingChecks.isEmpty) return; | 185 if (classesUsingChecks.isEmpty) return; |
186 Set<DartType> instantiatedTypes = universe.instantiatedTypes; | 186 Set<DartType> instantiatedTypes = universe.instantiatedTypes; |
187 if (cannotDetermineInstantiatedTypesPrecisely) { | 187 if (cannotDetermineInstantiatedTypesPrecisely) { |
188 for (DartType type in instantiatedTypes) { | 188 for (DartType type in instantiatedTypes) { |
189 if (type.kind != TypeKind.INTERFACE) continue; | 189 if (type.kind != TypeKind.INTERFACE) continue; |
190 InterfaceType interface = type; | 190 InterfaceType interface = type; |
191 do { | 191 do { |
192 for (DartType argument in interface.typeArguments) { | 192 for (DartType argument in interface.typeArguments) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 if (type.isFunctionType) { | 286 if (type.isFunctionType) { |
287 void analyzeMethod(TypedElement method) { | 287 void analyzeMethod(TypedElement method) { |
288 DartType memberType = method.type; | 288 DartType memberType = method.type; |
289 ClassElement contextClass = Types.getClassContext(memberType); | 289 ClassElement contextClass = Types.getClassContext(memberType); |
290 if (contextClass != null && | 290 if (contextClass != null && |
291 compiler.types.isPotentialSubtype(memberType, type)) { | 291 compiler.types.isPotentialSubtype(memberType, type)) { |
292 potentiallyAddForRti(contextClass); | 292 potentiallyAddForRti(contextClass); |
293 methodsNeedingRti.add(method); | 293 methodsNeedingRti.add(method); |
294 } | 294 } |
295 } | 295 } |
296 compiler.resolverWorld.closuresWithFreeTypeVariables.forEach( | 296 compiler.resolverWorld.closuresWithFreeTypeVariables |
297 analyzeMethod); | 297 .forEach(analyzeMethod); |
298 compiler.resolverWorld.callMethodsWithFreeTypeVariables.forEach( | 298 compiler.resolverWorld.callMethodsWithFreeTypeVariables |
299 analyzeMethod); | 299 .forEach(analyzeMethod); |
300 } | 300 } |
301 } | 301 } |
302 }); | 302 }); |
303 if (compiler.options.enableTypeAssertions) { | 303 if (compiler.options.enableTypeAssertions) { |
304 void analyzeMethod(TypedElement method) { | 304 void analyzeMethod(TypedElement method) { |
305 DartType memberType = method.type; | 305 DartType memberType = method.type; |
306 ClassElement contextClass = Types.getClassContext(memberType); | 306 ClassElement contextClass = Types.getClassContext(memberType); |
307 if (contextClass != null) { | 307 if (contextClass != null) { |
308 potentiallyAddForRti(contextClass); | 308 potentiallyAddForRti(contextClass); |
309 methodsNeedingRti.add(method); | 309 methodsNeedingRti.add(method); |
310 } | 310 } |
311 } | 311 } |
312 compiler.resolverWorld.closuresWithFreeTypeVariables.forEach( | 312 compiler.resolverWorld.closuresWithFreeTypeVariables |
313 analyzeMethod); | 313 .forEach(analyzeMethod); |
314 compiler.resolverWorld.callMethodsWithFreeTypeVariables.forEach( | 314 compiler.resolverWorld.callMethodsWithFreeTypeVariables |
315 analyzeMethod); | 315 .forEach(analyzeMethod); |
316 } | 316 } |
317 // Add the classes that need RTI because they use a type variable as | 317 // Add the classes that need RTI because they use a type variable as |
318 // expression. | 318 // expression. |
319 classesUsingTypeVariableExpression.forEach(potentiallyAddForRti); | 319 classesUsingTypeVariableExpression.forEach(potentiallyAddForRti); |
320 } | 320 } |
321 | 321 |
322 @override | 322 @override |
323 TypeChecks get requiredChecks { | 323 TypeChecks get requiredChecks { |
324 if (cachedRequiredChecks == null) { | 324 if (cachedRequiredChecks == null) { |
325 computeRequiredChecks(); | 325 computeRequiredChecks(); |
326 } | 326 } |
327 assert(cachedRequiredChecks != null); | 327 assert(cachedRequiredChecks != null); |
328 return cachedRequiredChecks; | 328 return cachedRequiredChecks; |
329 } | 329 } |
330 | 330 |
331 @override | 331 @override |
332 TypeChecks computeChecks(Set<ClassElement> instantiated, | 332 TypeChecks computeChecks( |
333 Set<ClassElement> checked) { | 333 Set<ClassElement> instantiated, Set<ClassElement> checked) { |
334 // Run through the combination of instantiated and checked | 334 // Run through the combination of instantiated and checked |
335 // arguments and record all combination where the element of a checked | 335 // arguments and record all combination where the element of a checked |
336 // argument is a superclass of the element of an instantiated type. | 336 // argument is a superclass of the element of an instantiated type. |
337 TypeCheckMapping result = new TypeCheckMapping(); | 337 TypeCheckMapping result = new TypeCheckMapping(); |
338 for (ClassElement element in instantiated) { | 338 for (ClassElement element in instantiated) { |
339 if (checked.contains(element)) { | 339 if (checked.contains(element)) { |
340 result.add(element, element, null); | 340 result.add(element, element, null); |
341 } | 341 } |
342 // Find all supertypes of [element] in [checkedArguments] and add checks | 342 // Find all supertypes of [element] in [checkedArguments] and add checks |
343 // and precompute the substitutions for them. | 343 // and precompute the substitutions for them. |
344 assert(invariant(element, element.allSupertypes != null, | 344 assert(invariant(element, element.allSupertypes != null, |
345 message: 'Supertypes have not been computed for $element.')); | 345 message: 'Supertypes have not been computed for $element.')); |
346 for (DartType supertype in element.allSupertypes) { | 346 for (DartType supertype in element.allSupertypes) { |
347 ClassElement superelement = supertype.element; | 347 ClassElement superelement = supertype.element; |
348 if (checked.contains(superelement)) { | 348 if (checked.contains(superelement)) { |
349 Substitution substitution = | 349 Substitution substitution = |
350 computeSubstitution(element, superelement); | 350 computeSubstitution(element, superelement); |
351 result.add(element, superelement, substitution); | 351 result.add(element, superelement, substitution); |
352 } | 352 } |
353 } | 353 } |
354 } | 354 } |
355 return result; | 355 return result; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 return instantiatedTypes; | 391 return instantiatedTypes; |
392 } | 392 } |
393 | 393 |
394 /** | 394 /** |
395 * Collects all types used in type arguments of instantiated types. | 395 * Collects all types used in type arguments of instantiated types. |
396 * | 396 * |
397 * This includes type arguments used in supertype relations, because we may | 397 * This includes type arguments used in supertype relations, because we may |
398 * have a type check against this supertype that includes a check against | 398 * have a type check against this supertype that includes a check against |
399 * the type arguments. | 399 * the type arguments. |
400 */ | 400 */ |
401 void computeInstantiatedArguments(Set<DartType> instantiatedTypes, | 401 void computeInstantiatedArguments( |
402 Set<DartType> isChecks) { | 402 Set<DartType> instantiatedTypes, Set<DartType> isChecks) { |
403 ArgumentCollector superCollector = new ArgumentCollector(backend); | 403 ArgumentCollector superCollector = new ArgumentCollector(backend); |
404 ArgumentCollector directCollector = new ArgumentCollector(backend); | 404 ArgumentCollector directCollector = new ArgumentCollector(backend); |
405 FunctionArgumentCollector functionArgumentCollector = | 405 FunctionArgumentCollector functionArgumentCollector = |
406 new FunctionArgumentCollector(backend); | 406 new FunctionArgumentCollector(backend); |
407 | 407 |
408 // We need to add classes occuring in function type arguments, like for | 408 // We need to add classes occuring in function type arguments, like for |
409 // instance 'I' for [: o is C<f> :] where f is [: typedef I f(); :]. | 409 // instance 'I' for [: o is C<f> :] where f is [: typedef I f(); :]. |
410 void collectFunctionTypeArguments(Iterable<DartType> types) { | 410 void collectFunctionTypeArguments(Iterable<DartType> types) { |
411 for (DartType type in types) { | 411 for (DartType type in types) { |
412 functionArgumentCollector.collect(type); | 412 functionArgumentCollector.collect(type); |
413 } | 413 } |
414 } | 414 } |
415 collectFunctionTypeArguments(isChecks); | 415 collectFunctionTypeArguments(isChecks); |
416 collectFunctionTypeArguments(checkedBounds); | 416 collectFunctionTypeArguments(checkedBounds); |
417 | 417 |
418 void collectTypeArguments(Iterable<DartType> types, | 418 void collectTypeArguments(Iterable<DartType> types, |
419 {bool isTypeArgument: false}) { | 419 {bool isTypeArgument: false}) { |
420 for (DartType type in types) { | 420 for (DartType type in types) { |
421 directCollector.collect(type, isTypeArgument: isTypeArgument); | 421 directCollector.collect(type, isTypeArgument: isTypeArgument); |
422 if (type.isInterfaceType) { | 422 if (type.isInterfaceType) { |
423 ClassElement cls = type.element; | 423 ClassElement cls = type.element; |
424 for (DartType supertype in cls.allSupertypes) { | 424 for (DartType supertype in cls.allSupertypes) { |
425 superCollector.collect(supertype, isTypeArgument: isTypeArgument); | 425 superCollector.collect(supertype, isTypeArgument: isTypeArgument); |
426 } | 426 } |
427 } | 427 } |
428 } | 428 } |
429 } | 429 } |
430 collectTypeArguments(instantiatedTypes); | 430 collectTypeArguments(instantiatedTypes); |
431 collectTypeArguments(checkedTypeArguments, isTypeArgument: true); | 431 collectTypeArguments(checkedTypeArguments, isTypeArgument: true); |
432 | 432 |
433 for (ClassElement cls in superCollector.classes.toList()) { | 433 for (ClassElement cls in superCollector.classes.toList()) { |
434 for (DartType supertype in cls.allSupertypes) { | 434 for (DartType supertype in cls.allSupertypes) { |
435 superCollector.collect(supertype); | 435 superCollector.collect(supertype); |
436 } | 436 } |
437 } | 437 } |
438 | 438 |
439 directlyInstantiatedArguments = | 439 directlyInstantiatedArguments = directCollector.classes |
440 directCollector.classes..addAll(functionArgumentCollector.classes); | 440 ..addAll(functionArgumentCollector.classes); |
441 allInstantiatedArguments = | 441 allInstantiatedArguments = superCollector.classes |
442 superCollector.classes..addAll(directlyInstantiatedArguments); | 442 ..addAll(directlyInstantiatedArguments); |
443 } | 443 } |
444 | 444 |
445 /// Collects all type arguments used in is-checks. | 445 /// Collects all type arguments used in is-checks. |
446 void computeCheckedArguments(Set<DartType> instantiatedTypes, | 446 void computeCheckedArguments( |
447 Set<DartType> isChecks) { | 447 Set<DartType> instantiatedTypes, Set<DartType> isChecks) { |
448 ArgumentCollector collector = new ArgumentCollector(backend); | 448 ArgumentCollector collector = new ArgumentCollector(backend); |
449 FunctionArgumentCollector functionArgumentCollector = | 449 FunctionArgumentCollector functionArgumentCollector = |
450 new FunctionArgumentCollector(backend); | 450 new FunctionArgumentCollector(backend); |
451 | 451 |
452 // We need to add types occuring in function type arguments, like for | 452 // We need to add types occuring in function type arguments, like for |
453 // instance 'J' for [: (J j) {} is f :] where f is | 453 // instance 'J' for [: (J j) {} is f :] where f is |
454 // [: typedef void f(I i); :] and 'J' is a subtype of 'I'. | 454 // [: typedef void f(I i); :] and 'J' is a subtype of 'I'. |
455 void collectFunctionTypeArguments(Iterable<DartType> types) { | 455 void collectFunctionTypeArguments(Iterable<DartType> types) { |
456 for (DartType type in types) { | 456 for (DartType type in types) { |
457 functionArgumentCollector.collect(type); | 457 functionArgumentCollector.collect(type); |
458 } | 458 } |
459 } | 459 } |
460 collectFunctionTypeArguments(instantiatedTypes); | 460 collectFunctionTypeArguments(instantiatedTypes); |
461 collectFunctionTypeArguments(checkedTypeArguments); | 461 collectFunctionTypeArguments(checkedTypeArguments); |
462 | 462 |
463 void collectTypeArguments(Iterable<DartType> types, | 463 void collectTypeArguments(Iterable<DartType> types, |
464 {bool isTypeArgument: false}) { | 464 {bool isTypeArgument: false}) { |
465 for (DartType type in types) { | 465 for (DartType type in types) { |
466 collector.collect(type, isTypeArgument: isTypeArgument); | 466 collector.collect(type, isTypeArgument: isTypeArgument); |
467 } | 467 } |
468 } | 468 } |
469 collectTypeArguments(isChecks); | 469 collectTypeArguments(isChecks); |
470 collectTypeArguments(checkedBounds, isTypeArgument: true); | 470 collectTypeArguments(checkedBounds, isTypeArgument: true); |
471 | 471 |
472 checkedArguments = | 472 checkedArguments = collector.classes |
473 collector.classes..addAll(functionArgumentCollector.classes); | 473 ..addAll(functionArgumentCollector.classes); |
474 } | 474 } |
475 | 475 |
476 @override | 476 @override |
477 Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend, | 477 Set<ClassElement> getClassesUsedInSubstitutions( |
478 TypeChecks checks) { | 478 JavaScriptBackend backend, TypeChecks checks) { |
479 Set<ClassElement> instantiated = new Set<ClassElement>(); | 479 Set<ClassElement> instantiated = new Set<ClassElement>(); |
480 ArgumentCollector collector = new ArgumentCollector(backend); | 480 ArgumentCollector collector = new ArgumentCollector(backend); |
481 for (ClassElement target in checks.classes) { | 481 for (ClassElement target in checks.classes) { |
482 instantiated.add(target); | 482 instantiated.add(target); |
483 for (TypeCheck check in checks[target]) { | 483 for (TypeCheck check in checks[target]) { |
484 Substitution substitution = check.substitution; | 484 Substitution substitution = check.substitution; |
485 if (substitution != null) { | 485 if (substitution != null) { |
486 collector.collectAll(substitution.arguments); | 486 collector.collectAll(substitution.arguments); |
487 } | 487 } |
488 } | 488 } |
489 } | 489 } |
490 return instantiated..addAll(collector.classes); | 490 return instantiated..addAll(collector.classes); |
491 } | 491 } |
492 | 492 |
493 @override | 493 @override |
494 Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend) { | 494 Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend) { |
495 Set<ClassElement> requiredArgumentClasses = | 495 Set<ClassElement> requiredArgumentClasses = new Set<ClassElement>.from( |
496 new Set<ClassElement>.from( | 496 getClassesUsedInSubstitutions(backend, requiredChecks)); |
497 getClassesUsedInSubstitutions(backend, requiredChecks)); | |
498 return requiredArgumentClasses | 497 return requiredArgumentClasses |
499 ..addAll(directlyInstantiatedArguments) | 498 ..addAll(directlyInstantiatedArguments) |
500 ..addAll(checkedArguments); | 499 ..addAll(checkedArguments); |
501 } | 500 } |
502 | 501 |
503 @override | 502 @override |
504 Set<ClassElement> getReferencedClasses(FunctionType type) { | 503 Set<ClassElement> getReferencedClasses(FunctionType type) { |
505 FunctionArgumentCollector collector = | 504 FunctionArgumentCollector collector = |
506 new FunctionArgumentCollector(backend); | 505 new FunctionArgumentCollector(backend); |
507 collector.collect(type); | 506 collector.collect(type); |
508 return collector.classes; | 507 return collector.classes; |
509 } | 508 } |
510 | 509 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 if (check.cls == other) { | 550 if (check.cls == other) { |
552 return check.substitution; | 551 return check.substitution; |
553 } | 552 } |
554 } | 553 } |
555 // There is no precomputed check for this pair (because the check is not | 554 // There is no precomputed check for this pair (because the check is not |
556 // done on type arguments only. Compute a new substitution. | 555 // done on type arguments only. Compute a new substitution. |
557 return computeSubstitution(cls, other); | 556 return computeSubstitution(cls, other); |
558 } | 557 } |
559 | 558 |
560 Substitution computeSubstitution(ClassElement cls, ClassElement check, | 559 Substitution computeSubstitution(ClassElement cls, ClassElement check, |
561 { bool alwaysGenerateFunction: false }) { | 560 {bool alwaysGenerateFunction: false}) { |
562 if (isTrivialSubstitution(cls, check)) return null; | 561 if (isTrivialSubstitution(cls, check)) return null; |
563 | 562 |
564 // Unnamed mixin application classes do not need substitutions, because they | 563 // Unnamed mixin application classes do not need substitutions, because they |
565 // are never instantiated and their checks are overwritten by the class that | 564 // are never instantiated and their checks are overwritten by the class that |
566 // they are mixed into. | 565 // they are mixed into. |
567 InterfaceType type = cls.thisType; | 566 InterfaceType type = cls.thisType; |
568 InterfaceType target = type.asInstanceOf(check); | 567 InterfaceType target = type.asInstanceOf(check); |
569 List<DartType> typeVariables = cls.typeVariables; | 568 List<DartType> typeVariables = cls.typeVariables; |
570 if (typeVariables.isEmpty && !alwaysGenerateFunction) { | 569 if (typeVariables.isEmpty && !alwaysGenerateFunction) { |
571 return new Substitution.list(target.typeArguments); | 570 return new Substitution.list(target.typeArguments); |
(...skipping 23 matching lines...) Expand all Loading... |
595 | 594 |
596 /// Returns the JavaScript template that creates at runtime a new function | 595 /// Returns the JavaScript template that creates at runtime a new function |
597 /// type object. | 596 /// type object. |
598 @override | 597 @override |
599 jsAst.Template get templateForCreateFunctionType { | 598 jsAst.Template get templateForCreateFunctionType { |
600 return representationGenerator.templateForCreateFunctionType; | 599 return representationGenerator.templateForCreateFunctionType; |
601 } | 600 } |
602 | 601 |
603 @override | 602 @override |
604 jsAst.Expression getTypeRepresentation( | 603 jsAst.Expression getTypeRepresentation( |
605 DartType type, | 604 DartType type, OnVariableCallback onVariable, |
606 OnVariableCallback onVariable, | |
607 [ShouldEncodeTypedefCallback shouldEncodeTypedef]) { | 605 [ShouldEncodeTypedefCallback shouldEncodeTypedef]) { |
608 return representationGenerator.getTypeRepresentation( | 606 return representationGenerator.getTypeRepresentation( |
609 type, onVariable, shouldEncodeTypedef); | 607 type, onVariable, shouldEncodeTypedef); |
610 } | 608 } |
611 | 609 |
612 @override | 610 @override |
613 jsAst.Expression getTypeRepresentationWithPlaceholders(DartType type, | 611 jsAst.Expression getTypeRepresentationWithPlaceholders( |
614 OnVariableCallback onVariable, {int firstPlaceholderIndex : 0}) { | 612 DartType type, OnVariableCallback onVariable, |
| 613 {int firstPlaceholderIndex: 0}) { |
615 // Create a type representation. For type variables call the original | 614 // Create a type representation. For type variables call the original |
616 // callback for side effects and return a template placeholder. | 615 // callback for side effects and return a template placeholder. |
617 int positions = firstPlaceholderIndex; | 616 int positions = firstPlaceholderIndex; |
618 jsAst.Expression representation = getTypeRepresentation(type, (variable) { | 617 jsAst.Expression representation = getTypeRepresentation(type, (variable) { |
619 onVariable(variable); | 618 onVariable(variable); |
620 return new jsAst.InterpolatedExpression(positions++); | 619 return new jsAst.InterpolatedExpression(positions++); |
621 }); | 620 }); |
622 return representation; | 621 return representation; |
623 } | 622 } |
624 | 623 |
625 @override | 624 @override |
626 jsAst.Expression getSubstitutionRepresentation( | 625 jsAst.Expression getSubstitutionRepresentation( |
627 List<DartType> types, | 626 List<DartType> types, OnVariableCallback onVariable) { |
628 OnVariableCallback onVariable) { | |
629 List<jsAst.Expression> elements = types | 627 List<jsAst.Expression> elements = types |
630 .map((DartType type) => getTypeRepresentation(type, onVariable)) | 628 .map((DartType type) => getTypeRepresentation(type, onVariable)) |
631 .toList(growable: false); | 629 .toList(growable: false); |
632 return new jsAst.ArrayInitializer(elements); | 630 return new jsAst.ArrayInitializer(elements); |
633 } | 631 } |
634 | 632 |
635 jsAst.Expression getTypeEncoding(DartType type, | 633 jsAst.Expression getTypeEncoding(DartType type, |
636 {bool alwaysGenerateFunction: false}) { | 634 {bool alwaysGenerateFunction: false}) { |
637 ClassElement contextClass = Types.getClassContext(type); | 635 ClassElement contextClass = Types.getClassContext(type); |
638 jsAst.Expression onVariable(TypeVariableType v) { | 636 jsAst.Expression onVariable(TypeVariableType v) { |
639 return new jsAst.VariableUse(v.name); | 637 return new jsAst.VariableUse(v.name); |
640 }; | 638 } |
| 639 ; |
641 jsAst.Expression encoding = getTypeRepresentation(type, onVariable); | 640 jsAst.Expression encoding = getTypeRepresentation(type, onVariable); |
642 if (contextClass == null && !alwaysGenerateFunction) { | 641 if (contextClass == null && !alwaysGenerateFunction) { |
643 return encoding; | 642 return encoding; |
644 } else { | 643 } else { |
645 List<String> parameters = const <String>[]; | 644 List<String> parameters = const <String>[]; |
646 if (contextClass != null) { | 645 if (contextClass != null) { |
647 parameters = contextClass.typeVariables.map((type) { | 646 parameters = contextClass.typeVariables.map((type) { |
648 return type.toString(); | 647 return type.toString(); |
649 }).toList(); | 648 }).toList(); |
650 } | 649 } |
651 return js('function(#) { return # }', [parameters, encoding]); | 650 return js('function(#) { return # }', [parameters, encoding]); |
652 } | 651 } |
653 } | 652 } |
654 | 653 |
655 @override | 654 @override |
656 jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_) { | 655 jsAst.Expression getSignatureEncoding(DartType type, jsAst.Expression this_) { |
657 ClassElement contextClass = Types.getClassContext(type); | 656 ClassElement contextClass = Types.getClassContext(type); |
658 jsAst.Expression encoding = | 657 jsAst.Expression encoding = |
659 getTypeEncoding(type, alwaysGenerateFunction: true); | 658 getTypeEncoding(type, alwaysGenerateFunction: true); |
660 if (contextClass != null) { | 659 if (contextClass != null) { |
661 JavaScriptBackend backend = compiler.backend; | 660 JavaScriptBackend backend = compiler.backend; |
662 jsAst.Name contextName = backend.namer.className(contextClass); | 661 jsAst.Name contextName = backend.namer.className(contextClass); |
663 return js('function () { return #(#, #, #); }', | 662 return js('function () { return #(#, #, #); }', [ |
664 [ backend.emitter.staticFunctionAccess( | 663 backend.emitter.staticFunctionAccess(backend.helpers.computeSignature), |
665 backend.helpers.computeSignature), | 664 encoding, |
666 encoding, this_, js.quoteName(contextName) ]); | 665 this_, |
| 666 js.quoteName(contextName) |
| 667 ]); |
667 } else { | 668 } else { |
668 return encoding; | 669 return encoding; |
669 } | 670 } |
670 } | 671 } |
671 | 672 |
672 /** | 673 /** |
673 * Compute a JavaScript expression that describes the necessary substitution | 674 * Compute a JavaScript expression that describes the necessary substitution |
674 * for type arguments in a subtype test. | 675 * for type arguments in a subtype test. |
675 * | 676 * |
676 * The result can be: | 677 * The result can be: |
(...skipping 25 matching lines...) Expand all Loading... |
702 Iterable<jsAst.Expression> formals = | 703 Iterable<jsAst.Expression> formals = |
703 substitution.parameters.map(declaration); | 704 substitution.parameters.map(declaration); |
704 return js('function(#) { return # }', [formals, value]); | 705 return js('function(#) { return # }', [formals, value]); |
705 } else { | 706 } else { |
706 return js('function() { return # }', value); | 707 return js('function() { return # }', value); |
707 } | 708 } |
708 } | 709 } |
709 } | 710 } |
710 | 711 |
711 @override | 712 @override |
712 jsAst.Expression getSubstitutionCodeForVariable(Substitution substitution, | 713 jsAst.Expression getSubstitutionCodeForVariable( |
713 int index) { | 714 Substitution substitution, int index) { |
714 jsAst.Expression declaration(TypeVariableType variable) { | 715 jsAst.Expression declaration(TypeVariableType variable) { |
715 return new jsAst.Parameter(getVariableName(variable.name)); | 716 return new jsAst.Parameter(getVariableName(variable.name)); |
716 } | 717 } |
717 | 718 |
718 jsAst.Expression use(TypeVariableType variable) { | 719 jsAst.Expression use(TypeVariableType variable) { |
719 return new jsAst.VariableUse(getVariableName(variable.name)); | 720 return new jsAst.VariableUse(getVariableName(variable.name)); |
720 } | 721 } |
721 | 722 |
722 if (substitution.arguments[index].isDynamic) { | 723 if (substitution.arguments[index].isDynamic) { |
723 return backend.emitter.emitter.generateFunctionThatReturnsNull(); | 724 return backend.emitter.emitter.generateFunctionThatReturnsNull(); |
724 } else { | 725 } else { |
725 jsAst.Expression value = | 726 jsAst.Expression value = |
726 getTypeRepresentation(substitution.arguments[index], use); | 727 getTypeRepresentation(substitution.arguments[index], use); |
727 Iterable<jsAst.Expression> formals = | 728 Iterable<jsAst.Expression> formals = |
728 substitution.parameters.map(declaration); | 729 substitution.parameters.map(declaration); |
729 return js('function(#) { return # }', [formals, value]); | 730 return js('function(#) { return # }', [formals, value]); |
730 } | 731 } |
731 } | 732 } |
732 | 733 |
733 String getVariableName(String name) { | 734 String getVariableName(String name) { |
734 return backend.namer.safeVariableName(name); | 735 return backend.namer.safeVariableName(name); |
735 } | 736 } |
736 | 737 |
737 @override | 738 @override |
738 jsAst.Name get getFunctionThatReturnsNullName | 739 jsAst.Name get getFunctionThatReturnsNullName => |
739 => backend.namer.internalGlobal('functionThatReturnsNull'); | 740 backend.namer.internalGlobal('functionThatReturnsNull'); |
740 | 741 |
741 @override | 742 @override |
742 String getTypeRepresentationForTypeConstant(DartType type) { | 743 String getTypeRepresentationForTypeConstant(DartType type) { |
743 JavaScriptBackend backend = compiler.backend; | 744 JavaScriptBackend backend = compiler.backend; |
744 Namer namer = backend.namer; | 745 Namer namer = backend.namer; |
745 if (type.isDynamic) return "dynamic"; | 746 if (type.isDynamic) return "dynamic"; |
746 String name = namer.uniqueNameForTypeConstantElement(type.element); | 747 String name = namer.uniqueNameForTypeConstantElement(type.element); |
747 if (!type.element.isClass) return name; | 748 if (!type.element.isClass) return name; |
748 InterfaceType interface = type; | 749 InterfaceType interface = type; |
749 List<DartType> variables = interface.element.typeVariables; | 750 List<DartType> variables = interface.element.typeVariables; |
750 // Type constants can currently only be raw types, so there is no point | 751 // Type constants can currently only be raw types, so there is no point |
751 // adding ground-term type parameters, as they would just be 'dynamic'. | 752 // adding ground-term type parameters, as they would just be 'dynamic'. |
752 // TODO(sra): Since the result string is used only in constructing constant | 753 // TODO(sra): Since the result string is used only in constructing constant |
753 // names, it would result in more readable names if the final string was a | 754 // names, it would result in more readable names if the final string was a |
754 // legal JavaScript identifer. | 755 // legal JavaScript identifer. |
755 if (variables.isEmpty) return name; | 756 if (variables.isEmpty) return name; |
756 String arguments = | 757 String arguments = new List.filled(variables.length, 'dynamic').join(', '); |
757 new List.filled(variables.length, 'dynamic').join(', '); | |
758 return '$name<$arguments>'; | 758 return '$name<$arguments>'; |
759 } | 759 } |
760 | 760 |
761 @override | 761 @override |
762 bool isSimpleFunctionType(FunctionType type) { | 762 bool isSimpleFunctionType(FunctionType type) { |
763 if (!type.returnType.isDynamic) return false; | 763 if (!type.returnType.isDynamic) return false; |
764 if (!type.optionalParameterTypes.isEmpty) return false; | 764 if (!type.optionalParameterTypes.isEmpty) return false; |
765 if (!type.namedParameterTypes.isEmpty) return false; | 765 if (!type.namedParameterTypes.isEmpty) return false; |
766 for (DartType parameter in type.parameterTypes ) { | 766 for (DartType parameter in type.parameterTypes) { |
767 if (!parameter.isDynamic) return false; | 767 if (!parameter.isDynamic) return false; |
768 } | 768 } |
769 return true; | 769 return true; |
770 } | 770 } |
771 } | 771 } |
772 | 772 |
773 class TypeRepresentationGenerator implements DartTypeVisitor { | 773 class TypeRepresentationGenerator implements DartTypeVisitor { |
774 final Compiler compiler; | 774 final Compiler compiler; |
775 OnVariableCallback onVariable; | 775 OnVariableCallback onVariable; |
776 ShouldEncodeTypedefCallback shouldEncodeTypedef; | 776 ShouldEncodeTypedefCallback shouldEncodeTypedef; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
838 /// is a function type. | 838 /// is a function type. |
839 jsAst.Template get templateForIsFunctionType { | 839 jsAst.Template get templateForIsFunctionType { |
840 return jsAst.js.expressionTemplateFor("'${namer.functionTypeTag}' in #"); | 840 return jsAst.js.expressionTemplateFor("'${namer.functionTypeTag}' in #"); |
841 } | 841 } |
842 | 842 |
843 /// Returns the JavaScript template that creates at runtime a new function | 843 /// Returns the JavaScript template that creates at runtime a new function |
844 /// type object. | 844 /// type object. |
845 jsAst.Template get templateForCreateFunctionType { | 845 jsAst.Template get templateForCreateFunctionType { |
846 // The value of the functionTypeTag can be anything. We use "dynaFunc" for | 846 // The value of the functionTypeTag can be anything. We use "dynaFunc" for |
847 // easier debugging. | 847 // easier debugging. |
848 return jsAst.js.expressionTemplateFor( | 848 return jsAst.js |
849 '{ ${namer.functionTypeTag}: "dynafunc" }'); | 849 .expressionTemplateFor('{ ${namer.functionTypeTag}: "dynafunc" }'); |
850 } | 850 } |
851 | 851 |
852 visitFunctionType(FunctionType type, _) { | 852 visitFunctionType(FunctionType type, _) { |
853 List<jsAst.Property> properties = <jsAst.Property>[]; | 853 List<jsAst.Property> properties = <jsAst.Property>[]; |
854 | 854 |
855 void addProperty(String name, jsAst.Expression value) { | 855 void addProperty(String name, jsAst.Expression value) { |
856 properties.add(new jsAst.Property(js.string(name), value)); | 856 properties.add(new jsAst.Property(js.string(name), value)); |
857 } | 857 } |
858 | 858 |
859 // Type representations for functions have a property which is a tag marking | 859 // Type representations for functions have a property which is a tag marking |
860 // them as function types. The value is not used, so '1' is just a dummy. | 860 // them as function types. The value is not used, so '1' is just a dummy. |
861 addProperty(namer.functionTypeTag, js.number(1)); | 861 addProperty(namer.functionTypeTag, js.number(1)); |
862 if (type.returnType.isVoid) { | 862 if (type.returnType.isVoid) { |
863 addProperty(namer.functionTypeVoidReturnTag, js('true')); | 863 addProperty(namer.functionTypeVoidReturnTag, js('true')); |
864 } else if (!type.returnType.treatAsDynamic) { | 864 } else if (!type.returnType.treatAsDynamic) { |
865 addProperty(namer.functionTypeReturnTypeTag, visit(type.returnType)); | 865 addProperty(namer.functionTypeReturnTypeTag, visit(type.returnType)); |
866 } | 866 } |
867 if (!type.parameterTypes.isEmpty) { | 867 if (!type.parameterTypes.isEmpty) { |
868 addProperty(namer.functionTypeRequiredParametersTag, | 868 addProperty(namer.functionTypeRequiredParametersTag, |
869 visitList(type.parameterTypes)); | 869 visitList(type.parameterTypes)); |
870 } | 870 } |
871 if (!type.optionalParameterTypes.isEmpty) { | 871 if (!type.optionalParameterTypes.isEmpty) { |
872 addProperty(namer.functionTypeOptionalParametersTag, | 872 addProperty(namer.functionTypeOptionalParametersTag, |
873 visitList(type.optionalParameterTypes)); | 873 visitList(type.optionalParameterTypes)); |
874 } | 874 } |
875 if (!type.namedParameterTypes.isEmpty) { | 875 if (!type.namedParameterTypes.isEmpty) { |
876 List<jsAst.Property> namedArguments = <jsAst.Property>[]; | 876 List<jsAst.Property> namedArguments = <jsAst.Property>[]; |
877 List<String> names = type.namedParameters; | 877 List<String> names = type.namedParameters; |
878 List<DartType> types = type.namedParameterTypes; | 878 List<DartType> types = type.namedParameterTypes; |
879 assert(types.length == names.length); | 879 assert(types.length == names.length); |
880 for (int index = 0; index < types.length; index++) { | 880 for (int index = 0; index < types.length; index++) { |
881 jsAst.Expression name = js.string(names[index]); | 881 jsAst.Expression name = js.string(names[index]); |
882 namedArguments.add(new jsAst.Property(name, visit(types[index]))); | 882 namedArguments.add(new jsAst.Property(name, visit(types[index]))); |
883 } | 883 } |
884 addProperty(namer.functionTypeNamedParametersTag, | 884 addProperty(namer.functionTypeNamedParametersTag, |
885 new jsAst.ObjectInitializer(namedArguments)); | 885 new jsAst.ObjectInitializer(namedArguments)); |
886 } | 886 } |
887 return new jsAst.ObjectInitializer(properties); | 887 return new jsAst.ObjectInitializer(properties); |
888 } | 888 } |
889 | 889 |
890 visitMalformedType(MalformedType type, _) { | 890 visitMalformedType(MalformedType type, _) { |
891 // Treat malformed types as dynamic at runtime. | 891 // Treat malformed types as dynamic at runtime. |
892 return js('null'); | 892 return js('null'); |
893 } | 893 } |
894 | 894 |
895 visitVoidType(VoidType type, _) { | 895 visitVoidType(VoidType type, _) { |
(...skipping 14 matching lines...) Expand all Loading... |
910 // Add it to the function-type object. | 910 // Add it to the function-type object. |
911 jsAst.LiteralString tag = js.string(namer.typedefTag); | 911 jsAst.LiteralString tag = js.string(namer.typedefTag); |
912 initializer.properties.add(new jsAst.Property(tag, encodedTypedef)); | 912 initializer.properties.add(new jsAst.Property(tag, encodedTypedef)); |
913 return initializer; | 913 return initializer; |
914 } else { | 914 } else { |
915 return unaliasedType.accept(this, null); | 915 return unaliasedType.accept(this, null); |
916 } | 916 } |
917 } | 917 } |
918 | 918 |
919 visitStatementType(StatementType type, _) { | 919 visitStatementType(StatementType type, _) { |
920 reporter.internalError(NO_LOCATION_SPANNABLE, | 920 reporter.internalError( |
921 'Unexpected type: $type (${type.kind}).'); | 921 NO_LOCATION_SPANNABLE, 'Unexpected type: $type (${type.kind}).'); |
922 } | 922 } |
923 } | 923 } |
924 | 924 |
925 | |
926 class TypeCheckMapping implements TypeChecks { | 925 class TypeCheckMapping implements TypeChecks { |
927 final Map<ClassElement, Set<TypeCheck>> map = | 926 final Map<ClassElement, Set<TypeCheck>> map = |
928 new Map<ClassElement, Set<TypeCheck>>(); | 927 new Map<ClassElement, Set<TypeCheck>>(); |
929 | 928 |
930 Iterable<TypeCheck> operator[](ClassElement element) { | 929 Iterable<TypeCheck> operator [](ClassElement element) { |
931 Set<TypeCheck> result = map[element]; | 930 Set<TypeCheck> result = map[element]; |
932 return result != null ? result : const <TypeCheck>[]; | 931 return result != null ? result : const <TypeCheck>[]; |
933 } | 932 } |
934 | 933 |
935 void add(ClassElement cls, ClassElement check, Substitution substitution) { | 934 void add(ClassElement cls, ClassElement check, Substitution substitution) { |
936 map.putIfAbsent(cls, () => new Set<TypeCheck>()); | 935 map.putIfAbsent(cls, () => new Set<TypeCheck>()); |
937 map[cls].add(new TypeCheck(check, substitution)); | 936 map[cls].add(new TypeCheck(check, substitution)); |
938 } | 937 } |
939 | 938 |
940 Iterable<ClassElement> get classes => map.keys; | 939 Iterable<ClassElement> get classes => map.keys; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1028 //TODO(floitsch): Remove support for non-function substitutions. | 1027 //TODO(floitsch): Remove support for non-function substitutions. |
1029 class Substitution { | 1028 class Substitution { |
1030 final bool isFunction; | 1029 final bool isFunction; |
1031 final List<DartType> arguments; | 1030 final List<DartType> arguments; |
1032 final List<DartType> parameters; | 1031 final List<DartType> parameters; |
1033 | 1032 |
1034 Substitution.list(this.arguments) | 1033 Substitution.list(this.arguments) |
1035 : isFunction = false, | 1034 : isFunction = false, |
1036 parameters = const <DartType>[]; | 1035 parameters = const <DartType>[]; |
1037 | 1036 |
1038 Substitution.function(this.arguments, this.parameters) | 1037 Substitution.function(this.arguments, this.parameters) : isFunction = true; |
1039 : isFunction = true; | |
1040 } | 1038 } |
1041 | 1039 |
1042 /** | 1040 /** |
1043 * A pair of a class that we need a check against and the type argument | 1041 * A pair of a class that we need a check against and the type argument |
1044 * substition for this check. | 1042 * substition for this check. |
1045 */ | 1043 */ |
1046 class TypeCheck { | 1044 class TypeCheck { |
1047 final ClassElement cls; | 1045 final ClassElement cls; |
1048 final Substitution substitution; | 1046 final Substitution substitution; |
1049 final int hashCode = (nextHash++) & 0x3fffffff; | 1047 final int hashCode = (nextHash++) & 0x3fffffff; |
1050 static int nextHash = 49; | 1048 static int nextHash = 49; |
1051 | 1049 |
1052 TypeCheck(this.cls, this.substitution); | 1050 TypeCheck(this.cls, this.substitution); |
1053 } | 1051 } |
OLD | NEW |