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

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

Issue 1059763003: Inference casts to dynamic, fuzzy types handled (Closed) Base URL: git@github.com:dart-lang/dart-dev-compiler.git@master
Patch Set: Created 5 years, 8 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
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.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
11 import 'package:dev_compiler/src/info.dart'; 11 import 'package:dev_compiler/src/info.dart';
12 import 'package:dev_compiler/src/options.dart'; 12 import 'package:dev_compiler/src/options.dart';
13 import 'package:dev_compiler/src/report.dart' show CheckerReporter; 13 import 'package:dev_compiler/src/report.dart' show CheckerReporter;
14 14
15 abstract class TypeRules { 15 abstract class TypeRules {
16 final TypeProvider provider; 16 final TypeProvider provider;
17 LibraryInfo currentLibraryInfo = null; 17 LibraryInfo currentLibraryInfo = null;
18 18
19 TypeRules(TypeProvider this.provider); 19 TypeRules(TypeProvider this.provider);
20 20
21 bool isSubTypeOf(DartType t1, DartType t2); 21 bool isSubTypeOf(DartType t1, DartType t2);
22 bool isAssignable(DartType t1, DartType t2); 22 bool isAssignable(DartType t1, DartType t2);
23 23
24 bool isGroundType(DartType t) => true; 24 bool isGroundType(DartType t) => true;
25 // TODO(vsm): The default implementation is not ignoring the return type, 25 // TODO(vsm): The default implementation is not ignoring the return type,
26 // only the restricted override is. 26 // only the restricted override is.
27 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2, 27 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2,
28 {bool ignoreReturn: false}) => isSubTypeOf(f1, f2); 28 {bool fuzzyArrows: true, bool ignoreReturn: false}) =>
29 isSubTypeOf(f1, f2);
29 30
30 bool isBoolType(DartType t) => t == provider.boolType; 31 bool isBoolType(DartType t) => t == provider.boolType;
31 bool isDoubleType(DartType t) => t == provider.doubleType; 32 bool isDoubleType(DartType t) => t == provider.doubleType;
32 bool isIntType(DartType t) => t == provider.intType; 33 bool isIntType(DartType t) => t == provider.intType;
33 bool isNumType(DartType t) => t == provider.intType.superclass; 34 bool isNumType(DartType t) => t == provider.intType.superclass;
34 bool isStringType(DartType t) => t == provider.stringType; 35 bool isStringType(DartType t) => t == provider.stringType;
35 bool isNonNullableType(DartType t) => false; 36 bool isNonNullableType(DartType t) => false;
36 bool maybeNonNullableType(DartType t) => false; 37 bool maybeNonNullableType(DartType t) => false;
37 38
38 StaticInfo checkAssignment(Expression expr, DartType t, bool constContext); 39 StaticInfo checkAssignment(Expression expr, DartType t, bool constContext);
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 InheritanceManager manager = new InheritanceManager(element.library); 187 InheritanceManager manager = new InheritanceManager(element.library);
187 FunctionType callType = manager.lookupMemberType(t, "call"); 188 FunctionType callType = manager.lookupMemberType(t, "call");
188 return callType; 189 return callType;
189 } 190 }
190 return null; 191 return null;
191 } 192 }
192 193
193 /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC 194 /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC
194 /// checker to determine whether f1 would be a subtype of f2 if the return 195 /// checker to determine whether f1 would be a subtype of f2 if the return
195 /// type of f1 is set to match f2's return type. 196 /// type of f1 is set to match f2's return type.
197 // [fuzzyArrows] indicates whether or not the f1 and f2 should be
198 // treated as fuzzy arrow types (and hence dynamic parameters to f2 treated as
199 // bottom).
196 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2, 200 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2,
197 {bool dynamicIsBottom: false, bool ignoreReturn: false}) { 201 {bool fuzzyArrows: true, bool ignoreReturn: false}) {
198 final r1s = f1.normalParameterTypes; 202 final r1s = f1.normalParameterTypes;
199 final o1s = f1.optionalParameterTypes; 203 final o1s = f1.optionalParameterTypes;
200 final n1s = f1.namedParameterTypes; 204 final n1s = f1.namedParameterTypes;
201 final r2s = f2.normalParameterTypes; 205 final r2s = f2.normalParameterTypes;
202 final o2s = f2.optionalParameterTypes; 206 final o2s = f2.optionalParameterTypes;
203 final n2s = f2.namedParameterTypes; 207 final n2s = f2.namedParameterTypes;
204 final ret1 = ignoreReturn ? f2.returnType : f1.returnType; 208 final ret1 = ignoreReturn ? f2.returnType : f1.returnType;
205 final ret2 = f2.returnType; 209 final ret2 = f2.returnType;
206 210
207 // A -> B <: C -> D if C <: A and 211 // A -> B <: C -> D if C <: A and
208 // either D is void or B <: D 212 // either D is void or B <: D
209 if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false; 213 if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false;
210 214
211 // Reject if one has named and the other has optional 215 // Reject if one has named and the other has optional
212 if (n1s.length > 0 && o2s.length > 0) return false; 216 if (n1s.length > 0 && o2s.length > 0) return false;
213 if (n2s.length > 0 && o1s.length > 0) return false; 217 if (n2s.length > 0 && o1s.length > 0) return false;
214 218
215 // f2 has named parameters 219 // f2 has named parameters
216 if (n2s.length > 0) { 220 if (n2s.length > 0) {
217 // Check that every named parameter in f2 has a match in f1 221 // Check that every named parameter in f2 has a match in f1
218 for (String k2 in n2s.keys) { 222 for (String k2 in n2s.keys) {
219 if (!n1s.containsKey(k2)) return false; 223 if (!n1s.containsKey(k2)) return false;
220 if (!isSubTypeOf(n2s[k2], n1s[k2], dynamicIsBottom: true)) return false; 224 if (!isSubTypeOf(n2s[k2], n1s[k2],
225 dynamicIsBottom: fuzzyArrows)) return false;
221 } 226 }
222 } 227 }
223 // If we get here, we either have no named parameters, 228 // If we get here, we either have no named parameters,
224 // or else the named parameters match and we have no optional 229 // or else the named parameters match and we have no optional
225 // parameters 230 // parameters
226 231
227 // If f1 has more required parameters, reject 232 // If f1 has more required parameters, reject
228 if (r1s.length > r2s.length) return false; 233 if (r1s.length > r2s.length) return false;
229 234
230 // If f2 has more required + optional parameters, reject 235 // If f2 has more required + optional parameters, reject
231 if (r2s.length + o2s.length > r1s.length + o1s.length) return false; 236 if (r2s.length + o2s.length > r1s.length + o1s.length) return false;
232 237
233 // The parameter lists must look like the following at this point 238 // The parameter lists must look like the following at this point
234 // where rrr is a region of required, and ooo is a region of optionals. 239 // where rrr is a region of required, and ooo is a region of optionals.
235 // f1: rrr ooo ooo ooo 240 // f1: rrr ooo ooo ooo
236 // f2: rrr rrr ooo 241 // f2: rrr rrr ooo
237 int rr = r1s.length; // required in both 242 int rr = r1s.length; // required in both
238 int or = r2s.length - r1s.length; // optional in f1, required in f2 243 int or = r2s.length - r1s.length; // optional in f1, required in f2
239 int oo = o2s.length; // optional in both 244 int oo = o2s.length; // optional in both
240 245
241 for (int i = 0; i < rr; ++i) { 246 for (int i = 0; i < rr; ++i) {
242 if (!isSubTypeOf(r2s[i], r1s[i], dynamicIsBottom: true)) return false; 247 if (!isSubTypeOf(r2s[i], r1s[i],
248 dynamicIsBottom: fuzzyArrows)) return false;
243 } 249 }
244 for (int i = 0, j = rr; i < or; ++i, ++j) { 250 for (int i = 0, j = rr; i < or; ++i, ++j) {
245 if (!isSubTypeOf(r2s[j], o1s[i], dynamicIsBottom: true)) return false; 251 if (!isSubTypeOf(r2s[j], o1s[i],
252 dynamicIsBottom: fuzzyArrows)) return false;
246 } 253 }
247 for (int i = or, j = 0; i < oo; ++i, ++j) { 254 for (int i = or, j = 0; i < oo; ++i, ++j) {
248 if (!isSubTypeOf(o2s[j], o1s[i], dynamicIsBottom: true)) return false; 255 if (!isSubTypeOf(o2s[j], o1s[i],
256 dynamicIsBottom: fuzzyArrows)) return false;
249 } 257 }
250 return true; 258 return true;
251 } 259 }
252 260
253 bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) { 261 bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) {
254 if (i1 == i2) return true; 262 if (i1 == i2) return true;
255 263
256 if (i1.element == i2.element) { 264 if (i1.element == i2.element) {
257 List<DartType> tArgs1 = i1.typeArguments; 265 List<DartType> tArgs1 = i1.typeArguments;
258 List<DartType> tArgs2 = i2.typeArguments; 266 List<DartType> tArgs2 = i2.typeArguments;
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 /// Called for each list literal which gets inferred 572 /// Called for each list literal which gets inferred
565 void annotateListLiteral(ListLiteral e, List<DartType> targs) {} 573 void annotateListLiteral(ListLiteral e, List<DartType> targs) {}
566 574
567 /// Called for each map literal which gets inferred 575 /// Called for each map literal which gets inferred
568 void annotateMapLiteral(MapLiteral e, List<DartType> targs) {} 576 void annotateMapLiteral(MapLiteral e, List<DartType> targs) {}
569 577
570 /// Called for each new/const which gets inferred 578 /// Called for each new/const which gets inferred
571 void annotateInstanceCreationExpression( 579 void annotateInstanceCreationExpression(
572 InstanceCreationExpression e, List<DartType> targs) {} 580 InstanceCreationExpression e, List<DartType> targs) {}
573 581
582 /// Called for cast from dynamic required for inference to succeed
583 void annotateCastFromDynamic(Expression e, DartType t) {}
584
585 /// Called for each function expression return type inferred
586 void annotateFunctionExpression(FunctionExpression e, DartType returnType) {}
587
574 /// Downward inference 588 /// Downward inference
575 bool inferExpression(Expression e, DartType t, List<String> errors) { 589 bool inferExpression(Expression e, DartType t, List<String> errors) {
576 if (e is Conversion) return inferExpression(e.node, t, errors); 590 // Don't cast top level expressions, only sub-expressions
591 return _inferExpression(e, t, errors, cast: false);
592 }
593
594 /// Downward inference
595 bool _inferExpression(Expression e, DartType t, List<String> errors,
596 {cast: true}) {
597 if (e is Conversion) return _inferExpression(e.node, t, errors);
577 if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true; 598 if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true;
599 if (cast && rules.getStaticType(e).isDynamic) {
600 annotateCastFromDynamic(e, t);
601 return true;
602 }
578 if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors); 603 if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors);
579 if (e is ListLiteral) return _inferListLiteral(e, t, errors); 604 if (e is ListLiteral) return _inferListLiteral(e, t, errors);
580 if (e is MapLiteral) return _inferMapLiteral(e, t, errors); 605 if (e is MapLiteral) return _inferMapLiteral(e, t, errors);
581 if (e is NamedExpression) return _inferNamedExpression(e, t, errors); 606 if (e is NamedExpression) return _inferNamedExpression(e, t, errors);
582 if (e is InstanceCreationExpression) return _inferInstanceCreationExpression ( 607 if (e is InstanceCreationExpression) return _inferInstanceCreationExpression (
583 e, t, errors); 608 e, t, errors);
584 errors.add("$e cannot be typed as $t"); 609 errors.add("$e cannot be typed as $t");
585 return false; 610 return false;
586 } 611 }
587 612
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
701 var fType = baseType.substitute2(targs, tparams); 726 var fType = baseType.substitute2(targs, tparams);
702 { 727 {
703 var rTypes = fType.normalParameterTypes; 728 var rTypes = fType.normalParameterTypes;
704 var oTypes = fType.optionalParameterTypes; 729 var oTypes = fType.optionalParameterTypes;
705 var pTypes = new List.from(rTypes)..addAll(oTypes); 730 var pTypes = new List.from(rTypes)..addAll(oTypes);
706 var pArgs = arguments.where((x) => x is! NamedExpression); 731 var pArgs = arguments.where((x) => x is! NamedExpression);
707 var pi = 0; 732 var pi = 0;
708 for (var arg in pArgs) { 733 for (var arg in pArgs) {
709 if (pi >= pTypes.length) return false; 734 if (pi >= pTypes.length) return false;
710 var argType = pTypes[pi]; 735 var argType = pTypes[pi];
711 if (!inferExpression(arg, argType, errors)) return false; 736 if (!_inferExpression(arg, argType, errors)) return false;
712 pi++; 737 pi++;
713 } 738 }
714 var nTypes = fType.namedParameterTypes; 739 var nTypes = fType.namedParameterTypes;
715 for (var arg0 in arguments) { 740 for (var arg0 in arguments) {
716 if (arg0 is! NamedExpression) continue; 741 if (arg0 is! NamedExpression) continue;
717 var arg = arg0 as NamedExpression; 742 var arg = arg0 as NamedExpression;
718 SimpleIdentifier nameNode = arg.name.label; 743 SimpleIdentifier nameNode = arg.name.label;
719 String name = nameNode.name; 744 String name = nameNode.name;
720 var argType = nTypes[name]; 745 var argType = nTypes[name];
721 if (argType == null) return false; 746 if (argType == null) return false;
722 if (!inferExpression(arg, argType, errors)) return false; 747 if (!_inferExpression(arg, argType, errors)) return false;
723 } 748 }
724 } 749 }
725 annotateInstanceCreationExpression(e, targs); 750 annotateInstanceCreationExpression(e, targs);
726 return true; 751 return true;
727 } 752 }
728 753
729 bool _inferNamedExpression(NamedExpression e, DartType t, errors) { 754 bool _inferNamedExpression(NamedExpression e, DartType t, errors) {
730 return inferExpression(e.expression, t, errors); 755 return _inferExpression(e.expression, t, errors);
731 } 756 }
732 757
733 bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) { 758 bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) {
734 if (t is! FunctionType) return false; 759 if (t is! FunctionType) return false;
735 var returnT = (t as FunctionType).returnType; 760 var fType = (t as FunctionType);
736 if (returnT.isDynamic) return false;
737 var eType = e.staticType; 761 var eType = e.staticType;
738 if (eType is! FunctionType) return false; 762 if (eType is! FunctionType) return false;
763
764 // We have a function literal, so we can treat the arrow type
765 // as non-fuzzy. Since we're not improving on parameter types
766 // currently, if this check fails then we cannot succeed, so
767 // bail out. Otherwise, we never need to check the parameter types
768 // again.
769 if (!rules.isFunctionSubTypeOf(eType, fType,
770 fuzzyArrows: false, ignoreReturn: true)) return false;
771
772 // This only entered inference because of fuzzy typing.
773 // The function type is already specific enough, we can just
774 // succeed and treat it as a succesful inference
vsm 2015/04/03 22:32:59 s/succesful/successful/
775 if (rules.isSubTypeOf(eType.returnType, fType.returnType)) return true;
776
777 // Fuzzy typing again, handle the void case (not caught by the previous)
778 if (fType.returnType.isVoid) return true;
779
739 if (e.body is! ExpressionFunctionBody) return false; 780 if (e.body is! ExpressionFunctionBody) return false;
740 var body = (e.body as ExpressionFunctionBody).expression; 781 var body = (e.body as ExpressionFunctionBody).expression;
741 if (!inferExpression(body, returnT, errors)) return false; 782 if (!_inferExpression(body, fType.returnType, errors)) return false;
783
742 // TODO(leafp): Try narrowing the argument types if possible 784 // TODO(leafp): Try narrowing the argument types if possible
743 // to get better code in the function body. This requires checking 785 // to get better code in the function body. This requires checking
744 // that the body is well-typed at the more specific type. 786 // that the body is well-typed at the more specific type.
745 var element = (e.element as ExecutableElementImpl); 787
746 var oldReturnT = element.returnType; 788 // At this point, we know that the parameter types are in the appropriate su btype
747 element.returnType = returnT; 789 // relation, and we have checked that we can type the body at the appropriat e return
748 // Work around dynamic as bottom for now by handling function literals 790 // type, so we can are done.
749 // with dynamic arguments specially. We already know the body is typable 791 annotateFunctionExpression(e, fType.returnType);
750 // at the chosen type, and if all args are dynamic, then function must be 792 return true;
751 // typeable.
752 if ((eType as FunctionType).parameters.every((x) => x.type.isDynamic)) {
753 return true;
754 }
755 if (rules.isSubTypeOf(e.staticType, t)) return true;
756 element.returnType = oldReturnT;
757 return false;
758 } 793 }
759 794
760 bool _inferListLiteral(ListLiteral e, DartType t, errors) { 795 bool _inferListLiteral(ListLiteral e, DartType t, errors) {
761 var dyn = rules.provider.dynamicType; 796 var dyn = rules.provider.dynamicType;
762 var listT = rules.provider.listType.substitute4([dyn]); 797 var listT = rules.provider.listType.substitute4([dyn]);
763 // List <: t (using dart rules) must be true 798 // List <: t (using dart rules) must be true
764 if (!listT.isSubtypeOf(t)) return false; 799 if (!listT.isSubtypeOf(t)) return false;
765 // The list literal must have no type arguments 800 // The list literal must have no type arguments
766 if (e.typeArguments != null) return false; 801 if (e.typeArguments != null) return false;
767 if (t is! InterfaceType) return false; 802 if (t is! InterfaceType) return false;
768 var targs = _matchTypes(listT, t); 803 var targs = _matchTypes(listT, t);
769 if (targs == null) return false; 804 if (targs == null) return false;
770 assert(targs.length == 1); 805 assert(targs.length == 1);
771 var etype = targs[0]; 806 var etype = targs[0];
772 assert(!etype.isDynamic); 807 assert(!etype.isDynamic);
773 var elements = e.elements; 808 var elements = e.elements;
774 var b = elements.every((e) => inferExpression(e, etype, errors)); 809 var b = elements.every((e) => _inferExpression(e, etype, errors));
775 if (b) annotateListLiteral(e, targs); 810 if (b) annotateListLiteral(e, targs);
776 return b; 811 return b;
777 } 812 }
778 813
779 bool _inferMapLiteral(MapLiteral e, DartType t, errors) { 814 bool _inferMapLiteral(MapLiteral e, DartType t, errors) {
780 var dyn = rules.provider.dynamicType; 815 var dyn = rules.provider.dynamicType;
781 var mapT = rules.provider.mapType.substitute4([dyn, dyn]); 816 var mapT = rules.provider.mapType.substitute4([dyn, dyn]);
782 // Map <: t (using dart rules) must be true 817 // Map <: t (using dart rules) must be true
783 if (!mapT.isSubtypeOf(t)) return false; 818 if (!mapT.isSubtypeOf(t)) return false;
784 // The map literal must have no type arguments 819 // The map literal must have no type arguments
785 if (e.typeArguments != null) return false; 820 if (e.typeArguments != null) return false;
786 if (t is! InterfaceType) return false; 821 if (t is! InterfaceType) return false;
787 var targs = _matchTypes(mapT, t); 822 var targs = _matchTypes(mapT, t);
788 if (targs == null) return false; 823 if (targs == null) return false;
789 assert(targs.length == 2); 824 assert(targs.length == 2);
790 var kType = targs[0]; 825 var kType = targs[0];
791 var vType = targs[1]; 826 var vType = targs[1];
792 assert(!(kType.isDynamic && vType.isDynamic)); 827 assert(!(kType.isDynamic && vType.isDynamic));
793 var entries = e.entries; 828 var entries = e.entries;
794 bool inferEntry(MapLiteralEntry entry) { 829 bool inferEntry(MapLiteralEntry entry) {
795 return inferExpression(entry.key, kType, errors) && 830 return _inferExpression(entry.key, kType, errors) &&
796 inferExpression(entry.value, vType, errors); 831 _inferExpression(entry.value, vType, errors);
797 } 832 }
798 var b = entries.every(inferEntry); 833 var b = entries.every(inferEntry);
799 if (b) annotateMapLiteral(e, targs); 834 if (b) annotateMapLiteral(e, targs);
800 return b; 835 return b;
801 } 836 }
802 } 837 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698