Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart

Issue 2946273002: Implement override-based type inference for instance methods. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698