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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1701583003: Introduce _emitParameterReferences to avoid mixing params with param references. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 10 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 unified diff | Download patch
« no previous file with comments | « no previous file | test/codegen/destructuring.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library js_codegen; 5 library js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 1311 matching lines...) Expand 10 before | Expand all | Expand 10 after
1322 1322
1323 JS.Expression _defaultParamValue(FormalParameter param) { 1323 JS.Expression _defaultParamValue(FormalParameter param) {
1324 if (param is DefaultFormalParameter && param.defaultValue != null) { 1324 if (param is DefaultFormalParameter && param.defaultValue != null) {
1325 return _visit(param.defaultValue); 1325 return _visit(param.defaultValue);
1326 } else { 1326 } else {
1327 return new JS.LiteralNull(); 1327 return new JS.LiteralNull();
1328 } 1328 }
1329 } 1329 }
1330 1330
1331 JS.Fun _emitNativeFunctionBody( 1331 JS.Fun _emitNativeFunctionBody(
1332 List<JS.Parameter> params, MethodDeclaration node) { 1332 List<JS.Parameter> params, List<JS.Expression> paramRefs,
1333 MethodDeclaration node) {
1333 if (node.isStatic) { 1334 if (node.isStatic) {
1334 // TODO(vsm): Do we need to handle this case? 1335 // TODO(vsm): Do we need to handle this case?
1335 return null; 1336 return null;
1336 } 1337 }
1337 1338
1338 String name = node.name.name; 1339 String name = node.name.name;
1339 var annotation = findAnnotation(node.element, isJsName); 1340 var annotation = findAnnotation(node.element, isJsName);
1340 if (annotation != null) { 1341 if (annotation != null) {
1341 name = getConstantField(annotation, 'name', types.stringType) 1342 name = getConstantField(annotation, 'name', types.stringType)
1342 ?.toStringValue(); 1343 ?.toStringValue();
1343 } 1344 }
1344 if (node.isGetter) { 1345 if (node.isGetter) {
1345 return new JS.Fun(params, js.statement('{ return this.#; }', [name])); 1346 return new JS.Fun(params, js.statement('{ return this.#; }', [name]));
1346 } else if (node.isSetter) { 1347 } else if (node.isSetter) {
1347 return new JS.Fun( 1348 return new JS.Fun(
1348 params, js.statement('{ this.# = #; }', [name, params.last])); 1349 params, js.statement('{ this.# = #; }', [name, paramRefs.last]));
1349 } else { 1350 } else {
1350 return new JS.Fun( 1351 return new JS.Fun(
1351 params, js.statement('{ return this.#(#); }', [name, params])); 1352 params, js.statement('{ return this.#(#); }', [name, paramRefs]));
1352 } 1353 }
1353 } 1354 }
1354 1355
1355 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) { 1356 JS.Method _emitMethodDeclaration(DartType type, MethodDeclaration node) {
1356 if (node.isAbstract) { 1357 if (node.isAbstract) {
1357 return null; 1358 return null;
1358 } 1359 }
1359 1360
1360 var params = _visit(node.parameters) as List<JS.Parameter>; 1361 var params = _visit(node.parameters) as List<JS.Parameter>;
1361 if (params == null) params = <JS.Parameter>[]; 1362 if (params == null) params = <JS.Parameter>[];
1363 var paramRefs = _emitParameterReferences(node.parameters);
1362 1364
1363 JS.Fun fn; 1365 JS.Fun fn;
1364 if (_externalOrNative(node)) { 1366 if (_externalOrNative(node)) {
1365 fn = _emitNativeFunctionBody(params, node); 1367 fn = _emitNativeFunctionBody(params, paramRefs, node);
1366 // TODO(vsm): Remove if / when we handle the static case above. 1368 // TODO(vsm): Remove if / when we handle the static case above.
1367 if (fn == null) return null; 1369 if (fn == null) return null;
1368 } else { 1370 } else {
1369 var typeParams = _emitTypeParams(node.element).toList(); 1371 var typeParams = _emitTypeParams(node.element).toList();
1370 var returnType = emitTypeRef(node.element.returnType); 1372 var returnType = emitTypeRef(node.element.returnType);
1371 fn = _emitFunctionBody(params, node.body, typeParams, returnType); 1373 fn = _emitFunctionBody(
1374 params, paramRefs, node.body, typeParams, returnType);
1372 } 1375 }
1373 1376
1374 if (node.operatorKeyword != null && 1377 if (node.operatorKeyword != null &&
1375 node.name.name == '[]=' && 1378 node.name.name == '[]=' &&
1376 params.isNotEmpty) { 1379 params.isNotEmpty) {
1377 // []= methods need to return the value. We could also address this at 1380 // []= methods need to return the value. We could also address this at
1378 // call sites, but it's cleaner to instead transform the operator method. 1381 // call sites, but it's cleaner to instead transform the operator method.
1379 var returnValue = new JS.Return(params.last); 1382 var returnValue = new JS.Return(params.last);
1380 var body = fn.body; 1383 var body = fn.body;
1381 if (JS.Return.foundIn(fn)) { 1384 if (JS.Return.foundIn(fn)) {
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
1540 @override 1543 @override
1541 JS.Expression visitFunctionExpression(FunctionExpression node) { 1544 JS.Expression visitFunctionExpression(FunctionExpression node) {
1542 var params = _visit(node.parameters) as List<JS.Parameter>; 1545 var params = _visit(node.parameters) as List<JS.Parameter>;
1543 if (params == null) params = <JS.Parameter>[]; 1546 if (params == null) params = <JS.Parameter>[];
1544 1547
1545 var parent = node.parent; 1548 var parent = node.parent;
1546 var inStmt = parent.parent is FunctionDeclarationStatement; 1549 var inStmt = parent.parent is FunctionDeclarationStatement;
1547 var typeParams = _emitTypeParams(node.element).toList(); 1550 var typeParams = _emitTypeParams(node.element).toList();
1548 var returnType = emitTypeRef(node.element.returnType); 1551 var returnType = emitTypeRef(node.element.returnType);
1549 if (parent is FunctionDeclaration) { 1552 if (parent is FunctionDeclaration) {
1550 return _emitFunctionBody(params, node.body, typeParams, returnType); 1553 var paramRefs = _emitParameterReferences(node.parameters);
1554 return _emitFunctionBody(
1555 params, paramRefs, node.body, typeParams, returnType);
1551 } else { 1556 } else {
1552 // Chrome Canary does not accept default values with destructuring in 1557 // Chrome Canary does not accept default values with destructuring in
1553 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them 1558 // arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
1554 // with regular functions (e.g. `function({a} = {}) { return 1 }`). 1559 // with regular functions (e.g. `function({a} = {}) { return 1 }`).
1555 // Note that Firefox accepts both syntaxes just fine. 1560 // Note that Firefox accepts both syntaxes just fine.
1556 // TODO(ochafik): Simplify this code when Chrome Canary catches up. 1561 // TODO(ochafik): Simplify this code when Chrome Canary catches up.
1557 var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam); 1562 var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam);
1558 1563
1559 JS.Node jsBody; 1564 JS.Node jsBody;
1560 var body = node.body; 1565 var body = node.body;
1561 if (body.isGenerator || body.isAsynchronous) { 1566 if (body.isGenerator || body.isAsynchronous) {
1562 jsBody = _emitGeneratorFunctionBody(params, body, returnType); 1567 var paramRefs = _emitParameterReferences(node.parameters);
1568 jsBody = _emitGeneratorFunctionBody(
1569 params, paramRefs, body, returnType);
1563 } else if (body is ExpressionFunctionBody) { 1570 } else if (body is ExpressionFunctionBody) {
1564 jsBody = _visit(body.expression); 1571 jsBody = _visit(body.expression);
1565 } else { 1572 } else {
1566 jsBody = _visit(body); 1573 jsBody = _visit(body);
1567 } 1574 }
1568 if (jsBody is JS.Expression && !canUseArrowFun) { 1575 if (jsBody is JS.Expression && !canUseArrowFun) {
1569 jsBody = js.statement("{ return #; }", [jsBody]); 1576 jsBody = js.statement("{ return #; }", [jsBody]);
1570 } 1577 }
1571 var clos = canUseArrowFun 1578 var clos = canUseArrowFun
1572 ? new JS.ArrowFun(params, jsBody, 1579 ? new JS.ArrowFun(params, jsBody,
1573 typeParams: typeParams, returnType: returnType) 1580 typeParams: typeParams, returnType: returnType)
1574 : new JS.Fun(params, jsBody, 1581 : new JS.Fun(params, jsBody,
1575 typeParams: typeParams, returnType: returnType); 1582 typeParams: typeParams, returnType: returnType);
1576 if (!inStmt) { 1583 if (!inStmt) {
1577 var type = getStaticType(node); 1584 var type = getStaticType(node);
1578 return _emitFunctionTagged(clos, type, 1585 return _emitFunctionTagged(clos, type,
1579 topLevel: _executesAtTopLevel(node)); 1586 topLevel: _executesAtTopLevel(node));
1580 } 1587 }
1581 return clos; 1588 return clos;
1582 } 1589 }
1583 } 1590 }
1584 1591
1585 JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body, 1592 JS.Fun _emitFunctionBody(List<JS.Parameter> params,
1593 List<JS.Expression> paramRefs, FunctionBody body,
1586 List<JS.Identifier> typeParams, JS.TypeRef returnType) { 1594 List<JS.Identifier> typeParams, JS.TypeRef returnType) {
1587 // sync*, async, async* 1595 // sync*, async, async*
1588 if (body.isAsynchronous || body.isGenerator) { 1596 if (body.isAsynchronous || body.isGenerator) {
1597 // TODO(ochafik): Refine params: we don't need default values in the
1598 // nested function, so we'd need to generate a custom, simpler params
1599 // list here.
1589 return new JS.Fun( 1600 return new JS.Fun(
1590 params, 1601 params,
1591 js.statement('{ return #; }', 1602 js.statement('{ return #; }', [
1592 [_emitGeneratorFunctionBody(params, body, returnType)]), 1603 _emitGeneratorFunctionBody(params, paramRefs, body, returnType)
1604 ]),
1593 returnType: returnType); 1605 returnType: returnType);
1594 } 1606 }
1595 // normal function (sync) 1607 // normal function (sync)
1596 return new JS.Fun(params, _visit(body), 1608 return new JS.Fun(params, _visit(body),
1597 typeParams: typeParams, returnType: returnType); 1609 typeParams: typeParams, returnType: returnType);
1598 } 1610 }
1599 1611
1600 JS.Expression _emitGeneratorFunctionBody( 1612 JS.Expression _emitGeneratorFunctionBody(
1601 List<JS.Parameter> params, FunctionBody body, JS.TypeRef returnType) { 1613 List<JS.Parameter> params, List<JS.Expression> paramRefs,
1614 FunctionBody body, JS.TypeRef returnType) {
1602 var kind = body.isSynchronous ? 'sync' : 'async'; 1615 var kind = body.isSynchronous ? 'sync' : 'async';
1603 if (body.isGenerator) kind += 'Star'; 1616 if (body.isGenerator) kind += 'Star';
1604 1617
1605 // Transforms `sync*` `async` and `async*` function bodies 1618 // Transforms `sync*` `async` and `async*` function bodies
1606 // using ES6 generators. 1619 // using ES6 generators.
1607 // 1620 //
1608 // `sync*` wraps a generator in a Dart Iterable<T>: 1621 // `sync*` wraps a generator in a Dart Iterable<T>:
1609 // 1622 //
1610 // function name(<args>) { 1623 // function name(<args>) {
1611 // return dart.syncStar(function*(<args>) { 1624 // return dart.syncStar(function*(<args>) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1645 JS.Expression gen = new JS.Fun(jsParams, _visit(body), 1658 JS.Expression gen = new JS.Fun(jsParams, _visit(body),
1646 isGenerator: true, returnType: returnType); 1659 isGenerator: true, returnType: returnType);
1647 if (JS.This.foundIn(gen)) { 1660 if (JS.This.foundIn(gen)) {
1648 gen = js.call('#.bind(this)', gen); 1661 gen = js.call('#.bind(this)', gen);
1649 } 1662 }
1650 _asyncStarController = savedController; 1663 _asyncStarController = savedController;
1651 1664
1652 var T = _emitTypeName(_getExpectedReturnType(body)); 1665 var T = _emitTypeName(_getExpectedReturnType(body));
1653 return js.call('dart.#(#)', [ 1666 return js.call('dart.#(#)', [
1654 kind, 1667 kind,
1655 [gen, T]..addAll(params) 1668 [gen, T]..addAll(paramRefs)
1656 ]); 1669 ]);
1657 } 1670 }
1658 1671
1659 @override 1672 @override
1660 JS.Statement visitFunctionDeclarationStatement( 1673 JS.Statement visitFunctionDeclarationStatement(
1661 FunctionDeclarationStatement node) { 1674 FunctionDeclarationStatement node) {
1662 var func = node.functionDeclaration; 1675 var func = node.functionDeclaration;
1663 if (func.isGetter || func.isSetter) { 1676 if (func.isGetter || func.isSetter) {
1664 return js.comment('Unimplemented function get/set statement: $node'); 1677 return js.comment('Unimplemented function get/set statement: $node');
1665 } 1678 }
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after
2157 _propertyName(node.name.label.name), _visit(node.expression)); 2170 _propertyName(node.name.label.name), _visit(node.expression));
2158 } 2171 }
2159 2172
2160 bool _isNamedParam(FormalParameter param) => 2173 bool _isNamedParam(FormalParameter param) =>
2161 param.kind == ParameterKind.NAMED; 2174 param.kind == ParameterKind.NAMED;
2162 2175
2163 @override 2176 @override
2164 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) => 2177 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) =>
2165 _emitFormalParameterList(node); 2178 _emitFormalParameterList(node);
2166 2179
2180 // TODO(ochafik): Decouple Parameter from Identifier.
2181 List<JS.Expression> _emitParameterReferences(FormalParameterList node) =>
2182 node == null
2183 ? <JS.Expression>[]
2184 : _emitFormalParameterList(node, allowDestructuring: false)
2185 .map((JS.Parameter p) {
2186 if (p is JS.RestParameter) return new JS.Spread(p.parameter);
2187 return p as JS.Identifier;
2188 })
2189 .toList();
2190
2167 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, 2191 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node,
2168 {bool allowDestructuring: true}) { 2192 {bool allowDestructuring: true}) {
2169 var result = <JS.Parameter>[]; 2193 var result = <JS.Parameter>[];
2170 2194
2171 var namedVars = <JS.DestructuredVariable>[]; 2195 var namedVars = <JS.DestructuredVariable>[];
2172 var destructure = allowDestructuring && options.destructureNamedParams; 2196 var destructure = allowDestructuring && options.destructureNamedParams;
2173 var hasNamedArgsConflictingWithObjectProperties = false; 2197 var hasNamedArgsConflictingWithObjectProperties = false;
2174 var needsOpts = false; 2198 var needsOpts = false;
2175 2199
2176 for (FormalParameter param in node.parameters) { 2200 for (FormalParameter param in node.parameters) {
(...skipping 14 matching lines...) Expand all
2191 namedVars.add(new JS.DestructuredVariable( 2215 namedVars.add(new JS.DestructuredVariable(
2192 name: name, 2216 name: name,
2193 structure: structure, 2217 structure: structure,
2194 defaultValue: _defaultParamValue(param))); 2218 defaultValue: _defaultParamValue(param)));
2195 } else { 2219 } else {
2196 needsOpts = true; 2220 needsOpts = true;
2197 } 2221 }
2198 } else { 2222 } else {
2199 var jsParam = _visit(param); 2223 var jsParam = _visit(param);
2200 result.add( 2224 result.add(
2201 param is DefaultFormalParameter && options.destructureNamedParams 2225 param is DefaultFormalParameter && destructure
2202 ? new JS.DestructuredVariable( 2226 ? new JS.DestructuredVariable(
2203 name: jsParam, defaultValue: _defaultParamValue(param)) 2227 name: jsParam, defaultValue: _defaultParamValue(param))
2204 : jsParam); 2228 : jsParam);
2205 } 2229 }
2206 } 2230 }
2207 2231
2208 if (needsOpts) { 2232 if (needsOpts) {
2209 result.add(_namedArgTemp); 2233 result.add(_namedArgTemp);
2210 } else if (namedVars.isNotEmpty) { 2234 } else if (namedVars.isNotEmpty) {
2211 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so 2235 // Note: `var {valueOf} = {}` extracts `Object.prototype.valueOf`, so
(...skipping 1543 matching lines...) Expand 10 before | Expand all | Expand 10 after
3755 3779
3756 /// A special kind of element created by the compiler, signifying a temporary 3780 /// A special kind of element created by the compiler, signifying a temporary
3757 /// variable. These objects use instance equality, and should be shared 3781 /// variable. These objects use instance equality, and should be shared
3758 /// everywhere in the tree where they are treated as the same variable. 3782 /// everywhere in the tree where they are treated as the same variable.
3759 class TemporaryVariableElement extends LocalVariableElementImpl { 3783 class TemporaryVariableElement extends LocalVariableElementImpl {
3760 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3784 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3761 3785
3762 int get hashCode => identityHashCode(this); 3786 int get hashCode => identityHashCode(this);
3763 bool operator ==(Object other) => identical(this, other); 3787 bool operator ==(Object other) => identical(this, other);
3764 } 3788 }
OLDNEW
« no previous file with comments | « no previous file | test/codegen/destructuring.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698