| 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 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 // but doesn't properly mix with class subtyping. I suspect Java 8 lambdas | 403 // but doesn't properly mix with class subtyping. I suspect Java 8 lambdas |
| 404 // essentially map to dynamic (and rely on invokedynamic) due to similar | 404 // essentially map to dynamic (and rely on invokedynamic) due to similar |
| 405 // issues. | 405 // issues. |
| 406 return isFunctionSubTypeOf(t1 as FunctionType, t2 as FunctionType); | 406 return isFunctionSubTypeOf(t1 as FunctionType, t2 as FunctionType); |
| 407 } | 407 } |
| 408 | 408 |
| 409 bool isAssignable(DartType t1, DartType t2) { | 409 bool isAssignable(DartType t1, DartType t2) { |
| 410 return isSubTypeOf(t1, t2); | 410 return isSubTypeOf(t1, t2); |
| 411 } | 411 } |
| 412 | 412 |
| 413 // If fromT <: toT, returns the identity coercion. | |
| 414 // Otherwise, creates a coercion wrapping a function of | |
| 415 // type fromT as a function of type toT, if: | |
| 416 // 1) this can be done without changing the reified type | |
| 417 // 2) The arguments can be coerced (see _coerceTo below) | |
| 418 // 3) The return value can be coerced or wrapped | |
| 419 // Otherwise, returns the error coercion | |
| 420 Coercion _wrapTo(FunctionType fromT, FunctionType toT) { | |
| 421 final r1s = fromT.normalParameterTypes; | |
| 422 final o1s = fromT.optionalParameterTypes; | |
| 423 final n1s = fromT.namedParameterTypes; | |
| 424 final ret1 = fromT.returnType; | |
| 425 | |
| 426 final r2s = toT.normalParameterTypes; | |
| 427 final o2s = toT.optionalParameterTypes; | |
| 428 final n2s = toT.namedParameterTypes; | |
| 429 final ret2 = toT.returnType; | |
| 430 | |
| 431 Coercion ret = _coerceTo(ret1, ret2, options.wrapClosures); | |
| 432 | |
| 433 // Reject if one has named and the other has optional | |
| 434 if (n1s.length > 0 && o2s.length > 0) return Coercion.error(); | |
| 435 if (n2s.length > 0 && o1s.length > 0) return Coercion.error(); | |
| 436 | |
| 437 Map<String, Coercion> ns = new Map<String, Coercion>(); | |
| 438 // toT has named parameters | |
| 439 if (n2s.length > 0) { | |
| 440 // Coerce each named parameter from toT to the expected | |
| 441 // type in fromT (note the contravariance) | |
| 442 for (String k2 in n2s.keys) { | |
| 443 if (!n1s.containsKey(k2)) return Coercion.error(); | |
| 444 ns[k2] = _coerceTo(n2s[k2], n1s[k2]); | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 // If fromT has more required parameters, reject | |
| 449 if (r1s.length > r2s.length) return Coercion.error(); | |
| 450 | |
| 451 // If toT has more required + optional parameters, reject | |
| 452 if (r2s.length + o2s.length > r1s.length + o1s.length) { | |
| 453 return Coercion.error(); | |
| 454 } | |
| 455 | |
| 456 // The parameter lists must look like the following at this point | |
| 457 // where rrr is a region of required, and ooo is a region of optionals. | |
| 458 // fromT: rrr ooo ooo ooo | |
| 459 // toT : rrr rrr ooo | |
| 460 int rr = r1s.length; // required in both | |
| 461 int or = r2s.length - r1s.length; // optional in fromT, required in toT | |
| 462 int oo = o2s.length; // optional in both | |
| 463 | |
| 464 List<Coercion> rs = new List<Coercion>(r1s.length); | |
| 465 for (int i = 0; i < rr; ++i) { | |
| 466 rs[i] = _coerceTo(r2s[i], r1s[i]); | |
| 467 } | |
| 468 List<Coercion> os = new List<Coercion>(o1s.length); | |
| 469 for (int i = 0, j = rr; i < or; ++i, ++j) { | |
| 470 os[i] = _coerceTo(r2s[j], o1s[i]); | |
| 471 } | |
| 472 for (int i = or, j = 0; i < oo; ++i, ++j) { | |
| 473 os[i] = _coerceTo(o2s[j], o1s[i]); | |
| 474 } | |
| 475 for (int i = oo; i < o1s.length; ++i) { | |
| 476 os[i] = Coercion.identity(o1s[i]); | |
| 477 } | |
| 478 return Coercion.wrapper(fromT, toT, rs, os, ns, ret); | |
| 479 } | |
| 480 | |
| 481 // Produce a coercion which coerces something of type fromT | 413 // Produce a coercion which coerces something of type fromT |
| 482 // to something of type toT. | 414 // to something of type toT. |
| 483 // If wrap is true and both are function types, a closure | 415 // If wrap is true and both are function types, a closure |
| 484 // wrapper coercion is produced using _wrapTo (see above) | 416 // wrapper coercion is produced using _wrapTo (see above) |
| 485 // Returns the error coercion if the types cannot be coerced | 417 // Returns the error coercion if the types cannot be coerced |
| 486 // according to our current criteria. | 418 // according to our current criteria. |
| 487 Coercion _coerceTo(DartType fromT, DartType toT, [bool wrap = false]) { | 419 Coercion _coerceTo(DartType fromT, DartType toT) { |
| 488 // We can use anything as void | 420 // We can use anything as void |
| 489 if (toT.isVoid) return Coercion.identity(toT); | 421 if (toT.isVoid) return Coercion.identity(toT); |
| 490 | 422 |
| 491 // fromT <: toT, no coercion needed | 423 // fromT <: toT, no coercion needed |
| 492 if (isSubTypeOf(fromT, toT)) return Coercion.identity(toT); | 424 if (isSubTypeOf(fromT, toT)) return Coercion.identity(toT); |
| 493 | 425 |
| 494 // For now, we always wrap closures. | |
| 495 if (wrap && fromT is FunctionType && toT is FunctionType) { | |
| 496 return _wrapTo(fromT, toT); | |
| 497 } | |
| 498 | |
| 499 // For now, reject conversions between function types and | 426 // For now, reject conversions between function types and |
| 500 // call method objects. We could choose to allow casts here. | 427 // call method objects. We could choose to allow casts here. |
| 501 // Wrapping a function type to assign it to a call method | 428 // Wrapping a function type to assign it to a call method |
| 502 // object will never succeed. Wrapping the other way could | 429 // object will never succeed. Wrapping the other way could |
| 503 // be allowed. | 430 // be allowed. |
| 504 if ((fromT is FunctionType && getCallMethodType(toT) != null) || | 431 if ((fromT is FunctionType && getCallMethodType(toT) != null) || |
| 505 (toT is FunctionType && getCallMethodType(fromT) != null)) { | 432 (toT is FunctionType && getCallMethodType(fromT) != null)) { |
| 506 return Coercion.error(); | 433 return Coercion.error(); |
| 507 } | 434 } |
| 508 | 435 |
| 509 // Downcast if toT <: fromT | 436 // Downcast if toT <: fromT |
| 510 if (isSubTypeOf(toT, fromT)) return Coercion.cast(fromT, toT); | 437 if (isSubTypeOf(toT, fromT)) return Coercion.cast(fromT, toT); |
| 511 | 438 |
| 512 // Downcast if toT <===> fromT | 439 // Downcast if toT <===> fromT |
| 513 // The intention here is to allow casts that are sideways in the restricted | 440 // The intention here is to allow casts that are sideways in the restricted |
| 514 // type system, but allowed in the regular dart type system, since these | 441 // type system, but allowed in the regular dart type system, since these |
| 515 // are likely to succeed. The canonical example is List<dynamic> and | 442 // are likely to succeed. The canonical example is List<dynamic> and |
| 516 // Iterable<T> for some concrete T (e.g. Object). These are unrelated | 443 // Iterable<T> for some concrete T (e.g. Object). These are unrelated |
| 517 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. | 444 // in the restricted system, but List<dynamic> <: Iterable<T> in dart. |
| 518 if (options.relaxedCasts && fromT.isAssignableTo(toT)) { | 445 if (options.relaxedCasts && fromT.isAssignableTo(toT)) { |
| 519 return Coercion.cast(fromT, toT); | 446 return Coercion.cast(fromT, toT); |
| 520 } | 447 } |
| 521 return Coercion.error(); | 448 return Coercion.error(); |
| 522 } | 449 } |
| 523 | 450 |
| 524 StaticInfo checkAssignment(Expression expr, DartType toT, bool constContext) { | 451 StaticInfo checkAssignment(Expression expr, DartType toT, bool constContext) { |
| 525 final fromT = getStaticType(expr); | 452 final fromT = getStaticType(expr); |
| 526 final Coercion c = _coerceTo(fromT, toT, options.wrapClosures); | 453 final Coercion c = _coerceTo(fromT, toT); |
| 527 if (c is Identity) return null; | 454 if (c is Identity) return null; |
| 528 if (c is CoercionError) return new StaticTypeError(this, expr, toT); | 455 if (c is CoercionError) return new StaticTypeError(this, expr, toT); |
| 529 var reason = null; | 456 var reason = null; |
| 530 if (options.inferDownwards) { | 457 if (options.inferDownwards) { |
| 531 var errors = <String>[]; | 458 var errors = <String>[]; |
| 532 var ok = inferrer.inferExpression(expr, toT, errors); | 459 var ok = inferrer.inferExpression(expr, toT, errors); |
| 533 if (ok) return InferredType.create(this, expr, toT); | 460 if (ok) return InferredType.create(this, expr, toT); |
| 534 reason = (errors.isNotEmpty) ? errors.first : null; | 461 reason = (errors.isNotEmpty) ? errors.first : null; |
| 535 } | 462 } |
| 536 if (c is Cast) return DownCast.create(this, expr, c, reason: reason); | 463 if (c is Cast) return DownCast.create(this, expr, c, reason: reason); |
| 537 if (c is Wrapper) return ClosureWrap.create(this, expr, c, toT); | |
| 538 assert(false); | 464 assert(false); |
| 539 return null; | 465 return null; |
| 540 } | 466 } |
| 541 | 467 |
| 542 DartType elementType(Element e) { | 468 DartType elementType(Element e) { |
| 543 return (e as dynamic).type; | 469 return (e as dynamic).type; |
| 544 } | 470 } |
| 545 | 471 |
| 546 bool isDynamic(DartType t) => options.ignoreTypes || t.isDynamic; | 472 bool isDynamic(DartType t) => options.ignoreTypes || t.isDynamic; |
| 547 | 473 |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 860 var entries = e.entries; | 786 var entries = e.entries; |
| 861 bool inferEntry(MapLiteralEntry entry) { | 787 bool inferEntry(MapLiteralEntry entry) { |
| 862 return _inferExpression(entry.key, kType, errors) && | 788 return _inferExpression(entry.key, kType, errors) && |
| 863 _inferExpression(entry.value, vType, errors); | 789 _inferExpression(entry.value, vType, errors); |
| 864 } | 790 } |
| 865 var b = entries.every(inferEntry); | 791 var b = entries.every(inferEntry); |
| 866 if (b) annotateMapLiteral(e, targs); | 792 if (b) annotateMapLiteral(e, targs); |
| 867 return b; | 793 return b; |
| 868 } | 794 } |
| 869 } | 795 } |
| OLD | NEW |