| OLD | NEW |
| 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 /** 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 Member method; | 8 Member method; |
| 9 | 9 |
| 10 String name; | 10 String name; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 // I hope this trust is well placed! | 153 // I hope this trust is well placed! |
| 154 return world.nonNullBool; | 154 return world.nonNullBool; |
| 155 } | 155 } |
| 156 return t; | 156 return t; |
| 157 } | 157 } |
| 158 | 158 |
| 159 Definition get definition() => null; | 159 Definition get definition() => null; |
| 160 | 160 |
| 161 List<Parameter> get parameters() => []; | 161 List<Parameter> get parameters() => []; |
| 162 | 162 |
| 163 MemberSet _preciseMemberSet, _potentialMemberSet; | |
| 164 | |
| 165 MemberSet get preciseMemberSet() { | |
| 166 if (_preciseMemberSet === null) { | |
| 167 _preciseMemberSet = new MemberSet(this); | |
| 168 } | |
| 169 return _preciseMemberSet; | |
| 170 } | |
| 171 | |
| 172 MemberSet get potentialMemberSet() { | |
| 173 if (_potentialMemberSet === null) { | |
| 174 if (declaringType.isObject) { | |
| 175 _potentialMemberSet = world._members[name]; | |
| 176 return _potentialMemberSet; | |
| 177 } | |
| 178 | |
| 179 final mems = new Set<Member>(); | |
| 180 if (declaringType.isClass) mems.add(this); | |
| 181 | |
| 182 | |
| 183 for (var subtype in declaringType.subtypes) { | |
| 184 if (!subtype.isClass) continue; | |
| 185 var mem = subtype.members[name]; | |
| 186 if (mem !== null) { | |
| 187 mems.add(mem); | |
| 188 } else if (!declaringType.isClass) { | |
| 189 // Handles weird interface case. | |
| 190 mem = subtype.getMember(name); | |
| 191 if (mem !== null) { | |
| 192 mems.add(mem); | |
| 193 } | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 if (mems.length != 0) { | |
| 198 for (var mem in mems) { | |
| 199 if (_potentialMemberSet === null) { | |
| 200 _potentialMemberSet = new MemberSet(mem); | |
| 201 } else { | |
| 202 _potentialMemberSet.add(mem); | |
| 203 } | |
| 204 } | |
| 205 } | |
| 206 } | |
| 207 return _potentialMemberSet; | |
| 208 } | |
| 209 | |
| 210 // If I have an object of [type] could I be invoking this member? | |
| 211 bool isDefinedOn(Type type) { | |
| 212 if (type.isClass) { | |
| 213 if (declaringType.isSubtypeOf(type)) { | |
| 214 return true; | |
| 215 } else if (type.isSubtypeOf(declaringType)) { | |
| 216 // maybe - but not if overridden somewhere | |
| 217 // !!! horrible hack for today - awful perf props | |
| 218 return type.getMember(name) == this; | |
| 219 //return true; | |
| 220 } else { | |
| 221 return false; | |
| 222 } | |
| 223 } else { | |
| 224 if (declaringType.isSubtypeOf(type)) { | |
| 225 return true; | |
| 226 } else { | |
| 227 // If this is an interface, the actual implementation may | |
| 228 // come from a class that does not implement this interface. | |
| 229 for (var t in declaringType.subtypes) { | |
| 230 if (t.isSubtypeOf(type) && t.getMember(name) == this) { | |
| 231 return true; | |
| 232 } | |
| 233 } | |
| 234 return false; | |
| 235 } | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 // TODO(jmesserly): isDynamic isn't a great name for this, something better? | 163 // TODO(jmesserly): isDynamic isn't a great name for this, something better? |
| 240 abstract Value _get(MethodGenerator context, Node node, Value target, | 164 abstract Value _get(MethodGenerator context, Node node, Value target, |
| 241 [bool isDynamic]); | 165 [bool isDynamic]); |
| 242 | 166 |
| 243 abstract Value _set(MethodGenerator context, Node node, Value target, | 167 abstract Value _set(MethodGenerator context, Node node, Value target, |
| 244 Value value, [bool isDynamic]); | 168 Value value, [bool isDynamic]); |
| 245 | 169 |
| 246 bool canInvoke(MethodGenerator context, Arguments args) { | 170 bool canInvoke(MethodGenerator context, Arguments args) { |
| 247 // No source location needed because canInvoke may not produce errors. | 171 // No source location needed because canInvoke may not produce errors. |
| 248 return canGet && | 172 return canGet && |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 | 267 |
| 344 bool isStatic; | 268 bool isStatic; |
| 345 bool isFinal; | 269 bool isFinal; |
| 346 bool isNative; | 270 bool isNative; |
| 347 | 271 |
| 348 // TODO(jimhug): Better notion of fields that need special handling... | 272 // TODO(jimhug): Better notion of fields that need special handling... |
| 349 bool get overridesProperty() { | 273 bool get overridesProperty() { |
| 350 if (isStatic) return false; | 274 if (isStatic) return false; |
| 351 | 275 |
| 352 if (declaringType.parent != null) { | 276 if (declaringType.parent != null) { |
| 353 var p = declaringType.parent.getProperty(name); | 277 var p = declaringType.parent.resolveMember(name); |
| 354 if (p != null && p.isProperty) return true; | 278 if (p != null && p.containsProperties) { |
| 355 if (p is FieldMember && p != this) return p.overridesProperty; | 279 return true; |
| 280 } |
| 356 } | 281 } |
| 357 return false; | 282 return false; |
| 358 } | 283 } |
| 359 | 284 |
| 360 bool override(Member other) { | 285 bool override(Member other) { |
| 361 if (!super.override(other)) return false; | 286 if (!super.override(other)) return false; |
| 362 | 287 |
| 363 // fields can override properties - but nothing else? | 288 // fields can override properties - but nothing else? |
| 364 if (other.isProperty) { | 289 if (other.isProperty) { |
| 365 // TODO(jimhug): | 290 // TODO(jimhug): |
| (...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1397 } | 1322 } |
| 1398 } | 1323 } |
| 1399 return _treatAsField; | 1324 return _treatAsField; |
| 1400 } | 1325 } |
| 1401 | 1326 |
| 1402 Value _get(MethodGenerator context, Node node, Value target, | 1327 Value _get(MethodGenerator context, Node node, Value target, |
| 1403 [bool isDynamic=false]) { | 1328 [bool isDynamic=false]) { |
| 1404 // If this is the global MemberSet from world, always bind dynamically. | 1329 // If this is the global MemberSet from world, always bind dynamically. |
| 1405 // Note: we need this for proper noSuchMethod and REPL behavior. | 1330 // Note: we need this for proper noSuchMethod and REPL behavior. |
| 1406 Value returnValue; | 1331 Value returnValue; |
| 1407 if (members.length == 1 && !isVar) { | |
| 1408 return members[0]._get(context, node, target, isDynamic); | |
| 1409 } | |
| 1410 | |
| 1411 | |
| 1412 final targets = members.filter((m) => m.canGet); | 1332 final targets = members.filter((m) => m.canGet); |
| 1413 if (isVar) { | 1333 if (isVar) { |
| 1414 targets.forEach((m) => m._get(context, node, target, isDynamic: true)); | 1334 targets.forEach((m) => m._get(context, node, target, isDynamic: true)); |
| 1415 returnValue = new Value(_foldTypes(targets), null, node.span); | 1335 returnValue = new Value(_foldTypes(targets), null, node.span); |
| 1416 } else { | 1336 } else { |
| 1417 if (members.length == 1) { | 1337 if (members.length == 1) { |
| 1418 return members[0]._get(context, node, target, isDynamic); | 1338 return members[0]._get(context, node, target, isDynamic); |
| 1419 } else if (targets.length == 1) { | 1339 } else if (targets.length == 1) { |
| 1420 return targets[0]._get(context, node, target, isDynamic); | 1340 return targets[0]._get(context, node, target, isDynamic); |
| 1421 } | 1341 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1438 node.span); | 1358 node.span); |
| 1439 } | 1359 } |
| 1440 } | 1360 } |
| 1441 return returnValue; | 1361 return returnValue; |
| 1442 } | 1362 } |
| 1443 | 1363 |
| 1444 Value _set(MethodGenerator context, Node node, Value target, Value value, | 1364 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 1445 [bool isDynamic=false]) { | 1365 [bool isDynamic=false]) { |
| 1446 // If this is the global MemberSet from world, always bind dynamically. | 1366 // If this is the global MemberSet from world, always bind dynamically. |
| 1447 // Note: we need this for proper noSuchMethod and REPL behavior. | 1367 // Note: we need this for proper noSuchMethod and REPL behavior. |
| 1448 if (members.length == 1 && !isVar) { | |
| 1449 return members[0]._set(context, node, target, value, isDynamic); | |
| 1450 } | |
| 1451 | |
| 1452 Value returnValue; | 1368 Value returnValue; |
| 1453 final targets = members.filter((m) => m.canSet); | 1369 final targets = members.filter((m) => m.canSet); |
| 1454 if (isVar) { | 1370 if (isVar) { |
| 1455 targets.forEach((m) => | 1371 targets.forEach((m) => |
| 1456 m._set(context, node, target, value, isDynamic: true)); | 1372 m._set(context, node, target, value, isDynamic: true)); |
| 1457 returnValue = new Value(_foldTypes(targets), null, node.span); | 1373 returnValue = new Value(_foldTypes(targets), null, node.span); |
| 1458 } else { | 1374 } else { |
| 1459 if (members.length == 1) { | 1375 if (members.length == 1) { |
| 1460 return members[0]._set(context, node, target, value, isDynamic); | 1376 return members[0]._set(context, node, target, value, isDynamic); |
| 1461 } else if (targets.length == 1) { | 1377 } else if (targets.length == 1) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1484 } | 1400 } |
| 1485 | 1401 |
| 1486 Value invoke(MethodGenerator context, Node node, Value target, | 1402 Value invoke(MethodGenerator context, Node node, Value target, |
| 1487 Arguments args, [bool isDynamic=false]) { | 1403 Arguments args, [bool isDynamic=false]) { |
| 1488 // If this is the global MemberSet from world, always bind dynamically. | 1404 // If this is the global MemberSet from world, always bind dynamically. |
| 1489 // Note: we need this for proper noSuchMethod and REPL behavior. | 1405 // Note: we need this for proper noSuchMethod and REPL behavior. |
| 1490 if (isVar && !isOperator) { | 1406 if (isVar && !isOperator) { |
| 1491 return invokeOnVar(context, node, target, args); | 1407 return invokeOnVar(context, node, target, args); |
| 1492 } | 1408 } |
| 1493 | 1409 |
| 1494 if (members.length == 1 && !isVar) { | 1410 if (members.length == 1) { |
| 1495 return members[0].invoke(context, node, target, args, isDynamic); | 1411 return members[0].invoke(context, node, target, args, isDynamic); |
| 1496 } | 1412 } |
| 1497 | |
| 1498 final targets = members.filter((m) => m.canInvoke(context, args)); | 1413 final targets = members.filter((m) => m.canInvoke(context, args)); |
| 1499 if (targets.length == 1) { | 1414 if (targets.length == 1) { |
| 1500 return targets[0].invoke(context, node, target, args, isDynamic); | 1415 return targets[0].invoke(context, node, target, args, isDynamic); |
| 1501 } | 1416 } |
| 1502 | 1417 |
| 1503 Value returnValue = null; | 1418 Value returnValue = null; |
| 1504 if (targets.length < 1000) { | 1419 for (var member in targets) { |
| 1505 for (var member in targets) { | 1420 final res = member.invoke(context, node, target, args, isDynamic:true); |
| 1506 final res = member.invoke(context, node, target, args, isDynamic:true); | 1421 // TODO(jmesserly): If the code has different type checks, it will fail to |
| 1507 // TODO(jmesserly): If the code has different type checks, it will fail
to | 1422 // unify and go through a dynamic stub. Good so far. However, we'll end |
| 1508 // unify and go through a dynamic stub. Good so far. However, we'll end | 1423 // up with a bogus unused temp generated (usually "var $0"). We need a way |
| 1509 // up with a bogus unused temp generated (usually "var $0"). We need a w
ay | 1424 // to throw away temps when we throw away the code. |
| 1510 // to throw away temps when we throw away the code. | 1425 returnValue = _tryUnion(returnValue, res, node); |
| 1511 returnValue = _tryUnion(returnValue, res, node); | 1426 } |
| 1512 } | |
| 1513 | 1427 |
| 1514 if (returnValue == null) { | 1428 if (returnValue == null) { |
| 1515 return _makeError(node, target, 'method'); | 1429 return _makeError(node, target, 'method'); |
| 1516 } | |
| 1517 } else { | |
| 1518 returnValue = new Value(world.varType, null, node.span); | |
| 1519 } | 1430 } |
| 1520 | 1431 |
| 1521 if (returnValue.code == null) { | 1432 if (returnValue.code == null) { |
| 1522 if (name == ':call') { | 1433 if (name == ':call') { |
| 1523 // TODO(jmesserly): reconcile this with similar code in Value | 1434 // TODO(jmesserly): reconcile this with similar code in Value |
| 1524 return target._varCall(context, node, args); | 1435 return target._varCall(context, node, args); |
| 1525 } else if (isOperator) { | 1436 } else if (isOperator) { |
| 1526 // TODO(jmesserly): make operators less special. | 1437 // TODO(jmesserly): make operators less special. |
| 1527 return invokeSpecial(target, args, returnValue.type); | 1438 return invokeSpecial(target, args, returnValue.type); |
| 1528 } else { | 1439 } else { |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1682 } | 1593 } |
| 1683 | 1594 |
| 1684 void forEach(void f(Member member)) { | 1595 void forEach(void f(Member member)) { |
| 1685 factories.forEach((_, Map constructors) { | 1596 factories.forEach((_, Map constructors) { |
| 1686 constructors.forEach((_, Member member) { | 1597 constructors.forEach((_, Member member) { |
| 1687 f(member); | 1598 f(member); |
| 1688 }); | 1599 }); |
| 1689 }); | 1600 }); |
| 1690 } | 1601 } |
| 1691 } | 1602 } |
| OLD | NEW |