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 class MemberSet { | 5 class MemberSet { |
6 final String name; | 6 final String name; |
7 final List<Member> members; | 7 final List<Member> members; |
8 final bool isVar; | 8 final bool isVar; |
9 String jsname; | |
10 | 9 |
11 bool _treatAsField; | 10 bool _treatAsField; |
12 Type _returnTypeForGet; | 11 Type _returnTypeForGet; |
13 bool _preparedForSet = false; | 12 bool _preparedForSet = false; |
14 List<InvokeKey> _invokes; | 13 List<InvokeKey> _invokes; |
15 | 14 |
16 MemberSet(Member member, [bool isVar=false]): | 15 MemberSet(Member member, [bool isVar=false]) |
17 name = member.name, members = [member], jsname = member.jsname, | 16 : name = member.name, members = [member], isVar = isVar; |
18 isVar = isVar; | |
19 | 17 |
20 toString() => '$name:${members.length}'; | 18 toString() => '$name:${members.length}'; |
21 | 19 |
| 20 /** |
| 21 * [jsname] should be called only when it is known that all the members have |
| 22 * the same jsname. (The name safety pass can cause members of the same |
| 23 * MemberSet to have different jsnames.) |
| 24 */ |
| 25 String get jsname() => members[0].jsname; |
| 26 |
22 void add(Member member) { | 27 void add(Member member) { |
23 // Only methods on classes "really exist" - so warn if we add others? | 28 // Only methods on classes "really exist" - so warn if we add others? |
24 members.add(member); | 29 members.add(member); |
25 } | 30 } |
26 | 31 |
27 // TODO(jimhug): Better way to check for operator. | 32 // TODO(jimhug): Better way to check for operator. |
28 bool get isOperator() => members[0].isOperator; | 33 bool get isOperator() => members[0].isOperator; |
29 | 34 |
30 bool get treatAsField() { | 35 bool get treatAsField() { |
31 if (_treatAsField == null) { | 36 if (_treatAsField == null) { |
32 _treatAsField = !isVar && members.every((m) => m.isField); | 37 // Must be all fields, all with the same jsname. |
| 38 _treatAsField = !isVar && |
| 39 members.every((m) => m.isField && m.jsname == members[0].jsname); |
33 } | 40 } |
34 return _treatAsField; | 41 return _treatAsField; |
35 } | 42 } |
36 | 43 |
37 static Type unionTypes(Type t1, Type t2) { | 44 static Type unionTypes(Type t1, Type t2) { |
38 if (t1 == null) return t2; | 45 if (t1 == null) return t2; |
39 if (t2 == null) return t1; | 46 if (t2 == null) return t1; |
40 return Type.union(t1, t2); | 47 return Type.union(t1, t2); |
41 } | 48 } |
42 | 49 |
(...skipping 18 matching lines...) Expand all Loading... |
61 // TODO(jimhug): Need to make target less specific... | 68 // TODO(jimhug): Need to make target less specific... |
62 var r = member._get(context, node, target); | 69 var r = member._get(context, node, target); |
63 _returnTypeForGet = unionTypes(_returnTypeForGet, r.type); | 70 _returnTypeForGet = unionTypes(_returnTypeForGet, r.type); |
64 } | 71 } |
65 if (_returnTypeForGet == null) { | 72 if (_returnTypeForGet == null) { |
66 world.error('no valid getters for "$name"', node.span); | 73 world.error('no valid getters for "$name"', node.span); |
67 } | 74 } |
68 } | 75 } |
69 | 76 |
70 if (_treatAsField) { | 77 if (_treatAsField) { |
71 return new Value(_returnTypeForGet, '${target.code}.$jsname', | 78 return new Value(_returnTypeForGet, |
72 node.span); | 79 '${target.code}.$jsname', node.span); |
73 } else { | 80 } else { |
74 return new Value(_returnTypeForGet, '${target.code}.get\$$jsname()', | 81 return new Value(_returnTypeForGet, |
75 node.span); | 82 '${target.code}.${members[0].jsnameOfGetter}()', node.span); |
76 } | 83 } |
77 } | 84 } |
78 | 85 |
79 // TODO(jimhug): Return value of this method is unclear. | 86 // TODO(jimhug): Return value of this method is unclear. |
80 Value _set(CallingContext context, Node node, Value target, Value value) { | 87 Value _set(CallingContext context, Node node, Value target, Value value) { |
81 // If this is the global MemberSet from world, always bind dynamically. | 88 // If this is the global MemberSet from world, always bind dynamically. |
82 // Note: we need this for proper noSuchMethod and REPL behavior. | 89 // Note: we need this for proper noSuchMethod and REPL behavior. |
83 if (members.length == 1 && !isVar) { | 90 if (members.length == 1 && !isVar) { |
84 return members[0]._set(context, node, target, value); | 91 return members[0]._set(context, node, target, value); |
85 } | 92 } |
86 | 93 |
87 if (!_preparedForSet) { | 94 if (!_preparedForSet) { |
88 _preparedForSet = true; | 95 _preparedForSet = true; |
89 | 96 |
90 for (var member in members) { | 97 for (var member in members) { |
91 if (!member.canSet) continue; | 98 if (!member.canSet) continue; |
92 if (!treatAsField) member.provideSetter(); | 99 if (!treatAsField) member.provideSetter(); |
93 // !!! Need more generic args to this call below. | 100 // !!! Need more generic args to this call below. |
94 var r = member._set(context, node, target, value); | 101 var r = member._set(context, node, target, value); |
95 } | 102 } |
96 } | 103 } |
97 | 104 |
98 if (treatAsField) { | 105 if (treatAsField) { |
99 return new Value(value.type, | 106 return new Value(value.type, |
100 '${target.code}.$jsname = ${value.code}', node.span); | 107 '${target.code}.$jsname = ${value.code}', node.span); |
101 } else { | 108 } else { |
102 return new Value(value.type, | 109 return new Value(value.type, |
103 '${target.code}.set\$$jsname(${value.code})', node.span); | 110 '${target.code}.${members[0].jsnameOfSetter}(${value.code})', node.span)
; |
104 } | 111 } |
105 } | 112 } |
106 | 113 |
107 Value invoke(CallingContext context, Node node, Value target, | 114 Value invoke(CallingContext context, Node node, Value target, |
108 Arguments args) { | 115 Arguments args) { |
109 if (members.length == 1 && !isVar) { | 116 if (members.length == 1 && !isVar) { |
110 return members[0].invoke(context, node, target, args); | 117 return members[0].invoke(context, node, target, args); |
111 } | 118 } |
112 | 119 |
113 var invokeKey = null; | 120 var invokeKey = null; |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 returnType = world.varType; | 295 returnType = world.varType; |
289 } | 296 } |
290 } | 297 } |
291 } | 298 } |
292 if (returnType == null) { | 299 if (returnType == null) { |
293 // TODO(jimhug): Warning here for no match anywhere in the world? | 300 // TODO(jimhug): Warning here for no match anywhere in the world? |
294 returnType = world.varType; | 301 returnType = world.varType; |
295 } | 302 } |
296 } | 303 } |
297 } | 304 } |
OLD | NEW |