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); |