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

Side by Side Diff: frog/member.dart

Issue 8567010: Dynamically dispatch getters and setters on dynamically-typed variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes, frogsh Created 9 years, 1 month 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
« no previous file with comments | « frog/frogsh ('k') | tests/language/language.status » ('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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** A formal parameter to a [Method]. */ 5 /** A formal parameter to a [Method]. */
6 class Parameter { 6 class Parameter {
7 FormalNode definition; 7 FormalNode definition;
8 8
9 String name; 9 String name;
10 Type type; 10 Type type;
(...skipping 1351 matching lines...) Expand 10 before | Expand all | Expand 10 after
1362 if (!target.type.isVar) { 1362 if (!target.type.isVar) {
1363 world.warning('could not find applicable $action for "$name"', node.span); 1363 world.warning('could not find applicable $action for "$name"', node.span);
1364 } 1364 }
1365 return new Value(world.varType, 1365 return new Value(world.varType,
1366 '${target.code}.$jsname() /*no applicable $action*/', node.span); 1366 '${target.code}.$jsname() /*no applicable $action*/', node.span);
1367 } 1367 }
1368 1368
1369 bool _treatAsField; 1369 bool _treatAsField;
1370 bool get treatAsField() { 1370 bool get treatAsField() {
1371 if (_treatAsField == null) { 1371 if (_treatAsField == null) {
1372 _treatAsField = true; 1372 // If this is the global MemberSet from world, always bind dynamically.
1373 // Note: we need this for proper noSuchMethod and REPL behavior.
1374 _treatAsField = !isVar;
1373 for (var member in members) { 1375 for (var member in members) {
1374 if (member.requiresFieldSyntax) { 1376 if (member.requiresFieldSyntax) {
1375 _treatAsField = true; 1377 _treatAsField = true;
1376 break; 1378 break;
1377 } 1379 }
1378 if (member.prefersPropertySyntax) { 1380 if (member.prefersPropertySyntax) {
1379 _treatAsField = false; 1381 _treatAsField = false;
1380 } 1382 }
1381 } 1383 }
1382 for (var member in members) { 1384 for (var member in members) {
1383 if (_treatAsField) { 1385 if (_treatAsField) {
1384 member.provideFieldSyntax(); 1386 member.provideFieldSyntax();
1385 } else { 1387 } else {
1386 member.providePropertySyntax(); 1388 member.providePropertySyntax();
1387 } 1389 }
1388 } 1390 }
1389 } 1391 }
1390 return _treatAsField; 1392 return _treatAsField;
1391 } 1393 }
1392 1394
1393 Value _get(MethodGenerator context, Node node, Value target, 1395 Value _get(MethodGenerator context, Node node, Value target,
1394 [bool isDynamic=false]) { 1396 [bool isDynamic=false]) {
1395 if (members.length == 1) { 1397 // If this is the global MemberSet from world, always bind dynamically.
1396 return members[0]._get(context, node, target, isDynamic); 1398 // Note: we need this for proper noSuchMethod and REPL behavior.
1397 } 1399 Value returnValue;
1398 final targets = members.filter((m) => m.canGet); 1400 final targets = members.filter((m) => m.canGet);
1399 if (targets.length == 1) { 1401 if (isVar) {
1400 return targets[0]._get(context, node, target, isDynamic); 1402 targets.forEach((m) => m._get(context, node, target, isDynamic: true));
1403 returnValue = new Value(_foldTypes(targets), null, node.span);
1404 } else {
1405 if (members.length == 1) {
1406 return members[0]._get(context, node, target, isDynamic);
1407 } else if (targets.length == 1) {
1408 return targets[0]._get(context, node, target, isDynamic);
1409 }
1410
1411 for (var member in targets) {
1412 final value = member._get(context, node, target, isDynamic:true);
1413 returnValue = _tryUnion(returnValue, value, node);
1414 }
1415 if (returnValue == null) {
1416 return _makeError(node, target, 'getter');
1417 }
1401 } 1418 }
1402 1419
1403 Value returnValue = null;
1404 for (var member in targets) {
1405 final value = member._get(context, node, target, isDynamic:true);
1406 returnValue = _tryUnion(returnValue, value, node);
1407 }
1408 if (returnValue == null) {
1409 return _makeError(node, target, 'getter');
1410 }
1411 if (returnValue.code == null) { 1420 if (returnValue.code == null) {
1412 if (treatAsField) { 1421 if (treatAsField) {
1413 return new Value(returnValue.type, '${target.code}.$jsname', 1422 return new Value(returnValue.type, '${target.code}.$jsname',
1414 node.span); 1423 node.span);
1415 } else { 1424 } else {
1416 return new Value(returnValue.type, '${target.code}.get\$$jsname()', 1425 return new Value(returnValue.type, '${target.code}.get\$$jsname()',
1417 node.span); 1426 node.span);
1418 } 1427 }
1419 } 1428 }
1420 return returnValue; 1429 return returnValue;
1421 } 1430 }
1422 1431
1423 Value _set(MethodGenerator context, Node node, Value target, Value value, 1432 Value _set(MethodGenerator context, Node node, Value target, Value value,
1424 [bool isDynamic=false]) { 1433 [bool isDynamic=false]) {
1425 if (members.length == 1) { 1434 // If this is the global MemberSet from world, always bind dynamically.
1426 return members[0]._set(context, node, target, value, isDynamic); 1435 // Note: we need this for proper noSuchMethod and REPL behavior.
1427 } 1436 Value returnValue;
1428 final targets = members.filter((m) => m.canSet); 1437 final targets = members.filter((m) => m.canSet);
1429 if (targets.length == 1) { 1438 if (isVar) {
1430 return targets[0]._set(context, node, target, value, isDynamic); 1439 targets.forEach((m) =>
1440 m._set(context, node, target, value, isDynamic: true));
1441 returnValue = new Value(_foldTypes(targets), null, node.span);
1442 } else {
1443 if (members.length == 1) {
1444 return members[0]._set(context, node, target, value, isDynamic);
1445 } else if (targets.length == 1) {
1446 return targets[0]._set(context, node, target, value, isDynamic);
1447 }
1448
1449 for (var member in targets) {
1450 final res = member._set(context, node, target, value, isDynamic:true);
1451 returnValue = _tryUnion(returnValue, res, node);
1452 }
1453 if (returnValue == null) {
1454 return _makeError(node, target, 'setter');
1455 }
1431 } 1456 }
1432 1457
1433 Value returnValue = null;
1434 for (var member in targets) {
1435 final res = member._set(context, node, target, value, isDynamic:true);
1436 returnValue = _tryUnion(returnValue, res, node);
1437 }
1438 if (returnValue == null) {
1439 return _makeError(node, target, 'setter');
1440 }
1441 if (returnValue.code == null) { 1458 if (returnValue.code == null) {
1442 if (treatAsField) { 1459 if (treatAsField) {
1443 return new Value(returnValue.type, 1460 return new Value(returnValue.type,
1444 '${target.code}.$jsname = ${value.code}', node.span); 1461 '${target.code}.$jsname = ${value.code}', node.span);
1445 } else { 1462 } else {
1446 return new Value(returnValue.type, 1463 return new Value(returnValue.type,
1447 '${target.code}.set\$$jsname(${value.code})', node.span); 1464 '${target.code}.set\$$jsname(${value.code})', node.span);
1448 } 1465 }
1449 } 1466 }
1450 return returnValue; 1467 return returnValue;
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1542 // Ensure that we're making stub with all possible members of this name. 1559 // Ensure that we're making stub with all possible members of this name.
1543 // We need this canonicalization step because only one VarMemberSet can 1560 // We need this canonicalization step because only one VarMemberSet can
1544 // live on Object.prototype 1561 // live on Object.prototype
1545 // TODO(jmesserly): this is ugly--we're throwing away type information! 1562 // TODO(jmesserly): this is ugly--we're throwing away type information!
1546 // The right solution is twofold: 1563 // The right solution is twofold:
1547 // 1. put stubs on a more precise type when possible 1564 // 1. put stubs on a more precise type when possible
1548 // 2. merge VarMemberSets together if necessary 1565 // 2. merge VarMemberSets together if necessary
1549 final mset = context.findMembers(name).members; 1566 final mset = context.findMembers(name).members;
1550 1567
1551 final targets = mset.filter((m) => m.canInvoke(context, args)); 1568 final targets = mset.filter((m) => m.canInvoke(context, args));
1552 final returnType = reduce(map(targets, (t) => t.returnType), Type.union); 1569 stub = new VarMethodSet(stubName, targets, args, _foldTypes(targets));
1553 stub = new VarMethodSet(stubName, targets, args, returnType);
1554 world.objectType.varStubs[stubName] = stub; 1570 world.objectType.varStubs[stubName] = stub;
1555 } 1571 }
1556 return stub; 1572 return stub;
1557 } 1573 }
1574
1575 Type _foldTypes(List<Member> targets) =>
1576 reduce(map(targets, (t) => t.returnType), Type.union, world.varType);
1558 } 1577 }
1559 1578
1560 /** 1579 /**
1561 * A [FactoryMap] maps type names to a list of factory constructors. 1580 * A [FactoryMap] maps type names to a list of factory constructors.
1562 * The constructors list is actually a map that maps factory names to 1581 * The constructors list is actually a map that maps factory names to
1563 * [MethodMember]. The reason why we need both indirections are: 1582 * [MethodMember]. The reason why we need both indirections are:
1564 * 1) A class can define factory methods for multiple interfaces. 1583 * 1) A class can define factory methods for multiple interfaces.
1565 * 2) A factory constructor can have a name. 1584 * 2) A factory constructor can have a name.
1566 * 1585 *
1567 * For example: 1586 * For example:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1615 } 1634 }
1616 1635
1617 void forEach(void f(Member member)) { 1636 void forEach(void f(Member member)) {
1618 factories.forEach((_, Map constructors) { 1637 factories.forEach((_, Map constructors) {
1619 constructors.forEach((_, Member member) { 1638 constructors.forEach((_, Member member) {
1620 f(member); 1639 f(member);
1621 }); 1640 });
1622 }); 1641 });
1623 } 1642 }
1624 } 1643 }
OLDNEW
« no previous file with comments | « frog/frogsh ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698