| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.typechecker; | 5 library dart2js.typechecker; |
| 6 | 6 |
| 7 import 'common/names.dart' show | 7 import 'common/names.dart' show |
| 8 Identifiers; | 8 Identifiers; |
| 9 import 'common/resolution.dart' show | 9 import 'common/resolution.dart' show |
| 10 Resolution; | 10 Resolution; |
| 11 import 'common/tasks.dart' show | 11 import 'common/tasks.dart' show |
| 12 CompilerTask; | 12 CompilerTask; |
| 13 import 'compiler.dart' show | 13 import 'compiler.dart' show |
| 14 Compiler; | 14 Compiler; |
| 15 import 'constants/expressions.dart'; | 15 import 'constants/expressions.dart'; |
| 16 import 'constants/values.dart'; | 16 import 'constants/values.dart'; |
| 17 import 'core_types.dart'; | 17 import 'core_types.dart'; |
| 18 import 'dart_types.dart'; | 18 import 'dart_types.dart'; |
| 19 import 'diagnostics/diagnostic_listener.dart' show | 19 import 'diagnostics/diagnostic_listener.dart' show |
| 20 DiagnosticMessage; | 20 DiagnosticMessage, |
| 21 DiagnosticReporter; |
| 21 import 'diagnostics/invariant.dart' show | 22 import 'diagnostics/invariant.dart' show |
| 22 invariant; | 23 invariant; |
| 23 import 'diagnostics/messages.dart'; | 24 import 'diagnostics/messages.dart'; |
| 24 import 'diagnostics/spannable.dart' show | 25 import 'diagnostics/spannable.dart' show |
| 25 Spannable; | 26 Spannable; |
| 26 import 'elements/elements.dart' show | 27 import 'elements/elements.dart' show |
| 27 AbstractFieldElement, | 28 AbstractFieldElement, |
| 28 AstElement, | 29 AstElement, |
| 29 AsyncMarker, | 30 AsyncMarker, |
| 30 ClassElement, | 31 ClassElement, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 61 import '../compiler_new.dart' as api; | 62 import '../compiler_new.dart' as api; |
| 62 | 63 |
| 63 class TypeCheckerTask extends CompilerTask { | 64 class TypeCheckerTask extends CompilerTask { |
| 64 TypeCheckerTask(Compiler compiler) : super(compiler); | 65 TypeCheckerTask(Compiler compiler) : super(compiler); |
| 65 String get name => "Type checker"; | 66 String get name => "Type checker"; |
| 66 | 67 |
| 67 void check(AstElement element) { | 68 void check(AstElement element) { |
| 68 if (element.isClass) return; | 69 if (element.isClass) return; |
| 69 if (element.isTypedef) return; | 70 if (element.isTypedef) return; |
| 70 ResolvedAst resolvedAst = element.resolvedAst; | 71 ResolvedAst resolvedAst = element.resolvedAst; |
| 71 compiler.withCurrentElement(element.implementation, () { | 72 reporter.withCurrentElement(element.implementation, () { |
| 72 measure(() { | 73 measure(() { |
| 73 TypeCheckerVisitor visitor = new TypeCheckerVisitor( | 74 TypeCheckerVisitor visitor = new TypeCheckerVisitor( |
| 74 compiler, resolvedAst.elements, compiler.types); | 75 compiler, resolvedAst.elements, compiler.types); |
| 75 if (element.isField) { | 76 if (element.isField) { |
| 76 visitor.analyzingInitializer = true; | 77 visitor.analyzingInitializer = true; |
| 77 } | 78 } |
| 78 resolvedAst.node.accept(visitor); | 79 resolvedAst.node.accept(visitor); |
| 79 }); | 80 }); |
| 80 }); | 81 }); |
| 81 } | 82 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 Node lastSeenNode; | 300 Node lastSeenNode; |
| 300 DartType expectedReturnType; | 301 DartType expectedReturnType; |
| 301 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; | 302 AsyncMarker currentAsyncMarker = AsyncMarker.SYNC; |
| 302 | 303 |
| 303 final ClassElement currentClass; | 304 final ClassElement currentClass; |
| 304 | 305 |
| 305 /// The immediately enclosing field, method or constructor being analyzed. | 306 /// The immediately enclosing field, method or constructor being analyzed. |
| 306 ExecutableElement executableContext; | 307 ExecutableElement executableContext; |
| 307 | 308 |
| 308 CoreTypes get coreTypes => compiler.coreTypes; | 309 CoreTypes get coreTypes => compiler.coreTypes; |
| 310 |
| 311 DiagnosticReporter get reporter => compiler.reporter; |
| 312 |
| 309 Resolution get resolution => compiler.resolution; | 313 Resolution get resolution => compiler.resolution; |
| 310 | 314 |
| 311 InterfaceType get intType => coreTypes.intType; | 315 InterfaceType get intType => coreTypes.intType; |
| 312 InterfaceType get doubleType => coreTypes.doubleType; | 316 InterfaceType get doubleType => coreTypes.doubleType; |
| 313 InterfaceType get boolType => coreTypes.boolType; | 317 InterfaceType get boolType => coreTypes.boolType; |
| 314 InterfaceType get stringType => coreTypes.stringType; | 318 InterfaceType get stringType => coreTypes.stringType; |
| 315 | 319 |
| 316 DartType thisType; | 320 DartType thisType; |
| 317 DartType superType; | 321 DartType superType; |
| 318 | 322 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 // If these are used, an error should have been reported by the resolver. | 394 // If these are used, an error should have been reported by the resolver. |
| 391 thisType = const DynamicType(); | 395 thisType = const DynamicType(); |
| 392 superType = const DynamicType(); | 396 superType = const DynamicType(); |
| 393 } | 397 } |
| 394 } | 398 } |
| 395 | 399 |
| 396 LibraryElement get currentLibrary => elements.analyzedElement.library; | 400 LibraryElement get currentLibrary => elements.analyzedElement.library; |
| 397 | 401 |
| 398 reportTypeWarning(Spannable spannable, MessageKind kind, | 402 reportTypeWarning(Spannable spannable, MessageKind kind, |
| 399 [Map arguments = const {}]) { | 403 [Map arguments = const {}]) { |
| 400 compiler.reportWarningMessage(spannable, kind, arguments); | 404 reporter.reportWarningMessage(spannable, kind, arguments); |
| 401 } | 405 } |
| 402 | 406 |
| 403 reportMessage(Spannable spannable, MessageKind kind, | 407 reportMessage(Spannable spannable, MessageKind kind, |
| 404 Map arguments, | 408 Map arguments, |
| 405 {bool isHint: false}) { | 409 {bool isHint: false}) { |
| 406 if (isHint) { | 410 if (isHint) { |
| 407 compiler.reportHintMessage(spannable, kind, arguments); | 411 reporter.reportHintMessage(spannable, kind, arguments); |
| 408 } else { | 412 } else { |
| 409 compiler.reportWarningMessage(spannable, kind, arguments); | 413 reporter.reportWarningMessage(spannable, kind, arguments); |
| 410 } | 414 } |
| 411 } | 415 } |
| 412 | 416 |
| 413 reportTypePromotionHint(TypePromotion typePromotion) { | 417 reportTypePromotionHint(TypePromotion typePromotion) { |
| 414 if (!reportedTypePromotions.contains(typePromotion)) { | 418 if (!reportedTypePromotions.contains(typePromotion)) { |
| 415 reportedTypePromotions.add(typePromotion); | 419 reportedTypePromotions.add(typePromotion); |
| 416 for (TypePromotionMessage message in typePromotion.messages) { | 420 for (TypePromotionMessage message in typePromotion.messages) { |
| 417 compiler.reportHint(message.hint, message.infos); | 421 reporter.reportHint(message.hint, message.infos); |
| 418 } | 422 } |
| 419 } | 423 } |
| 420 } | 424 } |
| 421 | 425 |
| 422 // TODO(karlklose): remove these functions. | 426 // TODO(karlklose): remove these functions. |
| 423 DartType unhandledExpression() => const DynamicType(); | 427 DartType unhandledExpression() => const DynamicType(); |
| 424 | 428 |
| 425 DartType analyzeNonVoid(Node node) { | 429 DartType analyzeNonVoid(Node node) { |
| 426 DartType type = analyze(node); | 430 DartType type = analyze(node); |
| 427 if (type.isVoid) { | 431 if (type.isVoid) { |
| 428 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); | 432 reportTypeWarning(node, MessageKind.VOID_EXPRESSION); |
| 429 } | 433 } |
| 430 return type; | 434 return type; |
| 431 } | 435 } |
| 432 | 436 |
| 433 DartType analyzeWithDefault(Node node, DartType defaultValue) { | 437 DartType analyzeWithDefault(Node node, DartType defaultValue) { |
| 434 return node != null ? analyze(node) : defaultValue; | 438 return node != null ? analyze(node) : defaultValue; |
| 435 } | 439 } |
| 436 | 440 |
| 437 /// If [inInitializer] is true, assignment should be interpreted as write to | 441 /// If [inInitializer] is true, assignment should be interpreted as write to |
| 438 /// a field and not to a setter. | 442 /// a field and not to a setter. |
| 439 DartType analyze(Node node, {bool inInitializer: false}) { | 443 DartType analyze(Node node, {bool inInitializer: false}) { |
| 440 if (node == null) { | 444 if (node == null) { |
| 441 final String error = 'Unexpected node: null'; | 445 final String error = 'Unexpected node: null'; |
| 442 if (lastSeenNode != null) { | 446 if (lastSeenNode != null) { |
| 443 compiler.internalError(lastSeenNode, error); | 447 reporter.internalError(lastSeenNode, error); |
| 444 } else { | 448 } else { |
| 445 compiler.internalError(executableContext, error); | 449 reporter.internalError(executableContext, error); |
| 446 } | 450 } |
| 447 } else { | 451 } else { |
| 448 lastSeenNode = node; | 452 lastSeenNode = node; |
| 449 } | 453 } |
| 450 bool previouslyInitializer = analyzingInitializer; | 454 bool previouslyInitializer = analyzingInitializer; |
| 451 analyzingInitializer = inInitializer; | 455 analyzingInitializer = inInitializer; |
| 452 DartType result = node.accept(this); | 456 DartType result = node.accept(this); |
| 453 analyzingInitializer = previouslyInitializer; | 457 analyzingInitializer = previouslyInitializer; |
| 454 if (result == null) { | 458 if (result == null) { |
| 455 compiler.internalError(node, 'Type is null.'); | 459 reporter.internalError(node, 'Type is null.'); |
| 456 } | 460 } |
| 457 return _record(node, result); | 461 return _record(node, result); |
| 458 } | 462 } |
| 459 | 463 |
| 460 void checkTypePromotion(Node node, TypePromotion typePromotion, | 464 void checkTypePromotion(Node node, TypePromotion typePromotion, |
| 461 {bool checkAccesses: false}) { | 465 {bool checkAccesses: false}) { |
| 462 VariableElement variable = typePromotion.variable; | 466 VariableElement variable = typePromotion.variable; |
| 463 String variableName = variable.name; | 467 String variableName = variable.name; |
| 464 List<Node> potentialMutationsIn = | 468 List<Node> potentialMutationsIn = |
| 465 elements.getPotentialMutationsIn(node, variable); | 469 elements.getPotentialMutationsIn(node, variable); |
| 466 if (!potentialMutationsIn.isEmpty) { | 470 if (!potentialMutationsIn.isEmpty) { |
| 467 DiagnosticMessage hint = compiler.createMessage( | 471 DiagnosticMessage hint = reporter.createMessage( |
| 468 typePromotion.node, | 472 typePromotion.node, |
| 469 MessageKind.POTENTIAL_MUTATION, | 473 MessageKind.POTENTIAL_MUTATION, |
| 470 {'variableName': variableName, 'shownType': typePromotion.type}); | 474 {'variableName': variableName, 'shownType': typePromotion.type}); |
| 471 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 475 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 472 for (Node mutation in potentialMutationsIn) { | 476 for (Node mutation in potentialMutationsIn) { |
| 473 infos.add(compiler.createMessage(mutation, | 477 infos.add(reporter.createMessage(mutation, |
| 474 MessageKind.POTENTIAL_MUTATION_HERE, | 478 MessageKind.POTENTIAL_MUTATION_HERE, |
| 475 {'variableName': variableName})); | 479 {'variableName': variableName})); |
| 476 } | 480 } |
| 477 typePromotion.addHint(hint, infos); | 481 typePromotion.addHint(hint, infos); |
| 478 } | 482 } |
| 479 List<Node> potentialMutationsInClosures = | 483 List<Node> potentialMutationsInClosures = |
| 480 elements.getPotentialMutationsInClosure(variable); | 484 elements.getPotentialMutationsInClosure(variable); |
| 481 if (!potentialMutationsInClosures.isEmpty) { | 485 if (!potentialMutationsInClosures.isEmpty) { |
| 482 DiagnosticMessage hint = compiler.createMessage( | 486 DiagnosticMessage hint = reporter.createMessage( |
| 483 typePromotion.node, | 487 typePromotion.node, |
| 484 MessageKind.POTENTIAL_MUTATION_IN_CLOSURE, | 488 MessageKind.POTENTIAL_MUTATION_IN_CLOSURE, |
| 485 {'variableName': variableName, 'shownType': typePromotion.type}); | 489 {'variableName': variableName, 'shownType': typePromotion.type}); |
| 486 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 490 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 487 for (Node mutation in potentialMutationsInClosures) { | 491 for (Node mutation in potentialMutationsInClosures) { |
| 488 infos.add(compiler.createMessage( | 492 infos.add(reporter.createMessage( |
| 489 mutation, | 493 mutation, |
| 490 MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE, | 494 MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE, |
| 491 {'variableName': variableName})); | 495 {'variableName': variableName})); |
| 492 } | 496 } |
| 493 typePromotion.addHint(hint, infos); | 497 typePromotion.addHint(hint, infos); |
| 494 } | 498 } |
| 495 if (checkAccesses) { | 499 if (checkAccesses) { |
| 496 List<Node> accesses = elements.getAccessesByClosureIn(node, variable); | 500 List<Node> accesses = elements.getAccessesByClosureIn(node, variable); |
| 497 List<Node> mutations = elements.getPotentialMutations(variable); | 501 List<Node> mutations = elements.getPotentialMutations(variable); |
| 498 if (!accesses.isEmpty && !mutations.isEmpty) { | 502 if (!accesses.isEmpty && !mutations.isEmpty) { |
| 499 DiagnosticMessage hint = compiler.createMessage( | 503 DiagnosticMessage hint = reporter.createMessage( |
| 500 typePromotion.node, | 504 typePromotion.node, |
| 501 MessageKind.ACCESSED_IN_CLOSURE, | 505 MessageKind.ACCESSED_IN_CLOSURE, |
| 502 {'variableName': variableName, 'shownType': typePromotion.type}); | 506 {'variableName': variableName, 'shownType': typePromotion.type}); |
| 503 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 507 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 504 for (Node access in accesses) { | 508 for (Node access in accesses) { |
| 505 infos.add(compiler.createMessage( | 509 infos.add(reporter.createMessage( |
| 506 access, | 510 access, |
| 507 MessageKind.ACCESSED_IN_CLOSURE_HERE, | 511 MessageKind.ACCESSED_IN_CLOSURE_HERE, |
| 508 {'variableName': variableName})); | 512 {'variableName': variableName})); |
| 509 } | 513 } |
| 510 for (Node mutation in mutations) { | 514 for (Node mutation in mutations) { |
| 511 infos.add(compiler.createMessage( | 515 infos.add(reporter.createMessage( |
| 512 mutation, | 516 mutation, |
| 513 MessageKind.POTENTIAL_MUTATION_HERE, | 517 MessageKind.POTENTIAL_MUTATION_HERE, |
| 514 {'variableName': variableName})); | 518 {'variableName': variableName})); |
| 515 } | 519 } |
| 516 typePromotion.addHint(hint, infos); | 520 typePromotion.addHint(hint, infos); |
| 517 } | 521 } |
| 518 } | 522 } |
| 519 } | 523 } |
| 520 | 524 |
| 521 /// Show type promotions from [left] and [right] in [node] given that the | 525 /// Show type promotions from [left] and [right] in [node] given that the |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 | 560 |
| 557 /** | 561 /** |
| 558 * Check if a value of type [from] can be assigned to a variable, parameter or | 562 * Check if a value of type [from] can be assigned to a variable, parameter or |
| 559 * return value of type [to]. If `isConst == true`, an error is emitted in | 563 * return value of type [to]. If `isConst == true`, an error is emitted in |
| 560 * checked mode, otherwise a warning is issued. | 564 * checked mode, otherwise a warning is issued. |
| 561 */ | 565 */ |
| 562 bool checkAssignable(Spannable spannable, DartType from, DartType to, | 566 bool checkAssignable(Spannable spannable, DartType from, DartType to, |
| 563 {bool isConst: false}) { | 567 {bool isConst: false}) { |
| 564 if (!types.isAssignable(from, to)) { | 568 if (!types.isAssignable(from, to)) { |
| 565 if (compiler.enableTypeAssertions && isConst) { | 569 if (compiler.enableTypeAssertions && isConst) { |
| 566 compiler.reportErrorMessage( | 570 reporter.reportErrorMessage( |
| 567 spannable, | 571 spannable, |
| 568 MessageKind.NOT_ASSIGNABLE, | 572 MessageKind.NOT_ASSIGNABLE, |
| 569 {'fromType': from, 'toType': to}); | 573 {'fromType': from, 'toType': to}); |
| 570 } else { | 574 } else { |
| 571 compiler.reportWarningMessage( | 575 reporter.reportWarningMessage( |
| 572 spannable, | 576 spannable, |
| 573 MessageKind.NOT_ASSIGNABLE, | 577 MessageKind.NOT_ASSIGNABLE, |
| 574 {'fromType': from, 'toType': to}); | 578 {'fromType': from, 'toType': to}); |
| 575 } | 579 } |
| 576 return false; | 580 return false; |
| 577 } | 581 } |
| 578 return true; | 582 return true; |
| 579 } | 583 } |
| 580 | 584 |
| 581 checkCondition(Expression condition) { | 585 checkCondition(Expression condition) { |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 893 /// Report [warning] including info(s) about the declaration of [element] | 897 /// Report [warning] including info(s) about the declaration of [element] |
| 894 /// or [type]. | 898 /// or [type]. |
| 895 void reportWarning(DiagnosticMessage warning) { | 899 void reportWarning(DiagnosticMessage warning) { |
| 896 // TODO(johnniwinther): Support pointing to individual parameters on | 900 // TODO(johnniwinther): Support pointing to individual parameters on |
| 897 // assignability warnings. | 901 // assignability warnings. |
| 898 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; | 902 List<DiagnosticMessage> infos = <DiagnosticMessage>[]; |
| 899 Element declaration = element; | 903 Element declaration = element; |
| 900 if (declaration == null) { | 904 if (declaration == null) { |
| 901 declaration = type.element; | 905 declaration = type.element; |
| 902 } else if (type.isTypedef) { | 906 } else if (type.isTypedef) { |
| 903 infos.add(compiler.createMessage( | 907 infos.add(reporter.createMessage( |
| 904 declaration, | 908 declaration, |
| 905 MessageKind.THIS_IS_THE_DECLARATION, | 909 MessageKind.THIS_IS_THE_DECLARATION, |
| 906 {'name': element.name})); | 910 {'name': element.name})); |
| 907 declaration = type.element; | 911 declaration = type.element; |
| 908 } | 912 } |
| 909 if (declaration != null) { | 913 if (declaration != null) { |
| 910 infos.add(compiler.createMessage( | 914 infos.add(reporter.createMessage( |
| 911 declaration, MessageKind.THIS_IS_THE_METHOD)); | 915 declaration, MessageKind.THIS_IS_THE_METHOD)); |
| 912 } | 916 } |
| 913 compiler.reportWarning(warning, infos); | 917 reporter.reportWarning(warning, infos); |
| 914 } | 918 } |
| 915 | 919 |
| 916 /// Report a warning on [node] if [argumentType] is not assignable to | 920 /// Report a warning on [node] if [argumentType] is not assignable to |
| 917 /// [parameterType]. | 921 /// [parameterType]. |
| 918 void checkAssignable(Spannable node, | 922 void checkAssignable(Spannable node, |
| 919 DartType argumentType, | 923 DartType argumentType, |
| 920 DartType parameterType) { | 924 DartType parameterType) { |
| 921 if (!types.isAssignable(argumentType, parameterType)) { | 925 if (!types.isAssignable(argumentType, parameterType)) { |
| 922 reportWarning(compiler.createMessage( | 926 reportWarning(reporter.createMessage( |
| 923 node, | 927 node, |
| 924 MessageKind.NOT_ASSIGNABLE, | 928 MessageKind.NOT_ASSIGNABLE, |
| 925 {'fromType': argumentType, 'toType': parameterType})); | 929 {'fromType': argumentType, 'toType': parameterType})); |
| 926 } | 930 } |
| 927 } | 931 } |
| 928 | 932 |
| 929 FunctionType funType = unaliasedType; | 933 FunctionType funType = unaliasedType; |
| 930 Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; | 934 Iterator<DartType> parameterTypes = funType.parameterTypes.iterator; |
| 931 Iterator<DartType> optionalParameterTypes = | 935 Iterator<DartType> optionalParameterTypes = |
| 932 funType.optionalParameterTypes.iterator; | 936 funType.optionalParameterTypes.iterator; |
| 933 while (!arguments.isEmpty) { | 937 while (!arguments.isEmpty) { |
| 934 Node argument = arguments.head; | 938 Node argument = arguments.head; |
| 935 NamedArgument namedArgument = argument.asNamedArgument(); | 939 NamedArgument namedArgument = argument.asNamedArgument(); |
| 936 if (namedArgument != null) { | 940 if (namedArgument != null) { |
| 937 argument = namedArgument.expression; | 941 argument = namedArgument.expression; |
| 938 String argumentName = namedArgument.name.source; | 942 String argumentName = namedArgument.name.source; |
| 939 DartType namedParameterType = | 943 DartType namedParameterType = |
| 940 funType.getNamedParameterType(argumentName); | 944 funType.getNamedParameterType(argumentName); |
| 941 if (namedParameterType == null) { | 945 if (namedParameterType == null) { |
| 942 // TODO(johnniwinther): Provide better information on the called | 946 // TODO(johnniwinther): Provide better information on the called |
| 943 // function. | 947 // function. |
| 944 reportWarning(compiler.createMessage( | 948 reportWarning(reporter.createMessage( |
| 945 argument, | 949 argument, |
| 946 MessageKind.NAMED_ARGUMENT_NOT_FOUND, | 950 MessageKind.NAMED_ARGUMENT_NOT_FOUND, |
| 947 {'argumentName': argumentName})); | 951 {'argumentName': argumentName})); |
| 948 | 952 |
| 949 DartType argumentType = analyze(argument); | 953 DartType argumentType = analyze(argument); |
| 950 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 954 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 951 } else { | 955 } else { |
| 952 DartType argumentType = analyze(argument); | 956 DartType argumentType = analyze(argument); |
| 953 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 957 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 954 checkAssignable(argument, argumentType, namedParameterType); | 958 checkAssignable(argument, argumentType, namedParameterType); |
| 955 } | 959 } |
| 956 } else { | 960 } else { |
| 957 if (!parameterTypes.moveNext()) { | 961 if (!parameterTypes.moveNext()) { |
| 958 if (!optionalParameterTypes.moveNext()) { | 962 if (!optionalParameterTypes.moveNext()) { |
| 959 | 963 |
| 960 // TODO(johnniwinther): Provide better information on the | 964 // TODO(johnniwinther): Provide better information on the |
| 961 // called function. | 965 // called function. |
| 962 reportWarning(compiler.createMessage( | 966 reportWarning(reporter.createMessage( |
| 963 argument, MessageKind.ADDITIONAL_ARGUMENT)); | 967 argument, MessageKind.ADDITIONAL_ARGUMENT)); |
| 964 | 968 |
| 965 DartType argumentType = analyze(argument); | 969 DartType argumentType = analyze(argument); |
| 966 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 970 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 967 } else { | 971 } else { |
| 968 DartType argumentType = analyze(argument); | 972 DartType argumentType = analyze(argument); |
| 969 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 973 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 970 checkAssignable( | 974 checkAssignable( |
| 971 argument, argumentType, optionalParameterTypes.current); | 975 argument, argumentType, optionalParameterTypes.current); |
| 972 } | 976 } |
| 973 } else { | 977 } else { |
| 974 DartType argumentType = analyze(argument); | 978 DartType argumentType = analyze(argument); |
| 975 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 979 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 976 checkAssignable(argument, argumentType, parameterTypes.current); | 980 checkAssignable(argument, argumentType, parameterTypes.current); |
| 977 } | 981 } |
| 978 } | 982 } |
| 979 arguments = arguments.tail; | 983 arguments = arguments.tail; |
| 980 } | 984 } |
| 981 if (parameterTypes.moveNext()) { | 985 if (parameterTypes.moveNext()) { |
| 982 // TODO(johnniwinther): Provide better information on the called | 986 // TODO(johnniwinther): Provide better information on the called |
| 983 // function. | 987 // function. |
| 984 reportWarning(compiler.createMessage( | 988 reportWarning(reporter.createMessage( |
| 985 send, MessageKind.MISSING_ARGUMENT, | 989 send, MessageKind.MISSING_ARGUMENT, |
| 986 {'argumentType': parameterTypes.current})); | 990 {'argumentType': parameterTypes.current})); |
| 987 } | 991 } |
| 988 } else { | 992 } else { |
| 989 while(!arguments.isEmpty) { | 993 while(!arguments.isEmpty) { |
| 990 DartType argumentType = analyze(arguments.head); | 994 DartType argumentType = analyze(arguments.head); |
| 991 if (argumentTypes != null) argumentTypes.addLast(argumentType); | 995 if (argumentTypes != null) argumentTypes.addLast(argumentType); |
| 992 arguments = arguments.tail; | 996 arguments = arguments.tail; |
| 993 } | 997 } |
| 994 } | 998 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1082 // foo() where foo is a method in the same class. | 1086 // foo() where foo is a method in the same class. |
| 1083 return createResolvedAccess(node, name, element); | 1087 return createResolvedAccess(node, name, element); |
| 1084 } else if (element.isVariable || | 1088 } else if (element.isVariable || |
| 1085 element.isParameter || | 1089 element.isParameter || |
| 1086 element.isField) { | 1090 element.isField) { |
| 1087 // foo() where foo is a field in the same class. | 1091 // foo() where foo is a field in the same class. |
| 1088 return createResolvedAccess(node, name, element); | 1092 return createResolvedAccess(node, name, element); |
| 1089 } else if (element.isGetter || element.isSetter) { | 1093 } else if (element.isGetter || element.isSetter) { |
| 1090 return createResolvedAccess(node, name, element); | 1094 return createResolvedAccess(node, name, element); |
| 1091 } else { | 1095 } else { |
| 1092 compiler.internalError(element, | 1096 reporter.internalError(element, |
| 1093 'Unexpected element kind ${element.kind}.'); | 1097 'Unexpected element kind ${element.kind}.'); |
| 1094 return null; | 1098 return null; |
| 1095 } | 1099 } |
| 1096 } | 1100 } |
| 1097 | 1101 |
| 1098 ElementAccess createResolvedAccess(Send node, String name, | 1102 ElementAccess createResolvedAccess(Send node, String name, |
| 1099 Element element) { | 1103 Element element) { |
| 1100 checkPrivateAccess(node, element, name); | 1104 checkPrivateAccess(node, element, name); |
| 1101 return createPromotedAccess(element); | 1105 return createPromotedAccess(element); |
| 1102 } | 1106 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1115 * Computes the type of the access of [name] on the [node] possibly using the | 1119 * Computes the type of the access of [name] on the [node] possibly using the |
| 1116 * [element] provided for [node] by the resolver. | 1120 * [element] provided for [node] by the resolver. |
| 1117 */ | 1121 */ |
| 1118 DartType computeAccessType(Send node, String name, Element element, | 1122 DartType computeAccessType(Send node, String name, Element element, |
| 1119 MemberKind memberKind, | 1123 MemberKind memberKind, |
| 1120 {bool lookupClassMember: false}) { | 1124 {bool lookupClassMember: false}) { |
| 1121 DartType type = | 1125 DartType type = |
| 1122 computeAccess(node, name, element, memberKind, | 1126 computeAccess(node, name, element, memberKind, |
| 1123 lookupClassMember: lookupClassMember).computeType(resolution); | 1127 lookupClassMember: lookupClassMember).computeType(resolution); |
| 1124 if (type == null) { | 1128 if (type == null) { |
| 1125 compiler.internalError(node, 'Type is null on access of $name on $node.'); | 1129 reporter.internalError(node, 'Type is null on access of $name on $node.'); |
| 1126 } | 1130 } |
| 1127 return type; | 1131 return type; |
| 1128 } | 1132 } |
| 1129 | 1133 |
| 1130 /// Compute a version of [shownType] that is more specific that [knownType]. | 1134 /// Compute a version of [shownType] that is more specific that [knownType]. |
| 1131 /// This is used to provided better hints when trying to promote a supertype | 1135 /// This is used to provided better hints when trying to promote a supertype |
| 1132 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` | 1136 /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List` |
| 1133 /// we suggest the use of `List<int>`, which would make promotion valid. | 1137 /// we suggest the use of `List<int>`, which would make promotion valid. |
| 1134 DartType computeMoreSpecificType(DartType shownType, | 1138 DartType computeMoreSpecificType(DartType shownType, |
| 1135 DartType knownType) { | 1139 DartType knownType) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1234 if (variable != null && | 1238 if (variable != null && |
| 1235 (variable.isVariable || variable.isParameter)) { | 1239 (variable.isVariable || variable.isParameter)) { |
| 1236 DartType knownType = getKnownType(variable); | 1240 DartType knownType = getKnownType(variable); |
| 1237 if (!knownType.isDynamic) { | 1241 if (!knownType.isDynamic) { |
| 1238 DartType shownType = elements.getType(node.arguments.head); | 1242 DartType shownType = elements.getType(node.arguments.head); |
| 1239 TypePromotion typePromotion = | 1243 TypePromotion typePromotion = |
| 1240 new TypePromotion(node, variable, shownType); | 1244 new TypePromotion(node, variable, shownType); |
| 1241 if (!types.isMoreSpecific(shownType, knownType)) { | 1245 if (!types.isMoreSpecific(shownType, knownType)) { |
| 1242 String variableName = variable.name; | 1246 String variableName = variable.name; |
| 1243 if (!types.isSubtype(shownType, knownType)) { | 1247 if (!types.isSubtype(shownType, knownType)) { |
| 1244 typePromotion.addHint(compiler.createMessage( | 1248 typePromotion.addHint(reporter.createMessage( |
| 1245 node, | 1249 node, |
| 1246 MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, | 1250 MessageKind.NOT_MORE_SPECIFIC_SUBTYPE, |
| 1247 {'variableName': variableName, | 1251 {'variableName': variableName, |
| 1248 'shownType': shownType, | 1252 'shownType': shownType, |
| 1249 'knownType': knownType})); | 1253 'knownType': knownType})); |
| 1250 } else { | 1254 } else { |
| 1251 DartType shownTypeSuggestion = | 1255 DartType shownTypeSuggestion = |
| 1252 computeMoreSpecificType(shownType, knownType); | 1256 computeMoreSpecificType(shownType, knownType); |
| 1253 if (shownTypeSuggestion != null) { | 1257 if (shownTypeSuggestion != null) { |
| 1254 typePromotion.addHint(compiler.createMessage( | 1258 typePromotion.addHint(reporter.createMessage( |
| 1255 node, | 1259 node, |
| 1256 MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, | 1260 MessageKind.NOT_MORE_SPECIFIC_SUGGESTION, |
| 1257 {'variableName': variableName, | 1261 {'variableName': variableName, |
| 1258 'shownType': shownType, | 1262 'shownType': shownType, |
| 1259 'shownTypeSuggestion': shownTypeSuggestion, | 1263 'shownTypeSuggestion': shownTypeSuggestion, |
| 1260 'knownType': knownType})); | 1264 'knownType': knownType})); |
| 1261 } else { | 1265 } else { |
| 1262 typePromotion.addHint(compiler.createMessage( | 1266 typePromotion.addHint(reporter.createMessage( |
| 1263 node, | 1267 node, |
| 1264 MessageKind.NOT_MORE_SPECIFIC, | 1268 MessageKind.NOT_MORE_SPECIFIC, |
| 1265 {'variableName': variableName, | 1269 {'variableName': variableName, |
| 1266 'shownType': shownType, | 1270 'shownType': shownType, |
| 1267 'knownType': knownType})); | 1271 'knownType': knownType})); |
| 1268 } | 1272 } |
| 1269 } | 1273 } |
| 1270 } | 1274 } |
| 1271 showTypePromotion(node, typePromotion); | 1275 showTypePromotion(node, typePromotion); |
| 1272 } | 1276 } |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1541 case '*=': operatorName = '*'; break; | 1545 case '*=': operatorName = '*'; break; |
| 1542 case '/=': operatorName = '/'; break; | 1546 case '/=': operatorName = '/'; break; |
| 1543 case '%=': operatorName = '%'; break; | 1547 case '%=': operatorName = '%'; break; |
| 1544 case '~/=': operatorName = '~/'; break; | 1548 case '~/=': operatorName = '~/'; break; |
| 1545 case '&=': operatorName = '&'; break; | 1549 case '&=': operatorName = '&'; break; |
| 1546 case '|=': operatorName = '|'; break; | 1550 case '|=': operatorName = '|'; break; |
| 1547 case '^=': operatorName = '^'; break; | 1551 case '^=': operatorName = '^'; break; |
| 1548 case '<<=': operatorName = '<<'; break; | 1552 case '<<=': operatorName = '<<'; break; |
| 1549 case '>>=': operatorName = '>>'; break; | 1553 case '>>=': operatorName = '>>'; break; |
| 1550 default: | 1554 default: |
| 1551 compiler.internalError(node, 'Unexpected assignment operator $name.'); | 1555 reporter.internalError(node, 'Unexpected assignment operator $name.'); |
| 1552 } | 1556 } |
| 1553 if (node.isIndex) { | 1557 if (node.isIndex) { |
| 1554 // base[key] o= value for some operator o. | 1558 // base[key] o= value for some operator o. |
| 1555 final Node valueNode = node.arguments.tail.head; | 1559 final Node valueNode = node.arguments.tail.head; |
| 1556 final DartType value = analyze(valueNode); | 1560 final DartType value = analyze(valueNode); |
| 1557 return checkIndexAssignmentOperator( | 1561 return checkIndexAssignmentOperator( |
| 1558 node, operatorName, valueNode, value); | 1562 node, operatorName, valueNode, value); |
| 1559 } else { | 1563 } else { |
| 1560 // target o= value for some operator o. | 1564 // target o= value for some operator o. |
| 1561 final Node valueNode = node.arguments.head; | 1565 final Node valueNode = node.arguments.head; |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1960 ConstantExpression caseConstant = | 1964 ConstantExpression caseConstant = |
| 1961 compiler.resolver.constantCompiler.compileNode( | 1965 compiler.resolver.constantCompiler.compileNode( |
| 1962 caseMatch.expression, elements); | 1966 caseMatch.expression, elements); |
| 1963 enumValues.remove( | 1967 enumValues.remove( |
| 1964 compiler.constants.getConstantValue(caseConstant)); | 1968 compiler.constants.getConstantValue(caseConstant)); |
| 1965 } | 1969 } |
| 1966 } | 1970 } |
| 1967 } | 1971 } |
| 1968 unreferencedFields.addAll(enumValues.values); | 1972 unreferencedFields.addAll(enumValues.values); |
| 1969 if (!unreferencedFields.isEmpty) { | 1973 if (!unreferencedFields.isEmpty) { |
| 1970 compiler.reportWarningMessage( | 1974 reporter.reportWarningMessage( |
| 1971 node, MessageKind.MISSING_ENUM_CASES, | 1975 node, MessageKind.MISSING_ENUM_CASES, |
| 1972 {'enumType': expressionType, | 1976 {'enumType': expressionType, |
| 1973 'enumValues': unreferencedFields.map( | 1977 'enumValues': unreferencedFields.map( |
| 1974 (e) => e.name).join(', ')}); | 1978 (e) => e.name).join(', ')}); |
| 1975 } | 1979 } |
| 1976 }); | 1980 }); |
| 1977 } | 1981 } |
| 1978 | 1982 |
| 1979 return const StatementType(); | 1983 return const StatementType(); |
| 1980 } | 1984 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1997 | 2001 |
| 1998 visitCatchBlock(CatchBlock node) { | 2002 visitCatchBlock(CatchBlock node) { |
| 1999 return analyze(node.block); | 2003 return analyze(node.block); |
| 2000 } | 2004 } |
| 2001 | 2005 |
| 2002 visitTypedef(Typedef node) { | 2006 visitTypedef(Typedef node) { |
| 2003 // Do not typecheck [Typedef] nodes. | 2007 // Do not typecheck [Typedef] nodes. |
| 2004 } | 2008 } |
| 2005 | 2009 |
| 2006 visitNode(Node node) { | 2010 visitNode(Node node) { |
| 2007 compiler.internalError(node, | 2011 reporter.internalError(node, |
| 2008 'Unexpected node ${node.getObjectDescription()} in the type checker.'); | 2012 'Unexpected node ${node.getObjectDescription()} in the type checker.'); |
| 2009 } | 2013 } |
| 2010 } | 2014 } |
| OLD | NEW |