| Index: lib/src/codegen/js_codegen.dart
|
| diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
|
| index 0ff3baadbffb8904081d3144b30bb3d788b64e54..ffd51b990e2be43035873b6a9fa0a90638c22925 100644
|
| --- a/lib/src/codegen/js_codegen.dart
|
| +++ b/lib/src/codegen/js_codegen.dart
|
| @@ -94,6 +94,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| final _dartxVar = new JS.Identifier('dartx');
|
| final _exportsVar = new JS.TemporaryId('exports');
|
| final _runtimeLibVar = new JS.Identifier('dart');
|
| + final _utilsLibVar = new JS.TemporaryId('utils');
|
| + final _classesLibVar = new JS.TemporaryId('classes');
|
| + final _rttiLibVar = new JS.TemporaryId('rtti');
|
| final _namedArgTemp = new JS.TemporaryId('opts');
|
|
|
| final TypeProvider _types;
|
| @@ -108,7 +111,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| /// The default value of the module object. See [visitLibraryDirective].
|
| String _jsModuleValue;
|
|
|
| - bool _isDartUtils;
|
| + bool _isDartRuntime;
|
|
|
| Map<String, DartType> _objectMembers;
|
|
|
| @@ -123,10 +126,24 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var src = context.sourceFactory.forUri('dart:_interceptors');
|
| var interceptors = context.computeLibraryElement(src);
|
| _jsArray = interceptors.getType('JSArray');
|
| - _isDartUtils = currentLibrary.source.uri.toString() == 'dart:_utils';
|
| +
|
| + _isDartRuntime = _runtimeLibUris.contains(_getLibUri(currentLibrary));
|
|
|
| _objectMembers = getObjectMemberMap(types);
|
| }
|
| + String _getLibUri(LibraryElement lib) => lib.source.uri.toString();
|
| +
|
| + static final _runtimeLibUris = new Set<String>.from([
|
| + 'dart:_utils',
|
| + 'dart:_runtime',
|
| + 'dart:_operations',
|
| + 'dart:_errors',
|
| + 'dart:_classes',
|
| + 'dart:_generators',
|
| + 'dart:_operations',
|
| + 'dart:_types',
|
| + 'dart:_rtti'
|
| + ]);
|
|
|
| TypeProvider get types => rules.provider;
|
|
|
| @@ -196,39 +213,51 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| // TODO(jmesserly): it would be great to run the renamer on the body,
|
| // then figure out if we really need each of these parameters.
|
| // See ES6 modules: https://github.com/dart-lang/dev_compiler/issues/34
|
| - var params = [_exportsVar, _runtimeLibVar];
|
| - var processImport =
|
| - (LibraryElement library, JS.TemporaryId temp, List list) {
|
| - params.add(temp);
|
| - list.add(js.string(compiler.getModuleName(library.source.uri), "'"));
|
| - };
|
| + var params = [_exportsVar];
|
| + var lazyParams = [];
|
|
|
| - var needsDartRuntime = !_isDartUtils;
|
| + var libUri = _getLibUri(currentLibrary);
|
|
|
| var imports = <JS.Expression>[];
|
| + var lazyImports = <JS.Expression>[];
|
| var moduleStatements = <JS.Statement>[];
|
| - if (needsDartRuntime) {
|
| - imports.add(js.string('dart/_runtime'));
|
| +
|
| + addImport(String name, JS.Expression libVar, {bool eager: true}) {
|
| + (eager ? imports : lazyImports).add(js.string(name, "'"));
|
| + (eager ? params : lazyParams).add(libVar);
|
| + }
|
| +
|
| + if (!_isDartRuntime) {
|
| + addImport('dart/_runtime', _runtimeLibVar);
|
|
|
| var dartxImport =
|
| js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
|
| moduleStatements.add(dartxImport);
|
| + } else {
|
| + if (libUri == 'dart:_generators') {
|
| + addImport('dart/_classes', _classesLibVar);
|
| + }
|
| }
|
| moduleStatements.addAll(_moduleItems);
|
|
|
| - _imports.forEach((library, temp) {
|
| - if (_loader.libraryIsLoaded(library)) {
|
| - processImport(library, temp, imports);
|
| - }
|
| - });
|
| + bool shouldImportEagerly(lib) {
|
| + var otherLibUri = _getLibUri(lib);
|
| + if (otherLibUri == 'dart:_utils') return true;
|
| + if (libUri == 'dart:_types' && otherLibUri == 'dart:_rtti') return true;
|
| + if (libUri == 'dart:_runtime') return otherLibUri != 'dart:_js_helper';
|
| + return !_isDartRuntime && _loader.libraryIsLoaded(lib);
|
| + }
|
|
|
| - var lazyImports = <JS.Expression>[];
|
| - _imports.forEach((library, temp) {
|
| - if (!_loader.libraryIsLoaded(library)) {
|
| - processImport(library, temp, lazyImports);
|
| - }
|
| + var importsEagerness = new Map<LibraryElement, bool>.fromIterable(
|
| + _imports.keys, value: shouldImportEagerly);
|
| +
|
| + _imports.forEach((LibraryElement lib, JS.TemporaryId temp) {
|
| + bool eager = importsEagerness[lib];
|
| + addImport(compiler.getModuleName(lib.source.uri), temp, eager: eager);
|
| });
|
|
|
| + params.addAll(lazyParams);
|
| +
|
| var module =
|
| js.call("function(#) { 'use strict'; #; }", [params, moduleStatements]);
|
|
|
| @@ -264,9 +293,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| void visitLibraryDirective(LibraryDirective node) {
|
| assert(_jsModuleValue == null);
|
|
|
| - var jsName = findAnnotation(node.element, isJSAnnotation);
|
| - _jsModuleValue =
|
| - getConstantField(jsName, 'name', types.stringType)?.toStringValue();
|
| + _jsModuleValue = _getJsName(node.element);
|
| + }
|
| +
|
| + String _getJsName(Element e) {
|
| + var jsName = findAnnotation(e, isJSAnnotation);
|
| + return getConstantField(jsName, 'name', types.stringType)?.toStringValue();
|
| }
|
|
|
| @override
|
| @@ -294,8 +326,12 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var hide = node.combinators.firstWhere((c) => c is HideCombinator,
|
| orElse: () => null) as HideCombinator;
|
| if (show != null) {
|
| + var singleName = _getJsName(node.element);
|
| + if (singleName != null && show.shownNames.length != 1) {
|
| + throw new StateError('Cannot set js name on more than one name');
|
| + }
|
| shownNames.addAll(show.shownNames
|
| - .map((i) => i.name)
|
| + .map((i) => singleName ?? i.name)
|
| .where((s) => !currentLibNames.containsKey(s))
|
| .map((s) => js.string(s, "'")));
|
| }
|
| @@ -305,7 +341,10 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| args.add(new JS.ArrayInitializer(shownNames));
|
| args.add(new JS.ArrayInitializer(hiddenNames));
|
| }
|
| - _moduleItems.add(js.statement('dart.export_(#);', [args]));
|
| +
|
| + // When we compile _runtime.js, we need to source export_ from _utils.js:
|
| + _moduleItems.add(js.statement('#.export(#);',
|
| + [_isDartRuntime ? _utilsLibVar : _runtimeLibVar, args]));
|
| }
|
|
|
| JS.Identifier _initSymbol(JS.Identifier id) {
|
| @@ -579,10 +618,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var genericName = '$name\$';
|
| var typeParams = type.typeParameters.map((p) => p.name);
|
| if (isPublic(name)) _exports.add(genericName);
|
| - return js.statement('const # = dart.generic(function(#) { #; return #; });',
|
| - [genericName, typeParams, body, name]);
|
| +
|
| + return js.statement('const # = #(function(#) { #; return #; });',
|
| + [genericName, _dartGeneric, typeParams, body, name]);
|
| }
|
|
|
| + get _dartGeneric =>
|
| + js.call('#.generic', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]);
|
| +
|
| final _hasDeferredSupertype = new HashSet<ClassElement>();
|
|
|
| bool _deferIfNeeded(DartType type, ClassElement current) {
|
| @@ -832,7 +875,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| if (!sigFields.isEmpty || extensions.isNotEmpty) {
|
| var sig = new JS.ObjectInitializer(sigFields);
|
| var classExpr = new JS.Identifier(name);
|
| - body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig]));
|
| + body.add(js.statement('#(#, #);', [_dartSetSignature, classExpr, sig]));
|
| }
|
| }
|
|
|
| @@ -862,6 +905,9 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| return _statement(body);
|
| }
|
|
|
| + get _dartSetSignature =>
|
| + js.call('#.setSignature', [_isDartRuntime ? _classesLibVar : _runtimeLibVar]);
|
| +
|
| List<ExecutableElement> _extensionsToImplement(ClassElement element) {
|
| var members = <ExecutableElement>[];
|
| if (_extensionTypes.contains(element)) return members;
|
| @@ -1302,15 +1348,14 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var body = <JS.Statement>[];
|
| _flushLibraryProperties(body);
|
|
|
| - var name = node.name.name;
|
| + var name = _getJsName(node.element) ?? node.name.name;
|
|
|
| var fn = _visit(node.functionExpression);
|
| - bool needsTagging = true;
|
| + bool needsTagging = !_isDartRuntime;
|
|
|
| if (currentLibrary.source.isInSystemLibrary &&
|
| _isInlineJSFunction(node.functionExpression)) {
|
| fn = _simplifyPassThroughArrowFunCallBody(fn);
|
| - needsTagging = !_isDartUtils;
|
| }
|
|
|
| var id = new JS.Identifier(name);
|
| @@ -1406,16 +1451,18 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| type.optionalParameterTypes.isEmpty &&
|
| type.namedParameterTypes.isEmpty &&
|
| type.normalParameterTypes.every((t) => t.isDynamic)) {
|
| - return js.call('dart.fn(#)', [clos]);
|
| + return js.call('#(#)', [_dartFn, clos]);
|
| }
|
| if (lazy) {
|
| - return js.call('dart.fn(#, () => #)', [clos, _emitFunctionRTTI(type)]);
|
| + return js.call('#(#, () => #)', [_dartFn, clos, _emitFunctionRTTI(type)]);
|
| }
|
| - return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
|
| + return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
|
| }
|
| throw 'Function has non function type: $type';
|
| }
|
|
|
| + get _dartFn => js.call('#.fn', _isDartRuntime ? _rttiLibVar : _runtimeLibVar);
|
| +
|
| @override
|
| JS.Expression visitFunctionExpression(FunctionExpression node) {
|
| var params = _visit(node.parameters) as List<JS.Parameter>;
|
| @@ -1566,7 +1613,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
|
|
| _loader.declareBeforeUse(element);
|
|
|
| - var name = element.name;
|
| + var name = _getJsName(element) ?? element.name;
|
|
|
| // type literal
|
| if (element is ClassElement ||
|
| @@ -1578,7 +1625,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
|
|
| // library member
|
| if (element.enclosingElement is CompilationUnitElement) {
|
| - return _maybeQualifiedName(element);
|
| + return _maybeQualifiedName(element, name);
|
| }
|
|
|
| // Unqualified class member. This could mean implicit-this, or implicit
|
| @@ -1881,11 +1928,30 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| new JS.Block(_visitList(node.statements) as List<JS.Statement>,
|
| isScope: true);
|
|
|
| + /// Return the type constructor `_foolib.Bar$` given `Bar` from lib `_foolib`.
|
| + JS.Expression _emitGenericTypeConstructor(Expression typeExpression) {
|
| + var ref = _visit(typeExpression);
|
| + if (ref is JS.PropertyAccess) {
|
| + var name = (ref.selector as JS.LiteralString).valueWithoutQuotes;
|
| + return new JS.PropertyAccess(
|
| + ref.receiver, new JS.LiteralString("'$name\$'"));
|
| + } else if (ref is JS.MaybeQualifiedId) {
|
| + var name = (ref.name as JS.Identifier).name;
|
| + return new JS.PropertyAccess(
|
| + ref.qualifier, new JS.Identifier('$name\$'));
|
| + } else {
|
| + throw new ArgumentError('Invalid type ref: $ref (${ref?.runtimeType})');
|
| + }
|
| + }
|
| +
|
| @override
|
| visitMethodInvocation(MethodInvocation node) {
|
| if (node.operator != null && node.operator.lexeme == '?.') {
|
| return _emitNullSafe(node);
|
| }
|
| + if (isGenericTypeConstructorInvocation(node)) {
|
| + return _emitGenericTypeConstructor(node.argumentList.arguments.single);
|
| + }
|
|
|
| var target = _getTarget(node);
|
| var result = _emitForeignJS(node);
|
| @@ -2211,7 +2277,8 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
|
| if (isJSTopLevel) eagerInit = true;
|
|
|
| - var fieldName = field.name.name;
|
| + var fieldName = _getJsName(element) ?? field.name.name;
|
| +
|
| if ((field.isConst && eagerInit && element is TopLevelVariableElement) ||
|
| isJSTopLevel) {
|
| // constant fields don't change, so we can generate them as `let`
|
| @@ -2847,7 +2914,7 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| } else if (_requiresStaticDispatch(target, memberId.name)) {
|
| var type = member.type;
|
| var clos = js.call('dart.#.bind(#)', [name, _visit(target)]);
|
| - return js.call('dart.fn(#, #)', [clos, _emitFunctionTypeParts(type)]);
|
| + return js.call('#(#, #)', [_dartFn, clos, _emitFunctionTypeParts(type)]);
|
| }
|
| code = 'dart.bind(#, #)';
|
| } else if (_requiresStaticDispatch(target, memberId.name)) {
|
| @@ -3416,8 +3483,13 @@ class JSCodegenVisitor extends GeneralizingAstVisitor with ClosureAnnotator {
|
| /// declaration) as it doesn't have any meaningful rules enforced.
|
| JS.Identifier _libraryName(LibraryElement library) {
|
| if (library == currentLibrary) return _exportsVar;
|
| - return _imports.putIfAbsent(
|
| - library, () => new JS.TemporaryId(jsLibraryName(library)));
|
| + return _imports.putIfAbsent(library, () {
|
| + var name = library.name;
|
| + if (name == 'dart._utils') return _utilsLibVar;
|
| + else if (name == 'dart._classes') return _classesLibVar;
|
| + else if (name == 'dart._rtti') return _rttiLibVar;
|
| + else return new JS.TemporaryId(jsLibraryName(library));
|
| + });
|
| }
|
|
|
| DartType getStaticType(Expression e) => rules.getStaticType(e);
|
|
|