| OLD | NEW |
| 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.rules; | 5 library dev_compiler.src.checker.rules; |
| 6 | 6 |
| 7 import 'package:analyzer/src/generated/ast.dart'; | 7 import 'package:analyzer/src/generated/ast.dart'; |
| 8 import 'package:analyzer/src/generated/element.dart'; | 8 import 'package:analyzer/src/generated/element.dart'; |
| 9 import 'package:analyzer/src/generated/resolver.dart'; | 9 import 'package:analyzer/src/generated/resolver.dart'; |
| 10 | 10 |
| (...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 return Coercion.cast(fromT, toT); | 486 return Coercion.cast(fromT, toT); |
| 487 } | 487 } |
| 488 return Coercion.error(); | 488 return Coercion.error(); |
| 489 } | 489 } |
| 490 | 490 |
| 491 StaticInfo checkAssignment(Expression expr, DartType toT, bool constContext) { | 491 StaticInfo checkAssignment(Expression expr, DartType toT, bool constContext) { |
| 492 final fromT = getStaticType(expr); | 492 final fromT = getStaticType(expr); |
| 493 final Coercion c = _coerceTo(fromT, toT, options.wrapClosures); | 493 final Coercion c = _coerceTo(fromT, toT, options.wrapClosures); |
| 494 if (c is Identity) return null; | 494 if (c is Identity) return null; |
| 495 if (c is CoercionError) return new StaticTypeError(this, expr, toT); | 495 if (c is CoercionError) return new StaticTypeError(this, expr, toT); |
| 496 if (options.inferDownwards && inferrer.inferExpression(expr, toT)) { | 496 var reason = null; |
| 497 return InferredType.create(this, expr, toT); | 497 if (options.inferDownwards) { |
| 498 var errors = <String>[]; |
| 499 var ok = inferrer.inferExpression(expr, toT, errors); |
| 500 if (ok) return InferredType.create(this, expr, toT); |
| 501 reason = (errors.isNotEmpty) ? errors.first : null; |
| 498 } | 502 } |
| 499 if (constContext && !options.allowConstCasts) { | 503 if (constContext && !options.allowConstCasts) { |
| 500 return new StaticTypeError(this, expr, toT); | 504 reason = (reason == null) ? "Cast not allowed in const context" : reason; |
| 505 return new StaticTypeError(this, expr, toT, reason: reason); |
| 501 } | 506 } |
| 502 if (c is Cast) return DownCast.create(this, expr, c); | 507 if (c is Cast) return DownCast.create(this, expr, c, reason: reason); |
| 503 if (c is Wrapper) return ClosureWrap.create(this, expr, c, toT); | 508 if (c is Wrapper) return ClosureWrap.create(this, expr, c, toT); |
| 504 assert(false); | 509 assert(false); |
| 505 return null; | 510 return null; |
| 506 } | 511 } |
| 507 | 512 |
| 508 DartType elementType(Element e) { | 513 DartType elementType(Element e) { |
| 509 return (e as dynamic).type; | 514 return (e as dynamic).type; |
| 510 } | 515 } |
| 511 | 516 |
| 512 bool isDynamic(DartType t) => options.ignoreTypes || t.isDynamic; | 517 bool isDynamic(DartType t) => options.ignoreTypes || t.isDynamic; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 void annotateListLiteral(ListLiteral e, List<DartType> targs) {} | 565 void annotateListLiteral(ListLiteral e, List<DartType> targs) {} |
| 561 | 566 |
| 562 /// Called for each map literal which gets inferred | 567 /// Called for each map literal which gets inferred |
| 563 void annotateMapLiteral(MapLiteral e, List<DartType> targs) {} | 568 void annotateMapLiteral(MapLiteral e, List<DartType> targs) {} |
| 564 | 569 |
| 565 /// Called for each new/const which gets inferred | 570 /// Called for each new/const which gets inferred |
| 566 void annotateInstanceCreationExpression( | 571 void annotateInstanceCreationExpression( |
| 567 InstanceCreationExpression e, List<DartType> targs) {} | 572 InstanceCreationExpression e, List<DartType> targs) {} |
| 568 | 573 |
| 569 /// Downward inference | 574 /// Downward inference |
| 570 bool inferExpression(Expression e, DartType t) { | 575 bool inferExpression(Expression e, DartType t, List<String> errors) { |
| 571 if (e is Conversion) return inferExpression(e.node, t); | 576 if (e is Conversion) return inferExpression(e.node, t, errors); |
| 572 if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true; | 577 if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true; |
| 573 if (e is FunctionExpression) return _inferFunctionExpression(e, t); | 578 if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors); |
| 574 if (e is ListLiteral) return _inferListLiteral(e, t); | 579 if (e is ListLiteral) return _inferListLiteral(e, t, errors); |
| 575 if (e is MapLiteral) return _inferMapLiteral(e, t); | 580 if (e is MapLiteral) return _inferMapLiteral(e, t, errors); |
| 576 if (e is NamedExpression) return _inferNamedExpression(e, t); | 581 if (e is NamedExpression) return _inferNamedExpression(e, t, errors); |
| 577 if (e is InstanceCreationExpression) return _inferInstanceCreationExpression
( | 582 if (e is InstanceCreationExpression) return _inferInstanceCreationExpression
( |
| 578 e, t); | 583 e, t, errors); |
| 584 errors.add("$e cannot be typed as $t"); |
| 579 return false; | 585 return false; |
| 580 } | 586 } |
| 581 | 587 |
| 582 /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype | 588 /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype |
| 583 /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'> | 589 /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'> |
| 584 /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm' | 590 /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm' |
| 585 /// to derive a concrete instantation for I of the form <T0, ..., Tn>, | 591 /// to derive a concrete instantation for I of the form <T0, ..., Tn>, |
| 586 /// such that I<T0, .., Tn> <: t2 | 592 /// such that I<T0, .., Tn> <: t2 |
| 587 List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) { | 593 List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) { |
| 588 if (t1 == t2) return t2.typeArguments; | 594 if (t1 == t2) return t2.typeArguments; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 if (!match(t1.element.type)) return null; | 660 if (!match(t1.element.type)) return null; |
| 655 var newT1 = t1.element.type.substitute4(actuals); | 661 var newT1 = t1.element.type.substitute4(actuals); |
| 656 // If we found a solution, return it. | 662 // If we found a solution, return it. |
| 657 if (rules.isSubTypeOf(newT1, t2)) return actuals; | 663 if (rules.isSubTypeOf(newT1, t2)) return actuals; |
| 658 return null; | 664 return null; |
| 659 } | 665 } |
| 660 | 666 |
| 661 /// These assume that e is not already a subtype of t | 667 /// These assume that e is not already a subtype of t |
| 662 | 668 |
| 663 bool _inferInstanceCreationExpression( | 669 bool _inferInstanceCreationExpression( |
| 664 InstanceCreationExpression e, DartType t) { | 670 InstanceCreationExpression e, DartType t, errors) { |
| 665 var arguments = e.argumentList.arguments; | 671 var arguments = e.argumentList.arguments; |
| 666 var rawType = rules.getStaticType(e); | 672 var rawType = rules.getStaticType(e); |
| 667 // rawType is the instantiated type of the instance | 673 // rawType is the instantiated type of the instance |
| 668 if (rawType is! InterfaceType) return false; | 674 if (rawType is! InterfaceType) return false; |
| 669 var type = (rawType as InterfaceType); | 675 var type = (rawType as InterfaceType); |
| 670 if (type.typeParameters == null || | 676 if (type.typeParameters == null || |
| 671 type.typeParameters.length == 0) return false; | 677 type.typeParameters.length == 0) return false; |
| 672 if (e.constructorName.type == null) return false; | 678 if (e.constructorName.type == null) return false; |
| 673 // classTypeName is the type name of the class being instantiated | 679 // classTypeName is the type name of the class being instantiated |
| 674 var classTypeName = e.constructorName.type; | 680 var classTypeName = e.constructorName.type; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 695 var fType = baseType.substitute2(targs, tparams); | 701 var fType = baseType.substitute2(targs, tparams); |
| 696 { | 702 { |
| 697 var rTypes = fType.normalParameterTypes; | 703 var rTypes = fType.normalParameterTypes; |
| 698 var oTypes = fType.optionalParameterTypes; | 704 var oTypes = fType.optionalParameterTypes; |
| 699 var pTypes = new List.from(rTypes)..addAll(oTypes); | 705 var pTypes = new List.from(rTypes)..addAll(oTypes); |
| 700 var pArgs = arguments.where((x) => x is! NamedExpression); | 706 var pArgs = arguments.where((x) => x is! NamedExpression); |
| 701 var pi = 0; | 707 var pi = 0; |
| 702 for (var arg in pArgs) { | 708 for (var arg in pArgs) { |
| 703 if (pi >= pTypes.length) return false; | 709 if (pi >= pTypes.length) return false; |
| 704 var argType = pTypes[pi]; | 710 var argType = pTypes[pi]; |
| 705 if (!inferExpression(arg, argType)) return false; | 711 if (!inferExpression(arg, argType, errors)) return false; |
| 706 pi++; | 712 pi++; |
| 707 } | 713 } |
| 708 var nTypes = fType.namedParameterTypes; | 714 var nTypes = fType.namedParameterTypes; |
| 709 for (var arg0 in arguments) { | 715 for (var arg0 in arguments) { |
| 710 if (arg0 is! NamedExpression) continue; | 716 if (arg0 is! NamedExpression) continue; |
| 711 var arg = arg0 as NamedExpression; | 717 var arg = arg0 as NamedExpression; |
| 712 SimpleIdentifier nameNode = arg.name.label; | 718 SimpleIdentifier nameNode = arg.name.label; |
| 713 String name = nameNode.name; | 719 String name = nameNode.name; |
| 714 var argType = nTypes[name]; | 720 var argType = nTypes[name]; |
| 715 if (argType == null) return false; | 721 if (argType == null) return false; |
| 716 if (!inferExpression(arg, argType)) return false; | 722 if (!inferExpression(arg, argType, errors)) return false; |
| 717 } | 723 } |
| 718 } | 724 } |
| 719 annotateInstanceCreationExpression(e, targs); | 725 annotateInstanceCreationExpression(e, targs); |
| 720 return true; | 726 return true; |
| 721 } | 727 } |
| 722 | 728 |
| 723 bool _inferNamedExpression(NamedExpression e, DartType t) { | 729 bool _inferNamedExpression(NamedExpression e, DartType t, errors) { |
| 724 return inferExpression(e.expression, t); | 730 return inferExpression(e.expression, t, errors); |
| 725 } | 731 } |
| 726 | 732 |
| 727 bool _inferFunctionExpression(FunctionExpression e, DartType t) { | 733 bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) { |
| 728 if (t is! FunctionType) return false; | 734 if (t is! FunctionType) return false; |
| 729 var returnT = (t as FunctionType).returnType; | 735 var returnT = (t as FunctionType).returnType; |
| 730 if (returnT.isDynamic) return false; | 736 if (returnT.isDynamic) return false; |
| 731 var eType = e.staticType; | 737 var eType = e.staticType; |
| 732 if (eType is! FunctionType) return false; | 738 if (eType is! FunctionType) return false; |
| 733 if (e.body is! ExpressionFunctionBody) return false; | 739 if (e.body is! ExpressionFunctionBody) return false; |
| 734 var body = (e.body as ExpressionFunctionBody).expression; | 740 var body = (e.body as ExpressionFunctionBody).expression; |
| 735 if (!inferExpression(body, returnT)) return false; | 741 if (!inferExpression(body, returnT, errors)) return false; |
| 736 // TODO(leafp): Try narrowing the argument types if possible | 742 // TODO(leafp): Try narrowing the argument types if possible |
| 737 // to get better code in the function body. This requires checking | 743 // to get better code in the function body. This requires checking |
| 738 // that the body is well-typed at the more specific type. | 744 // that the body is well-typed at the more specific type. |
| 739 var element = (e.element as ExecutableElementImpl); | 745 var element = (e.element as ExecutableElementImpl); |
| 740 var oldReturnT = element.returnType; | 746 var oldReturnT = element.returnType; |
| 741 element.returnType = returnT; | 747 element.returnType = returnT; |
| 742 // Work around dynamic as bottom for now by handling function literals | 748 // Work around dynamic as bottom for now by handling function literals |
| 743 // with dynamic arguments specially. We already know the body is typable | 749 // with dynamic arguments specially. We already know the body is typable |
| 744 // at the chosen type, and if all args are dynamic, then function must be | 750 // at the chosen type, and if all args are dynamic, then function must be |
| 745 // typeable. | 751 // typeable. |
| 746 if ((eType as FunctionType).parameters.every((x) => x.type.isDynamic)) { | 752 if ((eType as FunctionType).parameters.every((x) => x.type.isDynamic)) { |
| 747 return true; | 753 return true; |
| 748 } | 754 } |
| 749 if (rules.isSubTypeOf(e.staticType, t)) return true; | 755 if (rules.isSubTypeOf(e.staticType, t)) return true; |
| 750 element.returnType = oldReturnT; | 756 element.returnType = oldReturnT; |
| 751 return false; | 757 return false; |
| 752 } | 758 } |
| 753 | 759 |
| 754 bool _inferListLiteral(ListLiteral e, DartType t) { | 760 bool _inferListLiteral(ListLiteral e, DartType t, errors) { |
| 755 var dyn = rules.provider.dynamicType; | 761 var dyn = rules.provider.dynamicType; |
| 756 var listT = rules.provider.listType.substitute4([dyn]); | 762 var listT = rules.provider.listType.substitute4([dyn]); |
| 757 // List <: t (using dart rules) must be true | 763 // List <: t (using dart rules) must be true |
| 758 if (!listT.isSubtypeOf(t)) return false; | 764 if (!listT.isSubtypeOf(t)) return false; |
| 759 // The list literal must have no type arguments | 765 // The list literal must have no type arguments |
| 760 if (e.typeArguments != null) return false; | 766 if (e.typeArguments != null) return false; |
| 761 if (t is! InterfaceType) return false; | 767 if (t is! InterfaceType) return false; |
| 762 var targs = _matchTypes(listT, t); | 768 var targs = _matchTypes(listT, t); |
| 763 if (targs == null) return false; | 769 if (targs == null) return false; |
| 764 assert(targs.length == 1); | 770 assert(targs.length == 1); |
| 765 var etype = targs[0]; | 771 var etype = targs[0]; |
| 766 assert(!etype.isDynamic); | 772 assert(!etype.isDynamic); |
| 767 var elements = e.elements; | 773 var elements = e.elements; |
| 768 var b = elements.every((e) => inferExpression(e, etype)); | 774 var b = elements.every((e) => inferExpression(e, etype, errors)); |
| 769 if (b) annotateListLiteral(e, targs); | 775 if (b) annotateListLiteral(e, targs); |
| 770 return b; | 776 return b; |
| 771 } | 777 } |
| 772 | 778 |
| 773 bool _inferMapLiteral(MapLiteral e, DartType t) { | 779 bool _inferMapLiteral(MapLiteral e, DartType t, errors) { |
| 774 var dyn = rules.provider.dynamicType; | 780 var dyn = rules.provider.dynamicType; |
| 775 var mapT = rules.provider.mapType.substitute4([dyn, dyn]); | 781 var mapT = rules.provider.mapType.substitute4([dyn, dyn]); |
| 776 // Map <: t (using dart rules) must be true | 782 // Map <: t (using dart rules) must be true |
| 777 if (!mapT.isSubtypeOf(t)) return false; | 783 if (!mapT.isSubtypeOf(t)) return false; |
| 778 // The map literal must have no type arguments | 784 // The map literal must have no type arguments |
| 779 if (e.typeArguments != null) return false; | 785 if (e.typeArguments != null) return false; |
| 780 if (t is! InterfaceType) return false; | 786 if (t is! InterfaceType) return false; |
| 781 var targs = _matchTypes(mapT, t); | 787 var targs = _matchTypes(mapT, t); |
| 782 if (targs == null) return false; | 788 if (targs == null) return false; |
| 783 assert(targs.length == 2); | 789 assert(targs.length == 2); |
| 784 var kType = targs[0]; | 790 var kType = targs[0]; |
| 785 var vType = targs[1]; | 791 var vType = targs[1]; |
| 786 assert(!(kType.isDynamic && vType.isDynamic)); | 792 assert(!(kType.isDynamic && vType.isDynamic)); |
| 787 var entries = e.entries; | 793 var entries = e.entries; |
| 788 bool inferEntry(MapLiteralEntry entry) { | 794 bool inferEntry(MapLiteralEntry entry) { |
| 789 return inferExpression(entry.key, kType) && | 795 return inferExpression(entry.key, kType, errors) && |
| 790 inferExpression(entry.value, vType); | 796 inferExpression(entry.value, vType, errors); |
| 791 } | 797 } |
| 792 var b = entries.every(inferEntry); | 798 var b = entries.every(inferEntry); |
| 793 if (b) annotateMapLiteral(e, targs); | 799 if (b) annotateMapLiteral(e, targs); |
| 794 return b; | 800 return b; |
| 795 } | 801 } |
| 796 } | 802 } |
| OLD | NEW |