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

Side by Side Diff: lib/src/checker/checker.dart

Issue 1172453002: fixes #209, remove tree mutation from CodeChecker (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 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
« no previous file with comments | « no previous file | lib/src/checker/rules.dart » ('j') | lib/src/testing.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 dev_compiler.src.checker.checker; 5 library dev_compiler.src.checker.checker;
6 6
7 import 'package:analyzer/analyzer.dart'; 7 import 'package:analyzer/analyzer.dart';
8 import 'package:analyzer/src/generated/ast.dart'; 8 import 'package:analyzer/src/generated/ast.dart';
9 import 'package:analyzer/src/generated/element.dart'; 9 import 'package:analyzer/src/generated/element.dart';
10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType; 10 import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 super.visitClassDeclaration(node); 391 super.visitClassDeclaration(node);
392 } 392 }
393 393
394 @override 394 @override
395 void visitAssignmentExpression(AssignmentExpression node) { 395 void visitAssignmentExpression(AssignmentExpression node) {
396 var token = node.operator; 396 var token = node.operator;
397 if (token.type != TokenType.EQ) { 397 if (token.type != TokenType.EQ) {
398 _checkCompoundAssignment(node); 398 _checkCompoundAssignment(node);
399 } else { 399 } else {
400 DartType staticType = _rules.getStaticType(node.leftHandSide); 400 DartType staticType = _rules.getStaticType(node.leftHandSide);
401 node.rightHandSide = checkAssignment(node.rightHandSide, staticType); 401 checkAssignment(node.rightHandSide, staticType);
402 } 402 }
403 node.visitChildren(this); 403 node.visitChildren(this);
404 } 404 }
405 405
406 /// Check constructor declaration to ensure correct super call placement. 406 /// Check constructor declaration to ensure correct super call placement.
407 @override 407 @override
408 void visitConstructorDeclaration(ConstructorDeclaration node) { 408 void visitConstructorDeclaration(ConstructorDeclaration node) {
409 _visitMaybeConst(node, (node) { 409 _visitMaybeConst(node, (node) {
410 node.visitChildren(this); 410 node.visitChildren(this);
411 411
412 final init = node.initializers; 412 final init = node.initializers;
413 for (int i = 0, last = init.length - 1; i < last; i++) { 413 for (int i = 0, last = init.length - 1; i < last; i++) {
414 final node = init[i]; 414 final node = init[i];
415 if (node is SuperConstructorInvocation) { 415 if (node is SuperConstructorInvocation) {
416 _recordMessage(new InvalidSuperInvocation(node)); 416 _recordMessage(new InvalidSuperInvocation(node));
417 } 417 }
418 } 418 }
419 }); 419 });
420 } 420 }
421 421
422 @override 422 @override
423 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) { 423 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
424 var field = node.fieldName; 424 var field = node.fieldName;
425 DartType staticType = _rules.elementType(field.staticElement); 425 DartType staticType = _rules.elementType(field.staticElement);
426 node.expression = checkAssignment(node.expression, staticType); 426 checkAssignment(node.expression, staticType);
427 node.visitChildren(this); 427 node.visitChildren(this);
428 } 428 }
429 429
430 @override 430 @override
431 void visitForEachStatement(ForEachStatement node) { 431 void visitForEachStatement(ForEachStatement node) {
432 // Check that the expression is an Iterable. 432 // Check that the expression is an Iterable.
433 var expr = node.iterable; 433 var expr = node.iterable;
434 var iterableType = _rules.provider.iterableType; 434 var iterableType = _rules.provider.iterableType;
435 var loopVariable = node.identifier != null 435 var loopVariable = node.identifier != null
436 ? node.identifier 436 ? node.identifier
437 : node.loopVariable.identifier; 437 : node.loopVariable.identifier;
438 var iteratorType = loopVariable.staticType; 438 var iteratorType = loopVariable.staticType;
439 var checkedType = iterableType.substitute4([iteratorType]); 439 var checkedType = iterableType.substitute4([iteratorType]);
440 node.iterable = checkAssignment(expr, checkedType); 440 checkAssignment(expr, checkedType);
441 node.visitChildren(this); 441 node.visitChildren(this);
442 } 442 }
443 443
444 @override 444 @override
445 void visitForStatement(ForStatement node) { 445 void visitForStatement(ForStatement node) {
446 if (node.condition != null) { 446 if (node.condition != null) {
447 node.condition = checkBoolean(node.condition); 447 checkBoolean(node.condition);
448 } 448 }
449 node.visitChildren(this); 449 node.visitChildren(this);
450 } 450 }
451 451
452 @override 452 @override
453 void visitIfStatement(IfStatement node) { 453 void visitIfStatement(IfStatement node) {
454 node.condition = checkBoolean(node.condition); 454 checkBoolean(node.condition);
455 node.visitChildren(this); 455 node.visitChildren(this);
456 } 456 }
457 457
458 @override 458 @override
459 void visitDoStatement(DoStatement node) { 459 void visitDoStatement(DoStatement node) {
460 node.condition = checkBoolean(node.condition); 460 checkBoolean(node.condition);
461 node.visitChildren(this); 461 node.visitChildren(this);
462 } 462 }
463 463
464 @override 464 @override
465 void visitWhileStatement(WhileStatement node) { 465 void visitWhileStatement(WhileStatement node) {
466 node.condition = checkBoolean(node.condition); 466 checkBoolean(node.condition);
467 node.visitChildren(this); 467 node.visitChildren(this);
468 } 468 }
469 469
470 @override 470 @override
471 void visitSwitchStatement(SwitchStatement node) { 471 void visitSwitchStatement(SwitchStatement node) {
472 // SwitchStatement defines a boolean conversion to check the result of the 472 // SwitchStatement defines a boolean conversion to check the result of the
473 // case value == the switch value, but in dev_compiler we require a boolean 473 // case value == the switch value, but in dev_compiler we require a boolean
474 // return type from an overridden == operator (because Object.==), so 474 // return type from an overridden == operator (because Object.==), so
475 // checking in SwitchStatement shouldn't be necessary. 475 // checking in SwitchStatement shouldn't be necessary.
476 node.visitChildren(this); 476 node.visitChildren(this);
477 } 477 }
478 478
479 @override 479 @override
480 void visitListLiteral(ListLiteral node) { 480 void visitListLiteral(ListLiteral node) {
481 var type = _rules.provider.dynamicType; 481 var type = _rules.provider.dynamicType;
482 if (node.typeArguments != null) { 482 if (node.typeArguments != null) {
483 var targs = node.typeArguments.arguments; 483 var targs = node.typeArguments.arguments;
484 if (targs.length > 0) type = targs[0].type; 484 if (targs.length > 0) type = targs[0].type;
485 } 485 }
486 var elements = node.elements; 486 var elements = node.elements;
487 for (int i = 0; i < elements.length; i++) { 487 for (int i = 0; i < elements.length; i++) {
488 elements[i] = checkArgument(elements[i], type); 488 checkArgument(elements[i], type);
489 } 489 }
490 super.visitListLiteral(node); 490 super.visitListLiteral(node);
491 } 491 }
492 492
493 @override 493 @override
494 void visitMapLiteral(MapLiteral node) { 494 void visitMapLiteral(MapLiteral node) {
495 var ktype = _rules.provider.dynamicType; 495 var ktype = _rules.provider.dynamicType;
496 var vtype = _rules.provider.dynamicType; 496 var vtype = _rules.provider.dynamicType;
497 if (node.typeArguments != null) { 497 if (node.typeArguments != null) {
498 var targs = node.typeArguments.arguments; 498 var targs = node.typeArguments.arguments;
499 if (targs.length > 0) ktype = targs[0].type; 499 if (targs.length > 0) ktype = targs[0].type;
500 if (targs.length > 1) vtype = targs[1].type; 500 if (targs.length > 1) vtype = targs[1].type;
501 } 501 }
502 var entries = node.entries; 502 var entries = node.entries;
503 for (int i = 0; i < entries.length; i++) { 503 for (int i = 0; i < entries.length; i++) {
504 var entry = entries[i]; 504 var entry = entries[i];
505 entry.key = checkArgument(entry.key, ktype); 505 checkArgument(entry.key, ktype);
506 entry.value = checkArgument(entry.value, vtype); 506 checkArgument(entry.value, vtype);
507 } 507 }
508 super.visitMapLiteral(node); 508 super.visitMapLiteral(node);
509 } 509 }
510 510
511 // Check invocations 511 // Check invocations
512 bool checkArgumentList(ArgumentList node, FunctionType type) { 512 void checkArgumentList(ArgumentList node, FunctionType type) {
513 NodeList<Expression> list = node.arguments; 513 NodeList<Expression> list = node.arguments;
514 int len = list.length; 514 int len = list.length;
515 for (int i = 0; i < len; ++i) { 515 for (int i = 0; i < len; ++i) {
516 Expression arg = list[i]; 516 Expression arg = list[i];
517 ParameterElement element = arg.staticParameterElement; 517 ParameterElement element = arg.staticParameterElement;
518 if (element == null) { 518 if (element == null) {
519 if (type.parameters.length < len) { 519 if (type.parameters.length < len) {
520 // We found an argument mismatch, the analyzer will report this too, 520 // We found an argument mismatch, the analyzer will report this too,
521 // so no need to insert an error for this here. 521 // so no need to insert an error for this here.
522 continue; 522 continue;
523 } 523 }
524 element = type.parameters[i]; 524 element = type.parameters[i];
525 // TODO(vsm): When can this happen? 525 // TODO(vsm): When can this happen?
526 assert(element != null); 526 assert(element != null);
527 } 527 }
528 DartType expectedType = _rules.elementType(element); 528 DartType expectedType = _rules.elementType(element);
529 if (expectedType == null) expectedType = _rules.provider.dynamicType; 529 if (expectedType == null) expectedType = _rules.provider.dynamicType;
530 list[i] = checkArgument(arg, expectedType); 530 checkArgument(arg, expectedType);
531 } 531 }
532 return true;
533 } 532 }
534 533
535 Expression checkArgument(Expression arg, DartType expectedType) { 534 void checkArgument(Expression arg, DartType expectedType) {
536 // Preserve named argument structure, so their immediate parent is the 535 // Preserve named argument structure, so their immediate parent is the
537 // method invocation. 536 // method invocation.
538 if (arg is NamedExpression) { 537 if (arg is NamedExpression) {
539 arg.expression = checkAssignment(arg.expression, expectedType); 538 arg = (arg as NamedExpression).expression;
540 return arg;
541 } 539 }
542 return checkAssignment(arg, expectedType); 540 checkAssignment(arg, expectedType);
543 } 541 }
544 542
545 void checkFunctionApplication( 543 void checkFunctionApplication(
546 Expression node, Expression f, ArgumentList list) { 544 Expression node, Expression f, ArgumentList list) {
547 if (_rules.isDynamicCall(f)) { 545 if (_rules.isDynamicCall(f)) {
548 // If f is Function and this is a method invocation, we should have 546 // If f is Function and this is a method invocation, we should have
549 // gotten an analyzer error, so no need to issue another error. 547 // gotten an analyzer error, so no need to issue another error.
550 _recordDynamicInvoke(node); 548 _recordDynamicInvoke(node);
551 } else { 549 } else {
552 checkArgumentList(list, _rules.getTypeAsCaller(f)); 550 checkArgumentList(list, _rules.getTypeAsCaller(f));
553 } 551 }
554 } 552 }
555 553
556 @override 554 @override
557 void visitMethodInvocation(MethodInvocation node) { 555 void visitMethodInvocation(MethodInvocation node) {
558 checkFunctionApplication(node, node.methodName, node.argumentList); 556 checkFunctionApplication(node, node.methodName, node.argumentList);
559 node.visitChildren(this); 557 node.visitChildren(this);
560 } 558 }
561 559
562 @override 560 @override
563 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 561 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
564 checkFunctionApplication(node, node.function, node.argumentList); 562 checkFunctionApplication(node, node.function, node.argumentList);
565 node.visitChildren(this); 563 node.visitChildren(this);
566 } 564 }
567 565
568 @override 566 @override
569 void visitRedirectingConstructorInvocation( 567 void visitRedirectingConstructorInvocation(
570 RedirectingConstructorInvocation node) { 568 RedirectingConstructorInvocation node) {
571 var type = node.staticElement.type; 569 var type = node.staticElement.type;
572 bool checked = checkArgumentList(node.argumentList, type); 570 checkArgumentList(node.argumentList, type);
573 assert(checked);
574 node.visitChildren(this); 571 node.visitChildren(this);
575 } 572 }
576 573
577 @override 574 @override
578 void visitSuperConstructorInvocation(SuperConstructorInvocation node) { 575 void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
579 var element = node.staticElement; 576 var element = node.staticElement;
580 if (element == null) { 577 if (element == null) {
581 _recordMessage(new MissingTypeError(node)); 578 _recordMessage(new MissingTypeError(node));
582 } else { 579 } else {
583 var type = node.staticElement.type; 580 var type = node.staticElement.type;
584 bool checked = checkArgumentList(node.argumentList, type); 581 checkArgumentList(node.argumentList, type);
585 assert(checked);
586 } 582 }
587 node.visitChildren(this); 583 node.visitChildren(this);
588 } 584 }
589 585
590 AstNode _getOwnerFunction(AstNode node) { 586 AstNode _getOwnerFunction(AstNode node) {
591 var parent = node.parent; 587 var parent = node.parent;
592 while (parent is! FunctionExpression && 588 while (parent is! FunctionExpression &&
593 parent is! MethodDeclaration && 589 parent is! MethodDeclaration &&
594 parent is! ConstructorDeclaration) { 590 parent is! ConstructorDeclaration) {
595 parent = parent.parent; 591 parent = parent.parent;
596 } 592 }
597 return parent; 593 return parent;
598 } 594 }
599 595
600 FunctionType _getFunctionType(AstNode node) { 596 FunctionType _getFunctionType(AstNode node) {
601 if (node is Declaration) { 597 if (node is Declaration) {
602 return _rules.elementType(node.element); 598 return _rules.elementType(node.element);
603 } else { 599 } else {
604 assert(node is FunctionExpression); 600 assert(node is FunctionExpression);
605 return _rules.getStaticType(node); 601 return _rules.getStaticType(node);
606 } 602 }
607 } 603 }
608 604
609 Expression _checkReturn(Expression expression, AstNode node) { 605 void _checkReturn(Expression expression, AstNode node) {
610 var type = _getFunctionType(_getOwnerFunction(node)).returnType; 606 var type = _getFunctionType(_getOwnerFunction(node)).returnType;
611 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null. 607 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
612 if (expression == null) return null; 608 if (expression != null) checkAssignment(expression, type);
613 return checkAssignment(expression, type);
614 } 609 }
615 610
616 @override 611 @override
617 void visitExpressionFunctionBody(ExpressionFunctionBody node) { 612 void visitExpressionFunctionBody(ExpressionFunctionBody node) {
618 node.expression = _checkReturn(node.expression, node); 613 _checkReturn(node.expression, node);
619 node.visitChildren(this); 614 node.visitChildren(this);
620 } 615 }
621 616
622 @override 617 @override
623 void visitReturnStatement(ReturnStatement node) { 618 void visitReturnStatement(ReturnStatement node) {
624 node.expression = _checkReturn(node.expression, node); 619 _checkReturn(node.expression, node);
625 node.visitChildren(this); 620 node.visitChildren(this);
626 } 621 }
627 622
628 @override 623 @override
629 void visitPropertyAccess(PropertyAccess node) { 624 void visitPropertyAccess(PropertyAccess node) {
630 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) { 625 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) {
631 _recordDynamicInvoke(node); 626 _recordDynamicInvoke(node);
632 } 627 }
633 node.visitChildren(this); 628 node.visitChildren(this);
634 } 629 }
(...skipping 15 matching lines...) Expand all
650 var parameterType = _rules.elementType(parameter.element); 645 var parameterType = _rules.elementType(parameter.element);
651 assert(parameterType != null); 646 assert(parameterType != null);
652 var defaultValue = node.defaultValue; 647 var defaultValue = node.defaultValue;
653 if (defaultValue == null) { 648 if (defaultValue == null) {
654 if (_rules.maybeNonNullableType(parameterType)) { 649 if (_rules.maybeNonNullableType(parameterType)) {
655 var staticInfo = new InvalidVariableDeclaration( 650 var staticInfo = new InvalidVariableDeclaration(
656 _rules, node.identifier, parameterType); 651 _rules, node.identifier, parameterType);
657 _recordMessage(staticInfo); 652 _recordMessage(staticInfo);
658 } 653 }
659 } else { 654 } else {
660 var staticInfo = checkAssignment(defaultValue, parameterType); 655 checkAssignment(defaultValue, parameterType);
661 if (staticInfo is! StaticError) node.defaultValue = staticInfo;
662 } 656 }
663 657
664 node.visitChildren(this); 658 node.visitChildren(this);
665 }); 659 });
666 } 660 }
667 661
668 @override 662 @override
669 void visitFieldFormalParameter(FieldFormalParameter node) { 663 void visitFieldFormalParameter(FieldFormalParameter node) {
670 var element = node.element; 664 var element = node.element;
671 var typeName = node.type; 665 var typeName = node.type;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 TypeName type = node.type; 698 TypeName type = node.type;
705 if (type == null) { 699 if (type == null) {
706 // No checks are needed when the type is var. Although internally the 700 // No checks are needed when the type is var. Although internally the
707 // typing rules may have inferred a more precise type for the variable 701 // typing rules may have inferred a more precise type for the variable
708 // based on the initializer. 702 // based on the initializer.
709 } else { 703 } else {
710 var dartType = getType(type); 704 var dartType = getType(type);
711 for (VariableDeclaration variable in node.variables) { 705 for (VariableDeclaration variable in node.variables) {
712 var initializer = variable.initializer; 706 var initializer = variable.initializer;
713 if (initializer != null) { 707 if (initializer != null) {
714 variable.initializer = checkAssignment(initializer, dartType); 708 checkAssignment(initializer, dartType);
715 } else if (_rules.maybeNonNullableType(dartType)) { 709 } else if (_rules.maybeNonNullableType(dartType)) {
716 var element = variable.element; 710 var element = variable.element;
717 if (element is FieldElement && !element.isStatic) { 711 if (element is FieldElement && !element.isStatic) {
718 // Initialized - possibly implicitly - during construction. 712 // Initialized - possibly implicitly - during construction.
719 // Handle this via a runtime check during code generation. 713 // Handle this via a runtime check during code generation.
720 714
721 // TODO(vsm): Detect statically whether this can fail and 715 // TODO(vsm): Detect statically whether this can fail and
722 // report a static error (must fail) or warning (can fail). 716 // report a static error (must fail) or warning (can fail).
723 } else { 717 } else {
724 var staticInfo = 718 var staticInfo =
(...skipping 29 matching lines...) Expand all
754 748
755 @override 749 @override
756 void visitIsExpression(IsExpression node) { 750 void visitIsExpression(IsExpression node) {
757 _checkRuntimeTypeCheck(node, node.type); 751 _checkRuntimeTypeCheck(node, node.type);
758 node.visitChildren(this); 752 node.visitChildren(this);
759 } 753 }
760 754
761 @override 755 @override
762 void visitPrefixExpression(PrefixExpression node) { 756 void visitPrefixExpression(PrefixExpression node) {
763 if (node.operator.type == TokenType.BANG) { 757 if (node.operator.type == TokenType.BANG) {
764 node.operand = checkBoolean(node.operand); 758 checkBoolean(node.operand);
765 } else { 759 } else {
766 _checkUnary(node); 760 _checkUnary(node);
767 } 761 }
768 node.visitChildren(this); 762 node.visitChildren(this);
769 } 763 }
770 764
771 @override 765 @override
772 void visitPostfixExpression(PostfixExpression node) { 766 void visitPostfixExpression(PostfixExpression node) {
773 _checkUnary(node); 767 _checkUnary(node);
774 node.visitChildren(this); 768 node.visitChildren(this);
(...skipping 24 matching lines...) Expand all
799 _recordDynamicInvoke(node); 793 _recordDynamicInvoke(node);
800 } 794 }
801 } else { 795 } else {
802 var element = node.staticElement; 796 var element = node.staticElement;
803 // Method invocation. 797 // Method invocation.
804 if (element is MethodElement) { 798 if (element is MethodElement) {
805 var type = element.type as FunctionType; 799 var type = element.type as FunctionType;
806 // Analyzer should enforce number of parameter types, but check in 800 // Analyzer should enforce number of parameter types, but check in
807 // case we have erroneous input. 801 // case we have erroneous input.
808 if (type.normalParameterTypes.isNotEmpty) { 802 if (type.normalParameterTypes.isNotEmpty) {
809 node.rightOperand = 803 checkArgument(node.rightOperand, type.normalParameterTypes[0]);
810 checkArgument(node.rightOperand, type.normalParameterTypes[0]);
811 } 804 }
812 } else { 805 } else {
813 // TODO(vsm): Assert that the analyzer found an error here? 806 // TODO(vsm): Assert that the analyzer found an error here?
814 } 807 }
815 } 808 }
816 } else { 809 } else {
817 // Non-method operator. 810 // Non-method operator.
818 switch (op.type) { 811 switch (op.type) {
819 case TokenType.AMPERSAND_AMPERSAND: 812 case TokenType.AMPERSAND_AMPERSAND:
820 case TokenType.BAR_BAR: 813 case TokenType.BAR_BAR:
821 node.leftOperand = checkBoolean(node.leftOperand); 814 checkBoolean(node.leftOperand);
822 node.rightOperand = checkBoolean(node.rightOperand); 815 checkBoolean(node.rightOperand);
823 break; 816 break;
824 case TokenType.BANG_EQ: 817 case TokenType.BANG_EQ:
825 break; 818 break;
826 default: 819 default:
827 assert(false); 820 assert(false);
828 } 821 }
829 } 822 }
830 node.visitChildren(this); 823 node.visitChildren(this);
831 } 824 }
832 825
833 @override 826 @override
834 void visitConditionalExpression(ConditionalExpression node) { 827 void visitConditionalExpression(ConditionalExpression node) {
835 node.condition = checkBoolean(node.condition); 828 checkBoolean(node.condition);
836 node.visitChildren(this); 829 node.visitChildren(this);
837 } 830 }
838 831
839 @override 832 @override
840 void visitIndexExpression(IndexExpression node) { 833 void visitIndexExpression(IndexExpression node) {
841 if (_rules.isDynamicTarget(node.target)) { 834 if (_rules.isDynamicTarget(node.target)) {
842 _recordDynamicInvoke(node); 835 _recordDynamicInvoke(node);
843 } else { 836 } else {
844 var element = node.staticElement; 837 var element = node.staticElement;
845 if (element is MethodElement) { 838 if (element is MethodElement) {
846 var type = element.type as FunctionType; 839 var type = element.type as FunctionType;
847 // Analyzer should enforce number of parameter types, but check in 840 // Analyzer should enforce number of parameter types, but check in
848 // case we have erroneous input. 841 // case we have erroneous input.
849 if (type.normalParameterTypes.isNotEmpty) { 842 if (type.normalParameterTypes.isNotEmpty) {
850 node.index = checkArgument(node.index, type.normalParameterTypes[0]); 843 checkArgument(node.index, type.normalParameterTypes[0]);
851 } 844 }
852 } else { 845 } else {
853 // TODO(vsm): Assert that the analyzer found an error here? 846 // TODO(vsm): Assert that the analyzer found an error here?
854 } 847 }
855 } 848 }
856 node.visitChildren(this); 849 node.visitChildren(this);
857 } 850 }
858 851
859 DartType getType(TypeName name) { 852 DartType getType(TypeName name) {
860 return (name == null) ? _rules.provider.dynamicType : name.type; 853 return (name == null) ? _rules.provider.dynamicType : name.type;
861 } 854 }
862 855
863 /// Analyzer checks boolean conversions, but we need to check too, because 856 /// Analyzer checks boolean conversions, but we need to check too, because
864 /// it uses the default assignability rules that allow `dynamic` and `Object` 857 /// it uses the default assignability rules that allow `dynamic` and `Object`
865 /// to be assigned to bool with no message. 858 /// to be assigned to bool with no message.
866 Expression checkBoolean(Expression expr) => 859 void checkBoolean(Expression expr) =>
867 checkAssignment(expr, _rules.provider.boolType); 860 checkAssignment(expr, _rules.provider.boolType);
868 861
869 Expression checkAssignment(Expression expr, DartType type) { 862 void checkAssignment(Expression expr, DartType type) {
870 if (expr is ParenthesizedExpression) { 863 if (expr is ParenthesizedExpression) {
871 expr.expression = checkAssignment(expr.expression, type); 864 checkAssignment(expr.expression, type);
872 } else { 865 } else {
873 final staticInfo = _rules.checkAssignment(expr, type, _constantContext); 866 _recordMessage(_rules.checkAssignment(expr, type, _constantContext));
874 _recordMessage(staticInfo);
875 if (staticInfo is Conversion) expr = staticInfo;
876 } 867 }
877 return expr;
878 } 868 }
879 869
880 DartType _specializedBinaryReturnType( 870 DartType _specializedBinaryReturnType(
881 TokenType op, DartType t1, DartType t2, DartType normalReturnType) { 871 TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
882 // This special cases binary return types as per 16.26 and 16.27 of the 872 // This special cases binary return types as per 16.26 and 16.27 of the
883 // Dart language spec. 873 // Dart language spec.
884 switch (op) { 874 switch (op) {
885 case TokenType.PLUS: 875 case TokenType.PLUS:
886 case TokenType.MINUS: 876 case TokenType.MINUS:
887 case TokenType.STAR: 877 case TokenType.STAR:
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
926 916
927 if (!_rules.isSubTypeOf(returnType, lhsType)) { 917 if (!_rules.isSubTypeOf(returnType, lhsType)) {
928 final numType = _rules.provider.numType; 918 final numType = _rules.provider.numType;
929 // Try to fix up the numerical case if possible. 919 // Try to fix up the numerical case if possible.
930 if (_rules.isSubTypeOf(lhsType, numType) && 920 if (_rules.isSubTypeOf(lhsType, numType) &&
931 _rules.isSubTypeOf(lhsType, rhsType)) { 921 _rules.isSubTypeOf(lhsType, rhsType)) {
932 // This is also slightly different from spec, but allows us to keep 922 // This is also slightly different from spec, but allows us to keep
933 // compound operators in the int += num and num += dynamic cases. 923 // compound operators in the int += num and num += dynamic cases.
934 staticInfo = DownCast.create( 924 staticInfo = DownCast.create(
935 _rules, expr.rightHandSide, Coercion.cast(rhsType, lhsType)); 925 _rules, expr.rightHandSide, Coercion.cast(rhsType, lhsType));
936 if (staticInfo is DownCast) {
937 expr.rightHandSide = staticInfo;
938 }
939 rhsType = lhsType; 926 rhsType = lhsType;
940 } else { 927 } else {
941 // Static type error 928 // Static type error
942 staticInfo = new StaticTypeError(_rules, expr, lhsType); 929 staticInfo = new StaticTypeError(_rules, expr, lhsType);
943 } 930 }
944 _recordMessage(staticInfo); 931 _recordMessage(staticInfo);
945 } 932 }
946 933
947 // Check the rhs type 934 // Check the rhs type
948 if (staticInfo is! Conversion) { 935 if (staticInfo is! CoercionInfo) {
949 var paramType = paramTypes.first; 936 var paramType = paramTypes.first;
950 staticInfo = _rules.checkAssignment( 937 staticInfo = _rules.checkAssignment(
951 expr.rightHandSide, paramType, _constantContext); 938 expr.rightHandSide, paramType, _constantContext);
952 _recordMessage(staticInfo); 939 _recordMessage(staticInfo);
953 if (staticInfo is Conversion) expr.rightHandSide = staticInfo;
954 } 940 }
955 } 941 }
956 } 942 }
957 943
958 void _recordDynamicInvoke(AstNode node) { 944 void _recordDynamicInvoke(AstNode node) {
959 _reporter.log(new DynamicInvoke(_rules, node)); 945 _reporter.log(new DynamicInvoke(_rules, node));
960 } 946 }
961 947
962 void _recordMessage(StaticInfo info) { 948 void _recordMessage(StaticInfo info) {
963 if (info == null) return; 949 if (info == null) return;
964 if (info.level >= logger.Level.SEVERE) _failure = true; 950 if (info.level >= logger.Level.SEVERE) _failure = true;
965 _reporter.log(info); 951 _reporter.log(info);
952 if (info is CoercionInfo) {
953 assert(CoercionInfo.get(info.node) == null);
954 CoercionInfo.set(info.node, info);
955 }
966 } 956 }
967 } 957 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/checker/rules.dart » ('j') | lib/src/testing.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698