Remove experimental closure support from dartdevc

Change-Id: Id171cbfd220c4b504f13183ffdcad581c44fb41a
Reviewed-on: https://dart-review.googlesource.com/64826
Commit-Queue: Jenny Messerly <jmesserly@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
This commit is contained in:
Jenny Messerly 2018-07-16 19:32:44 +00:00
parent 2420134b23
commit 875abcea39
16 changed files with 61 additions and 1343 deletions

View file

@ -35,7 +35,6 @@ import 'package:analyzer/src/task/strong/ast_properties.dart';
import 'package:path/path.dart' as path;
import 'package:source_span/source_span.dart' show SourceLocation;
import '../closure/closure_annotator.dart' show ClosureAnnotator;
import '../compiler/js_metalet.dart' as JS;
import '../compiler/js_names.dart' as JS;
import '../compiler/js_utils.dart' as JS;
@ -49,7 +48,6 @@ import 'element_helpers.dart';
import 'error_helpers.dart';
import 'extension_types.dart' show ExtensionTypeSet;
import 'js_interop.dart';
import 'js_typeref_codegen.dart' show JSTypeRefCodegen;
import 'js_typerep.dart';
import 'module_compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile;
import 'nullable_type_inference.dart' show NullableTypeInference;
@ -74,11 +72,7 @@ import 'type_utilities.dart';
// expressions (which result in JS.Expression) and statements
// (which result in (JS.Statement).
class CodeGenerator extends Object
with
ClosureAnnotator,
JSTypeRefCodegen,
NullableTypeInference,
SharedCompiler<LibraryElement>
with NullableTypeInference, SharedCompiler<LibraryElement>
implements AstVisitor<JS.Node> {
final AnalysisContext context;
final SummaryDataStore summaryData;
@ -871,13 +865,10 @@ class CodeGenerator extends Object
}
}
JS.Expression body = closureAnnotate(
runtimeCall('typedef(#, () => #)', [
js.string(element.name, "'"),
_emitFunctionType(type, nameType: false)
]),
element,
node);
JS.Expression body = runtimeCall('typedef(#, () => #)', [
js.string(element.name, "'"),
_emitFunctionType(type, nameType: false)
]);
if (typeFormals.isNotEmpty) {
return _defineClassTypeArguments(element, typeFormals,
@ -1231,19 +1222,6 @@ class CodeGenerator extends Object
.toList(growable: false);
}
/// Emits a field declaration for TypeScript & Closure's ES6_TYPED
/// (e.g. `class Foo { i: string; }`)
JS.VariableDeclarationList _emitTypeScriptField(FieldElement field) {
return JS.VariableDeclarationList(field.isStatic ? 'static' : null, [
JS.VariableInitialization(
JS.Identifier(
// TODO(ochafik): use a refactored _emitMemberName instead.
field.name,
type: emitTypeRef(field.type)),
null)
]);
}
@override
JS.Statement visitEnumDeclaration(EnumDeclaration node) {
return _emitClassDeclaration(node, node.element, []);
@ -1279,19 +1257,12 @@ class CodeGenerator extends Object
JS.Expression className,
JS.Expression heritage,
List<JS.Method> methods) {
var typeParams = _emitTypeFormals(classElem.typeParameters);
var jsFields = options.closure
? classElem.fields.map(_emitTypeScriptField).toList()
: null;
if (classElem.typeParameters.isNotEmpty) {
return JS.ClassExpression(className as JS.Identifier, heritage, methods,
typeParams: typeParams, fields: jsFields)
return JS.ClassExpression(className as JS.Identifier, heritage, methods)
.toStatement();
}
var classExpr = JS.ClassExpression(
JS.TemporaryId(classElem.name), heritage, methods,
typeParams: typeParams, fields: jsFields);
var classExpr =
JS.ClassExpression(JS.TemporaryId(classElem.name), heritage, methods);
return js.statement('# = #;', [className, classExpr]);
}
@ -1648,8 +1619,7 @@ class CodeGenerator extends Object
body.add(js.statement(
'return super.#(#)(#);', [name, typeFormals, jsParams]));
}
var fn = JS.Fun(jsParams, JS.Block(body),
typeParams: typeFormals, returnType: emitTypeRef(type.returnType));
var fn = JS.Fun(jsParams, JS.Block(body));
methods.add(JS.Method(name, fn));
} else {
throw StateError(
@ -1664,7 +1634,6 @@ class CodeGenerator extends Object
if (isUnsupportedFactoryConstructor(node)) return null;
var element = node.element;
var returnType = emitTypeRef(element.returnType);
var name = _constructorName(element.name);
JS.Fun fun;
@ -1687,8 +1656,7 @@ class CodeGenerator extends Object
js.statement('return $newKeyword #(#)',
[visitConstructorName(redirect), params])
..sourceInformation = _nodeStart(redirect)
]),
returnType: returnType);
]));
} else {
// Normal factory constructor
var body = <JS.Statement>[];
@ -1697,16 +1665,13 @@ class CodeGenerator extends Object
body.add(_visitStatement(node.body));
var params = _emitParameters(node.parameters?.parameters);
fun = JS.Fun(params, JS.Block(body), returnType: returnType);
fun = JS.Fun(params, JS.Block(body));
}
_currentFunction = savedFunction;
return closureAnnotate(
JS.Method(name, fun, isStatic: true)
..sourceInformation = _functionEnd(node),
element,
node);
return JS.Method(name, fun, isStatic: true)
..sourceInformation = _functionEnd(node);
}
/// Given a class C that implements method M from interface I, but does not
@ -1784,7 +1749,7 @@ class CodeGenerator extends Object
return JS.Method(
_declareMemberName(method,
useExtension: _extensionTypes.isNativeClass(type.element)),
JS.Fun(fnArgs, fnBlock, typeParams: typeParams),
JS.Fun(fnArgs, fnBlock),
isGetter: method is PropertyAccessorElement && method.isGetter,
isSetter: method is PropertyAccessorElement && method.isSetter,
isStatic: false);
@ -2630,14 +2595,11 @@ class CodeGenerator extends Object
fn = _emitFunction(node.element, node.parameters, node.body);
}
return closureAnnotate(
JS.Method(_declareMemberName(node.element), fn,
isGetter: node.isGetter,
isSetter: node.isSetter,
isStatic: node.isStatic)
..sourceInformation = _functionEnd(node),
node.element,
node);
return JS.Method(_declareMemberName(node.element), fn,
isGetter: node.isGetter,
isSetter: node.isSetter,
isStatic: node.isStatic)
..sourceInformation = _functionEnd(node);
}
@override
@ -2683,8 +2645,7 @@ class CodeGenerator extends Object
var element = resolutionMap.elementDeclaredByFunctionDeclaration(node);
var nameExpr = _emitTopLevelName(element);
body.add(
closureAnnotate(js.statement('# = #', [nameExpr, fn]), element, node));
body.add(js.statement('# = #', [nameExpr, fn]));
// Function types of top-level/static functions are only needed when
// dart:mirrors is enabled.
// TODO(jmesserly): do we even need this for mirrors, since statics are not
@ -2718,13 +2679,10 @@ class CodeGenerator extends Object
JS.Method _emitTopLevelProperty(FunctionDeclaration node) {
var name = node.name.name;
return closureAnnotate(
JS.Method(_propertyName(name),
_emitFunctionExpression(node.functionExpression),
isGetter: node.isGetter, isSetter: node.isSetter)
..sourceInformation = _functionEnd(node),
node.element,
node);
return JS.Method(
_propertyName(name), _emitFunctionExpression(node.functionExpression),
isGetter: node.isGetter, isSetter: node.isSetter)
..sourceInformation = _functionEnd(node);
}
bool _executesAtTopLevel(AstNode node) {
@ -2788,8 +2746,7 @@ class CodeGenerator extends Object
// Convert `function(...) { ... }` to `(...) => ...`
// This is for readability, but it also ensures correct `this` binding.
return JS.ArrowFun(f.params, body,
typeParams: f.typeParams, returnType: f.returnType);
return JS.ArrowFun(f.params, body);
}
/// Emits a non-arrow FunctionExpression node.
@ -2824,8 +2781,7 @@ class CodeGenerator extends Object
]);
code = super.exitFunction(element.name, formals, code);
return JS.Fun(formals, code,
typeParams: typeFormals, returnType: emitTypeRef(type.returnType));
return JS.Fun(formals, code);
}
JS.Block _emitFunctionBody(ExecutableElement element,
@ -2897,8 +2853,7 @@ class CodeGenerator extends Object
// TODO(jmesserly): this will emit argument initializers (for default
// values) inside the generator function body. Is that the best place?
var jsBody = _emitFunctionBody(element, parameters, body);
var genFn = JS.Fun(jsParams, jsBody,
isGenerator: true, returnType: emitTypeRef(returnType));
var genFn = JS.Fun(jsParams, jsBody, isGenerator: true);
// Name the function if possible, to get better stack traces.
var name = element.name;
@ -3132,9 +3087,8 @@ class CodeGenerator extends Object
return JS.PropertyAccess(target, member);
}
JS.Identifier _emitVariableDef(SimpleIdentifier id, {JS.TypeRef type}) {
return JS.Identifier(id.name, type: type)
..sourceInformation = _nodeStart(id);
JS.Identifier _emitVariableDef(SimpleIdentifier id) {
return JS.Identifier(id.name)..sourceInformation = _nodeStart(id);
}
/// Returns `true` if the type name referred to by [node] is used in a
@ -3175,8 +3129,7 @@ class CodeGenerator extends Object
element, () => JS.TemporaryId(element.name.substring(1)));
}
var type = declaration ? emitTypeRef(element.type) : null;
return JS.Identifier(element.name, type: type);
return JS.Identifier(element.name);
}
List<Annotation> _parameterMetadata(FormalParameter p) =>
@ -4272,8 +4225,7 @@ class CodeGenerator extends Object
return null;
}
var name =
_emitVariableDef(node.name, type: emitTypeRef(node.element.type));
var name = _emitVariableDef(node.name);
return JS.VariableInitialization(
name, _visitInitializer(node.initializer, node.element));
}
@ -4300,13 +4252,10 @@ class CodeGenerator extends Object
_isJSInvocation(init) ||
init is InstanceCreationExpression &&
isSdkInternalRuntime(init.staticElement.library)) {
moduleItems.add(closureAnnotate(
js.statement('# = #;', [
_emitTopLevelName(field.element),
_visitInitializer(field.initializer, field.element)
]),
field.element,
field));
moduleItems.add(js.statement('# = #;', [
_emitTopLevelName(field.element),
_visitInitializer(field.initializer, field.element)
]));
} else {
lazyFields.add(field);
}
@ -4332,41 +4281,24 @@ class CodeGenerator extends Object
for (var node in fields) {
var element = node.element;
var access = emitFieldName(element);
accessors.add(closureAnnotate(
JS.Method(
access,
js.call('function() { return #; }',
_visitInitializer(node.initializer, element)) as JS.Fun,
isGetter: true)
..sourceInformation =
_hoverComment(JS.PropertyAccess(objExpr, access), node.name),
_findAccessor(element, getter: true),
node));
accessors.add(JS.Method(
access,
js.call('function() { return #; }',
_visitInitializer(node.initializer, element)) as JS.Fun,
isGetter: true)
..sourceInformation =
_hoverComment(JS.PropertyAccess(objExpr, access), node.name));
// TODO(jmesserly): currently uses a dummy setter to indicate writable.
if (!node.isFinal && !node.isConst) {
accessors.add(closureAnnotate(
JS.Method(access, js.call('function(_) {}') as JS.Fun,
isSetter: true),
_findAccessor(element, getter: false),
node));
accessors.add(JS.Method(access, js.call('function(_) {}') as JS.Fun,
isSetter: true));
}
}
return runtimeStatement('defineLazy(#, { # })', [objExpr, accessors]);
}
PropertyAccessorElement _findAccessor(VariableElement element,
{bool getter}) {
var parent = element.enclosingElement;
if (parent is ClassElement) {
return getter
? parent.getGetter(element.name)
: parent.getSetter(element.name);
}
return null;
}
JS.Expression _emitConstructorName(DartType type, String name) {
return _emitJSInterop(type.element) ??
JS.PropertyAccess(_emitConstructorAccess(type), _constructorName(name));
@ -6219,15 +6151,6 @@ class CodeGenerator extends Object
() => JS.TemporaryId(jsLibraryName(_libraryRoot, library)));
}
T closureAnnotate<T extends JS.Node>(
T node, Element element, AnnotatedNode original) {
if (options.closure) {
node.closureAnnotation =
closureAnnotationFor(node, original, element, namedArgumentTemp.name);
}
return node;
}
/// Return true if this is one of the methods/properties on all Dart Objects
/// (toString, hashCode, noSuchMethod, runtimeType).
///

