Chromium Code Reviews| 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 |