| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** 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 SourceSpan get span() => definition.span; |
| 19 |
| 18 resolve() { | 20 resolve() { |
| 19 name = definition.name.name; | 21 name = definition.name.name; |
| 20 if (name.startsWith('this.')) { | 22 if (name.startsWith('this.')) { |
| 21 name = name.substring(5); | 23 name = name.substring(5); |
| 22 isInitializer = true; | 24 isInitializer = true; |
| 23 } | 25 } |
| 24 | 26 |
| 25 type = method.resolveType(definition.type, false); | 27 type = method.resolveType(definition.type, false); |
| 26 | 28 |
| 27 if (definition.value != null) { | 29 if (definition.value != null) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 42 } else if (method.isAbstract) { | 44 } else if (method.isAbstract) { |
| 43 world.error('default value not allowed on abstract methods', | 45 world.error('default value not allowed on abstract methods', |
| 44 definition.span); | 46 definition.span); |
| 45 } | 47 } |
| 46 } else if (isInitializer && !method.isConstructor) { | 48 } else if (isInitializer && !method.isConstructor) { |
| 47 world.error('initializer parameters only allowed on constructors', | 49 world.error('initializer parameters only allowed on constructors', |
| 48 definition.span); | 50 definition.span); |
| 49 } | 51 } |
| 50 } | 52 } |
| 51 | 53 |
| 52 genValue(MethodMember method, MethodGenerator context) { | 54 genValue(MethodMember method, [MethodGenerator context]) { |
| 53 if (definition.value == null || value != null) return; | 55 if (definition.value == null || value != null) return; |
| 54 | 56 |
| 55 if (context == null) { // interface method | 57 if (context == null) { // interface method |
| 56 context = new MethodGenerator(method, null); | 58 context = new MethodGenerator(method); |
| 57 } | 59 } |
| 58 value = definition.value.visit(context); | 60 value = context.evalExpression(definition.value); |
| 59 if (!value.isConst) { | 61 if (!value.isConst) { |
| 60 world.error('default parameter values must be constant', value.span); | 62 world.error('default parameter values must be constant', value.span); |
| 61 } | 63 } |
| 62 value = value.convertTo(context, type); | 64 value = value.convertTo(context, type); |
| 63 } | 65 } |
| 64 | 66 |
| 65 Parameter copyWithNewType(Member newMethod, Type newType) { | 67 Parameter copyWithNewType(Member newMethod, Type newType) { |
| 66 var ret = new Parameter(definition, newMethod); | 68 var ret = new Parameter(definition, newMethod); |
| 67 ret.type = newType; | 69 ret.type = newType; |
| 68 ret.name = name; | 70 ret.name = name; |
| 69 ret.isInitializer = isInitializer; | 71 ret.isInitializer = isInitializer; |
| 70 return ret; | 72 return ret; |
| 71 } | 73 } |
| 72 | 74 |
| 73 bool get isOptional() => definition != null && definition.value != null; | 75 bool get isOptional() => definition != null && definition.value != null; |
| 74 | 76 |
| 75 /** | 77 /** |
| 76 * Gets whether this named parameter has an explicit default value or relies | 78 * Gets whether this named parameter has an explicit default value or relies |
| 77 * on the implicit `null`. | 79 * on the implicit `null`. |
| 78 */ | 80 */ |
| 79 bool get hasDefaultValue() => | 81 bool get hasDefaultValue() => |
| 80 definition.value.span.start != definition.span.start; | 82 definition.value.span.start != definition.span.start; |
| 81 } | 83 } |
| 82 | 84 |
| 83 | 85 |
| 84 class Member extends Element { | 86 class Member extends Element { |
| 85 final Type declaringType; | 87 final Type declaringType; |
| 86 | 88 |
| 87 bool isGenerated; | 89 bool isUsed; |
| 88 MethodGenerator generator; | 90 |
| 91 // TODO(jmesserly): this only makes sense if we never specialize functions |
| 92 // for their argument types. |
| 93 MethodGenerator get generator() => specializer.generator; |
| 94 MethodSpecializer specializer; |
| 89 | 95 |
| 90 Member(String name, Type declaringType) | 96 Member(String name, Type declaringType) |
| 91 : isGenerated = false, this.declaringType = declaringType, | 97 : isUsed = false, this.declaringType = declaringType, |
| 92 super(name, declaringType); | 98 super(name, declaringType); |
| 93 | 99 |
| 94 abstract bool get isStatic(); | 100 abstract bool get isStatic(); |
| 95 abstract Type get returnType(); | 101 abstract Type get returnType(); |
| 96 | 102 |
| 97 abstract bool get canGet(); | 103 abstract bool get canGet(); |
| 98 abstract bool get canSet(); | 104 abstract bool get canSet(); |
| 99 | 105 |
| 100 Library get library() => declaringType.library; | 106 Library get library() => declaringType.library; |
| 101 | 107 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 world.internalError('cannot have initializers', span); | 141 world.internalError('cannot have initializers', span); |
| 136 } | 142 } |
| 137 void set initDelegate(ctor) { | 143 void set initDelegate(ctor) { |
| 138 world.internalError('cannot have initializers', span); | 144 world.internalError('cannot have initializers', span); |
| 139 } | 145 } |
| 140 | 146 |
| 141 Value computeValue() { | 147 Value computeValue() { |
| 142 world.internalError('cannot have value', span); | 148 world.internalError('cannot have value', span); |
| 143 } | 149 } |
| 144 | 150 |
| 145 /** | |
| 146 * The inferred returnType. Right now this is just used to track | |
| 147 * non-nullable bools. | |
| 148 */ | |
| 149 Type get inferredResult() { | |
| 150 var t = returnType; | |
| 151 if (t.isBool && (library.isCore || library.isCoreImpl)) { | |
| 152 // We trust our core libraries not to return null from bools. | |
| 153 // I hope this trust is well placed! | |
| 154 return world.nonNullBool; | |
| 155 } | |
| 156 return t; | |
| 157 } | |
| 158 | |
| 159 Definition get definition() => null; | 151 Definition get definition() => null; |
| 160 | 152 |
| 161 List<Parameter> get parameters() => []; | 153 List<Parameter> get parameters() => []; |
| 162 | 154 |
| 155 void markUsed() => declaringType.markUsedMethod(this); |
| 156 |
| 163 MemberSet _preciseMemberSet, _potentialMemberSet; | 157 MemberSet _preciseMemberSet, _potentialMemberSet; |
| 164 | 158 |
| 165 MemberSet get preciseMemberSet() { | 159 MemberSet get preciseMemberSet() { |
| 166 if (_preciseMemberSet === null) { | 160 if (_preciseMemberSet === null) { |
| 167 _preciseMemberSet = new MemberSet(this); | 161 _preciseMemberSet = new MemberSet(this); |
| 168 } | 162 } |
| 169 return _preciseMemberSet; | 163 return _preciseMemberSet; |
| 170 } | 164 } |
| 171 | 165 |
| 172 MemberSet get potentialMemberSet() { | 166 MemberSet get potentialMemberSet() { |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 if (value == null) return null; | 422 if (value == null) return null; |
| 429 | 423 |
| 430 if (_computedValue == null) { | 424 if (_computedValue == null) { |
| 431 if (_computing) { | 425 if (_computing) { |
| 432 world.error('circular reference', value.span); | 426 world.error('circular reference', value.span); |
| 433 return null; | 427 return null; |
| 434 } | 428 } |
| 435 _computing = true; | 429 _computing = true; |
| 436 var finalMethod = new MethodMember('final_context', declaringType, null); | 430 var finalMethod = new MethodMember('final_context', declaringType, null); |
| 437 finalMethod.isStatic = true; | 431 finalMethod.isStatic = true; |
| 438 var finalGen = new MethodGenerator(finalMethod, null); | 432 _computedValue = new MethodGenerator(finalMethod).evalExpression(value); |
| 439 _computedValue = value.visit(finalGen); | |
| 440 if (!_computedValue.isConst) { | 433 if (!_computedValue.isConst) { |
| 441 if (isStatic) { | 434 if (isStatic) { |
| 442 world.error( | 435 world.error( |
| 443 'non constant static field must be initialized in functions', | 436 'non constant static field must be initialized in functions', |
| 444 value.span); | 437 value.span); |
| 445 } else { | 438 } else { |
| 446 world.error( | 439 world.error( |
| 447 'non constant field must be initialized in constructor', | 440 'non constant field must be initialized in constructor', |
| 448 value.span); | 441 value.span); |
| 449 } | 442 } |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 704 Type resolveType(TypeReference node, bool isRequired) { | 697 Type resolveType(TypeReference node, bool isRequired) { |
| 705 var type = baseMember.resolveType(node, isRequired); | 698 var type = baseMember.resolveType(node, isRequired); |
| 706 return type.resolveTypeParams(declaringType); | 699 return type.resolveTypeParams(declaringType); |
| 707 } | 700 } |
| 708 | 701 |
| 709 Value computeValue() => baseMember.computeValue(); | 702 Value computeValue() => baseMember.computeValue(); |
| 710 | 703 |
| 711 // TODO(jimhug): Add support for type params. | 704 // TODO(jimhug): Add support for type params. |
| 712 bool override(Member other) => baseMember.override(other); | 705 bool override(Member other) => baseMember.override(other); |
| 713 | 706 |
| 707 // TODO(jmesserly): this hack is needed because ConcreteMember is using |
| 708 // baseMember to do the operation, then replacing the type on the Value. |
| 709 // Something else needs to happen. |
| 710 Type get inferredResult() => returnType; |
| 711 |
| 714 Value _get(MethodGenerator context, Node node, Value target, | 712 Value _get(MethodGenerator context, Node node, Value target, |
| 715 [bool isDynamic=false]) { | 713 [bool isDynamic=false]) { |
| 716 Value ret = baseMember._get(context, node, target, isDynamic); | 714 Value ret = baseMember._get(context, node, target, isDynamic); |
| 717 return new Value(inferredResult, ret.code, node.span); | 715 return new Value(inferredResult, ret.code, node.span); |
| 718 } | 716 } |
| 719 | 717 |
| 720 Value _set(MethodGenerator context, Node node, Value target, Value value, | 718 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 721 [bool isDynamic=false]) { | 719 [bool isDynamic=false]) { |
| 722 // TODO(jimhug): Check arg types in context of concrete type. | 720 // TODO(jimhug): Check arg types in context of concrete type. |
| 723 Value ret = baseMember._set(context, node, target, value, isDynamic); | 721 Value ret = baseMember._set(context, node, target, value, isDynamic); |
| 724 return new Value(returnType, ret.code, node.span); | 722 return new Value(inferredResult, ret.code, node.span); |
| 725 } | 723 } |
| 726 | 724 |
| 727 _evalConstConstructor(ObjectValue newObject, Arguments args) { | 725 _evalConstConstructor(ObjectValue newObject, Arguments args) { |
| 728 // TODO(jimhug): Concrete type probably matters somehow here | 726 // TODO(jimhug): Concrete type probably matters somehow here |
| 729 return baseMember.dynamic._evalConstConstructor(newObject, args); | 727 return baseMember.dynamic._evalConstConstructor(newObject, args); |
| 730 } | 728 } |
| 731 | 729 |
| 732 | 730 |
| 733 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, | 731 Value invoke(MethodGenerator context, Node node, Value target, Arguments args, |
| 734 [bool isDynamic=false]) { | 732 [bool isDynamic=false]) { |
| 735 // TODO(jimhug): Check arg types in context of concrete type. | 733 // TODO(jimhug): Check arg types in context of concrete type. |
| 736 // TODO(jmesserly): I think what needs to happen is to move MethodMember's | 734 // 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 | 735 // invoke so that it's run against the "parameters" and "returnType" of the |
| 738 // ConcreteMember instead. | 736 // ConcreteMember instead. |
| 739 Value ret = baseMember.invoke(context, node, target, args, isDynamic); | 737 Value ret = baseMember.invoke(context, node, target, args, isDynamic); |
| 740 var code = ret.code; | 738 var code = ret.code; |
| 741 if (isConstructor) { | 739 if (isConstructor) { |
| 742 // TODO(jimhug): Egregious hack - won't live through the year. | 740 // TODO(jimhug): Egregious hack - won't live through the year. |
| 743 code = code.replaceFirst( | 741 code = code.replaceFirst( |
| 744 declaringType.genericType.jsname, declaringType.jsname); | 742 declaringType.genericType.jsname, declaringType.jsname); |
| 745 } | 743 } |
| 746 if (baseMember is MethodMember) { | 744 if (baseMember is MethodMember) { |
| 747 declaringType.genMethod(this); | 745 // TODO(jmesserly): we should be filling in the right args here and |
| 746 // using the result type. But the args need to be reordered to match the |
| 747 // call site, like baseMember.invoke does. |
| 748 world.gen.invokeMethod(this, target, null); |
| 748 } | 749 } |
| 749 return new Value(inferredResult, code, node.span); | 750 return new Value(inferredResult, code, node.span); |
| 750 } | 751 } |
| 751 } | 752 } |
| 752 | 753 |
| 753 | 754 |
| 754 /** Represents a Dart method or top-level function. */ | 755 /** Represents a Dart method or top-level function. */ |
| 755 class MethodMember extends Member { | 756 class MethodMember extends Member { |
| 756 FunctionDefinition definition; | 757 FunctionDefinition definition; |
| 757 Type returnType; | 758 Type returnType; |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 void provideFieldSyntax() { _provideFieldSyntax = true; } | 874 void provideFieldSyntax() { _provideFieldSyntax = true; } |
| 874 void providePropertySyntax() { _providePropertySyntax = true; } | 875 void providePropertySyntax() { _providePropertySyntax = true; } |
| 875 | 876 |
| 876 Value _set(MethodGenerator context, Node node, Value target, Value value, | 877 Value _set(MethodGenerator context, Node node, Value target, Value value, |
| 877 [bool isDynamic=false]) { | 878 [bool isDynamic=false]) { |
| 878 world.error('cannot set method', node.span); | 879 world.error('cannot set method', node.span); |
| 879 } | 880 } |
| 880 | 881 |
| 881 Value _get(MethodGenerator context, Node node, Value target, | 882 Value _get(MethodGenerator context, Node node, Value target, |
| 882 [bool isDynamic=false]) { | 883 [bool isDynamic=false]) { |
| 883 // TODO(jimhug): Would prefer to invoke! | 884 |
| 884 declaringType.genMethod(this); | 885 // TODO(jmesserly): if we tracked functions as values, this would be the |
| 886 // place to do it. |
| 887 world.gen.invokeMethod(this); |
| 888 |
| 885 _provideOptionalParamInfo = true; | 889 _provideOptionalParamInfo = true; |
| 886 if (isStatic) { | 890 if (isStatic) { |
| 887 // ensure the type is generated. | 891 // ensure the type is generated. |
| 888 // TODO(sigmund): can we avoid generating the entire type, but only what | 892 // TODO(sigmund): can we avoid generating the entire type, but only what |
| 889 // we need? | 893 // we need? |
| 890 declaringType.markUsed(); | 894 declaringType.markUsed(); |
| 891 var type = declaringType.isTop ? '' : '${declaringType.jsname}.'; | 895 var type = declaringType.isTop ? '' : '${declaringType.jsname}.'; |
| 892 return new Value(functionType, '$type$jsname', node.span); | 896 return new Value(functionType, '$type$jsname', node.span); |
| 893 } | 897 } |
| 894 _providePropertySyntax = true; | 898 _providePropertySyntax = true; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 if (isStatic || isConstructor) { | 976 if (isStatic || isConstructor) { |
| 973 world.error(msg, span); | 977 world.error(msg, span); |
| 974 } else { | 978 } else { |
| 975 world.warning(msg, span); | 979 world.warning(msg, span); |
| 976 } | 980 } |
| 977 return target.invokeNoSuchMethod(context, name, node, args); | 981 return target.invokeNoSuchMethod(context, name, node, args); |
| 978 } | 982 } |
| 979 | 983 |
| 980 genParameterValues() { | 984 genParameterValues() { |
| 981 // Pure lazy? | 985 // Pure lazy? |
| 982 for (var p in parameters) p.genValue(this, generator); | 986 for (var p in parameters) p.genValue(this); |
| 983 } | 987 } |
| 984 | 988 |
| 985 /** | 989 /** |
| 986 * Invokes this method on the given [target] with the given [args]. | 990 * Invokes this method on the given [target] with the given [args]. |
| 987 * [node] provides a [SourceSpan] for any error messages. | 991 * [node] provides a [SourceSpan] for any error messages. |
| 988 */ | 992 */ |
| 989 Value invoke(MethodGenerator context, Node node, Value target, | 993 Value invoke(MethodGenerator context, Node node, Value target, |
| 990 Arguments args, [bool isDynamic=false]) { | 994 Arguments args, [bool isDynamic=false]) { |
| 991 // TODO(jimhug): Fix this hack for ensuring a method is resolved. | 995 // TODO(jimhug): Fix this hack for ensuring a method is resolved. |
| 992 if (parameters == null) { | 996 if (parameters == null) { |
| 993 world.info('surprised to need to resolve: ${declaringType.name}.$name'); | 997 world.info('surprised to need to resolve: ${declaringType.name}.$name'); |
| 994 resolve(); | 998 resolve(); |
| 995 } | 999 } |
| 996 | 1000 |
| 997 declaringType.genMethod(this); | |
| 998 | |
| 999 if (isStatic || isFactory) { | 1001 if (isStatic || isFactory) { |
| 1000 // TODO(sigmund): can we avoid generating the entire type, but only what | 1002 // TODO(sigmund): can we avoid generating the entire type, but only what |
| 1001 // we need? | 1003 // we need? |
| 1002 declaringType.markUsed(); | 1004 declaringType.markUsed(); |
| 1003 } | 1005 } |
| 1004 | 1006 |
| 1005 // TODO(jmesserly): get rid of this in favor of using the native method | 1007 // TODO(jmesserly): get rid of this in favor of using the native method |
| 1006 // "bodies" to tell the compiler about valid return types. | 1008 // "bodies" to tell the compiler about valid return types. |
| 1007 if (isNative && returnType != null) returnType.markUsed(); | 1009 if (isNative && returnType != null) returnType.markUsed(); |
| 1008 | 1010 |
| 1009 if (!namesInOrder(args)) { | 1011 if (!namesInOrder(args)) { |
| 1010 // Names aren't in order. For now, use a var call because it's an | 1012 // Names aren't in order. For now, use a var call because it's an |
| 1011 // easy way to get the right eval order for out of order arguments. | 1013 // easy way to get the right eval order for out of order arguments. |
| 1012 // TODO(jmesserly): temps would be better. | 1014 // TODO(jmesserly): temps would be better. |
| 1013 return context.findMembers(name).invokeOnVar(context, node, target, args); | 1015 return context.findMembers(name).invokeOnVar(context, node, target, args); |
| 1014 } | 1016 } |
| 1015 | 1017 |
| 1016 var argsCode = []; | 1018 final argValues = <Value>[]; |
| 1017 if (!target.isType && (isConstructor || target.isSuper)) { | |
| 1018 argsCode.add('this'); | |
| 1019 } | |
| 1020 | |
| 1021 int bareCount = args.bareCount; | 1019 int bareCount = args.bareCount; |
| 1022 for (int i = 0; i < bareCount; i++) { | 1020 for (int i = 0; i < bareCount; i++) { |
| 1023 var arg = args.values[i]; | 1021 var arg = args.values[i]; |
| 1024 if (i >= parameters.length) { | 1022 if (i >= parameters.length) { |
| 1025 var msg = _argCountMsg(args.length, parameters.length); | 1023 var msg = _argCountMsg(args.length, parameters.length); |
| 1026 return _argError(context, node, target, args, msg, i); | 1024 return _argError(context, node, target, args, msg, i); |
| 1027 } | 1025 } |
| 1028 arg = arg.convertTo(context, parameters[i].type, isDynamic); | 1026 arg = arg.convertTo(context, parameters[i].type, isDynamic); |
| 1029 argsCode.add(arg.code); | 1027 argValues.add(arg); |
| 1030 } | 1028 } |
| 1031 | 1029 |
| 1032 int namedArgsUsed = 0; | 1030 int namedArgsUsed = 0; |
| 1033 if (bareCount < parameters.length) { | 1031 if (bareCount < parameters.length) { |
| 1034 genParameterValues(); | 1032 genParameterValues(); |
| 1035 | 1033 |
| 1036 for (int i = bareCount; i < parameters.length; i++) { | 1034 for (int i = bareCount; i < parameters.length; i++) { |
| 1037 var arg = args.getValue(parameters[i].name); | 1035 var arg = args.getValue(parameters[i].name); |
| 1038 if (arg == null) { | 1036 if (arg == null) { |
| 1039 arg = parameters[i].value; | 1037 arg = parameters[i].value; |
| 1040 } else { | 1038 } else { |
| 1041 arg = arg.convertTo(context, parameters[i].type, isDynamic); | 1039 arg = arg.convertTo(context, parameters[i].type, isDynamic); |
| 1042 namedArgsUsed++; | 1040 namedArgsUsed++; |
| 1043 } | 1041 } |
| 1044 | 1042 |
| 1045 if (arg == null || !parameters[i].isOptional) { | 1043 if (arg == null || !parameters[i].isOptional) { |
| 1046 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true); | 1044 var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true); |
| 1047 return _argError(context, node, target, args, msg, i); | 1045 return _argError(context, node, target, args, msg, i); |
| 1048 } else { | 1046 } else { |
| 1049 argsCode.add(arg.code); | 1047 argValues.add(arg); |
| 1050 } | 1048 } |
| 1051 } | 1049 } |
| 1052 Arguments.removeTrailingNulls(argsCode); | |
| 1053 } | 1050 } |
| 1054 | 1051 |
| 1055 if (namedArgsUsed < args.nameCount) { | 1052 if (namedArgsUsed < args.nameCount) { |
| 1056 // Find the unused argument name | 1053 // Find the unused argument name |
| 1057 var seen = new Set<String>(); | 1054 var seen = new Set<String>(); |
| 1058 for (int i = bareCount; i < args.length; i++) { | 1055 for (int i = bareCount; i < args.length; i++) { |
| 1059 var name = args.getName(i); | 1056 var name = args.getName(i); |
| 1060 if (seen.contains(name)) { | 1057 if (seen.contains(name)) { |
| 1061 return _argError(context, node, target, args, | 1058 return _argError(context, node, target, args, |
| 1062 'duplicate argument "$name"', i); | 1059 'duplicate argument "$name"', i); |
| 1063 } | 1060 } |
| 1064 seen.add(name); | 1061 seen.add(name); |
| 1065 int p = indexOfParameter(name); | 1062 int p = indexOfParameter(name); |
| 1066 if (p < 0) { | 1063 if (p < 0) { |
| 1067 return _argError(context, node, target, args, | 1064 return _argError(context, node, target, args, |
| 1068 'method does not have optional parameter "$name"', i); | 1065 'method does not have optional parameter "$name"', i); |
| 1069 } else if (p < bareCount) { | 1066 } else if (p < bareCount) { |
| 1070 return _argError(context, node, target, args, | 1067 return _argError(context, node, target, args, |
| 1071 'argument "$name" passed as positional and named', | 1068 'argument "$name" passed as positional and named', |
| 1072 // Given that the named was mentioned explicitly, highlight the | 1069 // Given that the named was mentioned explicitly, highlight the |
| 1073 // positional location instead: | 1070 // positional location instead: |
| 1074 p); | 1071 p); |
| 1075 } | 1072 } |
| 1076 } | 1073 } |
| 1077 world.internalError('wrong named arguments calling $name', node.span); | 1074 world.internalError('wrong named arguments calling $name', node.span); |
| 1078 } | 1075 } |
| 1079 | 1076 |
| 1080 var argsString = Strings.join(argsCode, ', '); | 1077 // TODO(jmesserly): maybe this should be producing the result Value, and we |
| 1078 // just return on this line. |
| 1079 Type inferredResult = world.gen.invokeMethod(this, target, |
| 1080 new Arguments(null, argValues)); |
| 1081 |
| 1082 final argsCode = map(argValues, (v) => v.code); |
| 1083 if (!target.isType && (isConstructor || target.isSuper)) { |
| 1084 argsCode.insertRange(0, 1, 'this'); |
| 1085 } |
| 1086 if (namedArgsUsed < args.nameCount) { |
| 1087 Arguments.removeTrailingNulls(argsCode); |
| 1088 } |
| 1089 final argsString = Strings.join(argsCode, ', '); |
| 1081 | 1090 |
| 1082 if (isConstructor) { | 1091 if (isConstructor) { |
| 1083 return _invokeConstructor(context, node, target, args, argsString); | 1092 return _invokeConstructor(context, node, target, args, argsString); |
| 1084 } | 1093 } |
| 1085 | 1094 |
| 1086 if (target.isSuper) { | 1095 if (target.isSuper) { |
| 1087 return new Value(inferredResult, | 1096 return new Value(inferredResult, |
| 1088 '${declaringType.jsname}.prototype.$jsname.call($argsString)', | 1097 '${declaringType.jsname}.prototype.$jsname.call($argsString)', |
| 1089 node.span); | 1098 node.span); |
| 1090 } | 1099 } |
| 1091 | 1100 |
| 1092 if (isOperator) { | 1101 if (isOperator) { |
| 1093 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic); | 1102 return _invokeBuiltin(context, node, target, args, argsCode, isDynamic, |
| 1103 inferredResult); |
| 1094 } | 1104 } |
| 1095 | 1105 |
| 1096 if (isFactory) { | 1106 if (isFactory) { |
| 1097 assert(target.isType); | 1107 assert(target.isType); |
| 1098 return new Value(target.type, '$generatedFactoryName($argsString)', | 1108 return new Value(target.type, '$generatedFactoryName($argsString)', |
| 1099 node !== null ? node.span : null); | 1109 node !== null ? node.span : null); |
| 1100 } | 1110 } |
| 1101 | 1111 |
| 1102 if (isStatic) { | 1112 if (isStatic) { |
| 1103 if (declaringType.isTop) { | 1113 if (declaringType.isTop) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 return world.gen.globalForConst(newObject, [args.values]); | 1158 return world.gen.globalForConst(newObject, [args.values]); |
| 1149 } else { | 1159 } else { |
| 1150 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; | 1160 var code = 'new ${declaringType.nativeName}${ctor}($argsString)'; |
| 1151 return new Value(target.type, code, span); | 1161 return new Value(target.type, code, span); |
| 1152 } | 1162 } |
| 1153 } | 1163 } |
| 1154 } | 1164 } |
| 1155 | 1165 |
| 1156 _evalConstConstructor(Value newObject, Arguments args) { | 1166 _evalConstConstructor(Value newObject, Arguments args) { |
| 1157 declaringType.markUsed(); | 1167 declaringType.markUsed(); |
| 1158 var generator = new MethodGenerator(this, null); | 1168 new MethodGenerator(this).evalBody(newObject, args); |
| 1159 generator.evalBody(newObject, args); | |
| 1160 } | 1169 } |
| 1161 | 1170 |
| 1162 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, | 1171 Value _invokeBuiltin(MethodGenerator context, Node node, Value target, |
| 1163 Arguments args, argsCode, bool isDynamic) { | 1172 Arguments args, argsCode, bool isDynamic, Type inferredResult) { |
| 1164 // Handle some fast paths for Number, String, List and DOM. | 1173 // Handle some fast paths for Number, String, List and DOM. |
| 1165 if (declaringType.isNum) { | 1174 if (declaringType.isNum) { |
| 1166 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num. | 1175 // TODO(jimhug): This fails in bad ways when argsCode[1] is not num. |
| 1167 // TODO(jimhug): What about null? | 1176 // TODO(jimhug): What about null? |
| 1168 var code; | 1177 var code; |
| 1169 if (name == ':negate') { | 1178 if (name == ':negate') { |
| 1170 code = '-${target.code}'; | 1179 code = '-${target.code}'; |
| 1171 } else if (name == ':bit_not') { | 1180 } else if (name == ':bit_not') { |
| 1172 code = '~${target.code}'; | 1181 code = '~${target.code}'; |
| 1173 } else if (name == ':truncdiv' || name == ':mod') { | 1182 } else if (name == ':truncdiv' || name == ':mod') { |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1688 } | 1697 } |
| 1689 | 1698 |
| 1690 void forEach(void f(Member member)) { | 1699 void forEach(void f(Member member)) { |
| 1691 factories.forEach((_, Map constructors) { | 1700 factories.forEach((_, Map constructors) { |
| 1692 constructors.forEach((_, Member member) { | 1701 constructors.forEach((_, Member member) { |
| 1693 f(member); | 1702 f(member); |
| 1694 }); | 1703 }); |
| 1695 }); | 1704 }); |
| 1696 } | 1705 } |
| 1697 } | 1706 } |
| OLD | NEW |