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

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

Issue 1147143007: fixes #206, add checking for unary ops (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: merged 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 | « lib/runtime/dart/math.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »
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 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 bool _failure = false; 341 bool _failure = false;
342 bool get failure => _failure || _overrideChecker._failure; 342 bool get failure => _failure || _overrideChecker._failure;
343 343
344 CodeChecker( 344 CodeChecker(
345 TypeRules rules, CheckerReporter reporter, CompilerOptions options) 345 TypeRules rules, CheckerReporter reporter, CompilerOptions options)
346 : _rules = rules, 346 : _rules = rules,
347 _reporter = reporter, 347 _reporter = reporter,
348 _overrideChecker = new _OverrideChecker(rules, reporter, options); 348 _overrideChecker = new _OverrideChecker(rules, reporter, options);
349 349
350 @override 350 @override
351 visitCompilationUnit(CompilationUnit unit) { 351 void visitCompilationUnit(CompilationUnit unit) {
352 void report(Expression expr) { 352 void report(Expression expr) {
353 _reporter.log(new MissingTypeError(expr)); 353 _reporter.log(new MissingTypeError(expr));
354 } 354 }
355 var callback = _rules.reportMissingType; 355 var callback = _rules.reportMissingType;
356 _rules.reportMissingType = report; 356 _rules.reportMissingType = report;
357 unit.visitChildren(this); 357 unit.visitChildren(this);
358 _rules.reportMissingType = callback; 358 _rules.reportMissingType = callback;
359 } 359 }
360 360
361 _visitMaybeConst(AstNode n, visitNode(AstNode n)) { 361 _visitMaybeConst(AstNode n, visitNode(AstNode n)) {
(...skipping 10 matching lines...) Expand all
372 } else if (n is InstanceCreationExpression) { 372 } else if (n is InstanceCreationExpression) {
373 _constantContext = o || n.isConst; 373 _constantContext = o || n.isConst;
374 } else if (n is ConstructorDeclaration) { 374 } else if (n is ConstructorDeclaration) {
375 _constantContext = o || n.element.isConst; 375 _constantContext = o || n.element.isConst;
376 } 376 }
377 } 377 }
378 visitNode(n); 378 visitNode(n);
379 _constantContext = o; 379 _constantContext = o;
380 } 380 }
381 381
382 visitComment(Comment node) { 382 @override
383 void visitComment(Comment node) {
383 // skip, no need to do typechecking inside comments (they may contain 384 // skip, no need to do typechecking inside comments (they may contain
384 // comment references which would require resolution). 385 // comment references which would require resolution).
385 } 386 }
386 387
387 visitClassDeclaration(ClassDeclaration node) { 388 @override
389 void visitClassDeclaration(ClassDeclaration node) {
388 _overrideChecker.check(node); 390 _overrideChecker.check(node);
389 super.visitClassDeclaration(node); 391 super.visitClassDeclaration(node);
390 } 392 }
391 393
392 visitAssignmentExpression(AssignmentExpression node) { 394 @override
395 void visitAssignmentExpression(AssignmentExpression node) {
393 var token = node.operator; 396 var token = node.operator;
394 if (token.type != TokenType.EQ) { 397 if (token.type != TokenType.EQ) {
395 _checkCompoundAssignment(node); 398 _checkCompoundAssignment(node);
396 } else { 399 } else {
397 DartType staticType = _rules.getStaticType(node.leftHandSide); 400 DartType staticType = _rules.getStaticType(node.leftHandSide);
398 node.rightHandSide = checkAssignment(node.rightHandSide, staticType); 401 node.rightHandSide = checkAssignment(node.rightHandSide, staticType);
399 } 402 }
400 node.visitChildren(this); 403 node.visitChildren(this);
401 } 404 }
402 405
403 /// Check constructor declaration to ensure correct super call placement. 406 /// Check constructor declaration to ensure correct super call placement.
404 @override 407 @override
405 visitConstructorDeclaration(ConstructorDeclaration node) { 408 void visitConstructorDeclaration(ConstructorDeclaration node) {
406 _visitMaybeConst(node, (node) { 409 _visitMaybeConst(node, (node) {
407 node.visitChildren(this); 410 node.visitChildren(this);
408 411
409 final init = node.initializers; 412 final init = node.initializers;
410 for (int i = 0, last = init.length - 1; i < last; i++) { 413 for (int i = 0, last = init.length - 1; i < last; i++) {
411 final node = init[i]; 414 final node = init[i];
412 if (node is SuperConstructorInvocation) { 415 if (node is SuperConstructorInvocation) {
413 _recordMessage(new InvalidSuperInvocation(node)); 416 _recordMessage(new InvalidSuperInvocation(node));
414 } 417 }
415 } 418 }
416 }); 419 });
417 } 420 }
418 421
419 @override 422 @override
420 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { 423 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
421 var field = node.fieldName; 424 var field = node.fieldName;
422 DartType staticType = _rules.elementType(field.staticElement); 425 DartType staticType = _rules.elementType(field.staticElement);
423 node.expression = checkAssignment(node.expression, staticType); 426 node.expression = checkAssignment(node.expression, staticType);
424 node.visitChildren(this); 427 node.visitChildren(this);
425 } 428 }
426 429
427 @override 430 @override
428 visitForEachStatement(ForEachStatement node) { 431 void visitForEachStatement(ForEachStatement node) {
429 // Check that the expression is an Iterable. 432 // Check that the expression is an Iterable.
430 var expr = node.iterable; 433 var expr = node.iterable;
431 var iterableType = _rules.provider.iterableType; 434 var iterableType = _rules.provider.iterableType;
432 var loopVariable = node.identifier != null 435 var loopVariable = node.identifier != null
433 ? node.identifier 436 ? node.identifier
434 : node.loopVariable.identifier; 437 : node.loopVariable.identifier;
435 var iteratorType = loopVariable.staticType; 438 var iteratorType = loopVariable.staticType;
436 var checkedType = iterableType.substitute4([iteratorType]); 439 var checkedType = iterableType.substitute4([iteratorType]);
437 node.iterable = checkAssignment(expr, checkedType); 440 node.iterable = checkAssignment(expr, checkedType);
438 node.visitChildren(this); 441 node.visitChildren(this);
439 } 442 }
440 443
441 @override visitListLiteral(ListLiteral node) { 444 @override
445 void visitForStatement(ForStatement node) {
446 if (node.condition != null) {
447 node.condition = checkBoolean(node.condition);
448 }
449 node.visitChildren(this);
450 }
451
452 @override
453 void visitIfStatement(IfStatement node) {
454 node.condition = checkBoolean(node.condition);
455 node.visitChildren(this);
456 }
457
458 @override
459 void visitDoStatement(DoStatement node) {
460 node.condition = checkBoolean(node.condition);
461 node.visitChildren(this);
462 }
463
464 @override
465 void visitWhileStatement(WhileStatement node) {
466 node.condition = checkBoolean(node.condition);
467 node.visitChildren(this);
468 }
469
470 @override
471 void visitSwitchStatement(SwitchStatement node) {
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
474 // return type from an overridden == operator (because Object.==), so
475 // checking in SwitchStatement shouldn't be necessary.
476 node.visitChildren(this);
477 }
478
479 @override
480 void visitListLiteral(ListLiteral node) {
442 var type = _rules.provider.dynamicType; 481 var type = _rules.provider.dynamicType;
443 if (node.typeArguments != null) { 482 if (node.typeArguments != null) {
444 var targs = node.typeArguments.arguments; 483 var targs = node.typeArguments.arguments;
445 if (targs.length > 0) type = targs[0].type; 484 if (targs.length > 0) type = targs[0].type;
446 } 485 }
447 var elements = node.elements; 486 var elements = node.elements;
448 for (int i = 0; i < elements.length; i++) { 487 for (int i = 0; i < elements.length; i++) {
449 elements[i] = checkArgument(elements[i], type); 488 elements[i] = checkArgument(elements[i], type);
450 } 489 }
451 super.visitListLiteral(node); 490 super.visitListLiteral(node);
452 } 491 }
453 492
454 @override visitMapLiteral(MapLiteral node) { 493 @override
494 void visitMapLiteral(MapLiteral node) {
455 var ktype = _rules.provider.dynamicType; 495 var ktype = _rules.provider.dynamicType;
456 var vtype = _rules.provider.dynamicType; 496 var vtype = _rules.provider.dynamicType;
457 if (node.typeArguments != null) { 497 if (node.typeArguments != null) {
458 var targs = node.typeArguments.arguments; 498 var targs = node.typeArguments.arguments;
459 if (targs.length > 0) ktype = targs[0].type; 499 if (targs.length > 0) ktype = targs[0].type;
460 if (targs.length > 1) vtype = targs[1].type; 500 if (targs.length > 1) vtype = targs[1].type;
461 } 501 }
462 var entries = node.entries; 502 var entries = node.entries;
463 for (int i = 0; i < entries.length; i++) { 503 for (int i = 0; i < entries.length; i++) {
464 var entry = entries[i]; 504 var entry = entries[i];
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 Expression node, Expression f, ArgumentList list) { 546 Expression node, Expression f, ArgumentList list) {
507 if (_rules.isDynamicCall(f)) { 547 if (_rules.isDynamicCall(f)) {
508 // If f is Function and this is a method invocation, we should have 548 // If f is Function and this is a method invocation, we should have
509 // gotten an analyzer error, so no need to issue another error. 549 // gotten an analyzer error, so no need to issue another error.
510 _recordDynamicInvoke(node); 550 _recordDynamicInvoke(node);
511 } else { 551 } else {
512 checkArgumentList(list, _rules.getTypeAsCaller(f)); 552 checkArgumentList(list, _rules.getTypeAsCaller(f));
513 } 553 }
514 } 554 }
515 555
516 visitMethodInvocation(MethodInvocation node) { 556 @override
557 void visitMethodInvocation(MethodInvocation node) {
517 checkFunctionApplication(node, node.methodName, node.argumentList); 558 checkFunctionApplication(node, node.methodName, node.argumentList);
518 node.visitChildren(this); 559 node.visitChildren(this);
519 } 560 }
520 561
521 visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 562 @override
563 void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
522 checkFunctionApplication(node, node.function, node.argumentList); 564 checkFunctionApplication(node, node.function, node.argumentList);
523 node.visitChildren(this); 565 node.visitChildren(this);
524 } 566 }
525 567
526 visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) { 568 @override
569 void visitRedirectingConstructorInvocation(
570 RedirectingConstructorInvocation node) {
527 var type = node.staticElement.type; 571 var type = node.staticElement.type;
528 bool checked = checkArgumentList(node.argumentList, type); 572 bool checked = checkArgumentList(node.argumentList, type);
529 assert(checked); 573 assert(checked);
530 node.visitChildren(this); 574 node.visitChildren(this);
531 } 575 }
532 576
533 visitSuperConstructorInvocation(SuperConstructorInvocation node) { 577 @override
578 void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
534 var element = node.staticElement; 579 var element = node.staticElement;
535 if (element == null) { 580 if (element == null) {
536 _recordMessage(new MissingTypeError(node)); 581 _recordMessage(new MissingTypeError(node));
537 } else { 582 } else {
538 var type = node.staticElement.type; 583 var type = node.staticElement.type;
539 bool checked = checkArgumentList(node.argumentList, type); 584 bool checked = checkArgumentList(node.argumentList, type);
540 assert(checked); 585 assert(checked);
541 } 586 }
542 node.visitChildren(this); 587 node.visitChildren(this);
543 } 588 }
(...skipping 17 matching lines...) Expand all
561 } 606 }
562 } 607 }
563 608
564 Expression _checkReturn(Expression expression, AstNode node) { 609 Expression _checkReturn(Expression expression, AstNode node) {
565 var type = _getFunctionType(_getOwnerFunction(node)).returnType; 610 var type = _getFunctionType(_getOwnerFunction(node)).returnType;
566 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null. 611 // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
567 if (expression == null) return null; 612 if (expression == null) return null;
568 return checkAssignment(expression, type); 613 return checkAssignment(expression, type);
569 } 614 }
570 615
571 visitExpressionFunctionBody(ExpressionFunctionBody node) { 616 @override
617 void visitExpressionFunctionBody(ExpressionFunctionBody node) {
572 node.expression = _checkReturn(node.expression, node); 618 node.expression = _checkReturn(node.expression, node);
573 node.visitChildren(this); 619 node.visitChildren(this);
574 } 620 }
575 621
576 visitReturnStatement(ReturnStatement node) { 622 @override
623 void visitReturnStatement(ReturnStatement node) {
577 node.expression = _checkReturn(node.expression, node); 624 node.expression = _checkReturn(node.expression, node);
578 node.visitChildren(this); 625 node.visitChildren(this);
579 } 626 }
580 627
581 visitPropertyAccess(PropertyAccess node) { 628 @override
629 void visitPropertyAccess(PropertyAccess node) {
582 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) { 630 if (node.staticType.isDynamic && _rules.isDynamicTarget(node.realTarget)) {
583 _recordDynamicInvoke(node); 631 _recordDynamicInvoke(node);
584 } 632 }
585 node.visitChildren(this); 633 node.visitChildren(this);
586 } 634 }
587 635
588 visitPrefixedIdentifier(PrefixedIdentifier node) { 636 @override
637 void visitPrefixedIdentifier(PrefixedIdentifier node) {
589 final target = node.prefix; 638 final target = node.prefix;
590 if (_rules.isDynamicTarget(target)) { 639 if (_rules.isDynamicTarget(target)) {
591 _recordDynamicInvoke(node); 640 _recordDynamicInvoke(node);
592 } 641 }
593 node.visitChildren(this); 642 node.visitChildren(this);
594 } 643 }
595 644
596 @override visitDefaultFormalParameter(DefaultFormalParameter node) { 645 @override
646 void visitDefaultFormalParameter(DefaultFormalParameter node) {
597 _visitMaybeConst(node, (node) { 647 _visitMaybeConst(node, (node) {
598 // Check that defaults have the proper subtype. 648 // Check that defaults have the proper subtype.
599 var parameter = node.parameter; 649 var parameter = node.parameter;
600 var parameterType = _rules.elementType(parameter.element); 650 var parameterType = _rules.elementType(parameter.element);
601 assert(parameterType != null); 651 assert(parameterType != null);
602 var defaultValue = node.defaultValue; 652 var defaultValue = node.defaultValue;
603 if (defaultValue == null) { 653 if (defaultValue == null) {
604 if (_rules.maybeNonNullableType(parameterType)) { 654 if (_rules.maybeNonNullableType(parameterType)) {
605 var staticInfo = new InvalidVariableDeclaration( 655 var staticInfo = new InvalidVariableDeclaration(
606 _rules, node.identifier, parameterType); 656 _rules, node.identifier, parameterType);
607 _recordMessage(staticInfo); 657 _recordMessage(staticInfo);
608 } 658 }
609 } else { 659 } else {
610 var staticInfo = checkAssignment(defaultValue, parameterType); 660 var staticInfo = checkAssignment(defaultValue, parameterType);
611 if (staticInfo is! StaticError) node.defaultValue = staticInfo; 661 if (staticInfo is! StaticError) node.defaultValue = staticInfo;
612 } 662 }
613 663
614 node.visitChildren(this); 664 node.visitChildren(this);
615 }); 665 });
616 } 666 }
617 667
618 visitFieldFormalParameter(FieldFormalParameter node) { 668 @override
669 void visitFieldFormalParameter(FieldFormalParameter node) {
619 var element = node.element; 670 var element = node.element;
620 var typeName = node.type; 671 var typeName = node.type;
621 if (typeName != null) { 672 if (typeName != null) {
622 var type = _rules.elementType(element); 673 var type = _rules.elementType(element);
623 var fieldElement = 674 var fieldElement =
624 node.identifier.staticElement as FieldFormalParameterElement; 675 node.identifier.staticElement as FieldFormalParameterElement;
625 var fieldType = _rules.elementType(fieldElement.field); 676 var fieldType = _rules.elementType(fieldElement.field);
626 if (!_rules.isSubTypeOf(type, fieldType)) { 677 if (!_rules.isSubTypeOf(type, fieldType)) {
627 var staticInfo = 678 var staticInfo =
628 new InvalidParameterDeclaration(_rules, node, fieldType); 679 new InvalidParameterDeclaration(_rules, node, fieldType);
629 _recordMessage(staticInfo); 680 _recordMessage(staticInfo);
630 } 681 }
631 } 682 }
632 node.visitChildren(this); 683 node.visitChildren(this);
633 } 684 }
634 685
635 @override 686 @override
636 visitInstanceCreationExpression(InstanceCreationExpression node) { 687 void visitInstanceCreationExpression(InstanceCreationExpression node) {
637 _visitMaybeConst(node, (node) { 688 _visitMaybeConst(node, (node) {
638 var arguments = node.argumentList; 689 var arguments = node.argumentList;
639 var element = node.staticElement; 690 var element = node.staticElement;
640 if (element != null) { 691 if (element != null) {
641 var type = _rules.elementType(node.staticElement); 692 var type = _rules.elementType(node.staticElement);
642 checkArgumentList(arguments, type); 693 checkArgumentList(arguments, type);
643 } else { 694 } else {
644 _recordMessage(new MissingTypeError(node)); 695 _recordMessage(new MissingTypeError(node));
645 } 696 }
646 node.visitChildren(this); 697 node.visitChildren(this);
647 }); 698 });
648 } 699 }
649 700
650 @override 701 @override
651 visitVariableDeclarationList(VariableDeclarationList node) { 702 void visitVariableDeclarationList(VariableDeclarationList node) {
652 _visitMaybeConst(node, (node) { 703 _visitMaybeConst(node, (node) {
653 TypeName type = node.type; 704 TypeName type = node.type;
654 if (type == null) { 705 if (type == null) {
655 // No checks are needed when the type is var. Although internally the 706 // No checks are needed when the type is var. Although internally the
656 // typing rules may have inferred a more precise type for the variable 707 // typing rules may have inferred a more precise type for the variable
657 // based on the initializer. 708 // based on the initializer.
658 } else { 709 } else {
659 var dartType = getType(type); 710 var dartType = getType(type);
660 for (VariableDeclaration variable in node.variables) { 711 for (VariableDeclaration variable in node.variables) {
661 var initializer = variable.initializer; 712 var initializer = variable.initializer;
(...skipping 13 matching lines...) Expand all
675 _recordMessage(staticInfo); 726 _recordMessage(staticInfo);
676 } 727 }
677 } 728 }
678 } 729 }
679 } 730 }
680 node.visitChildren(this); 731 node.visitChildren(this);
681 }); 732 });
682 } 733 }
683 734
684 @override 735 @override
685 visitVariableDeclaration(VariableDeclaration node) { 736 void visitVariableDeclaration(VariableDeclaration node) {
686 _visitMaybeConst(node, super.visitVariableDeclaration); 737 _visitMaybeConst(node, super.visitVariableDeclaration);
687 } 738 }
688 739
689 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) { 740 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
690 var type = getType(typeName); 741 var type = getType(typeName);
691 if (!_rules.isGroundType(type)) { 742 if (!_rules.isGroundType(type)) {
692 _recordMessage(new InvalidRuntimeCheckError(node, type)); 743 _recordMessage(new InvalidRuntimeCheckError(node, type));
693 } 744 }
694 } 745 }
695 746
696 visitAsExpression(AsExpression node) { 747 @override
748 void visitAsExpression(AsExpression node) {
697 // We could do the same check as the IsExpression below, but that is 749 // We could do the same check as the IsExpression below, but that is
698 // potentially too conservative. Instead, at runtime, we must fail hard 750 // potentially too conservative. Instead, at runtime, we must fail hard
699 // if the Dart as and the DDC as would return different values. 751 // if the Dart as and the DDC as would return different values.
700 node.visitChildren(this); 752 node.visitChildren(this);
701 } 753 }
702 754
703 visitIsExpression(IsExpression node) { 755 @override
756 void visitIsExpression(IsExpression node) {
704 _checkRuntimeTypeCheck(node, node.type); 757 _checkRuntimeTypeCheck(node, node.type);
705 node.visitChildren(this); 758 node.visitChildren(this);
706 } 759 }
707 760
708 visitBinaryExpression(BinaryExpression node) { 761 @override
762 void visitPrefixExpression(PrefixExpression node) {
763 if (node.operator.type == TokenType.BANG) {
764 node.operand = checkBoolean(node.operand);
765 } else {
766 _checkUnary(node);
767 }
768 node.visitChildren(this);
769 }
770
771 @override
772 void visitPostfixExpression(PostfixExpression node) {
773 _checkUnary(node);
774 node.visitChildren(this);
775 }
776
777 void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) {
778 var op = node.operator;
779 if (op.isUserDefinableOperator ||
780 op.type == TokenType.PLUS_PLUS ||
781 op.type == TokenType.MINUS_MINUS) {
782 if (_rules.isDynamicTarget(node.operand)) {
783 _recordDynamicInvoke(node);
784 }
785 // For ++ and --, even if it is not dynamic, we still need to check
786 // that the user defined method accepts an `int` as the RHS.
787 // We assume Analyzer has done this already.
788 }
789 }
790
791 @override
792 void visitBinaryExpression(BinaryExpression node) {
709 var op = node.operator; 793 var op = node.operator;
710 if (op.isUserDefinableOperator) { 794 if (op.isUserDefinableOperator) {
711 if (_rules.isDynamicTarget(node.leftOperand)) { 795 if (_rules.isDynamicTarget(node.leftOperand)) {
712 // Dynamic invocation 796 // Dynamic invocation
713 // TODO(vsm): Move this logic to the resolver? 797 // TODO(vsm): Move this logic to the resolver?
714 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) { 798 if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
715 _recordDynamicInvoke(node); 799 _recordDynamicInvoke(node);
716 } 800 }
717 } else { 801 } else {
718 var element = node.staticElement; 802 var element = node.staticElement;
719 // Method invocation. 803 // Method invocation.
720 if (element is MethodElement) { 804 if (element is MethodElement) {
721 var type = element.type as FunctionType; 805 var type = element.type as FunctionType;
722 // Analyzer should enforce number of parameter types, but check in 806 // Analyzer should enforce number of parameter types, but check in
723 // case we have erroneous input. 807 // case we have erroneous input.
724 if (type.normalParameterTypes.isNotEmpty) { 808 if (type.normalParameterTypes.isNotEmpty) {
725 node.rightOperand = 809 node.rightOperand =
726 checkArgument(node.rightOperand, type.normalParameterTypes[0]); 810 checkArgument(node.rightOperand, type.normalParameterTypes[0]);
727 } 811 }
728 } else { 812 } else {
729 // TODO(vsm): Assert that the analyzer found an error here? 813 // TODO(vsm): Assert that the analyzer found an error here?
730 } 814 }
731 } 815 }
732 } else { 816 } else {
733 // Non-method operator. 817 // Non-method operator.
734 switch (op.type) { 818 switch (op.type) {
735 case TokenType.AMPERSAND_AMPERSAND: 819 case TokenType.AMPERSAND_AMPERSAND:
736 case TokenType.BAR_BAR: 820 case TokenType.BAR_BAR:
737 var boolType = _rules.provider.boolType; 821 node.leftOperand = checkBoolean(node.leftOperand);
738 node.leftOperand = checkArgument(node.leftOperand, boolType); 822 node.rightOperand = checkBoolean(node.rightOperand);
739 node.rightOperand = checkArgument(node.rightOperand, boolType);
740 break; 823 break;
741 case TokenType.BANG_EQ: 824 case TokenType.BANG_EQ:
742 break; 825 break;
743 default: 826 default:
744 assert(false); 827 assert(false);
745 } 828 }
746 } 829 }
747 node.visitChildren(this); 830 node.visitChildren(this);
748 } 831 }
749 832
750 @override 833 @override
834 void visitConditionalExpression(ConditionalExpression node) {
835 node.condition = checkBoolean(node.condition);
836 node.visitChildren(this);
837 }
838
839 @override
751 void visitIndexExpression(IndexExpression node) { 840 void visitIndexExpression(IndexExpression node) {
752 if (_rules.isDynamicTarget(node.target)) { 841 if (_rules.isDynamicTarget(node.target)) {
753 _recordDynamicInvoke(node); 842 _recordDynamicInvoke(node);
754 } else { 843 } else {
755 var element = node.staticElement; 844 var element = node.staticElement;
756 if (element is MethodElement) { 845 if (element is MethodElement) {
757 var type = element.type as FunctionType; 846 var type = element.type as FunctionType;
758 // Analyzer should enforce number of parameter types, but check in 847 // Analyzer should enforce number of parameter types, but check in
759 // case we have erroneous input. 848 // case we have erroneous input.
760 if (type.normalParameterTypes.isNotEmpty) { 849 if (type.normalParameterTypes.isNotEmpty) {
761 node.index = checkArgument(node.index, type.normalParameterTypes[0]); 850 node.index = checkArgument(node.index, type.normalParameterTypes[0]);
762 } 851 }
763 } else { 852 } else {
764 // TODO(vsm): Assert that the analyzer found an error here? 853 // TODO(vsm): Assert that the analyzer found an error here?
765 } 854 }
766 } 855 }
767 node.visitChildren(this); 856 node.visitChildren(this);
768 } 857 }
769 858
770 DartType getType(TypeName name) { 859 DartType getType(TypeName name) {
771 return (name == null) ? _rules.provider.dynamicType : name.type; 860 return (name == null) ? _rules.provider.dynamicType : name.type;
772 } 861 }
773 862
863 /// Analyzer checks boolean conversions, but we need to check too, because
864 /// it uses the default assignability rules that allow `dynamic` and `Object`
865 /// to be assigned to bool with no message.
866 Expression checkBoolean(Expression expr) =>
867 checkAssignment(expr, _rules.provider.boolType);
868
774 Expression checkAssignment(Expression expr, DartType type) { 869 Expression checkAssignment(Expression expr, DartType type) {
775 if (expr is ParenthesizedExpression) { 870 if (expr is ParenthesizedExpression) {
776 expr.expression = checkAssignment(expr.expression, type); 871 expr.expression = checkAssignment(expr.expression, type);
777 } else { 872 } else {
778 final staticInfo = _rules.checkAssignment(expr, type, _constantContext); 873 final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
779 _recordMessage(staticInfo); 874 _recordMessage(staticInfo);
780 if (staticInfo is Conversion) expr = staticInfo; 875 if (staticInfo is Conversion) expr = staticInfo;
781 } 876 }
782 return expr; 877 return expr;
783 } 878 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 void _recordDynamicInvoke(AstNode node) { 958 void _recordDynamicInvoke(AstNode node) {
864 _reporter.log(new DynamicInvoke(_rules, node)); 959 _reporter.log(new DynamicInvoke(_rules, node));
865 } 960 }
866 961
867 void _recordMessage(StaticInfo info) { 962 void _recordMessage(StaticInfo info) {
868 if (info == null) return; 963 if (info == null) return;
869 if (info.level >= logger.Level.SEVERE) _failure = true; 964 if (info.level >= logger.Level.SEVERE) _failure = true;
870 _reporter.log(info); 965 _reporter.log(info);
871 } 966 }
872 } 967 }
OLDNEW
« no previous file with comments | « lib/runtime/dart/math.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698