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

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

Issue 2515353003: Support lazy JS types. (Closed)
Patch Set: Support lazy JS types. 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..361f5ec0198127d03ab3f0f684ebeaa356228e5d 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 ||
+ 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,40 @@ class CodeGenerator extends GeneralizingAstVisitor
return typeParts;
}
+ /// Emits an expression that lets you access statics on a [type] from code.
+ ///
+ /// 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,
+ {bool nameType: true, bool hoistType: true}) {
+ return _emitJSInterop(type.element) ??
+ _emitType(type, nameType: nameType, hoistType: hoistType);
+ }
+
+ /// Emits an expression that lets you access statics on a [type] from code.
+ 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 +2970,37 @@ 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.
+ // We have to use lazy JS types because until we have proper module
+ // loading for JS libraries bundled with Dart libraries, we will sometimes
+ // need to load Dart libraries before the corresponding JS libraries are
+ // actually loaded.
+ // Given a JS type such as:
+ // @JS('google.maps.Location')
+ // class Location { ... }
+ // We can't emit a reference to MyType because the JS library that defines
+ // it may be loaded after our code. So for now, we use a special lazy type
+ // object to represent MyType.
+ // Anonymous JS types do not have a corresponding concrete JS type so we
+ // have to use a helper to define them.
+ 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 +3014,7 @@ class CodeGenerator extends GeneralizingAstVisitor
return new JS.Identifier(name);
}
- if (type == subClass?.type) {
- return className;
- }
+ if (type == subClass?.type) return className;
if (type is ParameterizedType) {
var args = type.typeArguments;
@@ -2982,12 +3037,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 +3270,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));
@@ -3362,6 +3421,19 @@ 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);
+ }
+ if (element is ExecutableElement) {
+ return _emitStaticAccess(
+ (element.enclosingElement as ClassElement).type);
+ }
+ }
+ return _visit(target);
+ }
+
/// Emits a (possibly generic) instance method call.
JS.Expression _emitMethodCallInternal(
Expression target,
@@ -3374,7 +3446,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 +3971,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 +3997,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 +4821,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 +5195,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);
« no previous file with comments | « pkg/dev_compiler/lib/sdk/ddc_sdk.sum ('k') | pkg/dev_compiler/test/codegen/lib/html/js_typed_interop_lazy_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698