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

Unified 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 side-by-side diff with in-line comments
Download patch
« frog/gen.dart ('K') | « frog/library.dart ('k') | frog/member_set.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/member.dart
diff --git a/frog/member.dart b/frog/member.dart
index 5d34ab7969397e42088dc305f39f985cab6ee4ef..fae4246fb186d657105f49f7edb9ca04dc611bd1 100644
--- a/frog/member.dart
+++ b/frog/member.dart
@@ -22,7 +22,7 @@ class Parameter {
isInitializer = true;
}
- type = method.resolveType(definition.type, false);
+ type = method.resolveType(definition.type, false, true);
if (definition.value != null) {
// To match VM, detect cases where value was not actually specified in
@@ -49,7 +49,7 @@ class Parameter {
}
}
- genValue(MethodMember method, MethodGenerator context) {
+ genValue(MethodMember method, CallingContext context) {
if (definition.value == null || value != null) return;
if (context == null) { // interface method
@@ -84,11 +84,10 @@ class Parameter {
class Member extends Element {
final Type declaringType;
- bool isGenerated;
- MethodGenerator generator;
+ Member genericMember;
Member(String name, Type declaringType)
- : isGenerated = false, this.declaringType = declaringType,
+ : this.declaringType = declaringType,
super(name, declaringType);
abstract bool get isStatic();
@@ -119,16 +118,12 @@ class Member extends Element {
bool get requiresPropertySyntax() => false;
bool _providePropertySyntax = false;
- bool get requiresFieldSyntax() => false;
- bool _provideFieldSyntax = false;
bool get isNative() => false;
String get constructorName() {
world.internalError('can not be a constructor', span);
}
- // Don't display an error here; we'll get a better error later.
- void provideFieldSyntax() {}
void providePropertySyntax() {}
Member get initDelegate() {
@@ -170,31 +165,45 @@ class Member extends Element {
}
MemberSet get potentialMemberSet() {
+ // TODO(jimhug): This needs one more redesign - move to TypeSets...
+
if (_potentialMemberSet === null) {
- if (declaringType.isObject) {
- _potentialMemberSet = world._members[name];
+ if (name == ':call') {
+ _potentialMemberSet = preciseMemberSet;
return _potentialMemberSet;
}
final mems = new Set<Member>();
if (declaringType.isClass) mems.add(this);
-
- for (var subtype in declaringType.subtypes) {
+ for (var subtype in declaringType.genericType.subtypes) {
if (!subtype.isClass) continue;
var mem = subtype.members[name];
if (mem !== null) {
- mems.add(mem);
+ if (mem.isDefinedOn(declaringType)) {
+ mems.add(mem);
+ }
} else if (!declaringType.isClass) {
// Handles weird interface case.
mem = subtype.getMember(name);
- if (mem !== null) {
+ if (mem !== null && mem.isDefinedOn(declaringType)) {
mems.add(mem);
}
}
}
if (mems.length != 0) {
+ // TODO(jimhug): This hack needs to be rationalized.
+ for (var mem in mems) {
+ if (declaringType.genericType != declaringType &&
+ mem.genericMember != null && mems.contains(mem.genericMember)) {
+ //world.info('skip ${name} on ${mem.genericMember.declaringType.name}' +
+ // ' because we have on ${mem.declaringType.name} for ${declaringType.name}');
+ mems.remove(mem.genericMember);
+ }
+ }
+
+
for (var mem in mems) {
if (_potentialMemberSet === null) {
_potentialMemberSet = new MemberSet(mem);
@@ -214,9 +223,8 @@ class Member extends Element {
return true;
} else if (type.isSubtypeOf(declaringType)) {
// maybe - but not if overridden somewhere
- // !!! horrible hack for today - awful perf props
+ // TODO(jimhug): This lookup is not great for perf of this method.
return type.getMember(name) == this;
- //return true;
} else {
return false;
}
@@ -236,23 +244,25 @@ class Member extends Element {
}
}
- // TODO(jmesserly): isDynamic isn't a great name for this, something better?
- abstract Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic]);
+ abstract Value _get(CallingContext context, Node node, Value target);
- abstract Value _set(MethodGenerator context, Node node, Value target,
- Value value, [bool isDynamic]);
+ abstract Value _set(CallingContext context, Node node, Value target,
+ Value value);
- bool canInvoke(MethodGenerator context, Arguments args) {
- // No source location needed because canInvoke may not produce errors.
- return canGet &&
- new Value(returnType, null, null).canInvoke(context, ':call', args);
+
+ bool canInvoke(CallingContext context, Arguments args) {
+ // Any gettable member whose return type is callable can be "invoked".
+ if (canGet && (isField || isProperty)) {
+ return this.returnType.isFunction || this.returnType.isVar ||
+ this.returnType.getCallMethod() != null;
+ }
+ return false;
}
- Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
- [bool isDynamic=false]) {
- var newTarget = _get(context, node, target, isDynamic);
- return newTarget.invoke(context, ':call', node, args, isDynamic);
+ Value invoke(CallingContext context, Node node, Value target,
+ Arguments args) {
+ var newTarget = _get(context, node, target);
+ return newTarget.invoke(context, ':call', node, args);
}
bool override(Member other) {
@@ -269,7 +279,7 @@ class Member extends Element {
String get generatedFactoryName() {
assert(this.isFactory);
- String prefix = '${declaringType.jsname}.${constructorName}\$';
+ String prefix = '${declaringType.genericType.jsname}.${constructorName}\$';
if (name == '') {
return '${prefix}factory';
} else {
@@ -289,6 +299,18 @@ class Member extends Element {
declaringType == other.declaringType && (isConstructor ?
constructorName == other.constructorName : name == other.name);
}
+
+ /** Overriden to ensure that type arguments aren't used in static mems. */
+ Type resolveType(TypeReference node, bool typeErrors, bool allowTypeParams) {
+ allowTypeParams = allowTypeParams && !(isStatic && !isFactory);
+
+ return super.resolveType(node, typeErrors, allowTypeParams);
+ }
+
+ // TODO(jimhug): Make this abstract.
+ Member makeConcrete(Type concreteType) {
+ world.internalError('can not make this concrete', span);
+ }
}
@@ -311,24 +333,20 @@ class TypeMember extends Member {
// If this really becomes first class, this should return typeof(Type)
Type get returnType() => world.varType;
- bool canInvoke(MethodGenerator context, Arguments args) => false;
+ bool canInvoke(CallingContext context, Arguments args) => false;
bool get canGet() => true;
bool get canSet() => false;
- bool get requiresFieldSyntax() => true;
-
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
+ Value _get(CallingContext context, Node node, Value target) {
return new TypeValue(type, node.span);
}
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [bool isDynamic=false]) {
+ Value _set(CallingContext context, Node node, Value target, Value value) {
world.error('cannot set type', node.span);
}
- Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
- [bool isDynamic=false]) {
+ Value invoke(CallingContext context, Node node, Value target,
+ Arguments args) {
world.error('cannot invoke type', node.span);
}
}
@@ -373,12 +391,24 @@ class FieldMember extends Member {
}
}
- void provideFieldSyntax() {} // Nothing to do.
- void providePropertySyntax() { _providePropertySyntax = true; }
+ void providePropertySyntax() {
+ _providePropertySyntax = true;
+ if (genericMember !== null) {
+ genericMember.providePropertySyntax();
+ }
+ }
FieldMember(String name, Type declaringType, this.definition, this.value)
: super(name, declaringType), isNative = false;
+ Member makeConcrete(Type concreteType) {
+ var ret = new FieldMember(name, concreteType, definition, value);
+ ret.genericMember = this;
+ ret._jsname = _jsname;
+ return ret;
+ }
+
+
SourceSpan get span() => definition == null ? null : definition.span;
Type get returnType() => type;
@@ -408,17 +438,13 @@ class FieldMember extends Member {
}
}
}
- type = resolveType(definition.type, false);
- if (isStatic && !isFactory && type.hasTypeParams) {
- world.error('using type parameter in static context',
- definition.type.span);
- }
+ type = resolveType(definition.type, false, true);
if (isStatic && isFinal && value == null) {
world.error('static final field is missing initializer', span);
}
- library._addMember(this);
+ if (declaringType.isClass) library._addMember(this);
}
@@ -463,8 +489,11 @@ class FieldMember extends Member {
return _computedValue;
}
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
+ Value _get(CallingContext context, Node node, Value target) {
+ if (!context.needsCode) {
+ return new PureStaticValue(type, node.span, isStatic && isFinal);
+ }
+
if (isNative && returnType != null) {
returnType.markUsed();
if (returnType is DefinedType) {
@@ -511,10 +540,14 @@ class FieldMember extends Member {
return new Value(type, '${target.code}.$jsname', node.span);
}
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [bool isDynamic=false]) {
- var lhs = _get(context, node, target, isDynamic);
- value = value.convertTo(context, type, isDynamic);
+ Value _set(CallingContext context, Node node, Value target, Value value) {
+ if (!context.needsCode) {
+ // TODO(jimhug): Add type checks here.
+ return new PureStaticValue(type, node.span);
+ }
+
+ var lhs = _get(context, node, target);
+ value = value.convertTo(context, type);
return new Value(type, '${lhs.code} = ${value.code}', node.span);
}
}
@@ -535,15 +568,11 @@ class PropertyMember extends Member {
// field syntax in the generated code.
bool get requiresPropertySyntax() => declaringType.isClass;
- void provideFieldSyntax() { _provideFieldSyntax = true; }
- void providePropertySyntax() {
- // when overriding native fields, we still provide a field syntax to ensure
- // that native functions will find the appropriate property implementation.
- // TODO(sigmund): should check for this transitively...
- if (_overriddenField != null && _overriddenField.isNative) {
- provideFieldSyntax();
- }
- }
+ // when overriding native fields, we still provide a field syntax to ensure
+ // that native functions will find the appropriate property implementation.
+ // TODO(sigmund): should check for this transitively...
+ bool get needsFieldSyntax() =>
+ _overriddenField != null && _overriddenField.isNative;
// TODO(jimhug): Union of getter and setters sucks!
bool get isStatic() => getter == null ? setter.isStatic : getter.isStatic;
@@ -556,6 +585,14 @@ class PropertyMember extends Member {
PropertyMember(String name, Type declaringType): super(name, declaringType);
+ Member makeConcrete(Type concreteType) {
+ var ret = new PropertyMember(name, concreteType);
+ if (getter !== null) ret.getter = getter.makeConcrete(concreteType);
+ if (setter !== null) ret.setter = setter.makeConcrete(concreteType);
+ ret._jsname = _jsname;
+ return ret;
+ }
+
bool override(Member other) {
if (!super.override(other)) return false;
@@ -573,39 +610,29 @@ class PropertyMember extends Member {
}
}
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
+ Value _get(CallingContext context, Node node, Value target) {
if (getter == null) {
if (_overriddenField != null) {
- return _overriddenField._get(context, node, target, isDynamic);
+ return _overriddenField._get(context, node, target);
}
return target.invokeNoSuchMethod(context, 'get:$name', node);
}
return getter.invoke(context, node, target, Arguments.EMPTY);
}
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [bool isDynamic=false]) {
+ Value _set(CallingContext context, Node node, Value target, Value value) {
if (setter == null) {
if (_overriddenField != null) {
- return _overriddenField._set(context, node, target, value, isDynamic);
+ return _overriddenField._set(context, node, target, value);
}
return target.invokeNoSuchMethod(context, 'set:$name', node,
new Arguments(null, [value]));
}
- return setter.invoke(context, node, target, new Arguments(null, [value]),
- isDynamic);
+ return setter.invoke(context, node, target, new Arguments(null, [value]));
}
addFromParent(Member parentMember) {
- // TODO(jimhug): Egregious Hack!
- PropertyMember parent;
- if (parentMember is ConcreteMember) {
- ConcreteMember c = parentMember;
- parent = c.baseMember;
- } else {
- parent = parentMember;
- }
+ final parent = parentMember;
if (getter == null) getter = parent.getter;
if (setter == null) setter = parent.setter;
@@ -637,116 +664,7 @@ class PropertyMember extends Member {
}
}
- library._addMember(this);
- }
-}
-
-
-class ConcreteMember extends Member {
- final Member baseMember;
- Type returnType;
- List<Parameter> parameters;
-
- ConcreteMember(String name, ConcreteType declaringType, this.baseMember)
- : super(name, declaringType) {
- parameters = [];
- returnType = baseMember.returnType.resolveTypeParams(declaringType);
- // TODO(jimhug): Optimize not creating new array if no new param types.
- for (var p in baseMember.parameters) {
- var newType = p.type.resolveTypeParams(declaringType);
- if (newType != p.type) {
- parameters.add(p.copyWithNewType(this, newType));
- } else {
- parameters.add(p);
- }
- }
- }
-
- SourceSpan get span() => baseMember.span;
-
- bool get isStatic() => baseMember.isStatic;
- bool get isAbstract() => baseMember.isAbstract;
- bool get isConst() => baseMember.isConst;
- bool get isFactory() => baseMember.isFactory;
- bool get isFinal() => baseMember.isFinal;
- bool get isNative() => baseMember.isNative;
-
- String get jsname() => baseMember.jsname;
- set jsname(String name) =>
- world.internalError('bad set of jsname on ConcreteMember');
-
-
- bool get canGet() => baseMember.canGet;
- bool get canSet() => baseMember.canSet;
- bool canInvoke(MethodGenerator context, Arguments args) =>
- baseMember.canInvoke(context, args);
-
- bool get isField() => baseMember.isField;
- bool get isMethod() => baseMember.isMethod;
- bool get isProperty() => baseMember.isProperty;
-
- bool get requiresPropertySyntax() => baseMember.requiresPropertySyntax;
- bool get requiresFieldSyntax() => baseMember.requiresFieldSyntax;
-
- void provideFieldSyntax() => baseMember.provideFieldSyntax();
- void providePropertySyntax() => baseMember.providePropertySyntax();
-
- bool get isConstructor() => name == declaringType.name;
-
- String get constructorName() => baseMember.constructorName;
-
- Definition get definition() => baseMember.definition;
-
- // TODO(sigmund): this is EGREGIOUS
- Member get initDelegate() => baseMember.initDelegate;
- void set initDelegate(ctor) { baseMember.initDelegate = ctor; }
-
- Type resolveType(TypeReference node, bool isRequired) {
- var type = baseMember.resolveType(node, isRequired);
- return type.resolveTypeParams(declaringType);
- }
-
- Value computeValue() => baseMember.computeValue();
-
- // TODO(jimhug): Add support for type params.
- bool override(Member other) => baseMember.override(other);
-
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
- Value ret = baseMember._get(context, node, target, isDynamic);
- return new Value(inferredResult, ret.code, node.span);
- }
-
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [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);
- }
-
- _evalConstConstructor(ObjectValue newObject, Arguments args) {
- // TODO(jimhug): Concrete type probably matters somehow here
- return baseMember.dynamic._evalConstConstructor(newObject, args);
- }
-
-
- Value invoke(MethodGenerator context, Node node, Value target, Arguments args,
- [bool isDynamic=false]) {
- // TODO(jimhug): Check arg types in context of concrete type.
- // TODO(jmesserly): I think what needs to happen is to move MethodMember's
- // invoke so that it's run against the "parameters" and "returnType" of the
- // ConcreteMember instead.
- Value ret = baseMember.invoke(context, node, target, args, isDynamic);
- var code = ret.code;
- if (isConstructor) {
- // TODO(jimhug): Egregious hack - won't live through the year.
- code = code.replaceFirst(
- declaringType.genericType.jsname, declaringType.jsname);
- }
- if (baseMember is MethodMember) {
- declaringType.genMethod(this);
- }
- return new Value(inferredResult, code, node.span);
+ if (declaringType.isClass) library._addMember(this);
}
}
@@ -757,6 +675,8 @@ class MethodMember extends Member {
Type returnType;
List<Parameter> parameters;
+ MethodData _methodData;
+
Type _functionType;
bool isStatic = false;
bool isAbstract = false;
@@ -783,6 +703,23 @@ class MethodMember extends Member {
MethodMember(String name, Type declaringType, this.definition)
: super(name, declaringType);
+ Member makeConcrete(Type concreteType) {
+ var _name = isConstructor ? concreteType.name : name;
+ var ret = new MethodMember(_name, concreteType, definition);
+ ret.genericMember = this;
+ ret._jsname = _jsname;
+ return ret;
+ }
+
+ MethodData get methodData() {
+ if (genericMember !== null) return genericMember.dynamic.methodData;
+
+ if (_methodData === null) {
+ _methodData = new MethodData(this);
+ }
+ return _methodData;
+ }
+
bool get isConstructor() => name == declaringType.name;
bool get isMethod() => !isConstructor;
@@ -813,8 +750,8 @@ class MethodMember extends Member {
Type get functionType() {
if (_functionType == null) {
- _functionType =
- library.getOrAddFunctionType(declaringType, name, definition);
+ _functionType = library.getOrAddFunctionType(declaringType, name,
+ definition, methodData);
// TODO(jimhug): Better resolution checks.
if (parameters == null) {
resolve();
@@ -838,7 +775,7 @@ class MethodMember extends Member {
}
}
- bool canInvoke(MethodGenerator context, Arguments args) {
+ bool canInvoke(CallingContext context, Arguments args) {
int bareCount = args.bareCount;
if (bareCount > parameters.length) return false;
@@ -870,16 +807,17 @@ class MethodMember extends Member {
return -1;
}
- void provideFieldSyntax() { _provideFieldSyntax = true; }
void providePropertySyntax() { _providePropertySyntax = true; }
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [bool isDynamic=false]) {
+ Value _set(CallingContext context, Node node, Value target, Value value) {
world.error('cannot set method', node.span);
}
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
+ Value _get(CallingContext context, Node node, Value target) {
+ if (!context.needsCode) {
+ return new PureStaticValue(functionType, node.span);
+ }
+
// TODO(jimhug): Would prefer to invoke!
declaringType.genMethod(this);
_provideOptionalParamInfo = true;
@@ -944,7 +882,6 @@ class MethodMember extends Member {
}
if (bareCount < parameters.length) {
- genParameterValues();
for (int i = bareCount; i < parameters.length; i++) {
var arg = args.getValue(parameters[i].name);
if (arg != null && arg.needsConversion(parameters[i].type)) {
@@ -961,7 +898,7 @@ class MethodMember extends Member {
'${atLeast ? "at least " : ""}$expected but found $actual';
}
- Value _argError(MethodGenerator context, Node node, Value target,
+ Value _argError(CallingContext context, Node node, Value target,
Arguments args, String msg, int argIndex) {
SourceSpan span;
if ((args.nodes == null) || (argIndex >= args.nodes.length)) {
@@ -977,21 +914,20 @@ class MethodMember extends Member {
return target.invokeNoSuchMethod(context, name, node, args);
}
- genParameterValues() {
- // Pure lazy?
- for (var p in parameters) p.genValue(this, generator);
+ genParameterValues(CallingContext context) {
+ // TODO(jimhug): Is this the right context?
+ for (var p in parameters) p.genValue(this, context);
}
/**
* Invokes this method on the given [target] with the given [args].
* [node] provides a [SourceSpan] for any error messages.
*/
- Value invoke(MethodGenerator context, Node node, Value target,
- Arguments args, [bool isDynamic=false]) {
- // TODO(jimhug): Fix this hack for ensuring a method is resolved.
- if (parameters == null) {
- world.info('surprised to need to resolve: ${declaringType.name}.$name');
- resolve();
+ Value invoke(CallingContext context, Node node, Value target,
+ Arguments args) {
+ if (!context.needsCode) {
+ // TODO(jimhug): Add argument type and name checks here.
+ return new PureStaticValue(returnType, node.span);
}
declaringType.genMethod(this);
@@ -1025,20 +961,20 @@ class MethodMember extends Member {
var msg = _argCountMsg(args.length, parameters.length);
return _argError(context, node, target, args, msg, i);
}
- arg = arg.convertTo(context, parameters[i].type, isDynamic);
+ arg = arg.convertTo(context, parameters[i].type);
argsCode.add(arg.code);
}
int namedArgsUsed = 0;
if (bareCount < parameters.length) {
- genParameterValues();
+ genParameterValues(context);
for (int i = bareCount; i < parameters.length; i++) {
var arg = args.getValue(parameters[i].name);
if (arg == null) {
arg = parameters[i].value;
} else {
- arg = arg.convertTo(context, parameters[i].type, isDynamic);
+ arg = arg.convertTo(context, parameters[i].type);
namedArgsUsed++;
}
@@ -1090,7 +1026,7 @@ class MethodMember extends Member {
}
if (isOperator) {
- return _invokeBuiltin(context, node, target, args, argsCode, isDynamic);
+ return _invokeBuiltin(context, node, target, args, argsCode);
}
if (isFactory) {
@@ -1117,7 +1053,7 @@ class MethodMember extends Member {
return new Value(inferredResult, code, node.span);
}
- Value _invokeConstructor(MethodGenerator context, Node node,
+ Value _invokeConstructor(CallingContext context, Node node,
Value target, Arguments args, argsString) {
declaringType.markUsed();
@@ -1155,45 +1091,52 @@ class MethodMember extends Member {
_evalConstConstructor(Value newObject, Arguments args) {
declaringType.markUsed();
- var generator = new MethodGenerator(this, null);
- generator.evalBody(newObject, args);
+ methodData.eval(this, newObject, args);
}
- Value _invokeBuiltin(MethodGenerator context, Node node, Value target,
- Arguments args, argsCode, bool isDynamic) {
+ Value _invokeBuiltin(CallingContext context, Node node, Value target,
+ Arguments args, argsCode) {
// Handle some fast paths for Number, String, List and DOM.
- if (declaringType.isNum) {
+ if (target.type.isNum) {
// TODO(jimhug): This fails in bad ways when argsCode[1] is not num.
// TODO(jimhug): What about null?
- var code;
- if (name == ':negate') {
- code = '-${target.code}';
- } else if (name == ':bit_not') {
- code = '~${target.code}';
- } else if (name == ':truncdiv' || name == ':mod') {
- world.gen.corejs.useOperator(name);
- code = '$jsname(${target.code}, ${argsCode[0]})';
- } else {
- var op = TokenKind.rawOperatorFromMethod(name);
- code = '${target.code} $op ${argsCode[0]}';
+ var code = null;
+ if (args.length == 0) {
+ if (name == ':negate') {
+ code = '-${target.code}';
+ } else if (name == ':bit_not') {
+ code = '~${target.code}';
+ }
+ } else if (args.length == 1 && args.values[0].type.isNum) {
+ if (name == ':truncdiv' || name == ':mod') {
+ world.gen.corejs.useOperator(name);
+ code = '$jsname(${target.code}, ${argsCode[0]})';
+ } else {
+ var op = TokenKind.rawOperatorFromMethod(name);
+ code = '${target.code} $op ${argsCode[0]}';
+ }
}
-
- return new Value(inferredResult, code, node.span);
- } else if (declaringType.isString) {
- if (name == ':index') {
+ if (code !== null) {
+ return new Value(inferredResult, code, node.span);
+ }
+ } else if (target.type.isString) {
+ if (name == ':index' && args.values[0].type.isNum) {
return new Value(declaringType, '${target.code}[${argsCode[0]}]',
node.span);
- } else if (name == ':add') {
+ } else if (name == ':add' && args.values[0].type.isNum) {
return new Value(declaringType, '${target.code} + ${argsCode[0]}',
node.span);
}
} else if (declaringType.isNative) {
- if (name == ':index') {
- return
- new Value(returnType, '${target.code}[${argsCode[0]}]', node.span);
- } else if (name == ':setindex') {
- return new Value(returnType,
- '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span);
+ if (args.length > 0 && args.values[0].type.isNum) {
+ // TODO(jimhug): make more accurate/reliable
+ if (name == ':index') {
+ return
+ new Value(returnType, '${target.code}[${argsCode[0]}]', node.span);
+ } else if (name == ':setindex') {
+ return new Value(returnType,
+ '${target.code}[${argsCode[0]}] = ${argsCode[1]}', node.span);
+ }
}
}
@@ -1203,7 +1146,7 @@ class MethodMember extends Member {
if (name == ':ne') {
// Ensure == is generated.
- target.invoke(context, ':eq', node, args, isDynamic);
+ target.invoke(context, ':eq', node, args);
}
// Optimize test when null is on the rhs.
@@ -1226,10 +1169,16 @@ class MethodMember extends Member {
'${target.code}(${Strings.join(argsCode, ", ")})', node.span);
}
+ // TODO(jimhug): Reconcile with MethodSet version - ideally just eliminate
if (name == ':index') {
world.gen.corejs.useIndex = true;
} else if (name == ':setindex') {
world.gen.corejs.useSetIndex = true;
+ } else {
+ world.gen.corejs.useOperator(name);
+ var argsString = argsCode.length == 0 ? '' : ', ${argsCode[0]}';
+ return new Value(returnType, '$jsname(${target.code}${argsString})',
+ node.span);
}
// Fall back to normal method invocation.
@@ -1316,7 +1265,12 @@ class MethodMember extends Member {
returnType = declaringType;
} else {
// This is the one and only place we allow void.
- returnType = resolveType(definition.returnType, false, allowVoid: true);
+ if (definition.returnType is SimpleTypeReference &&
+ definition.returnType.dynamic.type == world.voidType) {
+ returnType = world.voidType;
+ } else {
+ returnType = resolveType(definition.returnType, false, !isStatic);
+ }
}
parameters = [];
for (var formal in definition.formals) {
@@ -1326,310 +1280,13 @@ class MethodMember extends Member {
parameters.add(param);
}
- if (!isLambda) {
+ if (!isLambda && declaringType.isClass) {
library._addMember(this);
}
}
-
- /** Overriden to ensure that type arguments aren't used in static methods. */
- Type resolveType(TypeReference node, bool typeErrors,
- [bool allowVoid = false]) {
- Type t = super.resolveType(node, typeErrors);
- if (isStatic && !isFactory && t is ParameterType) {
- world.error('using type parameter in static context.', node.span);
- }
- if (!allowVoid && t.isVoid) {
- world.error('"void" only allowed as return type', node.span);
- }
- return t;
- }
}
-class MemberSet {
- final String name;
- final List<Member> members;
- final String jsname;
- final bool isVar;
-
- MemberSet(Member member, [bool isVar=false]):
- name = member.name, members = [member], jsname = member.jsname,
- isVar = isVar;
-
- toString() => '$name:${members.length}';
-
- // TODO(jimhug): Still working towards the right logic for conflicts...
- bool get containsProperties() => members.some((m) => m is PropertyMember);
- bool get containsMethods() => members.some((m) => m is MethodMember);
-
-
- void add(Member member) => members.add(member);
-
- // TODO(jimhug): Always false, or is this needed?
- bool get isStatic() => members.length == 1 && members[0].isStatic;
- bool get isOperator() => members[0].isOperator;
-
- bool canInvoke(MethodGenerator context, Arguments args) =>
- members.some((m) => m.canInvoke(context, args));
-
- Value _makeError(Node node, Value target, String action) {
- if (!target.type.isVar) {
- world.warning('could not find applicable $action for "$name"', node.span);
- }
- return new Value(world.varType,
- '${target.code}.$jsname() /*no applicable $action*/', node.span);
- }
-
- bool _treatAsField;
- bool get treatAsField() {
- if (_treatAsField == null) {
- // If this is the global MemberSet from world, always bind dynamically.
- // Note: we need this for proper noSuchMethod and REPL behavior.
- _treatAsField = !isVar && (members.some((m) => m.requiresFieldSyntax)
- || members.every((m) => !m.requiresPropertySyntax));
-
- for (var member in members) {
- if (_treatAsField) {
- member.provideFieldSyntax();
- } else {
- member.providePropertySyntax();
- }
- }
- }
- return _treatAsField;
- }
-
- Value _get(MethodGenerator context, Node node, Value target,
- [bool isDynamic=false]) {
- // If this is the global MemberSet from world, always bind dynamically.
- // Note: we need this for proper noSuchMethod and REPL behavior.
- Value returnValue;
- if (members.length == 1 && !isVar) {
- return members[0]._get(context, node, target, isDynamic);
- }
-
-
- final targets = members.filter((m) => m.canGet);
- if (isVar) {
- targets.forEach((m) => m._get(context, node, target, isDynamic: true));
- returnValue = new Value(_foldTypes(targets), null, node.span);
- } else {
- if (members.length == 1) {
- return members[0]._get(context, node, target, isDynamic);
- } else if (targets.length == 1) {
- return targets[0]._get(context, node, target, isDynamic);
- }
-
- for (var member in targets) {
- final value = member._get(context, node, target, isDynamic:true);
- returnValue = _tryUnion(returnValue, value, node);
- }
- if (returnValue == null) {
- return _makeError(node, target, 'getter');
- }
- }
-
- if (returnValue.code == null) {
- if (treatAsField) {
- return new Value(returnValue.type, '${target.code}.$jsname',
- node.span);
- } else {
- return new Value(returnValue.type, '${target.code}.get\$$jsname()',
- node.span);
- }
- }
- return returnValue;
- }
-
- Value _set(MethodGenerator context, Node node, Value target, Value value,
- [bool isDynamic=false]) {
- // If this is the global MemberSet from world, always bind dynamically.
- // Note: we need this for proper noSuchMethod and REPL behavior.
- if (members.length == 1 && !isVar) {
- return members[0]._set(context, node, target, value, isDynamic);
- }
-
- Value returnValue;
- final targets = members.filter((m) => m.canSet);
- if (isVar) {
- targets.forEach((m) =>
- m._set(context, node, target, value, isDynamic: true));
- returnValue = new Value(_foldTypes(targets), null, node.span);
- } else {
- if (members.length == 1) {
- return members[0]._set(context, node, target, value, isDynamic);
- } else if (targets.length == 1) {
- return targets[0]._set(context, node, target, value, isDynamic);
- }
-
- for (var member in targets) {
- final res = member._set(context, node, target, value, isDynamic:true);
- returnValue = _tryUnion(returnValue, res, node);
- }
- if (returnValue == null) {
- return _makeError(node, target, 'setter');
- }
- }
-
- if (returnValue.code == null) {
- if (treatAsField) {
- return new Value(returnValue.type,
- '${target.code}.$jsname = ${value.code}', node.span);
- } else {
- return new Value(returnValue.type,
- '${target.code}.set\$$jsname(${value.code})', node.span);
- }
- }
- return returnValue;
- }
-
- Value invoke(MethodGenerator context, Node node, Value target,
- Arguments args, [bool isDynamic=false]) {
- // If this is the global MemberSet from world, always bind dynamically.
- // Note: we need this for proper noSuchMethod and REPL behavior.
- if (isVar && !isOperator) {
- return invokeOnVar(context, node, target, args);
- }
-
- if (members.length == 1 && !isVar) {
- return members[0].invoke(context, node, target, args, isDynamic);
- }
-
- final targets = members.filter((m) => m.canInvoke(context, args));
- if (targets.length == 1) {
- return targets[0].invoke(context, node, target, args, isDynamic);
- }
-
- Value returnValue = null;
- if (targets.length < 1000) {
- for (var member in targets) {
- final res = member.invoke(context, node, target, args, isDynamic:true);
- // TODO(jmesserly): If the code has different type checks, it will fail to
- // unify and go through a dynamic stub. Good so far. However, we'll end
- // up with a bogus unused temp generated (usually "var $0"). We need a way
- // to throw away temps when we throw away the code.
- returnValue = _tryUnion(returnValue, res, node);
- }
-
- if (returnValue == null) {
- return _makeError(node, target, 'method');
- }
- } else {
- returnValue = new Value(world.varType, null, node.span);
- }
-
- if (returnValue.code == null) {
- if (name == ':call') {
- // TODO(jmesserly): reconcile this with similar code in Value
- return target._varCall(context, node, args);
- } else if (isOperator) {
- // TODO(jmesserly): make operators less special.
- return invokeSpecial(target, args, returnValue.type);
- } else {
- return invokeOnVar(context, node, target, args);
- }
- }
-
- return returnValue;
- }
-
- Value invokeSpecial(Value target, Arguments args, Type returnType) {
- assert(name.startsWith(':'));
- assert(!args.hasNames);
- // TODO(jimhug): We need to do this a little bit more like get and set on
- // properties. We should check the set of members for something
- // like "requiresNativeIndexer" and "requiresDartIndexer" to
- // decide on a strategy.
-
- var argsString = args.getCode();
- // Most operator calls need to be emitted as function calls, so we don't
- // box numbers accidentally. Indexing is the exception.
- if (name == ':index' || name == ':setindex') {
- // TODO(jimhug): should not need this test both here and in invoke
- if (name == ':index') {
- world.gen.corejs.useIndex = true;
- } else if (name == ':setindex') {
- world.gen.corejs.useSetIndex = true;
- }
- return new Value(returnType, '${target.code}.$jsname($argsString)',
- target.span);
- } else {
- if (argsString.length > 0) argsString = ', $argsString';
- world.gen.corejs.useOperator(name);
- return new Value(returnType, '$jsname(${target.code}$argsString)',
- target.span);
- }
- }
-
- Value invokeOnVar(MethodGenerator context, Node node, Value target,
- Arguments args) {
- context.counters.dynamicMethodCalls++;
- var member = getVarMember(context, node, args);
- return member.invoke(context, node, target, args);
- }
-
- Value _union(Value x, Value y, Node node) {
- var result = _tryUnion(x, y, node);
- if (result.code == null) {
- world.internalError('mismatched code for $name (${x.code}, ${y.code})',
- node.span);
- }
- return result;
- }
-
- // TODO(jimhug): This is icky - but this whole class needs cleanup.
- Value _tryUnion(Value x, Value y, Node node) {
- if (x == null) return y;
- var type = Type.union(x.type, y.type);
- if (x.code == y.code) {
- if (type == x.type) {
- return x;
- } else if (x.isConst || y.isConst) {
- world.internalError("unexpected: union of const values ");
- } else {
- return Value.union(x, y);
- }
- } else {
- return new Value(type, null, node.span);
- }
- }
-
- dumpAllMembers() {
- for (var member in members) {
- world.warning('hard-multi $name on ${member.declaringType.name}',
- member.span);
- }
- }
-
- VarMember getVarMember(MethodGenerator context, Node node, Arguments args) {
- if (world.objectType.varStubs == null) {
- world.objectType.varStubs = {};
- }
-
- var stubName = _getCallStubName(name, args);
- var stub = world.objectType.varStubs[stubName];
- if (stub == null) {
- // Ensure that we're making stub with all possible members of this name.
- // We need this canonicalization step because only one VarMemberSet can
- // live on Object.prototype
- // TODO(jmesserly): this is ugly--we're throwing away type information!
- // The right solution is twofold:
- // 1. put stubs on a more precise type when possible
- // 2. merge VarMemberSets together if necessary
- final mset = context.findMembers(name).members;
-
- final targets = mset.filter((m) => m.canInvoke(context, args));
- stub = new VarMethodSet(name, stubName, targets, args,
- _foldTypes(targets));
- world.objectType.varStubs[stubName] = stub;
- }
- return stub;
- }
-
- Type _foldTypes(List<Member> targets) =>
- reduce(map(targets, (t) => t.returnType), Type.union, world.varType);
-}
-
/**
* A [FactoryMap] maps type names to a list of factory constructors.
* The constructors list is actually a map that maps factory names to
« 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