View file

@ -1,127 +0,0 @@
// 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.
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import '../js_ast/js_ast.dart' as JS;
import 'module_compiler.dart' show CompilerOptions;
import 'js_interop.dart';
/// Mixin with logic to generate [TypeRef]s out of [DartType]s.
abstract class JSTypeRefCodegen {
final _resolved = <DartType, JS.TypeRef>{};
// Mixin dependencies:
CompilerOptions get options;
TypeProvider get types;
LibraryElement get dartJSLibrary;
JS.Identifier get namedArgumentTemp;
JS.Identifier emitLibraryName(LibraryElement e);
/// Finds the qualified path to the type.
JS.TypeRef _emitTopLevelTypeRef(DartType type) {
var e = type.element;
return JS.TypeRef.qualified([
emitLibraryName(e.library),
JS.Identifier(getJSExportName(e) ?? e.name)
]);
}
JS.TypeRef emitTypeRef(DartType type) {
if (!options.closure) return null;
return _resolved.putIfAbsent(type, () {
if (type == null) JS.TypeRef.unknown();
// TODO(ochafik): Consider calling _loader.declareBeforeUse(type.element).
if (type.isBottom || type.isDynamic) JS.TypeRef.any();
if (type.isVoid) return JS.TypeRef.void_();
if (type == types.intType) return JS.TypeRef.number().orNull();
if (type == types.numType) return JS.TypeRef.number().orNull();
if (type == types.doubleType) return JS.TypeRef.number().orNull();
if (type == types.boolType) return JS.TypeRef.boolean().orNull();
if (type == types.stringType) return JS.TypeRef.string();
if (type is TypeParameterType) return 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.isNamed) break;
var type = emitTypeRef(param.type);
args[JS.Identifier(param.name)] =
param.isPositional ? type.toOptional() : type;
}
var namedParamType = emitNamedParamsArgType(type.parameters);
if (namedParamType != null) {
args[namedArgumentTemp] = namedParamType.toOptional();
}
rawType = 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
: JS.TypeRef.generic(rawType, typeArgs);
}
return JS.TypeRef.unknown();
});
}
JS.TypeRef emitNamedParamsArgType(Iterable<ParameterElement> params) {
if (!options.closure) return null;
var namedArgs = <JS.Identifier, JS.TypeRef>{};
for (ParameterElement param in params) {
if (param.isPositional) continue;
namedArgs[JS.Identifier(param.name)] =
emitTypeRef(param.type).toOptional();
}
if (namedArgs.isEmpty) return null;
return 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) {
if (type.element.library == dartJSLibrary) {
switch (type.name) {
case 'JsArray':
return JS.TypeRef.array(
type is InterfaceType && type.typeArguments.length == 1
? emitTypeRef(type.typeArguments.single)
: null);
case 'JsObject':
return JS.TypeRef.object();
case 'JsFunction':
return JS.TypeRef.function();
}
}
return null;
}
}

