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

Side by Side Diff: frog/value.dart

Issue 9270048: Lots of frog cleanup (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
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 interface CallingContext {
7 MemberSet findMembers(String name);
8 CounterLog get counters();
9 Library get library();
10 bool get isStatic();
11 MethodMember get method();
12
13 bool get needsCode();
14 bool get showWarnings();
15
16 // Hopefully remove the 5 members below that are only used for code gen.
17 String _makeThisCode();
18
19 Value getTemp(Value value);
20 VariableValue forceTemp(Value value);
21 Value assignTemp(Value tmp, Value v);
22 void freeTemp(VariableValue value);
23 }
24
25 // TODO(jimhug): Value needs better separation into three parts:
26 // 1. Static analysis
27 // 2. Type inferred abstract interpretation analysis
28 // 3. Actual code generation
29 /**
30 * This subtype of value is the one and only version used for static
31 * analysis. It has no code and its type is always the static type.
32 */
33 class PureStaticValue extends Value {
34 bool isConst;
35 bool isType;
36
37 // TODO(jimhug): Can we remove span?
38 PureStaticValue(Type type, SourceSpan span,
39 [this.isConst = false, this.isType = false]):
40 super(type, null, span);
41
42 Member getMem(CallingContext context, String name, Node node) {
43 var member = type.getMember(name);
44
45 if (member == null) {
46 world.warning('can not find "$name" on "${type.name}"', node.span);
47 }
48
49 if (isType && !member.isStatic) {
50 world.error('can not refer to instance member as static', node.span);
51 }
52
53 return member;
54 }
55
56 Value get_(CallingContext context, String name, Node node) {
57 if (type.isVar) return new PureStaticValue(world.varType, node.span);
58 var member = getMem(context, name, node);
59 if (member == null) return new PureStaticValue(world.varType, node.span);
60
61 return member._get(context, node, this);
62 }
63
64 Value set_(CallingContext context, String name, Node node, Value value,
65 [int kind=0, int returnKind=ReturnKind.IGNORE]) {
66 if (type.isVar) return new PureStaticValue(world.varType, node.span);
67
68 var member = getMem(context, name, node);
69 if (member != null) {
70 member._set(context, node, this, value);
71 }
72 return new PureStaticValue(value.type, node.span);
73 }
74
75 Value setIndex(CallingContext context, Value index, Node node, Value value,
76 [int kind=0, int returnKind=ReturnKind.IGNORE]) {
77 return invoke(context, ':setindex', node,
78 new Arguments(null, [index, value]));
79 }
80
81 Value unop(int kind, CallingContext context, var node) {
82 switch (kind) {
83 case TokenKind.NOT:
84 // TODO(jimhug): Issue #359 seeks to clarify this behavior.
85 // ?var newVal = convertTo(context, world.nonNullBool);
86 return new PureStaticValue(world.boolType, node.span);
87 case TokenKind.ADD:
88 if (!isConst && !type.isNum) {
89 world.error('no unary add operator in dart', node.span);
90 }
91 return new PureStaticValue(world.numType, node.span);
92 case TokenKind.SUB:
93 return invoke(context, ':negate', node, Arguments.EMPTY);
94 case TokenKind.BIT_NOT:
95 return invoke(context, ':bit_not', node, Arguments.EMPTY);
96 }
97 world.internalError('unimplemented: ${node.op}', node.span);
98 }
99
100 Value binop(int kind, Value other, CallingContext context, var node) {
101 var isConst = isConst && other.isConst;
102
103
104 switch (kind) {
105 case TokenKind.AND:
106 case TokenKind.OR:
107 return new PureStaticValue(world.boolType, node.span, isConst);
108 case TokenKind.EQ_STRICT:
109 return new PureStaticValue(world.boolType, node.span, isConst);
110 case TokenKind.NE_STRICT:
111 return new PureStaticValue(world.boolType, node.span, isConst);
112 }
113
114 var name = kind == TokenKind.NE ? ':ne': TokenKind.binaryMethodName(kind);
115 var ret = invoke(context, name, node, new Arguments(null, [other]));
116 if (isConst) {
117 ret = new PureStaticValue(ret.type, node.span, isConst);
118 }
119 return ret;
120 }
121
122
123 Value invoke(CallingContext context, String name, Node node,
124 Arguments args) {
125 if (type.isVar) return new PureStaticValue(world.varType, node.span);
126 if (type.isFunction && name == ':call') {
127 return new PureStaticValue(world.varType, node.span);
128 }
129
130 var member = getMem(context, name, node);
131 if (member == null) return new PureStaticValue(world.varType, node.span);
132
133 return member.invoke(context, node, this, args);
134 }
135 }
136
137
6 /** 138 /**
7 * Represents a meta-value for code generation. 139 * Represents a meta-value for code generation.
8 */ 140 */
9 class Value { 141 class Value {
10 /** The inferred (i.e. most precise) [Type] of the [Value]. */ 142 /** The inferred (i.e. most precise) [Type] of the [Value]. */
11 final Type type; 143 final Type type;
12 144
13 /** The javascript code to generate this value. */ 145 /** The javascript code to generate this value. */
14 final String code; 146 final String code;
15 147
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 Value _tryUnion(Value right) => null; 208 Value _tryUnion(Value right) => null;
77 209
78 // TODO(jimhug): remove once type system works better. 210 // TODO(jimhug): remove once type system works better.
79 setField(Member field, Value value, [bool duringInit = false]) { } 211 setField(Member field, Value value, [bool duringInit = false]) { }
80 212
81 // Nothing to do in general? 213 // Nothing to do in general?
82 validateInitialized(SourceSpan span) { } 214 validateInitialized(SourceSpan span) { }
83 215
84 // TODO(jimhug): Fix these names once get/set are truly pseudo-keywords. 216 // TODO(jimhug): Fix these names once get/set are truly pseudo-keywords.
85 // See issue #379. 217 // See issue #379.
86 Value get_(MethodGenerator context, String name, Node node) { 218 Value get_(CallingContext context, String name, Node node) {
87 final member = _resolveMember(context, name, node); 219 final member = _resolveMember(context, name, node);
88 if (member != null) { 220 if (member != null) {
89 return member._get(context, node, this); 221 return member._get(context, node, this);
90 } else { 222 } else {
91 return invokeNoSuchMethod(context, 'get:$name', node); 223 return invokeNoSuchMethod(context, 'get:$name', node);
92 } 224 }
93 } 225 }
94 226
95 Value set_(MethodGenerator context, String name, Node node, Value value, 227 Value set_(CallingContext context, String name, Node node, Value value,
96 [bool isDynamic=false, int kind=0, int returnKind=ReturnKind.IGNORE]) { 228 [int kind=0, int returnKind=ReturnKind.IGNORE]) {
97 final member = _resolveMember(context, name, node, isDynamic); 229 final member = _resolveMember(context, name, node);
98 if (member != null) { 230 if (member != null) {
99 var thisValue = this; 231 var thisValue = this;
100 var thisTmp = null; 232 var thisTmp = null;
101 var retTmp = null; 233 var retTmp = null;
102 if (kind != 0) { 234 if (kind != 0) {
103 // TODO(jimhug): Very special number optimizations will go here... 235 // TODO(jimhug): Very special number optimizations will go here...
104 thisTmp = context.getTemp(thisValue); 236 thisTmp = context.getTemp(thisValue);
105 thisValue = context.assignTemp(thisTmp, thisValue); 237 thisValue = context.assignTemp(thisTmp, thisValue);
106 var lhs = member._get(context, node, thisTmp); 238 var lhs = member._get(context, node, thisTmp);
107 if (returnKind == ReturnKind.PRE) { 239 if (returnKind == ReturnKind.PRE) {
108 retTmp = context.forceTemp(lhs); 240 retTmp = context.forceTemp(lhs);
109 lhs = context.assignTemp(retTmp, lhs); 241 lhs = context.assignTemp(retTmp, lhs);
110 } 242 }
111 value = lhs.binop(kind, value, context, node); 243 value = lhs.binop(kind, value, context, node);
112 } 244 }
113 245
114 if (returnKind == ReturnKind.POST) { 246 if (returnKind == ReturnKind.POST) {
115 // TODO(jimhug): Optimize this away when native JS is detected. 247 // TODO(jimhug): Optimize this away when native JS is detected.
116 retTmp = context.forceTemp(value); 248 retTmp = context.forceTemp(value);
117 value = context.assignTemp(retTmp, value); 249 value = context.assignTemp(retTmp, value);
118 } 250 }
119 251
120 var ret = member._set(context, node, thisValue, value, isDynamic); 252 var ret = member._set(context, node, thisValue, value);
121 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp); 253 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp);
122 if (retTmp != null) { 254 if (retTmp != null) {
123 context.freeTemp(retTmp); 255 context.freeTemp(retTmp);
124 return Value.comma(ret, retTmp); 256 return Value.comma(ret, retTmp);
125 } else { 257 } else {
126 return ret; 258 return ret;
127 } 259 }
128 } else { 260 } else {
129 // TODO(jimhug): Need to support += and noSuchMethod better. 261 // TODO(jimhug): Need to support += and noSuchMethod better.
130 return invokeNoSuchMethod(context, 'set:$name', node, 262 return invokeNoSuchMethod(context, 'set:$name', node,
131 new Arguments(null, [value])); 263 new Arguments(null, [value]));
132 } 264 }
133 } 265 }
134 266
135 // TODO(jimhug): This method body has too much in common with set_ above. 267 // TODO(jimhug): This method body has too much in common with set_ above.
136 Value setIndex(MethodGenerator context, Value index, Node node, Value value, 268 Value setIndex(CallingContext context, Value index, Node node, Value value,
137 [bool isDynamic=false, int kind=0, int returnKind=ReturnKind.IGNORE]) { 269 [int kind=0, int returnKind=ReturnKind.IGNORE]) {
138 final member = _resolveMember(context, ':setindex', node, isDynamic); 270 final member = _resolveMember(context, ':setindex', node);
139 if (member != null) { 271 if (member != null) {
140 var thisValue = this; 272 var thisValue = this;
141 var indexValue = index; 273 var indexValue = index;
142 var thisTmp = null; 274 var thisTmp = null;
143 var indexTmp = null; 275 var indexTmp = null;
144 var retTmp = null; 276 var retTmp = null;
145 if (returnKind == ReturnKind.POST) { 277 if (returnKind == ReturnKind.POST) {
146 // TODO(jimhug): Optimize this away when native JS works. 278 // TODO(jimhug): Optimize this away when native JS works.
147 retTmp = context.forceTemp(value); 279 retTmp = context.forceTemp(value);
148 } 280 }
(...skipping 13 matching lines...) Expand all
162 if (returnKind == ReturnKind.PRE) { 294 if (returnKind == ReturnKind.PRE) {
163 lhs = context.assignTemp(retTmp, lhs); 295 lhs = context.assignTemp(retTmp, lhs);
164 } 296 }
165 value = lhs.binop(kind, value, context, node); 297 value = lhs.binop(kind, value, context, node);
166 } 298 }
167 if (returnKind == ReturnKind.POST) { 299 if (returnKind == ReturnKind.POST) {
168 value = context.assignTemp(retTmp, value); 300 value = context.assignTemp(retTmp, value);
169 } 301 }
170 302
171 var ret = member.invoke(context, node, thisValue, 303 var ret = member.invoke(context, node, thisValue,
172 new Arguments(null, [indexValue, value]), isDynamic); 304 new Arguments(null, [indexValue, value]));
173 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp); 305 if (thisTmp != null && thisTmp != this) context.freeTemp(thisTmp);
174 if (indexTmp != null && indexTmp != index) context.freeTemp(indexTmp); 306 if (indexTmp != null && indexTmp != index) context.freeTemp(indexTmp);
175 if (retTmp != null) { 307 if (retTmp != null) {
176 context.freeTemp(retTmp); 308 context.freeTemp(retTmp);
177 return Value.comma(ret, retTmp); 309 return Value.comma(ret, retTmp);
178 } else { 310 } else {
179 return ret; 311 return ret;
180 } 312 }
181 } else { 313 } else {
182 // TODO(jimhug): Need to support += and noSuchMethod better. 314 // TODO(jimhug): Need to support += and noSuchMethod better.
183 return invokeNoSuchMethod(context, ':index', node, 315 return invokeNoSuchMethod(context, ':index', node,
184 new Arguments(null, [index, value])); 316 new Arguments(null, [index, value]));
185 } 317 }
186 } 318 }
187 319
188 //Value getIndex(MethodGenerator context, Value index, var node) { 320 //Value getIndex(CallingContext context, Value index, var node) {
189 //} 321 //}
190 322
191 Value unop(int kind, MethodGenerator context, var node) { 323 Value unop(int kind, CallingContext context, var node) {
192 switch (kind) { 324 switch (kind) {
193 case TokenKind.NOT: 325 case TokenKind.NOT:
194 // TODO(jimhug): Issue #359 seeks to clarify this behavior. 326 // TODO(jimhug): Issue #359 seeks to clarify this behavior.
195 var newVal = convertTo(context, world.nonNullBool); 327 var newVal = convertTo(context, world.nonNullBool);
196 return new Value(newVal.type, '!${newVal.code}', node.span); 328 return new Value(newVal.type, '!${newVal.code}', node.span);
197 case TokenKind.ADD: 329 case TokenKind.ADD:
198 world.error('no unary add operator in dart', node.span); 330 world.error('no unary add operator in dart', node.span);
199 break; 331 break;
200 case TokenKind.SUB: 332 case TokenKind.SUB:
201 return invoke(context, ':negate', node, Arguments.EMPTY); 333 return invoke(context, ':negate', node, Arguments.EMPTY);
202 case TokenKind.BIT_NOT: 334 case TokenKind.BIT_NOT:
203 return invoke(context, ':bit_not', node, Arguments.EMPTY); 335 return invoke(context, ':bit_not', node, Arguments.EMPTY);
204 } 336 }
205 world.internalError('unimplemented: ${node.op}', node.span); 337 world.internalError('unimplemented: ${node.op}', node.span);
206 } 338 }
207 339
208 Value binop(int kind, Value other, MethodGenerator context, var node) { 340 bool _mayOverrideEqual() {
341 // TODO(jimhug): Need to check subtypes as well
342 return type.isVar || type.isObject ||
343 !type.getMember(':eq').declaringType.isObject;
344 }
345
346 Value binop(int kind, Value other, CallingContext context, var node) {
209 switch (kind) { 347 switch (kind) {
210 case TokenKind.AND: 348 case TokenKind.AND:
211 case TokenKind.OR: 349 case TokenKind.OR:
212 final code = '${code} ${node.op} ${other.code}'; 350 final code = '${code} ${node.op} ${other.code}';
213 return new Value(world.nonNullBool, code, node.span); 351 return new Value(world.nonNullBool, code, node.span);
214 // TODO(jimhug): Lot's to resolve here. 352 // TODO(jimhug): Wrong on primitives, need new fix for null == undefined
215 case TokenKind.EQ_STRICT: 353 case TokenKind.EQ_STRICT:
216 return new Value(world.nonNullBool, '${code} == ${other.code}', 354 return new Value(world.nonNullBool, '${code} == ${other.code}',
217 node.span); 355 node.span);
218 case TokenKind.NE_STRICT: 356 case TokenKind.NE_STRICT:
219 return new Value(world.nonNullBool, '${code} != ${other.code}', 357 return new Value(world.nonNullBool, '${code} != ${other.code}',
220 node.span); 358 node.span);
359
360 case TokenKind.EQ:
361 if (other.code == 'null') {
362 if (!_mayOverrideEqual()) {
363 return new Value(world.nonNullBool, '${code} == ${other.code}',
364 node.span);
365 }
366 } else if (code == 'null') {
367 return new Value(world.nonNullBool, '${code} == ${other.code}',
368 node.span);
369 }
370 break;
371 case TokenKind.NE:
372 if (other.code == 'null') {
373 if (!_mayOverrideEqual()) {
374 return new Value(world.nonNullBool, '${code} != ${other.code}',
375 node.span);
376 }
377 } else if (code == 'null') {
378 return new Value(world.nonNullBool, '${code} != ${other.code}',
379 node.span);
380 }
381 break;
382
221 } 383 }
222 384
223 var name = kind == TokenKind.NE ? ':ne': TokenKind.binaryMethodName(kind); 385 var name = kind == TokenKind.NE ? ':ne': TokenKind.binaryMethodName(kind);
224 return invoke(context, name, node, new Arguments(null, [other])); 386 return invoke(context, name, node, new Arguments(null, [other]));
225 } 387 }
226 388
227 389
228 Value invoke(MethodGenerator context, String name, Node node, Arguments args, 390 Value invoke(CallingContext context, String name, Node node,
229 [bool isDynamic=false]) { 391 Arguments args) {
230
231 // TODO(jmesserly): it'd be nice to remove these special cases 392 // TODO(jmesserly): it'd be nice to remove these special cases
232 // We could create a :call in world members, and have that handle the 393 // We could create a :call in world members, and have that handle the
233 // canInvoke/Invoke logic. 394 // canInvoke/Invoke logic.
234 395
235 // Note: this check is a little different than the one in canInvoke, because 396 // Note: this check is a little different than the one in canInvoke, because
236 // sometimes we need to call dynamically even if we found the :call method 397 // sometimes we need to call dynamically even if we found the :call method
237 // statically. 398 // statically.
238 399
239 if (name == ':call') { 400 if (name == ':call') {
240 if (isType) { 401 if (isType) {
241 world.error('must use "new" or "const" to construct a new instance', 402 world.error('must use "new" or "const" to construct a new instance',
242 node.span); 403 node.span);
243 } 404 }
244 if (type.needsVarCall(args)) { 405 if (type.needsVarCall(args)) {
245 return _varCall(context, node, args); 406 return _varCall(context, node, args);
246 } 407 }
247 } 408 }
248 409
249 var member = _resolveMember(context, name, node, isDynamic); 410 var member = _resolveMember(context, name, node);
250 if (member == null) { 411 if (member == null) {
251 return invokeNoSuchMethod(context, name, node, args); 412 return invokeNoSuchMethod(context, name, node, args);
252 } else { 413 } else {
253 return member.invoke(context, node, this, args, isDynamic); 414 return member.invoke(context, node, this, args);
254 } 415 }
255 } 416 }
256 417
257 bool canInvoke(MethodGenerator context, String name, Arguments args) {
258 if (type.isVarOrFunction && name == ':call') {
259 return true;
260 }
261
262 var member = _resolveMember(context, name, null, isDynamic:true);
263 return member != null && member.canInvoke(context, args);
264 }
265
266 /** 418 /**
267 * True if this class (or some related class that is not Object) overrides 419 * True if this class (or some related class that is not Object) overrides
268 * noSuchMethod. If it does we suppress warnings about unknown members. 420 * noSuchMethod. If it does we suppress warnings about unknown members.
269 */ 421 */
270 // TODO(jmesserly): should we be doing this? 422 // TODO(jmesserly): should we be doing this?
271 bool _hasOverriddenNoSuchMethod() { 423 bool _hasOverriddenNoSuchMethod() {
272 var m = type.getMember('noSuchMethod'); 424 var m = type.getMember('noSuchMethod');
273 return m != null && !m.declaringType.isObject; 425 return m != null && !m.declaringType.isObject;
274 } 426 }
275 427
276 // TODO(jimhug): Handle more precise types here, i.e. consts or closed... 428 // TODO(jimhug): Handle more precise types here, i.e. consts or closed...
277 bool get isPreciseType() => isSuper || isType; 429 bool get isPreciseType() => isSuper || isType;
278 430
279 void _missingMemberError(MethodGenerator context, String name, bool isDynamic, Node node) { 431 void _missingMemberError(CallingContext context, String name, Node node) {
280 bool onStaticType = false; 432 bool onStaticType = false;
281 if (type != staticType) { 433 if (type != staticType) {
282 onStaticType = staticType.getMember(name) !== null; 434 onStaticType = staticType.getMember(name) !== null;
283 } 435 }
284 436
285 if (!onStaticType && !isDynamic && 437 if (!onStaticType && context.showWarnings &&
286 !_isVarOrParameterType(staticType) && !_hasOverriddenNoSuchMethod()) { 438 !_isVarOrParameterType(staticType) && !_hasOverriddenNoSuchMethod()) {
287 // warn if the member was not found, or error if it is a static lookup. 439 // warn if the member was not found, or error if it is a static lookup.
288 var typeName = staticType.name; 440 var typeName = staticType.name;
289 if (typeName == null) typeName = staticType.library.name; 441 if (typeName == null) typeName = staticType.library.name;
290 var message = 'can not resolve "$name" on "${typeName}"'; 442 var message = 'can not resolve "$name" on "${typeName}"';
291 if (isType) { 443 if (isType) {
292 world.error(message, node.span); 444 world.error(message, node.span);
293 } else { 445 } else {
294 world.warning(message, node.span); 446 world.warning(message, node.span);
295 } 447 }
296 } 448 }
297 } 449 }
298 450
299 451
300 452
301 MemberSet _tryResolveMember(MethodGenerator context, String name, bool isDynam ic, Node node) { 453 MemberSet _tryResolveMember(CallingContext context, String name, Node node) {
302 var member = type.getMember(name); 454 var member = type.getMember(name);
303 if (member == null) { 455 if (member == null) {
304 _missingMemberError(context, name, isDynamic, node); 456 _missingMemberError(context, name, node);
305 return null; 457 return null;
306 } else { 458 } else {
307 if (isType && !member.isStatic) { 459 if (isType && !member.isStatic && context.showWarnings) {
308 if (!isDynamic) { 460 world.error('can not refer to instance member as static', node.span);
309 world.error('can not refer to instance member as static', node.span);
310 }
311 return null; 461 return null;
312 } 462 }
313 } 463 }
314 464
315 if (isPreciseType || member.isStatic) { 465 if (isPreciseType || member.isStatic) {
316 return member.preciseMemberSet; 466 return member.preciseMemberSet;
317 } else { 467 } else {
318 return member.potentialMemberSet; 468 return member.potentialMemberSet;
319 } 469 }
320 } 470 }
321 471
322 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as 472 // TODO(jmesserly): until reified generics are fixed, treat ParameterType as
323 // "var". 473 // "var".
324 bool _isVarOrParameterType(Type t) => t.isVar || t is ParameterType; 474 bool _isVarOrParameterType(Type t) => t.isVar || t is ParameterType;
325 475
326 bool _shouldBindDynamically() { 476 bool _shouldBindDynamically() {
327 return _isVarOrParameterType(type) || options.forceDynamic && !isConst; 477 return _isVarOrParameterType(type) || options.forceDynamic && !isConst;
328 } 478 }
329 479
330 // TODO(jimhug): Better type here - currently is union(Member, MemberSet) 480 // TODO(jimhug): Better type here - currently is union(Member, MemberSet)
331 MemberSet _resolveMember(MethodGenerator context, String name, Node node, 481 MemberSet _resolveMember(CallingContext context, String name, Node node) {
332 [bool isDynamic=false]) {
333 var member = null; 482 var member = null;
334 if (!_shouldBindDynamically()) { 483 if (!_shouldBindDynamically()) {
335 member = _tryResolveMember(context, name, isDynamic, node); 484 member = _tryResolveMember(context, name, node);
336 } 485 }
337 486
338 // Fall back to a dynamic operation for instance members 487 // Fall back to a dynamic operation for instance members
339 if (member == null && !isSuper && !isType) { 488 if (member == null && !isSuper && !isType) {
340 member = context.findMembers(name); 489 member = context.findMembers(name);
341 if (member == null && !isDynamic) { 490 if (member == null && context.showWarnings) {
342 var where = 'the world'; 491 var where = 'the world';
343 if (name.startsWith('_')) { 492 if (name.startsWith('_')) {
344 where = 'library "${context.library.name}"'; 493 where = 'library "${context.library.name}"';
345 } 494 }
346 world.warning('$name is not defined anywhere in $where.', 495 world.warning('$name is not defined anywhere in $where.',
347 node.span); 496 node.span);
348 } 497 }
349 } 498 }
350 499
351 return member; 500 return member;
352 } 501 }
353 502
354 checkFirstClass(SourceSpan span) { 503 checkFirstClass(SourceSpan span) {
355 if (isType) { 504 if (isType) {
356 world.error('Types are not first class', span); 505 world.error('Types are not first class', span);
357 } 506 }
358 } 507 }
359 508
360 /** Generate a call to an unknown function type. */ 509 /** Generate a call to an unknown function type. */
361 Value _varCall(MethodGenerator context, Node node, Arguments args) { 510 Value _varCall(CallingContext context, Node node, Arguments args) {
362 // TODO(jmesserly): calls to unknown functions will bypass type checks, 511 // TODO(jmesserly): calls to unknown functions will bypass type checks,
363 // which normally happen on the caller side, or in the generated stub for 512 // which normally happen on the caller side, or in the generated stub for
364 // dynamic method calls. What should we do? 513 // dynamic method calls. What should we do?
365 var stub = world.functionType.getCallStub(args); 514 var stub = world.functionType.getCallStub(args);
366 return stub.invoke(context, node, this, args); 515 return stub.invoke(context, node, this, args);
367 } 516 }
368 517
369 /** True if convertTo would generate a conversion. */ 518 /** True if convertTo would generate a conversion. */
370 bool needsConversion(Type toType) { 519 bool needsConversion(Type toType) {
371 var c = convertTo(null, toType, isDynamic:true); 520 var c = convertTo(null, toType);
372 return c == null || code != c.code; 521 return c == null || code != c.code;
373 } 522 }
374 523
375 /** 524 /**
376 * Assign or convert this value to another type. 525 * Assign or convert this value to another type.
377 * This is used for converting between function types, inserting type 526 * This is used for converting between function types, inserting type
378 * checks when --enable_type_checks is enabled, and wrapping callback 527 * checks when --enable_type_checks is enabled, and wrapping callback
379 * functions passed to the dom so we can restore their isolate context. 528 * functions passed to the dom so we can restore their isolate context.
380 */ 529 */
381 Value convertTo(MethodGenerator context, Type toType, 530 Value convertTo(CallingContext context, Type toType) {
382 [bool isDynamic=false]) {
383 531
384 // Issue type warnings unless we are processing a dynamic operation. 532 // Issue type warnings unless we are processing a dynamic operation.
385 bool checked = !isDynamic; 533 bool checked = context != null && context.showWarnings;
386 534
387 var callMethod = toType.getCallMethod(); 535 var callMethod = toType.getCallMethod();
388 if (callMethod != null) { 536 if (callMethod != null) {
389 if (checked && !toType.isAssignable(type)) { 537 if (checked && !toType.isAssignable(type)) {
390 convertWarning(toType); 538 convertWarning(toType);
391 } 539 }
392 540
393 return _maybeWrapFunction(toType, callMethod); 541 return _maybeWrapFunction(toType, callMethod);
394 } 542 }
395 543
(...skipping 17 matching lines...) Expand all
413 return changeStaticType(toType); 561 return changeStaticType(toType);
414 } 562 }
415 563
416 if (checked && !toType.isSubtypeOf(type)) { 564 if (checked && !toType.isSubtypeOf(type)) {
417 // According to the static types, this conversion can't work. 565 // According to the static types, this conversion can't work.
418 convertWarning(toType); 566 convertWarning(toType);
419 } 567 }
420 568
421 // Generate a runtime checks if they're turned on, otherwise skip it. 569 // Generate a runtime checks if they're turned on, otherwise skip it.
422 if (options.enableTypeChecks) { 570 if (options.enableTypeChecks) {
423 if (context == null && isDynamic) { 571 if (context == null) {
424 // If we're called from needsConversion, we don't need a context. 572 // If we're called from needsConversion, we don't need a context.
425 // Just return null so it knows a conversion is required. 573 // Just return null so it knows a conversion is required.
426 return null; 574 return null;
427 } 575 }
428 return _typeAssert(context, toType, isDynamic); 576 return _typeAssert(context, toType);
429 } else { 577 } else {
430 return changeStaticType(toType); 578 return changeStaticType(toType);
431 } 579 }
432 } 580 }
433 581
434 // TODO(jmesserly): I think we can replace our usage of the "isDynamic" flag
435 // by changing the static type of the target to "Dynamic" instead.
436 changeStaticType(Type toType) { 582 changeStaticType(Type toType) {
437 // Ensure that we return something with the right type for inference 583 // Ensure that we return something with the right type for inference
438 // purposes. 584 // purposes.
439 return (toType == type) ? this : new ConvertedValue(this, toType); 585 return (toType == type) ? this : new ConvertedValue(this, toType);
440 } 586 }
441 587
442 /** 588 /**
443 * Wraps a function with a conversion, so it can be called directly from 589 * Wraps a function with a conversion, so it can be called directly from
444 * Dart or JS code with the proper arity. We avoid the wrapping if the target 590 * Dart or JS code with the proper arity. We avoid the wrapping if the target
445 * function has the same arity. 591 * function has the same arity.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 623
478 if (result === this) result = changeStaticType(toType); 624 if (result === this) result = changeStaticType(toType);
479 return result; 625 return result;
480 } 626 }
481 627
482 /** 628 /**
483 * Generates a run time type assertion for the given value. This works like 629 * Generates a run time type assertion for the given value. This works like
484 * [instanceOf], but it allows null since Dart types are nullable. 630 * [instanceOf], but it allows null since Dart types are nullable.
485 * Also it will throw a TypeError if it gets the wrong type. 631 * Also it will throw a TypeError if it gets the wrong type.
486 */ 632 */
487 Value _typeAssert(MethodGenerator context, Type toType, bool isDynamic) { 633 Value _typeAssert(CallingContext context, Type toType) {
488 if (toType is ParameterType) { 634 if (toType is ParameterType) {
489 ParameterType p = toType; 635 ParameterType p = toType;
490 toType = p.extendsType; 636 toType = p.extendsType;
491 } 637 }
492 638
493 if (toType.isObject || toType.isVar) { 639 if (toType.isObject || toType.isVar) {
494 world.internalError( 640 world.internalError(
495 'We thought ${type.name} is not a subtype of ${toType.name}?'); 641 'We thought ${type.name} is not a subtype of ${toType.name}?');
496 } 642 }
497 643
498 // Prevent a stack overflow when forceDynamic and type checks are both 644 // Prevent a stack overflow when forceDynamic and type checks are both
499 // enabled. forceDynamic would cause the TypeError constructor to type check 645 // enabled. forceDynamic would cause the TypeError constructor to type check
500 // its arguments, which in turn invokes the TypeError constructor, ad 646 // its arguments, which in turn invokes the TypeError constructor, ad
501 // infinitum. 647 // infinitum.
502 String throwTypeError(String paramName) => world.withoutForceDynamic(() { 648 String throwTypeError(String paramName) => world.withoutForceDynamic(() {
503 final typeErrorCtor = world.typeErrorType.getConstructor('_internal'); 649 final typeErrorCtor = world.typeErrorType.getConstructor('_internal');
504 world.gen.corejs.ensureTypeNameOf(); 650 world.gen.corejs.ensureTypeNameOf();
505 final result = typeErrorCtor.invoke(context, null, 651 final result = typeErrorCtor.invoke(context, null,
506 new TypeValue(world.typeErrorType, null), 652 new TypeValue(world.typeErrorType, null),
507 new Arguments(null, [ 653 new Arguments(null, [
508 new Value(world.objectType, paramName, null), 654 new Value(world.objectType, paramName, null),
509 new Value(world.stringType, '"${toType.name}"', null)]), 655 new Value(world.stringType, '"${toType.name}"', null)]));
510 isDynamic);
511 world.gen.corejs.useThrow = true; 656 world.gen.corejs.useThrow = true;
512 return '\$throw(${result.code})'; 657 return '\$throw(${result.code})';
513 }); 658 });
514 659
515 // TODO(jmesserly): better assert for integers? 660 // TODO(jmesserly): better assert for integers?
516 if (toType.isNum) toType = world.numType; 661 if (toType.isNum) toType = world.numType;
517 662
518 // Generate a check like these: 663 // Generate a check like these:
519 // obj && obj.is$TypeName() 664 // obj && obj.is$TypeName()
520 // $assert_int(obj) 665 // $assert_int(obj)
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 } 713 }
569 714
570 /** 715 /**
571 * Test to see if value is an instance of this type. 716 * Test to see if value is an instance of this type.
572 * 717 *
573 * - If a primitive type, then uses the JavaScript typeof. 718 * - If a primitive type, then uses the JavaScript typeof.
574 * - If it's a non-generic class, use instanceof. 719 * - If it's a non-generic class, use instanceof.
575 * - Otherwise add a fake member to test for. This value is generated 720 * - Otherwise add a fake member to test for. This value is generated
576 * as a function so that it can be called for a runtime failure. 721 * as a function so that it can be called for a runtime failure.
577 */ 722 */
578 Value instanceOf(MethodGenerator context, Type toType, SourceSpan span, 723 Value instanceOf(CallingContext context, Type toType, SourceSpan span,
579 [bool isTrue=true, bool forceCheck=false]) { 724 [bool isTrue=true, bool forceCheck=false]) {
580 // TODO(jimhug): Optimize away tests that will always pass unless 725 // TODO(jimhug): Optimize away tests that will always pass unless
581 // forceCheck is true. 726 // forceCheck is true.
582 727
583 if (toType.isVar) { 728 if (toType.isVar) {
584 world.error('can not resolve type', span); 729 world.error('can not resolve type', span);
585 } 730 }
586 731
587 String testCode = null; 732 String testCode = null;
588 if (toType.isVar || toType.isObject || toType is ParameterType) { 733 if (toType.isVar || toType.isObject || toType is ParameterType) {
589 // Note: everything is an Object, including null. 734 // Note: everything is an Object, including null.
590 if (needsTemp) { 735 if (needsTemp) {
591 return new Value(world.nonNullBool, '($code, true)', span); 736 return new Value(world.nonNullBool, '($code, true)', span);
592 } else { 737 } else {
593 // TODO(jimhug): Mark non-const? 738 // TODO(jimhug): Mark non-const?
594 return Value.fromBool(true, span); 739 return Value.fromBool(true, span);
595 } 740 }
596 } 741 }
597 742
598 if (toType.library.isCore) { 743 if (toType.library.isCore) {
599 var typeofName = toType.typeofName; 744 var typeofName = toType.typeofName;
600 if (typeofName != null) { 745 if (typeofName != null) {
601 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')"; 746 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')";
602 } 747 }
603 } 748 }
604 if (toType.isClass && toType is !ConcreteType 749
605 && !toType.isHiddenNativeType) { 750 if (toType.isClass
751 && !toType.isHiddenNativeType && !toType.isConcreteGeneric) {
606 toType.markUsed(); 752 toType.markUsed();
607 testCode = '($code instanceof ${toType.jsname})'; 753 testCode = '($code instanceof ${toType.jsname})';
608 if (!isTrue) { 754 if (!isTrue) {
609 testCode = '!' + testCode; 755 testCode = '!' + testCode;
610 } 756 }
611 } 757 }
612 if (testCode == null) { 758 if (testCode == null) {
613 toType.isTested = true; 759 toType.isTested = true;
614 760
615 // If we track nullability, we could simplify this check. 761 // If we track nullability, we could simplify this check.
(...skipping 21 matching lines...) Expand all
637 } 783 }
638 return new Value(world.nonNullBool, testCode, span); 784 return new Value(world.nonNullBool, testCode, span);
639 } 785 }
640 786
641 void convertWarning(Type toType) { 787 void convertWarning(Type toType) {
642 // TODO(jmesserly): better error messages for type conversion failures 788 // TODO(jmesserly): better error messages for type conversion failures
643 world.warning('type "${type.name}" is not assignable to "${toType.name}"', 789 world.warning('type "${type.name}" is not assignable to "${toType.name}"',
644 span); 790 span);
645 } 791 }
646 792
647 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node, 793 Value invokeNoSuchMethod(CallingContext context, String name, Node node,
648 [Arguments args]) { 794 [Arguments args]) {
649 if (isType) { 795 if (isType) {
650 world.error('member lookup failed for "$name"', node.span); 796 world.error('member lookup failed for "$name"', node.span);
651 } 797 }
652 798
653 var pos = ''; 799 var pos = '';
654 if (args != null) { 800 if (args != null) {
655 var argsCode = []; 801 var argsCode = [];
656 for (int i = 0; i < args.length; i++) { 802 for (int i = 0; i < args.length; i++) {
657 argsCode.add(args.values[i].code); 803 argsCode.add(args.values[i].code);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 874
729 875
730 class NullValue extends EvaluatedValue { 876 class NullValue extends EvaluatedValue {
731 NullValue(bool isConst, SourceSpan span): 877 NullValue(bool isConst, SourceSpan span):
732 super(isConst, world.varType, span); 878 super(isConst, world.varType, span);
733 879
734 get actualValue() => null; 880 get actualValue() => null;
735 881
736 String get code() => 'null'; 882 String get code() => 'null';
737 883
738 Value binop(int kind, var other, MethodGenerator context, var node) { 884 Value binop(int kind, var other, CallingContext context, var node) {
739 if (other is! NullValue) return super.binop(kind, other, context, node); 885 if (other is! NullValue) return super.binop(kind, other, context, node);
740 886
741 final c = isConst && other.isConst; 887 final c = isConst && other.isConst;
742 final s = node.span; 888 final s = node.span;
743 switch (kind) { 889 switch (kind) {
744 case TokenKind.EQ_STRICT: 890 case TokenKind.EQ_STRICT:
745 case TokenKind.EQ: 891 case TokenKind.EQ:
746 return new BoolValue(true, c, s); 892 return new BoolValue(true, c, s);
747 case TokenKind.NE_STRICT: 893 case TokenKind.NE_STRICT:
748 case TokenKind.NE: 894 case TokenKind.NE:
749 return new BoolValue(false, c, s); 895 return new BoolValue(false, c, s);
750 } 896 }
751 897
752 return super.binop(kind, other, context, node); 898 return super.binop(kind, other, context, node);
753 } 899 }
754 } 900 }
755 901
756 class BoolValue extends EvaluatedValue { 902 class BoolValue extends EvaluatedValue {
757 final bool actualValue; 903 final bool actualValue;
758 904
759 BoolValue(this.actualValue, bool isConst, SourceSpan span): 905 BoolValue(this.actualValue, bool isConst, SourceSpan span):
760 super(isConst, world.nonNullBool, span); 906 super(isConst, world.nonNullBool, span);
761 907
762 String get code() => actualValue ? 'true' : 'false'; 908 String get code() => actualValue ? 'true' : 'false';
763 909
764 Value unop(int kind, MethodGenerator context, var node) { 910 Value unop(int kind, CallingContext context, var node) {
765 switch (kind) { 911 switch (kind) {
766 case TokenKind.NOT: 912 case TokenKind.NOT:
767 return new BoolValue(!actualValue, isConst, node.span); 913 return new BoolValue(!actualValue, isConst, node.span);
768 } 914 }
769 return super.unop(kind, context, node); 915 return super.unop(kind, context, node);
770 } 916 }
771 917
772 Value binop(int kind, var other, MethodGenerator context, var node) { 918 Value binop(int kind, var other, CallingContext context, var node) {
773 if (other is! BoolValue) return super.binop(kind, other, context, node); 919 if (other is! BoolValue) return super.binop(kind, other, context, node);
774 920
775 final c = isConst && other.isConst; 921 final c = isConst && other.isConst;
776 final s = node.span; 922 final s = node.span;
777 bool x = actualValue, y = other.actualValue; 923 bool x = actualValue, y = other.actualValue;
778 switch (kind) { 924 switch (kind) {
779 case TokenKind.EQ_STRICT: 925 case TokenKind.EQ_STRICT:
780 case TokenKind.EQ: 926 case TokenKind.EQ:
781 return new BoolValue(x == y, c, s); 927 return new BoolValue(x == y, c, s);
782 case TokenKind.NE_STRICT: 928 case TokenKind.NE_STRICT:
(...skipping 11 matching lines...) Expand all
794 940
795 class IntValue extends EvaluatedValue { 941 class IntValue extends EvaluatedValue {
796 final int actualValue; 942 final int actualValue;
797 943
798 IntValue(this.actualValue, bool isConst, SourceSpan span): 944 IntValue(this.actualValue, bool isConst, SourceSpan span):
799 super(isConst, world.intType, span); 945 super(isConst, world.intType, span);
800 946
801 // TODO(jimhug): Only add parens when needed. 947 // TODO(jimhug): Only add parens when needed.
802 String get code() => '(${actualValue})'; 948 String get code() => '(${actualValue})';
803 949
804 Value unop(int kind, MethodGenerator context, var node) { 950 Value unop(int kind, CallingContext context, var node) {
805 switch (kind) { 951 switch (kind) {
806 case TokenKind.ADD: 952 case TokenKind.ADD:
807 // This is allowed on numeric constants only 953 // This is allowed on numeric constants only
808 return new IntValue(actualValue, isConst, span); 954 return new IntValue(actualValue, isConst, span);
809 case TokenKind.SUB: 955 case TokenKind.SUB:
810 return new IntValue(-actualValue, isConst, span); 956 return new IntValue(-actualValue, isConst, span);
811 case TokenKind.BIT_NOT: 957 case TokenKind.BIT_NOT:
812 return new IntValue(~actualValue, isConst, span); 958 return new IntValue(~actualValue, isConst, span);
813 } 959 }
814 return super.unop(kind, context, node); 960 return super.unop(kind, context, node);
815 } 961 }
816 962
817 963
818 Value binop(int kind, var other, MethodGenerator context, var node) { 964 Value binop(int kind, var other, CallingContext context, var node) {
819 final c = isConst && other.isConst; 965 final c = isConst && other.isConst;
820 final s = node.span; 966 final s = node.span;
821 if (other is IntValue) { 967 if (other is IntValue) {
822 int x = actualValue; 968 int x = actualValue;
823 int y = other.actualValue; 969 int y = other.actualValue;
824 switch (kind) { 970 switch (kind) {
825 case TokenKind.EQ_STRICT: 971 case TokenKind.EQ_STRICT:
826 case TokenKind.EQ: 972 case TokenKind.EQ:
827 return new BoolValue(x == y, c, s); 973 return new BoolValue(x == y, c, s);
828 case TokenKind.NE_STRICT: 974 case TokenKind.NE_STRICT:
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
900 } 1046 }
901 1047
902 class DoubleValue extends EvaluatedValue { 1048 class DoubleValue extends EvaluatedValue {
903 final double actualValue; 1049 final double actualValue;
904 1050
905 DoubleValue(this.actualValue, bool isConst, SourceSpan span): 1051 DoubleValue(this.actualValue, bool isConst, SourceSpan span):
906 super(isConst, world.doubleType, span); 1052 super(isConst, world.doubleType, span);
907 1053
908 String get code() => '(${actualValue})'; 1054 String get code() => '(${actualValue})';
909 1055
910 Value unop(int kind, MethodGenerator context, var node) { 1056 Value unop(int kind, CallingContext context, var node) {
911 switch (kind) { 1057 switch (kind) {
912 case TokenKind.ADD: 1058 case TokenKind.ADD:
913 // This is allowed on numeric constants only 1059 // This is allowed on numeric constants only
914 return new DoubleValue(actualValue, isConst, span); 1060 return new DoubleValue(actualValue, isConst, span);
915 case TokenKind.SUB: 1061 case TokenKind.SUB:
916 return new DoubleValue(-actualValue, isConst, span); 1062 return new DoubleValue(-actualValue, isConst, span);
917 } 1063 }
918 return super.unop(kind, context, node); 1064 return super.unop(kind, context, node);
919 } 1065 }
920 1066
921 Value binop(int kind, var other, MethodGenerator context, var node) { 1067 Value binop(int kind, var other, CallingContext context, var node) {
922 final c = isConst && other.isConst; 1068 final c = isConst && other.isConst;
923 final s = node.span; 1069 final s = node.span;
924 if (other is DoubleValue) { 1070 if (other is DoubleValue) {
925 double x = actualValue; 1071 double x = actualValue;
926 double y = other.actualValue; 1072 double y = other.actualValue;
927 switch (kind) { 1073 switch (kind) {
928 case TokenKind.EQ_STRICT: 1074 case TokenKind.EQ_STRICT:
929 case TokenKind.EQ: 1075 case TokenKind.EQ:
930 return new BoolValue(x == y, c, s); 1076 return new BoolValue(x == y, c, s);
931 case TokenKind.NE_STRICT: 1077 case TokenKind.NE_STRICT:
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 return super.binop(kind, other, context, node); 1138 return super.binop(kind, other, context, node);
993 } 1139 }
994 } 1140 }
995 1141
996 class StringValue extends EvaluatedValue { 1142 class StringValue extends EvaluatedValue {
997 final String actualValue; 1143 final String actualValue;
998 1144
999 StringValue(this.actualValue, bool isConst, SourceSpan span): 1145 StringValue(this.actualValue, bool isConst, SourceSpan span):
1000 super(isConst, world.stringType, span); 1146 super(isConst, world.stringType, span);
1001 1147
1002 Value binop(int kind, var other, MethodGenerator context, var node) { 1148 Value binop(int kind, var other, CallingContext context, var node) {
1003 if (other is! StringValue) return super.binop(kind, other, context, node); 1149 if (other is! StringValue) return super.binop(kind, other, context, node);
1004 1150
1005 final c = isConst && other.isConst; 1151 final c = isConst && other.isConst;
1006 final s = node.span; 1152 final s = node.span;
1007 String x = actualValue, y = other.actualValue; 1153 String x = actualValue, y = other.actualValue;
1008 switch (kind) { 1154 switch (kind) {
1009 case TokenKind.EQ_STRICT: 1155 case TokenKind.EQ_STRICT:
1010 case TokenKind.EQ: 1156 case TokenKind.EQ:
1011 return new BoolValue(x == y, c, s); 1157 return new BoolValue(x == y, c, s);
1012 case TokenKind.NE_STRICT: 1158 case TokenKind.NE_STRICT:
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1071 if (i > 0) buf.add(', '); 1217 if (i > 0) buf.add(', ');
1072 buf.add(values[i].code); 1218 buf.add(values[i].code);
1073 } 1219 }
1074 buf.add(']'); 1220 buf.add(']');
1075 var listCode = buf.toString(); 1221 var listCode = buf.toString();
1076 1222
1077 if (!isConst) return listCode; 1223 if (!isConst) return listCode;
1078 1224
1079 var v = new Value(world.listType, listCode, span); 1225 var v = new Value(world.listType, listCode, span);
1080 final immutableListCtor = world.immutableListType.getConstructor('from'); 1226 final immutableListCtor = world.immutableListType.getConstructor('from');
1081 final result = immutableListCtor.invoke(null, null, 1227 final result = immutableListCtor.invoke(world.gen.mainContext, null,
1082 new TypeValue(v.type, span), new Arguments(null, [v])); 1228 new TypeValue(v.type, span), new Arguments(null, [v]));
1083 return result.code; 1229 return result.code;
1084 } 1230 }
1085 1231
1086 Value binop(int kind, var other, MethodGenerator context, var node) { 1232 Value binop(int kind, var other, CallingContext context, var node) {
1087 // TODO(jimhug): Support int/double better 1233 // TODO(jimhug): Support int/double better
1088 if (other is! ListValue) return super.binop(kind, other, context, node); 1234 if (other is! ListValue) return super.binop(kind, other, context, node);
1089 1235
1090 switch (kind) { 1236 switch (kind) {
1091 case TokenKind.EQ_STRICT: 1237 case TokenKind.EQ_STRICT:
1092 return new BoolValue(type == other.type && code == other.code, 1238 return new BoolValue(type == other.type && code == other.code,
1093 isConst && other.isConst, node.span); 1239 isConst && other.isConst, node.span);
1094 case TokenKind.NE_STRICT: 1240 case TokenKind.NE_STRICT:
1095 return new BoolValue(type != other.type || code != other.code, 1241 return new BoolValue(type != other.type || code != other.code,
1096 isConst && other.isConst, node.span); 1242 isConst && other.isConst, node.span);
(...skipping 15 matching lines...) Expand all
1112 1258
1113 MapValue(this.values, bool isConst, Type type, SourceSpan span): 1259 MapValue(this.values, bool isConst, Type type, SourceSpan span):
1114 super(isConst, type, span); 1260 super(isConst, type, span);
1115 1261
1116 String get code() { 1262 String get code() {
1117 // Cache? 1263 // Cache?
1118 var items = new ListValue(values, false, world.listType, span); 1264 var items = new ListValue(values, false, world.listType, span);
1119 var tp = world.coreimpl.topType; 1265 var tp = world.coreimpl.topType;
1120 Member f = isConst ? tp.getMember('_constMap') : tp.getMember('_map'); 1266 Member f = isConst ? tp.getMember('_constMap') : tp.getMember('_map');
1121 // TODO(jimhug): Clean up invoke signature 1267 // TODO(jimhug): Clean up invoke signature
1122 var value = f.invoke(null, null, new TypeValue(tp, null), 1268 var value = f.invoke(world.gen.mainContext, null, new TypeValue(tp, null),
1123 new Arguments(null, [items])); 1269 new Arguments(null, [items]));
1124 return value.code; 1270 return value.code;
1125 } 1271 }
1126 1272
1127 GlobalValue getGlobalValue() { 1273 GlobalValue getGlobalValue() {
1128 assert(isConst); 1274 assert(isConst);
1129 1275
1130 return world.gen.globalForConst(this, values); 1276 return world.gen.globalForConst(this, values);
1131 } 1277 }
1132 1278
1133 Value binop(int kind, var other, MethodGenerator context, var node) { 1279 Value binop(int kind, var other, CallingContext context, var node) {
1134 if (other is! MapValue) return super.binop(kind, other, context, node); 1280 if (other is! MapValue) return super.binop(kind, other, context, node);
1135 1281
1136 switch (kind) { 1282 switch (kind) {
1137 case TokenKind.EQ_STRICT: 1283 case TokenKind.EQ_STRICT:
1138 return new BoolValue(type == other.type && code == other.code, 1284 return new BoolValue(type == other.type && code == other.code,
1139 isConst && other.isConst, node.span); 1285 isConst && other.isConst, node.span);
1140 case TokenKind.NE_STRICT: 1286 case TokenKind.NE_STRICT:
1141 return new BoolValue(type != other.type || code != other.code, 1287 return new BoolValue(type != other.type || code != other.code,
1142 isConst && other.isConst, node.span); 1288 isConst && other.isConst, node.span);
1143 } 1289 }
(...skipping 11 matching lines...) Expand all
1155 1301
1156 ObjectValue(bool isConst, Type type, SourceSpan span): 1302 ObjectValue(bool isConst, Type type, SourceSpan span):
1157 fields = {}, super(isConst, type, span); 1303 fields = {}, super(isConst, type, span);
1158 1304
1159 String get code() { 1305 String get code() {
1160 if (_code === null) validateInitialized(null); 1306 if (_code === null) validateInitialized(null);
1161 return _code; 1307 return _code;
1162 } 1308 }
1163 1309
1164 initFields() { 1310 initFields() {
1165 var allMembers = world.gen._orderValues(type.getAllMembers()); 1311 var allMembers = world.gen._orderValues(type.genericType.getAllMembers());
1166 for (var f in allMembers) { 1312 for (var f in allMembers) {
1167 if (f.isField && !f.isStatic && f.declaringType.isClass) { 1313 if (f.isField && !f.isStatic && f.declaringType.isClass) {
1168 fields[f] = f.computeValue(); 1314 fields[f] = f.computeValue();
1169 } 1315 }
1170 } 1316 }
1171 } 1317 }
1172 1318
1173 setField(Member field, Value value, [bool duringInit = false]) { 1319 setField(Member field, Value value, [bool duringInit = false]) {
1174 // Unpack constant values 1320 // Unpack constant values
1175 if (value.isConst && value is VariableValue) { 1321 if (value.isConst && value is VariableValue) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 buf.add('null'); 1359 buf.add('null');
1214 } else { 1360 } else {
1215 buf.add(fields[field].code); 1361 buf.add(fields[field].code);
1216 } 1362 }
1217 buf.add(', writeable: false}, '); 1363 buf.add(', writeable: false}, ');
1218 } 1364 }
1219 buf.add('})'); 1365 buf.add('})');
1220 _code = buf.toString(); 1366 _code = buf.toString();
1221 } 1367 }
1222 1368
1223 Value binop(int kind, var other, MethodGenerator context, var node) { 1369 Value binop(int kind, var other, CallingContext context, var node) {
1224 if (other is! ObjectValue) return super.binop(kind, other, context, node); 1370 if (other is! ObjectValue) return super.binop(kind, other, context, node);
1225 1371
1226 switch (kind) { 1372 switch (kind) {
1227 case TokenKind.EQ_STRICT: 1373 case TokenKind.EQ_STRICT:
1228 case TokenKind.EQ: 1374 case TokenKind.EQ:
1229 return new BoolValue(type == other.type && code == other.code, 1375 return new BoolValue(type == other.type && code == other.code,
1230 isConst && other.isConst, node.span); 1376 isConst && other.isConst, node.span);
1231 case TokenKind.NE_STRICT: 1377 case TokenKind.NE_STRICT:
1232 case TokenKind.NE: 1378 case TokenKind.NE:
1233 return new BoolValue(type != other.type || code != other.code, 1379 return new BoolValue(type != other.type || code != other.code,
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
1311 } 1457 }
1312 } 1458 }
1313 1459
1314 /** 1460 /**
1315 * Represents the hidden or implicit value in a bare reference like 'a'. 1461 * Represents the hidden or implicit value in a bare reference like 'a'.
1316 * This could be this, the current type, or the current library for purposes 1462 * This could be this, the current type, or the current library for purposes
1317 * of resolving members. 1463 * of resolving members.
1318 */ 1464 */
1319 class BareValue extends Value { 1465 class BareValue extends Value {
1320 final bool isType; 1466 final bool isType;
1321 final MethodGenerator home; 1467 final CallingContext home;
1322 1468
1323 String _code; 1469 String _code;
1324 1470
1325 BareValue(this.home, MethodGenerator outermost, SourceSpan span): 1471 BareValue(this.home, CallingContext outermost, SourceSpan span):
1326 isType = outermost.isStatic, 1472 isType = outermost.isStatic,
1327 super(outermost.method.declaringType, null, span); 1473 super(outermost.method.declaringType, null, span);
1328 1474
1329 bool get needsTemp() => false; 1475 bool get needsTemp() => false;
1330 bool _shouldBindDynamically() => false; 1476 bool _shouldBindDynamically() => false;
1331 1477
1332 String get code() => _code; 1478 String get code() => _code;
1333 1479
1334 // TODO(jimhug): Lazy initialization here is weird! 1480 // TODO(jimhug): Lazy initialization here is weird!
1335 void _ensureCode() { 1481 void _ensureCode() {
1336 if (_code === null) _code = isType ? type.jsname : home._makeThisCode(); 1482 if (_code === null) _code = isType ? type.jsname : home._makeThisCode();
1337 } 1483 }
1338 1484
1339 MemberSet _tryResolveMember(MethodGenerator context, String name, bool isDynam ic, Node node) { 1485 MemberSet _tryResolveMember(CallingContext context, String name, Node node) {
1340 assert(context == home); 1486 assert(context == home);
1341 1487
1342 // TODO(jimhug): Confirm this matches final resolution of issue 641. 1488 // TODO(jimhug): Confirm this matches final resolution of issue 641.
1343 var member = type.getMember(name); 1489 var member = type.getMember(name);
1344 if (member == null || member.declaringType != type) { 1490 if (member == null || member.declaringType != type) {
1345 var libMember = home.library.lookup(name, span); 1491 var libMember = home.library.lookup(name, span);
1346 if (libMember !== null) { 1492 if (libMember !== null) {
1347 return libMember.preciseMemberSet; 1493 return libMember.preciseMemberSet;
1348 } 1494 }
1349 } 1495 }
1350 1496
1351 _ensureCode(); 1497 _ensureCode();
1352 return super._tryResolveMember(context, name, isDynamic, node); 1498 return super._tryResolveMember(context, name, node);
1353 } 1499 }
1354 } 1500 }
1355 1501
1356 /** A reference to 'super'. */ 1502 /** A reference to 'super'. */
1357 // TODO(jmesserly): override resolveMember to clean up the one on Value 1503 // TODO(jmesserly): override resolveMember to clean up the one on Value
1358 class SuperValue extends Value { 1504 class SuperValue extends Value {
1359 SuperValue(Type parentType, SourceSpan span): 1505 SuperValue(Type parentType, SourceSpan span):
1360 super(parentType, 'this', span); 1506 super(parentType, 'this', span);
1361 1507
1362 bool get needsTemp() => false; 1508 bool get needsTemp() => false;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1404 } 1550 }
1405 1551
1406 bool get needsTemp() => value.needsTemp; 1552 bool get needsTemp() => value.needsTemp;
1407 bool get isFinal() => value.isFinal; 1553 bool get isFinal() => value.isFinal;
1408 bool get isConst() => value.isConst; 1554 bool get isConst() => value.isConst;
1409 1555
1410 // TODO(jmesserly): preserve the staticType? 1556 // TODO(jmesserly): preserve the staticType?
1411 Value _tryUnion(Value right) => Value.union(value, right); 1557 Value _tryUnion(Value right) => Value.union(value, right);
1412 1558
1413 // TODO(jmessery): override get/set/invoke/unop/binop? 1559 // TODO(jmessery): override get/set/invoke/unop/binop?
1414 // (The tricky part is we want them to use our staticType for warning
1415 // purposes. It's like the whole ConcreteType/ConcreteMember issues...)
1416 } 1560 }
1417 1561
1418 /** 1562 /**
1419 * A value that represents a variable or parameter. The [assigned] value can be 1563 * A value that represents a variable or parameter. The [assigned] value can be
1420 * mutated when the variable is assigned to a new Value. 1564 * mutated when the variable is assigned to a new Value.
1421 */ 1565 */
1422 class VariableValue extends Value { 1566 class VariableValue extends Value {
1423 final bool isFinal; 1567 final bool isFinal;
1424 final Value value; 1568 final Value value;
1425 1569
(...skipping 28 matching lines...) Expand all
1454 Type get staticType() => super.type; 1598 Type get staticType() => super.type;
1455 bool get isConst() => value !== null ? value.isConst : false; 1599 bool get isConst() => value !== null ? value.isConst : false;
1456 1600
1457 // TODO(jmesserly): we could use this for checking uninitialized values 1601 // TODO(jmesserly): we could use this for checking uninitialized values
1458 bool get isInitialized() => value != null; 1602 bool get isInitialized() => value != null;
1459 1603
1460 VariableValue replaceValue(Value v) => 1604 VariableValue replaceValue(Value v) =>
1461 new VariableValue(staticType, code, span, isFinal, v); 1605 new VariableValue(staticType, code, span, isFinal, v);
1462 1606
1463 // TODO(jmesserly): anything else to override? 1607 // TODO(jmesserly): anything else to override?
1464 Value unop(int kind, MethodGenerator context, var node) { 1608 Value unop(int kind, CallingContext context, var node) {
1465 if (value != null) { 1609 if (value != null) {
1466 return replaceValue(value.unop(kind, context, node)); 1610 return replaceValue(value.unop(kind, context, node));
1467 } 1611 }
1468 return super.unop(kind, context, node); 1612 return super.unop(kind, context, node);
1469 } 1613 }
1470 Value binop(int kind, var other, MethodGenerator context, var node) { 1614 Value binop(int kind, var other, CallingContext context, var node) {
1471 if (value != null) { 1615 if (value != null) {
1472 return replaceValue(value.binop(kind, _unwrap(other), context, node)); 1616 return replaceValue(value.binop(kind, _unwrap(other), context, node));
1473 } 1617 }
1474 return super.binop(kind, other, context, node); 1618 return super.binop(kind, other, context, node);
1475 } 1619 }
1476 } 1620 }
OLDNEW
« frog/gen.dart ('K') | « frog/utils.dart ('k') | frog/var_member.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698