| Index: lib/src/codegen/js_codegen.dart
|
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
|
| index 9dde503bab801025052cac8d45bc6630452dd7d5..e06a145e2e50d3c0291e0d4d665a238cd3e9747a 100644
|
| --- a/lib/src/codegen/js_codegen.dart
|
| +++ b/lib/src/codegen/js_codegen.dart
|
| @@ -644,6 +644,45 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
|
| return heritage;
|
| }
|
|
|
| + /// Provide Dart getters and setters that forward to the underlying native
|
| + /// field. Note that the Dart names are always symbolized to avoid
|
| + /// conflicts. They will be installed as extension methods on the underlying
|
| + /// native type.
|
| + List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) {
|
| + // TODO(vsm): Can this by meta-programmed?
|
| + // E.g., dart.nativeField(symbol, jsName)
|
| + // Alternatively, perhaps it could be meta-programmed directly in
|
| + // dart.registerExtensions?
|
| + var jsMethods = <JS.Method>[];
|
| + if (!node.isStatic) {
|
| + for (var decl in node.fields.variables) {
|
| + var field = decl.element;
|
| + var name = decl.name.name;
|
| + var annotation = findAnnotation(field, isJsName);
|
| + if (annotation != null) {
|
| + name = getConstantField(annotation, 'name', types.stringType)
|
| + ?.toStringValue();
|
| + }
|
| + // Generate getter
|
| + var fn = new JS.Fun([], js.statement('{ return this.#; }', [name]));
|
| + var method =
|
| + new JS.Method(_elementMemberName(field.getter), fn, isGetter: true);
|
| + jsMethods.add(method);
|
| +
|
| + // Generate setter
|
| + if (!decl.isFinal) {
|
| + var value = new JS.TemporaryId('value');
|
| + fn = new JS.Fun(
|
| + [value], js.statement('{ this.# = #; }', [name, value]));
|
| + method = new JS.Method(_elementMemberName(field.setter), fn,
|
| + isSetter: true);
|
| + jsMethods.add(method);
|
| + }
|
| + }
|
| + }
|
| + return jsMethods;
|
| + }
|
| +
|
| List<JS.Method> _emitClassMethods(ClassDeclaration node,
|
| List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
|
| var element = node.element;
|
| @@ -670,6 +709,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
|
| hasIterator = true;
|
| jsMethods.add(_emitIterable(type));
|
| }
|
| + } else if (m is FieldDeclaration && _extensionTypes.contains(element)) {
|
| + jsMethods.addAll(_emitNativeFieldAccessors(m));
|
| }
|
| }
|
|
|
| @@ -770,6 +811,16 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
|
| dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
|
| }
|
| }
|
| + for (var f in fields) {
|
| + if (!f.isStatic) {
|
| + for (var d in f.fields.variables) {
|
| + if (d.element.isPublic) {
|
| + dartxNames.add(
|
| + _elementMemberName(d.element.getter, allowExtensions: false));
|
| + }
|
| + }
|
| + }
|
| + }
|
| if (dartxNames.isNotEmpty) {
|
| body.add(js.statement('dart.defineExtensionNames(#)',
|
| [new JS.ArrayInitializer(dartxNames, multiline: true)]));
|
| @@ -2993,13 +3044,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
|
| if (!_isObjectProperty(memberName)) {
|
| return false;
|
| }
|
| - if (!type.isObject &&
|
| - !_isJSBuiltinType(type) &&
|
| - !_extensionTypes.contains(type.element) &&
|
| - !_isNullable(target)) {
|
| - return false;
|
| - }
|
| - return true;
|
| +
|
| + // If the target could be `null`, we need static dispatch.
|
| + // If the target may be an extension type, we also use static dispatch
|
| + // as we don't symbolize object properties like hashCode.
|
| + return _isNullable(target) ||
|
| + (_extensionTypes.contains(type.element) && target is! SuperExpression);
|
| }
|
|
|
| /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
|
| @@ -3586,6 +3636,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor
|
| baseType = baseType.element.bound;
|
| }
|
| if (allowExtensions &&
|
| + baseType != null &&
|
| _extensionTypes.contains(baseType.element) &&
|
| !_isObjectProperty(name)) {
|
| return js.call('dartx.#', _propertyName(name));
|
| @@ -3732,6 +3783,12 @@ class JSGenerator extends CodeGenerator {
|
| var finder = new _ExtensionFinder(context, _extensionTypes, _types);
|
| finder._addExtensionTypes('dart:_interceptors');
|
| finder._addExtensionTypes('dart:_native_typed_data');
|
| + finder._addExtensionTypes('dart:html');
|
| + finder._addExtensionTypes('dart:indexed_db');
|
| + finder._addExtensionTypes('dart:svg');
|
| + finder._addExtensionTypes('dart:web_audio');
|
| + finder._addExtensionTypes('dart:web_gl');
|
| + finder._addExtensionTypes('dart:web_sql');
|
|
|
| // TODO(vsm): If we're analyzing against the main SDK, those
|
| // types are not explicitly annotated.
|
|
|