Chromium Code Reviews| Index: lib/src/codegen/js_codegen.dart |
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart |
| index 85b42aa56d42f9ca351932e4bee14d862c65b40a..02e2113d3ddef31f447c05d1bfe057fb8ab5ca56 100644 |
| --- a/lib/src/codegen/js_codegen.dart |
| +++ b/lib/src/codegen/js_codegen.dart |
| @@ -68,6 +68,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| ConstantEvaluator _constEvaluator; |
| + /// Map of fields / properties / methods on Object. |
| + Map<String, DartType> _objectMembers; |
| + |
| final _exports = new Set<String>(); |
| final _lazyFields = <VariableDeclaration>[]; |
| final _properties = <FunctionDeclaration>[]; |
| @@ -94,7 +97,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); |
| JSCodegenVisitor(this.options, this.rules, this.libraryInfo, |
| - this._extensionMethods, this._fieldsNeedingStorage); |
| + this._extensionMethods, this._fieldsNeedingStorage) { |
| + _objectMembers = getObjectMemberMap(rules.provider); |
|
Jennifer Messerly
2015/04/23 19:01:42
thought here, TypeRules is our type (src/checker/r
vsm
2015/04/23 20:35:55
Yeah, I suppose that's better than here.
Done.
|
| + } |
| LibraryElement get currentLibrary => libraryInfo.library; |
| TypeProvider get types => rules.provider; |
| @@ -185,10 +190,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| var code = _visit(child); |
| if (code != null) { |
| - if (_pendingStatements.isNotEmpty) { |
| - body.addAll(_pendingStatements); |
| - _pendingStatements.clear(); |
| - } |
| + _flushPendingStatements(body); |
| body.add(code); |
| } |
| } |
| @@ -1126,7 +1128,6 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| var element = type.element; |
| if (name == '' || lowerTypedef && type is FunctionType) { |
| if (type is FunctionType) { |
| - // TODO(vsm): Support all parameter types. |
| var returnType = type.returnType; |
| var parameterTypes = type.normalParameterTypes; |
| var optionalTypes = type.optionalParameterTypes; |
| @@ -1276,6 +1277,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| code, [_visit(node.methodName), _visit(node.argumentList)]); |
| } |
| + var type = getStaticType(target); |
| + var name = node.methodName.name; |
| + var memberName = _emitMemberName(name, type: type); |
| + |
| if (rules.isDynamicTarget(target)) { |
| code = 'dart.$DSEND(#, #, #)'; |
| } else if (rules.isDynamicCall(node.methodName)) { |
| @@ -1283,14 +1288,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| // class Foo { Function bar; } |
| // new Foo().bar(); // dynamic call |
| code = 'dart.$DCALL(#.#, #)'; |
| + } else if (_objectMembers.containsKey(name)) { |
|
Jennifer Messerly
2015/04/23 19:05:58
Is this only if `target` is nullable**? A test cas
vsm
2015/04/23 20:35:55
I added a check in. We need both checks as all ty
|
| + assert(_objectMembers[name] is FunctionType); |
| + // Object methods require a helper for null checks. |
| + return js.call('dart.#(#, #)', [ |
| + memberName, |
| + _visit(target), |
| + _visit(node.argumentList) |
| + ]); |
| } else { |
| code = '#.#(#)'; |
| } |
| - return js.call(code, [ |
| - _visit(target), |
| - _emitMemberName(node.methodName.name, type: getStaticType(target)), |
| - _visit(node.argumentList) |
| - ]); |
| + |
| + return js.call( |
| + code, [_visit(target), memberName, _visit(node.argumentList)]); |
| } |
| /// Emits code for the `JS(...)` builtin. |
| @@ -1442,9 +1453,20 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| return value != null ? value : new JS.LiteralNull(); |
| } |
| + void _flushPendingStatements(List<JS.Statement> body) { |
| + if (_pendingStatements.isNotEmpty) { |
| + body.addAll(_pendingStatements); |
| + _pendingStatements.clear(); |
| + } |
| + } |
| + |
| void _flushLazyFields(List<JS.Statement> body) { |
| var code = _emitLazyFields(_exportsVar, _lazyFields); |
| - if (code != null) body.add(code); |
| + if (code != null) { |
| + // Ensure symbols for private fields are defined. |
| + _flushPendingStatements(body); |
| + body.add(code); |
| + } |
| _lazyFields.clear(); |
| } |
| @@ -1455,14 +1477,16 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| var methods = []; |
| for (var node in fields) { |
| var name = node.name.name; |
| - methods.add(new JS.Method(_propertyName(name), |
| - js.call('function() { return #; }', _visit(node.initializer)), |
| + var element = node.element; |
| + var access = _emitMemberName(name, type: element.type, isStatic: true); |
| + methods.add(new JS.Method( |
| + access, js.call('function() { return #; }', _visit(node.initializer)), |
| isGetter: true)); |
| // TODO(jmesserly): use a dummy setter to indicate writable. |
| if (!node.isFinal) { |
| - methods.add(new JS.Method( |
| - _propertyName(name), js.call('function(_) {}'), isSetter: true)); |
| + methods.add( |
| + new JS.Method(access, js.call('function(_) {}'), isSetter: true)); |
| } |
| } |
| @@ -1876,10 +1900,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { |
| var member = memberId.staticElement; |
| if (member != null && member is MethodElement) { |
| // Tear-off methods: explicitly bind it. |
| - if (isStateless(target, target)) { |
| + if (isStateless(target, target) && |
| + !_objectMembers.containsKey(memberId.name)) { |
| return js.call('#.#.bind(#)', [_visit(target), name, _visit(target)]); |
| } |
| code = 'dart.bind(#, #)'; |
| + } else if (_objectMembers.containsKey(memberId.name)) { |
| + code = 'dart.#(#)'; |
| + return js.call(code, [name, _visit(target)]); |
| } else { |
| code = '#.#'; |
| } |