| Index: lib/src/codegen/js_typeref_codegen.dart
|
| diff --git a/lib/src/codegen/js_typeref_codegen.dart b/lib/src/codegen/js_typeref_codegen.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f6f5d61e0c5fc416291703623f2f75c616ac0304
|
| --- /dev/null
|
| +++ b/lib/src/codegen/js_typeref_codegen.dart
|
| @@ -0,0 +1,128 @@
|
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +part of js_codegen;
|
| +
|
| +/// Mixin with logic to generate [TypeRef]s out of [DartType]s.
|
| +abstract class JsTypeRefCodegen {
|
| + final _resolved = <DartType, JS.TypeRef>{};
|
| +
|
| + // Mixin dependencies:
|
| + CodegenOptions get options;
|
| + TypeProvider get types;
|
| + JS.Identifier get _namedArgTemp;
|
| + LibraryElement get currentLibrary;
|
| + JS.Identifier _libraryName(LibraryElement e);
|
| + String _getJSExportName(Element e);
|
| +
|
| + /// Finds the qualified path to the type.
|
| + JS.TypeRef _emitTopLevelTypeRef(DartType type) {
|
| + var e = type.element;
|
| + if (e.library == currentLibrary) {
|
| + return new JS.TypeRef.named(type.name);
|
| + } else {
|
| + return new JS.TypeRef.qualified([
|
| + _libraryName(e.library),
|
| + new JS.Identifier(_getJSExportName(e) ?? type.name)
|
| + ]);
|
| + }
|
| + }
|
| +
|
| + JS.TypeRef emitTypeRef(DartType type) {
|
| + if (!options.closure) return null;
|
| +
|
| + return _resolved.putIfAbsent(type, () {
|
| + if (type == null) new JS.TypeRef.unknown();
|
| + // TODO(ochafik): Consider calling _loader.declareBeforeUse(type.element).
|
| + if (type.isBottom || type.isDynamic) new JS.TypeRef.any();
|
| + if (type.isVoid) return new JS.TypeRef.void_();
|
| +
|
| + if (type == types.intType) return new JS.TypeRef.number().orNull();
|
| + if (type == types.numType) return new JS.TypeRef.number().orNull();
|
| + if (type == types.doubleType) return new JS.TypeRef.number().orNull();
|
| + if (type == types.boolType) return new JS.TypeRef.boolean().orNull();
|
| + if (type == types.stringType) return new JS.TypeRef.string();
|
| +
|
| + if (type is TypeParameterType) return new JS.TypeRef.named(type.name);
|
| + if (type is ParameterizedType) {
|
| + JS.TypeRef rawType;
|
| + if (type is FunctionType && type.name == null) {
|
| + var args = <JS.Identifier, JS.TypeRef>{};
|
| + for (var param in type.parameters) {
|
| + if (param.parameterKind == ParameterKind.NAMED) break;
|
| + var type = emitTypeRef(param.type);
|
| + args[new JS.Identifier(param.name)] = param.parameterKind ==
|
| + ParameterKind.POSITIONAL ? type.toOptional() : type;
|
| + }
|
| + var namedParamType = emitNamedParamsArgType(type.parameters);
|
| + if (namedParamType != null) {
|
| + args[_namedArgTemp] = namedParamType.toOptional();
|
| + }
|
| +
|
| + rawType = new JS.TypeRef.function(emitTypeRef(type.returnType), args);
|
| + } else {
|
| + var jsTypeRef = _getDartJsTypeRef(type);
|
| + if (jsTypeRef != null) return jsTypeRef;
|
| +
|
| + rawType = _emitTopLevelTypeRef(type);
|
| + }
|
| + var typeArgs = _getOwnTypeArguments(type).map(emitTypeRef);
|
| + return typeArgs.isEmpty
|
| + ? rawType
|
| + : new JS.TypeRef.generic(rawType, typeArgs);
|
| + }
|
| + return new JS.TypeRef.unknown();
|
| + });
|
| + }
|
| +
|
| + JS.TypeRef emitNamedParamsArgType(List<ParameterElement> params) {
|
| + if (!options.closure) return null;
|
| +
|
| + var namedArgs = <JS.Identifier, JS.TypeRef>{};
|
| + for (ParameterElement param in params) {
|
| + if (param.parameterKind != ParameterKind.NAMED) continue;
|
| + namedArgs[new JS.Identifier(param.name)] =
|
| + emitTypeRef(param.type).toOptional();
|
| + }
|
| + if (namedArgs.isEmpty) return null;
|
| + return new JS.TypeRef.record(namedArgs);
|
| + }
|
| +
|
| + /// Gets the "own" type arguments of [type].
|
| + ///
|
| + /// Method argument with adhoc unnamed [FunctionType] inherit any type params
|
| + /// from their enclosing class:
|
| + ///
|
| + /// class Foo<T> {
|
| + /// void method(f()); // f has [T] as type arguments,
|
| + /// } // but [] as its "own" type arguments.
|
| + Iterable<DartType> _getOwnTypeArguments(ParameterizedType type) sync* {
|
| + for (int i = 0, n = type.typeParameters.length; i < n; i++) {
|
| + if (type.typeParameters[i].enclosingElement == type.element) {
|
| + yield type.typeArguments[i];
|
| + }
|
| + }
|
| + }
|
| +
|
| + /// Special treatment of types from dart:js
|
| + /// TODO(ochafik): Is this the right thing to do? And what about package:js?
|
| + JS.TypeRef _getDartJsTypeRef(DartType type) {
|
| + switch (type.element.source.uri.toString()) {
|
| + case 'dart:js':
|
| + switch (type.name) {
|
| + case 'JsArray':
|
| + return new JS.TypeRef.array(
|
| + type is InterfaceType && type.typeArguments.length == 1
|
| + ? emitTypeRef(type.typeArguments.single)
|
| + : null);
|
| + case 'JsObject':
|
| + return new JS.TypeRef.object();
|
| + case 'JsFunction':
|
| + return new JS.TypeRef.function();
|
| + }
|
| + break;
|
| + }
|
| + return null;
|
| + }
|
| +}
|
|
|