| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |