OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.type_checker; | 4 library kernel.type_checker; |
5 | 5 |
6 import 'ast.dart'; | 6 import 'ast.dart'; |
7 import 'class_hierarchy.dart'; | 7 import 'class_hierarchy.dart'; |
8 import 'core_types.dart'; | 8 import 'core_types.dart'; |
9 import 'type_algebra.dart'; | 9 import 'type_algebra.dart'; |
10 import 'type_environment.dart'; | 10 import 'type_environment.dart'; |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 // have a declared interface target. | 241 // have a declared interface target. |
242 fail(access, '$member is not accessible on a receiver of type $type'); | 242 fail(access, '$member is not accessible on a receiver of type $type'); |
243 return Substitution.bottomForClass(superclass); // Continue type checking. | 243 return Substitution.bottomForClass(superclass); // Continue type checking. |
244 } | 244 } |
245 | 245 |
246 Substitution getSuperReceiverType(Member member) { | 246 Substitution getSuperReceiverType(Member member) { |
247 return Substitution.fromSupertype( | 247 return Substitution.fromSupertype( |
248 hierarchy.getClassAsInstanceOf(currentClass, member.enclosingClass)); | 248 hierarchy.getClassAsInstanceOf(currentClass, member.enclosingClass)); |
249 } | 249 } |
250 | 250 |
251 DartType handleCall(Arguments arguments, FunctionNode function, | 251 DartType handleCall(Arguments arguments, DartType functionType, |
252 {Substitution receiver: Substitution.empty, | 252 {Substitution receiver: Substitution.empty, |
253 List<TypeParameter> typeParameters}) { | 253 List<TypeParameter> typeParameters}) { |
254 typeParameters ??= function.typeParameters; | 254 if (functionType is FunctionType) { |
255 if (arguments.positional.length < function.requiredParameterCount) { | 255 typeParameters ??= functionType.typeParameters; |
256 fail(arguments, 'Too few positional arguments'); | 256 if (arguments.positional.length < functionType.requiredParameterCount) { |
257 return const BottomType(); | 257 fail(arguments, 'Too few positional arguments'); |
258 } | 258 return const BottomType(); |
259 if (arguments.positional.length > function.positionalParameters.length) { | 259 } |
260 fail(arguments, 'Too many positional arguments'); | 260 if (arguments.positional.length > |
261 return const BottomType(); | 261 functionType.positionalParameters.length) { |
262 } | 262 fail(arguments, 'Too many positional arguments'); |
263 if (arguments.types.length != typeParameters.length) { | 263 return const BottomType(); |
264 fail(arguments, 'Wrong number of type arguments'); | 264 } |
265 return const BottomType(); | 265 if (arguments.types.length != typeParameters.length) { |
266 } | 266 fail(arguments, 'Wrong number of type arguments'); |
267 var instantiation = Substitution.fromPairs(typeParameters, arguments.types); | 267 return const BottomType(); |
268 var substitution = Substitution.combine(receiver, instantiation); | 268 } |
269 for (int i = 0; i < typeParameters.length; ++i) { | 269 var instantiation = |
270 var argument = arguments.types[i]; | 270 Substitution.fromPairs(typeParameters, arguments.types); |
271 var bound = substitution.substituteType(typeParameters[i].bound); | 271 var substitution = Substitution.combine(receiver, instantiation); |
272 checkAssignable(arguments, argument, bound); | 272 for (int i = 0; i < typeParameters.length; ++i) { |
273 } | 273 var argument = arguments.types[i]; |
274 for (int i = 0; i < arguments.positional.length; ++i) { | 274 var bound = substitution.substituteType(typeParameters[i].bound); |
275 var expectedType = substitution.substituteType( | 275 checkAssignable(arguments, argument, bound); |
276 function.positionalParameters[i].type, | 276 } |
277 contravariant: true); | 277 for (int i = 0; i < arguments.positional.length; ++i) { |
278 arguments.positional[i] = | 278 var expectedType = substitution.substituteType( |
279 checkAndDowncastExpression(arguments.positional[i], expectedType); | 279 functionType.positionalParameters[i], |
280 } | 280 contravariant: true); |
281 for (int i = 0; i < arguments.named.length; ++i) { | 281 arguments.positional[i] = |
282 var argument = arguments.named[i]; | 282 checkAndDowncastExpression(arguments.positional[i], expectedType); |
283 bool found = false; | 283 } |
284 for (int j = 0; j < function.namedParameters.length; ++j) { | 284 for (int i = 0; i < arguments.named.length; ++i) { |
285 if (argument.name == function.namedParameters[j].name) { | 285 var argument = arguments.named[i]; |
286 var expectedType = substitution.substituteType( | 286 bool found = false; |
287 function.namedParameters[j].type, | 287 for (int j = 0; j < functionType.namedParameters.length; ++j) { |
288 contravariant: true); | 288 if (argument.name == functionType.namedParameters[j].name) { |
289 argument.value = | 289 var expectedType = substitution.substituteType( |
290 checkAndDowncastExpression(argument.value, expectedType); | 290 functionType.namedParameters[j].type, |
291 found = true; | 291 contravariant: true); |
292 break; | 292 argument.value = |
| 293 checkAndDowncastExpression(argument.value, expectedType); |
| 294 found = true; |
| 295 break; |
| 296 } |
| 297 } |
| 298 if (!found) { |
| 299 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); |
| 300 return const BottomType(); |
293 } | 301 } |
294 } | 302 } |
295 if (!found) { | 303 return substitution.substituteType(functionType.returnType); |
296 fail(argument.value, 'Unexpected named parameter: ${argument.name}'); | 304 } else { |
297 return const BottomType(); | 305 // Note: attempting to resolve .call() on [functionType] could lead to an |
298 } | 306 // infinite regress, so just assume `dynamic`. |
| 307 return const DynamicType(); |
299 } | 308 } |
300 return substitution.substituteType(function.returnType); | |
301 } | 309 } |
302 | 310 |
303 DartType _getInternalReturnType(FunctionNode function) { | 311 DartType _getInternalReturnType(FunctionNode function) { |
304 switch (function.asyncMarker) { | 312 switch (function.asyncMarker) { |
305 case AsyncMarker.Sync: | 313 case AsyncMarker.Sync: |
306 return function.returnType; | 314 return function.returnType; |
307 | 315 |
308 case AsyncMarker.Async: | 316 case AsyncMarker.Async: |
309 Class container = coreTypes.futureClass; | 317 Class container = coreTypes.futureClass; |
310 DartType returnType = function.returnType; | 318 DartType returnType = function.returnType; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 node.otherwise = | 380 node.otherwise = |
373 checkAndDowncastExpression(node.otherwise, node.staticType); | 381 checkAndDowncastExpression(node.otherwise, node.staticType); |
374 return node.staticType; | 382 return node.staticType; |
375 } | 383 } |
376 | 384 |
377 @override | 385 @override |
378 DartType visitConstructorInvocation(ConstructorInvocation node) { | 386 DartType visitConstructorInvocation(ConstructorInvocation node) { |
379 Constructor target = node.target; | 387 Constructor target = node.target; |
380 Arguments arguments = node.arguments; | 388 Arguments arguments = node.arguments; |
381 Class class_ = target.enclosingClass; | 389 Class class_ = target.enclosingClass; |
382 handleCall(arguments, target.function, | 390 handleCall(arguments, target.function.functionType, |
383 typeParameters: class_.typeParameters); | 391 typeParameters: class_.typeParameters); |
384 return new InterfaceType(target.enclosingClass, arguments.types); | 392 return new InterfaceType(target.enclosingClass, arguments.types); |
385 } | 393 } |
386 | 394 |
387 @override | 395 @override |
388 DartType visitDirectMethodInvocation(DirectMethodInvocation node) { | 396 DartType visitDirectMethodInvocation(DirectMethodInvocation node) { |
389 return handleCall(node.arguments, node.target.function, | 397 return handleCall(node.arguments, node.target.getterType, |
390 receiver: getReceiverType(node, node.receiver, node.target)); | 398 receiver: getReceiverType(node, node.receiver, node.target)); |
391 } | 399 } |
392 | 400 |
393 @override | 401 @override |
394 DartType visitDirectPropertyGet(DirectPropertyGet node) { | 402 DartType visitDirectPropertyGet(DirectPropertyGet node) { |
395 var receiver = getReceiverType(node, node.receiver, node.target); | 403 var receiver = getReceiverType(node, node.receiver, node.target); |
396 return receiver.substituteType(node.target.getterType); | 404 return receiver.substituteType(node.target.getterType); |
397 } | 405 } |
398 | 406 |
399 @override | 407 @override |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 if (target == null) { | 525 if (target == null) { |
518 var receiver = visitExpression(node.receiver); | 526 var receiver = visitExpression(node.receiver); |
519 if (node.name.name == '==') { | 527 if (node.name.name == '==') { |
520 visitExpression(node.arguments.positional.single); | 528 visitExpression(node.arguments.positional.single); |
521 return environment.boolType; | 529 return environment.boolType; |
522 } | 530 } |
523 if (node.name.name == 'call' && receiver is FunctionType) { | 531 if (node.name.name == 'call' && receiver is FunctionType) { |
524 return handleFunctionCall(node, receiver, node.arguments); | 532 return handleFunctionCall(node, receiver, node.arguments); |
525 } | 533 } |
526 return handleDynamicCall(receiver, node.arguments); | 534 return handleDynamicCall(receiver, node.arguments); |
527 } else if (environment.isOverloadedArithmeticOperator(target)) { | 535 } else if (target is Procedure && |
| 536 environment.isOverloadedArithmeticOperator(target)) { |
528 assert(node.arguments.positional.length == 1); | 537 assert(node.arguments.positional.length == 1); |
529 var receiver = visitExpression(node.receiver); | 538 var receiver = visitExpression(node.receiver); |
530 var argument = visitExpression(node.arguments.positional[0]); | 539 var argument = visitExpression(node.arguments.positional[0]); |
531 return environment.getTypeOfOverloadedArithmetic(receiver, argument); | 540 return environment.getTypeOfOverloadedArithmetic(receiver, argument); |
532 } else { | 541 } else { |
533 return handleCall(node.arguments, target.function, | 542 return handleCall(node.arguments, target.getterType, |
534 receiver: getReceiverType(node, node.receiver, node.interfaceTarget)); | 543 receiver: getReceiverType(node, node.receiver, node.interfaceTarget)); |
535 } | 544 } |
536 } | 545 } |
537 | 546 |
538 @override | 547 @override |
539 DartType visitPropertyGet(PropertyGet node) { | 548 DartType visitPropertyGet(PropertyGet node) { |
540 if (node.interfaceTarget == null) { | 549 if (node.interfaceTarget == null) { |
541 visitExpression(node.receiver); | 550 visitExpression(node.receiver); |
542 return const DynamicType(); | 551 return const DynamicType(); |
543 } else { | 552 } else { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
578 return const BottomType(); | 587 return const BottomType(); |
579 } | 588 } |
580 | 589 |
581 @override | 590 @override |
582 DartType visitStaticGet(StaticGet node) { | 591 DartType visitStaticGet(StaticGet node) { |
583 return node.target.getterType; | 592 return node.target.getterType; |
584 } | 593 } |
585 | 594 |
586 @override | 595 @override |
587 DartType visitStaticInvocation(StaticInvocation node) { | 596 DartType visitStaticInvocation(StaticInvocation node) { |
588 return handleCall(node.arguments, node.target.function); | 597 return handleCall(node.arguments, node.target.getterType); |
589 } | 598 } |
590 | 599 |
591 @override | 600 @override |
592 DartType visitStaticSet(StaticSet node) { | 601 DartType visitStaticSet(StaticSet node) { |
593 var value = visitExpression(node.value); | 602 var value = visitExpression(node.value); |
594 checkAssignable(node.value, value, node.target.setterType); | 603 checkAssignable(node.value, value, node.target.setterType); |
595 return value; | 604 return value; |
596 } | 605 } |
597 | 606 |
598 @override | 607 @override |
599 DartType visitStringConcatenation(StringConcatenation node) { | 608 DartType visitStringConcatenation(StringConcatenation node) { |
600 node.expressions.forEach(visitExpression); | 609 node.expressions.forEach(visitExpression); |
601 return environment.stringType; | 610 return environment.stringType; |
602 } | 611 } |
603 | 612 |
604 @override | 613 @override |
605 DartType visitStringLiteral(StringLiteral node) { | 614 DartType visitStringLiteral(StringLiteral node) { |
606 return environment.stringType; | 615 return environment.stringType; |
607 } | 616 } |
608 | 617 |
609 @override | 618 @override |
610 DartType visitSuperMethodInvocation(SuperMethodInvocation node) { | 619 DartType visitSuperMethodInvocation(SuperMethodInvocation node) { |
611 if (node.interfaceTarget == null) { | 620 if (node.interfaceTarget == null) { |
612 return handleDynamicCall(environment.thisType, node.arguments); | 621 return handleDynamicCall(environment.thisType, node.arguments); |
613 } else { | 622 } else { |
614 return handleCall(node.arguments, node.interfaceTarget.function, | 623 return handleCall(node.arguments, node.interfaceTarget.getterType, |
615 receiver: getSuperReceiverType(node.interfaceTarget)); | 624 receiver: getSuperReceiverType(node.interfaceTarget)); |
616 } | 625 } |
617 } | 626 } |
618 | 627 |
619 @override | 628 @override |
620 DartType visitSuperPropertyGet(SuperPropertyGet node) { | 629 DartType visitSuperPropertyGet(SuperPropertyGet node) { |
621 if (node.interfaceTarget == null) { | 630 if (node.interfaceTarget == null) { |
622 return const DynamicType(); | 631 return const DynamicType(); |
623 } else { | 632 } else { |
624 var receiver = getSuperReceiverType(node.interfaceTarget); | 633 var receiver = getSuperReceiverType(node.interfaceTarget); |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
930 } | 939 } |
931 } | 940 } |
932 | 941 |
933 @override | 942 @override |
934 visitFieldInitializer(FieldInitializer node) { | 943 visitFieldInitializer(FieldInitializer node) { |
935 node.value = checkAndDowncastExpression(node.value, node.field.type); | 944 node.value = checkAndDowncastExpression(node.value, node.field.type); |
936 } | 945 } |
937 | 946 |
938 @override | 947 @override |
939 visitRedirectingInitializer(RedirectingInitializer node) { | 948 visitRedirectingInitializer(RedirectingInitializer node) { |
940 handleCall(node.arguments, node.target.function, | 949 handleCall(node.arguments, node.target.getterType, |
941 typeParameters: const <TypeParameter>[]); | 950 typeParameters: const <TypeParameter>[]); |
942 } | 951 } |
943 | 952 |
944 @override | 953 @override |
945 visitSuperInitializer(SuperInitializer node) { | 954 visitSuperInitializer(SuperInitializer node) { |
946 handleCall(node.arguments, node.target.function, | 955 handleCall(node.arguments, node.target.getterType, |
947 typeParameters: const <TypeParameter>[], | 956 typeParameters: const <TypeParameter>[], |
948 receiver: getSuperReceiverType(node.target)); | 957 receiver: getSuperReceiverType(node.target)); |
949 } | 958 } |
950 | 959 |
951 @override | 960 @override |
952 visitLocalInitializer(LocalInitializer node) { | 961 visitLocalInitializer(LocalInitializer node) { |
953 visitVariableDeclaration(node.variable); | 962 visitVariableDeclaration(node.variable); |
954 } | 963 } |
955 | 964 |
956 @override | 965 @override |
957 visitInvalidInitializer(InvalidInitializer node) {} | 966 visitInvalidInitializer(InvalidInitializer node) {} |
958 } | 967 } |
OLD | NEW |