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

Unified Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 2515353003: Support lazy JS types. (Closed)
Patch Set: rebased Created 4 years, 1 month 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: pkg/dev_compiler/lib/src/compiler/code_generator.dart
diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
index b7f3d5a048c61f3eb83779eb8979cf64a025c04e..9073fd8c4e44b0dbe24626f9aabc3451e2aba334 100644
--- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart
@@ -308,7 +308,8 @@ class CodeGenerator extends GeneralizingAstVisitor
}
List<String> _getJSName(Element e) {
- if (findAnnotation(e.library, isPublicJSAnnotation) == null) {
+ if (e.library == null ||
Jennifer Messerly 2016/11/22 18:18:19 nice fix. I'm curious, do you know how this happen
Jacob 2016/11/22 18:51:37 I suspect one of dynamic or bottom doesn't show up
+ findAnnotation(e.library, isPublicJSAnnotation) == null) {
return null;
}
@@ -322,6 +323,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (findAnnotation(e, isPublicJSAnnotation) != null) {
elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? '';
}
+
if (e is TopLevelVariableElement &&
e.getter != null &&
(e.getter.isExternal ||
@@ -2705,11 +2707,8 @@ class CodeGenerator extends GeneralizingAstVisitor
var type = element.enclosingElement.type;
var member = _emitMemberName(name, isStatic: isStatic, type: type);
- // For static methods, we add the raw type name, without generics or
- // library prefix. We don't need those because static calls can't use
- // the generic type.
if (isStatic) {
- var dynType = _emitType(fillDynamicTypeArgs(type));
+ var dynType = _emitStaticAccess(type);
return new JS.PropertyAccess(dynType, member);
}
@@ -2908,6 +2907,45 @@ class CodeGenerator extends GeneralizingAstVisitor
return typeParts;
}
+ /// Emits an expression that lets you access statics on a [[type]] from code.
Jennifer Messerly 2016/11/22 18:18:19 comment nit: I don't think you want two brackets,
Jacob 2016/11/22 18:51:37 [[[done]]]
+ ///
+ /// If [nameType] is true, then the type will be named. In addition,
+ /// if [hoistType] is true, then the named type will be hoisted.
+ JS.Expression _emitConstructorAccess(DartType type,
Jennifer Messerly 2016/11/22 18:18:19 just wanted to say, this is factored in a lovely w
Jacob 2016/11/22 18:51:36 yay!
+ {bool nameType: true, bool hoistType: true}) {
+ var interop = _emitJSInterop(type.element);
Jennifer Messerly 2016/11/22 18:18:19 this could be: return _emitJSInterop(type.elemen
Jacob 2016/11/22 18:51:36 Done.
+ if (interop != null) return interop;
+
+ // TODO(jacobr): we could consider duplicating logic instead of calling
Jennifer Messerly 2016/11/22 18:18:19 personally I'm not sure we need this TODO ... we c
Jacob 2016/11/22 18:51:36 sounds good. My only concern is that this is only
+ // through to the somewhat unrelated _emitType mode. Calling _emitType here
+ // is acceptable as the type cannot be a JS interop type.
+ return _emitType(type, nameType: nameType, hoistType: hoistType);
+ }
+
+ /// Emits an expression that lets you access statics on a [[type]] from code.
Jennifer Messerly 2016/11/22 18:18:19 comment nit again: [type] instead of [[type]]
Jacob 2016/11/22 18:51:36 Done.
+ JS.Expression _emitStaticAccess(DartType type) {
+ // Make sure we aren't attempting to emit a static access path to a type
+ // that does not have a valid static access path.
+ assert(!type.isVoid &&
+ !type.isDynamic &&
+ !type.isBottom &&
+ type is! TypeParameterType);
+
+ // For statics, we add the raw type name, without generics or
+ // library prefix. We don't need those because static calls can't use
+ // the generic type.
+ type = fillDynamicTypeArgs(type);
+ var element = type.element;
+ _declareBeforeUse(element);
+
+ var interop = _emitJSInterop(element);
+ if (interop != null) return interop;
+
+ assert(type.name != '' && type.name != null);
+
+ return _emitTopLevelNameNoInterop(element);
+ }
+
/// Emits a Dart [type] into code.
///
/// If [lowerTypedef] is set, a typedef will be expanded as if it were a
@@ -2937,13 +2975,29 @@ class CodeGenerator extends GeneralizingAstVisitor
return _callHelper('bottom');
}
- _declareBeforeUse(type.element);
+ var element = type.element;
+ _declareBeforeUse(element);
+
+ var interop = _emitJSInterop(element);
+ // Type parameters don't matter as JS interop types cannot be reified.
Jennifer Messerly 2016/11/22 18:18:19 should we error out if the type is generic? I'm g
Jacob 2016/11/22 18:51:36 Would really like to allow it assuming JS interop
+ // We have to use lazy JS types because until we have proper module
Jennifer Messerly 2016/11/22 18:18:19 This comment is good, but maybe a code example wou
Jacob 2016/11/22 18:51:37 Done.
+ // loading for JS libraries bundled with Dart libraries, we will sometimes
+ // need to load Dart libraries before the corresponding JS libraries are
+ // actually loaded.
+ if (interop != null) {
+ if (_isObjectLiteral(element)) {
+ return _callHelper(
+ 'lazyAnonymousJSType(#)', js.string(element.displayName));
+ } else {
+ return _callHelper('lazyJSType(() => #, #)',
+ [interop, js.string(_getJSName(element).join('.'))]);
+ }
+ }
// TODO(jmesserly): like constants, should we hoist function types out of
// methods? Similar issue with generic types. For all of these, we may want
// to canonicalize them too, at least when inside the same library.
var name = type.name;
- var element = type.element;
if (name == '' || name == null || lowerTypedef) {
// TODO(jmesserly): should we change how typedefs work? They currently
// go through use similar logic as generic classes. This makes them
@@ -2957,9 +3011,7 @@ class CodeGenerator extends GeneralizingAstVisitor
return new JS.Identifier(name);
}
- if (type == subClass?.type) {
- return className;
- }
+ if (type == subClass?.type) return className;
Jennifer Messerly 2016/11/22 18:18:19 nice!
Jacob 2016/11/22 18:51:36 Acknowledged.
if (type is ParameterizedType) {
var args = type.typeArguments;
@@ -2982,12 +3034,16 @@ class CodeGenerator extends GeneralizingAstVisitor
}
}
- return _emitTopLevelName(element);
+ return _emitTopLevelNameNoInterop(element);
}
JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) {
var interop = _emitJSInterop(e);
if (interop != null) return interop;
+ return _emitTopLevelNameNoInterop(e, suffix: suffix);
+ }
+
+ JS.PropertyAccess _emitTopLevelNameNoInterop(Element e, {String suffix: ''}) {
String name = getJSExportName(e) + suffix;
return new JS.PropertyAccess(
emitLibraryName(e.library), _propertyName(name));
@@ -3211,7 +3267,7 @@ class CodeGenerator extends GeneralizingAstVisitor
// the generic type.
ClassElement classElement = element.enclosingElement;
var type = classElement.type;
- var dynType = _emitType(fillDynamicTypeArgs(type));
+ var dynType = _emitStaticAccess(type);
var member = _emitMemberName(element.name, isStatic: true, type: type);
return _visit(rhs).toAssignExpression(
annotate(new JS.PropertyAccess(dynType, member), lhs));
@@ -3291,6 +3347,7 @@ class CodeGenerator extends GeneralizingAstVisitor
return _emitNullSafe(node);
}
+ // SSS
Jennifer Messerly 2016/11/22 18:18:19 remove this?
Jacob 2016/11/22 18:51:37 Done.
var result = _emitForeignJS(node);
if (result != null) return result;
@@ -3362,6 +3419,17 @@ class CodeGenerator extends GeneralizingAstVisitor
return helperMethodName;
}
+ JS.Expression _emitTarget(Expression target, Element element, bool isStatic) {
+ if (isStatic) {
+ if (element is ConstructorElement)
+ return _emitConstructorAccess(element.enclosingElement.type);
Jennifer Messerly 2016/11/22 18:18:19 style nit: should have curly braces if it's more t
Jacob 2016/11/22 18:51:36 Done.
+ if (element is ExecutableElement)
+ return _emitStaticAccess(
Jennifer Messerly 2016/11/22 18:18:19 same here
Jacob 2016/11/22 18:51:36 Done.
+ (element.enclosingElement as ClassElement).type);
+ }
+ return _visit(target);
+ }
+
/// Emits a (possibly generic) instance method call.
JS.Expression _emitMethodCallInternal(
Expression target,
@@ -3374,7 +3442,7 @@ class CodeGenerator extends GeneralizingAstVisitor
bool isStatic = element is ExecutableElement && element.isStatic;
var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
- JS.Expression jsTarget = _visit(target);
+ JS.Expression jsTarget = _emitTarget(target, element, isStatic);
if (isDynamicInvoke(target) || isDynamicInvoke(node.methodName)) {
if (_inWhitelistCode(target)) {
var vars = <JS.MetaLetVariable, JS.Expression>{};
@@ -3899,7 +3967,7 @@ class CodeGenerator extends GeneralizingAstVisitor
var classElem = element.enclosingElement;
var interop = _emitJSInterop(classElem);
if (interop != null) return interop;
- var typeName = _emitType(type);
+ var typeName = _emitConstructorAccess(type);
if (name != null || element.isFactory) {
var namedCtor = _constructorName(element);
return new JS.PropertyAccess(typeName, namedCtor);
@@ -3925,7 +3993,7 @@ class CodeGenerator extends GeneralizingAstVisitor
if (element == null) {
// TODO(jmesserly): this only happens if we had a static error.
// Should we generate a throw instead?
- ctor = _emitType(type,
+ ctor = _emitConstructorAccess(type,
nameType: options.hoistInstanceCreation,
hoistType: options.hoistInstanceCreation);
if (name != null) {
@@ -4749,7 +4817,7 @@ class CodeGenerator extends GeneralizingAstVisitor
[_emitDynamicOperationName('dload'), _visit(target), name]);
}
- var jsTarget = _visit(target);
+ var jsTarget = _emitTarget(target, member, isStatic);
bool isSuper = jsTarget is JS.Super;
if (isSuper && member is FieldElement && !member.isSynthetic) {
@@ -5123,7 +5191,8 @@ class CodeGenerator extends GeneralizingAstVisitor
// TODO(vsm): When we canonicalize, we need to treat private symbols
// correctly.
var name = js.string(node.components.join('.'), "'");
- return js.call('#.new(#)', [_emitType(types.symbolType), name]);
+ return js
+ .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]);
}
return _emitConst(emitSymbol);

Powered by Google App Engine
This is Rietveld 408576698