View file

@ -6,8 +6,7 @@ import 'dart:collection' show HashSet, Queue;
import 'dart:convert' show json;
import 'dart:io' show File;
import 'package:analyzer/analyzer.dart'
show AnalysisError, CompilationUnit, ErrorSeverity;
import 'package:analyzer/analyzer.dart' show AnalysisError, CompilationUnit;
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/element/element.dart'
show LibraryElement, UriReferencedElement;
@ -16,7 +15,6 @@ import 'package:analyzer/file_system/physical_file_system.dart'
show PhysicalResourceProvider;
import 'package:analyzer/src/context/builder.dart' show ContextBuilder;
import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
import 'package:analyzer/src/error/codes.dart' show StaticTypeWarningCode;
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine;
import 'package:analyzer/src/generated/sdk.dart' show DartSdkManager;
@ -129,21 +127,6 @@ class ModuleCompiler {
return ModuleCompiler._(context, summaryData);
}
bool _isFatalError(AnalysisError e, CompilerOptions options) {
if (errorSeverity(context, e) != ErrorSeverity.ERROR) return false;
// These errors are not fatal in the REPL compile mode as we
// allow access to private members across library boundaries
// and those accesses will show up as undefined members unless
// additional analyzer changes are made to support them.
// TODO(jacobr): consider checking that the identifier name
// referenced by the error is private.
return !options.replCompile ||
(e.errorCode != StaticTypeWarningCode.UNDEFINED_GETTER &&
e.errorCode != StaticTypeWarningCode.UNDEFINED_SETTER &&
e.errorCode != StaticTypeWarningCode.UNDEFINED_METHOD);
}
/// Compiles a single Dart build unit into a JavaScript module.
///
/// *Warning* - this may require resolving the entire world.
@ -263,9 +246,6 @@ class CompilerOptions {
/// to private members across library boundaries.
final bool replCompile;
/// Whether to emit Closure Compiler-friendly code.
final bool closure;
/// Mapping from absolute file paths to bazel short path to substitute in
/// source maps.
final Map<String, String> bazelMapping;
@ -284,7 +264,6 @@ class CompilerOptions {
this.replCompile = false,
this.emitMetadata = false,
this.enableAsserts = true,
this.closure = false,
this.bazelMapping = const {},
this.summaryOutPath});
@ -298,7 +277,6 @@ class CompilerOptions {
replCompile = args['repl-compile'] as bool,
emitMetadata = args['emit-metadata'] as bool,
enableAsserts = args['enable-asserts'] as bool,
closure = args['closure-experimental'] as bool,
bazelMapping =
_parseBazelMappings(args['bazel-mapping'] as List<String>),
summaryOutPath = args['summary-out'] as String;
@ -432,9 +410,7 @@ class JSModuleFile {
JSModuleCode getCode(ModuleFormat format, String jsUrl, String mapUrl,
{bool singleOutFile = false}) {
var opts = JS.JavaScriptPrintingOptions(
emitTypes: options.closure,
allowKeywordsInProperties: true,
allowSingleLineIfStatements: true);
allowKeywordsInProperties: true, allowSingleLineIfStatements: true);
JS.SimpleJavaScriptPrintingContext printer;
SourceMapBuilder sourceMap;
if (options.sourceMap) {

View file

@ -1,133 +0,0 @@
// 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.
import '../js_ast/js_ast.dart' as JS show TypeRef, ClosureTypePrinter;
/// Set of closure annotations that can be [toString]ed to a single JsDoc comment.
/// See https://developers.google.com/closure/compiler/docs/js-for-compiler
///
/// TODO(ochafik): Support inclusion of 'normal' comments (including @param comments).
class ClosureAnnotation {
final String comment;
final bool isConst;
final bool isConstructor;
final bool isFinal;
final bool isNoCollapse;
final bool isNoSideEffects;
final bool isOverride;
final bool isPrivate;
final bool isProtected;
final bool isStruct;
final bool isTypedef;
final JS.TypeRef lendsToType;
final JS.TypeRef returnType;
final JS.TypeRef superType;
final JS.TypeRef thisType;
final JS.TypeRef throwsType;
final JS.TypeRef type;
final List<JS.TypeRef> interfaces;
final List<String> templates;
final Map<String, JS.TypeRef> paramTypes;
ClosureAnnotation(
{this.comment,
this.interfaces = const [],
this.isConst = false,
this.isConstructor = false,
this.isFinal = false,
this.isNoCollapse = false,
this.isNoSideEffects = false,
this.isOverride = false,
this.isPrivate = false,
this.isProtected = false,
this.isStruct = false,
this.isTypedef = false,
this.lendsToType,
this.paramTypes = const {},
this.returnType,
this.superType,
this.templates = const [],
this.thisType,
this.throwsType,
this.type});
@override
int get hashCode => _cachedString.hashCode;
@override
bool operator ==(other) =>
other is ClosureAnnotation && _cachedString == other._cachedString;
@override
String toString([String indent = '']) =>
_cachedString.replaceAll('\n', '\n$indent');
String _print(JS.TypeRef t) => (JS.ClosureTypePrinter()..visit(t)).toString();
String __cachedString;
String get _cachedString {
if (__cachedString == null) {
bool isNonWildcard(JS.TypeRef t) => t != null && !t.isAny && !t.isUnknown;
var lines = <String>[];
if (comment != null) lines.addAll(comment.split('\n'));
if (templates != null && templates.isNotEmpty) {
lines.add('@template ${templates.join(', ')}');
}
if (thisType != null) lines.add('@this {${_print(thisType)}}');
if (isOverride) lines.add('@override');
if (isNoSideEffects) lines.add('@nosideeffects');
if (isNoCollapse) lines.add('@nocollapse');
if (lendsToType != null) lines.add('@lends {${_print(lendsToType)}}');
{
var typeHolders = <String>[];
if (isPrivate) typeHolders.add('@private');
if (isProtected) typeHolders.add('@protected');
if (isFinal) typeHolders.add('@final');
if (isConst) typeHolders.add('@const');
if (isTypedef) typeHolders.add('@typedef');
if (isNonWildcard(type)) {
if (typeHolders.isEmpty) typeHolders.add('@type');
typeHolders.add('{${_print(type)}}');
}
if (!typeHolders.isEmpty) lines.add(typeHolders.join(' '));
}
{
List constructorLine = [];
if (isConstructor) constructorLine.add('@constructor');
if (isStruct) constructorLine.add('@struct');
if (isNonWildcard(superType)) {
constructorLine.add('@extends {${_print(superType)}}');
}
if (constructorLine.isNotEmpty) lines.add(constructorLine.join(' '));
}
if (interfaces != null) {
for (var interface in interfaces) {
if (isNonWildcard(interface))
lines.add('@implements {${_print(interface)}}');
}
}
if (paramTypes != null) {
paramTypes.forEach((String paramName, JS.TypeRef paramType) {
// Must output params even with wildcard type.
lines.add('@param {${_print(paramType)}} $paramName');
});
}
if (isNonWildcard(returnType))
lines.add('@return {${_print(returnType)}}');
if (isNonWildcard(throwsType))
lines.add('@throws {${_print(throwsType)}}');
if (lines.length == 0) return '';
if (lines.length == 1) return '/** ${lines.single} */';
__cachedString = '/**\n' + lines.map((l) => ' * $l').join('\n') + '\n */';
}
return __cachedString;
}
}

View file

@ -1,38 +0,0 @@
// 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.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import '../js_ast/js_ast.dart' as JS show Node, TypeRef;
import 'closure_annotation.dart';
/// Mixin that can generate [ClosureAnnotation]s for Dart elements and types.
abstract class ClosureAnnotator {
TypeProvider get types;
JS.TypeRef emitTypeRef(DartType type);
// TODO(ochafik): Handle destructured params when Closure supports it.
ClosureAnnotation closureAnnotationFor(JS.Node node, AnnotatedNode original,
Element e, String namedArgsMapName) {
// Note: Dart and Closure privacy are not compatible: don't set `isPrivate: e.isPrivate`.
return ClosureAnnotation(
comment: original?.documentationComment?.toSource(),
// Note: we don't set isConst here because Closure's constness and
// Dart's are not really compatible.
isFinal: e is VariableElement && (e.isFinal || e.isConst),
type: e is VariableElement
? emitTypeRef(e.type /*, forceTypeDefExpansion: true*/)
: null,
superType: e is ClassElement ? emitTypeRef(e.supertype) : null,
interfaces:
e is ClassElement ? e.interfaces.map(emitTypeRef).toList() : null,
isOverride: e.isOverride,
isTypedef: e is FunctionTypeAliasElement);
}
}

View file

@ -1,85 +0,0 @@
// 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.
/// Poor-man's representation of a Closure type.
/// See https://developers.google.com/closure/compiler/docs/js-for-compiler
///
/// The goal here is not to completely support Closure's type system, but to
/// be able to generate just the types needed for DDC's JS output.
///
/// TODO(ochafik): Consider convergence with TypeScript, which has no nullability-awareness
/// (see http://www.typescriptlang.org/Handbook).
class ClosureType {
static const ClosureType _ALL = ClosureType._("*");
static const ClosureType _UNKNOWN = ClosureType._("?");
final String _representation;
final bool isNullable;
const ClosureType._(this._representation, {this.isNullable = true});
bool get isAll => _representation == "*";
bool get isUnknown => _representation == "?";
@override
toString() => _representation;
factory ClosureType.all() => _ALL;
factory ClosureType.unknown() => _UNKNOWN;
factory ClosureType.record(Map<String, ClosureType> fieldTypes) {
var entries = <String>[];
fieldTypes.forEach((n, t) => entries.add('$n: $t'));
return ClosureType._('{${entries.join(', ')}}');
}
factory ClosureType.function(
[List<ClosureType> paramTypes, ClosureType returnType]) {
if (paramTypes == null && returnType == null) {
return ClosureType.type("Function");
}
var suffix = returnType == null ? '' : ':$returnType';
return ClosureType._(
'function(${paramTypes == null ? '...*' : paramTypes.join(', ')})$suffix');
}
factory ClosureType.map([ClosureType keyType, ClosureType valueType]) =>
ClosureType._("Object<${keyType ?? _ALL}, ${valueType ?? _ALL}>");
factory ClosureType.type([String className = "Object"]) =>
ClosureType._(className);
factory ClosureType.array([ClosureType componentType]) =>
ClosureType._("Array<${componentType ?? _ALL}>");
factory ClosureType.undefined() =>
ClosureType._("undefined", isNullable: false);
factory ClosureType.number() => ClosureType._("number", isNullable: false);
factory ClosureType.boolean() => ClosureType._("boolean", isNullable: false);
factory ClosureType.string() => ClosureType._("string");
ClosureType toOptional() => ClosureType._("$this=");
ClosureType toNullable() => isNullable
? this
: ClosureType._(
_representation.startsWith('!')
? _representation.substring(1)
: "?$this",
isNullable: true);
ClosureType toNonNullable() => !isNullable
? this
: ClosureType._(
_representation.startsWith('?')
? _representation.substring(1)
: "!$this",
isNullable: false);
/// TODO(ochafik): See which optimizations make sense here (it could be that `(*|undefined)`
/// cannot be optimized to `*` when used to model optional record fields).
ClosureType or(ClosureType other) => ClosureType._("($this|$other)",
isNullable: isNullable || other.isNullable);
ClosureType orUndefined() => or(ClosureType.undefined());
}

View file

@ -17,8 +17,7 @@ Fun simplifyPassThroughArrowFunCallBody(Fun fn) {
innerFun.params.isEmpty) {
var body = innerFun.body;
if (body is Block) {
return Fun(fn.params, body,
typeParams: fn.typeParams, returnType: fn.returnType);
return Fun(fn.params, body);
}
}
}

View file

@ -6,11 +6,8 @@ library js_ast;
import 'precedence.dart';
import 'characters.dart' as charCodes;
import '../closure/closure_annotation.dart';
part 'nodes.dart';
part 'builder.dart';
part 'js_types.dart';
part 'printer.dart';
part 'template.dart';
part 'type_printer.dart';

View file

@ -1,202 +0,0 @@
// Copyright (c) 2016, 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_ast;
final _any = AnyTypeRef._();
final _unknown = UnknownTypeRef._();
final _null = NullTypeRef();
/// JavaScript type reference, designed to support a subset of the type systems
/// of the Closure Compiler and TypeScript:
/// - https://developers.google.com/closure/compiler/docs/js-for-compiler#types
/// - https://github.com/Microsoft/TypeScript/blob/v1.8.0-beta/doc/spec.md#3
///
/// Note that some subtleties like "nullability" or "optionality" are handled
/// using unions (with a [NullTypeRef] or with an "undefined" named typeref).
/// Also, primitives aren't modeled differently than named / qualified types,
/// as it brings little value for now. Primitive-specific type formatting is
/// handled by the type printers (for instance, the knowledge that
/// `number|null` is just `number` in TypeScript, and is `number?` in Closure).
abstract class TypeRef extends Expression {
int get precedenceLevel => PRIMARY;
TypeRef();
factory TypeRef.any() => _any;
factory TypeRef.void_() => TypeRef.named('void');
factory TypeRef.unknown() => _unknown;
factory TypeRef.generic(TypeRef rawType, Iterable<TypeRef> typeArgs) {
if (typeArgs.isEmpty) {
throw ArgumentError.value(typeArgs, "typeArgs", "is empty");
}
return GenericTypeRef(rawType, typeArgs.toList());
}
factory TypeRef.array([TypeRef elementType]) => ArrayTypeRef(elementType);
factory TypeRef.object([TypeRef keyType, TypeRef valueType]) {
// TODO(ochafik): Roll out a dedicated ObjectTypeRef?
var rawType = TypeRef.named('Object');
return keyType == null && valueType == null
? rawType
: GenericTypeRef(rawType, [keyType ?? _any, valueType ?? _any]);
}
factory TypeRef.function(
[TypeRef returnType, Map<Identifier, TypeRef> paramTypes]) =>
FunctionTypeRef(returnType, paramTypes);
factory TypeRef.record(Map<Identifier, TypeRef> types) =>
RecordTypeRef(types);
factory TypeRef.string() => TypeRef.named('string');
factory TypeRef.number() => TypeRef.named('number');
factory TypeRef.undefined() => TypeRef.named('undefined');
factory TypeRef.boolean() => TypeRef.named('boolean');
factory TypeRef.qualified(List<Identifier> path) => QualifiedTypeRef(path);
factory TypeRef.named(String name) =>
TypeRef.qualified(<Identifier>[Identifier(name)]);
bool get isAny => this is AnyTypeRef;
bool get isUnknown => this is UnknownTypeRef;
bool get isNull => this is NullTypeRef;
TypeRef or(TypeRef other) => UnionTypeRef([this, other]);
TypeRef orUndefined() => or(TypeRef.undefined());
TypeRef orNull() => or(_null);
TypeRef toOptional() => OptionalTypeRef(this);
}
class AnyTypeRef extends TypeRef {
AnyTypeRef._() : super();
factory AnyTypeRef() => _any;
T accept<T>(NodeVisitor<T> visitor) => visitor.visitAnyTypeRef(this);
void visitChildren(NodeVisitor visitor) {}
_clone() => AnyTypeRef();
}
class NullTypeRef extends QualifiedTypeRef {
NullTypeRef() : super([Identifier("null")]);
_clone() => NullTypeRef();
}
class UnknownTypeRef extends TypeRef {
UnknownTypeRef._() : super();
factory UnknownTypeRef() => _unknown;
T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnknownTypeRef(this);
void visitChildren(NodeVisitor visitor) {}
_clone() => UnknownTypeRef();
}
class QualifiedTypeRef extends TypeRef {
final List<Identifier> path;
QualifiedTypeRef(this.path);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitQualifiedTypeRef(this);
void visitChildren(NodeVisitor visitor) =>
path.forEach((p) => p.accept(visitor));
_clone() => QualifiedTypeRef(path);
}
class ArrayTypeRef extends TypeRef {
final TypeRef elementType;
ArrayTypeRef(this.elementType);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrayTypeRef(this);
void visitChildren(NodeVisitor visitor) {
elementType.accept(visitor);
}
_clone() => ArrayTypeRef(elementType);
}
class GenericTypeRef extends TypeRef {
final TypeRef rawType;
final List<TypeRef> typeArgs;
GenericTypeRef(this.rawType, this.typeArgs);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitGenericTypeRef(this);
void visitChildren(NodeVisitor visitor) {
rawType.accept(visitor);
typeArgs.forEach((p) => p.accept(visitor));
}
_clone() => GenericTypeRef(rawType, typeArgs);
}
class UnionTypeRef extends TypeRef {
final List<TypeRef> types;
UnionTypeRef(this.types);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitUnionTypeRef(this);
void visitChildren(NodeVisitor visitor) {
types.forEach((p) => p.accept(visitor));
}
_clone() => UnionTypeRef(types);
@override
TypeRef or(TypeRef other) {
if (types.contains(other)) return this;
return UnionTypeRef([]
..addAll(types)
..add(other));
}
}
class OptionalTypeRef extends TypeRef {
final TypeRef type;
OptionalTypeRef(this.type);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitOptionalTypeRef(this);
void visitChildren(NodeVisitor visitor) {
type.accept(visitor);
}
_clone() => OptionalTypeRef(type);
@override
TypeRef orUndefined() => this;
}
class RecordTypeRef extends TypeRef {
final Map<Identifier, TypeRef> types;
RecordTypeRef(this.types);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitRecordTypeRef(this);
void visitChildren(NodeVisitor visitor) {
types.values.forEach((p) => p.accept(visitor));
}
_clone() => RecordTypeRef(types);
}
class FunctionTypeRef extends TypeRef {
final TypeRef returnType;
final Map<Identifier, TypeRef> paramTypes;
FunctionTypeRef(this.returnType, this.paramTypes);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFunctionTypeRef(this);
void visitChildren(NodeVisitor visitor) {
returnType.accept(visitor);
paramTypes.forEach((n, t) {
n.accept(visitor);
t.accept(visitor);
});
}
_clone() => FunctionTypeRef(returnType, paramTypes);
}

View file

@ -4,7 +4,7 @@
part of js_ast;
abstract class NodeVisitor<T> implements TypeRefVisitor<T> {
abstract class NodeVisitor<T> {
T visitProgram(Program node);
T visitBlock(Block node);
@ -95,18 +95,6 @@ abstract class NodeVisitor<T> implements TypeRefVisitor<T> {
T visitSimpleBindingPattern(SimpleBindingPattern node);
}
abstract class TypeRefVisitor<T> {
T visitQualifiedTypeRef(QualifiedTypeRef node);
T visitGenericTypeRef(GenericTypeRef node);
T visitUnionTypeRef(UnionTypeRef node);
T visitRecordTypeRef(RecordTypeRef node);
T visitOptionalTypeRef(OptionalTypeRef node);
T visitFunctionTypeRef(FunctionTypeRef node);
T visitAnyTypeRef(AnyTypeRef node);
T visitUnknownTypeRef(UnknownTypeRef node);
T visitArrayTypeRef(ArrayTypeRef node);
}
class BaseVisitor<T> implements NodeVisitor<T> {
T visitNode(Node node) {
node.visitChildren(this);
@ -229,17 +217,6 @@ class BaseVisitor<T> implements NodeVisitor<T> {
visitBindingPattern(node);
T visitDestructuredVariable(DestructuredVariable node) => visitNode(node);
T visitSimpleBindingPattern(SimpleBindingPattern node) => visitNode(node);
T visitTypeRef(TypeRef node) => visitNode(node);
T visitQualifiedTypeRef(QualifiedTypeRef node) => visitTypeRef(node);
T visitGenericTypeRef(GenericTypeRef node) => visitTypeRef(node);
T visitOptionalTypeRef(OptionalTypeRef node) => visitTypeRef(node);
T visitRecordTypeRef(RecordTypeRef node) => visitTypeRef(node);
T visitUnionTypeRef(UnionTypeRef node) => visitTypeRef(node);
T visitFunctionTypeRef(FunctionTypeRef node) => visitTypeRef(node);
T visitAnyTypeRef(AnyTypeRef node) => visitTypeRef(node);
T visitUnknownTypeRef(UnknownTypeRef node) => visitTypeRef(node);
T visitArrayTypeRef(ArrayTypeRef node) => visitTypeRef(node);
}
abstract class Node {
@ -247,9 +224,6 @@ abstract class Node {
/// setting this after construction.
Object sourceInformation;
/// Closure annotation of this node.
ClosureAnnotation closureAnnotation;
T accept<T>(NodeVisitor<T> visitor);
void visitChildren(NodeVisitor visitor);
@ -892,13 +866,9 @@ class DestructuredVariable extends Expression implements Parameter {
final BindingPattern structure;
final Expression defaultValue;
final TypeRef type;
DestructuredVariable(
{this.name,
this.property,
this.structure,
this.defaultValue,
this.type}) {
{this.name, this.property, this.structure, this.defaultValue}) {
assert(name != null || structure != null);
}
@ -1177,16 +1147,13 @@ class Postfix extends Expression {
int get precedenceLevel => UNARY;
}
abstract class Parameter implements Expression, VariableBinding {
TypeRef get type;
}
abstract class Parameter implements Expression, VariableBinding {}
class Identifier extends Expression implements Parameter {
final String name;
final bool allowRename;
final TypeRef type;
Identifier(this.name, {this.allowRename = true, this.type}) {
Identifier(this.name, {this.allowRename = true}) {
if (!_identifierRE.hasMatch(name)) {
throw ArgumentError.value(name, "name", "not a valid identifier");
}
@ -1204,7 +1171,6 @@ class Identifier extends Expression implements Parameter {
// This is an expression for convenience in the AST.
class RestParameter extends Expression implements Parameter {
final Identifier parameter;
TypeRef get type => null;
RestParameter(this.parameter);
@ -1278,24 +1244,13 @@ class NamedFunction extends Expression {
}
abstract class FunctionExpression extends Expression {
Node get body; // Expression or block
List<Parameter> get params;
get body; // Expression or block
/// Type parameters passed to this generic function, if any. `null` otherwise.
// TODO(ochafik): Support type bounds.
List<Identifier> get typeParams;
/// Return type of this function, if any. `null` otherwise.
TypeRef get returnType;
}
class Fun extends FunctionExpression {
final List<Parameter> params;
final Block body;
@override
final List<Identifier> typeParams;
@override
final TypeRef returnType;
/** Whether this is a JS generator (`function*`) that may contain `yield`. */
final bool isGenerator;
@ -1304,9 +1259,7 @@ class Fun extends FunctionExpression {
Fun(this.params, this.body,
{this.isGenerator = false,
this.asyncModifier = const AsyncModifier.sync(),
this.typeParams,
this.returnType});
this.asyncModifier = const AsyncModifier.sync()});
T accept<T>(NodeVisitor<T> visitor) => visitor.visitFun(this);
@ -1324,12 +1277,8 @@ class Fun extends FunctionExpression {
class ArrowFun extends FunctionExpression {
final List<Parameter> params;
final body; // Expression or Block
@override
final List<Identifier> typeParams;
@override
final TypeRef returnType;
ArrowFun(this.params, this.body, {this.typeParams, this.returnType});
ArrowFun(this.params, this.body);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitArrowFun(this);
@ -1627,15 +1576,7 @@ class ClassExpression extends Expression {
final Expression heritage; // Can be null.
final List<Method> methods;
/// Type parameters of this class, if any. `null` otherwise.
// TODO(ochafik): Support type bounds.
final List<Identifier> typeParams;
/// Field declarations of this class (TypeScript / ES6_TYPED).
final List<VariableDeclarationList> fields;
ClassExpression(this.name, this.heritage, this.methods,
{this.typeParams, this.fields});
ClassExpression(this.name, this.heritage, this.methods);
T accept<T>(NodeVisitor<T> visitor) => visitor.visitClassExpression(this);
@ -1643,23 +1584,12 @@ class ClassExpression extends Expression {
name.accept(visitor);
if (heritage != null) heritage.accept(visitor);
for (Method element in methods) element.accept(visitor);
if (fields != null) {
for (var field in fields) {
field.accept(visitor);
}
}
if (typeParams != null) {
for (var typeParam in typeParams) {
typeParam.accept(visitor);
}
}
}
@override
ClassDeclaration toStatement() => ClassDeclaration(this);
ClassExpression _clone() => ClassExpression(name, heritage, methods,
typeParams: typeParams, fields: fields);
ClassExpression _clone() => ClassExpression(name, heritage, methods);
int get precedenceLevel => PRIMARY_LOW_PRECEDENCE;
}
@ -1726,7 +1656,6 @@ class InterpolatedParameter extends Expression
with InterpolatedNode
implements Identifier {
final nameOrPosition;
TypeRef get type => null;
String get name {
throw "InterpolatedParameter.name must not be invoked";
@ -1797,7 +1726,6 @@ class InterpolatedIdentifier extends Expression
with InterpolatedNode
implements Identifier {
final nameOrPosition;
TypeRef get type => null;
InterpolatedIdentifier(this.nameOrPosition);

View file

@ -8,7 +8,6 @@ class JavaScriptPrintingOptions {
final bool shouldCompressOutput;
final bool minifyLocalVariables;
final bool preferSemicolonToNewlineInMinifiedOutput;
final bool emitTypes;
final bool allowSingleLineIfStatements;
/// True to allow keywords in properties, such as `obj.var` or `obj.function`
@ -19,7 +18,6 @@ class JavaScriptPrintingOptions {
{this.shouldCompressOutput = false,
this.minifyLocalVariables = false,
this.preferSemicolonToNewlineInMinifiedOutput = false,
this.emitTypes = false,
this.allowKeywordsInProperties = false,
this.allowSingleLineIfStatements = false});
}
@ -58,7 +56,7 @@ class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext {
// TODO(ochafik): Inline the body of [TypeScriptTypePrinter] here if/when it no
// longer needs to share utils with [ClosureTypePrinter].
class Printer extends TypeScriptTypePrinter implements NodeVisitor {
class Printer implements NodeVisitor {
final JavaScriptPrintingOptions options;
final JavaScriptPrintingContext context;
final bool shouldCompressOutput;
@ -296,7 +294,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
visitExpressionStatement(ExpressionStatement expressionStatement) {
indent();
outClosureAnnotation(expressionStatement);
visitNestedExpression(expressionStatement.expression, EXPRESSION,
newInForInit: false, newAtStatementBegin: true);
outSemicolonLn();
@ -558,14 +555,12 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
newInForInit: false, newAtStatementBegin: false);
}
localNamer.enterScope(fun);
outTypeParams(fun.typeParams);
out("(");
if (fun.params != null) {
visitCommaSeparated(fun.params, PRIMARY,
newInForInit: false, newAtStatementBegin: false);
}
out(")");
outTypeAnnotation(fun.returnType);
switch (fun.asyncModifier) {
case const AsyncModifier.sync():
break;
@ -585,7 +580,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
visitFunctionDeclaration(FunctionDeclaration declaration) {
indent();
outClosureAnnotation(declaration);
var f = declaration.function;
context.enterNode(f);
functionOut(f, declaration.name);
@ -623,7 +617,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
}
visitVariableDeclarationList(VariableDeclarationList list) {
outClosureAnnotation(list);
// Note: keyword can be null for non-static field declarations.
if (list.keyword != null) {
out(list.keyword);
@ -665,7 +658,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
}
visit(structure);
}
outTypeAnnotation(node.type);
var defaultValue = node.defaultValue;
if (defaultValue != null) {
spaceOut();
@ -695,7 +687,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
}
visitVariableInitialization(VariableInitialization init) {
outClosureAnnotation(init);
visitNestedExpression(init.declaration, LEFT_HAND_SIDE,
newInForInit: inForInit, newAtStatementBegin: atStatementBegin);
if (init.value != null) {
@ -898,7 +889,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
visitIdentifier(Identifier node) {
out(localNamer.getName(node));
outTypeAnnotation(node.type);
}
visitRestParameter(RestParameter node) {
@ -966,9 +956,7 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
visitArrowFun(ArrowFun fun) {
localNamer.enterScope(fun);
if (fun.params.length == 1 &&
fun.params[0] is Identifier &&
(!options.emitTypes || fun.params[0].type == null)) {
if (fun.params.length == 1 && fun.params[0] is Identifier) {
visitNestedExpression(fun.params.single, SPREAD,
newInForInit: false, newAtStatementBegin: false);
} else {
@ -977,7 +965,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
newInForInit: false, newAtStatementBegin: false);
out(")");
}
outTypeAnnotation(fun.returnType);
spaceOut();
out("=>");
var body = fun.body;
@ -1116,24 +1103,10 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
lineOut();
}
void outTypeParams(Iterable<Identifier> typeParams) {
if (typeParams != null && options.emitTypes && typeParams.isNotEmpty) {
out("<");
var first = true;
for (var typeParam in typeParams) {
if (!first) out(", ");
first = false;
visit(typeParam);
}
out(">");
}
}
visitClassExpression(ClassExpression node) {
localNamer.enterScope(node);
out('class ');
visit(node.name);
outTypeParams(node.typeParams);
if (node.heritage != null) {
out(' extends ');
visit(node.heritage);
@ -1143,14 +1116,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
out('{');
lineOut();
indentMore();
if (options.emitTypes && node.fields != null) {
for (var field in node.fields) {
indent();
visit(field);
out(";");
lineOut();
}
}
for (var method in node.methods) {
indent();
visit(method);
@ -1166,7 +1131,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
}
visitMethod(Method node) {
outClosureAnnotation(node);
if (node.isStatic) {
out('static ');
}
@ -1198,17 +1162,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
localNamer.leaveScope();
}
void outClosureAnnotation(Node node) {
if (node != null && node.closureAnnotation != null) {
String comment = node.closureAnnotation.toString(indentation);
if (comment.isNotEmpty) {
out(comment);
lineOut();
indent();
}
}
}
void propertyNameOut(Expression node,
{bool inMethod = false, bool inAccess = false}) {
if (node is LiteralNumber) {
@ -1404,18 +1357,6 @@ class Printer extends TypeScriptTypePrinter implements NodeVisitor {
out("await ");
visit(node.expression);
}
void outTypeAnnotation(TypeRef node) {
if (node == null || !options.emitTypes || node.isUnknown) return;
if (node is OptionalTypeRef) {
out("?: ");
visit(node.type);
} else {
out(": ");
visit(node);
}
}
}
// Collects all the var declarations in the function. We need to do this in a

View file

@ -598,7 +598,7 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator<ArrowFun> visitArrowFun(ArrowFun node) {
var paramMakers = node.params.map(visitSplayable).toList();
Instantiator makeBody = visit(node.body as Node);
Instantiator makeBody = visit(node.body);
return (a) => ArrowFun(splayNodes(paramMakers, a), makeBody(a));
}
@ -700,32 +700,6 @@ class InstantiatorGeneratorVisitor implements NodeVisitor<Instantiator> {
Instantiator visitExportClause(ExportClause node) =>
throw UnimplementedError();
Instantiator visitAnyTypeRef(AnyTypeRef node) => throw UnimplementedError();
Instantiator visitUnknownTypeRef(UnknownTypeRef node) =>
throw UnimplementedError();
Instantiator visitArrayTypeRef(ArrayTypeRef node) =>
throw UnimplementedError();
Instantiator visitFunctionTypeRef(FunctionTypeRef node) =>
throw UnimplementedError();
Instantiator visitGenericTypeRef(GenericTypeRef node) =>
throw UnimplementedError();
Instantiator visitQualifiedTypeRef(QualifiedTypeRef node) =>
throw UnimplementedError();
Instantiator visitOptionalTypeRef(OptionalTypeRef node) =>
throw UnimplementedError();
Instantiator visitRecordTypeRef(RecordTypeRef node) =>
throw UnimplementedError();
Instantiator visitUnionTypeRef(UnionTypeRef node) =>
throw UnimplementedError();
@override
Instantiator<DestructuredVariable> visitDestructuredVariable(
DestructuredVariable node) {

View file

@ -1,227 +0,0 @@
// Copyright (c) 2016, 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_ast;
abstract class _TypePrinterBase implements TypeRefVisitor {
void out(String s);
void visit(Node node);
void outSeparated<T extends Node>(String separator, Iterable<T> items,
[action(T item)]) {
action ??= visit;
var first = true;
for (var item in items) {
if (first) {
first = false;
} else {
out(separator);
}
action(item);
}
}
void outTypeArg(Iterable<TypeRef> typeArgs) {
if (typeArgs.isNotEmpty) {
// TODO(ochafik): Double-check precedence issues when we start emitting
// type arguments outside type literals (generic method call, etc).
out('<');
outSeparated(", ", typeArgs);
out('>');
}
}
@override
visitQualifiedTypeRef(QualifiedTypeRef node) {
outSeparated(".", node.path);
}
}
abstract class TypeScriptTypePrinter extends _TypePrinterBase {
void _outTypeAnnotation(TypeRef type) {
if (type is OptionalTypeRef) {
out("?: ");
visit(type.type);
} else {
out(": ");
visit(type);
}
}
@override
visitGenericTypeRef(GenericTypeRef node) {
if (node.rawType is FunctionTypeRef) {
outTypeArg(node.typeArgs);
visit(node.rawType);
} else {
visit(node.rawType);
outTypeArg(node.typeArgs);
}
}
@override
visitArrayTypeRef(ArrayTypeRef node) {
if (node.elementType == null) {
out("Array");
} else {
visit(node.elementType);
out("[]");
}
}
@override
visitOptionalTypeRef(OptionalTypeRef node) {
visit(node.type);
}
@override
visitRecordTypeRef(RecordTypeRef node) {
out('{');
outSeparated(", ", node.types.keys, (Identifier name) {
var type = node.types[name];
visit(name);
_outTypeAnnotation(type);
});
out('}');
}
@override
visitUnionTypeRef(UnionTypeRef node) {
outSeparated("|", node.types.where((t) => !t.isNull));
}
@override
visitFunctionTypeRef(FunctionTypeRef node) {
if (node.returnType == null) {
out('Function');
} else {
out('(');
if (node.paramTypes == null) {
out('...any');
} else {
outSeparated(", ", node.paramTypes.keys, (Identifier name) {
var paramType = node.paramTypes[name];
visit(name);
_outTypeAnnotation(paramType);
});
}
out(') => ');
visit(node.returnType);
}
}
@override
visitAnyTypeRef(AnyTypeRef node) {
out("any");
}
@override
visitUnknownTypeRef(UnknownTypeRef node) {
out("any");
}
}
class ClosureTypePrinter extends _TypePrinterBase implements NodeVisitor {
final _buffer = StringBuffer();
@override
void out(String s) => _buffer.write(s);
@override
void visit(Node node) => node.accept(this);
noSuchMethod(Invocation i) => super.noSuchMethod(i);
@override
visitGenericTypeRef(GenericTypeRef node) {
visit(node.rawType);
outTypeArg(node.typeArgs);
}
@override
visitIdentifier(Identifier node) {
//out(localNamer.getName(node));
out(node.name);
}
@override
visitAccess(PropertyAccess node) {
var selector = node.selector;
if (selector is LiteralString) {
visit(node.receiver);
out(".");
out(selector.valueWithoutQuotes);
} else {
assert(false);
out("?");
}
}
@override
toString() => _buffer.toString();
@override
visitArrayTypeRef(ArrayTypeRef node) {
out("Array");
if (node.elementType != null) {
out("<");
visit(node.elementType);
out(">");
}
}
@override
visitOptionalTypeRef(OptionalTypeRef node) {
visit(node.type);
out("=");
}
@override
visitRecordTypeRef(RecordTypeRef node) {
out('{');
outSeparated(", ", node.types.keys, (Identifier name) {
var type = node.types[name];
visit(name);
out(": ");
visit(type is OptionalTypeRef ? type.orUndefined() : type);
});
out('}');
}
@override
visitAnyTypeRef(AnyTypeRef node) {
out("*");
}
@override
visitUnknownTypeRef(UnknownTypeRef node) {
out("?");
}
@override
visitUnionTypeRef(UnionTypeRef node) {
out("(");
outSeparated("|", node.types);
out(")");
}
@override
visitFunctionTypeRef(FunctionTypeRef node) {
if (node.returnType == null) {
out('Function');
} else {
out('function(');
if (node.paramTypes == null) {
out("...*");
} else {
outSeparated(", ", node.paramTypes.values);
}
out(')');
if (node.returnType != null) {
out(":");
visit(node.returnType);
}
}
}
}

View file

@ -4839,8 +4839,7 @@ class ProgramCompiler extends Object
// Convert `function(...) { ... }` to `(...) => ...`
// This is for readability, but it also ensures correct `this` binding.
return JS.ArrowFun(f.params, body,
typeParams: f.typeParams, returnType: f.returnType);
return JS.ArrowFun(f.params, body);
}
@override

View file

@ -1,125 +0,0 @@
// 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.
library dev_compiler.test.closure_annotation_test;
import 'package:test/test.dart';
import 'package:dev_compiler/src/closure/closure_annotation.dart';
import 'package:dev_compiler/src/js_ast/js_ast.dart' show TypeRef, Identifier;
void main() {
group('ClosureAnnotation', () {
var anyType = TypeRef.any();
var unknownType = TypeRef.unknown();
var numberType = TypeRef.number();
var stringType = TypeRef.string();
var booleanType = TypeRef.boolean();
var fooType = TypeRef.qualified([Identifier("foo"), Identifier("Foo")]);
var barType = TypeRef.named("Bar");
var bazType = TypeRef.named("Baz");
var bamType = TypeRef.named("Bam");
var batType = TypeRef.named("Bat");
test('gives empty comment when no has no meaningful info', () {
expect(ClosureAnnotation().toString(), "");
expect(ClosureAnnotation(type: anyType).toString(), "");
expect(ClosureAnnotation(type: unknownType).toString(), "");
});
test('gives single line comment when it fits', () {
expect(ClosureAnnotation(type: numberType).toString(),
"/** @type {number} */");
expect(ClosureAnnotation(paramTypes: {'foo': anyType}).toString(),
"/** @param {*} foo */");
expect(ClosureAnnotation(paramTypes: {'foo': unknownType}).toString(),
"/** @param {?} foo */");
});
test('gives multiple line comment when it it does not fit on one line', () {
expect(
ClosureAnnotation(
returnType: stringType,
paramTypes: {'foo': numberType}).toString(),
"/**\n"
" * @param {number} foo\n"
" * @return {string}\n"
" */");
});
test('inserts indentation', () {
expect(
ClosureAnnotation(
returnType: stringType,
paramTypes: {'foo': numberType}).toString(" "),
"/**\n" // No indent on first line.
" * @param {number} foo\n"
" * @return {string}\n"
" */");
});
test('compresses @type, @final, @const, @private, @protected, @typedef',
() {
expect(ClosureAnnotation(type: stringType).toString(),
"/** @type {string} */");
expect(ClosureAnnotation(type: stringType, isConst: true).toString(),
"/** @const {string} */");
expect(ClosureAnnotation(type: stringType, isFinal: true).toString(),
"/** @final {string} */");
expect(ClosureAnnotation(type: stringType, isPrivate: true).toString(),
"/** @private {string} */");
expect(ClosureAnnotation(type: stringType, isTypedef: true).toString(),
"/** @typedef {string} */");
expect(ClosureAnnotation(type: stringType, isProtected: true).toString(),
"/** @protected {string} */");
expect(
ClosureAnnotation(
type: stringType,
isPrivate: true,
isConst: true,
isFinal: true,
isProtected: true,
isTypedef: true)
.toString(),
"/** @private @protected @final @const @typedef {string} */");
});
test('supports a full constructor annotation', () {
expect(
ClosureAnnotation(
returnType: booleanType,
throwsType: bamType,
thisType: fooType,
superType: barType,
lendsToType: batType,
interfaces: [bazType],
isStruct: true,
isPrivate: true,
isProtected: true,
isOverride: true,
isFinal: true,
isConst: true,
isConstructor: true,
isNoSideEffects: true,
isNoCollapse: true,
paramTypes: {'x': stringType, 'y': numberType},
templates: ['A', 'B']).toString(),
'/**\n'
' * @template A, B\n'
' * @this {foo.Foo}\n'
' * @override\n'
' * @nosideeffects\n'
' * @nocollapse\n'
' * @lends {Bat}\n'
' * @private @protected @final @const\n'
' * @constructor @struct @extends {Bar}\n'
' * @implements {Baz}\n'
' * @param {string} x\n'
' * @param {number} y\n'
' * @return {boolean}\n'
' * @throws {Bam}\n'
' */');
});
});
}

View file

@ -1,82 +0,0 @@
// 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.
library dev_compiler.test.closure_type_test;
import 'package:test/test.dart';
import 'package:dev_compiler/src/closure/closure_type.dart';
void main() {
expectToString(ClosureType t, String s,
{String nullable, String nonNullable}) {
expect(t.toString(), s);
if (nullable != null) {
expect(t.toNullable().toString(), nullable);
}
if (nonNullable != null) {
expect(t.toNonNullable().toString(), nonNullable);
}
}
group('ClosureType', () {
test('supports simple types', () {
expectToString(ClosureType.number(), "number",
nullable: "?number", nonNullable: "number");
expectToString(ClosureType.boolean(), "boolean",
nullable: "?boolean", nonNullable: "boolean");
expectToString(ClosureType.string(), "string",
nullable: "string", nonNullable: "!string");
expectToString(ClosureType.type("foo.Bar"), "foo.Bar",
nullable: "foo.Bar", nonNullable: "!foo.Bar");
});
test('supports array types', () {
expectToString(ClosureType.array(), "Array<*>",
nullable: "Array<*>", nonNullable: "!Array<*>");
expectToString(ClosureType.array(ClosureType.type("Foo")), "Array<Foo>",
nullable: "Array<Foo>", nonNullable: "!Array<Foo>");
});
test('supports map types', () {
expectToString(
ClosureType.map(ClosureType.type("Foo"), ClosureType.type("Bar")),
"Object<Foo, Bar>",
nullable: "Object<Foo, Bar>",
nonNullable: "!Object<Foo, Bar>");
expectToString(ClosureType.map(), "Object<*, *>",
nullable: "Object<*, *>", nonNullable: "!Object<*, *>");
});
test('supports function types', () {
expectToString(ClosureType.function(), "Function",
nullable: "Function", nonNullable: "!Function");
expectToString(
ClosureType.function([ClosureType.number()]), "function(number)");
expectToString(ClosureType.function(null, ClosureType.number()),
"function(...*):number");
expectToString(
ClosureType.function([ClosureType.number(), ClosureType.string()],
ClosureType.boolean()),
"function(number, string):boolean");
});
test('supports union types', () {
expectToString(
ClosureType.number().or(ClosureType.boolean()), "(number|boolean)");
expectToString(ClosureType.number().orUndefined(), "(number|undefined)");
});
test('supports record types', () {
expectToString(
ClosureType.record(
{'x': ClosureType.number(), 'y': ClosureType.boolean()}),
"{x: number, y: boolean}");
});
test('supports optional pseudo-types', () {
expectToString(ClosureType.number().toOptional(), "number=");
});
});
}