| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 | 9 |
| 9 String name; | 10 String name; |
| 10 Type type; | 11 Type type; |
| 11 bool isInitializer = false; | 12 bool isInitializer = false; |
| 12 | 13 |
| 13 Value value; | 14 Value value; |
| 14 | 15 |
| 15 Parameter(this.definition); | 16 Parameter(this.definition, this.method); |
| 16 | 17 |
| 17 resolve(Member method, Type inType) { | 18 resolve() { |
| 18 name = definition.name.name; | 19 name = definition.name.name; |
| 19 if (name.startsWith('this.')) { | 20 if (name.startsWith('this.')) { |
| 20 name = name.substring(5); | 21 name = name.substring(5); |
| 21 isInitializer = true; | 22 isInitializer = true; |
| 22 } | 23 } |
| 23 | 24 |
| 24 type = inType.resolveType(definition.type, false); | 25 type = method.resolveType(definition.type, false); |
| 25 | 26 |
| 26 if (method.isStatic && type.hasTypeParams) { | 27 if (method.isStatic && method.typeParameters === null && type.hasTypeParams)
{ |
| 27 world.error('using type parameter in static context', definition.span); | 28 world.error('using type parameter in static context', definition.span); |
| 28 } | 29 } |
| 29 | 30 |
| 30 if (definition.value != null) { | 31 if (definition.value != null) { |
| 31 // To match VM, detect cases where value was not actually specified in | 32 // To match VM, detect cases where value was not actually specified in |
| 32 // code and don't signal errors. | 33 // code and don't signal errors. |
| 33 // TODO(jimhug): Clean up after issue #352 is resolved. | 34 // TODO(jimhug): Clean up after issue #352 is resolved. |
| 34 if (definition.value is NullExpression && | 35 if (definition.value is NullExpression && |
| 35 definition.value.span.start == definition.span.start) { | 36 definition.value.span.start == definition.span.start) { |
| 36 return; | 37 return; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 55 genValue(MethodMember method, MethodGenerator context) { | 56 genValue(MethodMember method, MethodGenerator context) { |
| 56 if (definition.value == null || value != null) return; | 57 if (definition.value == null || value != null) return; |
| 57 | 58 |
| 58 if (context == null) { // interface method | 59 if (context == null) { // interface method |
| 59 context = new MethodGenerator(method, null); | 60 context = new MethodGenerator(method, null); |
| 60 } | 61 } |
| 61 value = definition.value.visit(context); | 62 value = definition.value.visit(context); |
| 62 value = value.convertTo(context, type, definition.value); | 63 value = value.convertTo(context, type, definition.value); |
| 63 } | 64 } |
| 64 | 65 |
| 65 Parameter copyWithNewType(Type newType) { | 66 Parameter copyWithNewType(Member newMethod, Type newType) { |
| 66 var ret = new Parameter(definition); | 67 var ret = new Parameter(definition, newMethod); |
| 67 ret.type = newType; | 68 ret.type = newType; |
| 68 ret.name = name; | 69 ret.name = name; |
| 69 ret.isInitializer = isInitializer; | 70 ret.isInitializer = isInitializer; |
| 70 return ret; | 71 return ret; |
| 71 } | 72 } |
| 72 | 73 |
| 73 bool get isOptional() => definition != null && definition.value != null; | 74 bool get isOptional() => definition != null && definition.value != null; |
| 74 } | 75 } |
| 75 | 76 |
| 76 | 77 |
| 77 interface Named { | 78 class Member extends Element { |
| 78 String get name(); | |
| 79 Library get library(); | |
| 80 bool get isNative(); | |
| 81 String get jsname(); | |
| 82 set jsname(String name); | |
| 83 | |
| 84 SourceSpan get span(); | |
| 85 } | |
| 86 | |
| 87 class Member implements Named { | |
| 88 final String name; | |
| 89 final Type declaringType; | 79 final Type declaringType; |
| 90 | 80 |
| 91 String _jsname; | |
| 92 | |
| 93 bool isGenerated; | 81 bool isGenerated; |
| 94 MethodGenerator generator; | 82 MethodGenerator generator; |
| 95 | 83 |
| 96 Member(this.name, this.declaringType): isGenerated = false; | 84 Member(String name, Type declaringType) |
| 97 | 85 : isGenerated = false, this.declaringType = declaringType, |
| 98 abstract SourceSpan get span(); | 86 super(name, declaringType); |
| 99 | 87 |
| 100 abstract bool get isStatic(); | 88 abstract bool get isStatic(); |
| 101 abstract Type get returnType(); | 89 abstract Type get returnType(); |
| 102 | 90 |
| 103 abstract bool get canGet(); | 91 abstract bool get canGet(); |
| 104 abstract bool get canSet(); | 92 abstract bool get canSet(); |
| 105 | 93 |
| 106 abstract void resolve(Type inType); | |
| 107 | |
| 108 String get jsname() => _jsname == null ? name : _jsname; | |
| 109 | |
| 110 set jsname(String name) => _jsname = name; | |
| 111 | |
| 112 Library get library() => declaringType.library; | 94 Library get library() => declaringType.library; |
| 113 | 95 |
| 114 bool get isPrivate() => name.startsWith('_'); | 96 bool get isPrivate() => name.startsWith('_'); |
| 115 | 97 |
| 116 bool get isConstructor() => false; | 98 bool get isConstructor() => false; |
| 117 bool get isField() => false; | 99 bool get isField() => false; |
| 118 bool get isMethod() => false; | 100 bool get isMethod() => false; |
| 119 bool get isProperty() => false; | 101 bool get isProperty() => false; |
| 120 bool get isAbstract() => false; | 102 bool get isAbstract() => false; |
| 121 | 103 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 String get generatedFactoryName() { | 186 String get generatedFactoryName() { |
| 205 assert(this.isFactory); | 187 assert(this.isFactory); |
| 206 String prefix = '${declaringType.jsname}.${constructorName}\$'; | 188 String prefix = '${declaringType.jsname}.${constructorName}\$'; |
| 207 if (name == '') { | 189 if (name == '') { |
| 208 return '${prefix}factory'; | 190 return '${prefix}factory'; |
| 209 } else { | 191 } else { |
| 210 return '${prefix}$name\$factory'; | 192 return '${prefix}$name\$factory'; |
| 211 } | 193 } |
| 212 } | 194 } |
| 213 | 195 |
| 214 Type resolveType(TypeReference node, bool isRequired) { | |
| 215 var type = declaringType.resolveType(node, isRequired); | |
| 216 if (isStatic && type.hasTypeParams) { | |
| 217 // TODO(jimhug): Is this really so hard? | |
| 218 world.error('using type parameter in static context', | |
| 219 node.span); | |
| 220 } | |
| 221 return type; | |
| 222 } | |
| 223 | |
| 224 int hashCode() => (declaringType.hashCode() << 4) ^ name.hashCode(); | 196 int hashCode() => (declaringType.hashCode() << 4) ^ name.hashCode(); |
| 225 } | 197 } |
| 226 | 198 |
| 227 | 199 |
| 228 /** | 200 /** |
| 229 * Types are treated as first class members of their library's top type. | 201 * Types are treated as first class members of their library's top type. |
| 230 */ | 202 */ |
| 231 // TODO(jmesserly): perhaps Type should extend Member, but that can get | 203 // TODO(jmesserly): perhaps Type should extend Member, but that can get |
| 232 // complicated. | 204 // complicated. |
| 233 class TypeMember extends Member { | 205 class TypeMember extends Member { |
| 234 final DefinedType type; | 206 final DefinedType type; |
| 235 | 207 |
| 236 TypeMember(DefinedType type) | 208 TypeMember(DefinedType type) |
| 237 : super(type.name, type.library.topType), | 209 : super(type.name, type.library.topType), |
| 238 this.type = type; | 210 this.type = type; |
| 239 | 211 |
| 240 SourceSpan get span() => type.definition.span; | 212 SourceSpan get span() => type.definition.span; |
| 241 | 213 |
| 242 bool get isStatic() => true; | 214 bool get isStatic() => true; |
| 243 | 215 |
| 244 // If this really becomes first class, this should return typeof(Type) | 216 // If this really becomes first class, this should return typeof(Type) |
| 245 Type get returnType() => world.varType; | 217 Type get returnType() => world.varType; |
| 246 | 218 |
| 247 bool canInvoke(MethodGenerator context, Arguments args) => false; | 219 bool canInvoke(MethodGenerator context, Arguments args) => false; |
| 248 bool get canGet() => true; | 220 bool get canGet() => true; |
| 249 bool get canSet() => false; | 221 bool get canSet() => false; |
| 250 | 222 |
| 251 void resolve(Type inType) {} | |
| 252 | |
| 253 Value _get(MethodGenerator context, Node node, Value target, | 223 Value _get(MethodGenerator context, Node node, Value target, |
| 254 [bool isDynamic=false]) { | 224 [bool isDynamic=false]) { |
| 255 return new Value.type(type, node.span); | 225 return new Value.type(type, node.span); |
| 256 } | 226 } |
| 257 | 227 |
| 258 Value _set(MethodGenerator context, Node node, Value target, Value value, | 228 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 259 [bool isDynamic=false]) { | 229 [bool isDynamic=false]) { |
| 260 world.error('cannot set type', node.span); | 230 world.error('cannot set type', node.span); |
| 261 } | 231 } |
| 262 | 232 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 | 290 |
| 321 SourceSpan get span() => definition == null ? null : definition.span; | 291 SourceSpan get span() => definition == null ? null : definition.span; |
| 322 | 292 |
| 323 Type get returnType() => type; | 293 Type get returnType() => type; |
| 324 | 294 |
| 325 bool get canGet() => true; | 295 bool get canGet() => true; |
| 326 bool get canSet() => !isFinal; | 296 bool get canSet() => !isFinal; |
| 327 | 297 |
| 328 bool get isField() => true; | 298 bool get isField() => true; |
| 329 | 299 |
| 330 resolve(Type inType) { | 300 resolve() { |
| 331 isStatic = declaringType.isTop; | 301 isStatic = declaringType.isTop; |
| 332 isFinal = false; | 302 isFinal = false; |
| 333 if (definition.modifiers != null) { | 303 if (definition.modifiers != null) { |
| 334 for (var mod in definition.modifiers) { | 304 for (var mod in definition.modifiers) { |
| 335 if (mod.kind == TokenKind.STATIC) { | 305 if (mod.kind == TokenKind.STATIC) { |
| 336 if (isStatic) { | 306 if (isStatic) { |
| 337 world.error('duplicate static modifier', mod.span); | 307 world.error('duplicate static modifier', mod.span); |
| 338 } | 308 } |
| 339 isStatic = true; | 309 isStatic = true; |
| 340 } else if (mod.kind == TokenKind.FINAL) { | 310 } else if (mod.kind == TokenKind.FINAL) { |
| 341 if (isFinal) { | 311 if (isFinal) { |
| 342 world.error('duplicate final modifier', mod.span); | 312 world.error('duplicate final modifier', mod.span); |
| 343 } | 313 } |
| 344 isFinal = true; | 314 isFinal = true; |
| 345 } else { | 315 } else { |
| 346 world.error('${mod} modifier not allowed on field', mod.span); | 316 world.error('${mod} modifier not allowed on field', mod.span); |
| 347 } | 317 } |
| 348 } | 318 } |
| 349 } | 319 } |
| 350 type = inType.resolveType(definition.type, false); | 320 type = resolveType(definition.type, false); |
| 351 if (isStatic && type.hasTypeParams) { | 321 if (isStatic && type.hasTypeParams) { |
| 352 world.error('using type parameter in static context', | 322 world.error('using type parameter in static context', |
| 353 definition.type.span); | 323 definition.type.span); |
| 354 } | 324 } |
| 355 | 325 |
| 356 if (isStatic && isFinal && value == null) { | 326 if (isStatic && isFinal && value == null) { |
| 357 world.error('static final field is missing initializer', span); | 327 world.error('static final field is missing initializer', span); |
| 358 } | 328 } |
| 359 | 329 |
| 360 library._addMember(this); | 330 library._addMember(this); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 ConcreteMember c = parentMember; | 497 ConcreteMember c = parentMember; |
| 528 parent = c.baseMember; | 498 parent = c.baseMember; |
| 529 } else { | 499 } else { |
| 530 parent = parentMember; | 500 parent = parentMember; |
| 531 } | 501 } |
| 532 | 502 |
| 533 if (getter == null) getter = parent.getter; | 503 if (getter == null) getter = parent.getter; |
| 534 if (setter == null) setter = parent.setter; | 504 if (setter == null) setter = parent.setter; |
| 535 } | 505 } |
| 536 | 506 |
| 537 resolve(Type inType) { | 507 resolve() { |
| 538 if (getter != null) getter.resolve(inType); | 508 if (getter != null) getter.resolve(); |
| 539 if (setter != null) setter.resolve(inType); | 509 if (setter != null) setter.resolve(); |
| 540 | 510 |
| 541 library._addMember(this); | 511 library._addMember(this); |
| 542 } | 512 } |
| 543 } | 513 } |
| 544 | 514 |
| 545 | 515 |
| 546 class ConcreteMember extends Member { | 516 class ConcreteMember extends Member { |
| 547 final Member baseMember; | 517 final Member baseMember; |
| 548 Type returnType; | 518 Type returnType; |
| 549 List<Parameter> parameters; | 519 List<Parameter> parameters; |
| 550 | 520 |
| 551 ConcreteMember(String name, ConcreteType declaringType, this.baseMember) | 521 ConcreteMember(String name, ConcreteType declaringType, this.baseMember) |
| 552 : super(name, declaringType) { | 522 : super(name, declaringType) { |
| 553 parameters = []; | 523 parameters = []; |
| 554 returnType = baseMember.returnType.resolveTypeParams(declaringType); | 524 returnType = baseMember.returnType.resolveTypeParams(declaringType); |
| 555 // TODO(jimhug): Optimize not creating new array if new param types. | 525 // TODO(jimhug): Optimize not creating new array if no new param types. |
| 556 for (var p in baseMember.parameters) { | 526 for (var p in baseMember.parameters) { |
| 557 var newType = p.type.resolveTypeParams(declaringType); | 527 var newType = p.type.resolveTypeParams(declaringType); |
| 558 if (newType != p.type) { | 528 if (newType != p.type) { |
| 559 parameters.add(p.copyWithNewType(newType)); | 529 parameters.add(p.copyWithNewType(this, newType)); |
| 560 } else { | 530 } else { |
| 561 parameters.add(p); | 531 parameters.add(p); |
| 562 } | 532 } |
| 563 } | 533 } |
| 564 } | 534 } |
| 565 | 535 |
| 566 SourceSpan get span() => baseMember.span; | 536 SourceSpan get span() => baseMember.span; |
| 567 | 537 |
| 568 bool get isStatic() => baseMember.isStatic; | 538 bool get isStatic() => baseMember.isStatic; |
| 569 bool get isAbstract() => baseMember.isAbstract; | 539 bool get isAbstract() => baseMember.isAbstract; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 } | 611 } |
| 642 } | 612 } |
| 643 | 613 |
| 644 | 614 |
| 645 /** Represents a Dart method or top-level function. */ | 615 /** Represents a Dart method or top-level function. */ |
| 646 class MethodMember extends Member { | 616 class MethodMember extends Member { |
| 647 FunctionDefinition definition; | 617 FunctionDefinition definition; |
| 648 Type returnType; | 618 Type returnType; |
| 649 List<Parameter> parameters; | 619 List<Parameter> parameters; |
| 650 | 620 |
| 621 // Could support generic methods in general. Right now only used for |
| 622 // strange corner case of factory methods for generic types. |
| 623 List<ParameterType> typeParameters; |
| 624 |
| 651 | 625 |
| 652 Type _functionType; | 626 Type _functionType; |
| 653 bool isStatic = false; | 627 bool isStatic = false; |
| 654 bool isAbstract = false; | 628 bool isAbstract = false; |
| 655 | 629 |
| 656 // Note: these two modifiers are only legal on constructors | 630 // Note: these two modifiers are only legal on constructors |
| 657 bool isConst = false; | 631 bool isConst = false; |
| 658 bool isFactory = false; | 632 bool isFactory = false; |
| 659 | 633 |
| 660 /** True if this is a function defined inside another method. */ | 634 /** True if this is a function defined inside another method. */ |
| (...skipping 21 matching lines...) Expand all Loading... |
| 682 bool get isMethod() => !isConstructor; | 656 bool get isMethod() => !isConstructor; |
| 683 | 657 |
| 684 bool get isNative() => definition.body is NativeStatement; | 658 bool get isNative() => definition.body is NativeStatement; |
| 685 | 659 |
| 686 bool get canGet() => false; // TODO(jimhug): get bound method support. | 660 bool get canGet() => false; // TODO(jimhug): get bound method support. |
| 687 bool get canSet() => false; | 661 bool get canSet() => false; |
| 688 | 662 |
| 689 SourceSpan get span() => definition == null ? null : definition.span; | 663 SourceSpan get span() => definition == null ? null : definition.span; |
| 690 | 664 |
| 691 String get constructorName() { | 665 String get constructorName() { |
| 692 NameTypeReference returnType = definition.returnType; | 666 var returnType = definition.returnType; |
| 693 if (returnType == null) return ''; | 667 if (returnType == null) return ''; |
| 668 if (returnType is GenericTypeReference) { |
| 669 return ''; |
| 670 } |
| 694 | 671 |
| 695 // TODO(jmesserly): make this easier? | 672 // TODO(jmesserly): make this easier? |
| 696 if (returnType.names != null) { | 673 if (returnType.names != null) { |
| 697 return returnType.names[0].name; | 674 return returnType.names[0].name; |
| 698 } else if (returnType.name != null) { | 675 } else if (returnType.name != null) { |
| 699 return returnType.name.name; | 676 return returnType.name.name; |
| 700 } | 677 } |
| 701 world.internalError('no valid constructor name', definition.span); | 678 world.internalError('no valid constructor name', definition.span); |
| 702 } | 679 } |
| 703 | 680 |
| 704 Type get functionType() { | 681 Type get functionType() { |
| 705 if (_functionType == null) { | 682 if (_functionType == null) { |
| 706 _functionType = library.getOrAddFunctionType(name, | 683 _functionType = library.getOrAddFunctionType(declaringType, name, definiti
on); |
| 707 definition, declaringType); | |
| 708 // TODO(jimhug): Better resolution checks. | 684 // TODO(jimhug): Better resolution checks. |
| 709 if (parameters == null) { | 685 if (parameters == null) { |
| 710 resolve(declaringType); | 686 resolve(); |
| 711 } | 687 } |
| 712 } | 688 } |
| 713 return _functionType; | 689 return _functionType; |
| 714 } | 690 } |
| 715 | 691 |
| 716 bool override(Member other) { | 692 bool override(Member other) { |
| 717 if (!super.override(other)) return false; | 693 if (!super.override(other)) return false; |
| 718 | 694 |
| 719 // methods can only override other methods | 695 // methods can only override other methods |
| 720 if (other.isMethod) { | 696 if (other.isMethod) { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 | 829 |
| 854 /** | 830 /** |
| 855 * Invokes this method on the given [target] with the given [args]. | 831 * Invokes this method on the given [target] with the given [args]. |
| 856 * [node] provides a [SourceSpan] for any error messages. | 832 * [node] provides a [SourceSpan] for any error messages. |
| 857 */ | 833 */ |
| 858 Value invoke(MethodGenerator context, Node node, Value target, | 834 Value invoke(MethodGenerator context, Node node, Value target, |
| 859 Arguments args, [bool isDynamic=false]) { | 835 Arguments args, [bool isDynamic=false]) { |
| 860 // TODO(jimhug): Fix this hack for ensuring a method is resolved. | 836 // TODO(jimhug): Fix this hack for ensuring a method is resolved. |
| 861 if (parameters == null) { | 837 if (parameters == null) { |
| 862 world.info('surprised to need to resolve: ${declaringType.name}.$name'); | 838 world.info('surprised to need to resolve: ${declaringType.name}.$name'); |
| 863 this.resolve(declaringType); | 839 resolve(); |
| 864 } | 840 } |
| 865 | 841 |
| 866 declaringType.genMethod(this); | 842 declaringType.genMethod(this); |
| 867 | 843 |
| 868 if (isStatic || isFactory) { | 844 if (isStatic || isFactory) { |
| 869 // TODO(sigmund): can we avoid generating the entire type, but only what | 845 // TODO(sigmund): can we avoid generating the entire type, but only what |
| 870 // we need? | 846 // we need? |
| 871 declaringType.markUsed(); | 847 declaringType.markUsed(); |
| 872 } | 848 } |
| 873 | 849 |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1208 var value = '${val0}${val1}'; | 1184 var value = '${val0}${val1}'; |
| 1209 value = '"' + value.replaceAll('"', '\\"') + '"'; | 1185 value = '"' + value.replaceAll('"', '\\"') + '"'; |
| 1210 return new EvaluatedValue(world.stringType, value, value, node.span); | 1186 return new EvaluatedValue(world.stringType, value, value, node.span); |
| 1211 } | 1187 } |
| 1212 | 1188 |
| 1213 // Ensure we generate toString on the right side | 1189 // Ensure we generate toString on the right side |
| 1214 args.values[0].invoke(context, 'toString', node, Arguments.EMPTY); | 1190 args.values[0].invoke(context, 'toString', node, Arguments.EMPTY); |
| 1215 return new Value(declaringType, '${target.code} + ${argsCode[0]}', | 1191 return new Value(declaringType, '${target.code} + ${argsCode[0]}', |
| 1216 node.span); | 1192 node.span); |
| 1217 } | 1193 } |
| 1218 } else if (declaringType.isNativeType) { | 1194 } else if (declaringType.isNative) { |
| 1219 if (name == '\$index') { | 1195 if (name == '\$index') { |
| 1220 // Note: this could technically propagate constness, but that's not | 1196 // Note: this could technically propagate constness, but that's not |
| 1221 // specified explicitly and the VM doesn't do that. | 1197 // specified explicitly and the VM doesn't do that. |
| 1222 return new Value(returnType, '${target.code}[${argsCode[0]}]', node.span
); | 1198 return new Value(returnType, '${target.code}[${argsCode[0]}]', node.span
); |
| 1223 } else if (name == '\$setindex') { | 1199 } else if (name == '\$setindex') { |
| 1224 return new Value(returnType, | 1200 return new Value(returnType, |
| 1225 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); | 1201 '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span); |
| 1226 } | 1202 } |
| 1227 } | 1203 } |
| 1228 | 1204 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1267 world.gen.corejs.useSetIndex = true; | 1243 world.gen.corejs.useSetIndex = true; |
| 1268 } | 1244 } |
| 1269 | 1245 |
| 1270 // Fall back to normal method invocation. | 1246 // Fall back to normal method invocation. |
| 1271 var argsString = Strings.join(argsCode, ', '); | 1247 var argsString = Strings.join(argsCode, ', '); |
| 1272 return new Value(inferredResult, '${target.code}.$jsname($argsString)', | 1248 return new Value(inferredResult, '${target.code}.$jsname($argsString)', |
| 1273 node.span); | 1249 node.span); |
| 1274 } | 1250 } |
| 1275 | 1251 |
| 1276 | 1252 |
| 1277 resolve(Type inType) { | 1253 resolve() { |
| 1278 // TODO(jimhug): cut-and-paste-and-edit from Field.resolve | 1254 // TODO(jimhug): cut-and-paste-and-edit from Field.resolve |
| 1279 isStatic = inType.isTop; | 1255 isStatic = declaringType.isTop; |
| 1280 isConst = false; | 1256 isConst = false; |
| 1281 isFactory = false; | 1257 isFactory = false; |
| 1282 isAbstract = !declaringType.isClass; | 1258 isAbstract = !declaringType.isClass; |
| 1283 if (definition.modifiers != null) { | 1259 if (definition.modifiers != null) { |
| 1284 for (var mod in definition.modifiers) { | 1260 for (var mod in definition.modifiers) { |
| 1285 if (mod.kind == TokenKind.STATIC) { | 1261 if (mod.kind == TokenKind.STATIC) { |
| 1286 if (isStatic) { | 1262 if (isStatic) { |
| 1287 world.error('duplicate static modifier', mod.span); | 1263 world.error('duplicate static modifier', mod.span); |
| 1288 } | 1264 } |
| 1289 isStatic = true; | 1265 isStatic = true; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1310 } else { | 1286 } else { |
| 1311 world.error('${mod} modifier not allowed on method', mod.span); | 1287 world.error('${mod} modifier not allowed on method', mod.span); |
| 1312 } | 1288 } |
| 1313 } | 1289 } |
| 1314 } | 1290 } |
| 1315 | 1291 |
| 1316 if (isFactory) { | 1292 if (isFactory) { |
| 1317 isStatic = true; | 1293 isStatic = true; |
| 1318 } | 1294 } |
| 1319 | 1295 |
| 1296 if (definition.typeParameters != null) { |
| 1297 if (!isFactory) { |
| 1298 world.error( |
| 1299 'Only factories are allowed to have explicit type parameters', |
| 1300 definition.typeParameters[0].span); |
| 1301 } else { |
| 1302 typeParameters = definition.typeParameters; |
| 1303 for (var tp in definition.typeParameters) { |
| 1304 tp.enclosingElement = this; |
| 1305 tp.resolve(); |
| 1306 } |
| 1307 } |
| 1308 } |
| 1309 |
| 1320 // TODO(jimhug): need a better annotation for being an operator method | 1310 // TODO(jimhug): need a better annotation for being an operator method |
| 1321 if (isOperator && isStatic && !isCallMethod) { | 1311 if (isOperator && isStatic && !isCallMethod) { |
| 1322 world.error('operator method may not be static "${name}"', span); | 1312 world.error('operator method may not be static "${name}"', span); |
| 1323 } | 1313 } |
| 1324 | 1314 |
| 1325 if (isAbstract) { | 1315 if (isAbstract) { |
| 1326 if (definition.body != null && | 1316 if (definition.body != null && |
| 1327 declaringType.definition is! FunctionTypeDefinition) { | 1317 declaringType.definition is! FunctionTypeDefinition) { |
| 1328 // TODO(jimhug): Creating function types for concrete methods is | 1318 // TODO(jimhug): Creating function types for concrete methods is |
| 1329 // steadily feeling uglier... | 1319 // steadily feeling uglier... |
| 1330 world.error('abstract method can not have a body', span); | 1320 world.error('abstract method can not have a body', span); |
| 1331 } | 1321 } |
| 1332 if (isStatic && | 1322 if (isStatic && |
| 1333 declaringType.definition is! FunctionTypeDefinition) { | 1323 declaringType.definition is! FunctionTypeDefinition) { |
| 1334 world.error('static method can not be abstract', span); | 1324 world.error('static method can not be abstract', span); |
| 1335 } | 1325 } |
| 1336 } else { | 1326 } else { |
| 1337 if (definition.body == null && !isConstructor) { | 1327 if (definition.body == null && !isConstructor) { |
| 1338 world.error('method needs a body', span); | 1328 world.error('method needs a body', span); |
| 1339 } | 1329 } |
| 1340 } | 1330 } |
| 1341 | 1331 |
| 1342 if (isConstructor) { | 1332 if (isConstructor && !isFactory) { |
| 1343 returnType = declaringType; | 1333 returnType = declaringType; |
| 1344 } else { | 1334 } else { |
| 1345 // TODO(jimhug): Unify this check and the below with method's | 1335 returnType = resolveType(definition.returnType, false); |
| 1346 // resolveType method - requires cleaning up inType stuff. | |
| 1347 returnType = inType.resolveType(definition.returnType, false); | |
| 1348 | |
| 1349 if (isStatic && returnType.hasTypeParams) { | |
| 1350 world.error('using type parameter in static context', | |
| 1351 definition.returnType.span); | |
| 1352 } | |
| 1353 } | 1336 } |
| 1354 parameters = []; | 1337 parameters = []; |
| 1355 for (var formal in definition.formals) { | 1338 for (var formal in definition.formals) { |
| 1356 var param = new Parameter(formal); | 1339 // TODO(jimhug): Clean up construction of Parameters. |
| 1357 param.resolve(this, inType); | 1340 var param = new Parameter(formal, this); |
| 1341 param.resolve(); |
| 1358 parameters.add(param); | 1342 parameters.add(param); |
| 1359 } | 1343 } |
| 1360 | 1344 |
| 1361 if (!isLambda) { | 1345 if (!isLambda) { |
| 1362 library._addMember(this); | 1346 library._addMember(this); |
| 1363 } | 1347 } |
| 1364 } | 1348 } |
| 1365 | |
| 1366 Type findTypeVariable(TypeReference node, bool isRequired) { | |
| 1367 if (!this.isFactory || node is! NameTypeReference) { | |
| 1368 return super.resolveType(node, isRequired); | |
| 1369 } else { | |
| 1370 // TODO(ahe): We cannot find any type variables as they aren't | |
| 1371 // recorded. So we turn this in to a warning instead. | |
| 1372 return super.resolveType(node, false); | |
| 1373 } | |
| 1374 } | |
| 1375 | |
| 1376 Type resolveType(TypeReference node, bool isRequired) { | |
| 1377 if (node !== null && this.isFactory && isRequired) { | |
| 1378 if (node is GenericTypeReference) { | |
| 1379 // TODO(ahe): This is bascially a copy of code in | |
| 1380 // DefinedType.resolveType. More checks should be performed, | |
| 1381 // such as bounds check, but the code is structured in a way | |
| 1382 // that makes this hard. | |
| 1383 GenericTypeReference genericReference = node; | |
| 1384 var baseType = super.resolveType(genericReference.baseType, isRequired); | |
| 1385 var typeArguments = []; | |
| 1386 for (TypeReference ref in genericReference.typeArguments) { | |
| 1387 // TODO(ahe): This let us ignore T in new Foo<T>, but not in | |
| 1388 // new Foo<Foo<T>>. | |
| 1389 typeArguments.add(findTypeVariable(ref, isRequired)); | |
| 1390 } | |
| 1391 node.type = baseType.getOrMakeConcreteType(typeArguments); | |
| 1392 return node.type; | |
| 1393 } | |
| 1394 } | |
| 1395 return super.resolveType(node, isRequired); | |
| 1396 } | |
| 1397 } | 1349 } |
| 1398 | 1350 |
| 1399 | 1351 |
| 1400 class MemberSet { | 1352 class MemberSet { |
| 1401 final String name; | 1353 final String name; |
| 1402 final List<Member> members; | 1354 final List<Member> members; |
| 1403 final String jsname; | 1355 final String jsname; |
| 1404 final bool isVar; | 1356 final bool isVar; |
| 1405 | 1357 |
| 1406 MemberSet(Member member, [bool isVar=false]): | 1358 MemberSet(Member member, [bool isVar=false]): |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1706 } | 1658 } |
| 1707 | 1659 |
| 1708 void forEach(void f(Member member)) { | 1660 void forEach(void f(Member member)) { |
| 1709 factories.forEach((_, Map constructors) { | 1661 factories.forEach((_, Map constructors) { |
| 1710 constructors.forEach((_, Member member) { | 1662 constructors.forEach((_, Member member) { |
| 1711 f(member); | 1663 f(member); |
| 1712 }); | 1664 }); |
| 1713 }); | 1665 }); |
| 1714 } | 1666 } |
| 1715 } | 1667 } |
| OLD | NEW |