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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/lib/js_helper.dart

Issue 12018015: Implement substitution for type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 7 years, 10 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 _js_helper; 5 library _js_helper;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:collection-dev'; 8 import 'dart:collection-dev';
9 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS, 9 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
10 JS, 10 JS,
11 JS_CALL_IN_ISOLATE, 11 JS_CALL_IN_ISOLATE,
12 JS_CURRENT_ISOLATE, 12 JS_CURRENT_ISOLATE,
13 JS_OPERATOR_IS_PREFIX, 13 JS_OPERATOR_IS_PREFIX,
14 JS_OPERATOR_AS_PREFIX,
14 JS_HAS_EQUALS, 15 JS_HAS_EQUALS,
15 RAW_DART_FUNCTION_REF, 16 RAW_DART_FUNCTION_REF,
16 UNINTERCEPTED; 17 UNINTERCEPTED;
17 18
18 part 'constant_map.dart'; 19 part 'constant_map.dart';
19 part 'native_helper.dart'; 20 part 'native_helper.dart';
20 part 'regexp_helper.dart'; 21 part 'regexp_helper.dart';
21 part 'string_helper.dart'; 22 part 'string_helper.dart';
22 23
23 bool isJsArray(var value) { 24 bool isJsArray(var value) {
(...skipping 1023 matching lines...) Expand 10 before | Expand all | Expand 10 after
1047 } 1048 }
1048 1049
1049 setRuntimeTypeInfo(target, typeInfo) { 1050 setRuntimeTypeInfo(target, typeInfo) {
1050 assert(typeInfo == null || isJsArray(typeInfo)); 1051 assert(typeInfo == null || isJsArray(typeInfo));
1051 // We have to check for null because factories may return null. 1052 // We have to check for null because factories may return null.
1052 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo); 1053 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo);
1053 } 1054 }
1054 1055
1055 getRuntimeTypeInfo(target) { 1056 getRuntimeTypeInfo(target) {
1056 if (target == null) return null; 1057 if (target == null) return null;
1057 var res = JS('var', r'#.$builtinTypeInfo', target); 1058 return JS('var', r'#.$builtinTypeInfo', target);
1058 // If the object does not have runtime type information, return an 1059 }
1059 // empty literal, to avoid null checks. 1060
1060 // TODO(ngeoffray): Make the object a top-level field to avoid 1061 getRuntimeTypeArgument(target, index) {
1061 // allocating a new object every single time. 1062 var rti = getRuntimeTypeInfo(target);
1062 return (res == null) ? JS('var', '{}') : res; 1063 return (rti != null) ? JS('var', r'#[#]', rti, index) : null;
1063 } 1064 }
1064 1065
1065 /** 1066 /**
1066 * The following methods are called by the runtime to implement 1067 * The following methods are called by the runtime to implement
1067 * checked mode and casts. We specialize each primitive type (eg int, bool), and 1068 * checked mode and casts. We specialize each primitive type (eg int, bool), and
1068 * use the compiler's convention to do is-checks on regular objects. 1069 * use the compiler's convention to do is-checks on regular objects.
1069 */ 1070 */
1070 boolConversionCheck(value) { 1071 boolConversionCheck(value) {
1071 boolTypeCheck(value); 1072 boolTypeCheck(value);
1072 assert(value != null); 1073 assert(value != null);
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
1414 bool operator ==(other) { 1415 bool operator ==(other) {
1415 if (other is !TypeImpl) return false; 1416 if (other is !TypeImpl) return false;
1416 return typeName == other.typeName; 1417 return typeName == other.typeName;
1417 } 1418 }
1418 } 1419 }
1419 1420
1420 String getClassName(var object) { 1421 String getClassName(var object) {
1421 return JS('String', r'#.constructor.builtin$cls', object); 1422 return JS('String', r'#.constructor.builtin$cls', object);
1422 } 1423 }
1423 1424
1424 String getTypeArgumentAsString(List runtimeType) { 1425 String getRuntimeTypeAsString(List runtimeType) {
1425 String className = getConstructorName(runtimeType[0]); 1426 String className = getConstructorName(runtimeType[0]);
1426 if (runtimeType.length == 1) return className; 1427 if (runtimeType.length == 1) return className;
1427 return '$className<${joinArguments(runtimeType, 1)}>'; 1428 return '$className<${joinArguments(runtimeType, 1)}>';
1428 } 1429 }
1429 1430
1430 String getConstructorName(type) => JS('String', r'#.builtin$cls', type); 1431 String getConstructorName(type) => JS('String', r'#.builtin$cls', type);
1431 1432
1432 String runtimeTypeToString(type) { 1433 String runtimeTypeToString(type) {
1433 if (type == null) { 1434 if (type == null) {
1434 return 'dynamic'; 1435 return 'dynamic';
1435 } else if (isJsArray(type)) { 1436 } else if (isJsArray(type)) {
1436 // A list representing a type with arguments. 1437 // A list representing a type with arguments.
1437 return getTypeArgumentAsString(type); 1438 return getRuntimeTypeAsString(type);
1438 } else { 1439 } else {
1439 // A reference to the constructor. 1440 // A reference to the constructor.
1440 return getConstructorName(type); 1441 return getConstructorName(type);
1441 } 1442 }
1442 } 1443 }
1443 1444
1444 String joinArguments(var types, int startIndex) { 1445 String joinArguments(var types, int startIndex) {
1445 bool firstArgument = true; 1446 bool firstArgument = true;
1446 StringBuffer buffer = new StringBuffer(); 1447 StringBuffer buffer = new StringBuffer();
1447 for (int index = startIndex; index < types.length; index++) { 1448 for (int index = startIndex; index < types.length; index++) {
1448 if (firstArgument) { 1449 if (firstArgument) {
1449 firstArgument = false; 1450 firstArgument = false;
1450 } else { 1451 } else {
1451 buffer. add(', '); 1452 buffer. add(', ');
1452 } 1453 }
1453 var argument = types[index]; 1454 var argument = types[index];
1454 buffer.add(runtimeTypeToString(argument)); 1455 buffer.add(runtimeTypeToString(argument));
1455 } 1456 }
1456 return buffer.toString(); 1457 return buffer.toString();
1457 } 1458 }
1458 1459
1459 String getRuntimeTypeString(var object) { 1460 String getRuntimeTypeString(var object) {
1460 String className = isJsArray(object) ? 'List' : getClassName(object); 1461 String className = isJsArray(object) ? 'List' : getClassName(object);
1461 var typeInfo = JS('var', r'#.$builtinTypeInfo', object); 1462 var typeInfo = JS('var', r'#.$builtinTypeInfo', object);
1462 if (typeInfo == null) return className; 1463 if (typeInfo == null) return className;
1463 return "$className<${joinArguments(typeInfo, 0)}>"; 1464 return "$className<${joinArguments(typeInfo, 0)}>";
1464 } 1465 }
1465 1466
1467 bool isJsFunction(var o) => JS('bool', r"typeof # == 'function'", o);
1468
1469 Object invoke(function, arguments) {
1470 return JS('var', r'#.apply(null, #)', function, arguments);
ngeoffray 2013/01/30 13:06:00 "#(#)" ?
karlklose 2013/01/30 15:37:18 The arguments are in a JS array, but we want them
1471 }
1472
1473 /**
1474 * Check that the types in the list [arguments] are subtypes of the types in
1475 * list [checks] (at the respective positions), possibly applying [substitution]
1476 * to the arguments before the check.
1477 *
1478 * See [:RuntimeTypes.getSubtypeSubstitution:] for a description of the possible
1479 * values for [substitution].
1480 */
1481 bool checkArguments(var substitution, var arguments, var checks) {
1482 if (isJsArray(substitution)) {
1483 arguments = substitution;
1484 } else if (isJsFunction(substitution)) {
1485 arguments = invoke(substitution, arguments);
1486 }
1487 return areSubtypes(arguments, checks);
1488 }
1489
1490 bool areSubtypes(var s, var t) {
ngeoffray 2013/01/30 13:06:00 (var s, var t) -> (List s, List t)
karlklose 2013/01/30 15:37:18 Done.
1491 // [:null:] means a raw type.
1492 if (s == null || t == null) return true;
1493
1494 assert(isJsArray(s));
1495 assert(isJsArray(t));
1496 assert(s.length == t.length);
1497
1498 int len = s.length;
1499 for (int i = 0; i < len; i++) {
1500 if (!isSubtype(s[i], t[i])) {
1501 return false;
1502 }
1503 }
1504 return true;
1505 }
1506
1507 getArguments(var type) => JS('var', r'#.slice(1)', type);
1508
1509 getField(var object, String name) => JS('var', r'#[#]', object, name);
1510
1466 /** 1511 /**
1467 * Check whether the type represented by [s] is a subtype of the type 1512 * Check whether the type represented by [s] is a subtype of the type
1468 * represented by [t]. 1513 * represented by [t].
1469 * 1514 *
1470 * Type representations can be: 1515 * Type representations can be:
1471 * 1) a JavaScript constructor for a class C: the represented type is the raw 1516 * 1) a JavaScript constructor for a class C: the represented type is the raw
1472 * type C. 1517 * type C.
1473 * 2) a JavaScript object: this represents a class for which there is no 1518 * 2) a JavaScript object: this represents a class for which there is no
1474 * JavaScript constructor, because it is only used in type arguments or it 1519 * JavaScript constructor, because it is only used in type arguments or it
1475 * is native. The represented type is the raw type of this class. 1520 * is native. The represented type is the raw type of this class.
1476 * 3) a JavaScript array: the first entry is of type 1 or 2 and identifies the 1521 * 3) a JavaScript array: the first entry is of type 1 or 2 and identifies the
1477 * class of the type and the rest of the array are the type arguments. 1522 * class of the type and the rest of the array are the type arguments.
1478 * 4) [:null:]: the dynamic type. 1523 * 4) [:null:]: the dynamic type.
1479 */ 1524 */
1480 bool isSubtype(var s, var t) { 1525 bool isSubtype(var s, var t) {
1481 // If either type is dynamic, [s] is a subtype of [t]. 1526 // If either type is dynamic, [s] is a subtype of [t].
1482 if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true; 1527 if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true;
1483 // Subtyping is reflexive. 1528 // Subtyping is reflexive.
1484 if (JS('bool', '# === #', s, t)) return true; 1529 if (JS('bool', '# === #', s, t)) return true;
1485 // Get the object describing the class and check for the subtyping flag 1530 // Get the object describing the class and check for the subtyping flag
1486 // constructed from the type of [t]. 1531 // constructed from the type of [t].
1487 var typeOfS = isJsArray(s) ? s[0] : s; 1532 var typeOfS = isJsArray(s) ? s[0] : s;
1488 var typeOfT = isJsArray(t) ? t[0] : t; 1533 var typeOfT = isJsArray(t) ? t[0] : t;
1534 // Check for a subtyping flag.
1489 var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}'; 1535 var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}';
1490 if (JS('var', r'#[#]', typeOfS, test) == null) return false; 1536 if (getField(typeOfS, test) == null) return false;
1491 // The class of [s] is a subclass of the class of [t]. If either of the types 1537 // The class of [s] is a subclass of the class of [t]. If either of the types
1492 // is raw, [s] is a subtype of [t]. 1538 // is raw, [s] is a subtype of [t].
1493 if (!isJsArray(s) || !isJsArray(t)) return true; 1539 if (!isJsArray(s) || !isJsArray(t)) return true;
1540 // Get the necessary substitution of the type arguments, if there is one.
1541 var substitution;
1542 if (JS('bool', '# !== #', typeOfT, typeOfS)) {
ngeoffray 2013/01/30 13:06:00 Can we use Dart's "!=" for typeOfT and typeOfS?
karlklose 2013/01/30 15:37:18 I don't think so, as it would try to call $eq on a
1543 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}';
1544 substitution = getField(typeOfS, field);
1545 }
1494 // Recursively check the type arguments. 1546 // Recursively check the type arguments.
1495 int len = s.length; 1547 return checkArguments(substitution, getArguments(s), getArguments(t));
1496 if (len != t.length) return false;
1497 for (int i = 1; i < len; i++) {
1498 if (!isSubtype(s[i], t[i])) {
1499 return false;
1500 }
1501 }
1502 return true;
1503 } 1548 }
1504 1549
1505 createRuntimeType(String name) => new TypeImpl(name); 1550 createRuntimeType(String name) => new TypeImpl(name);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698