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

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

Issue 957013002: Typecheck map and list literals (Closed) Base URL: git@github.com:dart-lang/dart-dev-compiler.git@master
Patch Set: Rebase Created 5 years, 9 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') | 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 ddc.src.checker.checker; 5 library ddc.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 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 if (info.level >= logger.Level.SEVERE) _failure = true; 330 if (info.level >= logger.Level.SEVERE) _failure = true;
331 _reporter.log(info); 331 _reporter.log(info);
332 } 332 }
333 } 333 }
334 334
335 /// Checks the body of functions and properties. 335 /// Checks the body of functions and properties.
336 class CodeChecker extends RecursiveAstVisitor { 336 class CodeChecker extends RecursiveAstVisitor {
337 final TypeRules _rules; 337 final TypeRules _rules;
338 final CheckerReporter _reporter; 338 final CheckerReporter _reporter;
339 final _OverrideChecker _overrideChecker; 339 final _OverrideChecker _overrideChecker;
340 bool _constantContext = false;
340 bool _failure = false; 341 bool _failure = false;
341 bool get failure => _failure || _overrideChecker._failure; 342 bool get failure => _failure || _overrideChecker._failure;
342 343
343 CodeChecker( 344 CodeChecker(
344 TypeRules rules, CheckerReporter reporter, CompilerOptions options) 345 TypeRules rules, CheckerReporter reporter, CompilerOptions options)
345 : _rules = rules, 346 : _rules = rules,
346 _reporter = reporter, 347 _reporter = reporter,
347 _overrideChecker = new _OverrideChecker(rules, reporter, options); 348 _overrideChecker = new _OverrideChecker(rules, reporter, options);
348 349
350 _visitMaybeConst(AstNode n, visitNode(AstNode n)) {
351 var o = _constantContext;
352 if (!o) {
353 if (n is VariableDeclarationList) {
354 _constantContext = o || n.isConst;
355 } else if (n is VariableDeclaration) {
356 _constantContext = o || n.isConst;
357 } else if (n is FormalParameter) {
358 _constantContext = o || n.isConst;
359 } else if (n is InstanceCreationExpression) {
360 _constantContext = o || n.isConst;
361 } else if (n is ConstructorDeclaration) {
362 _constantContext = o || n.element.isConst;
363 }
364 }
365 visitNode(n);
366 _constantContext = o;
367 }
368
349 visitComment(Comment node) { 369 visitComment(Comment node) {
350 // skip, no need to do typechecking inside comments (they may contain 370 // skip, no need to do typechecking inside comments (they may contain
351 // comment references which would require resolution). 371 // comment references which would require resolution).
352 } 372 }
353 373
354 visitClassDeclaration(ClassDeclaration node) { 374 visitClassDeclaration(ClassDeclaration node) {
355 _overrideChecker.check(node); 375 _overrideChecker.check(node);
356 super.visitClassDeclaration(node); 376 super.visitClassDeclaration(node);
357 } 377 }
358 378
359 visitAssignmentExpression(AssignmentExpression node) { 379 visitAssignmentExpression(AssignmentExpression node) {
360 var token = node.operator; 380 var token = node.operator;
361 if (token.type != TokenType.EQ) { 381 if (token.type != TokenType.EQ) {
362 _checkCompoundAssignment(node); 382 _checkCompoundAssignment(node);
363 } else { 383 } else {
364 DartType staticType = _rules.getStaticType(node.leftHandSide); 384 DartType staticType = _rules.getStaticType(node.leftHandSide);
365 node.rightHandSide = checkAssignment(node.rightHandSide, staticType); 385 node.rightHandSide = checkAssignment(node.rightHandSide, staticType);
366 } 386 }
367 node.visitChildren(this); 387 node.visitChildren(this);
368 } 388 }
369 389
370 /// Check constructor declaration to ensure correct super call placement. 390 /// Check constructor declaration to ensure correct super call placement.
371 @override 391 @override
372 visitConstructorDeclaration(ConstructorDeclaration node) { 392 visitConstructorDeclaration(ConstructorDeclaration node) {
373 node.visitChildren(this); 393 _visitMaybeConst(node, (node) {
394 node.visitChildren(this);
374 395
375 final init = node.initializers; 396 final init = node.initializers;
376 for (int i = 0, last = init.length - 1; i < last; i++) { 397 for (int i = 0, last = init.length - 1; i < last; i++) {
377 final node = init[i]; 398 final node = init[i];
378 if (node is SuperConstructorInvocation) { 399 if (node is SuperConstructorInvocation) {
379 _recordMessage(new InvalidSuperInvocation(node)); 400 _recordMessage(new InvalidSuperInvocation(node));
401 }
380 } 402 }
381 } 403 });
382 } 404 }
383 405
384 @override 406 @override
385 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { 407 visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
386 var field = node.fieldName; 408 var field = node.fieldName;
387 DartType staticType = _rules.elementType(field.staticElement); 409 DartType staticType = _rules.elementType(field.staticElement);
388 node.expression = checkAssignment(node.expression, staticType); 410 node.expression = checkAssignment(node.expression, staticType);
389 node.visitChildren(this); 411 node.visitChildren(this);
390 } 412 }
391 413
414 @override visitListLiteral(ListLiteral node) {
415 var type = _rules.provider.dynamicType;
416 if (node.typeArguments != null) {
417 var targs = node.typeArguments.arguments;
418 if (targs.length > 0) type = targs[0].type;
419 }
420 var elements = node.elements;
421 for (int i = 0; i < elements.length; i++) {
422 elements[i] = checkArgument(elements[i], type);
423 }
424 super.visitListLiteral(node);
425 }
426
427 @override visitMapLiteral(MapLiteral node) {
428 var ktype = _rules.provider.dynamicType;
429 var vtype = _rules.provider.dynamicType;
430 if (node.typeArguments != null) {
431 var targs = node.typeArguments.arguments;
432 if (targs.length > 0) ktype = targs[0].type;
433 if (targs.length > 1) vtype = targs[1].type;
434 }
435 var entries = node.entries;
436 for (int i = 0; i < entries.length; i++) {
437 var entry = entries[i];
438 entry.key = checkArgument(entry.key, ktype);
439 entry.value = checkArgument(entry.value, vtype);
440 }
441 super.visitMapLiteral(node);
442 }
443
392 // Check invocations 444 // Check invocations
393 bool checkArgumentList(ArgumentList node, FunctionType type) { 445 bool checkArgumentList(ArgumentList node, FunctionType type) {
394 NodeList<Expression> list = node.arguments; 446 NodeList<Expression> list = node.arguments;
395 int len = list.length; 447 int len = list.length;
396 for (int i = 0; i < len; ++i) { 448 for (int i = 0; i < len; ++i) {
397 Expression arg = list[i]; 449 Expression arg = list[i];
398 ParameterElement element = node.getStaticParameterElementFor(arg); 450 ParameterElement element = node.getStaticParameterElementFor(arg);
399 if (element == null) { 451 if (element == null) {
400 if (type.parameters.length < len) { 452 if (type.parameters.length < len) {
401 // We found an argument mismatch, the analyzer will report this too, 453 // We found an argument mismatch, the analyzer will report this too,
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 visitPrefixedIdentifier(PrefixedIdentifier node) { 561 visitPrefixedIdentifier(PrefixedIdentifier node) {
510 final target = node.prefix; 562 final target = node.prefix;
511 // Check if the prefix is a library - PrefixElement denotes a library 563 // Check if the prefix is a library - PrefixElement denotes a library
512 // access. 564 // access.
513 if (target.staticElement is! PrefixElement && _rules.isDynamicGet(target)) { 565 if (target.staticElement is! PrefixElement && _rules.isDynamicGet(target)) {
514 _recordDynamicInvoke(node); 566 _recordDynamicInvoke(node);
515 } 567 }
516 node.visitChildren(this); 568 node.visitChildren(this);
517 } 569 }
518 570
519 visitDefaultFormalParameter(DefaultFormalParameter node) { 571 @override visitDefaultFormalParameter(DefaultFormalParameter node) {
520 // Check that defaults have the proper subtype. 572 _visitMaybeConst(node, (node) {
521 var parameter = node.parameter; 573 // Check that defaults have the proper subtype.
522 var parameterType = _rules.elementType(parameter.element); 574 var parameter = node.parameter;
523 assert(parameterType != null); 575 var parameterType = _rules.elementType(parameter.element);
524 var defaultValue = node.defaultValue; 576 assert(parameterType != null);
525 var defaultType; 577 var defaultValue = node.defaultValue;
526 if (defaultValue == null) { 578 var defaultType;
527 // TODO(vsm): Should this be null? 579 if (defaultValue == null) {
528 defaultType = _rules.provider.bottomType; 580 // TODO(vsm): Should this be null?
529 } else { 581 defaultType = _rules.provider.bottomType;
530 defaultType = _rules.getStaticType(defaultValue); 582 } else {
531 } 583 defaultType = _rules.getStaticType(defaultValue);
584 }
532 585
533 // If defaultType is bottom, this enforces that parameterType is not 586 // If defaultType is bottom, this enforces that parameterType is not
534 // non-nullable. 587 // non-nullable.
535 if (!_rules.isSubTypeOf(defaultType, parameterType)) { 588 if (!_rules.isSubTypeOf(defaultType, parameterType)) {
536 var staticInfo = (defaultValue == null) 589 var staticInfo = (defaultValue == null)
537 ? new InvalidVariableDeclaration( 590 ? new InvalidVariableDeclaration(
538 _rules, node.identifier, parameterType) 591 _rules, node.identifier, parameterType)
539 : new StaticTypeError(_rules, defaultValue, parameterType); 592 : new StaticTypeError(_rules, defaultValue, parameterType);
540 _recordMessage(staticInfo); 593 _recordMessage(staticInfo);
541 } 594 }
542 node.visitChildren(this); 595 node.visitChildren(this);
596 });
543 } 597 }
544 598
545 visitFieldFormalParameter(FieldFormalParameter node) { 599 visitFieldFormalParameter(FieldFormalParameter node) {
546 var element = node.element; 600 var element = node.element;
547 var typeName = node.type; 601 var typeName = node.type;
548 if (typeName != null) { 602 if (typeName != null) {
549 var type = _rules.elementType(element); 603 var type = _rules.elementType(element);
550 var fieldElement = 604 var fieldElement =
551 node.identifier.staticElement as FieldFormalParameterElement; 605 node.identifier.staticElement as FieldFormalParameterElement;
552 var fieldType = _rules.elementType(fieldElement.field); 606 var fieldType = _rules.elementType(fieldElement.field);
553 if (!_rules.isSubTypeOf(type, fieldType)) { 607 if (!_rules.isSubTypeOf(type, fieldType)) {
554 var staticInfo = 608 var staticInfo =
555 new InvalidParameterDeclaration(_rules, node, fieldType); 609 new InvalidParameterDeclaration(_rules, node, fieldType);
556 _recordMessage(staticInfo); 610 _recordMessage(staticInfo);
557 } 611 }
558 } 612 }
559 node.visitChildren(this); 613 node.visitChildren(this);
560 } 614 }
561 615
562 @override 616 @override
563 visitInstanceCreationExpression(InstanceCreationExpression node) { 617 visitInstanceCreationExpression(InstanceCreationExpression node) {
564 var arguments = node.argumentList; 618 _visitMaybeConst(node, (node) {
565 var element = node.staticElement; 619 var arguments = node.argumentList;
566 if (element != null) { 620 var element = node.staticElement;
567 var type = _rules.elementType(node.staticElement); 621 if (element != null) {
568 checkArgumentList(arguments, type); 622 var type = _rules.elementType(node.staticElement);
569 } else { 623 checkArgumentList(arguments, type);
570 _recordMessage(new MissingTypeError(node)); 624 } else {
571 } 625 _recordMessage(new MissingTypeError(node));
572 node.visitChildren(this); 626 }
627 node.visitChildren(this);
628 });
573 } 629 }
574 630
575 @override 631 @override
576 visitVariableDeclarationList(VariableDeclarationList node) { 632 visitVariableDeclarationList(VariableDeclarationList node) {
577 TypeName type = node.type; 633 _visitMaybeConst(node, (node) {
578 if (type == null) { 634 TypeName type = node.type;
579 // No checks are needed when the type is var. Although internally the 635 if (type == null) {
580 // typing rules may have inferred a more precise type for the variable 636 // No checks are needed when the type is var. Although internally the
581 // based on the initializer. 637 // typing rules may have inferred a more precise type for the variable
582 } else { 638 // based on the initializer.
583 var dartType = getType(type); 639 } else {
584 for (VariableDeclaration variable in node.variables) { 640 var dartType = getType(type);
585 var initializer = variable.initializer; 641 for (VariableDeclaration variable in node.variables) {
586 if (initializer != null) { 642 var initializer = variable.initializer;
587 variable.initializer = checkAssignment(initializer, dartType); 643 if (initializer != null) {
588 } else if (_rules.maybeNonNullableType(dartType)) { 644 variable.initializer = checkAssignment(initializer, dartType);
589 var element = variable.element; 645 } else if (_rules.maybeNonNullableType(dartType)) {
590 if (element is FieldElement && !element.isStatic) { 646 var element = variable.element;
591 // Initialized - possibly implicitly - during construction. 647 if (element is FieldElement && !element.isStatic) {
592 // Handle this via a runtime check during code generation. 648 // Initialized - possibly implicitly - during construction.
649 // Handle this via a runtime check during code generation.
593 650
594 // TODO(vsm): Detect statically whether this can fail and 651 // TODO(vsm): Detect statically whether this can fail and
595 // report a static error (must fail) or warning (can fail). 652 // report a static error (must fail) or warning (can fail).
596 } else { 653 } else {
597 var staticInfo = 654 var staticInfo =
598 new InvalidVariableDeclaration(_rules, variable, dartType); 655 new InvalidVariableDeclaration(_rules, variable, dartType);
599 _recordMessage(staticInfo); 656 _recordMessage(staticInfo);
657 }
600 } 658 }
601 } 659 }
602 } 660 }
603 } 661 node.visitChildren(this);
604 node.visitChildren(this); 662 });
663 }
664
665 @override
666 visitVariableDeclaration(VariableDeclaration node) {
667 _visitMaybeConst(node, super.visitVariableDeclaration);
605 } 668 }
606 669
607 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) { 670 void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
608 var type = getType(typeName); 671 var type = getType(typeName);
609 if (!_rules.isGroundType(type)) { 672 if (!_rules.isGroundType(type)) {
610 _recordMessage(new InvalidRuntimeCheckError(node, type)); 673 _recordMessage(new InvalidRuntimeCheckError(node, type));
611 } 674 }
612 } 675 }
613 676
614 visitAsExpression(AsExpression node) { 677 visitAsExpression(AsExpression node) {
615 node.visitChildren(this); 678 node.visitChildren(this);
616 } 679 }
617 680
618 visitIsExpression(IsExpression node) { 681 visitIsExpression(IsExpression node) {
619 _checkRuntimeTypeCheck(node, node.type); 682 _checkRuntimeTypeCheck(node, node.type);
620 node.visitChildren(this); 683 node.visitChildren(this);
621 } 684 }
622 685
623 DartType getType(TypeName name) { 686 DartType getType(TypeName name) {
624 return (name == null) ? _rules.provider.dynamicType : name.type; 687 return (name == null) ? _rules.provider.dynamicType : name.type;
625 } 688 }
626 689
627 Expression checkAssignment(Expression expr, DartType type) { 690 Expression checkAssignment(Expression expr, DartType type) {
628 final staticInfo = _rules.checkAssignment(expr, type); 691 final staticInfo = _rules.checkAssignment(expr, type, _constantContext);
629 _recordMessage(staticInfo); 692 _recordMessage(staticInfo);
630 if (staticInfo is Conversion) expr = staticInfo; 693 if (staticInfo is Conversion) expr = staticInfo;
631 return expr; 694 return expr;
632 } 695 }
633 696
634 DartType _specializedBinaryReturnType( 697 DartType _specializedBinaryReturnType(
635 TokenType op, DartType t1, DartType t2, DartType normalReturnType) { 698 TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
636 // This special cases binary return types as per 16.26 and 16.27 of the 699 // This special cases binary return types as per 16.26 and 16.27 of the
637 // Dart language spec. 700 // Dart language spec.
638 switch (op) { 701 switch (op) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 } else { 755 } else {
693 // Static type error 756 // Static type error
694 staticInfo = new StaticTypeError(_rules, expr, lhsType); 757 staticInfo = new StaticTypeError(_rules, expr, lhsType);
695 } 758 }
696 _recordMessage(staticInfo); 759 _recordMessage(staticInfo);
697 } 760 }
698 761
699 // Check the rhs type 762 // Check the rhs type
700 if (staticInfo is! Conversion) { 763 if (staticInfo is! Conversion) {
701 var paramType = paramTypes.first; 764 var paramType = paramTypes.first;
702 staticInfo = _rules.checkAssignment(expr.rightHandSide, paramType); 765 staticInfo = _rules.checkAssignment(
766 expr.rightHandSide, paramType, _constantContext);
703 _recordMessage(staticInfo); 767 _recordMessage(staticInfo);
704 if (staticInfo is Conversion) expr.rightHandSide = staticInfo; 768 if (staticInfo is Conversion) expr.rightHandSide = staticInfo;
705 } 769 }
706 } 770 }
707 } 771 }
708 772
709 void _recordDynamicInvoke(AstNode node) { 773 void _recordDynamicInvoke(AstNode node) {
710 _reporter.log(new DynamicInvoke(_rules, node)); 774 _reporter.log(new DynamicInvoke(_rules, node));
711 } 775 }
712 776
713 void _recordMessage(StaticInfo info) { 777 void _recordMessage(StaticInfo info) {
714 if (info == null) return; 778 if (info == null) return;
715 if (info.level >= logger.Level.SEVERE) _failure = true; 779 if (info.level >= logger.Level.SEVERE) _failure = true;
716 _reporter.log(info); 780 _reporter.log(info);
717 } 781 }
718 } 782 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/checker/rules.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698