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

Side by Side Diff: frog/member.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 /** 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;
11 Type type; 11 Type type;
12 bool isInitializer = false; 12 bool isInitializer = false;
13 13
14 Value value; 14 Value value;
15 15
16 Parameter(this.definition, this.method); 16 Parameter(this.definition, this.method);
17 17
18 resolve() { 18 resolve() {
19 name = definition.name.name; 19 name = definition.name.name;
20 if (name.startsWith('this.')) { 20 if (name.startsWith('this.')) {
21 name = name.substring(5); 21 name = name.substring(5);
22 isInitializer = true; 22 isInitializer = true;
23 } 23 }
24 24
25 type = method.resolveType(definition.type, false); 25 type = method.resolveType(definition.type, false, true);
26 26
27 if (definition.value != null) { 27 if (definition.value != null) {
28 // To match VM, detect cases where value was not actually specified in 28 // To match VM, detect cases where value was not actually specified in
29 // code and don't signal errors. 29 // code and don't signal errors.
30 // TODO(jimhug): Clean up after issue #352 is resolved. 30 // TODO(jimhug): Clean up after issue #352 is resolved.
31 if (!hasDefaultValue) return; 31 if (!hasDefaultValue) return;
32 32
33 if (method.name == ':call') { 33 if (method.name == ':call') {
34 // TODO(jimhug): Need simpler way to detect "true" function types vs. 34 // TODO(jimhug): Need simpler way to detect "true" function types vs.
35 // regular methods being used as function types for closures. 35 // regular methods being used as function types for closures.
36 // TODO(sigmund): Disallow non-null default values for native calls? 36 // TODO(sigmund): Disallow non-null default values for native calls?
37 var methodDef = method.definition; 37 var methodDef = method.definition;
38 if (methodDef.body == null && !method.isNative) { 38 if (methodDef.body == null && !method.isNative) {
39 world.error('default value not allowed on function type', 39 world.error('default value not allowed on function type',
40 definition.span); 40 definition.span);
41 } 41 }
42 } else if (method.isAbstract) { 42 } else if (method.isAbstract) {
43 world.error('default value not allowed on abstract methods', 43 world.error('default value not allowed on abstract methods',
44 definition.span); 44 definition.span);
45 } 45 }
46 } else if (isInitializer && !method.isConstructor) { 46 } else if (isInitializer && !method.isConstructor) {
47 world.error('initializer parameters only allowed on constructors', 47 world.error('initializer parameters only allowed on constructors',
48 definition.span); 48 definition.span);
49 } 49 }
50 } 50 }
51 51
52 genValue(MethodMember method, MethodGenerator context) { 52 genValue(MethodMember method, CallingContext context) {
53 if (definition.value == null || value != null) return; 53 if (definition.value == null || value != null) return;
54 54
55 if (context == null) { // interface method 55 if (context == null) { // interface method
56 context = new MethodGenerator(method, null); 56 context = new MethodGenerator(method, null);
57 } 57 }
58 value = definition.value.visit(context); 58 value = definition.value.visit(context);
59 if (!value.isConst) { 59 if (!value.isConst) {
60 world.error('default parameter values must be constant', value.span); 60 world.error('default parameter values must be constant', value.span);
61 } 61 }
62 value = value.convertTo(context, type); 62 value = value.convertTo(context, type);
(...skipping 14 matching lines...) Expand all
77 * on the implicit `null`. 77 * on the implicit `null`.
78 */ 78 */
79 bool get hasDefaultValue() => 79 bool get hasDefaultValue() =>
80 definition.value.span.start != definition.span.start; 80 definition.value.span.start != definition.span.start;
81 } 81 }
82 82
83 83
84 class Member extends Element { 84 class Member extends Element {
85 final Type declaringType; 85 final Type declaringType;
86 86
87 bool isGenerated; 87 Member genericMember;
88 MethodGenerator generator;
89 88
90 Member(String name, Type declaringType) 89 Member(String name, Type declaringType)
91 : isGenerated = false, this.declaringType = declaringType, 90 : this.declaringType = declaringType,
92 super(name, declaringType); 91 super(name, declaringType);
93 92
94 abstract bool get isStatic(); 93 abstract bool get isStatic();
95 abstract Type get returnType(); 94 abstract Type get returnType();
96 95
97 abstract bool get canGet(); 96 abstract bool get canGet();
98 abstract bool get canSet(); 97 abstract bool get canSet();
99 98
100 Library get library() => declaringType.library; 99 Library get library() => declaringType.library;
101 100
(...skipping 10 matching lines...) Expand all
112 // TODO(jmesserly): these only makes sense on methods, but because of 111 // TODO(jmesserly): these only makes sense on methods, but because of
113 // ConcreteMember we need to support them on Member. 112 // ConcreteMember we need to support them on Member.
114 bool get isConst() => false; 113 bool get isConst() => false;
115 bool get isFactory() => false; 114 bool get isFactory() => false;
116 115
117 bool get isOperator() => name.startsWith(':'); 116 bool get isOperator() => name.startsWith(':');
118 bool get isCallMethod() => name == ':call'; 117 bool get isCallMethod() => name == ':call';
119 118
120 bool get requiresPropertySyntax() => false; 119 bool get requiresPropertySyntax() => false;
121 bool _providePropertySyntax = false; 120 bool _providePropertySyntax = false;
122 bool get requiresFieldSyntax() => false;
123 bool _provideFieldSyntax = false;
124 121
125 bool get isNative() => false; 122 bool get isNative() => false;
126 String get constructorName() { 123 String get constructorName() {
127 world.internalError('can not be a constructor', span); 124 world.internalError('can not be a constructor', span);
128 } 125 }
129 126
130 // Don't display an error here; we'll get a better error later.
131 void provideFieldSyntax() {}
132 void providePropertySyntax() {} 127 void providePropertySyntax() {}
133 128
134 Member get initDelegate() { 129 Member get initDelegate() {
135 world.internalError('cannot have initializers', span); 130 world.internalError('cannot have initializers', span);
136 } 131 }
137 void set initDelegate(ctor) { 132 void set initDelegate(ctor) {
138 world.internalError('cannot have initializers', span); 133 world.internalError('cannot have initializers', span);
139 } 134 }
140 135
141 Value computeValue() { 136 Value computeValue() {
(...skipping 21 matching lines...) Expand all
163 MemberSet _preciseMemberSet, _potentialMemberSet; 158 MemberSet _preciseMemberSet, _potentialMemberSet;
164 159
165 MemberSet get preciseMemberSet() { 160 MemberSet get preciseMemberSet() {
166 if (_preciseMemberSet === null) { 161 if (_preciseMemberSet === null) {
167 _preciseMemberSet = new MemberSet(this); 162 _preciseMemberSet = new MemberSet(this);
168 } 163 }
169 return _preciseMemberSet; 164 return _preciseMemberSet;
170 } 165 }
171 166
172 MemberSet get potentialMemberSet() { 167 MemberSet get potentialMemberSet() {
168 // TODO(jimhug): This needs one more redesign - move to TypeSets...
169
173 if (_potentialMemberSet === null) { 170 if (_potentialMemberSet === null) {
174 if (declaringType.isObject) { 171 if (name == ':call') {
175 _potentialMemberSet = world._members[name]; 172 _potentialMemberSet = preciseMemberSet;
176 return _potentialMemberSet; 173 return _potentialMemberSet;
177 } 174 }
178 175
179 final mems = new Set<Member>(); 176 final mems = new Set<Member>();
180 if (declaringType.isClass) mems.add(this); 177 if (declaringType.isClass) mems.add(this);
181 178
182 179 for (var subtype in declaringType.genericType.subtypes) {
183 for (var subtype in declaringType.subtypes) {
184 if (!subtype.isClass) continue; 180 if (!subtype.isClass) continue;
185 var mem = subtype.members[name]; 181 var mem = subtype.members[name];
186 if (mem !== null) { 182 if (mem !== null) {
187 mems.add(mem); 183 if (mem.isDefinedOn(declaringType)) {
184 mems.add(mem);
185 }
188 } else if (!declaringType.isClass) { 186 } else if (!declaringType.isClass) {
189 // Handles weird interface case. 187 // Handles weird interface case.
190 mem = subtype.getMember(name); 188 mem = subtype.getMember(name);
191 if (mem !== null) { 189 if (mem !== null && mem.isDefinedOn(declaringType)) {
192 mems.add(mem); 190 mems.add(mem);
193 } 191 }
194 } 192 }
195 } 193 }
196 194
197 if (mems.length != 0) { 195 if (mems.length != 0) {
196 // TODO(jimhug): This hack needs to be rationalized.
197 for (var mem in mems) {
198 if (declaringType.genericType != declaringType &&
199 mem.genericMember != null && mems.contains(mem.genericMember)) {
200 //world.info('skip ${name} on ${mem.genericMember.declaringType.name }' +
201 // ' because we have on ${mem.declaringType.name} for ${declaringTy pe.name}');
202 mems.remove(mem.genericMember);
203 }
204 }
205
206
198 for (var mem in mems) { 207 for (var mem in mems) {
199 if (_potentialMemberSet === null) { 208 if (_potentialMemberSet === null) {
200 _potentialMemberSet = new MemberSet(mem); 209 _potentialMemberSet = new MemberSet(mem);
201 } else { 210 } else {
202 _potentialMemberSet.add(mem); 211 _potentialMemberSet.add(mem);
203 } 212 }
204 } 213 }
205 } 214 }
206 } 215 }
207 return _potentialMemberSet; 216 return _potentialMemberSet;
208 } 217 }
209 218
210 // If I have an object of [type] could I be invoking this member? 219 // If I have an object of [type] could I be invoking this member?
211 bool isDefinedOn(Type type) { 220 bool isDefinedOn(Type type) {
212 if (type.isClass) { 221 if (type.isClass) {
213 if (declaringType.isSubtypeOf(type)) { 222 if (declaringType.isSubtypeOf(type)) {
214 return true; 223 return true;
215 } else if (type.isSubtypeOf(declaringType)) { 224 } else if (type.isSubtypeOf(declaringType)) {
216 // maybe - but not if overridden somewhere 225 // maybe - but not if overridden somewhere
217 // !!! horrible hack for today - awful perf props 226 // TODO(jimhug): This lookup is not great for perf of this method.
218 return type.getMember(name) == this; 227 return type.getMember(name) == this;
219 //return true;
220 } else { 228 } else {
221 return false; 229 return false;
222 } 230 }
223 } else { 231 } else {
224 if (declaringType.isSubtypeOf(type)) { 232 if (declaringType.isSubtypeOf(type)) {
225 return true; 233 return true;
226 } else { 234 } else {
227 // If this is an interface, the actual implementation may 235 // If this is an interface, the actual implementation may
228 // come from a class that does not implement this interface. 236 // come from a class that does not implement this interface.
229 for (var t in declaringType.subtypes) { 237 for (var t in declaringType.subtypes) {
230 if (t.isSubtypeOf(type) && t.getMember(name) == this) { 238 if (t.isSubtypeOf(type) && t.getMember(name) == this) {
231 return true; 239 return true;
232 } 240 }
233 } 241 }
234 return false; 242 return false;
235 } 243 }
236 } 244 }
237 } 245 }
238 246
239 // TODO(jmesserly): isDynamic isn't a great name for this, something better? 247 abstract Value _get(CallingContext context, Node node, Value target);
240 abstract Value _get(MethodGenerator context, Node node, Value target,
241 [bool isDynamic]);
242 248
243 abstract Value _set(MethodGenerator context, Node node, Value target, 249 abstract Value _set(CallingContext context, Node node, Value target,
244 Value value, [bool isDynamic]); 250 Value value);
245 251
246 bool canInvoke(MethodGenerator context, Arguments args) { 252
247 // No source location needed because canInvoke may not produce errors. 253 bool canInvoke(CallingContext context, Arguments args) {
248 return canGet && 254 // Any gettable member whose return type is callable can be "invoked".
249 new Value(returnType, null, null).canInvoke(context, ':call', args); 255 if (canGet && (isField || isProperty)) {
256 return this.returnType.isFunction || this.returnType.isVar ||
257 this.returnType.getCallMethod() != null;
258 }
259 return false;
250 } 260 }
251 261
252 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, 262 Value invoke(CallingContext context, Node node, Value target,
253 [bool isDynamic=false]) { 263 Arguments args) {
254 var newTarget = _get(context, node, target, isDynamic); 264 var newTarget = _get(context, node, target);
255 return newTarget.invoke(context, ':call', node, args, isDynamic); 265 return newTarget.invoke(context, ':call', node, args);
256 } 266 }
257 267
258 bool override(Member other) { 268 bool override(Member other) {
259 if (isStatic) { 269 if (isStatic) {
260 world.error('static members can not hide parent members', 270 world.error('static members can not hide parent members',
261 span, other.span); 271 span, other.span);
262 return false; 272 return false;
263 } else if (other.isStatic) { 273 } else if (other.isStatic) {
264 world.error('can not override static member', span, other.span); 274 world.error('can not override static member', span, other.span);
265 return false; 275 return false;
266 } 276 }
267 return true; 277 return true;
268 } 278 }
269 279
270 String get generatedFactoryName() { 280 String get generatedFactoryName() {
271 assert(this.isFactory); 281 assert(this.isFactory);
272 String prefix = '${declaringType.jsname}.${constructorName}\$'; 282 String prefix = '${declaringType.genericType.jsname}.${constructorName}\$';
273 if (name == '') { 283 if (name == '') {
274 return '${prefix}factory'; 284 return '${prefix}factory';
275 } else { 285 } else {
276 return '${prefix}$name\$factory'; 286 return '${prefix}$name\$factory';
277 } 287 }
278 } 288 }
279 289
280 int hashCode() { 290 int hashCode() {
281 final typeCode = declaringType == null ? 1 : declaringType.hashCode(); 291 final typeCode = declaringType == null ? 1 : declaringType.hashCode();
282 final nameCode = isConstructor ? constructorName.hashCode() : 292 final nameCode = isConstructor ? constructorName.hashCode() :
283 name.hashCode(); 293 name.hashCode();
284 return (typeCode << 4) ^ nameCode; 294 return (typeCode << 4) ^ nameCode;
285 } 295 }
286 296
287 bool operator ==(other) { 297 bool operator ==(other) {
288 return other is Member && isConstructor == other.isConstructor && 298 return other is Member && isConstructor == other.isConstructor &&
289 declaringType == other.declaringType && (isConstructor ? 299 declaringType == other.declaringType && (isConstructor ?
290 constructorName == other.constructorName : name == other.name); 300 constructorName == other.constructorName : name == other.name);
291 } 301 }
302
303 /** Overriden to ensure that type arguments aren't used in static mems. */
304 Type resolveType(TypeReference node, bool typeErrors, bool allowTypeParams) {
305 allowTypeParams = allowTypeParams && !(isStatic && !isFactory);
306
307 return super.resolveType(node, typeErrors, allowTypeParams);
308 }
309
310 // TODO(jimhug): Make this abstract.
311 Member makeConcrete(Type concreteType) {
312 world.internalError('can not make this concrete', span);
313 }
292 } 314 }
293 315
294 316
295 /** 317 /**
296 * Types are treated as first class members of their library's top type. 318 * Types are treated as first class members of their library's top type.
297 */ 319 */
298 // TODO(jmesserly): perhaps Type should extend Member, but that can get 320 // TODO(jmesserly): perhaps Type should extend Member, but that can get
299 // complicated. 321 // complicated.
300 class TypeMember extends Member { 322 class TypeMember extends Member {
301 final DefinedType type; 323 final DefinedType type;
302 324
303 TypeMember(DefinedType type) 325 TypeMember(DefinedType type)
304 : super(type.name, type.library.topType), 326 : super(type.name, type.library.topType),
305 this.type = type; 327 this.type = type;
306 328
307 SourceSpan get span() => type.definition === null ? null : type.definition.spa n; 329 SourceSpan get span() => type.definition === null ? null : type.definition.spa n;
308 330
309 bool get isStatic() => true; 331 bool get isStatic() => true;
310 332
311 // If this really becomes first class, this should return typeof(Type) 333 // If this really becomes first class, this should return typeof(Type)
312 Type get returnType() => world.varType; 334 Type get returnType() => world.varType;
313 335
314 bool canInvoke(MethodGenerator context, Arguments args) => false; 336 bool canInvoke(CallingContext context, Arguments args) => false;
315 bool get canGet() => true; 337 bool get canGet() => true;
316 bool get canSet() => false; 338 bool get canSet() => false;
317 339
318 bool get requiresFieldSyntax() => true; 340 Value _get(CallingContext context, Node node, Value target) {
319
320 Value _get(MethodGenerator context, Node node, Value target,
321 [bool isDynamic=false]) {
322 return new TypeValue(type, node.span); 341 return new TypeValue(type, node.span);
323 } 342 }
324 343
325 Value _set(MethodGenerator context, Node node, Value target, Value value, 344 Value _set(CallingContext context, Node node, Value target, Value value) {
326 [bool isDynamic=false]) {
327 world.error('cannot set type', node.span); 345 world.error('cannot set type', node.span);
328 } 346 }
329 347
330 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, 348 Value invoke(CallingContext context, Node node, Value target,
331 [bool isDynamic=false]) { 349 Arguments args) {
332 world.error('cannot invoke type', node.span); 350 world.error('cannot invoke type', node.span);
333 } 351 }
334 } 352 }
335 353
336 /** Represents a Dart field from source code. */ 354 /** Represents a Dart field from source code. */
337 class FieldMember extends Member { 355 class FieldMember extends Member {
338 final VariableDefinition definition; 356 final VariableDefinition definition;
339 final Expression value; 357 final Expression value;
340 358
341 Type type; 359 Type type;
(...skipping 24 matching lines...) Expand all
366 // other.returnType.ensureAssignableFrom(returnType, null, true); 384 // other.returnType.ensureAssignableFrom(returnType, null, true);
367 return true; 385 return true;
368 // TODO(jimhug): Merge in overridesProperty logic here. 386 // TODO(jimhug): Merge in overridesProperty logic here.
369 } else { 387 } else {
370 world.error('field can not override anything but property', 388 world.error('field can not override anything but property',
371 span, other.span); 389 span, other.span);
372 return false; 390 return false;
373 } 391 }
374 } 392 }
375 393
376 void provideFieldSyntax() {} // Nothing to do. 394 void providePropertySyntax() {
377 void providePropertySyntax() { _providePropertySyntax = true; } 395 _providePropertySyntax = true;
396 if (genericMember !== null) {
397 genericMember.providePropertySyntax();
398 }
399 }
378 400
379 FieldMember(String name, Type declaringType, this.definition, this.value) 401 FieldMember(String name, Type declaringType, this.definition, this.value)
380 : super(name, declaringType), isNative = false; 402 : super(name, declaringType), isNative = false;
381 403
404 Member makeConcrete(Type concreteType) {
405 var ret = new FieldMember(name, concreteType, definition, value);
406 ret.genericMember = this;
407 ret._jsname = _jsname;
408 return ret;
409 }
410
411
382 SourceSpan get span() => definition == null ? null : definition.span; 412 SourceSpan get span() => definition == null ? null : definition.span;
383 413
384 Type get returnType() => type; 414 Type get returnType() => type;
385 415
386 bool get canGet() => true; 416 bool get canGet() => true;
387 bool get canSet() => !isFinal; 417 bool get canSet() => !isFinal;
388 418
389 bool get isField() => true; 419 bool get isField() => true;
390 420
391 resolve() { 421 resolve() {
392 isStatic = declaringType.isTop; 422 isStatic = declaringType.isTop;
393 isFinal = false; 423 isFinal = false;
394 if (definition.modifiers != null) { 424 if (definition.modifiers != null) {
395 for (var mod in definition.modifiers) { 425 for (var mod in definition.modifiers) {
396 if (mod.kind == TokenKind.STATIC) { 426 if (mod.kind == TokenKind.STATIC) {
397 if (isStatic) { 427 if (isStatic) {
398 world.error('duplicate static modifier', mod.span); 428 world.error('duplicate static modifier', mod.span);
399 } 429 }
400 isStatic = true; 430 isStatic = true;
401 } else if (mod.kind == TokenKind.FINAL) { 431 } else if (mod.kind == TokenKind.FINAL) {
402 if (isFinal) { 432 if (isFinal) {
403 world.error('duplicate final modifier', mod.span); 433 world.error('duplicate final modifier', mod.span);
404 } 434 }
405 isFinal = true; 435 isFinal = true;
406 } else { 436 } else {
407 world.error('${mod} modifier not allowed on field', mod.span); 437 world.error('${mod} modifier not allowed on field', mod.span);
408 } 438 }
409 } 439 }
410 } 440 }
411 type = resolveType(definition.type, false); 441 type = resolveType(definition.type, false, true);
412 if (isStatic && !isFactory && type.hasTypeParams) {
413 world.error('using type parameter in static context',
414 definition.type.span);
415 }
416 442
417 if (isStatic && isFinal && value == null) { 443 if (isStatic && isFinal && value == null) {
418 world.error('static final field is missing initializer', span); 444 world.error('static final field is missing initializer', span);
419 } 445 }
420 446
421 library._addMember(this); 447 if (declaringType.isClass) library._addMember(this);
422 } 448 }
423 449
424 450
425 bool _computing = false; 451 bool _computing = false;
426 /** Generates the initial value for this field, if any. Marks it as used. */ 452 /** Generates the initial value for this field, if any. Marks it as used. */
427 Value computeValue() { 453 Value computeValue() {
428 if (value == null) return null; 454 if (value == null) return null;
429 455
430 if (_computedValue == null) { 456 if (_computedValue == null) {
431 if (_computing) { 457 if (_computing) {
(...skipping 24 matching lines...) Expand all
456 } else { 482 } else {
457 _computedValue = world.gen.globalForStaticField( 483 _computedValue = world.gen.globalForStaticField(
458 this, _computedValue, [_computedValue]); 484 this, _computedValue, [_computedValue]);
459 } 485 }
460 } 486 }
461 _computing = false; 487 _computing = false;
462 } 488 }
463 return _computedValue; 489 return _computedValue;
464 } 490 }
465 491
466 Value _get(MethodGenerator context, Node node, Value target, 492 Value _get(CallingContext context, Node node, Value target) {
467 [bool isDynamic=false]) { 493 if (!context.needsCode) {
494 return new PureStaticValue(type, node.span, isStatic && isFinal);
495 }
496
468 if (isNative && returnType != null) { 497 if (isNative && returnType != null) {
469 returnType.markUsed(); 498 returnType.markUsed();
470 if (returnType is DefinedType) { 499 if (returnType is DefinedType) {
471 // TODO(jmesserly): this handles native fields that return types like 500 // TODO(jmesserly): this handles native fields that return types like
472 // "List". Is there a better solution for fields? Unlike methods we have 501 // "List". Is there a better solution for fields? Unlike methods we have
473 // no good way to annotate them. 502 // no good way to annotate them.
474 var defaultType = returnType.genericType.defaultType; 503 var defaultType = returnType.genericType.defaultType;
475 if (defaultType != null && defaultType.isNative) { 504 if (defaultType != null && defaultType.isNative) {
476 defaultType.markUsed(); 505 defaultType.markUsed();
477 } 506 }
(...skipping 26 matching lines...) Expand all
504 } 533 }
505 return new Value(type, '${declaringType.jsname}.$jsname', node.span); 534 return new Value(type, '${declaringType.jsname}.$jsname', node.span);
506 } else { 535 } else {
507 return new Value(type, 536 return new Value(type,
508 '\$globals.${declaringType.jsname}_$jsname', node.span); 537 '\$globals.${declaringType.jsname}_$jsname', node.span);
509 } 538 }
510 } 539 }
511 return new Value(type, '${target.code}.$jsname', node.span); 540 return new Value(type, '${target.code}.$jsname', node.span);
512 } 541 }
513 542
514 Value _set(MethodGenerator context, Node node, Value target, Value value, 543 Value _set(CallingContext context, Node node, Value target, Value value) {
515 [bool isDynamic=false]) { 544 if (!context.needsCode) {
516 var lhs = _get(context, node, target, isDynamic); 545 // TODO(jimhug): Add type checks here.
517 value = value.convertTo(context, type, isDynamic); 546 return new PureStaticValue(type, node.span);
547 }
548
549 var lhs = _get(context, node, target);
550 value = value.convertTo(context, type);
518 return new Value(type, '${lhs.code} = ${value.code}', node.span); 551 return new Value(type, '${lhs.code} = ${value.code}', node.span);
519 } 552 }
520 } 553 }
521 554
522 class PropertyMember extends Member { 555 class PropertyMember extends Member {
523 MethodMember getter; 556 MethodMember getter;
524 MethodMember setter; 557 MethodMember setter;
525 558
526 Member _overriddenField; 559 Member _overriddenField;
527 560
528 // TODO(jimhug): What is the right span for this beast? 561 // TODO(jimhug): What is the right span for this beast?
529 SourceSpan get span() => getter != null ? getter.span : null; 562 SourceSpan get span() => getter != null ? getter.span : null;
530 563
531 bool get canGet() => getter != null; 564 bool get canGet() => getter != null;
532 bool get canSet() => setter != null; 565 bool get canSet() => setter != null;
533 566
534 // If the property is just a declaration in an interface, continue to allow 567 // If the property is just a declaration in an interface, continue to allow
535 // field syntax in the generated code. 568 // field syntax in the generated code.
536 bool get requiresPropertySyntax() => declaringType.isClass; 569 bool get requiresPropertySyntax() => declaringType.isClass;
537 570
538 void provideFieldSyntax() { _provideFieldSyntax = true; } 571 // when overriding native fields, we still provide a field syntax to ensure
539 void providePropertySyntax() { 572 // that native functions will find the appropriate property implementation.
540 // when overriding native fields, we still provide a field syntax to ensure 573 // TODO(sigmund): should check for this transitively...
541 // that native functions will find the appropriate property implementation. 574 bool get needsFieldSyntax() =>
542 // TODO(sigmund): should check for this transitively... 575 _overriddenField != null && _overriddenField.isNative;
543 if (_overriddenField != null && _overriddenField.isNative) {
544 provideFieldSyntax();
545 }
546 }
547 576
548 // TODO(jimhug): Union of getter and setters sucks! 577 // TODO(jimhug): Union of getter and setters sucks!
549 bool get isStatic() => getter == null ? setter.isStatic : getter.isStatic; 578 bool get isStatic() => getter == null ? setter.isStatic : getter.isStatic;
550 579
551 bool get isProperty() => true; 580 bool get isProperty() => true;
552 581
553 Type get returnType() { 582 Type get returnType() {
554 return getter == null ? setter.returnType : getter.returnType; 583 return getter == null ? setter.returnType : getter.returnType;
555 } 584 }
556 585
557 PropertyMember(String name, Type declaringType): super(name, declaringType); 586 PropertyMember(String name, Type declaringType): super(name, declaringType);
558 587
588 Member makeConcrete(Type concreteType) {
589 var ret = new PropertyMember(name, concreteType);
590 if (getter !== null) ret.getter = getter.makeConcrete(concreteType);
591 if (setter !== null) ret.setter = setter.makeConcrete(concreteType);
592 ret._jsname = _jsname;
593 return ret;
594 }
595
559 bool override(Member other) { 596 bool override(Member other) {
560 if (!super.override(other)) return false; 597 if (!super.override(other)) return false;
561 598
562 // properties can override other properties and fields 599 // properties can override other properties and fields
563 if (other.isProperty || other.isField) { 600 if (other.isProperty || other.isField) {
564 // TODO(jimhug): 601 // TODO(jimhug):
565 // other.returnType.ensureAssignableFrom(returnType, null, true); 602 // other.returnType.ensureAssignableFrom(returnType, null, true);
566 if (other.isProperty) addFromParent(other); 603 if (other.isProperty) addFromParent(other);
567 else _overriddenField = other; 604 else _overriddenField = other;
568 return true; 605 return true;
569 } else { 606 } else {
570 world.error('property can only override field or property', 607 world.error('property can only override field or property',
571 span, other.span); 608 span, other.span);
572 return false; 609 return false;
573 } 610 }
574 } 611 }
575 612
576 Value _get(MethodGenerator context, Node node, Value target, 613 Value _get(CallingContext context, Node node, Value target) {
577 [bool isDynamic=false]) {
578 if (getter == null) { 614 if (getter == null) {
579 if (_overriddenField != null) { 615 if (_overriddenField != null) {
580 return _overriddenField._get(context, node, target, isDynamic); 616 return _overriddenField._get(context, node, target);
581 } 617 }
582 return target.invokeNoSuchMethod(context, 'get:$name', node); 618 return target.invokeNoSuchMethod(context, 'get:$name', node);
583 } 619 }
584 return getter.invoke(context, node, target, Arguments.EMPTY); 620 return getter.invoke(context, node, target, Arguments.EMPTY);
585 } 621 }
586 622
587 Value _set(MethodGenerator context, Node node, Value target, Value value, 623 Value _set(CallingContext context, Node node, Value target, Value value) {
588 [bool isDynamic=false]) {
589 if (setter == null) { 624 if (setter == null) {
590 if (_overriddenField != null) { 625 if (_overriddenField != null) {
591 return _overriddenField._set(context, node, target, value, isDynamic); 626 return _overriddenField._set(context, node, target, value);
592 } 627 }
593 return target.invokeNoSuchMethod(context, 'set:$name', node, 628 return target.invokeNoSuchMethod(context, 'set:$name', node,
594 new Arguments(null, [value])); 629 new Arguments(null, [value]));
595 } 630 }
596 return setter.invoke(context, node, target, new Arguments(null, [value]), 631 return setter.invoke(context, node, target, new Arguments(null, [value]));
597 isDynamic);
598 } 632 }
599 633
600 addFromParent(Member parentMember) { 634 addFromParent(Member parentMember) {
601 // TODO(jimhug): Egregious Hack! 635 final parent = parentMember;
602 PropertyMember parent;
603 if (parentMember is ConcreteMember) {
604 ConcreteMember c = parentMember;
605 parent = c.baseMember;
606 } else {
607 parent = parentMember;
608 }
609 636
610 if (getter == null) getter = parent.getter; 637 if (getter == null) getter = parent.getter;
611 if (setter == null) setter = parent.setter; 638 if (setter == null) setter = parent.setter;
612 } 639 }
613 640
614 resolve() { 641 resolve() {
615 if (getter != null) { 642 if (getter != null) {
616 getter.resolve(); 643 getter.resolve();
617 if (getter.parameters.length != 0) { 644 if (getter.parameters.length != 0) {
618 world.error('getter methods should take no arguments', 645 world.error('getter methods should take no arguments',
(...skipping 11 matching lines...) Expand all
630 setter.definition.span); 657 setter.definition.span);
631 } 658 }
632 // Not issue warning if setter is implicitly dynamic (returnType == null), 659 // Not issue warning if setter is implicitly dynamic (returnType == null),
633 // but do if it is explicit (returnType.isVar) 660 // but do if it is explicit (returnType.isVar)
634 if (!setter.returnType.isVoid && setter.definition.returnType != null) { 661 if (!setter.returnType.isVoid && setter.definition.returnType != null) {
635 world.warning('setter methods should be void', 662 world.warning('setter methods should be void',
636 setter.definition.returnType.span); 663 setter.definition.returnType.span);
637 } 664 }
638 } 665 }
639 666
640 library._addMember(this); 667 if (declaringType.isClass) library._addMember(this);
641 } 668 }
642 } 669 }
643 670
644
645 class ConcreteMember extends Member {
646 final Member baseMember;
647 Type returnType;
648 List<Parameter> parameters;
649
650 ConcreteMember(String name, ConcreteType declaringType, this.baseMember)
651 : super(name, declaringType) {
652 parameters = [];
653 returnType = baseMember.returnType.resolveTypeParams(declaringType);
654 // TODO(jimhug): Optimize not creating new array if no new param types.
655 for (var p in baseMember.parameters) {
656 var newType = p.type.resolveTypeParams(declaringType);
657 if (newType != p.type) {
658 parameters.add(p.copyWithNewType(this, newType));
659 } else {
660 parameters.add(p);
661 }
662 }
663 }
664
665 SourceSpan get span() => baseMember.span;
666
667 bool get isStatic() => baseMember.isStatic;
668 bool get isAbstract() => baseMember.isAbstract;
669 bool get isConst() => baseMember.isConst;
670 bool get isFactory() => baseMember.isFactory;
671 bool get isFinal() => baseMember.isFinal;
672 bool get isNative() => baseMember.isNative;
673
674 String get jsname() => baseMember.jsname;
675 set jsname(String name) =>
676 world.internalError('bad set of jsname on ConcreteMember');
677
678
679 bool get canGet() => baseMember.canGet;
680 bool get canSet() => baseMember.canSet;
681 bool canInvoke(MethodGenerator context, Arguments args) =>
682 baseMember.canInvoke(context, args);
683
684 bool get isField() => baseMember.isField;
685 bool get isMethod() => baseMember.isMethod;
686 bool get isProperty() => baseMember.isProperty;
687
688 bool get requiresPropertySyntax() => baseMember.requiresPropertySyntax;
689 bool get requiresFieldSyntax() => baseMember.requiresFieldSyntax;
690
691 void provideFieldSyntax() => baseMember.provideFieldSyntax();
692 void providePropertySyntax() => baseMember.providePropertySyntax();
693
694 bool get isConstructor() => name == declaringType.name;
695
696 String get constructorName() => baseMember.constructorName;
697
698 Definition get definition() => baseMember.definition;
699
700 // TODO(sigmund): this is EGREGIOUS
701 Member get initDelegate() => baseMember.initDelegate;
702 void set initDelegate(ctor) { baseMember.initDelegate = ctor; }
703
704 Type resolveType(TypeReference node, bool isRequired) {
705 var type = baseMember.resolveType(node, isRequired);
706 return type.resolveTypeParams(declaringType);
707 }
708
709 Value computeValue() => baseMember.computeValue();
710
711 // TODO(jimhug): Add support for type params.
712 bool override(Member other) => baseMember.override(other);
713
714 Value _get(MethodGenerator context, Node node, Value target,
715 [bool isDynamic=false]) {
716 Value ret = baseMember._get(context, node, target, isDynamic);
717 return new Value(inferredResult, ret.code, node.span);
718 }
719
720 Value _set(MethodGenerator context, Node node, Value target, Value value,
721 [bool isDynamic=false]) {
722 // TODO(jimhug): Check arg types in context of concrete type.
723 Value ret = baseMember._set(context, node, target, value, isDynamic);
724 return new Value(returnType, ret.code, node.span);
725 }
726
727 _evalConstConstructor(ObjectValue newObject, Arguments args) {
728 // TODO(jimhug): Concrete type probably matters somehow here
729 return baseMember.dynamic._evalConstConstructor(newObject, args);
730 }
731
732
733 Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
734 [bool isDynamic=false]) {
735 // TODO(jimhug): Check arg types in context of concrete type.
736 // TODO(jmesserly): I think what needs to happen is to move MethodMember's
737 // invoke so that it's run against the "parameters" and "returnType" of the
738 // ConcreteMember instead.
739 Value ret = baseMember.invoke(context, node, target, args, isDynamic);
740 var code = ret.code;
741 if (isConstructor) {
742 // TODO(jimhug): Egregious hack - won't live through the year.
743 code = code.replaceFirst(
744 declaringType.genericType.jsname, declaringType.jsname);
745 }
746 if (baseMember is MethodMember) {
747 declaringType.genMethod(this);
748 }
749 return new Value(inferredResult, code, node.span);
750 }
751 }
752
753 671
754 /** Represents a Dart method or top-level function. */ 672 /** Represents a Dart method or top-level function. */
755 class MethodMember extends Member { 673 class MethodMember extends Member {
756 FunctionDefinition definition; 674 FunctionDefinition definition;
757 Type returnType; 675 Type returnType;
758 List<Parameter> parameters; 676 List<Parameter> parameters;
759 677
678 MethodData _methodData;
679
760 Type _functionType; 680 Type _functionType;
761 bool isStatic = false; 681 bool isStatic = false;
762 bool isAbstract = false; 682 bool isAbstract = false;
763 683
764 // Note: these two modifiers are only legal on constructors 684 // Note: these two modifiers are only legal on constructors
765 bool isConst = false; 685 bool isConst = false;
766 bool isFactory = false; 686 bool isFactory = false;
767 687
768 /** True if this is a function defined inside another method. */ 688 /** True if this is a function defined inside another method. */
769 bool isLambda = false; 689 bool isLambda = false;
770 690
771 /** 691 /**
772 * True if we should provide info on optional parameters for use by runtime 692 * True if we should provide info on optional parameters for use by runtime
773 * dispatch. 693 * dispatch.
774 */ 694 */
775 bool _provideOptionalParamInfo = false; 695 bool _provideOptionalParamInfo = false;
776 696
777 /* 697 /*
778 * When this is a constructor, contains any other constructor called during 698 * When this is a constructor, contains any other constructor called during
779 * initialization (if any). 699 * initialization (if any).
780 */ 700 */
781 Member initDelegate; 701 Member initDelegate;
782 702
783 MethodMember(String name, Type declaringType, this.definition) 703 MethodMember(String name, Type declaringType, this.definition)
784 : super(name, declaringType); 704 : super(name, declaringType);
785 705
706 Member makeConcrete(Type concreteType) {
707 var _name = isConstructor ? concreteType.name : name;
708 var ret = new MethodMember(_name, concreteType, definition);
709 ret.genericMember = this;
710 ret._jsname = _jsname;
711 return ret;
712 }
713
714 MethodData get methodData() {
715 if (genericMember !== null) return genericMember.dynamic.methodData;
716
717 if (_methodData === null) {
718 _methodData = new MethodData(this);
719 }
720 return _methodData;
721 }
722
786 bool get isConstructor() => name == declaringType.name; 723 bool get isConstructor() => name == declaringType.name;
787 bool get isMethod() => !isConstructor; 724 bool get isMethod() => !isConstructor;
788 725
789 bool get isNative() => definition.nativeBody != null; 726 bool get isNative() => definition.nativeBody != null;
790 727
791 bool get canGet() => true; 728 bool get canGet() => true;
792 bool get canSet() => false; 729 bool get canSet() => false;
793 730
794 bool get requiresPropertySyntax() => true; 731 bool get requiresPropertySyntax() => true;
795 732
(...skipping 10 matching lines...) Expand all
806 if (returnType.names != null) { 743 if (returnType.names != null) {
807 return returnType.names[0].name; 744 return returnType.names[0].name;
808 } else if (returnType.name != null) { 745 } else if (returnType.name != null) {
809 return returnType.name.name; 746 return returnType.name.name;
810 } 747 }
811 world.internalError('no valid constructor name', definition.span); 748 world.internalError('no valid constructor name', definition.span);
812 } 749 }
813 750
814 Type get functionType() { 751 Type get functionType() {
815 if (_functionType == null) { 752 if (_functionType == null) {
816 _functionType = 753 _functionType = library.getOrAddFunctionType(declaringType, name,
817 library.getOrAddFunctionType(declaringType, name, definition); 754 definition, methodData);
818 // TODO(jimhug): Better resolution checks. 755 // TODO(jimhug): Better resolution checks.
819 if (parameters == null) { 756 if (parameters == null) {
820 resolve(); 757 resolve();
821 } 758 }
822 } 759 }
823 return _functionType; 760 return _functionType;
824 } 761 }
825 762
826 bool override(Member other) { 763 bool override(Member other) {
827 if (!super.override(other)) return false; 764 if (!super.override(other)) return false;
828 765
829 // methods can only override other methods 766 // methods can only override other methods
830 if (other.isMethod) { 767 if (other.isMethod) {
831 // TODO(jimhug): 768 // TODO(jimhug):
832 // other.returnType.ensureAssignableFrom(returnType, null, true); 769 // other.returnType.ensureAssignableFrom(returnType, null, true);
833 // TODO(jimhug): Check for further parameter compatibility. 770 // TODO(jimhug): Check for further parameter compatibility.
834 return true; 771 return true;
835 } else { 772 } else {
836 world.error('method can only override methods', span, other.span); 773 world.error('method can only override methods', span, other.span);
837 return false; 774 return false;
838 } 775 }
839 } 776 }
840 777
841 bool canInvoke(MethodGenerator context, Arguments args) { 778 bool canInvoke(CallingContext context, Arguments args) {
842 int bareCount = args.bareCount; 779 int bareCount = args.bareCount;
843 780
844 if (bareCount > parameters.length) return false; 781 if (bareCount > parameters.length) return false;
845 782
846 if (bareCount == parameters.length) { 783 if (bareCount == parameters.length) {
847 if (bareCount != args.length) return false; 784 if (bareCount != args.length) return false;
848 } else { 785 } else {
849 if (!parameters[bareCount].isOptional) return false; 786 if (!parameters[bareCount].isOptional) return false;
850 787
851 for (int i = bareCount; i < args.length; i++) { 788 for (int i = bareCount; i < args.length; i++) {
(...skipping 11 matching lines...) Expand all
863 int indexOfParameter(String name) { 800 int indexOfParameter(String name) {
864 for (int i = 0; i < parameters.length; i++) { 801 for (int i = 0; i < parameters.length; i++) {
865 final p = parameters[i]; 802 final p = parameters[i];
866 if (p.isOptional && p.name == name) { 803 if (p.isOptional && p.name == name) {
867 return i; 804 return i;
868 } 805 }
869 } 806 }
870 return -1; 807 return -1;
871 } 808 }
872 809
873 void provideFieldSyntax() { _provideFieldSyntax = true; }
874 void providePropertySyntax() { _providePropertySyntax = true; } 810 void providePropertySyntax() { _providePropertySyntax = true; }
875 811
876 Value _set(MethodGenerator context, Node node, Value target, Value value, 812 Value _set(CallingContext context, Node node, Value target, Value value) {
877 [bool isDynamic=false]) {
878 world.error('cannot set method', node.span); 813 world.error('cannot set method', node.span);
879 } 814 }
880 815
881 Value _get(MethodGenerator context, Node node, Value target, 816 Value _get(CallingContext context, Node node, Value target) {
882 [bool isDynamic=false]) { 817 if (!context.needsCode) {
818 return new PureStaticValue(functionType, node.span);
819 }
820
883 // TODO(jimhug): Would prefer to invoke! 821 // TODO(jimhug): Would prefer to invoke!
884 declaringType.genMethod(this); 822 declaringType.genMethod(this);
885 _provideOptionalParamInfo = true; 823 _provideOptionalParamInfo = true;
886 if (isStatic) { 824 if (isStatic) {
887 // ensure the type is generated. 825 // ensure the type is generated.
888 // TODO(sigmund): can we avoid generating the entire type, but only what 826 // TODO(sigmund): can we avoid generating the entire type, but only what
889 // we need? 827 // we need?
890 declaringType.markUsed(); 828 declaringType.markUsed();
891 var type = declaringType.isTop ? '' : '${declaringType.jsname}.'; 829 var type = declaringType.isTop ? '' : '${declaringType.jsname}.';
892 return new Value(functionType, '$type$jsname', node.span); 830 return new Value(functionType, '$type$jsname', node.span);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 bool needsArgumentConversion(Arguments args) { 875 bool needsArgumentConversion(Arguments args) {
938 int bareCount = args.bareCount; 876 int bareCount = args.bareCount;
939 for (int i = 0; i < bareCount; i++) { 877 for (int i = 0; i < bareCount; i++) {
940 var arg = args.values[i]; 878 var arg = args.values[i];
941 if (arg.needsConversion(parameters[i].type)) { 879 if (arg.needsConversion(parameters[i].type)) {
942 return true; 880 return true;
943 } 881 }
944 } 882 }
945 883
946 if (bareCount < parameters.length) { 884 if (bareCount < parameters.length) {
947 genParameterValues();
948 for (int i = bareCount; i < parameters.length; i++) { 885 for (int i = bareCount; i < parameters.length; i++) {
949 var arg = args.getValue(parameters[i].name); 886 var arg = args.getValue(parameters[i].name);
950 if (arg != null && arg.needsConversion(parameters[i].type)) { 887 if (arg != null && arg.needsConversion(parameters[i].type)) {
951 return true; 888 return true;
952 } 889 }
953 } 890 }
954 } 891 }
955 892
956 return false; 893 return false;
957 } 894 }
958 895
959 static String _argCountMsg(int actual, int expected, [bool atLeast=false]) { 896 static String _argCountMsg(int actual, int expected, [bool atLeast=false]) {
960 return 'wrong number of positional arguments, expected ' + 897 return 'wrong number of positional arguments, expected ' +
961 '${atLeast ? "at least " : ""}$expected but found $actual'; 898 '${atLeast ? "at least " : ""}$expected but found $actual';
962 } 899 }
963 900
964 Value _argError(MethodGenerator context, Node node, Value target, 901 Value _argError(CallingContext context, Node node, Value target,
965 Arguments args, String msg, int argIndex) { 902 Arguments args, String msg, int argIndex) {
966 SourceSpan span; 903 SourceSpan span;
967 if ((args.nodes == null) || (argIndex >= args.nodes.length)) { 904 if ((args.nodes == null) || (argIndex >= args.nodes.length)) {
968 span = node.span; 905 span = node.span;
969 } else { 906 } else {
970 span = args.nodes[argIndex].span; 907 span = args.nodes[argIndex].span;
971 } 908 }
972 if (isStatic || isConstructor) { 909 if (isStatic || isConstructor) {
973 world.error(msg, span); 910 world.error(msg, span);
974 } else { 911 } else {
975 world.warning(msg, span); 912 world.warning(msg, span);
976 } 913 }
977 return target.invokeNoSuchMethod(context, name, node, args); 914 return target.invokeNoSuchMethod(context, name, node, args);
978 } 915 }
979 916
980 genParameterValues() { 917 genParameterValues(CallingContext context) {
981 // Pure lazy? 918 // TODO(jimhug): Is this the right context?
982 for (var p in parameters) p.genValue(this, generator); 919 for (var p in parameters) p.genValue(this, context);
983 } 920 }
984 921
985 /** 922 /**
986 * Invokes this method on the given [target] with the given [args]. 923 * Invokes this method on the given [target] with the given [args].
987 * [node] provides a [SourceSpan] for any error messages. 924 * [node] provides a [SourceSpan] for any error messages.
988 */ 925 */
989 Value invoke(MethodGenerator context, Node node, Value target, 926 Value invoke(CallingContext context, Node node, Value target,
990 Arguments args, [bool isDynamic=false]) { 927 Arguments args) {
991 // TODO(jimhug): Fix this hack for ensuring a method is resolved. 928 if (!context.needsCode) {
992 if (parameters == null) { 929 // TODO(jimhug): Add argument type and name checks here.
993 world.info('surprised to need to resolve: ${declaringType.name}.$name'); 930 return new PureStaticValue(returnType, node.span);
994 resolve();
995 } 931 }
996 932
997 declaringType.genMethod(this); 933 declaringType.genMethod(this);
998 934
999 if (isStatic || isFactory) { 935 if (isStatic || isFactory) {
1000 // TODO(sigmund): can we avoid generating the entire type, but only what 936 // TODO(sigmund): can we avoid generating the entire type, but only what
1001 // we need? 937 // we need?
1002 declaringType.markUsed(); 938 declaringType.markUsed();
1003 } 939 }
1004 940
(...skipping 13 matching lines...) Expand all
1018 argsCode.add('this'); 954 argsCode.add('this');
1019 } 955 }
1020 956
1021 int bareCount = args.bareCount; 957 int bareCount = args.bareCount;
1022 for (int i = 0; i < bareCount; i++) { 958 for (int i = 0; i < bareCount; i++) {
1023 var arg = args.values[i]; 959 var arg = args.values[i];
1024 if (i >= parameters.length) { 960 if (i >= parameters.length) {
1025 var msg = _argCountMsg(args.length, parameters.length); 961 var msg = _argCountMsg(args.length, parameters.length);
1026 return _argError(context, node, target, args, msg, i); 962 return _argError(context, node, target, args, msg, i);
1027 } 963 }
1028 arg = arg.convertTo(context, parameters[i].type, isDynamic); 964 arg = arg.convertTo(context, parameters[i].type);
1029 argsCode.add(arg.code); 965 argsCode.add(arg.code);
1030 } 966 }
1031 967
1032 int namedArgsUsed = 0; 968 int namedArgsUsed = 0;
1033 if (bareCount < parameters.length) { 969 if (bareCount < parameters.length) {
1034 genParameterValues(); 970 genParameterValues(context);
1035 971
1036 for (int i = bareCount; i < parameters.length; i++) { 972 for (int i = bareCount; i < parameters.length; i++) {
1037 var arg = args.getValue(parameters[i].name); 973 var arg = args.getValue(parameters[i].name);
1038 if (arg == null) { 974 if (arg == null) {
1039 arg = parameters[i].value; 975 arg = parameters[i].value;
1040 } else { 976 } else {
1041 arg = arg.convertTo(context, parameters[i].type, isDynamic); 977 arg = arg.convertTo(context, parameters[i].type);
1042 namedArgsUsed++; 978 namedArgsUsed++;
1043 } 979 }
1044 980
1045 if (arg == null || !parameters[i].isOptional) { 981 if (arg == null || !parameters[i].isOptional) {
1046 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true); 982 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true);
1047 return _argError(context, node, target, args, msg, i); 983 return _argError(context, node, target, args, msg, i);
1048 } else { 984 } else {
1049 argsCode.add(arg.code); 985 argsCode.add(arg.code);
1050 } 986 }
1051 } 987 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1083 return _invokeConstructor(context, node, target, args, argsString); 1019 return _invokeConstructor(context, node, target, args, argsString);
1084 } 1020 }
1085 1021
1086 if (target.isSuper) { 1022 if (target.isSuper) {
1087 return new Value(inferredResult, 1023 return new Value(inferredResult,
1088 '${declaringType.jsname}.prototype.$jsname.call($argsString)', 1024 '${declaringType.jsname}.prototype.$jsname.call($argsString)',
1089 node.span); 1025 node.span);
1090 } 1026 }
1091 1027
1092 if (isOperator) { 1028 if (isOperator) {
1093 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); 1029 return _invokeBuiltin(context, node, target, args, argsCode);
1094 } 1030 }
1095 1031
1096 if (isFactory) { 1032 if (isFactory) {
1097 assert(target.isType); 1033 assert(target.isType);
1098 return new Value(target.type, '$generatedFactoryName($argsString)', 1034 return new Value(target.type, '$generatedFactoryName($argsString)',
1099 node !== null ? node.span : null); 1035 node !== null ? node.span : null);
1100 } 1036 }
1101 1037
1102 if (isStatic) { 1038 if (isStatic) {
1103 if (declaringType.isTop) { 1039 if (declaringType.isTop) {
1104 return new Value(inferredResult, 1040 return new Value(inferredResult,
1105 '$jsname($argsString)', node !== null ? node.span : null); 1041 '$jsname($argsString)', node !== null ? node.span : null);
1106 } 1042 }
1107 return new Value(inferredResult, 1043 return new Value(inferredResult,
1108 '${declaringType.jsname}.$jsname($argsString)', node.span); 1044 '${declaringType.jsname}.$jsname($argsString)', node.span);
1109 } 1045 }
1110 1046
1111 // TODO(jmesserly): factor this better 1047 // TODO(jmesserly): factor this better
1112 if (name == 'get:typeName' && declaringType.library.isDom) { 1048 if (name == 'get:typeName' && declaringType.library.isDom) {
1113 world.gen.corejs.ensureTypeNameOf(); 1049 world.gen.corejs.ensureTypeNameOf();
1114 } 1050 }
1115 1051
1116 var code = '${target.code}.$jsname($argsString)'; 1052 var code = '${target.code}.$jsname($argsString)';
1117 return new Value(inferredResult, code, node.span); 1053 return new Value(inferredResult, code, node.span);
1118 } 1054 }
1119 1055
1120 Value _invokeConstructor(MethodGenerator context, Node node, 1056 Value _invokeConstructor(CallingContext context, Node node,
1121 Value target, Arguments args, argsString) { 1057 Value target, Arguments args, argsString) {
1122 declaringType.markUsed(); 1058 declaringType.markUsed();
1123 1059
1124 String ctor = constructorName; 1060 String ctor = constructorName;
1125 if (ctor != '') ctor = '.${ctor}\$ctor'; 1061 if (ctor != '') ctor = '.${ctor}\$ctor';
1126 1062
1127 final span = node != null ? node.span : target.span; 1063 final span = node != null ? node.span : target.span;
1128 if (!target.isType) { 1064 if (!target.isType) {
1129 // initializer call to another constructor 1065 // initializer call to another constructor
1130 var code = '${declaringType.nativeName}${ctor}.call($argsString)'; 1066 var code = '${declaringType.nativeName}${ctor}.call($argsString)';
(...skipping 17 matching lines...) Expand all
1148 return world.gen.globalForConst(newObject, [args.values]); 1084 return world.gen.globalForConst(newObject, [args.values]);
1149 } else { 1085 } else {
1150 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; 1086 var code = 'new ${declaringType.nativeName}${ctor}($argsString)';
1151 return new Value(target.type, code, span); 1087 return new Value(target.type, code, span);
1152 } 1088 }
1153 } 1089 }
1154 } 1090 }
1155 1091
1156 _evalConstConstructor(Value newObject, Arguments args) { 1092 _evalConstConstructor(Value newObject, Arguments args) {
1157 declaringType.markUsed(); 1093 declaringType.markUsed();
1158 var generator = new MethodGenerator(this, null); 1094 methodData.eval(this, newObject, args);
1159 generator.evalBody(newObject, args);
1160 } 1095 }
1161 1096
1162 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, 1097 Value _invokeBuiltin(CallingContext context, Node node, Value target,
1163 Arguments args, argsCode, bool isDynamic) { 1098 Arguments args, argsCode) {
1164 // Handle some fast paths for Number, String, List and DOM. 1099 // Handle some fast paths for Number, String, List and DOM.
1165 if (declaringType.isNum) { 1100 if (target.type.isNum) {
1166 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num. 1101 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num.
1167 // TODO(jimhug): What about null? 1102 // TODO(jimhug): What about null?
1168 var code; 1103 var code = null;
1169 if (name == ':negate') { 1104 if (args.length == 0) {
1170 code = '-${target.code}'; 1105 if (name == ':negate') {
1171 } else if (name == ':bit_not') { 1106 code = '-${target.code}';
1172 code = '~${target.code}'; 1107 } else if (name == ':bit_not') {
1173 } else if (name == ':truncdiv' || name == ':mod') { 1108 code = '~${target.code}';
1174 world.gen.corejs.useOperator(name); 1109 }
1175 code = '$jsname(${target.code}, ${argsCode[0]})'; 1110 } else if (args.length == 1 && args.values[0].type.isNum) {
1176 } else { 1111 if (name == ':truncdiv' || name == ':mod') {
1177 var op = TokenKind.rawOperatorFromMethod(name); 1112 world.gen.corejs.useOperator(name);
1178 code = '${target.code} $op ${argsCode[0]}'; 1113 code = '$jsname(${target.code}, ${argsCode[0]})';
1114 } else {
1115 var op = TokenKind.rawOperatorFromMethod(name);
1116 code = '${target.code} $op ${argsCode[0]}';
1117 }
1179 } 1118 }
1180 1119 if (code !== null) {
1181 return new Value(inferredResult, code, node.span); 1120 return new Value(inferredResult, code, node.span);
1182 } else if (declaringType.isString) { 1121 }
1183 if (name == ':index') { 1122 } else if (target.type.isString) {
1123 if (name == ':index' && args.values[0].type.isNum) {
1184 return new Value(declaringType, '${target.code}[${argsCode[0]}]', 1124 return new Value(declaringType, '${target.code}[${argsCode[0]}]',
1185 node.span); 1125 node.span);
1186 } else if (name == ':add') { 1126 } else if (name == ':add' && args.values[0].type.isNum) {
1187 return new Value(declaringType, '${target.code} + ${argsCode[0]}', 1127 return new Value(declaringType, '${target.code} + ${argsCode[0]}',
1188 node.span); 1128 node.span);
1189 } 1129 }
1190 } else if (declaringType.isNative) { 1130 } else if (declaringType.isNative) {
1191 if (name == ':index') { 1131 if (args.length > 0 && args.values[0].type.isNum) {
1192 return 1132 // TODO(jimhug): make more accurate/reliable
1193 new Value(returnType, '${target.code}[${argsCode[0]}]', node.span); 1133 if (name == ':index') {
1194 } else if (name == ':setindex') { 1134 return
1195 return new Value(returnType, 1135 new Value(returnType, '${target.code}[${argsCode[0]}]', node.span) ;
1196 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); 1136 } else if (name == ':setindex') {
1137 return new Value(returnType,
1138 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span);
1139 }
1197 } 1140 }
1198 } 1141 }
1199 1142
1200 // TODO(jimhug): Optimize null on lhs as well. 1143 // TODO(jimhug): Optimize null on lhs as well.
1201 if (name == ':eq' || name == ':ne') { 1144 if (name == ':eq' || name == ':ne') {
1202 final op = name == ':eq' ? '==' : '!='; 1145 final op = name == ':eq' ? '==' : '!=';
1203 1146
1204 if (name == ':ne') { 1147 if (name == ':ne') {
1205 // Ensure == is generated. 1148 // Ensure == is generated.
1206 target.invoke(context, ':eq', node, args, isDynamic); 1149 target.invoke(context, ':eq', node, args);
1207 } 1150 }
1208 1151
1209 // Optimize test when null is on the rhs. 1152 // Optimize test when null is on the rhs.
1210 if (argsCode[0] == 'null') { 1153 if (argsCode[0] == 'null') {
1211 return new Value(inferredResult, '${target.code} $op null', node.span); 1154 return new Value(inferredResult, '${target.code} $op null', node.span);
1212 } else if (target.type.isNum || target.type.isString) { 1155 } else if (target.type.isNum || target.type.isString) {
1213 // TODO(jimhug): Maybe check rhs. 1156 // TODO(jimhug): Maybe check rhs.
1214 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}', 1157 return new Value(inferredResult, '${target.code} $op ${argsCode[0]}',
1215 node.span); 1158 node.span);
1216 } 1159 }
1217 world.gen.corejs.useOperator(name); 1160 world.gen.corejs.useOperator(name);
1218 // TODO(jimhug): Should be able to use faster path sometimes here! 1161 // TODO(jimhug): Should be able to use faster path sometimes here!
1219 return new Value(inferredResult, 1162 return new Value(inferredResult,
1220 '$jsname(${target.code}, ${argsCode[0]})', node.span); 1163 '$jsname(${target.code}, ${argsCode[0]})', node.span);
1221 } 1164 }
1222 1165
1223 if (isCallMethod) { 1166 if (isCallMethod) {
1224 declaringType.markUsed(); 1167 declaringType.markUsed();
1225 return new Value(inferredResult, 1168 return new Value(inferredResult,
1226 '${target.code}(${Strings.join(argsCode, ", ")})', node.span); 1169 '${target.code}(${Strings.join(argsCode, ", ")})', node.span);
1227 } 1170 }
1228 1171
1172 // TODO(jimhug): Reconcile with MethodSet version - ideally just eliminate
1229 if (name == ':index') { 1173 if (name == ':index') {
1230 world.gen.corejs.useIndex = true; 1174 world.gen.corejs.useIndex = true;
1231 } else if (name == ':setindex') { 1175 } else if (name == ':setindex') {
1232 world.gen.corejs.useSetIndex = true; 1176 world.gen.corejs.useSetIndex = true;
1177 } else {
1178 world.gen.corejs.useOperator(name);
1179 var argsString = argsCode.length == 0 ? '' : ', ${argsCode[0]}';
1180 return new Value(returnType, '$jsname(${target.code}${argsString})',
1181 node.span);
1233 } 1182 }
1234 1183
1235 // Fall back to normal method invocation. 1184 // Fall back to normal method invocation.
1236 var argsString = Strings.join(argsCode, ', '); 1185 var argsString = Strings.join(argsCode, ', ');
1237 return new Value(inferredResult, '${target.code}.$jsname($argsString)', 1186 return new Value(inferredResult, '${target.code}.$jsname($argsString)',
1238 node.span); 1187 node.span);
1239 } 1188 }
1240 1189
1241 resolve() { 1190 resolve() {
1242 // TODO(jimhug): work through side-by-side with spec 1191 // TODO(jimhug): work through side-by-side with spec
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1309 } else { 1258 } else {
1310 if (definition.body == null && !isConstructor && !isNative) { 1259 if (definition.body == null && !isConstructor && !isNative) {
1311 world.error('method needs a body', span); 1260 world.error('method needs a body', span);
1312 } 1261 }
1313 } 1262 }
1314 1263
1315 if (isConstructor && !isFactory) { 1264 if (isConstructor && !isFactory) {
1316 returnType = declaringType; 1265 returnType = declaringType;
1317 } else { 1266 } else {
1318 // This is the one and only place we allow void. 1267 // This is the one and only place we allow void.
1319 returnType = resolveType(definition.returnType, false, allowVoid: true); 1268 if (definition.returnType is SimpleTypeReference &&
1269 definition.returnType.dynamic.type == world.voidType) {
1270 returnType = world.voidType;
1271 } else {
1272 returnType = resolveType(definition.returnType, false, !isStatic);
1273 }
1320 } 1274 }
1321 parameters = []; 1275 parameters = [];
1322 for (var formal in definition.formals) { 1276 for (var formal in definition.formals) {
1323 // TODO(jimhug): Clean up construction of Parameters. 1277 // TODO(jimhug): Clean up construction of Parameters.
1324 var param = new Parameter(formal, this); 1278 var param = new Parameter(formal, this);
1325 param.resolve(); 1279 param.resolve();
1326 parameters.add(param); 1280 parameters.add(param);
1327 } 1281 }
1328 1282
1329 if (!isLambda) { 1283 if (!isLambda && declaringType.isClass) {
1330 library._addMember(this); 1284 library._addMember(this);
1331 } 1285 }
1332 } 1286 }
1333
1334 /** Overriden to ensure that type arguments aren't used in static methods. */
1335 Type resolveType(TypeReference node, bool typeErrors,
1336 [bool allowVoid = false]) {
1337 Type t = super.resolveType(node, typeErrors);
1338 if (isStatic && !isFactory && t is ParameterType) {
1339 world.error('using type parameter in static context.', node.span);
1340 }
1341 if (!allowVoid && t.isVoid) {
1342 world.error('"void" only allowed as return type', node.span);
1343 }
1344 return t;
1345 }
1346 } 1287 }
1347 1288
1348 1289
1349 class MemberSet {
1350 final String name;
1351 final List<Member> members;
1352 final String jsname;
1353 final bool isVar;
1354
1355 MemberSet(Member member, [bool isVar=false]):
1356 name = member.name, members = [member], jsname = member.jsname,
1357 isVar = isVar;
1358
1359 toString() => '$name:${members.length}';
1360
1361 // TODO(jimhug): Still working towards the right logic for conflicts...
1362 bool get containsProperties() => members.some((m) => m is PropertyMember);
1363 bool get containsMethods() => members.some((m) => m is MethodMember);
1364
1365
1366 void add(Member member) => members.add(member);
1367
1368 // TODO(jimhug): Always false, or is this needed?
1369 bool get isStatic() => members.length == 1 && members[0].isStatic;
1370 bool get isOperator() => members[0].isOperator;
1371
1372 bool canInvoke(MethodGenerator context, Arguments args) =>
1373 members.some((m) => m.canInvoke(context, args));
1374
1375 Value _makeError(Node node, Value target, String action) {
1376 if (!target.type.isVar) {
1377 world.warning('could not find applicable $action for "$name"', node.span);
1378 }
1379 return new Value(world.varType,
1380 '${target.code}.$jsname() /*no applicable $action*/', node.span);
1381 }
1382
1383 bool _treatAsField;
1384 bool get treatAsField() {
1385 if (_treatAsField == null) {
1386 // If this is the global MemberSet from world, always bind dynamically.
1387 // Note: we need this for proper noSuchMethod and REPL behavior.
1388 _treatAsField = !isVar && (members.some((m) => m.requiresFieldSyntax)
1389 || members.every((m) => !m.requiresPropertySyntax));
1390
1391 for (var member in members) {
1392 if (_treatAsField) {
1393 member.provideFieldSyntax();
1394 } else {
1395 member.providePropertySyntax();
1396 }
1397 }
1398 }
1399 return _treatAsField;
1400 }
1401
1402 Value _get(MethodGenerator context, Node node, Value target,
1403 [bool isDynamic=false]) {
1404 // If this is the global MemberSet from world, always bind dynamically.
1405 // Note: we need this for proper noSuchMethod and REPL behavior.
1406 Value returnValue;
1407 if (members.length == 1 && !isVar) {
1408 return members[0]._get(context, node, target, isDynamic);
1409 }
1410
1411
1412 final targets = members.filter((m) => m.canGet);
1413 if (isVar) {
1414 targets.forEach((m) => m._get(context, node, target, isDynamic: true));
1415 returnValue = new Value(_foldTypes(targets), null, node.span);
1416 } else {
1417 if (members.length == 1) {
1418 return members[0]._get(context, node, target, isDynamic);
1419 } else if (targets.length == 1) {
1420 return targets[0]._get(context, node, target, isDynamic);
1421 }
1422
1423 for (var member in targets) {
1424 final value = member._get(context, node, target, isDynamic:true);
1425 returnValue = _tryUnion(returnValue, value, node);
1426 }
1427 if (returnValue == null) {
1428 return _makeError(node, target, 'getter');
1429 }
1430 }
1431
1432 if (returnValue.code == null) {
1433 if (treatAsField) {
1434 return new Value(returnValue.type, '${target.code}.$jsname',
1435 node.span);
1436 } else {
1437 return new Value(returnValue.type, '${target.code}.get\$$jsname()',
1438 node.span);
1439 }
1440 }
1441 return returnValue;
1442 }
1443
1444 Value _set(MethodGenerator context, Node node, Value target, Value value,
1445 [bool isDynamic=false]) {
1446 // If this is the global MemberSet from world, always bind dynamically.
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
1452 Value returnValue;
1453 final targets = members.filter((m) => m.canSet);
1454 if (isVar) {
1455 targets.forEach((m) =>
1456 m._set(context, node, target, value, isDynamic: true));
1457 returnValue = new Value(_foldTypes(targets), null, node.span);
1458 } else {
1459 if (members.length == 1) {
1460 return members[0]._set(context, node, target, value, isDynamic);
1461 } else if (targets.length == 1) {
1462 return targets[0]._set(context, node, target, value, isDynamic);
1463 }
1464
1465 for (var member in targets) {
1466 final res = member._set(context, node, target, value, isDynamic:true);
1467 returnValue = _tryUnion(returnValue, res, node);
1468 }
1469 if (returnValue == null) {
1470 return _makeError(node, target, 'setter');
1471 }
1472 }
1473
1474 if (returnValue.code == null) {
1475 if (treatAsField) {
1476 return new Value(returnValue.type,
1477 '${target.code}.$jsname = ${value.code}', node.span);
1478 } else {
1479 return new Value(returnValue.type,
1480 '${target.code}.set\$$jsname(${value.code})', node.span);
1481 }
1482 }
1483 return returnValue;
1484 }
1485
1486 Value invoke(MethodGenerator context, Node node, Value target,
1487 Arguments args, [bool isDynamic=false]) {
1488 // If this is the global MemberSet from world, always bind dynamically.
1489 // Note: we need this for proper noSuchMethod and REPL behavior.
1490 if (isVar && !isOperator) {
1491 return invokeOnVar(context, node, target, args);
1492 }
1493
1494 if (members.length == 1 && !isVar) {
1495 return members[0].invoke(context, node, target, args, isDynamic);
1496 }
1497
1498 final targets = members.filter((m) => m.canInvoke(context, args));
1499 if (targets.length == 1) {
1500 return targets[0].invoke(context, node, target, args, isDynamic);
1501 }
1502
1503 Value returnValue = null;
1504 if (targets.length < 1000) {
1505 for (var member in targets) {
1506 final res = member.invoke(context, node, target, args, isDynamic:true);
1507 // TODO(jmesserly): If the code has different type checks, it will fail to
1508 // unify and go through a dynamic stub. Good so far. However, we'll end
1509 // up with a bogus unused temp generated (usually "var $0"). We need a w ay
1510 // to throw away temps when we throw away the code.
1511 returnValue = _tryUnion(returnValue, res, node);
1512 }
1513
1514 if (returnValue == null) {
1515 return _makeError(node, target, 'method');
1516 }
1517 } else {
1518 returnValue = new Value(world.varType, null, node.span);
1519 }
1520
1521 if (returnValue.code == null) {
1522 if (name == ':call') {
1523 // TODO(jmesserly): reconcile this with similar code in Value
1524 return target._varCall(context, node, args);
1525 } else if (isOperator) {
1526 // TODO(jmesserly): make operators less special.
1527 return invokeSpecial(target, args, returnValue.type);
1528 } else {
1529 return invokeOnVar(context, node, target, args);
1530 }
1531 }
1532
1533 return returnValue;
1534 }
1535
1536 Value invokeSpecial(Value target, Arguments args, Type returnType) {
1537 assert(name.startsWith(':'));
1538 assert(!args.hasNames);
1539 // TODO(jimhug): We need to do this a little bit more like get and set on
1540 // properties. We should check the set of members for something
1541 // like "requiresNativeIndexer" and "requiresDartIndexer" to
1542 // decide on a strategy.
1543
1544 var argsString = args.getCode();
1545 // Most operator calls need to be emitted as function calls, so we don't
1546 // box numbers accidentally. Indexing is the exception.
1547 if (name == ':index' || name == ':setindex') {
1548 // TODO(jimhug): should not need this test both here and in invoke
1549 if (name == ':index') {
1550 world.gen.corejs.useIndex = true;
1551 } else if (name == ':setindex') {
1552 world.gen.corejs.useSetIndex = true;
1553 }
1554 return new Value(returnType, '${target.code}.$jsname($argsString)',
1555 target.span);
1556 } else {
1557 if (argsString.length > 0) argsString = ', $argsString';
1558 world.gen.corejs.useOperator(name);
1559 return new Value(returnType, '$jsname(${target.code}$argsString)',
1560 target.span);
1561 }
1562 }
1563
1564 Value invokeOnVar(MethodGenerator context, Node node, Value target,
1565 Arguments args) {
1566 context.counters.dynamicMethodCalls++;
1567 var member = getVarMember(context, node, args);
1568 return member.invoke(context, node, target, args);
1569 }
1570
1571 Value _union(Value x, Value y, Node node) {
1572 var result = _tryUnion(x, y, node);
1573 if (result.code == null) {
1574 world.internalError('mismatched code for $name (${x.code}, ${y.code})',
1575 node.span);
1576 }
1577 return result;
1578 }
1579
1580 // TODO(jimhug): This is icky - but this whole class needs cleanup.
1581 Value _tryUnion(Value x, Value y, Node node) {
1582 if (x == null) return y;
1583 var type = Type.union(x.type, y.type);
1584 if (x.code == y.code) {
1585 if (type == x.type) {
1586 return x;
1587 } else if (x.isConst || y.isConst) {
1588 world.internalError("unexpected: union of const values ");
1589 } else {
1590 return Value.union(x, y);
1591 }
1592 } else {
1593 return new Value(type, null, node.span);
1594 }
1595 }
1596
1597 dumpAllMembers() {
1598 for (var member in members) {
1599 world.warning('hard-multi $name on ${member.declaringType.name}',
1600 member.span);
1601 }
1602 }
1603
1604 VarMember getVarMember(MethodGenerator context, Node node, Arguments args) {
1605 if (world.objectType.varStubs == null) {
1606 world.objectType.varStubs = {};
1607 }
1608
1609 var stubName = _getCallStubName(name, args);
1610 var stub = world.objectType.varStubs[stubName];
1611 if (stub == null) {
1612 // Ensure that we're making stub with all possible members of this name.
1613 // We need this canonicalization step because only one VarMemberSet can
1614 // live on Object.prototype
1615 // TODO(jmesserly): this is ugly--we're throwing away type information!
1616 // The right solution is twofold:
1617 // 1. put stubs on a more precise type when possible
1618 // 2. merge VarMemberSets together if necessary
1619 final mset = context.findMembers(name).members;
1620
1621 final targets = mset.filter((m) => m.canInvoke(context, args));
1622 stub = new VarMethodSet(name, stubName, targets, args,
1623 _foldTypes(targets));
1624 world.objectType.varStubs[stubName] = stub;
1625 }
1626 return stub;
1627 }
1628
1629 Type _foldTypes(List<Member> targets) =>
1630 reduce(map(targets, (t) => t.returnType), Type.union, world.varType);
1631 }
1632
1633 /** 1290 /**
1634 * A [FactoryMap] maps type names to a list of factory constructors. 1291 * A [FactoryMap] maps type names to a list of factory constructors.
1635 * The constructors list is actually a map that maps factory names to 1292 * The constructors list is actually a map that maps factory names to
1636 * [MethodMember]. The reason why we need both indirections are: 1293 * [MethodMember]. The reason why we need both indirections are:
1637 * 1) A class can define factory methods for multiple interfaces. 1294 * 1) A class can define factory methods for multiple interfaces.
1638 * 2) A factory constructor can have a name. 1295 * 2) A factory constructor can have a name.
1639 * 1296 *
1640 * For example: 1297 * For example:
1641 * 1298 *
1642 * [: 1299 * [:
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1688 } 1345 }
1689 1346
1690 void forEach(void f(Member member)) { 1347 void forEach(void f(Member member)) {
1691 factories.forEach((_, Map constructors) { 1348 factories.forEach((_, Map constructors) {
1692 constructors.forEach((_, Member member) { 1349 constructors.forEach((_, Member member) {
1693 f(member); 1350 f(member);
1694 }); 1351 });
1695 }); 1352 });
1696 } 1353 }
1697 } 1354 }
OLDNEW
« frog/gen.dart ('K') | « frog/library.dart ('k') | frog/member_set.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698