Version 1.8.0-dev.4.3
svn merge -c 41685 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 41709 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 41796 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 41822 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@41833 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 734bba3..9b923bb 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -80,6 +80,8 @@
forceIncrementalSupport ||
hasOption(options, '--incremental-support'),
suppressWarnings: hasOption(options, '--suppress-warnings'),
+ enableExperimentalMirrors:
+ hasOption(options, '--enable-experimental-mirrors'),
enableAsyncAwait: hasOption(options, '--enable-async'),
enableEnums: hasOption(options, '--enable-enum')) {
tasks.addAll([
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index c60a44c..74e408f 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -428,7 +428,7 @@
/// This method is called when all new libraries loaded through
/// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
/// have been computed.
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
+ Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
return new Future.value();
}
@@ -657,6 +657,7 @@
final bool disableTypeInferenceFlag;
final bool dumpInfo;
final bool useContentSecurityPolicy;
+ final bool enableExperimentalMirrors;
/**
* The maximum size of a concrete type before it widens to dynamic during
@@ -969,6 +970,7 @@
this.useContentSecurityPolicy: false,
this.suppressWarnings: false,
bool hasIncrementalSupport: false,
+ this.enableExperimentalMirrors: false,
this.enableAsyncAwait: false,
this.enableEnums: false,
api.CompilerOutputProvider outputProvider,
@@ -1223,9 +1225,67 @@
///
/// The method returns a [Future] allowing for the loading of additional
/// libraries.
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
+ Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
return new Future.sync(() {
- if (!loadedLibraries.containsKey(DART_CORE)) return new Future.value();
+ if (!loadedLibraries.containsLibrary(DART_CORE)) {
+ return null;
+ }
+ if (!enableExperimentalMirrors &&
+ loadedLibraries.containsLibrary(DART_MIRRORS)) {
+ // TODO(johnniwinther): Move computation of dependencies to the library
+ // loader.
+ Uri rootUri = loadedLibraries.rootUri;
+ Set<String> importChains = new Set<String>();
+ // The maximum number of full imports chains to process.
+ final int chainLimit = 10000;
+ // The maximum number of imports chains to show.
+ final int compactChainLimit = verbose ? 20 : 10;
+ int chainCount = 0;
+ bool limitExceeded = false;
+ loadedLibraries.forEachImportChain(DART_MIRRORS,
+ callback: (Link<Uri> importChainReversed) {
+ Link<CodeLocation> compactImportChain = const Link<CodeLocation>();
+ CodeLocation currentCodeLocation =
+ new UriLocation(importChainReversed.head);
+ compactImportChain = compactImportChain.prepend(currentCodeLocation);
+ for (Link<Uri> link = importChainReversed.tail;
+ !link.isEmpty;
+ link = link.tail) {
+ Uri uri = link.head;
+ if (!currentCodeLocation.inSameLocation(uri)) {
+ currentCodeLocation =
+ verbose ? new UriLocation(uri) : new CodeLocation(uri);
+ compactImportChain =
+ compactImportChain.prepend(currentCodeLocation);
+ }
+ }
+ String importChain =
+ compactImportChain.map((CodeLocation codeLocation) {
+ return codeLocation.relativize(rootUri);
+ }).join(' => ');
+
+ if (!importChains.contains(importChain)) {
+ if (importChains.length > compactChainLimit) {
+ importChains.add('...');
+ return false;
+ } else {
+ importChains.add(importChain);
+ }
+ }
+
+ chainCount++;
+ if (chainCount > chainLimit) {
+ // Assume there are more import chains.
+ importChains.add('...');
+ return false;
+ }
+ return true;
+ });
+ reportWarning(NO_LOCATION_SPANNABLE,
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
+ {'importChain': importChains.join(
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
+ }
functionClass.ensureResolved(this);
functionApplyMethod = functionClass.lookupLocalMember('apply');
@@ -1235,8 +1295,8 @@
coreLibrary.find('proxy')).value;
// TODO(johnniwinther): Move this to the JavaScript backend.
- LibraryElement jsHelperLibrary =
- loadedLibraries[js_backend.JavaScriptBackend.DART_JS_HELPER];
+ LibraryElement jsHelperLibrary = loadedLibraries.getLibrary(
+ js_backend.JavaScriptBackend.DART_JS_HELPER);
if (jsHelperLibrary != null) {
patchConstant = resolver.constantCompiler.compileConstant(
jsHelperLibrary.find('patch')).value;
@@ -1963,40 +2023,29 @@
/// If [assumeInUserCode] is `true`, [element] is assumed to be in user code
/// if no entrypoints have been set.
bool inUserCode(Element element, {bool assumeInUserCode: false}) {
- List<Uri> entrypoints = <Uri>[];
+ if (element == null) return false;
+ Iterable<CodeLocation> userCodeLocations =
+ computeUserCodeLocations(assumeInUserCode: assumeInUserCode);
+ Uri libraryUri = element.library.canonicalUri;
+ return userCodeLocations.any(
+ (CodeLocation codeLocation) => codeLocation.inSameLocation(libraryUri));
+ }
+
+ Iterable<CodeLocation> computeUserCodeLocations(
+ {bool assumeInUserCode: false}) {
+ List<CodeLocation> userCodeLocations = <CodeLocation>[];
if (mainApp != null) {
- entrypoints.add(mainApp.canonicalUri);
+ userCodeLocations.add(new CodeLocation(mainApp.canonicalUri));
}
if (librariesToAnalyzeWhenRun != null) {
- entrypoints.addAll(librariesToAnalyzeWhenRun);
+ userCodeLocations.addAll(librariesToAnalyzeWhenRun.map(
+ (Uri uri) => new CodeLocation(uri)));
}
- if (entrypoints.isEmpty && assumeInUserCode) {
+ if (userCodeLocations.isEmpty && assumeInUserCode) {
// Assume in user code since [mainApp] has not been set yet.
- return true;
+ userCodeLocations.add(const AnyLocation());
}
- if (element == null) return false;
- Uri libraryUri = element.library.canonicalUri;
- if (libraryUri.scheme == 'package') {
- for (Uri uri in entrypoints) {
- if (uri.scheme != 'package') continue;
- int slashPos = libraryUri.path.indexOf('/');
- if (slashPos != -1) {
- String packageName = libraryUri.path.substring(0, slashPos + 1);
- if (uri.path.startsWith(packageName)) {
- return true;
- }
- } else {
- if (libraryUri.path == uri.path) {
- return true;
- }
- }
- }
- } else {
- for (Uri uri in entrypoints) {
- if (libraryUri.scheme == uri.scheme) return true;
- }
- }
- return false;
+ return userCodeLocations;
}
/// Return a canonical URI for the source of [element].
@@ -2188,3 +2237,86 @@
GenericTask(this.name, Compiler compiler)
: super(compiler);
}
+
+/// [CodeLocation] divides uris into different classes.
+///
+/// These are used to group uris from user code, platform libraries and
+/// packages.
+abstract class CodeLocation {
+ /// Returns `true` if [uri] is in this code location.
+ bool inSameLocation(Uri uri);
+
+ /// Returns the uri of this location relative to [baseUri].
+ String relativize(Uri baseUri);
+
+ factory CodeLocation(Uri uri) {
+ if (uri.scheme == 'package') {
+ int slashPos = uri.path.indexOf('/');
+ if (slashPos != -1) {
+ String packageName = uri.path.substring(0, slashPos);
+ return new PackageLocation(packageName);
+ } else {
+ return new UriLocation(uri);
+ }
+ } else {
+ return new SchemeLocation(uri);
+ }
+ }
+}
+
+/// A code location defined by the scheme of the uri.
+///
+/// Used for non-package uris, such as 'dart', 'file', and 'http'.
+class SchemeLocation implements CodeLocation {
+ final Uri uri;
+
+ SchemeLocation(this.uri);
+
+ bool inSameLocation(Uri uri) {
+ return this.uri.scheme == uri.scheme;
+ }
+
+ String relativize(Uri baseUri) {
+ return uri_extras.relativize(baseUri, uri, false);
+ }
+}
+
+/// A code location defined by the package name.
+///
+/// Used for package uris, separated by their `package names`, that is, the
+/// 'foo' of 'package:foo/bar.dart'.
+class PackageLocation implements CodeLocation {
+ final String packageName;
+
+ PackageLocation(this.packageName);
+
+ bool inSameLocation(Uri uri) {
+ return uri.scheme == 'package' && uri.path.startsWith('$packageName/');
+ }
+
+ String relativize(Uri baseUri) => 'package:$packageName';
+}
+
+/// A code location defined by the whole uri.
+///
+/// Used for package uris with no package name. For instance 'package:foo.dart'.
+class UriLocation implements CodeLocation {
+ final Uri uri;
+
+ UriLocation(this.uri);
+
+ bool inSameLocation(Uri uri) => this.uri == uri;
+
+ String relativize(Uri baseUri) {
+ return uri_extras.relativize(baseUri, uri, false);
+ }
+}
+
+/// A code location that contains any uri.
+class AnyLocation implements CodeLocation {
+ const AnyLocation();
+
+ bool inSameLocation(Uri uri) => true;
+
+ String relativize(Uri baseUri) => '$baseUri';
+}
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index ab55c45..ac763bb 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -30,7 +30,7 @@
// and back-end.
int get precedence => 16;
- accept(ConstantExpressionVisitor visitor);
+ accept(ConstantExpressionVisitor visitor, [context]);
String getText() {
ConstExpPrinter printer = new ConstExpPrinter();
@@ -53,7 +53,9 @@
assert(value != null);
}
- accept(ConstantExpressionVisitor visitor) => visitor.visitPrimitive(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitPrimitive(this, context);
+ }
}
/// Literal list constant.
@@ -64,7 +66,9 @@
ListConstantExpression(this.value, this.type, this.values);
- accept(ConstantExpressionVisitor visitor) => visitor.visitList(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitList(this, context);
+ }
}
/// Literal map constant.
@@ -76,7 +80,9 @@
MapConstantExpression(this.value, this.type, this.keys, this.values);
- accept(ConstantExpressionVisitor visitor) => visitor.visitMap(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitMap(this, context);
+ }
}
/// Invocation of a const constructor.
@@ -95,7 +101,9 @@
assert(type.element == target.enclosingClass);
}
- accept(ConstantExpressionVisitor visitor) => visitor.visitConstructor(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitConstructed(this, context);
+ }
}
/// String literal with juxtaposition and/or interpolations.
@@ -106,7 +114,9 @@
ConcatenateConstantExpression(this.value, this.arguments);
- accept(ConstantExpressionVisitor visitor) => visitor.visitConcatenate(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitConcatenate(this, context);
+ }
}
/// Symbol literal.
@@ -116,7 +126,9 @@
SymbolConstantExpression(this.value, this.name);
- accept(ConstantExpressionVisitor visitor) => visitor.visitSymbol(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitSymbol(this, context);
+ }
}
/// Type literal.
@@ -129,7 +141,9 @@
assert(type is GenericType || type is DynamicType);
}
- accept(ConstantExpressionVisitor visitor) => visitor.visitType(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitType(this, context);
+ }
}
/// Reference to a constant local, top-level, or static variable.
@@ -139,7 +153,9 @@
VariableConstantExpression(this.value, this.element);
- accept(ConstantExpressionVisitor visitor) => visitor.visitVariable(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitVariable(this, context);
+ }
}
/// Reference to a top-level or static function.
@@ -149,7 +165,9 @@
FunctionConstantExpression(this.value, this.element);
- accept(ConstantExpressionVisitor visitor) => visitor.visitFunction(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitFunction(this, context);
+ }
}
/// A constant binary expression like `a * b` or `identical(a, b)`.
@@ -163,7 +181,9 @@
assert(PRECEDENCE_MAP[operator] != null);
}
- accept(ConstantExpressionVisitor visitor) => visitor.visitBinary(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitBinary(this, context);
+ }
int get precedence => PRECEDENCE_MAP[operator];
@@ -201,7 +221,9 @@
assert(PRECEDENCE_MAP[operator] != null);
}
- accept(ConstantExpressionVisitor visitor) => visitor.visitUnary(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitUnary(this, context);
+ }
int get precedence => PRECEDENCE_MAP[operator];
@@ -224,26 +246,32 @@
this.trueExp,
this.falseExp);
- accept(ConstantExpressionVisitor visitor) => visitor.visitConditional(this);
+ accept(ConstantExpressionVisitor visitor, [context]) {
+ return visitor.visitConditional(this, context);
+ }
int get precedence => 3;
}
-abstract class ConstantExpressionVisitor<T> {
- T visit(ConstantExpression constant) => constant.accept(this);
+abstract class ConstantExpressionVisitor<C, R> {
+ const ConstantExpressionVisitor();
- T visitPrimitive(PrimitiveConstantExpression exp);
- T visitList(ListConstantExpression exp);
- T visitMap(MapConstantExpression exp);
- T visitConstructor(ConstructedConstantExpresssion exp);
- T visitConcatenate(ConcatenateConstantExpression exp);
- T visitSymbol(SymbolConstantExpression exp);
- T visitType(TypeConstantExpression exp);
- T visitVariable(VariableConstantExpression exp);
- T visitFunction(FunctionConstantExpression exp);
- T visitBinary(BinaryConstantExpression exp);
- T visitUnary(UnaryConstantExpression exp);
- T visitConditional(ConditionalConstantExpression exp);
+ R visit(ConstantExpression constant, [C context]) {
+ return constant.accept(this, context);
+ }
+
+ R visitPrimitive(PrimitiveConstantExpression exp, [C context]);
+ R visitList(ListConstantExpression exp, [C context]);
+ R visitMap(MapConstantExpression exp, [C context]);
+ R visitConstructed(ConstructedConstantExpresssion exp, [C context]);
+ R visitConcatenate(ConcatenateConstantExpression exp, [C context]);
+ R visitSymbol(SymbolConstantExpression exp, [C context]);
+ R visitType(TypeConstantExpression exp, [C context]);
+ R visitVariable(VariableConstantExpression exp, [C context]);
+ R visitFunction(FunctionConstantExpression exp, [C context]);
+ R visitBinary(BinaryConstantExpression exp, [C context]);
+ R visitUnary(UnaryConstantExpression exp, [C context]);
+ R visitConditional(ConditionalConstantExpression exp, [C context]);
}
/// Represents the declaration of a constant [element] with value [expression].
@@ -285,11 +313,11 @@
sb.write('>');
}
- visitPrimitive(PrimitiveConstantExpression exp) {
+ visitPrimitive(PrimitiveConstantExpression exp, [_]) {
sb.write(exp.value.unparse());
}
- visitList(ListConstantExpression exp) {
+ visitList(ListConstantExpression exp, [_]) {
sb.write('const ');
writeTypeArguments(exp.type);
sb.write('[');
@@ -304,7 +332,7 @@
sb.write(']');
}
- visitMap(MapConstantExpression exp) {
+ visitMap(MapConstantExpression exp, [_]) {
sb.write('const ');
writeTypeArguments(exp.type);
sb.write('{');
@@ -319,7 +347,7 @@
sb.write('}');
}
- visitConstructor(ConstructedConstantExpresssion exp) {
+ visitConstructed(ConstructedConstantExpresssion exp, [_]) {
sb.write('const ');
sb.write(exp.target.enclosingClass.name);
if (exp.target.name != '') {
@@ -350,20 +378,20 @@
sb.write(')');
}
- visitConcatenate(ConcatenateConstantExpression exp) {
+ visitConcatenate(ConcatenateConstantExpression exp, [_]) {
sb.write(exp.value.unparse());
}
- visitSymbol(SymbolConstantExpression exp) {
+ visitSymbol(SymbolConstantExpression exp, [_]) {
sb.write('#');
sb.write(exp.name);
}
- visitType(TypeConstantExpression exp) {
+ visitType(TypeConstantExpression exp, [_]) {
sb.write(exp.type.name);
}
- visitVariable(VariableConstantExpression exp) {
+ visitVariable(VariableConstantExpression exp, [_]) {
if (exp.element.isStatic) {
sb.write(exp.element.enclosingClass.name);
sb.write('.');
@@ -371,7 +399,7 @@
sb.write(exp.element.name);
}
- visitFunction(FunctionConstantExpression exp) {
+ visitFunction(FunctionConstantExpression exp, [_]) {
if (exp.element.isStatic) {
sb.write(exp.element.enclosingClass.name);
sb.write('.');
@@ -379,7 +407,7 @@
sb.write(exp.element.name);
}
- visitBinary(BinaryConstantExpression exp) {
+ visitBinary(BinaryConstantExpression exp, [_]) {
if (exp.operator == 'identical') {
sb.write('identical(');
visit(exp.left);
@@ -395,12 +423,12 @@
}
}
- visitUnary(UnaryConstantExpression exp) {
+ visitUnary(UnaryConstantExpression exp, [_]) {
sb.write(exp.operator);
write(exp, exp.expression);
}
- visitConditional(ConditionalConstantExpression exp) {
+ visitConditional(ConditionalConstantExpression exp, [_]) {
write(exp, exp.condition, leftAssociative: false);
sb.write(' ? ');
write(exp, exp.trueExp);
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index af0fad3..324e33a 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -332,6 +332,7 @@
(_) => hasDisallowUnsafeEval = true),
new OptionHandler('--show-package-warnings', passThrough),
new OptionHandler('--csp', passThrough),
+ new OptionHandler('--enable-experimental-mirrors', passThrough),
new OptionHandler('--enable-async', setEnableAsync),
new OptionHandler('--enable-enum', passThrough),
new OptionHandler('-D.+=.*', addInEnvironment),
diff --git a/pkg/compiler/lib/src/dart2jslib.dart b/pkg/compiler/lib/src/dart2jslib.dart
index a59cefc..01cd054 100644
--- a/pkg/compiler/lib/src/dart2jslib.dart
+++ b/pkg/compiler/lib/src/dart2jslib.dart
@@ -34,7 +34,8 @@
import 'js_backend/js_backend.dart' as js_backend;
import 'library_loader.dart'
show LibraryLoader,
- LibraryLoaderTask;
+ LibraryLoaderTask,
+ LoadedLibraries;
import 'mirrors_used.dart' show MirrorUsageAnalyzerTask;
import 'native/native.dart' as native;
import 'ordered_typeset.dart';
@@ -49,6 +50,7 @@
import 'types/types.dart' as ti;
import 'universe/universe.dart';
import 'util/characters.dart' show $_;
+import 'util/uri_extras.dart' as uri_extras show relativize;
import 'util/util.dart';
export 'helpers/helpers.dart';
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index 3479b499..174c58b 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -261,10 +261,10 @@
log(String message) => compiler.log('[DartBackend] $message');
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
+ Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
// All platform classes must be resolved to ensure that their member names
// are preserved.
- loadedLibraries.values.forEach((LibraryElement library) {
+ loadedLibraries.forEachLibrary((LibraryElement library) {
if (library.isPlatformLibrary) {
library.forEachLocalMember((Element element) {
if (element.isClass) {
@@ -275,10 +275,10 @@
}
});
if (useMirrorHelperLibrary &&
- loadedLibraries.containsKey(Compiler.DART_MIRRORS)) {
+ loadedLibraries.containsLibrary(Compiler.DART_MIRRORS)) {
return compiler.libraryLoader.loadLibrary(
compiler.translateResolvedUri(
- loadedLibraries[Compiler.DART_MIRRORS],
+ loadedLibraries.getLibrary(Compiler.DART_MIRRORS),
MirrorRenamerImpl.DART_MIRROR_HELPER, null)).
then((LibraryElement library) {
mirrorRenamer = new MirrorRenamerImpl(compiler, this, library);
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
index 7ceefa6..7ae2d22 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
@@ -708,7 +708,7 @@
}
}
-class ConstantEmitter extends ConstantExpressionVisitor<Expression> {
+class ConstantEmitter extends ConstantExpressionVisitor<Null, Expression> {
ASTEmitter parent;
ConstantEmitter(this.parent);
@@ -730,13 +730,13 @@
}
@override
- Expression visitPrimitive(PrimitiveConstantExpression exp) {
+ Expression visitPrimitive(PrimitiveConstantExpression exp, [_]) {
return handlePrimitiveConstant(exp.value);
}
/// Given a negative num constant, returns the corresponding positive
/// literal wrapped by a unary minus operator.
- Expression negatedLiteral(NumConstantValue constant) {
+ Expression negatedLiteral(NumConstantValue constant, [_]) {
assert(constant.primitiveValue.isNegative);
NumConstantValue positiveConstant;
if (constant.isInt) {
@@ -750,7 +750,7 @@
}
@override
- Expression visitList(ListConstantExpression exp) {
+ Expression visitList(ListConstantExpression exp, [_]) {
return new LiteralList(
exp.values.map(visit).toList(growable: false),
isConst: true,
@@ -758,7 +758,7 @@
}
@override
- Expression visitMap(MapConstantExpression exp) {
+ Expression visitMap(MapConstantExpression exp, [_]) {
List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
exp.values.length,
(i) => new LiteralMapEntry(visit(exp.keys[i]),
@@ -770,7 +770,7 @@
}
@override
- Expression visitConstructor(ConstructedConstantExpresssion exp) {
+ Expression visitConstructed(ConstructedConstantExpresssion exp, [_]) {
int positionalArgumentCount = exp.selector.positionalArgumentCount;
List<Argument> args = new List<Argument>.generate(
positionalArgumentCount,
@@ -791,24 +791,24 @@
}
@override
- Expression visitConcatenate(ConcatenateConstantExpression exp) {
+ Expression visitConcatenate(ConcatenateConstantExpression exp, [_]) {
return new StringConcat(exp.arguments.map(visit).toList(growable: false));
}
@override
- Expression visitSymbol(SymbolConstantExpression exp) {
+ Expression visitSymbol(SymbolConstantExpression exp, [_]) {
return new LiteralSymbol(exp.name);
}
@override
- Expression visitType(TypeConstantExpression exp) {
+ Expression visitType(TypeConstantExpression exp, [_]) {
DartType type = exp.type;
return new LiteralType(type.name)
..type = type;
}
@override
- Expression visitVariable(VariableConstantExpression exp) {
+ Expression visitVariable(VariableConstantExpression exp, [_]) {
Element element = exp.element;
if (element.kind != ElementKind.VARIABLE) {
return new Identifier(element.name)..element = element;
@@ -819,18 +819,18 @@
}
@override
- Expression visitFunction(FunctionConstantExpression exp) {
+ Expression visitFunction(FunctionConstantExpression exp, [_]) {
return new Identifier(exp.element.name)
..element = exp.element;
}
@override
- Expression visitBinary(BinaryConstantExpression exp) {
+ Expression visitBinary(BinaryConstantExpression exp, [_]) {
return handlePrimitiveConstant(exp.value);
}
@override
- Expression visitConditional(ConditionalConstantExpression exp) {
+ Expression visitConditional(ConditionalConstantExpression exp, [_]) {
if (exp.condition.value.isTrue) {
return exp.trueExp.accept(this);
} else {
@@ -839,7 +839,7 @@
}
@override
- Expression visitUnary(UnaryConstantExpression exp) {
+ Expression visitUnary(UnaryConstantExpression exp, [_]) {
return handlePrimitiveConstant(exp.value);
}
}
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 36746b7..e44d1d5 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -8,6 +8,7 @@
import 'dart:math' show max;
import '../elements/elements.dart';
import '../dart2jslib.dart';
+import '../library_loader.dart' show LoadedLibraries;
import '../dart_types.dart';
import '../tree/tree.dart';
import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index eabc991..f8b7844 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -1414,6 +1414,12 @@
void addConstructor(FunctionElement constructor);
}
+/// Enum declaration.
+abstract class EnumClassElement extends ClassElement {
+ /// The static fields implied by the enum values.
+ Iterable<FieldElement> get enumValues;
+}
+
/// The label entity defined by a labeled statement.
abstract class LabelDefinition extends Entity {
Label get label;
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index fbffa06d..e862b14 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -2414,8 +2414,9 @@
}
}
-class EnumClassElementX extends ClassElementX {
+class EnumClassElementX extends ClassElementX implements EnumClassElement {
final Enum node;
+ Iterable<FieldElement> _enumValues;
EnumClassElementX(String name, Element enclosing, int id, this.node)
: super(name, enclosing, id, STATE_NOT_STARTED);
@@ -2433,9 +2434,21 @@
Node parseNode(Compiler compiler) => node;
@override
- accept(ElementVisitor visitor) => visitor.visitClassElement(this);
+ accept(ElementVisitor visitor) => visitor.visitEnumClassElement(this);
List<DartType> computeTypeParameters(Compiler compiler) => const <DartType>[];
+
+ Iterable<FieldElement> get enumValues {
+ assert(invariant(this, _enumValues != null,
+ message: "enumValues has not been computed for $this."));
+ return _enumValues;
+ }
+
+ void set enumValues(Iterable<FieldElement> values) {
+ assert(invariant(this, _enumValues == null,
+ message: "enumValues has already been computed for $this."));
+ _enumValues = values;
+ }
}
class EnumConstructorElementX extends ConstructorElementX {
diff --git a/pkg/compiler/lib/src/elements/visitor.dart b/pkg/compiler/lib/src/elements/visitor.dart
index 8d0323f..a1b2745 100644
--- a/pkg/compiler/lib/src/elements/visitor.dart
+++ b/pkg/compiler/lib/src/elements/visitor.dart
@@ -36,6 +36,7 @@
R visitMixinApplicationElement(MixinApplicationElement e) {
return visitClassElement(e);
}
+ R visitEnumClassElement(EnumClassElement e) => visitClassElement(e);
R visitTypeVariableElement(TypeVariableElement e) => visitElement(e);
R visitBoxFieldElement(BoxFieldElement e) => visitElement(e);
R visitClosureClassElement(ClosureClassElement e) => visitClassElement(e);
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index 097a222..bcfa12c 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -67,7 +67,7 @@
}
/// Implementation of [debugWrapPrint].
-DebugWrapPrint _debugWrapPrint(s, f()) {
+_debugWrapPrint(s, f()) {
debugPrint('start:$s');
var result = _indentation.indentBlock(f);
debugPrint('end:$s');
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0f01f9c..893445ba 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -1763,14 +1763,14 @@
});
}
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
- if (!loadedLibraries.containsKey(Compiler.DART_CORE)) {
+ Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
+ if (!loadedLibraries.containsLibrary(Compiler.DART_CORE)) {
return new Future.value();
}
- assert(loadedLibraries.containsKey(Compiler.DART_CORE));
- assert(loadedLibraries.containsKey(DART_INTERCEPTORS));
- assert(loadedLibraries.containsKey(DART_JS_HELPER));
+ assert(loadedLibraries.containsLibrary(Compiler.DART_CORE));
+ assert(loadedLibraries.containsLibrary(DART_INTERCEPTORS));
+ assert(loadedLibraries.containsLibrary(DART_JS_HELPER));
if (jsInvocationMirrorClass != null) {
jsInvocationMirrorClass.ensureResolved(compiler);
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 0f9f0ce..df03b80 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -19,7 +19,7 @@
import '../js/js.dart' show js;
import '../js_emitter/js_emitter.dart'
show Emitter, CodeEmitterTask, ClassBuilder, MetadataEmitter;
-import '../library_loader.dart' show LibraryLoader;
+import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native;
import '../ssa/ssa.dart';
import '../tree/tree.dart';
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index ff7d59a..b2db0bb 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -249,6 +249,7 @@
*/
class _LibraryLoaderTask extends CompilerTask implements LibraryLoaderTask {
_LibraryLoaderTask(Compiler compiler) : super(compiler);
+
String get name => 'LibraryLoader';
final Map<Uri, LibraryElement> libraryCanonicalUriMap =
@@ -342,11 +343,8 @@
return compiler.withCurrentElement(library, () {
return measure(() {
currentHandler.computeExports();
- Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{};
- currentHandler.loadedLibraries.forEach(
- (LibraryElement loadedLibrary) {
- loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary;
- });
+ LoadedLibraries loadedLibraries =
+ new _LoadedLibraries(library, currentHandler.nodeMap, this);
currentHandler = null;
return compiler.onLibrariesLoaded(loadedLibraries)
.then((_) => library);
@@ -1032,3 +1030,119 @@
return task.processLibraryTags(this, library);
}
}
+
+/// Information on the bulk of newly loaded libraries through a call to
+/// [LibraryLoader.loadLibrary].
+abstract class LoadedLibraries {
+ /// The uri passed to [LibraryLoader.loadLibrary].
+ Uri get rootUri;
+
+ /// Returns `true` if a library with canonical [uri] was loaded in this bulk.
+ bool containsLibrary(Uri uri);
+
+ /// Returns the library with canonical [uri] that was loaded in this bulk.
+ LibraryElement getLibrary(Uri uri);
+
+ /// Applies all libraries in this bulk to [f].
+ void forEachLibrary(f(LibraryElement library));
+
+ /// Applies all imports chains of [uri] in this bulk to [callback].
+ ///
+ /// The argument [importChainReversed] to [callback] contains the chain of
+ /// imports uris that lead to importing [uri] starting in [uri] and ending in
+ /// [rootUri].
+ ///
+ /// [callback] is called once for each chain of imports leading to [uri] until
+ /// [callback] returns `false`.
+ void forEachImportChain(Uri uri,
+ {bool callback(Link<Uri> importChainReversed)});
+}
+
+class _LoadedLibraries implements LoadedLibraries {
+ final _LibraryLoaderTask task;
+ final LibraryElement rootLibrary;
+ final Map<Uri, LibraryElement> loadedLibraries = <Uri, LibraryElement>{};
+ final Map<LibraryElement, LibraryDependencyNode> nodeMap;
+
+ _LoadedLibraries(this.rootLibrary, this.nodeMap, this.task) {
+ nodeMap.keys.forEach((LibraryElement loadedLibrary) {
+ loadedLibraries[loadedLibrary.canonicalUri] = loadedLibrary;
+ });
+ }
+
+ Uri get rootUri => rootLibrary.canonicalUri;
+
+ bool containsLibrary(Uri uri) => loadedLibraries.containsKey(uri);
+
+ LibraryElement getLibrary(Uri uri) => loadedLibraries[uri];
+
+ void forEachLibrary(f(LibraryElement library)) => nodeMap.keys.forEach(f);
+
+ void forEachImportChain(Uri targetUri,
+ {bool callback(Link<Uri> importChainReversed)}) {
+ bool aborted = false;
+
+ /// Map from libraries to the set of (unreversed) paths to [uri].
+ Map<LibraryElement, Iterable<Link<Uri>>> suffixChainMap =
+ <LibraryElement, Iterable<Link<Uri>>>{};
+
+ /// Computes the set of (unreversed) paths to [targetUri].
+ ///
+ /// Finds all paths (suffixes) from the current library to [uri] and stores
+ /// it in [suffixChainMap].
+ ///
+ /// For every found suffix it prepends the given [prefix] and the canonical
+ /// uri of [library] and invokes the [callback] with the concatenated chain.
+ void computeSuffixes(LibraryElement library,
+ Link<Uri> prefix) {
+ if (aborted) return;
+
+ Uri canonicalUri = library.canonicalUri;
+ prefix = prefix.prepend(canonicalUri);
+ if (suffixChainMap.containsKey(library)) return;
+ suffixChainMap[library] = const <Link<Uri>>[];
+ List<Link<Uri>> suffixes = [];
+ if (targetUri != canonicalUri) {
+ LibraryDependencyNode node = nodeMap[library];
+ for (ImportLink import in node.imports.reverse()) {
+ bool suffixesArePrecomputed =
+ suffixChainMap.containsKey(import.importedLibrary);
+
+ if (!suffixesArePrecomputed) {
+ computeSuffixes(import.importedLibrary, prefix);
+ if (aborted) return;
+ }
+
+ for (Link<Uri> suffix in suffixChainMap[import.importedLibrary]) {
+ suffixes.add(suffix.prepend(canonicalUri));
+
+ if (suffixesArePrecomputed) {
+ // Only report chains through [import] if the suffixes had already
+ // been computed, otherwise [computeSuffixes] have reported the
+ // paths through [prefix].
+ Link<Uri> chain = prefix;
+ while (!suffix.isEmpty) {
+ chain = chain.prepend(suffix.head);
+ suffix = suffix.tail;
+ }
+ if (!callback(chain)) {
+ aborted = true;
+ return;
+ }
+ }
+ }
+ }
+ } else { // Here `targetUri == canonicalUri`.
+ if (!callback(prefix)) {
+ aborted = true;
+ return;
+ }
+ suffixes.add(const Link<Uri>().prepend(canonicalUri));
+ }
+ suffixChainMap[library] = suffixes;
+ return;
+ }
+
+ computeSuffixes(rootLibrary, const Link<Uri>());
+ }
+}
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index f809260..5aa71de 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -448,19 +448,6 @@
Uri get uri => _element.script.resourceUri;
}
-class ResolvedNode {
- final node;
- final _elements;
- final _mirrorSystem;
- ResolvedNode(this.node, this._elements, this._mirrorSystem);
-
- Mirror resolvedMirror(node) {
- var element = _elements[node];
- if (element == null) return null;
- return _convertElementToDeclarationMirror(_mirrorSystem, element);
- }
-}
-
/**
* Transitional class that allows access to features that have not yet
* made it to the mirror API.
@@ -474,28 +461,25 @@
(cu) => new Dart2JsCompilationUnitMirror(cu, library));
}
- static Iterable metadataSyntaxOf(Dart2JsElementMirror declaration) {
- Compiler compiler = declaration.mirrorSystem.compiler;
- return declaration._element.metadata.map((metadata) {
- var node = metadata.parseNode(compiler);
- var treeElements = metadata.annotatedElement.treeElements;
- return new ResolvedNode(
- node, treeElements, declaration.mirrorSystem);
- });
+ static Iterable<ConstantExpression> metadataSyntaxOf(
+ Dart2JsElementMirror declaration) {
+ return declaration._element.metadata.map((metadata) => metadata.constant);
}
- static ResolvedNode initializerSyntaxOf(Dart2JsFieldMirror variable) {
- var node = variable._variable.initializer;
- if (node == null) return null;
- return new ResolvedNode(
- node, variable._variable.treeElements, variable.mirrorSystem);
+ static ConstantExpression initializerSyntaxOf(Dart2JsFieldMirror variable) {
+ Compiler compiler = variable.mirrorSystem.compiler;
+ return compiler.constants.getConstantForVariable(variable._variable);
}
- static ResolvedNode defaultValueSyntaxOf(Dart2JsParameterMirror parameter) {
+ static ConstantExpression defaultValueSyntaxOf(
+ Dart2JsParameterMirror parameter) {
if (!parameter.hasDefaultValue) return null;
ParameterElement parameterElement = parameter._element;
- var node = parameterElement.initializer;
- var treeElements = parameterElement.treeElements;
- return new ResolvedNode(node, treeElements, parameter.mirrorSystem);
+ Compiler compiler = parameter.mirrorSystem.compiler;
+ return compiler.constants.getConstantForVariable(parameterElement);
+ }
+
+ static Mirror getMirrorFromElement(Dart2JsMirror mirror, Element element) {
+ return _convertElementToDeclarationMirror(mirror.mirrorSystem, element);
}
}
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index fcc1796..fc9ee70 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -20,13 +20,27 @@
int get charOffset => position.charOffset;
- final Modifiers finalModifiers =
- new Modifiers.withFlags(null, Modifiers.FLAG_FINAL);
- final Modifiers constModifiers =
- new Modifiers.withFlags(null, Modifiers.FLAG_CONST);
- final Modifiers staticConstModifiers =
- new Modifiers.withFlags(null,
- Modifiers.FLAG_STATIC | Modifiers.FLAG_CONST);
+ Modifiers modifiers({bool isConst: false,
+ bool isFinal: false,
+ bool isStatic: false}) {
+ List identifiers = [];
+ int flags = 0;
+ if (isConst) {
+ identifiers.add(identifier('const'));
+ flags |= Modifiers.FLAG_CONST;
+ }
+ if (isFinal) {
+ identifiers.add(identifier('final'));
+ flags |= Modifiers.FLAG_FINAL;
+ }
+ if (isStatic) {
+ identifiers.add(identifier('static'));
+ flags |= Modifiers.FLAG_STATIC;
+ }
+ return new Modifiers.withFlags(
+ new NodeList(null, linkedList(identifiers), null, ''),
+ flags);
+ }
Token keywordToken(String text) {
return new KeywordToken(Keyword.keywords[text], position.charOffset);
@@ -135,6 +149,29 @@
new Send(null, identifier(typeName), arguments));
}
+ Send reference(Identifier identifier) {
+ return new Send(null, identifier);
+ }
+
+ Send indexGet(Expression receiver, Expression index) {
+ return new Send(receiver,
+ new Operator(symbolToken(INDEX_INFO)),
+ new NodeList.singleton(index));
+ }
+
+ LiteralMapEntry mapLiteralEntry(Expression key, Expression value) {
+ return new LiteralMapEntry(key, symbolToken(COLON_INFO), value);
+ }
+
+ LiteralMap mapLiteral(List<LiteralMapEntry> entries, {bool isConst: false}) {
+ return new LiteralMap(
+ null, // Type arguments.
+ new NodeList(symbolToken(OPEN_CURLY_BRACKET_INFO),
+ linkedList(entries),
+ symbolToken(CLOSE_CURLY_BRACKET_INFO),
+ ','),
+ isConst ? keywordToken('const') : null);
+ }
}
class EnumCreator {
@@ -153,7 +190,8 @@
EnumFieldElementX addInstanceMember(String name, InterfaceType type) {
Identifier identifier = builder.identifier(name);
- VariableList variableList = new VariableList(builder.finalModifiers);
+ VariableList variableList =
+ new VariableList(builder.modifiers(isFinal: true));
variableList.type = type;
EnumFieldElementX variable = new EnumFieldElementX(
identifier, enumClass, variableList, identifier);
@@ -162,20 +200,18 @@
}
EnumFieldElementX indexVariable = addInstanceMember('index', intType);
- EnumFieldElementX nameVariable = addInstanceMember('_name', stringType);
VariableDefinitions indexDefinition = builder.initializingFormal('index');
- VariableDefinitions nameDefinition = builder.initializingFormal('_name');
FunctionExpression constructorNode = builder.functionExpression(
- builder.constModifiers,
+ builder.modifiers(isConst: true),
enumClass.name,
- builder.argumentList([indexDefinition, nameDefinition]),
+ builder.argumentList([indexDefinition]),
builder.emptyStatement());
EnumConstructorElementX constructor = new EnumConstructorElementX(
enumClass,
- builder.constModifiers,
+ builder.modifiers(isConst: true),
constructorNode);
EnumFormalElementX indexFormal = new EnumFormalElementX(
@@ -184,48 +220,50 @@
builder.identifier('index'),
indexVariable);
- EnumFormalElementX nameFormal = new EnumFormalElementX(
- constructor,
- nameDefinition,
- builder.identifier('_name'),
- nameVariable);
-
FunctionSignatureX constructorSignature = new FunctionSignatureX(
- requiredParameters: builder.linkedList([indexFormal, nameFormal]),
- requiredParameterCount: 2,
+ requiredParameters: builder.linkedList([indexFormal]),
+ requiredParameterCount: 1,
type: new FunctionType(constructor, const VoidType(),
- <DartType>[intType, stringType]));
+ <DartType>[intType]));
constructor.functionSignatureCache = constructorSignature;
enumClass.addMember(constructor, compiler);
- VariableList variableList = new VariableList(builder.staticConstModifiers);
+ List<FieldElement> enumValues = <FieldElement>[];
+ VariableList variableList =
+ new VariableList(builder.modifiers(isStatic: true, isConst: true));
variableList.type = enumType;
int index = 0;
List<Node> valueReferences = <Node>[];
+ List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
for (Link<Node> link = node.names.nodes;
!link.isEmpty;
link = link.tail) {
Identifier name = link.head;
AstBuilder valueBuilder = new AstBuilder(name.token);
- valueReferences.add(new Send(null, name));
+
+ // Add reference for the `values` field.
+ valueReferences.add(valueBuilder.reference(name));
+
+ // Add map entry for `toString` implementation.
+ mapEntries.add(valueBuilder.mapLiteralEntry(
+ valueBuilder.literalInt(index),
+ valueBuilder.literalString('${enumClass.name}.${name.source}')));
Expression initializer = valueBuilder.newExpression(
enumClass.name,
- valueBuilder.argumentList([
- valueBuilder.literalInt(index),
- valueBuilder.literalString('${name.source}')
- ]),
+ valueBuilder.argumentList([valueBuilder.literalInt(index)]),
isConst: true);
SendSet definition = valueBuilder.createDefinition(name, initializer);
EnumFieldElementX field = new EnumFieldElementX(
name, enumClass, variableList, definition, initializer);
+ enumValues.add(field);
enumClass.addMember(field, compiler);
index++;
}
VariableList valuesVariableList =
- new VariableList(builder.staticConstModifiers);
+ new VariableList(builder.modifiers(isStatic: true, isConst: true));
InterfaceType listType = compiler.listClass.computeType(compiler);
valuesVariableList.type = listType.createInstantiation([enumType]);
@@ -249,12 +287,10 @@
'toString',
builder.argumentList([]),
builder.returnStatement(
- new StringInterpolation(
- builder.literalString('${enumClass.name}.', suffix: ''),
- new NodeList.singleton(new StringInterpolationPart(
- new Send(null, builder.identifier('_name')),
- builder.literalString('', prefix: '')))
- ))
+ builder.indexGet(
+ builder.mapLiteral(mapEntries, isConst: true),
+ builder.reference(builder.identifier('index')))
+ )
);
EnumMethodElementX toString = new EnumMethodElementX('toString',
@@ -263,5 +299,7 @@
type: new FunctionType(toString, stringType));
toString.functionSignatureCache = toStringSignature;
enumClass.addMember(toString, compiler);
+
+ enumClass.enumValues = enumValues;
}
}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 353bfdf..c697b2c 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -2909,11 +2909,11 @@
// Don't try to make constants of calls to type literals.
if (!node.isCall) {
- analyzeConstant(node);
+ analyzeConstantDeferred(node);
} else {
// The node itself is not a constant but we register the selector (the
// identifier that refers to the class/typedef) as a constant.
- analyzeConstant(node.selector);
+ analyzeConstantDeferred(node.selector);
}
}
if (isPotentiallyMutableTarget(target)) {
@@ -3177,7 +3177,7 @@
MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
{'value': node.slowNameString});
}
- analyzeConstant(node);
+ analyzeConstantDeferred(node);
}
visitStringJuxtaposition(StringJuxtaposition node) {
@@ -3428,7 +3428,7 @@
compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
}
if (node.isConst) {
- analyzeConstant(node);
+ analyzeConstantDeferred(node);
}
return null;
@@ -3452,34 +3452,38 @@
}
void analyzeConstant(Node node) {
- addDeferredAction(enclosingElement, () {
- ConstantExpression constant =
- compiler.resolver.constantCompiler.compileNode(
- node, registry.mapping);
+ ConstantExpression constant =
+ compiler.resolver.constantCompiler.compileNode(
+ node, registry.mapping);
- ConstantValue value = constant.value;
- if (value.isMap) {
- checkConstMapKeysDontOverrideEquals(node, value);
- }
+ ConstantValue value = constant.value;
+ if (value.isMap) {
+ checkConstMapKeysDontOverrideEquals(node, value);
+ }
- // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
- // a class that will be instantiated outside the program by attaching a
- // native class dispatch record referencing the interceptor.
- if (argumentsToJsInterceptorConstant != null &&
- argumentsToJsInterceptorConstant.contains(node)) {
- if (value.isType) {
- TypeConstantValue typeConstant = value;
- if (typeConstant.representedType is InterfaceType) {
- registry.registerInstantiatedType(typeConstant.representedType);
- } else {
- compiler.reportError(node,
- MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
- }
+ // The type constant that is an argument to JS_INTERCEPTOR_CONSTANT names
+ // a class that will be instantiated outside the program by attaching a
+ // native class dispatch record referencing the interceptor.
+ if (argumentsToJsInterceptorConstant != null &&
+ argumentsToJsInterceptorConstant.contains(node)) {
+ if (value.isType) {
+ TypeConstantValue typeConstant = value;
+ if (typeConstant.representedType is InterfaceType) {
+ registry.registerInstantiatedType(typeConstant.representedType);
} else {
compiler.reportError(node,
MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
}
+ } else {
+ compiler.reportError(node,
+ MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT);
}
+ }
+ }
+
+ void analyzeConstantDeferred(Node node) {
+ addDeferredAction(enclosingElement, () {
+ analyzeConstant(node);
});
}
@@ -3569,7 +3573,7 @@
registry.registerRequiredType(listType, enclosingElement);
visit(node.elements);
if (node.isConst) {
- analyzeConstant(node);
+ analyzeConstantDeferred(node);
}
sendIsMemberAccess = false;
@@ -3790,7 +3794,7 @@
registry.registerRequiredType(mapType, enclosingElement);
node.visitChildren(this);
if (node.isConst) {
- analyzeConstant(node);
+ analyzeConstantDeferred(node);
}
sendIsMemberAccess = false;
@@ -3900,7 +3904,7 @@
for (Node labelOrCase in switchCase.labelsAndCases) {
CaseMatch caseMatch = labelOrCase.asCaseMatch();
if (caseMatch != null) {
- analyzeConstant(caseMatch.expression);
+ analyzeConstantDeferred(caseMatch.expression);
continue;
}
Label label = labelOrCase;
@@ -4361,6 +4365,12 @@
element.interfaces = const Link<DartType>();
calculateAllSupertypes(element);
+ if (node.names.nodes.isEmpty) {
+ compiler.reportError(node,
+ MessageKind.EMPTY_ENUM_DECLARATION,
+ {'enumName': element.name});
+ }
+
EnumCreator creator = new EnumCreator(compiler, element);
creator.createMembers();
return enumType;
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index b1fb8cd..4073f29 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -1736,11 +1736,16 @@
visitSwitchStatement(SwitchStatement node) {
// TODO(johnniwinther): Handle reachability based on reachability of
// switch cases.
+ // TODO(johnniwinther): Provide hint of duplicate case constants.
DartType expressionType = analyze(node.expression);
// Check that all the case expressions are assignable to the expression.
+ bool hasDefaultCase = false;
for (SwitchCase switchCase in node.cases) {
+ if (switchCase.isDefaultCase) {
+ hasDefaultCase = true;
+ }
for (Node labelOrCase in switchCase.labelsAndCases) {
CaseMatch caseMatch = labelOrCase.asCaseMatch();
if (caseMatch == null) continue;
@@ -1752,6 +1757,44 @@
analyze(switchCase);
}
+ if (!hasDefaultCase && expressionType.isEnumType) {
+ compiler.enqueuer.resolution.addDeferredAction(
+ elements.analyzedElement, () {
+ Map<ConstantValue, FieldElement> enumValues =
+ <ConstantValue, FieldElement>{};
+ List<FieldElement> unreferencedFields = <FieldElement>[];
+ EnumClassElement enumClass = expressionType.element;
+ enumClass.enumValues.forEach((FieldElement field) {
+ ConstantExpression constantExpression =
+ compiler.constants.getConstantForVariable(field);
+ if (constantExpression == null) {
+ // The field might not have been resolved.
+ unreferencedFields.add(field);
+ } else {
+ enumValues[constantExpression.value] = field;
+ }
+ });
+
+ for (SwitchCase switchCase in node.cases) {
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ CaseMatch caseMatch = labelOrCase.asCaseMatch();
+ if (caseMatch != null) {
+ ConstantExpression caseConstant =
+ compiler.resolver.constantCompiler.compileNode(
+ caseMatch.expression, elements);
+ enumValues.remove(caseConstant.value);
+ }
+ }
+ }
+ unreferencedFields.addAll(enumValues.values);
+ if (!unreferencedFields.isEmpty) {
+ compiler.reportWarning(node, MessageKind.MISSING_ENUM_CASES,
+ {'enumType': expressionType,
+ 'enumValues': unreferencedFields.map((e) => e.name).join(', ')});
+ }
+ });
+ }
+
return const StatementType();
}
diff --git a/pkg/compiler/lib/src/util/uri_extras.dart b/pkg/compiler/lib/src/util/uri_extras.dart
index 65a4ed2..aa8cdcf 100644
--- a/pkg/compiler/lib/src/util/uri_extras.dart
+++ b/pkg/compiler/lib/src/util/uri_extras.dart
@@ -7,18 +7,20 @@
import 'dart:math';
String relativize(Uri base, Uri uri, bool isWindows) {
- if (!base.path.startsWith('/')) {
- // Also throw an exception if [base] or base.path is null.
- throw new ArgumentError('Expected absolute path: ${base.path}');
- }
- if (!uri.path.startsWith('/')) {
- // Also throw an exception if [uri] or uri.path is null.
- throw new ArgumentError('Expected absolute path: ${uri.path}');
- }
bool equalsNCS(String a, String b) {
return a.toLowerCase() == b.toLowerCase();
}
+ if (!equalsNCS(base.scheme, uri.scheme) ||
+ equalsNCS(base.scheme, 'dart') ||
+ equalsNCS(base.scheme, 'package')) {
+ return uri.toString();
+ }
+
+ if (!equalsNCS(base.scheme, 'file')) {
+ isWindows = false;
+ }
+
String normalize(String path) {
if (isWindows) {
return path.toLowerCase();
@@ -27,9 +29,7 @@
}
}
- if (equalsNCS(base.scheme, 'file') &&
- equalsNCS(base.scheme, uri.scheme) &&
- base.userInfo == uri.userInfo &&
+ if (base.userInfo == uri.userInfo &&
equalsNCS(base.host, uri.host) &&
base.port == uri.port &&
uri.query == "" && uri.fragment == "") {
@@ -37,6 +37,11 @@
return uri.path.substring(base.path.lastIndexOf('/') + 1);
}
+ if (!base.path.startsWith('/') ||
+ !uri.path.startsWith('/')) {
+ return uri.toString();
+ }
+
List<String> uriParts = uri.path.split('/');
List<String> baseParts = base.path.split('/');
int common = 0;
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index 1d72b64..5b63242 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -804,9 +804,9 @@
howToFix: "Try making '#{enumType}' a normal class or removing the "
"'extends' clause.",
examples: const ["""
-enum Enum {}
-class A extends Enum {}
-main() => new A();"""]);
+enum Enum { A }
+class B extends Enum {}
+main() => new B();"""]);
static const MessageKind CANNOT_IMPLEMENT_ENUM = const MessageKind(
"Class '#{className}' can't implement the type '#{enumType}' "
@@ -815,9 +815,9 @@
howToFix: "Try making '#{enumType}' a normal class or removing the "
"type from the 'implements' clause.",
examples: const ["""
-enum Enum {}
-class A implements Enum {}
-main() => new A();"""]);
+enum Enum { A }
+class B implements Enum {}
+main() => new B();"""]);
static const MessageKind CANNOT_MIXIN_ENUM = const MessageKind(
"Class '#{className}' can't mixin the type '#{enumType}' because it "
@@ -826,9 +826,9 @@
howToFix: "Try making '#{enumType}' a normal class or removing the "
"type from the 'with' clause.",
examples: const ["""
-enum Enum {}
-class A extends Object with Enum {}
-main() => new A();"""]);
+enum Enum { A }
+class B extends Object with Enum {}
+main() => new B();"""]);
static const MessageKind CANNOT_INSTANTIATE_ENUM = const MessageKind(
"Enum type '#{enumName}' cannot be instantiated.",
@@ -836,10 +836,37 @@
howToFix: "Try making '#{enumType}' a normal class or use an enum "
"constant.",
examples: const ["""
+enum Enum { A }
+main() => new Enum(0);""", """
+enum Enum { A }
+main() => const Enum(0);"""]);
+
+ static const MessageKind EMPTY_ENUM_DECLARATION = const MessageKind(
+ "Enum '#{enumName}' must contain at least one value.",
+ options: const ['--enable-enum'],
+ howToFix: "Try adding an enum constant or making #{enumName} a "
+ "normal class.",
+ examples: const ["""
enum Enum {}
-main() => new Enum(0, '');""", """
-enum Enum {}
-main() => const Enum(0, '');"""]);
+main() { Enum e; }"""]);
+
+ static const MessageKind MISSING_ENUM_CASES = const MessageKind(
+ "Missing enum constants in switch statement: #{enumValues}.",
+ options: const ['--enable-enum'],
+ howToFix: "Try adding the missing constants or a default case.",
+ examples: const ["""
+enum Enum { A, B }
+main() {
+ switch (Enum.A) {
+ case Enum.B: break;
+ }
+}""", """
+enum Enum { A, B, C }
+main() {
+ switch (Enum.A) {
+ case Enum.B: break;
+ }
+}"""]);
static const MessageKind DUPLICATE_EXTENDS_IMPLEMENTS = const MessageKind(
"'#{type}' can not be both extended and implemented.");
@@ -2226,6 +2253,30 @@
// Patch errors end.
//////////////////////////////////////////////////////////////////////////////
+ static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n* ';
+
+ static const MessageKind IMPORT_EXPERIMENTAL_MIRRORS =
+ const MessageKind(r'''
+
+****************************************************************
+* WARNING: dart:mirrors support in dart2js is experimental,
+* and not recommended.
+* This implementation of mirrors is incomplete,
+* and often greatly increases the size of the generated
+* JavaScript code.
+*
+* Your app imports dart:mirrors via:''''''
+$IMPORT_EXPERIMENTAL_MIRRORS_PADDING#{importChain}
+*
+* Starting with Dart 1.9, you must use the
+* --enable-experimental-mirrors command-line flag to opt-in.
+* You can begin using this flag now if mirrors support is critical.
+*
+* To learn what to do next, please visit:
+* http://dartlang.org/dart2js-reflection
+****************************************************************
+''');
+
static const MessageKind CALL_NOT_SUPPORTED_ON_NATIVE_CLASS =
const MessageKind(
"Non-supported 'call' member on a native class, or a "
diff --git a/pkg/docgen/lib/src/models/annotation.dart b/pkg/docgen/lib/src/models/annotation.dart
index 5a8dd11c..766939c 100644
--- a/pkg/docgen/lib/src/models/annotation.dart
+++ b/pkg/docgen/lib/src/models/annotation.dart
@@ -6,37 +6,22 @@
import '../exports/source_mirrors.dart';
-import '../exports/dart2js_mirrors.dart' show ResolvedNode;
-
import '../library_helpers.dart';
import 'library.dart';
import 'mirror_based.dart';
import 'dart:mirrors';
-import 'package:compiler/src/tree/tree.dart';
/// Holds the name of the annotation, and its parameters.
class Annotation extends MirrorBased<ClassMirror> {
/// The class of this annotation.
DeclarationMirror mirror;
- Send node;
final Library owningLibrary;
List<String> parameters;
- Annotation(ResolvedNode resolvedNode, this.owningLibrary) {
- parameters = [];
- getMirrorForResolvedNode(resolvedNode, (m, n) { mirror = m; node = n;},
- (String param) => parameters.add(param));
- }
-
- String getMirrorForResolvedNode(ResolvedNode node, callbackFunc,
- paramCallbackFunc) {
- ResolvedNodeMirrorFinder finder = new ResolvedNodeMirrorFinder(node,
- callbackFunc, paramCallbackFunc);
- finder.unparse(node.node);
- return finder.result;
- }
+ Annotation(this.owningLibrary, this.mirror,
+ [List<String> this.parameters = const <String>[]]);
Map toMap() => {
'name': owningLibrary.packagePrefix +
@@ -45,70 +30,3 @@
};
}
-class ResolvedNodeMirrorFinder extends Unparser {
- final ResolvedNode resolvedNode;
- final Function annotationMirrorCallback;
- final Function parameterValueCallback;
- int recursionLevel;
-
- ResolvedNodeMirrorFinder(this.resolvedNode, this.annotationMirrorCallback,
- this.parameterValueCallback) : recursionLevel = 0;
-
- visitSend(Send node) {
- if (recursionLevel == 0) {
- var m = resolvedNode.resolvedMirror(node.selector);
- annotationMirrorCallback(m, node);
- } else {
- Operator op = node.selector.asOperator();
- String opString = op != null ? op.source : null;
- bool spacesNeeded =
- identical(opString, 'is') || identical(opString, 'as');
- if (node.isPrefix) visit(node.selector);
- unparseSendReceiver(node, spacesNeeded: spacesNeeded);
- if (!node.isPrefix && !node.isIndex) visit(node.selector);
- if (spacesNeeded) sb.write(' ');
- // Also add a space for sequences like x + +1 and y - -y.
- // TODO(ahe): remove case for '+' when we drop the support for it.
- if (node.argumentsNode != null && (identical(opString, '-')
- || identical(opString, '+'))) {
- var beginToken = node.argumentsNode.getBeginToken();
- if (beginToken != null &&
- identical(beginToken.stringValue, opString)) {
- sb.write(' ');
- }
- }
- }
- recursionLevel++;
- visit(node.argumentsNode);
- recursionLevel--;
- }
-
- unparseNodeListFrom(NodeList node, var from, {bool spaces: true}) {
- if (from.isEmpty) return;
-
- visit(from.head);
-
- for (var link = from.tail; !link.isEmpty; link = link.tail) {
- if (recursionLevel >= 2) {
- parameterValueCallback(sb.toString());
- sb.clear();
- }
- visit(link.head);
- }
- if (recursionLevel >= 2) {
- parameterValueCallback(sb.toString());
- sb.clear();
- }
- }
-
- visitNodeList(NodeList node) {
- addToken(node.beginToken);
- if (recursionLevel == 1) sb.clear();
- if (node.nodes != null) {
- recursionLevel++;
- unparseNodeListFrom(node, node.nodes);
- recursionLevel--;
- }
- if (node.endToken != null) write(node.endToken.value);
- }
-}
diff --git a/pkg/docgen/lib/src/models/model_helpers.dart b/pkg/docgen/lib/src/models/model_helpers.dart
index e131472..526ab4a 100644
--- a/pkg/docgen/lib/src/models/model_helpers.dart
+++ b/pkg/docgen/lib/src/models/model_helpers.dart
@@ -6,6 +6,8 @@
import 'dart:collection';
+import 'package:compiler/src/constants/expressions.dart';
+
import '../exports/dart2js_mirrors.dart' as dart2js_mirrors;
import '../exports/mirrors_util.dart' as dart2js_util;
import '../exports/source_mirrors.dart';
@@ -53,22 +55,119 @@
return '${mirror.defaultValue}';
}
-// TODO(johnniwinther): Use the `ConstExp` classes instead of `ResolvedNode`.
/// Returns a list of meta annotations assocated with a mirror.
List<Annotation> createAnnotations(DeclarationMirror mirror,
Library owningLibrary) {
var annotations = [];
- for (dart2js_mirrors.ResolvedNode node in
- dart2js_mirrors.BackDoor.metadataSyntaxOf(mirror)) {
- var docgenAnnotation = new Annotation(node, owningLibrary);
- if (!_SKIPPED_ANNOTATIONS.contains(dart2js_util.qualifiedNameOf(
- docgenAnnotation.mirror))) {
+ var info = new AnnotationInfo(mirror, owningLibrary);
+ for (var expr in dart2js_mirrors.BackDoor.metadataSyntaxOf(mirror)) {
+ var docgenAnnotation = expr.accept(const AnnotationCreator(), info);
+ if (docgenAnnotation != null &&
+ !_SKIPPED_ANNOTATIONS.contains(
+ dart2js_util.qualifiedNameOf(docgenAnnotation.mirror))) {
annotations.add(docgenAnnotation);
}
}
return annotations;
}
+class AnnotationInfo {
+ final Mirror mirror;
+ final Library owningLibrary;
+
+ AnnotationInfo(this.mirror, this.owningLibrary);
+}
+
+class AnnotationCreator
+ extends ConstantExpressionVisitor<AnnotationInfo, Annotation> {
+
+ const AnnotationCreator();
+
+ Annotation createAnnotation(var element,
+ AnnotationInfo context,
+ [List<String> parameters = const <String>[]]) {
+ var mirror =
+ dart2js_mirrors.BackDoor.getMirrorFromElement(context.mirror, element);
+ if (mirror != null) {
+ return new Annotation(context.owningLibrary, mirror, parameters);
+ }
+ return null;
+ }
+
+ @override
+ Annotation visitBinary(BinaryConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitConcatenate(ConcatenateConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitConditional(ConditionalConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitConstructed(ConstructedConstantExpresssion exp,
+ [AnnotationInfo context]) {
+ return createAnnotation(exp.target, context,
+ exp.arguments.map((a) => a.getText()).toList());
+ }
+
+ @override
+ Annotation visitFunction(FunctionConstantExpression exp,
+ [AnnotationInfo context]) {
+ return createAnnotation(exp.element, context);
+ }
+
+ @override
+ Annotation visitList(ListConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitMap(MapConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitPrimitive(PrimitiveConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitSymbol(SymbolConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitType(TypeConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitUnary(UnaryConstantExpression exp,
+ [AnnotationInfo context]) {
+ return null;
+ }
+
+ @override
+ Annotation visitVariable(VariableConstantExpression exp,
+ [AnnotationInfo context]) {
+ return createAnnotation(exp.element, context);
+ }
+}
+
/// A declaration is private if itself is private, or the owner is private.
bool isHidden(DeclarationSourceMirror mirror) {
if (mirror is LibraryMirror) {
diff --git a/pkg/docgen/test/metadata_test.dart b/pkg/docgen/test/metadata_test.dart
new file mode 100644
index 0000000..87ea6f5
--- /dev/null
+++ b/pkg/docgen/test/metadata_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2014, 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 async_await_test;
+
+import 'dart:io';
+
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import '../lib/src/exports/mirrors_util.dart' as dart2js_util;
+import '../lib/src/models/annotation.dart';
+import '../lib/docgen.dart';
+
+const Map<String, String> SOURCES = const <String, String>{
+ 'main.dart': '''
+import 'lib.dart' as lib;
+
+@lib.Annotation("foo", 42)
+main() {
+}
+''',
+ 'lib.dart': '''
+class Annotation {
+ final String arg1;
+ final int arg2;
+ const Annotation(this.arg1, this.arg2);
+}
+'''};
+
+main() {
+ group('Generate docs for', () {
+ test('files with annotations', () {
+ var temporaryDir = Directory.systemTemp.createTempSync('metadata_');
+ var uris = <Uri>[];
+ SOURCES.forEach((name, code) {
+ var fileName = path.join(temporaryDir.path, name);
+ var file = new File(fileName);
+ file.writeAsStringSync(code);
+ uris.add(new Uri.file(fileName));
+ });
+
+ return getMirrorSystem(uris, false).then((mirrorSystem) {
+ var library = new Library(mirrorSystem.libraries[uris[0]]);
+ expect(library is Library, isTrue);
+
+ var main = library.functions['main'];
+ expect(main is Method, isTrue);
+
+ var annotations = main.annotations;
+ expect(annotations.length, equals(1));
+
+ var annotation = annotations[0];
+ expect(annotation is Annotation, isTrue);
+
+ var map = annotation.toMap();
+ expect(map['name'], equals('lib-dart.Annotation.Annotation-'));
+ expect(map['parameters'].length, equals(2));
+ expect(map['parameters'][0], equals('"foo"'));
+ expect(map['parameters'][1], equals('42'));
+ }).whenComplete(() => temporaryDir.deleteSync(recursive: true));
+ });
+ });
+}
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 4b9899d..9966f59 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -54,7 +54,7 @@
return super.onLibraryScanned(element, loader);
}
- Future onLibrariesLoaded(Map<Uri, LibraryElement> loadedLibraries) {
+ Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
test('Compiler.onLibrariesLoaded');
return super.onLibrariesLoaded(loadedLibraries);
}
diff --git a/tests/compiler/dart2js/import_mirrors_test.dart b/tests/compiler/dart2js/import_mirrors_test.dart
new file mode 100644
index 0000000..07c00d0
--- /dev/null
+++ b/tests/compiler/dart2js/import_mirrors_test.dart
@@ -0,0 +1,316 @@
+// Copyright (c) 2014, 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.
+
+// Test that the compiler emits a warning on import of 'dart:mirrors' unless
+// the flag --enable-experimental-mirrors is used.
+
+library dart2js.test.import;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/dart2jslib.dart' show MessageKind;
+import 'memory_compiler.dart';
+
+const DIRECT_IMPORT = const {
+ '/main.dart': '''
+import 'dart:mirrors';
+
+main() {}
+''',
+
+ 'paths':
+ "main.dart => dart:mirrors",
+};
+
+const INDIRECT_IMPORT1 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "first.dart => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => dart:mirrors",
+};
+
+const INDIRECT_IMPORT2 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'second.dart';
+''',
+ '/second.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "second.dart => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => second.dart => dart:mirrors",
+};
+
+const INDIRECT_PACKAGE_IMPORT1 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'package:second.dart';
+''',
+ '/pkg/second.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "first.dart => package:second.dart => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => package:second.dart => dart:mirrors",
+};
+
+const INDIRECT_PACKAGE_IMPORT2 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'package:package-name/second.dart';
+''',
+ '/pkg/package-name/second.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "first.dart => package:package-name => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => package:package-name/second.dart "
+ "=> dart:mirrors",
+};
+
+const INDIRECT_PACKAGE_IMPORT3 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'package:package1/second.dart';
+''',
+ '/pkg/package1/second.dart': '''
+import 'package:package2/third.dart';
+''',
+ '/pkg/package2/third.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "first.dart => package:package1 => package:package2 => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => package:package1/second.dart "
+ "=> package:package2/third.dart => dart:mirrors",
+};
+
+const INDIRECT_PACKAGE_IMPORT4 = const {
+ '/main.dart': '''
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'package:package1/second.dart';
+''',
+ '/pkg/package1/second.dart': '''
+import 'sub/third.dart';
+''',
+ '/pkg/package1/sub/third.dart': '''
+import 'package:package2/fourth.dart';
+''',
+ '/pkg/package2/fourth.dart': '''
+import 'lib/src/fifth.dart';
+''',
+ '/pkg/package2/lib/src/fifth.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "first.dart => package:package1 => package:package2 => dart:mirrors",
+ 'verbosePaths':
+ "main.dart => first.dart => package:package1/second.dart "
+ "=> package:package1/sub/third.dart => package:package2/fourth.dart "
+ "=> package:package2/lib/src/fifth.dart => dart:mirrors",
+};
+
+const DUAL_DIRECT_IMPORT = const {
+ '/main.dart': '''
+import 'dart:mirrors';
+import 'dart:mirrors';
+
+main() {}
+''',
+
+ 'paths':
+ "main.dart => dart:mirrors",
+};
+
+const DUAL_INDIRECT_IMPORT1 = const {
+ '/main.dart': '''
+import 'dart:mirrors';
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths': const
+ ["main.dart => dart:mirrors",
+ "first.dart => dart:mirrors"],
+ 'verbosePaths': const
+ ["main.dart => dart:mirrors",
+ "main.dart => first.dart => dart:mirrors"],
+};
+
+const DUAL_INDIRECT_IMPORT2 = const {
+ '/main.dart': '''
+import 'first.dart';
+import 'second.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'dart:mirrors';
+''',
+ '/second.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths': const
+ ["first.dart => dart:mirrors",
+ "second.dart => dart:mirrors"],
+ 'verbosePaths': const
+ ["main.dart => first.dart => dart:mirrors",
+ "main.dart => second.dart => dart:mirrors"],
+};
+
+const DUAL_INDIRECT_IMPORT3 = const {
+ '/main.dart': '''
+import 'first.dart';
+import 'second.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'third.dart';
+''',
+ '/second.dart': '''
+import 'third.dart';
+''',
+ '/third.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths':
+ "third.dart => dart:mirrors",
+ 'verbosePaths': const
+ ["main.dart => first.dart => third.dart => dart:mirrors",
+ "main.dart => second.dart => third.dart => dart:mirrors"],
+};
+
+const DUAL_INDIRECT_PACKAGE_IMPORT1 = const {
+ '/main.dart': '''
+import 'package:package1/second.dart';
+import 'first.dart';
+
+main() {}
+''',
+ '/first.dart': '''
+import 'package:package2/third.dart';
+''',
+ '/pkg/package1/second.dart': '''
+import 'dart:mirrors';
+''',
+ '/pkg/package2/third.dart': '''
+import 'dart:mirrors';
+''',
+
+ 'paths': const
+ ["main.dart => package:package1 => dart:mirrors",
+ "first.dart => package:package2 => dart:mirrors"],
+ 'verbosePaths': const
+ ["main.dart => package:package1/second.dart => dart:mirrors",
+ "main.dart => first.dart => package:package2/third.dart => dart:mirrors"]
+};
+
+
+test(Map sourceFiles,
+ {expectedPaths,
+ bool verbose: false,
+ bool enableExperimentalMirrors: false}) {
+ if (expectedPaths is! List) {
+ expectedPaths = [expectedPaths];
+ }
+ var collector = new DiagnosticCollector();
+ var options = [];
+ if (verbose) {
+ options.add('--verbose');
+ }
+ if (enableExperimentalMirrors) {
+ options.add('--enable-experimental-mirrors');
+ }
+ var compiler = compilerFor(sourceFiles, diagnosticHandler: collector,
+ packageRoot: Uri.parse('memory:/pkg/'),
+ options: options);
+ asyncTest(() => compiler.run(Uri.parse('memory:/main.dart')).then((_) {
+ Expect.equals(0, collector.errors.length, 'Errors: ${collector.errors}');
+ if (enableExperimentalMirrors) {
+ Expect.equals(0, collector.warnings.length,
+ 'Warnings: ${collector.errors}');
+ } else {
+ Expect.equals(1, collector.warnings.length,
+ 'Warnings: ${collector.errors}');
+ Expect.equals(
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS.message(
+ {'importChain': expectedPaths.join(
+ MessageKind.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)}).toString(),
+ collector.warnings.first.message);
+ }
+ }));
+}
+
+checkPaths(Map sourceData) {
+ Map sourceFiles = sourceData;
+ var expectedPaths = sourceData['paths'];
+ var expectedVerbosePaths = sourceData['verbosePaths'];
+ if (expectedVerbosePaths == null) {
+ expectedVerbosePaths = expectedPaths;
+ }
+ test(sourceFiles, expectedPaths: expectedPaths);
+ test(sourceFiles, expectedPaths: expectedVerbosePaths, verbose: true);
+ test(sourceFiles, enableExperimentalMirrors: true);
+}
+
+void main() {
+ checkPaths(DIRECT_IMPORT);
+ checkPaths(INDIRECT_IMPORT1);
+ checkPaths(INDIRECT_IMPORT2);
+ checkPaths(INDIRECT_PACKAGE_IMPORT1);
+ checkPaths(INDIRECT_PACKAGE_IMPORT2);
+ checkPaths(INDIRECT_PACKAGE_IMPORT3);
+ checkPaths(INDIRECT_PACKAGE_IMPORT4);
+ checkPaths(DUAL_DIRECT_IMPORT);
+ checkPaths(DUAL_INDIRECT_IMPORT1);
+ checkPaths(DUAL_INDIRECT_IMPORT2);
+ checkPaths(DUAL_INDIRECT_IMPORT3);
+ checkPaths(DUAL_INDIRECT_PACKAGE_IMPORT1);
+}
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index de75d6c..88bc8e2 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -10,13 +10,16 @@
show NullSink;
import 'package:compiler/compiler.dart'
- show Diagnostic, DiagnosticHandler, CompilerOutputProvider;
+ show Diagnostic, DiagnosticHandler, CompilerOutputProvider;
import 'dart:async';
import 'package:compiler/src/mirrors/source_mirrors.dart';
import 'package:compiler/src/mirrors/analyze.dart';
+import 'package:compiler/src/library_loader.dart'
+ show LoadedLibraries;
+
class DiagnosticMessage {
final Uri uri;
final int begin;
@@ -183,7 +186,7 @@
});
// TODO(johnniwinther): Assert that no libraries are loaded lazily from
// this call.
- compiler.onLibrariesLoaded(copiedLibraries);
+ compiler.onLibrariesLoaded(new MemoryLoadedLibraries(copiedLibraries));
compiler.symbolConstructor = cachedCompiler.symbolConstructor;
compiler.mirrorSystemClass = cachedCompiler.mirrorSystemClass;
@@ -229,6 +232,27 @@
return compiler;
}
+class MemoryLoadedLibraries implements LoadedLibraries {
+ final Map copiedLibraries;
+
+ MemoryLoadedLibraries(this.copiedLibraries);
+
+ @override
+ bool containsLibrary(Uri uri) => copiedLibraries.containsKey(uri);
+
+ @override
+ void forEachImportChain(f) {}
+
+ @override
+ void forEachLibrary(f) {}
+
+ @override
+ getLibrary(Uri uri) => copiedLibraries[uri];
+
+ @override
+ Uri get rootUri => null;
+}
+
Future<MirrorSystem> mirrorSystemFor(Map<String,String> memorySourceFiles,
{DiagnosticHandler diagnosticHandler,
List<String> options: const [],
diff --git a/tests/compiler/dart2js/message_kind_helper.dart b/tests/compiler/dart2js/message_kind_helper.dart
index 67f1d60..2258935 100644
--- a/tests/compiler/dart2js/message_kind_helper.dart
+++ b/tests/compiler/dart2js/message_kind_helper.dart
@@ -83,7 +83,8 @@
Compiler compiler = compilerFor(
example,
diagnosticHandler: collect,
- options: ['--analyze-only']..addAll(kind.options),
+ options: ['--analyze-only',
+ '--enable-experimental-mirrors']..addAll(kind.options),
cachedCompiler: cachedCompiler);
return compiler.run(Uri.parse('memory:main.dart')).then((_) {
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index 75ad6c8..368d51b 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -21,10 +21,14 @@
VariableMirror variable = declaration;
if (variable.isStatic) {
var value = cls.getField(name).reflectee;
+ String variableName = MirrorSystem.getName(name);
+ if (variableName == 'IMPORT_EXPERIMENTAL_MIRRORS_PADDING') {
+ return;
+ }
if (value is MessageKind) {
- kinds[MirrorSystem.getName(name)] = value;
+ kinds[variableName] = value;
} else {
- Expect.fail("Weird static field: '${MirrorSystem.getName(name)}'.");
+ Expect.fail("Weird static field: '${variableName}'.");
}
}
});
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 611dd98..2d26968 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -45,7 +45,8 @@
void main() {
Compiler compiler = compilerFor(
- MEMORY_SOURCE_FILES, diagnosticHandler: expectOnlyVerboseInfo);
+ MEMORY_SOURCE_FILES, diagnosticHandler: expectOnlyVerboseInfo,
+ options: ['--enable-experimental-mirrors']);
asyncTest(() => compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) {
print('');
List generatedCode =
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index bc88820..653a12d 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -817,20 +817,7 @@
compiler.resolver.resolve(mainElement);
Expect.equals(0, compiler.warnings.length,
'Unexpected warnings: ${compiler.warnings}');
- Expect.equals(0, compiler.errors.length,
- 'Unexpected errors: ${compiler.errors}');
- }, enableEnums: true),
-
- MockCompiler.create((MockCompiler compiler) {
- compiler.parseScript("""enum Enum {}
- main() { Enum e = Enum.A; }""");
- FunctionElement mainElement = compiler.mainApp.find(MAIN);
- compiler.resolver.resolve(mainElement);
- Expect.equals(1, compiler.warnings.length,
- 'Unexpected warnings: ${compiler.warnings}');
- Expect.equals(MessageKind.MEMBER_NOT_FOUND,
- compiler.warnings[0].message.kind);
- Expect.equals(0, compiler.errors.length,
+ Expect.equals(1, compiler.errors.length,
'Unexpected errors: ${compiler.errors}');
}, enableEnums: true),
@@ -870,7 +857,7 @@
}, enableEnums: true),
MockCompiler.create((MockCompiler compiler) {
- compiler.parseScript("""enum Enum {}
+ compiler.parseScript("""enum Enum { A }
main() { new Enum(0, ''); }""");
FunctionElement mainElement = compiler.mainApp.find(MAIN);
compiler.resolver.resolve(mainElement);
@@ -883,7 +870,7 @@
}, enableEnums: true),
MockCompiler.create((MockCompiler compiler) {
- compiler.parseScript("""enum Enum {}
+ compiler.parseScript("""enum Enum { A }
main() { const Enum(0, ''); }""");
FunctionElement mainElement = compiler.mainApp.find(MAIN);
compiler.resolver.resolve(mainElement);
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index c7ab34b..f00a0d7 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -29,6 +29,7 @@
testWhile,
testTry,
testSwitch,
+ testEnumSwitch,
testOperators,
testConstructorInvocationArgumentCount,
testConstructorInvocationArgumentTypes,
@@ -169,6 +170,89 @@
warnings: [NOT_ASSIGNABLE, NOT_ASSIGNABLE]);
}
+testEnumSwitch(MockCompiler compiler) {
+ String DECLARATIONS = """
+enum Enum { A, B, C }
+""";
+
+ check(String code, {warnings}) {
+ MockCompiler compiler = new MockCompiler.internal(enableEnums: true);
+ return compiler.init(DECLARATIONS).then((_) {
+ analyze(compiler, code, warnings: warnings, flushDeferred: true);
+ });
+ }
+
+ check("""
+switch (Enum.A) {
+default: break;
+}""");
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+default: break;
+}""");
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+case Enum.B: break;
+default: break;
+}""");
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+case Enum.B: break;
+case Enum.C: break;
+default: break;
+}""");
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+case Enum.B: break;
+case Enum.C: break;
+}""");
+
+ check("""
+switch (Enum.A) {
+case Enum.B: break;
+case Enum.C: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+case Enum.C: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+case Enum.B: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+case Enum.A: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+case Enum.B: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+case Enum.C: break;
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+
+ check("""
+switch (Enum.A) {
+}""", warnings: MessageKind.MISSING_ENUM_CASES);
+}
+
testOperators(MockCompiler compiler) {
check(String code, {warnings}) {
analyze(compiler, code, warnings: warnings);
@@ -2061,7 +2145,8 @@
*/
analyze(MockCompiler compiler,
String text,
- {errors, warnings, List hints, List infos}) {
+ {errors, warnings, List hints, List infos,
+ bool flushDeferred: false}) {
if (warnings == null) warnings = [];
if (warnings is !List) warnings = [warnings];
if (errors == null) errors = [];
@@ -2078,10 +2163,14 @@
new CompilationUnitElementX(new Script(null, null, null), compiler.mainApp);
Element function = new MockElement(compilationUnit);
TreeElements elements = compiler.resolveNodeStatement(node, function);
+ compiler.enqueuer.resolution.emptyDeferredTaskQueue();
TypeCheckerVisitor checker = new TypeCheckerVisitor(
compiler, elements, compiler.types);
compiler.clearMessages();
checker.analyze(node);
+ if (flushDeferred) {
+ compiler.enqueuer.resolution.emptyDeferredTaskQueue();
+ }
compareWarningKinds(text, warnings, compiler.warnings);
compareWarningKinds(text, errors, compiler.errors);
if (hints != null) compareWarningKinds(text, hints, compiler.hints);
diff --git a/tests/language/enum_test.dart b/tests/language/enum_test.dart
new file mode 100644
index 0000000..84daba1
--- /dev/null
+++ b/tests/language/enum_test.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2014, 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.
+
+// SharedOptions=--enable-enum
+
+import 'package:expect/expect.dart';
+
+enum Enum1 { _ }
+enum Enum2 { A }
+enum Enum3 { B, C }
+enum Enum4 { D, E, }
+enum Enum5 { F, G, H }
+
+main() {
+ Expect.equals('Enum1._', Enum1._.toString());
+ Expect.equals(0, Enum1._.index);
+ Expect.listEquals([Enum1._], Enum1.values);
+ Enum1.values.forEach(test1);
+
+ Expect.equals('Enum2.A', Enum2.A.toString());
+ Expect.equals(0, Enum2.A.index);
+ Expect.listEquals([Enum2.A], Enum2.values);
+ Enum2.values.forEach(test2);
+
+ Expect.equals('Enum3.B', Enum3.B.toString());
+ Expect.equals('Enum3.C', Enum3.C.toString());
+ Expect.equals(0, Enum3.B.index);
+ Expect.equals(1, Enum3.C.index);
+ Expect.listEquals([Enum3.B, Enum3.C], Enum3.values);
+ Enum3.values.forEach(test3);
+
+ Expect.equals('Enum4.D', Enum4.D.toString());
+ Expect.equals('Enum4.E', Enum4.E.toString());
+ Expect.equals(0, Enum4.D.index);
+ Expect.equals(1, Enum4.E.index);
+ Expect.listEquals([Enum4.D, Enum4.E], Enum4.values);
+ Enum4.values.forEach(test4);
+
+ Expect.equals('Enum5.F', Enum5.F.toString());
+ Expect.equals('Enum5.G', Enum5.G.toString());
+ Expect.equals('Enum5.H', Enum5.H.toString());
+ Expect.equals(0, Enum5.F.index);
+ Expect.equals(1, Enum5.G.index);
+ Expect.equals(2, Enum5.H.index);
+ Expect.listEquals([Enum5.F, Enum5.G, Enum5.H], Enum5.values);
+ Enum5.values.forEach(test5);
+}
+
+test1(Enum1 e) {
+ int index;
+ switch (e) {
+ case Enum1._:
+ index = 0;
+ break;
+ }
+ Expect.equals(e.index, index);
+}
+
+test2(Enum2 e) {
+ int index;
+ switch (e) {
+ case Enum2.A:
+ index = 0;
+ break;
+ }
+ Expect.equals(e.index, index);
+}
+
+test3(Enum3 e) {
+ int index;
+ switch (e) {
+ case Enum3.C:
+ index = 1;
+ break;
+ case Enum3.B:
+ index = 0;
+ break;
+ }
+ Expect.equals(e.index, index);
+}
+
+test4(Enum4 e) {
+ int index;
+ switch (e) {
+ case Enum4.D:
+ index = 0;
+ break;
+ case Enum4.E:
+ index = 1;
+ break;
+ }
+ Expect.equals(e.index, index);
+}
+
+test5(Enum5 e) {
+ int index;
+ switch (e) {
+ case Enum5.H:
+ index = 2;
+ break;
+ case Enum5.F:
+ index = 0;
+ break;
+ case Enum5.G:
+ index = 1;
+ break;
+ }
+ Expect.equals(e.index, index);
+}
\ No newline at end of file
diff --git a/tests/language/language.status b/tests/language/language.status
index 1e35edc..5d7549a 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -7,6 +7,7 @@
[ $compiler == none ]
built_in_identifier_prefix_test: Fail # Issue 6970
+enum_test: Fail # Issue 21416
# These bugs refer currently ongoing language discussions.
constructor_initializer_test/none: Fail # Issue 12633
@@ -49,6 +50,7 @@
deferred_closurize_load_library_test: Fail # Issue 17523
deferred_inlined_test: Fail # Issue 17523
deferred_optimized_test: Fail # Issue 17523
+enum_test: Crash # Issue 21416/21417
override_inheritance_mixed_test/08: Fail # Issue 18124
override_inheritance_mixed_test/09: Fail # Issue 18124
diff --git a/tools/VERSION b/tools/VERSION
index 9146f20..bfc0b1c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 8
PATCH 0
PRERELEASE 4
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3