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

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

Issue 1138793002: Tag closures with their types (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Rebase Created 5 years, 7 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
Index: lib/src/codegen/js_codegen.dart
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 8af06b9dfb02481a6e62f779bc649adf98c9852c..5b30959dd9b56ba8920733394a18378f6b45e1da 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -335,11 +335,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
var ctors = <ConstructorDeclaration>[];
var fields = <FieldDeclaration>[];
+ var methods = <MethodDeclaration>[];
for (var member in node.members) {
if (member is ConstructorDeclaration) {
ctors.add(member);
} else if (member is FieldDeclaration && !member.isStatic) {
fields.add(member);
+ } else if (member is MethodDeclaration) {
+ methods.add(member);
}
}
@@ -352,8 +355,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
jsPeerName = getConstantField(jsPeer, 'name', types.stringType);
}
- var body =
- _finishClassMembers(classElem, classExpr, ctors, fields, jsPeerName);
+ var body = _finishClassMembers(
+ classElem, classExpr, ctors, fields, methods, jsPeerName);
var result = _finishClassDef(type, body);
@@ -536,7 +539,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
/// inside the ES6 `class { ... }` node.
JS.Statement _finishClassMembers(ClassElement classElem,
JS.ClassExpression cls, List<ConstructorDeclaration> ctors,
- List<FieldDeclaration> fields, String jsPeerName) {
+ List<FieldDeclaration> fields, List<MethodDeclaration> methods,
+ String jsPeerName) {
var name = classElem.name;
var body = <JS.Statement>[];
body.add(new JS.ClassDeclaration(cls));
@@ -578,6 +582,48 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
}
}
+ {
vsm 2015/05/18 17:35:10 Add comment to this block ... e.g, // Emit signatu
Leaf 2015/05/19 00:02:21 Done.
+ var tStatics = [];
+ var tMethods = [];
+ var sNames = [];
+ var cType = classElem.type;
+ for (MethodDeclaration node in methods) {
+ if (!(node.isSetter || node.isGetter || node.isAbstract)) {
+ var name = node.name.name;
+ var element = node.element;
+ var unary = node.parameters.parameters.isEmpty;
+ var memberName = _emitMemberName(name,
+ type: cType, unary: unary, isStatic: node.isStatic);
+ var property =
+ new JS.Property(memberName, _emitTypeName(element.type));
+ if (node.isStatic) {
+ tStatics.add(property);
+ sNames.add(memberName);
+ } else tMethods.add(property);
+ }
+ }
+ build(name, elements) {
+ var o =
+ new JS.ObjectInitializer(elements, vertical: elements.length > 1);
+ var e = js.call('() => #', o);
+ var p = new JS.Property(_propertyName(name), e);
+ return p;
+ }
+ var sigFields = [];
+ if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods));
+ if (!tStatics.isEmpty) {
+ assert(!sNames.isEmpty);
+ var aNames = new JS.Property(
+ _propertyName('names'), new JS.ArrayInitializer(sNames));
+ sigFields.add(build('statics', tStatics));
+ sigFields.add(aNames);
+ }
+
+ var sig = new JS.ObjectInitializer(sigFields);
+ var classExpr = new JS.Identifier(name);
+ body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig]));
+ }
+
return _statement(body);
}
@@ -915,10 +961,11 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
_flushLibraryProperties(body);
var name = node.name.name;
- body.add(js.comment('Function $name: ${node.element.type}'));
- body.add(new JS.FunctionDeclaration(
- new JS.Identifier(name), _visit(node.functionExpression)));
+ var id = new JS.Identifier(name);
+ body.add(new JS.FunctionDeclaration(id, _visit(node.functionExpression)));
+ body.add(_emitFunctionTagged(id, node.element.type, topLevel: true)
+ .toStatement());
if (isPublic(name)) _addExport(name);
return _statement(body);
@@ -930,6 +977,44 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
isGetter: node.isGetter, isSetter: node.isSetter);
}
+ bool _executesAtTopLevel(AstNode node) {
+ var ancestor = node.getAncestor((n) => n is FunctionBody ||
+ (n is FieldDeclaration && n.staticKeyword == null) ||
+ (n is ConstructorDeclaration && n.constKeyword == null));
+ return ancestor == null;
+ }
+
+ bool _typeIsLoaded(DartType type) {
+ if (type is FunctionType && (type.name == '' || type.name == null)) {
+ return (_typeIsLoaded(type.returnType) &&
+ type.optionalParameterTypes.every(_typeIsLoaded) &&
+ type.namedParameterTypes.values.every(_typeIsLoaded) &&
+ type.normalParameterTypes.every(_typeIsLoaded));
+ }
+ if (type.isDynamic || type.isVoid || type.isBottom) return true;
+ return _loader.isLoaded(type.element);
+ }
+
+ JS.Expression _emitFunctionTagged(JS.Expression clos, DartType type,
+ {topLevel: false}) {
+ var name = type.name;
+ var lazy = topLevel && !_typeIsLoaded(type);
Jennifer Messerly 2015/05/19 18:19:01 Definitely not something that needs to be changed
Leaf 2015/05/19 22:31:12 Acknowledged.
+
+ if (type is FunctionType && (name == '' || name == null)) {
+ if (type.returnType.isDynamic &&
+ type.optionalParameterTypes.isEmpty &&
+ type.namedParameterTypes.isEmpty &&
+ type.normalParameterTypes.every((t) => t.isDynamic)) {
+ return js.call('dart.fn(#)', [clos]);
+ }
+ if (lazy) {
+ return js.call('dart.fn(#, () => #)', [clos, _emitTypeName(type)]);
+ }
+ return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
+ }
+ throw 'Function has non function type: $type';
+ }
+
@override
JS.Expression visitFunctionExpression(FunctionExpression node) {
var params = _visit(node.parameters);
@@ -950,7 +1035,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
code = '(#) => { #; }';
body = nodeBody;
}
- return js.call(code, [params, _visit(body)]);
+ var clos = js.call(code, [params, _visit(body)]);
+ if (parent.parent is! FunctionDeclarationStatement) {
Jennifer Messerly 2015/05/19 18:19:01 maybe pull out `parent.parent is! FunctionDeclarat
Leaf 2015/05/19 22:31:13 Done.
+ var type = getStaticType(node);
+ return _emitFunctionTagged(clos, type,
+ topLevel: _executesAtTopLevel(node));
+ }
+ return clos;
}
}
@@ -967,8 +1058,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
// `this`, but it seems harmless enough to just do it always.
var name = new JS.Identifier(func.name.name);
return new JS.Block([
- js.comment("// Function ${func.name.name}: ${func.element.type}\n"),
- js.statement('let # = #;', [name, _visit(func.functionExpression)])
+ js.statement('let # = #;', [name, _visit(func.functionExpression)]),
+ _emitFunctionTagged(name, func.element.type).toStatement()
]);
}
@@ -1059,6 +1150,26 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
return new JS.ObjectInitializer(properties);
}
+ List<JS.Expression> _emitFunctionTypeParts(FunctionType type) {
+ var returnType = type.returnType;
+ var parameterTypes = type.normalParameterTypes;
+ var optionalTypes = type.optionalParameterTypes;
+ var namedTypes = type.namedParameterTypes;
+ var rt = _emitTypeName(returnType);
+ var ra = _emitTypeNames(parameterTypes);
+ if (!namedTypes.isEmpty) {
+ assert(optionalTypes.isEmpty);
+ var na = _emitTypeProperties(namedTypes);
+ return [rt, ra, na];
+ }
+ if (!optionalTypes.isEmpty) {
+ assert(namedTypes.isEmpty);
+ var oa = _emitTypeNames(optionalTypes);
+ return [rt, ra, oa];
+ }
+ return [rt, ra];
+ }
+
/// Emits a Dart [type] into code.
///
/// If [lowerTypedef] is set, a typedef will be expanded as if it were a
@@ -1073,6 +1184,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
return js.call('dart.void');
} else if (type.isDynamic) {
return js.call('dart.dynamic');
+ } else if (type.isBottom) {
+ return js.call('dart.bottom');
}
_loader.declareBeforeUse(type.element);
@@ -1082,33 +1195,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
// to canonicalize them too, at least when inside the same library.
var name = type.name;
var element = type.element;
- if (name == '' || lowerTypedef) {
- var fnType = type as FunctionType;
- var returnType = fnType.returnType;
- var parameterTypes = fnType.normalParameterTypes;
- var optionalTypes = fnType.optionalParameterTypes;
- var namedTypes = fnType.namedParameterTypes;
- if (namedTypes.isEmpty) {
- if (optionalTypes.isEmpty) {
- return js.call('dart.functionType(#, #)', [
- _emitTypeName(returnType),
- _emitTypeNames(parameterTypes)
- ]);
- } else {
- return js.call('dart.functionType(#, #, #)', [
- _emitTypeName(returnType),
- _emitTypeNames(parameterTypes),
- _emitTypeNames(optionalTypes)
- ]);
- }
- } else {
- assert(optionalTypes.isEmpty);
- return js.call('dart.functionType(#, #, #)', [
- _emitTypeName(returnType),
- _emitTypeNames(parameterTypes),
- _emitTypeProperties(namedTypes)
- ]);
- }
+ if (name == '' || name == null || lowerTypedef) {
+ var parts = _emitFunctionTypeParts(type as FunctionType);
+ return js.call('dart.functionType(#)', [parts]);
}
if (type is TypeParameterType) {

Powered by Google App Engine
This is Rietveld 408576698