OLD | NEW |
---|---|
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 import 'package:front_end/src/base/instrumentation.dart'; | 5 import 'package:front_end/src/base/instrumentation.dart'; |
6 import 'package:front_end/src/dependency_walker.dart' as dependencyWalker; | 6 import 'package:front_end/src/dependency_walker.dart' as dependencyWalker; |
7 import 'package:front_end/src/fasta/errors.dart'; | 7 import 'package:front_end/src/fasta/errors.dart'; |
8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart'; | 8 import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart'; |
9 import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart' ; | 9 import 'package:front_end/src/fasta/type_inference/type_inference_listener.dart' ; |
10 import 'package:front_end/src/fasta/type_inference/type_inferrer.dart'; | 10 import 'package:front_end/src/fasta/type_inference/type_inferrer.dart'; |
11 import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart' ; | 11 import 'package:front_end/src/fasta/type_inference/type_schema_environment.dart' ; |
12 import 'package:kernel/ast.dart' | 12 import 'package:kernel/ast.dart' |
13 show Class, DartType, DynamicType, Field, InterfaceType, Member, Procedure; | 13 show |
14 Class, | |
15 DartType, | |
16 DynamicType, | |
17 Field, | |
18 FunctionType, | |
19 InterfaceType, | |
20 Member, | |
21 Procedure, | |
22 TypeParameter, | |
23 TypeParameterType; | |
14 import 'package:kernel/class_hierarchy.dart'; | 24 import 'package:kernel/class_hierarchy.dart'; |
15 import 'package:kernel/core_types.dart'; | 25 import 'package:kernel/core_types.dart'; |
16 import 'package:kernel/type_algebra.dart'; | 26 import 'package:kernel/type_algebra.dart'; |
17 | 27 |
18 /// Data structure for tracking dependencies among fields, getters, and setters | 28 /// Data structure for tracking dependencies among fields, getters, and setters |
19 /// that require type inference. | 29 /// that require type inference. |
20 /// | 30 /// |
21 /// TODO(paulberry): see if it's possible to make this class more lightweight | 31 /// TODO(paulberry): see if it's possible to make this class more lightweight |
22 /// by changing the API so that the walker is passed to computeDependencies(). | 32 /// by changing the API so that the walker is passed to computeDependencies(). |
23 /// (This should allow us to drop the _typeInferenceEngine field). | 33 /// (This should allow us to drop the _typeInferenceEngine field). |
24 class AccessorNode extends dependencyWalker.Node<AccessorNode> { | 34 class AccessorNode extends dependencyWalker.Node<AccessorNode> { |
25 final TypeInferenceEngineImpl _typeInferenceEngine; | 35 final TypeInferenceEngineImpl _typeInferenceEngine; |
26 | 36 |
27 final KernelMember member; | 37 final KernelMember member; |
28 | 38 |
29 bool isImmediatelyEvident = false; | 39 bool isImmediatelyEvident = false; |
30 | 40 |
31 AccessorState state = AccessorState.NotInferredYet; | 41 InferenceState state = InferenceState.NotInferredYet; |
32 | 42 |
33 /// If [state] is [AccessorState.Inferring], and type inference for this | 43 /// If [state] is [InferenceState.Inferring], and type inference for this |
34 /// accessor is waiting on type inference of some other accessor, the accessor | 44 /// accessor is waiting on type inference of some other accessor, the accessor |
35 /// that is being waited on. | 45 /// that is being waited on. |
36 /// | 46 /// |
37 /// Otherwise `null`. | 47 /// Otherwise `null`. |
38 AccessorNode currentDependency; | 48 AccessorNode currentDependency; |
39 | 49 |
40 final overrides = <Member>[]; | 50 final overrides = <Member>[]; |
41 | 51 |
42 final crossOverrides = <Member>[]; | 52 final crossOverrides = <Member>[]; |
43 | 53 |
44 AccessorNode(this._typeInferenceEngine, this.member); | 54 AccessorNode(this._typeInferenceEngine, this.member); |
45 | 55 |
46 get candidateOverrides => overrides.isNotEmpty ? overrides : crossOverrides; | 56 get candidateOverrides => overrides.isNotEmpty ? overrides : crossOverrides; |
47 | 57 |
48 @override | 58 @override |
49 bool get isEvaluated => state == AccessorState.Inferred; | 59 bool get isEvaluated => state == InferenceState.Inferred; |
50 | 60 |
51 @override | 61 @override |
52 List<AccessorNode> computeDependencies() { | 62 List<AccessorNode> computeDependencies() { |
53 return _typeInferenceEngine.computeAccessorDependencies(this); | 63 return _typeInferenceEngine.computeAccessorDependencies(this); |
54 } | 64 } |
55 | 65 |
56 @override | 66 @override |
57 String toString() => member.toString(); | 67 String toString() => member.toString(); |
58 } | 68 } |
59 | 69 |
60 /// Enum tracking the type inference state of an accessor. | 70 /// Enum tracking the type inference state of an accessor or method. |
61 enum AccessorState { | 71 enum InferenceState { |
62 /// The accessor's type has not been inferred yet. | 72 /// The accessor or method's type has not been inferred yet. |
63 NotInferredYet, | 73 NotInferredYet, |
64 | 74 |
65 /// Type inference is in progress for the accessor. | 75 /// Type inference is in progress for the accessor or method. |
66 /// | 76 /// |
67 /// This means that code is currently on the stack which is attempting to | 77 /// This means that code is currently on the stack which is attempting to |
68 /// determine the type of the accessor. | 78 /// determine the type of the accessor or method. |
69 Inferring, | 79 Inferring, |
70 | 80 |
71 /// The accessor's type has been inferred. | 81 /// The accessor or method's type has been inferred. |
72 Inferred | 82 Inferred |
73 } | 83 } |
74 | 84 |
85 /// Data structure for tracking dependencies among methods that require type | |
86 /// inference. | |
87 class MethodNode { | |
88 final KernelProcedure procedure; | |
89 | |
90 InferenceState state = InferenceState.NotInferredYet; | |
91 | |
92 final overrides = <Procedure>[]; | |
93 | |
94 MethodNode(this.procedure); | |
95 | |
96 @override | |
97 String toString() => procedure.toString(); | |
98 } | |
99 | |
75 /// Keeps track of the global state for the type inference that occurs outside | 100 /// Keeps track of the global state for the type inference that occurs outside |
76 /// of method bodies and initalizers. | 101 /// of method bodies and initalizers. |
77 /// | 102 /// |
78 /// This class describes the interface for use by clients of type inference | 103 /// This class describes the interface for use by clients of type inference |
79 /// (e.g. DietListener). Derived classes should derive from | 104 /// (e.g. DietListener). Derived classes should derive from |
80 /// [TypeInferenceEngineImpl]. | 105 /// [TypeInferenceEngineImpl]. |
81 abstract class TypeInferenceEngine { | 106 abstract class TypeInferenceEngine { |
82 ClassHierarchy get classHierarchy; | 107 ClassHierarchy get classHierarchy; |
83 | 108 |
84 CoreTypes get coreTypes; | 109 CoreTypes get coreTypes; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
139 /// | 164 /// |
140 /// Requires [fusedTopLevelInference] to be `true`. | 165 /// Requires [fusedTopLevelInference] to be `true`. |
141 static const bool fullTopLevelInference = true; | 166 static const bool fullTopLevelInference = true; |
142 | 167 |
143 final Instrumentation instrumentation; | 168 final Instrumentation instrumentation; |
144 | 169 |
145 final bool strongMode; | 170 final bool strongMode; |
146 | 171 |
147 final accessorNodes = <AccessorNode>[]; | 172 final accessorNodes = <AccessorNode>[]; |
148 | 173 |
174 final methodNodes = <MethodNode>[]; | |
175 | |
149 final initializingFormals = <KernelVariableDeclaration>[]; | 176 final initializingFormals = <KernelVariableDeclaration>[]; |
150 | 177 |
151 @override | 178 @override |
152 CoreTypes coreTypes; | 179 CoreTypes coreTypes; |
153 | 180 |
154 @override | 181 @override |
155 ClassHierarchy classHierarchy; | 182 ClassHierarchy classHierarchy; |
156 | 183 |
157 TypeSchemaEnvironment typeSchemaEnvironment; | 184 TypeSchemaEnvironment typeSchemaEnvironment; |
158 | 185 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 } else { | 233 } else { |
207 // Member is a getter/setter that doesn't override anything, so we can't | 234 // Member is a getter/setter that doesn't override anything, so we can't |
208 // infer a type for it; therefore it has no dependencies. | 235 // infer a type for it; therefore it has no dependencies. |
209 return const []; | 236 return const []; |
210 } | 237 } |
211 } | 238 } |
212 | 239 |
213 /// Creates an [AccessorNode] to track dependencies of the given [member]. | 240 /// Creates an [AccessorNode] to track dependencies of the given [member]. |
214 AccessorNode createAccessorNode(KernelMember member); | 241 AccessorNode createAccessorNode(KernelMember member); |
215 | 242 |
243 /// Creates a [MethodNode] to track dependencies of the given [procedure]. | |
244 MethodNode createMethodNode(KernelProcedure procedure); | |
245 | |
216 @override | 246 @override |
217 void finishTopLevel() { | 247 void finishTopLevel() { |
248 for (var methodNode in methodNodes) { | |
249 inferMethodIfNeeded(methodNode); | |
250 } | |
218 for (var accessorNode in accessorNodes) { | 251 for (var accessorNode in accessorNodes) { |
219 if (fusedTopLevelInference) { | 252 if (fusedTopLevelInference) { |
220 assert(expandedTopLevelInference); | 253 assert(expandedTopLevelInference); |
221 inferAccessorFused(accessorNode, null); | 254 inferAccessorFused(accessorNode, null); |
222 } else { | 255 } else { |
223 if (accessorNode.isEvaluated) continue; | 256 if (accessorNode.isEvaluated) continue; |
224 new _AccessorWalker().walk(accessorNode); | 257 new _AccessorWalker().walk(accessorNode); |
225 } | 258 } |
226 } | 259 } |
227 for (var formal in initializingFormals) { | 260 for (var formal in initializingFormals) { |
228 formal.type = _inferInitializingFormalType(formal); | 261 formal.type = _inferInitializingFormalType(formal); |
229 } | 262 } |
230 } | 263 } |
231 | 264 |
232 /// Retrieve the [TypeInferrer] for the given [member], which was created by | 265 /// Retrieve the [TypeInferrer] for the given [member], which was created by |
233 /// a previous call to [createTopLevelTypeInferrer]. | 266 /// a previous call to [createTopLevelTypeInferrer]. |
234 TypeInferrerImpl getMemberTypeInferrer(KernelMember member); | 267 TypeInferrerImpl getMemberTypeInferrer(KernelMember member); |
235 | 268 |
269 DartType getNamedParameterType(FunctionType functionType, String name) { | |
270 return functionType.getNamedParameter(name) ?? const DynamicType(); | |
271 } | |
272 | |
273 DartType getPositionalParameterType(FunctionType functionType, int i) { | |
274 if (i < functionType.positionalParameters.length) { | |
275 return functionType.positionalParameters[i]; | |
276 } else { | |
277 return const DynamicType(); | |
Siggi Cherem (dart-lang)
2017/06/21 20:19:08
report an error instead? (same thing when the name
Paul Berry
2017/06/21 20:54:47
Good question--I should have been clearer here. L
| |
278 } | |
279 } | |
280 | |
236 /// Performs type inference on the given [accessorNode]. | 281 /// Performs type inference on the given [accessorNode]. |
237 void inferAccessor(AccessorNode accessorNode) { | 282 void inferAccessor(AccessorNode accessorNode) { |
238 assert(accessorNode.state == AccessorState.NotInferredYet); | 283 assert(accessorNode.state == InferenceState.NotInferredYet); |
239 accessorNode.state = AccessorState.Inferring; | 284 accessorNode.state = InferenceState.Inferring; |
240 var member = accessorNode.member; | 285 var member = accessorNode.member; |
241 if (strongMode) { | 286 if (strongMode) { |
242 var inferredType = tryInferAccessorByInheritance(accessorNode); | 287 var inferredType = tryInferAccessorByInheritance(accessorNode); |
243 var typeInferrer = getMemberTypeInferrer(member); | 288 var typeInferrer = getMemberTypeInferrer(member); |
244 if (inferredType == null) { | 289 if (inferredType == null) { |
245 if (member is KernelField) { | 290 if (member is KernelField) { |
246 typeInferrer.isImmediatelyEvident = true; | 291 typeInferrer.isImmediatelyEvident = true; |
247 inferredType = accessorNode.isImmediatelyEvident | 292 inferredType = accessorNode.isImmediatelyEvident |
248 ? typeInferrer.inferDeclarationType( | 293 ? typeInferrer.inferDeclarationType( |
249 typeInferrer.inferFieldTopLevel(member, null, true)) | 294 typeInferrer.inferFieldTopLevel(member, null, true)) |
250 : const DynamicType(); | 295 : const DynamicType(); |
251 if (!typeInferrer.isImmediatelyEvident) { | 296 if (!typeInferrer.isImmediatelyEvident) { |
252 inferredType = const DynamicType(); | 297 inferredType = const DynamicType(); |
253 } | 298 } |
254 } else { | 299 } else { |
255 inferredType = const DynamicType(); | 300 inferredType = const DynamicType(); |
256 } | 301 } |
257 } | 302 } |
258 if (accessorNode.state == AccessorState.Inferred) { | 303 if (accessorNode.state == InferenceState.Inferred) { |
259 // A circularity must have been detected; at the time it was detected, | 304 // A circularity must have been detected; at the time it was detected, |
260 // inference for this node was completed. | 305 // inference for this node was completed. |
261 return; | 306 return; |
262 } | 307 } |
263 member.setInferredType(this, typeInferrer.uri, inferredType); | 308 member.setInferredType(this, typeInferrer.uri, inferredType); |
264 } | 309 } |
265 accessorNode.state = AccessorState.Inferred; | 310 accessorNode.state = InferenceState.Inferred; |
266 // TODO(paulberry): if type != null, then check that the type of the | 311 // TODO(paulberry): if type != null, then check that the type of the |
267 // initializer is assignable to it. | 312 // initializer is assignable to it. |
268 // TODO(paulberry): the following is a hack so that outlines don't contain | 313 // TODO(paulberry): the following is a hack so that outlines don't contain |
269 // initializers. But it means that we rebuild the initializers when doing | 314 // initializers. But it means that we rebuild the initializers when doing |
270 // a full compile. There should be a better way. | 315 // a full compile. There should be a better way. |
271 if (member is KernelField) { | 316 if (member is KernelField) { |
272 member.initializer = null; | 317 member.initializer = null; |
273 } | 318 } |
274 } | 319 } |
275 | 320 |
276 /// Makes a note that the given [accessorNode] is part of a circularity, so | 321 /// Makes a note that the given [accessorNode] is part of a circularity, so |
277 /// its type can't be inferred. | 322 /// its type can't be inferred. |
278 void inferAccessorCircular(AccessorNode accessorNode) { | 323 void inferAccessorCircular(AccessorNode accessorNode) { |
279 var member = accessorNode.member; | 324 var member = accessorNode.member; |
280 // TODO(paulberry): report the appropriate error. | 325 // TODO(paulberry): report the appropriate error. |
281 var uri = getMemberTypeInferrer(member).uri; | 326 var uri = getMemberTypeInferrer(member).uri; |
282 accessorNode.state = AccessorState.Inferred; | 327 accessorNode.state = InferenceState.Inferred; |
283 member.setInferredType(this, uri, const DynamicType()); | 328 member.setInferredType(this, uri, const DynamicType()); |
284 // TODO(paulberry): the following is a hack so that outlines don't contain | 329 // TODO(paulberry): the following is a hack so that outlines don't contain |
285 // initializers. But it means that we rebuild the initializers when doing | 330 // initializers. But it means that we rebuild the initializers when doing |
286 // a full compile. There should be a better way. | 331 // a full compile. There should be a better way. |
287 if (member is KernelField) { | 332 if (member is KernelField) { |
288 member.initializer = null; | 333 member.initializer = null; |
289 } | 334 } |
290 } | 335 } |
291 | 336 |
292 /// Performs fused type inference on the given [accessorNode]. | 337 /// Performs fused type inference on the given [accessorNode]. |
293 void inferAccessorFused(AccessorNode accessorNode, AccessorNode dependant) { | 338 void inferAccessorFused(AccessorNode accessorNode, AccessorNode dependant) { |
294 switch (accessorNode.state) { | 339 switch (accessorNode.state) { |
295 case AccessorState.Inferred: | 340 case InferenceState.Inferred: |
296 // Already inferred. Nothing to do. | 341 // Already inferred. Nothing to do. |
297 break; | 342 break; |
298 case AccessorState.Inferring: | 343 case InferenceState.Inferring: |
299 // An accessor depends on itself (possibly by way of intermediate | 344 // An accessor depends on itself (possibly by way of intermediate |
300 // accessors). Mark all accessors involved as circular and infer a type | 345 // accessors). Mark all accessors involved as circular and infer a type |
301 // of `dynamic` for them. | 346 // of `dynamic` for them. |
302 var node = accessorNode; | 347 var node = accessorNode; |
303 while (node != null) { | 348 while (node != null) { |
304 var nextNode = node.currentDependency; | 349 var nextNode = node.currentDependency; |
305 inferAccessorCircular(node); | 350 inferAccessorCircular(node); |
306 node.currentDependency = null; | 351 node.currentDependency = null; |
307 node = nextNode; | 352 node = nextNode; |
308 } | 353 } |
309 break; | 354 break; |
310 case AccessorState.NotInferredYet: | 355 case InferenceState.NotInferredYet: |
311 // Mark the "dependant" accessor (if any) as depending on this one, and | 356 // Mark the "dependant" accessor (if any) as depending on this one, and |
312 // invoke accessor inference for this node. | 357 // invoke accessor inference for this node. |
313 dependant?.currentDependency = accessorNode; | 358 dependant?.currentDependency = accessorNode; |
314 // All accessors are "immediately evident" when doing fused inference. | 359 // All accessors are "immediately evident" when doing fused inference. |
315 accessorNode.isImmediatelyEvident = true; | 360 accessorNode.isImmediatelyEvident = true; |
316 inferAccessor(accessorNode); | 361 inferAccessor(accessorNode); |
317 dependant?.currentDependency = null; | 362 dependant?.currentDependency = null; |
318 break; | 363 break; |
319 } | 364 } |
320 } | 365 } |
321 | 366 |
367 /// Performs type inference on the given [methodNode]. | |
368 void inferMethodIfNeeded(MethodNode methodNode) { | |
369 switch (methodNode.state) { | |
370 case InferenceState.Inferred: | |
371 // Already inferred. Nothing to do. | |
372 break; | |
373 case InferenceState.Inferring: | |
374 // An method depends on itself (possibly by way of intermediate | |
375 // methods). This should never happen, because it would require a | |
376 // circular class hierarchy (which Fasta prevents). | |
377 internalError('Circular method inference'); | |
378 break; | |
379 case InferenceState.NotInferredYet: | |
380 methodNode.state = InferenceState.Inferring; | |
381 _inferMethod(methodNode); | |
382 methodNode.state = InferenceState.Inferred; | |
383 break; | |
384 } | |
385 } | |
386 | |
322 @override | 387 @override |
323 void prepareTopLevel(CoreTypes coreTypes, ClassHierarchy hierarchy) { | 388 void prepareTopLevel(CoreTypes coreTypes, ClassHierarchy hierarchy) { |
324 this.coreTypes = coreTypes; | 389 this.coreTypes = coreTypes; |
325 this.classHierarchy = hierarchy; | 390 this.classHierarchy = hierarchy; |
326 this.typeSchemaEnvironment = | 391 this.typeSchemaEnvironment = |
327 new TypeSchemaEnvironment(coreTypes, hierarchy, strongMode); | 392 new TypeSchemaEnvironment(coreTypes, hierarchy, strongMode); |
328 } | 393 } |
329 | 394 |
330 @override | 395 @override |
331 void recordInitializingFormal(KernelVariableDeclaration formal) { | 396 void recordInitializingFormal(KernelVariableDeclaration formal) { |
332 initializingFormals.add(formal); | 397 initializingFormals.add(formal); |
333 } | 398 } |
334 | 399 |
335 @override | 400 @override |
336 void recordMember(KernelMember member) { | 401 void recordMember(KernelMember member) { |
337 accessorNodes.add(createAccessorNode(member)); | 402 if (member is KernelProcedure && !member.isGetter && !member.isSetter) { |
403 methodNodes.add(createMethodNode(member)); | |
404 } else { | |
405 accessorNodes.add(createAccessorNode(member)); | |
406 } | |
338 } | 407 } |
339 | 408 |
340 DartType tryInferAccessorByInheritance(AccessorNode accessorNode) { | 409 DartType tryInferAccessorByInheritance(AccessorNode accessorNode) { |
341 DartType inferredType; | 410 DartType inferredType; |
342 for (var override in accessorNode.candidateOverrides) { | 411 for (var override in accessorNode.candidateOverrides) { |
343 var nextInferredType = | 412 var nextInferredType = |
344 _computeOverriddenAccessorType(override, accessorNode); | 413 _computeOverriddenAccessorType(override, accessorNode); |
345 if (inferredType == null) { | 414 if (inferredType == null) { |
346 inferredType = nextInferredType; | 415 inferredType = nextInferredType; |
347 } else if (inferredType != nextInferredType) { | 416 } else if (inferredType != nextInferredType) { |
348 // Overrides don't have matching types. | 417 // Overrides don't have matching types. |
349 // TODO(paulberry): report an error | 418 // TODO(paulberry): report an error |
350 return const DynamicType(); | 419 return const DynamicType(); |
351 } | 420 } |
352 } | 421 } |
353 return inferredType; | 422 return inferredType; |
354 } | 423 } |
355 | 424 |
425 List<FunctionType> _computeMethodOverriddenTypes(MethodNode methodNode) { | |
426 var overriddenTypes = <FunctionType>[]; | |
427 for (var override in methodNode.overrides) { | |
428 MethodNode overrideNode = KernelProcedure.getMethodNode(override); | |
429 if (overrideNode != null) { | |
430 inferMethodIfNeeded(overrideNode); | |
431 } | |
432 if (override.function == null) { | |
433 // This can happen if there are errors. Just skip this override. | |
434 continue; | |
435 } | |
436 var overriddenType = override.function.functionType; | |
437 var superclass = override.enclosingClass; | |
438 if (!superclass.typeParameters.isEmpty) { | |
439 var thisClass = methodNode.procedure.enclosingClass; | |
440 var superclassInstantiation = classHierarchy | |
441 .getClassAsInstanceOf(thisClass, superclass) | |
442 .asInterfaceType; | |
443 overriddenType = Substitution | |
444 .fromInterfaceType(superclassInstantiation) | |
445 .substituteType(overriddenType); | |
446 } | |
447 var methodTypeParameters = methodNode.procedure.function.typeParameters; | |
448 if (overriddenType.typeParameters.length != methodTypeParameters.length) { | |
449 // Generic arity mismatch. Don't do any inference for this method. | |
450 // TODO(paulberry): report an error. | |
451 return <FunctionType>[]; | |
452 } else if (overriddenType.typeParameters.isNotEmpty) { | |
453 var substitutionMap = <TypeParameter, DartType>{}; | |
454 for (int i = 0; i < methodTypeParameters.length; i++) { | |
455 substitutionMap[overriddenType.typeParameters[i]] = | |
456 new TypeParameterType(methodTypeParameters[i]); | |
457 } | |
458 overriddenType = substituteTypeParams( | |
459 overriddenType, substitutionMap, methodTypeParameters); | |
460 } | |
461 overriddenTypes.add(overriddenType); | |
462 } | |
463 return overriddenTypes; | |
464 } | |
465 | |
356 DartType _computeOverriddenAccessorType( | 466 DartType _computeOverriddenAccessorType( |
357 Member override, AccessorNode accessorNode) { | 467 Member override, AccessorNode accessorNode) { |
358 if (fusedTopLevelInference) { | 468 if (fusedTopLevelInference) { |
359 AccessorNode dependency = KernelMember.getAccessorNode(override); | 469 AccessorNode dependency = KernelMember.getAccessorNode(override); |
360 if (dependency != null) { | 470 if (dependency != null) { |
361 inferAccessorFused(dependency, accessorNode); | 471 inferAccessorFused(dependency, accessorNode); |
362 } | 472 } |
363 } | 473 } |
364 DartType overriddenType; | 474 DartType overriddenType; |
365 if (override is Field) { | 475 if (override is Field) { |
(...skipping 25 matching lines...) Expand all Loading... | |
391 assert(KernelVariableDeclaration.isImplicitlyTyped(formal)); | 501 assert(KernelVariableDeclaration.isImplicitlyTyped(formal)); |
392 Class enclosingClass = formal.parent.parent.parent; | 502 Class enclosingClass = formal.parent.parent.parent; |
393 for (var field in enclosingClass.fields) { | 503 for (var field in enclosingClass.fields) { |
394 if (field.name.name == formal.name) { | 504 if (field.name.name == formal.name) { |
395 return field.type; | 505 return field.type; |
396 } | 506 } |
397 } | 507 } |
398 // No matching field. The error should be reported elsewhere. | 508 // No matching field. The error should be reported elsewhere. |
399 return const DynamicType(); | 509 return const DynamicType(); |
400 } | 510 } |
511 | |
512 void _inferMethod(MethodNode methodNode) { | |
513 var typeInferrer = getMemberTypeInferrer(methodNode.procedure); | |
514 | |
515 // First collect types of overridden methods | |
516 var overriddenTypes = _computeMethodOverriddenTypes(methodNode); | |
517 | |
518 // Now infer types. | |
519 DartType matchTypes(Iterable<DartType> types) { | |
520 if (!strongMode) return const DynamicType(); | |
521 var iterator = types.iterator; | |
522 if (!iterator.moveNext()) { | |
523 // No overridden types. Infer `dynamic`. | |
524 return const DynamicType(); | |
525 } | |
526 var inferredType = iterator.current; | |
527 while (iterator.moveNext()) { | |
528 if (inferredType != iterator.current) { | |
529 // TODO(paulberry): Types don't match. Report an error. | |
Siggi Cherem (dart-lang)
2017/06/21 20:19:08
Random questions:
When not doing inference, are t
Paul Berry
2017/06/21 20:54:47
Peter has added some checks, but I believe that he
| |
530 return const DynamicType(); | |
531 } | |
532 } | |
533 return inferredType; | |
534 } | |
535 | |
536 if (KernelProcedure.hasImplicitReturnType(methodNode.procedure)) { | |
537 var inferredType = | |
538 matchTypes(overriddenTypes.map((type) => type.returnType)); | |
539 instrumentation?.record( | |
540 Uri.parse(typeInferrer.uri), | |
541 methodNode.procedure.fileOffset, | |
542 'topType', | |
543 new InstrumentationValueForType(inferredType)); | |
544 methodNode.procedure.function.returnType = inferredType; | |
545 } | |
546 var positionalParameters = | |
547 methodNode.procedure.function.positionalParameters; | |
548 for (int i = 0; i < positionalParameters.length; i++) { | |
549 if (KernelVariableDeclaration | |
550 .isImplicitlyTyped(positionalParameters[i])) { | |
551 var inferredType = matchTypes( | |
552 overriddenTypes.map((type) => getPositionalParameterType(type, i))); | |
553 instrumentation?.record( | |
554 Uri.parse(typeInferrer.uri), | |
555 positionalParameters[i].fileOffset, | |
556 'topType', | |
557 new InstrumentationValueForType(inferredType)); | |
558 positionalParameters[i].type = inferredType; | |
559 } | |
560 } | |
561 var namedParameters = methodNode.procedure.function.namedParameters; | |
562 for (int i = 0; i < namedParameters.length; i++) { | |
563 if (KernelVariableDeclaration.isImplicitlyTyped(namedParameters[i])) { | |
564 var name = namedParameters[i].name; | |
565 var inferredType = matchTypes( | |
566 overriddenTypes.map((type) => getNamedParameterType(type, name))); | |
567 instrumentation?.record( | |
568 Uri.parse(typeInferrer.uri), | |
569 namedParameters[i].fileOffset, | |
570 'topType', | |
571 new InstrumentationValueForType(inferredType)); | |
572 namedParameters[i].type = inferredType; | |
573 } | |
574 } | |
575 } | |
401 } | 576 } |
402 | 577 |
403 /// Subtype of [dependencyWalker.DependencyWalker] which is specialized to | 578 /// Subtype of [dependencyWalker.DependencyWalker] which is specialized to |
404 /// perform top level type inference. | 579 /// perform top level type inference. |
405 class _AccessorWalker extends dependencyWalker.DependencyWalker<AccessorNode> { | 580 class _AccessorWalker extends dependencyWalker.DependencyWalker<AccessorNode> { |
406 _AccessorWalker(); | 581 _AccessorWalker(); |
407 | 582 |
408 @override | 583 @override |
409 void evaluate(AccessorNode f) { | 584 void evaluate(AccessorNode f) { |
410 f._typeInferenceEngine.inferAccessor(f); | 585 f._typeInferenceEngine.inferAccessor(f); |
411 } | 586 } |
412 | 587 |
413 @override | 588 @override |
414 void evaluateScc(List<AccessorNode> scc) { | 589 void evaluateScc(List<AccessorNode> scc) { |
415 // Mark every accessor as part of a circularity. | 590 // Mark every accessor as part of a circularity. |
416 for (var f in scc) { | 591 for (var f in scc) { |
417 f._typeInferenceEngine.inferAccessorCircular(f); | 592 f._typeInferenceEngine.inferAccessorCircular(f); |
418 } | 593 } |
419 } | 594 } |
420 } | 595 } |
OLD | NEW |