Chromium Code Reviews| 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. | |
|
Jennifer Messerly
2012/01/18 00:03:00
might be worth expanding this comment :)
as I rea
| |
| 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 | |
| 163 // TODO(jmesserly): isDynamic isn't a great name for this, something better? | 239 // TODO(jmesserly): isDynamic isn't a great name for this, something better? |
| 164 abstract Value _get(MethodGenerator context, Node node, Value target, | 240 abstract Value _get(MethodGenerator context, Node node, Value target, |
| 165 [bool isDynamic]); | 241 [bool isDynamic]); |
| 166 | 242 |
| 167 abstract Value _set(MethodGenerator context, Node node, Value target, | 243 abstract Value _set(MethodGenerator context, Node node, Value target, |
| 168 Value value, [bool isDynamic]); | 244 Value value, [bool isDynamic]); |
| 169 | 245 |
| 170 bool canInvoke(MethodGenerator context, Arguments args) { | 246 bool canInvoke(MethodGenerator context, Arguments args) { |
| 171 // No source location needed because canInvoke may not produce errors. | 247 // No source location needed because canInvoke may not produce errors. |
| 172 return canGet && | 248 return canGet && |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 267 | 343 |
| 268 bool isStatic; | 344 bool isStatic; |
| 269 bool isFinal; | 345 bool isFinal; |
| 270 bool isNative; | 346 bool isNative; |
| 271 | 347 |
| 272 // TODO(jimhug): Better notion of fields that need special handling... | 348 // TODO(jimhug): Better notion of fields that need special handling... |
| 273 bool get overridesProperty() { | 349 bool get overridesProperty() { |
| 274 if (isStatic) return false; | 350 if (isStatic) return false; |
| 275 | 351 |
| 276 if (declaringType.parent != null) { | 352 if (declaringType.parent != null) { |
| 277 var p = declaringType.parent.resolveMember(name); | 353 var p = declaringType.parent.getProperty(name); |
| 278 if (p != null && p.containsProperties) { | 354 if (p != null && p.isProperty) return true; |
| 279 return true; | 355 if (p is FieldMember && p != this) return p.overridesProperty; |
| 280 } | |
| 281 } | 356 } |
| 282 return false; | 357 return false; |
| 283 } | 358 } |
| 284 | 359 |
| 285 bool override(Member other) { | 360 bool override(Member other) { |
| 286 if (!super.override(other)) return false; | 361 if (!super.override(other)) return false; |
| 287 | 362 |
| 288 // fields can override properties - but nothing else? | 363 // fields can override properties - but nothing else? |
| 289 if (other.isProperty) { | 364 if (other.isProperty) { |
| 290 // TODO(jimhug): | 365 // TODO(jimhug): |
| (...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1322 } | 1397 } |
| 1323 } | 1398 } |
| 1324 return _treatAsField; | 1399 return _treatAsField; |
| 1325 } | 1400 } |
| 1326 | 1401 |
| 1327 Value _get(MethodGenerator context, Node node, Value target, | 1402 Value _get(MethodGenerator context, Node node, Value target, |
| 1328 [bool isDynamic=false]) { | 1403 [bool isDynamic=false]) { |
| 1329 // If this is the global MemberSet from world, always bind dynamically. | 1404 // If this is the global MemberSet from world, always bind dynamically. |
| 1330 // Note: we need this for proper noSuchMethod and REPL behavior. | 1405 // Note: we need this for proper noSuchMethod and REPL behavior. |
| 1331 Value returnValue; | 1406 Value returnValue; |
| 1407 if (members.length == 1 && !isVar) { | |
| 1408 return members[0]._get(context, node, target, isDynamic); | |
| 1409 } | |
| 1410 | |
| 1411 | |
| 1332 final targets = members.filter((m) => m.canGet); | 1412 final targets = members.filter((m) => m.canGet); |
| 1333 if (isVar) { | 1413 if (isVar) { |
| 1334 targets.forEach((m) => m._get(context, node, target, isDynamic: true)); | 1414 targets.forEach((m) => m._get(context, node, target, isDynamic: true)); |
| 1335 returnValue = new Value(_foldTypes(targets), null, node.span); | 1415 returnValue = new Value(_foldTypes(targets), null, node.span); |
| 1336 } else { | 1416 } else { |
| 1337 if (members.length == 1) { | 1417 if (members.length == 1) { |
| 1338 return members[0]._get(context, node, target, isDynamic); | 1418 return members[0]._get(context, node, target, isDynamic); |
| 1339 } else if (targets.length == 1) { | 1419 } else if (targets.length == 1) { |
| 1340 return targets[0]._get(context, node, target, isDynamic); | 1420 return targets[0]._get(context, node, target, isDynamic); |
| 1341 } | 1421 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1358 node.span); | 1438 node.span); |
| 1359 } | 1439 } |
| 1360 } | 1440 } |
| 1361 return returnValue; | 1441 return returnValue; |
| 1362 } | 1442 } |
| 1363 | 1443 |
| 1364 Value _set(MethodGenerator context, Node node, Value target, Value value, | 1444 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 1365 [bool isDynamic=false]) { | 1445 [bool isDynamic=false]) { |
| 1366 // If this is the global MemberSet from world, always bind dynamically. | 1446 // If this is the global MemberSet from world, always bind dynamically. |
| 1367 // Note: we need this for proper noSuchMethod and REPL behavior. | 1447 // 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 | |
| 1368 Value returnValue; | 1452 Value returnValue; |
| 1369 final targets = members.filter((m) => m.canSet); | 1453 final targets = members.filter((m) => m.canSet); |
| 1370 if (isVar) { | 1454 if (isVar) { |
| 1371 targets.forEach((m) => | 1455 targets.forEach((m) => |
| 1372 m._set(context, node, target, value, isDynamic: true)); | 1456 m._set(context, node, target, value, isDynamic: true)); |
| 1373 returnValue = new Value(_foldTypes(targets), null, node.span); | 1457 returnValue = new Value(_foldTypes(targets), null, node.span); |
| 1374 } else { | 1458 } else { |
| 1375 if (members.length == 1) { | 1459 if (members.length == 1) { |
| 1376 return members[0]._set(context, node, target, value, isDynamic); | 1460 return members[0]._set(context, node, target, value, isDynamic); |
| 1377 } else if (targets.length == 1) { | 1461 } else if (targets.length == 1) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1400 } | 1484 } |
| 1401 | 1485 |
| 1402 Value invoke(MethodGenerator context, Node node, Value target, | 1486 Value invoke(MethodGenerator context, Node node, Value target, |
| 1403 Arguments args, [bool isDynamic=false]) { | 1487 Arguments args, [bool isDynamic=false]) { |
| 1404 // If this is the global MemberSet from world, always bind dynamically. | 1488 // If this is the global MemberSet from world, always bind dynamically. |
| 1405 // Note: we need this for proper noSuchMethod and REPL behavior. | 1489 // Note: we need this for proper noSuchMethod and REPL behavior. |
| 1406 if (isVar && !isOperator) { | 1490 if (isVar && !isOperator) { |
| 1407 return invokeOnVar(context, node, target, args); | 1491 return invokeOnVar(context, node, target, args); |
| 1408 } | 1492 } |
| 1409 | 1493 |
| 1410 if (members.length == 1) { | 1494 if (members.length == 1 && !isVar) { |
| 1411 return members[0].invoke(context, node, target, args, isDynamic); | 1495 return members[0].invoke(context, node, target, args, isDynamic); |
| 1412 } | 1496 } |
| 1497 | |
| 1413 final targets = members.filter((m) => m.canInvoke(context, args)); | 1498 final targets = members.filter((m) => m.canInvoke(context, args)); |
| 1414 if (targets.length == 1) { | 1499 if (targets.length == 1) { |
| 1415 return targets[0].invoke(context, node, target, args, isDynamic); | 1500 return targets[0].invoke(context, node, target, args, isDynamic); |
| 1416 } | 1501 } |
| 1417 | 1502 |
| 1418 Value returnValue = null; | 1503 Value returnValue = null; |
| 1419 for (var member in targets) { | 1504 if (targets.length < 1000) { |
|
Jennifer Messerly
2012/01/18 00:03:00
nice fix. I like having limits for all of these po
| |
| 1420 final res = member.invoke(context, node, target, args, isDynamic:true); | 1505 for (var member in targets) { |
| 1421 // TODO(jmesserly): If the code has different type checks, it will fail to | 1506 final res = member.invoke(context, node, target, args, isDynamic:true); |
| 1422 // unify and go through a dynamic stub. Good so far. However, we'll end | 1507 // TODO(jmesserly): If the code has different type checks, it will fail to |
| 1423 // up with a bogus unused temp generated (usually "var $0"). We need a way | 1508 // unify and go through a dynamic stub. Good so far. However, we'll end |
| 1424 // to throw away temps when we throw away the code. | 1509 // up with a bogus unused temp generated (usually "var $0"). We need a w ay |
| 1425 returnValue = _tryUnion(returnValue, res, node); | 1510 // to throw away temps when we throw away the code. |
| 1426 } | 1511 returnValue = _tryUnion(returnValue, res, node); |
| 1512 } | |
| 1427 | 1513 |
| 1428 if (returnValue == null) { | 1514 if (returnValue == null) { |
| 1429 return _makeError(node, target, 'method'); | 1515 return _makeError(node, target, 'method'); |
| 1516 } | |
| 1517 } else { | |
| 1518 returnValue = new Value(world.varType, null, node.span); | |
| 1430 } | 1519 } |
| 1431 | 1520 |
| 1432 if (returnValue.code == null) { | 1521 if (returnValue.code == null) { |
| 1433 if (name == ':call') { | 1522 if (name == ':call') { |
| 1434 // TODO(jmesserly): reconcile this with similar code in Value | 1523 // TODO(jmesserly): reconcile this with similar code in Value |
| 1435 return target._varCall(context, node, args); | 1524 return target._varCall(context, node, args); |
| 1436 } else if (isOperator) { | 1525 } else if (isOperator) { |
| 1437 // TODO(jmesserly): make operators less special. | 1526 // TODO(jmesserly): make operators less special. |
| 1438 return invokeSpecial(target, args, returnValue.type); | 1527 return invokeSpecial(target, args, returnValue.type); |
| 1439 } else { | 1528 } else { |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1593 } | 1682 } |
| 1594 | 1683 |
| 1595 void forEach(void f(Member member)) { | 1684 void forEach(void f(Member member)) { |
| 1596 factories.forEach((_, Map constructors) { | 1685 factories.forEach((_, Map constructors) { |
| 1597 constructors.forEach((_, Member member) { | 1686 constructors.forEach((_, Member member) { |
| 1598 f(member); | 1687 f(member); |
| 1599 }); | 1688 }); |
| 1600 }); | 1689 }); |
| 1601 } | 1690 } |
| 1602 } | 1691 } |
| OLD | NEW |