| Index: frog/member.dart
|
| diff --git a/frog/member.dart b/frog/member.dart
|
| index 5d34ab7969397e42088dc305f39f985cab6ee4ef..68391fefddf6744c01b8465fe120ef7bb5649ada 100644
|
| --- a/frog/member.dart
|
| +++ b/frog/member.dart
|
| @@ -15,6 +15,8 @@ class Parameter {
|
|
|
| Parameter(this.definition, this.method);
|
|
|
| + SourceSpan get span() => definition.span;
|
| +
|
| resolve() {
|
| name = definition.name.name;
|
| if (name.startsWith('this.')) {
|
| @@ -49,13 +51,13 @@ class Parameter {
|
| }
|
| }
|
|
|
| - genValue(MethodMember method, MethodGenerator context) {
|
| + genValue(MethodMember method, [MethodGenerator context]) {
|
| if (definition.value == null || value != null) return;
|
|
|
| if (context == null) { // interface method
|
| - context = new MethodGenerator(method, null);
|
| + context = new MethodGenerator(method);
|
| }
|
| - value = definition.value.visit(context);
|
| + value = context.evalExpression(definition.value);
|
| if (!value.isConst) {
|
| world.error('default parameter values must be constant', value.span);
|
| }
|
| @@ -84,11 +86,15 @@ class Parameter {
|
| class Member extends Element {
|
| final Type declaringType;
|
|
|
| - bool isGenerated;
|
| - MethodGenerator generator;
|
| + bool isUsed;
|
| +
|
| + // TODO(jmesserly): this only makes sense if we never specialize functions
|
| + // for their argument types.
|
| + MethodGenerator get generator() => specializer.generator;
|
| + MethodSpecializer specializer;
|
|
|
| Member(String name, Type declaringType)
|
| - : isGenerated = false, this.declaringType = declaringType,
|
| + : isUsed = false, this.declaringType = declaringType,
|
| super(name, declaringType);
|
|
|
| abstract bool get isStatic();
|
| @@ -142,24 +148,12 @@ class Member extends Element {
|
| world.internalError('cannot have value', span);
|
| }
|
|
|
| - /**
|
| - * The inferred returnType. Right now this is just used to track
|
| - * non-nullable bools.
|
| - */
|
| - Type get inferredResult() {
|
| - var t = returnType;
|
| - if (t.isBool && (library.isCore || library.isCoreImpl)) {
|
| - // We trust our core libraries not to return null from bools.
|
| - // I hope this trust is well placed!
|
| - return world.nonNullBool;
|
| - }
|
| - return t;
|
| - }
|
| -
|
| Definition get definition() => null;
|
|
|
| List<Parameter> get parameters() => [];
|
|
|
| + void markUsed() => declaringType.markUsedMethod(this);
|
| +
|
| MemberSet _preciseMemberSet, _potentialMemberSet;
|
|
|
| MemberSet get preciseMemberSet() {
|
| @@ -435,8 +429,7 @@ class FieldMember extends Member {
|
| _computing = true;
|
| var finalMethod = new MethodMember('final_context', declaringType, null);
|
| finalMethod.isStatic = true;
|
| - var finalGen = new MethodGenerator(finalMethod, null);
|
| - _computedValue = value.visit(finalGen);
|
| + _computedValue = new MethodGenerator(finalMethod).evalExpression(value);
|
| if (!_computedValue.isConst) {
|
| if (isStatic) {
|
| world.error(
|
| @@ -711,6 +704,11 @@ class ConcreteMember extends Member {
|
| // TODO(jimhug): Add support for type params.
|
| bool override(Member other) => baseMember.override(other);
|
|
|
| + // TODO(jmesserly): this hack is needed because ConcreteMember is using
|
| + // baseMember to do the operation, then replacing the type on the Value.
|
| + // Something else needs to happen.
|
| + Type get inferredResult() => returnType;
|
| +
|
| Value _get(MethodGenerator context, Node node, Value target,
|
| [bool isDynamic=false]) {
|
| Value ret = baseMember._get(context, node, target, isDynamic);
|
| @@ -721,7 +719,7 @@ class ConcreteMember extends Member {
|
| [bool isDynamic=false]) {
|
| // TODO(jimhug): Check arg types in context of concrete type.
|
| Value ret = baseMember._set(context, node, target, value, isDynamic);
|
| - return new Value(returnType, ret.code, node.span);
|
| + return new Value(inferredResult, ret.code, node.span);
|
| }
|
|
|
| _evalConstConstructor(ObjectValue newObject, Arguments args) {
|
| @@ -744,7 +742,10 @@ class ConcreteMember extends Member {
|
| declaringType.genericType.jsname, declaringType.jsname);
|
| }
|
| if (baseMember is MethodMember) {
|
| - declaringType.genMethod(this);
|
| + // TODO(jmesserly): we should be filling in the right args here and
|
| + // using the result type. But the args need to be reordered to match the
|
| + // call site, like baseMember.invoke does.
|
| + world.gen.invokeMethod(this, target, null);
|
| }
|
| return new Value(inferredResult, code, node.span);
|
| }
|
| @@ -880,8 +881,11 @@ class MethodMember extends Member {
|
|
|
| Value _get(MethodGenerator context, Node node, Value target,
|
| [bool isDynamic=false]) {
|
| - // TODO(jimhug): Would prefer to invoke!
|
| - declaringType.genMethod(this);
|
| +
|
| + // TODO(jmesserly): if we tracked functions as values, this would be the
|
| + // place to do it.
|
| + world.gen.invokeMethod(this);
|
| +
|
| _provideOptionalParamInfo = true;
|
| if (isStatic) {
|
| // ensure the type is generated.
|
| @@ -979,7 +983,7 @@ class MethodMember extends Member {
|
|
|
| genParameterValues() {
|
| // Pure lazy?
|
| - for (var p in parameters) p.genValue(this, generator);
|
| + for (var p in parameters) p.genValue(this);
|
| }
|
|
|
| /**
|
| @@ -994,8 +998,6 @@ class MethodMember extends Member {
|
| resolve();
|
| }
|
|
|
| - declaringType.genMethod(this);
|
| -
|
| if (isStatic || isFactory) {
|
| // TODO(sigmund): can we avoid generating the entire type, but only what
|
| // we need?
|
| @@ -1013,11 +1015,7 @@ class MethodMember extends Member {
|
| return context.findMembers(name).invokeOnVar(context, node, target, args);
|
| }
|
|
|
| - var argsCode = [];
|
| - if (!target.isType && (isConstructor || target.isSuper)) {
|
| - argsCode.add('this');
|
| - }
|
| -
|
| + final argValues = <Value>[];
|
| int bareCount = args.bareCount;
|
| for (int i = 0; i < bareCount; i++) {
|
| var arg = args.values[i];
|
| @@ -1026,7 +1024,7 @@ class MethodMember extends Member {
|
| return _argError(context, node, target, args, msg, i);
|
| }
|
| arg = arg.convertTo(context, parameters[i].type, isDynamic);
|
| - argsCode.add(arg.code);
|
| + argValues.add(arg);
|
| }
|
|
|
| int namedArgsUsed = 0;
|
| @@ -1046,10 +1044,9 @@ class MethodMember extends Member {
|
| var msg = _argCountMsg(Math.min(i, args.length), i + 1, atLeast:true);
|
| return _argError(context, node, target, args, msg, i);
|
| } else {
|
| - argsCode.add(arg.code);
|
| + argValues.add(arg);
|
| }
|
| }
|
| - Arguments.removeTrailingNulls(argsCode);
|
| }
|
|
|
| if (namedArgsUsed < args.nameCount) {
|
| @@ -1077,7 +1074,19 @@ class MethodMember extends Member {
|
| world.internalError('wrong named arguments calling $name', node.span);
|
| }
|
|
|
| - var argsString = Strings.join(argsCode, ', ');
|
| + // TODO(jmesserly): maybe this should be producing the result Value, and we
|
| + // just return on this line.
|
| + Type inferredResult = world.gen.invokeMethod(this, target,
|
| + new Arguments(null, argValues));
|
| +
|
| + final argsCode = map(argValues, (v) => v.code);
|
| + if (!target.isType && (isConstructor || target.isSuper)) {
|
| + argsCode.insertRange(0, 1, 'this');
|
| + }
|
| + if (namedArgsUsed < args.nameCount) {
|
| + Arguments.removeTrailingNulls(argsCode);
|
| + }
|
| + final argsString = Strings.join(argsCode, ', ');
|
|
|
| if (isConstructor) {
|
| return _invokeConstructor(context, node, target, args, argsString);
|
| @@ -1090,7 +1099,8 @@ class MethodMember extends Member {
|
| }
|
|
|
| if (isOperator) {
|
| - return _invokeBuiltin(context, node, target, args, argsCode, isDynamic);
|
| + return _invokeBuiltin(context, node, target, args, argsCode, isDynamic,
|
| + inferredResult);
|
| }
|
|
|
| if (isFactory) {
|
| @@ -1155,12 +1165,11 @@ class MethodMember extends Member {
|
|
|
| _evalConstConstructor(Value newObject, Arguments args) {
|
| declaringType.markUsed();
|
| - var generator = new MethodGenerator(this, null);
|
| - generator.evalBody(newObject, args);
|
| + new MethodGenerator(this).evalBody(newObject, args);
|
| }
|
|
|
| Value _invokeBuiltin(MethodGenerator context, Node node, Value target,
|
| - Arguments args, argsCode, bool isDynamic) {
|
| + Arguments args, argsCode, bool isDynamic, Type inferredResult) {
|
| // Handle some fast paths for Number, String, List and DOM.
|
| if (declaringType.isNum) {
|
| // TODO(jimhug): This fails in bad ways when argsCode[1] is not num.
|
|
|