| Index: lib/src/compiler/code_generator.dart
|
| diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart
|
| index 134907c8e4f6cf74d67e02455d7430e00961a8ed..95dba1cdabaa92703a3e0c6a11ea8fa81638d0fa 100644
|
| --- a/lib/src/compiler/code_generator.dart
|
| +++ b/lib/src/compiler/code_generator.dart
|
| @@ -224,12 +224,21 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| // Collect all Element -> Node mappings, in case we need to forward declare
|
| // any nodes.
|
| var nodes = new HashMap<Element, AstNode>.identity();
|
| - compilationUnits.map(_collectElements).forEach(nodes.addAll);
|
| + var sdkBootstrappingFns = new List<FunctionElement>();
|
| + for (var unit in compilationUnits) {
|
| + if (_isDartRuntime(unit.element.library)) {
|
| + sdkBootstrappingFns.addAll(unit.element.functions);
|
| + }
|
| + _collectElements(unit, nodes);
|
| + }
|
| _loader = new ElementLoader(_emitModuleItem, nodes);
|
|
|
| // Add implicit dart:core dependency so it is first.
|
| emitLibraryName(dartCoreLibrary);
|
|
|
| + // Emit SDK bootstrapping functions first, if any.
|
| + sdkBootstrappingFns.forEach(_loader.emitDeclaration);
|
| +
|
| // Visit each compilation unit and emit its code.
|
| //
|
| // NOTE: declarations are not necessarily emitted in this order.
|
| @@ -319,8 +328,8 @@ class CodeGenerator extends GeneralizingAstVisitor
|
|
|
| /// Collect toplevel elements and nodes we need to emit, and returns
|
| /// an ordered map of these.
|
| - static Map<Element, AstNode> _collectElements(CompilationUnit unit) {
|
| - var map = <Element, AstNode>{};
|
| + static void _collectElements(
|
| + CompilationUnit unit, Map<Element, AstNode> map) {
|
| for (var declaration in unit.declarations) {
|
| if (declaration is TopLevelVariableDeclaration) {
|
| for (var field in declaration.variables.variables) {
|
| @@ -330,7 +339,6 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| map[declaration.element] = declaration;
|
| }
|
| }
|
| - return map;
|
| }
|
|
|
| void _emitModuleItem(AstNode node) {
|
| @@ -961,7 +969,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
|
|
| // Generate a corresponding virtual getter / setter.
|
| var name = _elementMemberName(methodElement,
|
| - allowExtensions: _extensionTypes.isNativeClass(type.element));
|
| + useExtension: _extensionTypes.isNativeClass(type.element));
|
| if (method.isGetter) {
|
| // Generate a setter
|
| if (field.setter != null || !propertyOverrideResult.foundSetter)
|
| @@ -1116,7 +1124,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| if (extensions.isNotEmpty) {
|
| var methodNames = <JS.Expression>[];
|
| for (var e in extensions) {
|
| - methodNames.add(_elementMemberName(e, allowExtensions: false));
|
| + methodNames.add(_elementMemberName(e, useExtension: false));
|
| }
|
| body.add(js.statement('dart.defineExtensionMembers(#, #);', [
|
| className,
|
| @@ -1154,7 +1162,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| continue;
|
| }
|
| var memberName = _elementMemberName(element,
|
| - allowExtensions: _extensionTypes.isNativeClass(classElem));
|
| + useExtension: _extensionTypes.isNativeClass(classElem));
|
| var parts = _emitFunctionTypeParts(element.type);
|
| var property =
|
| new JS.Property(memberName, new JS.ArrayInitializer(parts));
|
| @@ -1210,7 +1218,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| var dartxNames = <JS.Expression>[];
|
| for (var m in methods) {
|
| if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
|
| - dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
|
| + dartxNames.add(_elementMemberName(m.element, useExtension: false));
|
| }
|
| }
|
| for (var f in fields) {
|
| @@ -1218,7 +1226,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| for (var d in f.fields.variables) {
|
| if (d.element.isPublic) {
|
| dartxNames.add(
|
| - _elementMemberName(d.element.getter, allowExtensions: false));
|
| + _elementMemberName(d.element.getter, useExtension: false));
|
| }
|
| }
|
| }
|
| @@ -1243,7 +1251,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| var extensionMembers = new HashSet<String>();
|
| for (var t in types) {
|
| for (var m in [t.methods, t.accessors].expand((e) => e)) {
|
| - if (!m.isStatic) extensionMembers.add(m.name);
|
| + if (!m.isStatic && m.isPublic) extensionMembers.add(m.name);
|
| }
|
| }
|
|
|
| @@ -1677,7 +1685,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| return annotate(
|
| new JS.Method(
|
| _elementMemberName(node.element,
|
| - allowExtensions: _extensionTypes.isNativeClass(type.element)),
|
| + useExtension: _extensionTypes.isNativeClass(type.element)),
|
| fn,
|
| isGetter: node.isGetter,
|
| isSetter: node.isSetter,
|
| @@ -2492,9 +2500,8 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| }
|
| }
|
| if (_isObjectMemberCall(target, name)) {
|
| - // Object methods require a helper for null checks & native types.
|
| assert(typeArgs == null); // Object methods don't take type args.
|
| - return js.call('dart.#(#, #)', [memberName, jsTarget, args]);
|
| + return js.call('dart.#(#, #)', [name, jsTarget, args]);
|
| }
|
|
|
| jsTarget = new JS.PropertyAccess(jsTarget, memberName);
|
| @@ -2845,11 +2852,6 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| return new JS.VariableInitialization(name, _visitInitializer(node));
|
| }
|
|
|
| - bool _isFinalJSDecl(AstNode field) =>
|
| - field is VariableDeclaration &&
|
| - field.isFinal &&
|
| - _isJSInvocation(field.initializer);
|
| -
|
| /// Try to emit a constant static field.
|
| ///
|
| /// If the field's initializer does not cause side effects, and if all of
|
| @@ -2915,10 +2917,9 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| eagerInit = false;
|
| }
|
|
|
| - // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile
|
| - // runtime helpers.
|
| - // TODO(jmesserly): we don't track dependencies correctly for these.
|
| - var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
|
| + // Treat dart:runtime stuff as safe to eagerly evaluate.
|
| + // TODO(jmesserly): it'd be nice to avoid this special case.
|
| + var isJSTopLevel = field.isFinal && _isDartRuntime(element.library);
|
| if (eagerInit || isJSTopLevel) {
|
| // Remember that we emitted it this way, so re-export can take advantage
|
| // of this fact.
|
| @@ -3611,8 +3612,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| /// For example `null.toString()` is legal in Dart, so we need to generate
|
| /// that as `dart.toString(obj)`.
|
| bool _isObjectMemberCall(Expression target, String memberName) {
|
| - // Is this a member on `Object`?
|
| - if (!isObjectProperty(memberName)) {
|
| + if (!isObjectMember(memberName)) {
|
| return false;
|
| }
|
|
|
| @@ -3690,12 +3690,13 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| if (isSuper) {
|
| result = js.call('dart.bind(this, #, #.#)', [name, jsTarget, name]);
|
| } else if (_isObjectMemberCall(target, memberName)) {
|
| - result = js.call('dart.bind(#, #, dart.#)', [jsTarget, name, name]);
|
| + result = js.call('dart.bind(#, #, dart.#)',
|
| + [jsTarget, _propertyName(memberName), memberName]);
|
| } else {
|
| result = js.call('dart.bind(#, #)', [jsTarget, name]);
|
| }
|
| } else if (_isObjectMemberCall(target, memberName)) {
|
| - result = js.call('dart.#(#)', [name, jsTarget]);
|
| + result = js.call('dart.#(#)', [memberName, jsTarget]);
|
| } else {
|
| result = js.call('#.#', [jsTarget, name]);
|
| }
|
| @@ -4161,8 +4162,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| ///
|
| /// Unlike call sites, we always have an element available, so we can use it
|
| /// directly rather than computing the relevant options for [_emitMemberName].
|
| - JS.Expression _elementMemberName(ExecutableElement e,
|
| - {bool allowExtensions: true}) {
|
| + JS.Expression _elementMemberName(ExecutableElement e, {bool useExtension}) {
|
| String name;
|
| if (e is PropertyAccessorElement) {
|
| name = e.variable.name;
|
| @@ -4173,7 +4173,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| type: (e.enclosingElement as ClassElement).type,
|
| unary: e.parameters.isEmpty,
|
| isStatic: e.isStatic,
|
| - allowExtensions: allowExtensions);
|
| + useExtension: useExtension);
|
| }
|
|
|
| /// This handles member renaming for private names and operators.
|
| @@ -4221,7 +4221,7 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| {DartType type,
|
| bool unary: false,
|
| bool isStatic: false,
|
| - bool allowExtensions: true}) {
|
| + bool useExtension}) {
|
| // Static members skip the rename steps.
|
| if (isStatic) return _propertyName(name);
|
|
|
| @@ -4241,19 +4241,20 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| name = '+$name';
|
| }
|
|
|
| - // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
|
| - var baseType = type;
|
| - while (baseType is TypeParameterType) {
|
| - baseType = baseType.element.bound;
|
| - }
|
| - if (allowExtensions &&
|
| - baseType != null &&
|
| - _extensionTypes.hasNativeSubtype(baseType) &&
|
| - !isObjectProperty(name)) {
|
| - return js.call('dartx.#', _propertyName(name));
|
| + var result = _propertyName(name);
|
| +
|
| + if (useExtension == null) {
|
| + // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
|
| + var baseType = type;
|
| + while (baseType is TypeParameterType) {
|
| + baseType = baseType.element.bound;
|
| + }
|
| + useExtension = baseType != null &&
|
| + _extensionTypes.hasNativeSubtype(baseType) &&
|
| + !isObjectMember(name);
|
| }
|
|
|
| - return _propertyName(name);
|
| + return useExtension ? js.call('dartx.#', result) : result;
|
| }
|
|
|
| JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
|
| @@ -4299,18 +4300,22 @@ class CodeGenerator extends GeneralizingAstVisitor
|
| /// a subtype of int and double (and num). It's in our "dart:_interceptors".
|
| bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType);
|
|
|
| - bool _isObjectGetter(String name) {
|
| - PropertyAccessorElement element = types.objectType.element.getGetter(name);
|
| - return (element != null && !element.isStatic);
|
| - }
|
| -
|
| - bool _isObjectMethod(String name) {
|
| - MethodElement element = types.objectType.element.getMethod(name);
|
| - return (element != null && !element.isStatic);
|
| - }
|
| -
|
| - bool isObjectProperty(String name) {
|
| - return _isObjectGetter(name) || _isObjectMethod(name);
|
| + /// Return true if this is one of the methods/properties on all Dart Objects
|
| + /// (toString, hashCode, noSuchMethod, runtimeType).
|
| + ///
|
| + /// Operator == is excluded, as it is handled as part of the equality binary
|
| + /// operator.
|
| + bool isObjectMember(String name) {
|
| + // We could look these up on Object, but we have hard coded runtime helpers
|
| + // so it's not really providing any benefit.
|
| + switch (name) {
|
| + case 'hashCode':
|
| + case 'toString':
|
| + case 'noSuchMethod':
|
| + case 'runtimeType':
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
|
|
| // TODO(leafp): Various analyzer pieces computed similar things.
|
|
|