| Index: lib/src/codegen/js_codegen.dart
|
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
|
| index 5e1b8a6ca2282f5a9905ca318051bd8d98e33889..9879bd42cd72f1e394626f7626358fdd7f062d68 100644
|
| --- a/lib/src/codegen/js_codegen.dart
|
| +++ b/lib/src/codegen/js_codegen.dart
|
| @@ -37,6 +37,7 @@ import 'js_metalet.dart' as JS;
|
| import 'js_module_item_order.dart';
|
| import 'js_printer.dart' show writeJsLibrary;
|
| import 'side_effect_analysis.dart';
|
| +import 'package:collection/equality.dart';
|
|
|
| // Various dynamic helpers we call.
|
| // If renaming these, make sure to check other places like the
|
| @@ -50,6 +51,8 @@ const DSETINDEX = 'dsetindex';
|
| const DCALL = 'dcall';
|
| const DSEND = 'dsend';
|
|
|
| +const ListEquality _listEquality = const ListEquality();
|
| +
|
| class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| final AbstractCompiler compiler;
|
| final CodegenOptions options;
|
| @@ -104,6 +107,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| /// The default value of the module object. See [visitLibraryDirective].
|
| String _jsModuleValue;
|
|
|
| + bool _isDartUtils;
|
| +
|
| Map<String, DartType> _objectMembers;
|
|
|
| JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary,
|
| @@ -117,6 +122,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var src = context.sourceFactory.forUri('dart:_interceptors');
|
| var interceptors = context.computeLibraryElement(src);
|
| _jsArray = interceptors.getType('JSArray');
|
| + _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils';
|
|
|
| _objectMembers = getObjectMemberMap(types);
|
| }
|
| @@ -196,7 +202,19 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| list.add(js.string(compiler.getModuleName(library.source.uri), "'"));
|
| };
|
|
|
| - var imports = <JS.Expression>[js.string('dart/_runtime')];
|
| + var needsDartRuntime = !_isDartUtils;
|
| +
|
| + var imports = <JS.Expression>[];
|
| + var moduleStatements = <JS.Statement>[];
|
| + if (needsDartRuntime) {
|
| + imports.add(js.string('dart/_runtime'));
|
| +
|
| + var dartxImport =
|
| + js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
|
| + moduleStatements.add(dartxImport);
|
| + }
|
| + moduleStatements.addAll(_moduleItems);
|
| +
|
| _imports.forEach((library, temp) {
|
| if (_loader.libraryIsLoaded(library)) {
|
| processImport(library, temp, imports);
|
| @@ -210,11 +228,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| }
|
| });
|
|
|
| - var dartxImport =
|
| - js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
|
| -
|
| - var module = js.call("function(#) { 'use strict'; #; #; }",
|
| - [params, dartxImport, _moduleItems]);
|
| + var module =
|
| + js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
|
|
|
| var moduleDef = js.statement("dart_library.library(#, #, #, #, #)", [
|
| js.string(jsPath, "'"),
|
| @@ -289,7 +304,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| args.add(new JS.ArrayInitializer(shownNames));
|
| args.add(new JS.ArrayInitializer(hiddenNames));
|
| }
|
| - _moduleItems.add(js.statement('dart.export(#);', [args]));
|
| + _moduleItems.add(js.statement('dart.export_(#);', [args]));
|
| }
|
|
|
| JS.Identifier _initSymbol(JS.Identifier id) {
|
| @@ -1285,17 +1300,69 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
|
|
| var name = node.name.name;
|
|
|
| + var fn = _visit(node.functionExpression);
|
| + bool needsTagging = true;
|
| +
|
| + if (currentLibrary.source.isInSystemLibrary &&
|
| + _isInlineJSFunction(node.functionExpression)) {
|
| + fn = _simplifyPassThroughArrowFunCallBody(fn);
|
| + needsTagging = !_isDartUtils;
|
| + }
|
| +
|
| var id = new JS.Identifier(name);
|
| - body.add(annotate(
|
| - new JS.FunctionDeclaration(id, _visit(node.functionExpression)),
|
| - node.element));
|
| - body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
|
| - .toStatement());
|
| + body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element));
|
| + if (needsTagging) {
|
| + body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
|
| + .toStatement());
|
| + }
|
|
|
| if (isPublic(name)) _addExport(name);
|
| return _statement(body);
|
| }
|
|
|
| + bool _isInlineJSFunction(FunctionExpression functionExpression) {
|
| + bool isJsInvocation(Expression expr) =>
|
| + expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
|
| +
|
| + var body = functionExpression.body;
|
| + if (body is ExpressionFunctionBody) {
|
| + return isJsInvocation(body.expression);
|
| + } else if (body is BlockFunctionBody) {
|
| + if (body.block.statements.length == 1) {
|
| + var stat = body.block.statements.single;
|
| + if (stat is ReturnStatement) {
|
| + return isJsInvocation(stat.expression);
|
| + }
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + // Simplify `(args) => ((x, y) => { ... })(x, y)` to `(args) => { ... }`.
|
| + // Note: we don't check if the top-level args match the ones passed through
|
| + // the arrow function, which allows silently passing args through to the
|
| + // body (which only works if we don't do weird renamings of Dart params).
|
| + JS.Fun _simplifyPassThroughArrowFunCallBody(JS.Fun fn) {
|
| + String getIdent(JS.Node node) => node is JS.Identifier ? node.name : null;
|
| + List<String> getIdents(List params) =>
|
| + params.map(getIdent).toList(growable: false);
|
| +
|
| + if (fn.body is JS.Block && fn.body.statements.length == 1) {
|
| + var stat = fn.body.statements.single;
|
| + if (stat is JS.Return && stat.value is JS.Call) {
|
| + JS.Call call = stat.value;
|
| + if (call.target is JS.ArrowFun) {
|
| + var passedArgs = getIdents(call.arguments);
|
| + JS.ArrowFun innerFun = call.target;
|
| + if (_listEquality.equals(getIdents(innerFun.params), passedArgs)) {
|
| + return new JS.Fun(fn.params, innerFun.body);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return fn;
|
| + }
|
| +
|
| JS.Method _emitTopLevelProperty(FunctionDeclaration node) {
|
| var name = node.name.name;
|
| return annotate(
|
|
|