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

Side by Side Diff: frog/value.dart

Issue 9222001: cleanup resolveMember and get/set (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: prereview Created 8 years, 11 months 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/type.dart ('k') | frog/var_member.dart » ('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) 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 5
6 /** 6 /**
7 * Represents a meta-value for code generation. 7 * Represents a meta-value for code generation.
8 */ 8 */
9 class Value { 9 class Value {
10 /** The inferred (i.e. most precise) [Type] of the [Value]. */ 10 /** The inferred (i.e. most precise) [Type] of the [Value]. */
(...skipping 29 matching lines...) Expand all
40 * The statically declared [Type] of the [Value]. This type determines which 40 * The statically declared [Type] of the [Value]. This type determines which
41 * kind of static type warnings are issued. It's also the type that is used 41 * kind of static type warnings are issued. It's also the type that is used
42 * for generating type assertions (i.e. given `Foo x; ...; x = expr;`, 42 * for generating type assertions (i.e. given `Foo x; ...; x = expr;`,
43 * expr will be checked against "Foo" regardless of the inferred type of `x`). 43 * expr will be checked against "Foo" regardless of the inferred type of `x`).
44 */ 44 */
45 Type get staticType() => type; 45 Type get staticType() => type;
46 46
47 /** If [isConst], the [EvaluatedValue] that defines this value. */ 47 /** If [isConst], the [EvaluatedValue] that defines this value. */
48 EvaluatedValue get constValue() => null; 48 EvaluatedValue get constValue() => null;
49 49
50 static Value comma(Value x, Value y) {
51 return new Value(y.type, '(${x.code}, ${y.code})', null);
52 }
53
50 // TODO(jmesserly): more work is needed to make unifying all kinds of Values 54 // TODO(jmesserly): more work is needed to make unifying all kinds of Values
51 // work properly. 55 // work properly.
52 static Value union(Value x, Value y) { 56 static Value union(Value x, Value y) {
53 if (y === null || x == y) return x; 57 if (y === null || x == y) return x;
54 if (x === null) return y; 58 if (x === null) return y;
55 59
56 var ret = x._tryUnion(y); 60 var ret = x._tryUnion(y);
57 if (ret != null) return ret; 61 if (ret != null) return ret;
58 62
59 // TODO(jmesserly): might want to call a _tryUnionReversed here. 63 // TODO(jmesserly): might want to call a _tryUnionReversed here.
(...skipping 22 matching lines...) Expand all
82 Value get_(MethodGenerator context, String name, Node node) { 86 Value get_(MethodGenerator context, String name, Node node) {
83 final member = _resolveMember(context, name, node); 87 final member = _resolveMember(context, name, node);
84 if (member != null) { 88 if (member != null) {
85 return member._get(context, node, this); 89 return member._get(context, node, this);
86 } else { 90 } else {
87 return invokeNoSuchMethod(context, 'get:$name', node); 91 return invokeNoSuchMethod(context, 'get:$name', node);
88 } 92 }
89 } 93 }
90 94
91 Value set_(MethodGenerator context, String name, Node node, Value value, 95 Value set_(MethodGenerator context, String name, Node node, Value value,
92 [bool isDynamic=false]) { 96 [bool isDynamic=false, int kind=0, int returnKind=ReturnKind.IGNORE]) {
93
94 final member = _resolveMember(context, name, node, isDynamic); 97 final member = _resolveMember(context, name, node, isDynamic);
95 if (member != null) { 98 if (member != null) {
96 return member._set(context, node, this, value, isDynamic); 99 var thisValue = this;
100 var thisTmp = null;
101 var retTmp = null;
102 if (kind != 0) {
103 // TODO(jimhug): Very special number optimizations will go here...
104 thisTmp = context.getTemp(thisValue);
105 thisValue = context.assignTemp(thisTmp, thisValue);
106 var lhs = member._get(context, node, thisTmp);
107 if (returnKind == ReturnKind.PRE) {
108 retTmp = context.forceTemp(lhs);
109 lhs = context.assignTemp(retTmp, lhs);
110 }
111 value = lhs.binop(kind, value, context, node);
112 }
113
114 if (returnKind == ReturnKind.POST) {
115 // TODO(jimhug): Optimize this away when native JS is detected.
116 retTmp = context.forceTemp(value);
117 value = context.assignTemp(retTmp, value);
118 }
119
120 var ret = member._set(context, node, thisValue, value, isDynamic);
121 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp);
122 if (retTmp != null) {
123 context.freeTemp(retTmp);
124 return Value.comma(ret, retTmp);
125 } else {
126 return ret;
127 }
97 } else { 128 } else {
129 // TODO(jimhug): Need to support += and noSuchMethod better.
98 return invokeNoSuchMethod(context, 'set:$name', node, 130 return invokeNoSuchMethod(context, 'set:$name', node,
99 new Arguments(null, [value])); 131 new Arguments(null, [value]));
100 } 132 }
101 } 133 }
102 134
135 // TODO(jimhug): This method body has too much in common with set_ above.
136 Value setIndex(MethodGenerator context, Value index, Node node, Value value,
137 [bool isDynamic=false, int kind=0, int returnKind=ReturnKind.IGNORE]) {
138 final member = _resolveMember(context, ':setindex', node, isDynamic);
139 if (member != null) {
140 var thisValue = this;
141 var indexValue = index;
142 var thisTmp = null;
143 var indexTmp = null;
144 var retTmp = null;
145 if (returnKind == ReturnKind.POST) {
146 // TODO(jimhug): Optimize this away when native JS works.
147 retTmp = context.forceTemp(value);
148 }
149 if (kind != 0) {
150 // TODO(jimhug): Very special number optimizations will go here...
151 thisTmp = context.getTemp(this);
152 indexTmp = context.getTemp(index);
153 thisValue = context.assignTemp(thisTmp, thisValue);
154 indexValue = context.assignTemp(indexTmp, indexValue);
155
156 if (returnKind == ReturnKind.PRE) {
157 retTmp = context.forceTemp(value);
158 }
159
160 var lhs = thisTmp.invoke(context, ':index', node,
161 new Arguments(null, [indexTmp]));
162 if (returnKind == ReturnKind.PRE) {
163 lhs = context.assignTemp(retTmp, lhs);
164 }
165 value = lhs.binop(kind, value, context, node);
166 }
167 if (returnKind == ReturnKind.POST) {
168 value = context.assignTemp(retTmp, value);
169 }
170
171 var ret = member.invoke(context, node, thisValue,
172 new Arguments(null, [indexValue, value]), isDynamic);
173 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp);
174 if (indexTmp != null && indexTmp != index) context.freeTemp(indexTmp);
175 if (retTmp != null) {
176 context.freeTemp(retTmp);
177 return Value.comma(ret, retTmp);
178 } else {
179 return ret;
180 }
181 } else {
182 // TODO(jimhug): Need to support += and noSuchMethod better.
183 return invokeNoSuchMethod(context, ':index', node,
184 new Arguments(null, [index, value]));
185 }
186 }
187
188 //Value getIndex(MethodGenerator context, Value index, var node) {
189 //}
190
103 Value unop(int kind, MethodGenerator context, var node) { 191 Value unop(int kind, MethodGenerator context, var node) {
104 switch (kind) { 192 switch (kind) {
105 case TokenKind.NOT: 193 case TokenKind.NOT:
106 // TODO(jimhug): Issue #359 seeks to clarify this behavior. 194 // TODO(jimhug): Issue #359 seeks to clarify this behavior.
107 var newVal = convertTo(context, world.nonNullBool); 195 var newVal = convertTo(context, world.nonNullBool);
108 return new Value(newVal.type, '!${newVal.code}', node.span); 196 return new Value(newVal.type, '!${newVal.code}', node.span);
109 case TokenKind.ADD: 197 case TokenKind.ADD:
110 world.error('no unary add operator in dart', node.span); 198 world.error('no unary add operator in dart', node.span);
111 break; 199 break;
112 case TokenKind.SUB: 200 case TokenKind.SUB:
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 var member = _resolveMember(context, name, null, isDynamic:true); 262 var member = _resolveMember(context, name, null, isDynamic:true);
175 return member != null && member.canInvoke(context, args); 263 return member != null && member.canInvoke(context, args);
176 } 264 }
177 265
178 /** 266 /**
179 * True if this class (or some related class that is not Object) overrides 267 * True if this class (or some related class that is not Object) overrides
180 * noSuchMethod. If it does we suppress warnings about unknown members. 268 * noSuchMethod. If it does we suppress warnings about unknown members.
181 */ 269 */
182 // TODO(jmesserly): should we be doing this? 270 // TODO(jmesserly): should we be doing this?
183 bool _hasOverriddenNoSuchMethod() { 271 bool _hasOverriddenNoSuchMethod() {
184 if (isSuper) { 272 var m = type.getMember('noSuchMethod');
185 var m = staticType.getMember('noSuchMethod'); 273 return m != null && !m.declaringType.isObject;
186 return m != null && !m.declaringType.isObject; 274 }
187 } else { 275
188 var m = staticType.resolveMember('noSuchMethod'); 276 // TODO(jimhug): Handle more precise types here, i.e. consts or closed...
189 return m != null && m.members.length > 1; 277 bool get isPreciseType() => isSuper || isType;
278
279 void _missingMemberError(MethodGenerator context, String name, bool isDynamic, Node node) {
280 bool onStaticType = false;
281 if (type != staticType) {
282 onStaticType = staticType.getMember(name) !== null;
283 }
284
285 if (!onStaticType && !isDynamic &&
286 !_isVarOrParameterType(staticType) && !_hasOverriddenNoSuchMethod()) {
287 // warn if the member was not found, or error if it is a static lookup.
288 var typeName = staticType.name;
289 if (typeName == null) typeName = staticType.library.name;
290 var message = 'can not resolve "$name" on "${typeName}"';
291 if (isType) {
292 world.error(message, node.span);
293 } else {
294 world.warning(message, node.span);
295 }
190 } 296 }
191 } 297 }
192 298
193 _tryResolveMember(MethodGenerator context, Type resolvetype, String name) { 299
194 if (isSuper) { 300
195 return resolvetype.getMember(name); 301 MemberSet _tryResolveMember(MethodGenerator context, String name, bool isDynam ic, Node node) {
302 var member = type.getMember(name);
303 if (member == null) {
304 _missingMemberError(context, name, isDynamic, node);
305 return null;
196 } else { 306 } else {
197 return resolvetype.resolveMember(name); 307 if (isType && !member.isStatic) {
308 if (!isDynamic) {
309 world.error('can not refer to instance member as static', node.span);
310 }
311 return null;
312 }
313 }
314
315 if (isPreciseType || member.isStatic) {
316 return member.preciseMemberSet;
317 } else {
318 return member.potentialMemberSet;
198 } 319 }
199 } 320 }
200 321
201 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as 322 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as
202 // "var". 323 // "var".
203 bool _isVarOrParameterType(Type t) => t.isVar || t is ParameterType; 324 bool _isVarOrParameterType(Type t) => t.isVar || t is ParameterType;
204 325
205 bool _shouldBindDynamically() { 326 bool _shouldBindDynamically() {
206 return _isVarOrParameterType(type) || options.forceDynamic && !isConst; 327 return _isVarOrParameterType(type) || options.forceDynamic && !isConst;
207 } 328 }
208 329
209 // TODO(jimhug): Better type here - currently is union(Member, MemberSet) 330 // TODO(jimhug): Better type here - currently is union(Member, MemberSet)
210 _resolveMember(MethodGenerator context, String name, Node node, 331 MemberSet _resolveMember(MethodGenerator context, String name, Node node,
211 [bool isDynamic=false]) { 332 [bool isDynamic=false]) {
212 333 var member = null;
213 // TODO(jmesserly): this has gotten ugly again.
214 var member;
215 if (!_shouldBindDynamically()) { 334 if (!_shouldBindDynamically()) {
216 member = _tryResolveMember(context, type, name); 335 member = _tryResolveMember(context, name, isDynamic, node);
217
218 if (member == null && type != staticType) {
219 member = _tryResolveMember(context, staticType, name);
220 }
221
222 if (member != null && isType && !member.isStatic) {
223 if (!isDynamic) {
224 world.error('can not refer to instance member as static', node.span);
225 }
226 return null;
227 }
228
229 if (member == null && !isDynamic &&
230 !_isVarOrParameterType(staticType) && !_hasOverriddenNoSuchMethod()) {
231 // warn if the member was not found, or error if it is a static lookup.
232 var typeName = staticType.name;
233 if (typeName == null) typeName = staticType.library.name;
234 var message = 'can not resolve "$name" on "${typeName}"';
235 if (isType) {
236 world.error(message, node.span);
237 } else {
238 world.warning(message, node.span);
239 }
240 }
241 } 336 }
242 337
243 // Fall back to a dynamic operation for instance members 338 // Fall back to a dynamic operation for instance members
244 if (member == null && !isSuper && !isType) { 339 if (member == null && !isSuper && !isType) {
245 member = context.findMembers(name); 340 member = context.findMembers(name);
246 if (member == null && !isDynamic) { 341 if (member == null && !isDynamic) {
247 var where = 'the world'; 342 var where = 'the world';
248 if (name.startsWith('_')) { 343 if (name.startsWith('_')) {
249 where = 'library "${context.library.name}"'; 344 where = 'library "${context.library.name}"';
250 } 345 }
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 } 638 }
544 639
545 void convertWarning(Type toType) { 640 void convertWarning(Type toType) {
546 // TODO(jmesserly): better error messages for type conversion failures 641 // TODO(jmesserly): better error messages for type conversion failures
547 world.warning('type "${type.name}" is not assignable to "${toType.name}"', 642 world.warning('type "${type.name}" is not assignable to "${toType.name}"',
548 span); 643 span);
549 } 644 }
550 645
551 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node, 646 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node,
552 [Arguments args]) { 647 [Arguments args]) {
648 if (isType) {
649 world.error('member lookup failed for "$name"', node.span);
650 }
651
553 var pos = ''; 652 var pos = '';
554 if (args != null) { 653 if (args != null) {
555 var argsCode = []; 654 var argsCode = [];
556 for (int i = 0; i < args.length; i++) { 655 for (int i = 0; i < args.length; i++) {
557 argsCode.add(args.values[i].code); 656 argsCode.add(args.values[i].code);
558 } 657 }
559 pos = Strings.join(argsCode, ", "); // don't remove trailing nulls 658 pos = Strings.join(argsCode, ", "); // don't remove trailing nulls
560 } 659 }
561 final noSuchArgs = [ 660 final noSuchArgs = [
562 new Value(world.stringType, '"$name"', node.span), 661 new Value(world.stringType, '"$name"', node.span),
(...skipping 666 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 bool get needsTemp() => false; 1328 bool get needsTemp() => false;
1230 bool _shouldBindDynamically() => false; 1329 bool _shouldBindDynamically() => false;
1231 1330
1232 String get code() => _code; 1331 String get code() => _code;
1233 1332
1234 // TODO(jimhug): Lazy initialization here is weird! 1333 // TODO(jimhug): Lazy initialization here is weird!
1235 void _ensureCode() { 1334 void _ensureCode() {
1236 if (_code === null) _code = isType ? type.jsname : home._makeThisCode(); 1335 if (_code === null) _code = isType ? type.jsname : home._makeThisCode();
1237 } 1336 }
1238 1337
1239 _tryResolveMember(MethodGenerator context, Type resolveType, String name) { 1338 MemberSet _tryResolveMember(MethodGenerator context, String name, bool isDynam ic, Node node) {
1240 assert(context == home); 1339 assert(context == home);
1241 1340
1242 // First look for members directly defined on my resolveType. 1341 // TODO(jimhug): Confirm this matches final resolution of issue 641.
1243 var member = resolveType.resolveMember(name); 1342 var member = type.getMember(name);
1244 if (member != null) { 1343 if (member == null || member.declaringType != type) {
1245 if (options.forceDynamic && !member.isStatic) { 1344 var libMember = home.library.lookup(name, span);
1246 member = context.findMembers(name); 1345 if (libMember !== null) {
1346 return libMember.preciseMemberSet;
1247 } 1347 }
1248 _ensureCode();
1249 return member;
1250 }
1251
1252 // Then look for members in my library.
1253 member = home.library.lookup(name, span);
1254 if (member != null) {
1255 return member;
1256 } 1348 }
1257 1349
1258 _ensureCode(); 1350 _ensureCode();
1259 return null; 1351 return super._tryResolveMember(context, name, isDynamic, node);
1260 } 1352 }
1261 } 1353 }
1262 1354
1263 /** A reference to 'super'. */ 1355 /** A reference to 'super'. */
1264 // TODO(jmesserly): override resolveMember to clean up the one on Value 1356 // TODO(jmesserly): override resolveMember to clean up the one on Value
1265 class SuperValue extends Value { 1357 class SuperValue extends Value {
1266 SuperValue(Type parentType, SourceSpan span): 1358 SuperValue(Type parentType, SourceSpan span):
1267 super(parentType, 'this', span); 1359 super(parentType, 'this', span);
1268 1360
1269 bool get needsTemp() => false; 1361 bool get needsTemp() => false;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1374 } 1466 }
1375 return super.unop(kind, context, node); 1467 return super.unop(kind, context, node);
1376 } 1468 }
1377 Value binop(int kind, var other, MethodGenerator context, var node) { 1469 Value binop(int kind, var other, MethodGenerator context, var node) {
1378 if (value != null) { 1470 if (value != null) {
1379 return replaceValue(value.binop(kind, _unwrap(other), context, node)); 1471 return replaceValue(value.binop(kind, _unwrap(other), context, node));
1380 } 1472 }
1381 return super.binop(kind, other, context, node); 1473 return super.binop(kind, other, context, node);
1382 } 1474 }
1383 } 1475 }
OLDNEW
« no previous file with comments | « frog/type.dart ('k') | frog/var_member.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698