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

Unified Diff: lib/src/codegen/js_codegen.dart

Issue 1676463002: Type annotations instead of closure comments. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: merged master 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/closure/closure_annotator.dart ('k') | lib/src/codegen/js_names.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 9650a36306b195dc94a98398d8b63c6e0951ea0b..005808114b65eefe3e35961473b15a75dcb16424 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+library js_codegen;
+
import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
@@ -41,6 +43,8 @@ import 'module_builder.dart';
import 'nullability_inferrer.dart';
import 'side_effect_analysis.dart';
+part 'js_typeref_codegen.dart';
+
// Various dynamic helpers we call.
// If renaming these, make sure to check other places like the
// _runtime.js file and comments.
@@ -53,7 +57,8 @@ const DSETINDEX = 'dsetindex';
const DCALL = 'dcall';
const DSEND = 'dsend';
-class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
+class JSCodegenVisitor extends GeneralizingAstVisitor
+ with ClosureAnnotator, JsTypeRefCodegen {
final AbstractCompiler compiler;
final CodegenOptions options;
final LibraryElement currentLibrary;
@@ -348,12 +353,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var type = element.type;
var name = element.name;
- var fnType = annotateTypeDef(
+ var fnType = annotate(
js.statement('const # = dart.typedef(#, () => #);', [
name,
js.string(name, "'"),
_emitTypeName(type, lowerTypedef: true)
]),
+ node,
node.element);
return _finishClassDef(type, fnType);
@@ -424,7 +430,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
}
var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
- _classHeritage(classElem), _emitClassMethods(node, ctors, fields));
+ _classHeritage(classElem), _emitClassMethods(node, ctors, fields),
+ typeParams: _emitTypeParams(classElem).toList(),
+ fields:
+ _emitFieldDeclarations(classElem, fields, staticFields).toList());
String jsPeerName;
var jsPeer = findAnnotation(classElem, isJsPeerInterface);
@@ -457,6 +466,39 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
return result;
}
+ Iterable<JS.Identifier> _emitTypeParams(TypeParameterizedElement e) sync* {
+ if (!options.closure) return;
+ for (var typeParam in e.typeParameters) {
+ yield new JS.Identifier(typeParam.name);
+ }
+ }
+
+ /// Emit field declarations for TypeScript & Closure's ES6_TYPED
+ /// (e.g. `class Foo { i: string; }`)
+ Iterable<JS.VariableDeclarationList> _emitFieldDeclarations(
+ ClassElement classElem,
+ List<FieldDeclaration> fields,
+ List<FieldDeclaration> staticFields) sync* {
+ if (!options.closure) return;
+
+ makeInitialization(VariableDeclaration decl) =>
+ new JS.VariableInitialization(
+ new JS.Identifier(
+ // TODO(ochafik): use a refactored _emitMemberName instead.
+ decl.name.name,
+ type: emitTypeRef(decl.element.type)),
+ null);
+
+ for (var field in fields) {
+ yield new JS.VariableDeclarationList(
+ null, field.fields.variables.map(makeInitialization).toList());
+ }
+ for (var field in staticFields) {
+ yield new JS.VariableDeclarationList(
+ 'static', field.fields.variables.map(makeInitialization).toList());
+ }
+ }
+
@override
JS.Statement visitEnumDeclaration(EnumDeclaration node) {
var element = node.element;
@@ -689,8 +731,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var superVar = new JS.TemporaryId(cls.name.name + r'$super');
return _statement([
js.statement('const # = #;', [superVar, cls.heritage]),
- new JS.ClassDeclaration(
- new JS.ClassExpression(cls.name, superVar, cls.methods))
+ new JS.ClassDeclaration(new JS.ClassExpression(
+ cls.name, superVar, cls.methods,
+ typeParams: cls.typeParams, fields: cls.fields))
]);
}
return new JS.ClassDeclaration(cls);
@@ -935,8 +978,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
];
}
var name = _constructorName(node.element.unnamedConstructor);
- return annotateDefaultConstructor(
+ return annotate(
new JS.Method(name, js.call('function() { #; }', body) as JS.Fun),
+ node,
node.element);
}
@@ -945,6 +989,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (_externalOrNative(node)) return null;
var name = _constructorName(node.element);
+ var returnType = emitTypeRef(node.element.enclosingElement.type);
// Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz;
var redirect = node.redirectedConstructor;
@@ -956,11 +1001,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var params =
_emitFormalParameterList(node.parameters, allowDestructuring: false);
- var fun = js.call('function(#) { return $newKeyword #(#); }',
- [params, _visit(redirect), params]) as JS.Fun;
+ var fun = new JS.Fun(
+ params,
+ js.statement(
+ '{ return $newKeyword #(#); }', [_visit(redirect), params]),
+ returnType: returnType);
return annotate(
- new JS.Method(name, fun, isStatic: true)..sourceInformation = node,
- node.element);
+ new JS.Method(name, fun, isStatic: true), node, node.element);
}
// For const constructors we need to ensure default values are
@@ -976,10 +1023,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var init = _emitArgumentInitializers(node, constructor: true);
if (init != null) body.add(init);
body.add(_visit(node.body));
- var fun = new JS.Fun(params, new JS.Block(body));
+ var fun = new JS.Fun(params, new JS.Block(body), returnType: returnType);
return annotate(
- new JS.Method(name, fun, isStatic: true)..sourceInformation = node,
- node.element);
+ new JS.Method(name, fun, isStatic: true), node, node.element);
}
// Code generation for Object's constructor.
@@ -1015,7 +1061,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// this allows use of `super` for instance methods/properties.
// It also avoids V8 restrictions on `super` in default constructors.
return annotate(
- new JS.Method(name, new JS.Fun(params, body))..sourceInformation = node,
+ new JS.Method(name, new JS.Fun(params, body, returnType: returnType)),
+ node,
node.element);
}
@@ -1112,7 +1159,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var name = _constructorName(superCtor);
var args = node != null ? _visit(node.argumentList) : [];
- return js.statement('super.#(#);', [name, args])..sourceInformation = node;
+ return annotate(js.statement('super.#(#);', [name, args]), node);
}
bool _shouldCallUnnamedSuperCtor(ClassElement e) {
@@ -1164,7 +1211,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
for (var p in ctor.parameters.parameters) {
var element = p.element;
if (element is FieldFormalParameterElement) {
- fields[element.field] = _visit(p);
+ fields[element.field] = _emitFormalParameter(p, allowType: false);
}
}
@@ -1222,7 +1269,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var body = <JS.Statement>[];
for (var param in parameters.parameters) {
- var jsParam = _visit(param.identifier);
+ var jsParam = _emitSimpleIdentifier(param.identifier, allowType: false);
if (param.kind == ParameterKind.NAMED) {
if (!options.destructureNamedParams) {
@@ -1281,7 +1328,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var params = _visit(node.parameters) as List<JS.Parameter>;
if (params == null) params = <JS.Parameter>[];
- JS.Fun fn = _emitFunctionBody(params, node.body);
+ var typeParams = _emitTypeParams(node.element).toList();
+ var returnType = emitTypeRef(node.element.returnType);
+ JS.Fun fn = _emitFunctionBody(params, node.body, typeParams, returnType);
if (node.operatorKeyword != null &&
node.name.name == '[]=' &&
params.isNotEmpty) {
@@ -1297,8 +1346,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
body = new JS.Call(new JS.ArrowFun([], fn.body), []).toStatement();
}
// Rewrite the function to include the return.
- fn = new JS.Fun(fn.params, new JS.Block([body, returnValue]))
- ..sourceInformation = fn.sourceInformation;
+ fn = new JS.Fun(fn.params, new JS.Block([body, returnValue]),
+ typeParams: fn.typeParams,
+ returnType: fn.returnType)..sourceInformation = fn.sourceInformation;
}
return annotate(
@@ -1306,6 +1356,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
isGetter: node.isGetter,
isSetter: node.isSetter,
isStatic: node.isStatic),
+ node,
node.element);
}
@@ -1313,7 +1364,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
/// the SDK), or `null` if there's none. This is used to control the name
/// under which functions are compiled and exported.
String _getJSExportName(Element e) {
- if (!currentLibrary.source.isInSystemLibrary) {
+ if (!e.source.isInSystemLibrary) {
return null;
}
var jsName = findAnnotation(e, isJSExportNameAnnotation);
@@ -1345,7 +1396,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
}
var id = new JS.Identifier(name);
- body.add(annotate(new JS.FunctionDeclaration(id, fn), node.element));
+ body.add(annotate(new JS.FunctionDeclaration(id, fn), node, node.element));
if (!_isDartRuntime) {
body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
.toStatement());
@@ -1386,7 +1437,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (call.target is JS.ArrowFun && call.arguments.isEmpty) {
JS.ArrowFun innerFun = call.target;
if (innerFun.params.isEmpty) {
- return new JS.Fun(fn.params, innerFun.body);
+ return new JS.Fun(fn.params, innerFun.body,
+ typeParams: fn.typeParams, returnType: fn.returnType);
}
}
}
@@ -1399,6 +1451,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
return annotate(
new JS.Method(_propertyName(name), _visit(node.functionExpression),
isGetter: node.isGetter, isSetter: node.isSetter),
+ node,
node.element);
}
@@ -1451,8 +1504,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var parent = node.parent;
var inStmt = parent.parent is FunctionDeclarationStatement;
+ var typeParams = _emitTypeParams(node.element).toList();
+ var returnType = emitTypeRef(node.element.returnType);
if (parent is FunctionDeclaration) {
- return _emitFunctionBody(params, node.body);
+ return _emitFunctionBody(params, node.body, typeParams, returnType);
} else {
// Chrome Canary does not accept default values with destructuring in
// arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
@@ -1461,18 +1516,23 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
// TODO(ochafik): Simplify this code when Chrome Canary catches up.
var canUseArrowFun = !node.parameters.parameters.any(_isNamedParam);
- String code = canUseArrowFun ? '(#) => #' : 'function(#) { return # }';
JS.Node jsBody;
var body = node.body;
if (body.isGenerator || body.isAsynchronous) {
- jsBody = _emitGeneratorFunctionBody(params, body);
+ jsBody = _emitGeneratorFunctionBody(params, body, returnType);
} else if (body is ExpressionFunctionBody) {
jsBody = _visit(body.expression);
} else {
- code = canUseArrowFun ? '(#) => { #; }' : 'function(#) { #; }';
jsBody = _visit(body);
}
- var clos = js.call(code, [params, jsBody]);
+ if (jsBody is JS.Expression && !canUseArrowFun) {
+ jsBody = js.statement("{ return #; }", [jsBody]);
+ }
+ var clos = canUseArrowFun
+ ? new JS.ArrowFun(params, jsBody,
+ typeParams: typeParams, returnType: returnType)
+ : new JS.Fun(params, jsBody,
+ typeParams: typeParams, returnType: returnType);
if (!inStmt) {
var type = getStaticType(node);
return _emitFunctionTagged(clos, type,
@@ -1482,20 +1542,23 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
}
}
- JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body) {
+ JS.Fun _emitFunctionBody(List<JS.Parameter> params, FunctionBody body,
+ List<JS.Identifier> typeParams, JS.TypeRef returnType) {
// sync*, async, async*
if (body.isAsynchronous || body.isGenerator) {
return new JS.Fun(
params,
- js.statement(
- '{ return #; }', [_emitGeneratorFunctionBody(params, body)]));
+ js.statement('{ return #; }',
+ [_emitGeneratorFunctionBody(params, body, returnType)]),
+ returnType: returnType);
}
// normal function (sync)
- return new JS.Fun(params, _visit(body));
+ return new JS.Fun(params, _visit(body),
+ typeParams: typeParams, returnType: returnType);
}
JS.Expression _emitGeneratorFunctionBody(
- List<JS.Parameter> params, FunctionBody body) {
+ List<JS.Parameter> params, FunctionBody body, JS.TypeRef returnType) {
var kind = body.isSynchronous ? 'sync' : 'async';
if (body.isGenerator) kind += 'Star';
@@ -1539,7 +1602,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
_asyncStarController = null;
jsParams = params;
}
- JS.Expression gen = new JS.Fun(jsParams, _visit(body), isGenerator: true);
+ JS.Expression gen = new JS.Fun(jsParams, _visit(body),
+ isGenerator: true, returnType: returnType);
if (JS.This.foundIn(gen)) {
gen = js.call('#.bind(this)', gen);
}
@@ -1569,7 +1633,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
} else {
declareFn = new JS.FunctionDeclaration(name, fn);
}
- declareFn = annotate(declareFn, node.functionDeclaration.element);
+ declareFn = annotate(declareFn, node, node.functionDeclaration.element);
return new JS.Block([
declareFn,
@@ -1577,10 +1641,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
]);
}
+ @override
+ JS.Expression visitSimpleIdentifier(SimpleIdentifier node) =>
+ _emitSimpleIdentifier(node);
+
/// Writes a simple identifier. This can handle implicit `this` as well as
/// going through the qualified library name if necessary.
- @override
- JS.Expression visitSimpleIdentifier(SimpleIdentifier node) {
+ JS.Expression _emitSimpleIdentifier(SimpleIdentifier node,
+ {bool allowType: false}) {
var accessor = node.staticElement;
if (accessor == null) {
return js.commentExpression(
@@ -1649,7 +1717,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
}
}
- return new JS.Identifier(name);
+ return annotate(
+ new JS.Identifier(name,
+ type: allowType ? emitTypeRef(node.bestType) : null),
+ node);
}
JS.TemporaryId _getTemp(Element key, String name) =>
@@ -2105,6 +2176,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
: js.call('{}');
result.add(new JS.DestructuredVariable(
structure: new JS.ObjectBindingPattern(namedVars),
+ type: emitNamedParamsArgType(node.parameterElements),
defaultValue: defaultOpts));
}
return result;
@@ -2236,7 +2308,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
return _emitTopLevelField(node);
}
- var name = new JS.Identifier(node.name.name);
+ var name =
+ new JS.Identifier(node.name.name, type: emitTypeRef(node.element.type));
return new JS.VariableInitialization(name, _visitInitializer(node));
}
@@ -2272,12 +2345,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
var fieldName = field.name.name;
if (eagerInit && !JS.invalidStaticFieldName(fieldName)) {
- return annotateVariable(
+ return annotate(
js.statement('#.# = #;', [
classElem.name,
_emitMemberName(fieldName, isStatic: true),
jsInit
]),
+ field,
field.element);
}
@@ -2325,15 +2399,22 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
if (isPublic(fieldName)) _addExport(fieldName, exportName);
var declKeyword = field.isConst || field.isFinal ? 'const' : 'let';
- return annotateVariable(
- js.statement(
- '$declKeyword # = #;', [new JS.Identifier(fieldName), jsInit]),
- field.element);
+ return js.statement('#;', [
+ annotate(
+ new JS.VariableDeclarationList(declKeyword, [
+ new JS.VariableInitialization(
+ new JS.Identifier(fieldName,
+ type: emitTypeRef(field.element.type)),
+ jsInit)
+ ]),
+ field,
+ field.element)
+ ]);
}
if (eagerInit && !JS.invalidStaticFieldName(fieldName)) {
- return annotateVariable(
- js.statement('# = #;', [_visit(field.name), jsInit]), field.element);
+ return annotate(js.statement('# = #;', [_visit(field.name), jsInit]),
+ field, field.element);
}
return _emitLazyFields(currentLibrary, [field]);
@@ -2359,6 +2440,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
js.call('function() { return #; }', _visit(node.initializer))
as JS.Fun,
isGetter: true),
+ node,
_findAccessor(element, getter: true)));
// TODO(jmesserly): currently uses a dummy setter to indicate writable.
@@ -2366,6 +2448,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
methods.add(annotate(
new JS.Method(access, js.call('function(_) {}') as JS.Fun,
isSetter: true),
+ node,
_findAccessor(element, getter: false)));
}
}
@@ -2754,8 +2837,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
_visit(node.expression);
@override
- visitFormalParameter(FormalParameter node) {
- var id = visitSimpleIdentifier(node.identifier);
+ visitFormalParameter(FormalParameter node) => _emitFormalParameter(node);
+
+ _emitFormalParameter(FormalParameter node, {bool allowType: true}) {
+ var id = _emitSimpleIdentifier(node.identifier, allowType: allowType);
var isRestArg = findAnnotation(node.element, isJsRestAnnotation) != null;
return isRestArg ? new JS.RestParameter(id) : id;
@@ -3315,7 +3400,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
_visit(AstNode node) {
if (node == null) return null;
var result = node.accept(this);
- if (result is JS.Node) result.sourceInformation = node;
+ if (result is JS.Node) result = annotate(result, node);
return result;
}
@@ -3458,34 +3543,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
DartType getStaticType(Expression e) =>
e.staticType ?? DynamicTypeImpl.instance;
- @override
- String getQualifiedName(TypeDefiningElement type) {
- JS.TemporaryId id = _imports[type.library];
- return id == null ? type.name : '${id.name}.${type.name}';
+ JS.Node annotate(JS.Node node, AstNode original, [Element element]) {
+ if (options.closure && element != null) {
+ node = node.withClosureAnnotation(
+ closureAnnotationFor(node, original, element, _namedArgTemp.name));
+ }
+ return node..sourceInformation = original;
}
- JS.Node annotate(JS.Node method, ExecutableElement e) =>
- options.closure && e != null
- ? method.withClosureAnnotation(
- closureAnnotationFor(e, _namedArgTemp.name))
- : method;
-
- JS.Node annotateDefaultConstructor(JS.Node method, ClassElement e) =>
- options.closure && e != null
- ? method
- .withClosureAnnotation(closureAnnotationForDefaultConstructor(e))
- : method;
-
- JS.Node annotateVariable(JS.Node node, VariableElement e) =>
- options.closure && e != null
- ? node.withClosureAnnotation(closureAnnotationForVariable(e))
- : node;
-
- JS.Node annotateTypeDef(JS.Node node, FunctionTypeAliasElement e) =>
- options.closure && e != null
- ? node.withClosureAnnotation(closureAnnotationForTypeDef(e))
- : node;
-
/// Returns true if this is any kind of object represented by `Number` in JS.
///
/// In practice, this is 4 types: num, int, double, and JSNumber.
« no previous file with comments | « lib/src/closure/closure_annotator.dart ('k') | lib/src/codegen/js_names.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698